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 "encoding/binary" 19 "encoding/hex" 20 "encoding/json" 21 "fmt" 22) 23 24type tlsKDFVectorSet struct { 25 Groups []tlsKDFTestGroup `json:"testGroups"` 26} 27 28type tlsKDFTestGroup struct { 29 ID uint64 `json:"tgId"` 30 Hash string `json:"hashAlg"` 31 TLSVersion string `json:"tlsVersion"` 32 KeyBlockBits uint64 `json:"keyBlockLength"` 33 PMSLength uint64 `json:"preMasterSecretLength"` 34 Tests []tlsKDFTest `json:"tests"` 35} 36 37type tlsKDFTest struct { 38 ID uint64 `json:"tcId"` 39 PMSHex string `json:"preMasterSecret"` 40 ClientRandomHex string `json:"clientRandom"` 41 ServerRandomHex string `json:"serverRandom"` 42 SessionHashHex string `json:"sessionHash"` 43} 44 45type tlsKDFTestGroupResponse struct { 46 ID uint64 `json:"tgId"` 47 Tests []tlsKDFTestResponse `json:"tests"` 48} 49 50type tlsKDFTestResponse struct { 51 ID uint64 `json:"tcId"` 52 MasterSecretHex string `json:"masterSecret"` 53 KeyBlockHex string `json:"keyBlock"` 54} 55 56type tlsKDF struct{} 57 58func (k *tlsKDF) Process(vectorSet []byte, m Transactable) (any, error) { 59 var parsed tlsKDFVectorSet 60 if err := json.Unmarshal(vectorSet, &parsed); err != nil { 61 return nil, err 62 } 63 64 // See https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html 65 var ret []tlsKDFTestGroupResponse 66 for _, group := range parsed.Groups { 67 group := group 68 response := tlsKDFTestGroupResponse{ 69 ID: group.ID, 70 } 71 72 switch group.Hash { 73 case "SHA2-256", "SHA2-384", "SHA2-512": 74 break 75 default: 76 return nil, fmt.Errorf("unknown hash %q", group.Hash) 77 } 78 79 if group.KeyBlockBits%8 != 0 { 80 return nil, fmt.Errorf("requested key-block length (%d bits) is not a whole number of bytes", group.KeyBlockBits) 81 } 82 83 method := "TLSKDF/1.2/" + group.Hash 84 85 for _, test := range group.Tests { 86 test := test 87 pms, err := hex.DecodeString(test.PMSHex) 88 if err != nil { 89 return nil, err 90 } 91 92 clientRandom, err := hex.DecodeString(test.ClientRandomHex) 93 if err != nil { 94 return nil, err 95 } 96 97 serverRandom, err := hex.DecodeString(test.ServerRandomHex) 98 if err != nil { 99 return nil, err 100 } 101 102 sessionHash, err := hex.DecodeString(test.SessionHashHex) 103 if err != nil { 104 return nil, err 105 } 106 107 const ( 108 masterSecretLength = 48 109 masterSecretLabel = "extended master secret" 110 keyBlockLabel = "key expansion" 111 ) 112 113 var outLenBytes [4]byte 114 binary.LittleEndian.PutUint32(outLenBytes[:], uint32(masterSecretLength)) 115 result, err := m.Transact(method, 1, outLenBytes[:], pms, []byte(masterSecretLabel), sessionHash, nil) 116 if err != nil { 117 return nil, err 118 } 119 120 binary.LittleEndian.PutUint32(outLenBytes[:], uint32(group.KeyBlockBits/8)) 121 // TLS 1.0, 1.1, and 1.2 use a different order for the client and server 122 // randoms when computing the key block. 123 m.TransactAsync(method, 1, [][]byte{outLenBytes[:], result[0], []byte(keyBlockLabel), serverRandom, clientRandom}, func(result2 [][]byte) error { 124 response.Tests = append(response.Tests, tlsKDFTestResponse{ 125 ID: test.ID, 126 MasterSecretHex: hex.EncodeToString(result[0]), 127 KeyBlockHex: hex.EncodeToString(result2[0]), 128 }) 129 return nil 130 }) 131 } 132 133 m.Barrier(func() { 134 ret = append(ret, response) 135 }) 136 } 137 138 if err := m.Flush(); err != nil { 139 return nil, err 140 } 141 142 return ret, nil 143} 144