1// Copyright (c) 2020, Google Inc. 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 // ClientHelloRandomHex and ServerHelloRandomHex are used for deriving the 41 // master secret. ClientRandomHex and ServerRandomHex are used for deriving the 42 // key block. Having different values for these is not possible in a TLS 43 // handshake unless you squint at a resumption handshake and somehow rederive 44 // the master secret from the session information during resumption. 45 ClientHelloRandomHex string `json:"clientHelloRandom"` 46 ServerHelloRandomHex string `json:"serverHelloRandom"` 47 ClientRandomHex string `json:"clientRandom"` 48 ServerRandomHex string `json:"serverRandom"` 49} 50 51type tlsKDFTestGroupResponse struct { 52 ID uint64 `json:"tgId"` 53 Tests []tlsKDFTestResponse `json:"tests"` 54} 55 56type tlsKDFTestResponse struct { 57 ID uint64 `json:"tcId"` 58 MasterSecretHex string `json:"masterSecret"` 59 KeyBlockHex string `json:"keyBlock"` 60} 61 62type tlsKDF struct{} 63 64func (k *tlsKDF) Process(vectorSet []byte, m Transactable) (interface{}, error) { 65 var parsed tlsKDFVectorSet 66 if err := json.Unmarshal(vectorSet, &parsed); err != nil { 67 return nil, err 68 } 69 70 // See https://usnistgov.github.io/ACVP/draft-celi-acvp-kdf-tls.html 71 var ret []tlsKDFTestGroupResponse 72 for _, group := range parsed.Groups { 73 response := tlsKDFTestGroupResponse{ 74 ID: group.ID, 75 } 76 77 var tlsVer string 78 switch group.TLSVersion { 79 case "v1.0/1.1": 80 tlsVer = "1.0" 81 case "v1.2": 82 tlsVer = "1.2" 83 default: 84 return nil, fmt.Errorf("unknown TLS version %q", group.TLSVersion) 85 } 86 87 hashIsTLS10 := false 88 switch group.Hash { 89 case "SHA-1": 90 hashIsTLS10 = true 91 case "SHA2-256", "SHA2-384", "SHA2-512": 92 break 93 default: 94 return nil, fmt.Errorf("unknown hash %q", group.Hash) 95 } 96 97 if (tlsVer == "1.0") != hashIsTLS10 { 98 return nil, fmt.Errorf("hash %q not permitted with TLS version %q", group.Hash, group.TLSVersion) 99 } 100 101 if group.KeyBlockBits%8 != 0 { 102 return nil, fmt.Errorf("requested key-block length (%d bits) is not a whole number of bytes", group.KeyBlockBits) 103 } 104 105 method := "TLSKDF/" + tlsVer + "/" + group.Hash 106 107 for _, test := range group.Tests { 108 pms, err := hex.DecodeString(test.PMSHex) 109 if err != nil { 110 return nil, err 111 } 112 113 clientHelloRandom, err := hex.DecodeString(test.ClientHelloRandomHex) 114 if err != nil { 115 return nil, err 116 } 117 118 serverHelloRandom, err := hex.DecodeString(test.ServerHelloRandomHex) 119 if err != nil { 120 return nil, err 121 } 122 123 clientRandom, err := hex.DecodeString(test.ClientRandomHex) 124 if err != nil { 125 return nil, err 126 } 127 128 serverRandom, err := hex.DecodeString(test.ServerRandomHex) 129 if err != nil { 130 return nil, err 131 } 132 133 const ( 134 masterSecretLength = 48 135 masterSecretLabel = "master secret" 136 keyBlockLabel = "key expansion" 137 ) 138 139 var outLenBytes [4]byte 140 binary.LittleEndian.PutUint32(outLenBytes[:], uint32(masterSecretLength)) 141 result, err := m.Transact(method, 1, outLenBytes[:], pms, []byte(masterSecretLabel), clientHelloRandom, serverHelloRandom) 142 if err != nil { 143 return nil, err 144 } 145 146 binary.LittleEndian.PutUint32(outLenBytes[:], uint32(group.KeyBlockBits/8)) 147 // TLS 1.0, 1.1, and 1.2 use a different order for the client and server 148 // randoms when computing the key block. 149 result2, err := m.Transact(method, 1, outLenBytes[:], result[0], []byte(keyBlockLabel), serverRandom, clientRandom) 150 if err != nil { 151 return nil, err 152 } 153 154 response.Tests = append(response.Tests, tlsKDFTestResponse{ 155 ID: test.ID, 156 MasterSecretHex: hex.EncodeToString(result[0]), 157 KeyBlockHex: hex.EncodeToString(result2[0]), 158 }) 159 } 160 161 ret = append(ret, response) 162 } 163 164 return ret, nil 165} 166