1// Copyright 2020 The BoringSSL Authors 2// 3// Permission to use, copy, modify, and/or distribute this software for any 4// purpose with or without fee is hereby granted, provided that the above 5// copyright notice and this permission notice appear in all copies. 6// 7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 15package subprocess 16 17import ( 18 "bytes" 19 "encoding/hex" 20 "encoding/json" 21 "fmt" 22) 23 24// The following structures reflect the JSON of ACVP KDF tests. See 25// https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html#name-test-vectors 26 27type kdfTestVectorSet struct { 28 Groups []kdfTestGroup `json:"testGroups"` 29} 30 31type kdfTestGroup struct { 32 ID uint64 `json:"tgId"` 33 // KDFMode can take the values "counter", "feedback", or 34 // "double pipeline iteration". 35 KDFMode string `json:"kdfMode"` 36 MACMode string `json:"macMode"` 37 CounterLocation string `json:"counterLocation"` 38 OutputBits uint32 `json:"keyOutLength"` 39 CounterBits uint32 `json:"counterLength"` 40 ZeroIV bool `json:"zeroLengthIv"` 41 42 Tests []struct { 43 ID uint64 `json:"tcId"` 44 Key string `json:"keyIn"` 45 Deferred bool `json:"deferred"` 46 } 47} 48 49type kdfTestGroupResponse struct { 50 ID uint64 `json:"tgId"` 51 Tests []kdfTestResponse `json:"tests"` 52} 53 54type kdfTestResponse struct { 55 ID uint64 `json:"tcId"` 56 KeyIn string `json:"keyIn,omitempty"` 57 FixedData string `json:"fixedData"` 58 KeyOut string `json:"keyOut"` 59} 60 61type kdfPrimitive struct{} 62 63func (k *kdfPrimitive) Process(vectorSet []byte, m Transactable) (any, error) { 64 var parsed kdfTestVectorSet 65 if err := json.Unmarshal(vectorSet, &parsed); err != nil { 66 return nil, err 67 } 68 69 var respGroups []kdfTestGroupResponse 70 for _, group := range parsed.Groups { 71 group := group 72 groupResp := kdfTestGroupResponse{ID: group.ID} 73 74 if group.OutputBits%8 != 0 { 75 return nil, fmt.Errorf("%d bit key in test group %d: fractional bytes not supported", group.OutputBits, group.ID) 76 } 77 78 if group.KDFMode != "counter" { 79 // feedback mode would need the IV to be handled. 80 // double-pipeline mode is not useful. 81 return nil, fmt.Errorf("KDF mode %q not supported", group.KDFMode) 82 } 83 84 switch group.CounterLocation { 85 case "after fixed data", "before fixed data": 86 break 87 default: 88 return nil, fmt.Errorf("Label location %q not supported", group.CounterLocation) 89 } 90 91 counterBits := uint32le(group.CounterBits) 92 outputBytes := uint32le(group.OutputBits / 8) 93 94 for _, test := range group.Tests { 95 test := test 96 testResp := kdfTestResponse{ID: test.ID} 97 98 var key []byte 99 if test.Deferred { 100 if len(test.Key) != 0 { 101 return nil, fmt.Errorf("key provided in deferred test case %d/%d", group.ID, test.ID) 102 } 103 } else { 104 var err error 105 if key, err = hex.DecodeString(test.Key); err != nil { 106 return nil, fmt.Errorf("failed to decode Key in test case %d/%d: %v", group.ID, test.ID, err) 107 } 108 } 109 110 // Make the call to the crypto module. 111 m.TransactAsync("KDF-counter", 3, [][]byte{outputBytes, []byte(group.MACMode), []byte(group.CounterLocation), key, counterBits}, func(result [][]byte) error { 112 testResp.ID = test.ID 113 if test.Deferred { 114 testResp.KeyIn = hex.EncodeToString(result[0]) 115 } 116 testResp.FixedData = hex.EncodeToString(result[1]) 117 testResp.KeyOut = hex.EncodeToString(result[2]) 118 119 if !test.Deferred && !bytes.Equal(result[0], key) { 120 return fmt.Errorf("wrapper returned a different key for non-deferred KDF operation") 121 } 122 123 groupResp.Tests = append(groupResp.Tests, testResp) 124 return nil 125 }) 126 } 127 128 m.Barrier(func() { 129 respGroups = append(respGroups, groupResp) 130 }) 131 } 132 133 if err := m.Flush(); err != nil { 134 return nil, err 135 } 136 137 return respGroups, nil 138} 139