1// Copyright 2021 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 KAS KDF tests. See 25// https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-hkdf.html 26 27type hkdfTestVectorSet struct { 28 Groups []hkdfTestGroup `json:"testGroups"` 29} 30 31type hkdfTestGroup struct { 32 ID uint64 `json:"tgId"` 33 Type string `json:"testType"` // AFT or VAL 34 Config hkdfConfiguration `json:"kdfConfiguration"` 35 Tests []hkdfTest `json:"tests"` 36} 37 38type hkdfTest struct { 39 ID uint64 `json:"tcId"` 40 Params hkdfParameters `json:"kdfParameter"` 41 PartyU hkdfPartyInfo `json:"fixedInfoPartyU"` 42 PartyV hkdfPartyInfo `json:"fixedInfoPartyV"` 43 ExpectedHex string `json:"dkm"` 44} 45 46type hkdfConfiguration struct { 47 Type string `json:"kdfType"` 48 OutputBits uint32 `json:"l"` 49 HashName string `json:"hmacAlg"` 50 FixedInfoPattern string `json:"fixedInfoPattern"` 51 FixedInputEncoding string `json:"fixedInfoEncoding"` 52} 53 54func (c *hkdfConfiguration) extract() (outBytes uint32, hashName string, err error) { 55 if c.Type != "hkdf" || 56 c.FixedInfoPattern != "uPartyInfo||vPartyInfo" || 57 c.FixedInputEncoding != "concatenation" || 58 c.OutputBits%8 != 0 { 59 return 0, "", fmt.Errorf("KDA not configured for HKDF: %#v", c) 60 } 61 62 return c.OutputBits / 8, c.HashName, nil 63} 64 65type hkdfParameters struct { 66 SaltHex string `json:"salt"` 67 KeyHex string `json:"z"` 68} 69 70func (p *hkdfParameters) extract() (key, salt []byte, err error) { 71 salt, err = hex.DecodeString(p.SaltHex) 72 if err != nil { 73 return nil, nil, err 74 } 75 76 key, err = hex.DecodeString(p.KeyHex) 77 if err != nil { 78 return nil, nil, err 79 } 80 81 return key, salt, nil 82} 83 84type hkdfPartyInfo struct { 85 IDHex string `json:"partyId"` 86 ExtraHex string `json:"ephemeralData"` 87} 88 89func (p *hkdfPartyInfo) data() ([]byte, error) { 90 ret, err := hex.DecodeString(p.IDHex) 91 if err != nil { 92 return nil, err 93 } 94 95 if len(p.ExtraHex) > 0 { 96 extra, err := hex.DecodeString(p.ExtraHex) 97 if err != nil { 98 return nil, err 99 } 100 ret = append(ret, extra...) 101 } 102 103 return ret, nil 104} 105 106type hkdfTestGroupResponse struct { 107 ID uint64 `json:"tgId"` 108 Tests []hkdfTestResponse `json:"tests"` 109} 110 111type hkdfTestResponse struct { 112 ID uint64 `json:"tcId"` 113 KeyOut string `json:"dkm,omitempty"` 114 Passed *bool `json:"testPassed,omitempty"` 115} 116 117type hkdf struct{} 118 119func (k *hkdf) Process(vectorSet []byte, m Transactable) (any, error) { 120 var parsed hkdfTestVectorSet 121 if err := json.Unmarshal(vectorSet, &parsed); err != nil { 122 return nil, err 123 } 124 125 var respGroups []hkdfTestGroupResponse 126 for _, group := range parsed.Groups { 127 group := group 128 groupResp := hkdfTestGroupResponse{ID: group.ID} 129 130 var isValidationTest bool 131 switch group.Type { 132 case "VAL": 133 isValidationTest = true 134 case "AFT": 135 isValidationTest = false 136 default: 137 return nil, fmt.Errorf("unknown test type %q", group.Type) 138 } 139 140 outBytes, hashName, err := group.Config.extract() 141 if err != nil { 142 return nil, err 143 } 144 145 for _, test := range group.Tests { 146 test := test 147 testResp := hkdfTestResponse{ID: test.ID} 148 149 key, salt, err := test.Params.extract() 150 if err != nil { 151 return nil, err 152 } 153 uData, err := test.PartyU.data() 154 if err != nil { 155 return nil, err 156 } 157 vData, err := test.PartyV.data() 158 if err != nil { 159 return nil, err 160 } 161 162 var expected []byte 163 if isValidationTest { 164 expected, err = hex.DecodeString(test.ExpectedHex) 165 if err != nil { 166 return nil, err 167 } 168 } 169 170 info := make([]byte, 0, len(uData)+len(vData)) 171 info = append(info, uData...) 172 info = append(info, vData...) 173 174 m.TransactAsync("HKDF/"+hashName, 1, [][]byte{key, salt, info, uint32le(outBytes)}, func(result [][]byte) error { 175 if len(result[0]) != int(outBytes) { 176 return fmt.Errorf("HKDF operation resulted in %d bytes but wanted %d", len(result[0]), outBytes) 177 } 178 if isValidationTest { 179 passed := bytes.Equal(expected, result[0]) 180 testResp.Passed = &passed 181 } else { 182 testResp.KeyOut = hex.EncodeToString(result[0]) 183 } 184 185 groupResp.Tests = append(groupResp.Tests, testResp) 186 return nil 187 }) 188 } 189 190 m.Barrier(func() { 191 respGroups = append(respGroups, groupResp) 192 }) 193 } 194 195 if err := m.Flush(); err != nil { 196 return nil, err 197 } 198 199 return respGroups, nil 200} 201