Change-Id: I4f4a89f97e2513d8b5b740620989b187a7b44a58 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/44386 Commit-Queue: Adam Langley <agl@google.com> Reviewed-by: David Benjamin <davidben@google.com>chromium-5359
parent
9ac743e0b4
commit
f0400014b3
3 changed files with 236 additions and 25 deletions
@ -0,0 +1,165 @@ |
||||
// Copyright (c) 2020, Google Inc.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package subprocess |
||||
|
||||
import ( |
||||
"encoding/binary" |
||||
"encoding/hex" |
||||
"encoding/json" |
||||
"fmt" |
||||
) |
||||
|
||||
type tlsKDFVectorSet struct { |
||||
Groups []tlsKDFTestGroup `json:"testGroups"` |
||||
} |
||||
|
||||
type tlsKDFTestGroup struct { |
||||
ID uint64 `json:"tgId"` |
||||
Hash string `json:"hashAlg"` |
||||
TLSVersion string `json:"tlsVersion"` |
||||
KeyBlockBits uint64 `json:"keyBlockLength"` |
||||
PMSLength uint64 `json:"preMasterSecretLength"` |
||||
Tests []tlsKDFTest `json:"tests"` |
||||
} |
||||
|
||||
type tlsKDFTest struct { |
||||
ID uint64 `json:"tcId"` |
||||
PMSHex string `json:"preMasterSecret"` |
||||
// ClientHelloRandomHex and ServerHelloRandomHex are used for deriving the
|
||||
// master secret. ClientRandomHex and ServerRandomHex are used for deriving the
|
||||
// key block. Having different values for these is not possible in a TLS
|
||||
// handshake unless you squint at a resumption handshake and somehow rederive
|
||||
// the master secret from the session information during resumption.
|
||||
ClientHelloRandomHex string `json:"clientHelloRandom"` |
||||
ServerHelloRandomHex string `json:"serverHelloRandom"` |
||||
ClientRandomHex string `json:"clientRandom"` |
||||
ServerRandomHex string `json:"serverRandom"` |
||||
} |
||||
|
||||
type tlsKDFTestGroupResponse struct { |
||||
ID uint64 `json:"tgId"` |
||||
Tests []tlsKDFTestResponse `json:"tests"` |
||||
} |
||||
|
||||
type tlsKDFTestResponse struct { |
||||
ID uint64 `json:"tcId"` |
||||
MasterSecretHex string `json:"masterSecret"` |
||||
KeyBlockHex string `json:"keyBlock"` |
||||
} |
||||
|
||||
type tlsKDF struct{} |
||||
|
||||
func (k *tlsKDF) Process(vectorSet []byte, m Transactable) (interface{}, error) { |
||||
var parsed tlsKDFVectorSet |
||||
if err := json.Unmarshal(vectorSet, &parsed); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// See https://usnistgov.github.io/ACVP/draft-celi-acvp-kdf-tls.html
|
||||
var ret []tlsKDFTestGroupResponse |
||||
for _, group := range parsed.Groups { |
||||
response := tlsKDFTestGroupResponse{ |
||||
ID: group.ID, |
||||
} |
||||
|
||||
var tlsVer string |
||||
switch group.TLSVersion { |
||||
case "v1.0/1.1": |
||||
tlsVer = "1.0" |
||||
case "v1.2": |
||||
tlsVer = "1.2" |
||||
default: |
||||
return nil, fmt.Errorf("unknown TLS version %q", group.TLSVersion) |
||||
} |
||||
|
||||
hashIsTLS10 := false |
||||
switch group.Hash { |
||||
case "SHA-1": |
||||
hashIsTLS10 = true |
||||
case "SHA2-256", "SHA2-384", "SHA2-512": |
||||
break |
||||
default: |
||||
return nil, fmt.Errorf("unknown hash %q", group.Hash) |
||||
} |
||||
|
||||
if (tlsVer == "1.0") != hashIsTLS10 { |
||||
return nil, fmt.Errorf("hash %q not permitted with TLS version %q", group.Hash, group.TLSVersion) |
||||
} |
||||
|
||||
if group.KeyBlockBits%8 != 0 { |
||||
return nil, fmt.Errorf("requested key-block length (%d bits) is not a whole number of bytes", group.KeyBlockBits) |
||||
} |
||||
|
||||
method := "TLSKDF/" + tlsVer + "/" + group.Hash |
||||
|
||||
for _, test := range group.Tests { |
||||
pms, err := hex.DecodeString(test.PMSHex) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
clientHelloRandom, err := hex.DecodeString(test.ClientHelloRandomHex) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
serverHelloRandom, err := hex.DecodeString(test.ServerHelloRandomHex) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
clientRandom, err := hex.DecodeString(test.ClientRandomHex) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
serverRandom, err := hex.DecodeString(test.ServerRandomHex) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
const ( |
||||
masterSecretLength = 48 |
||||
masterSecretLabel = "master secret" |
||||
keyBlockLabel = "key expansion" |
||||
) |
||||
|
||||
var outLenBytes [4]byte |
||||
binary.LittleEndian.PutUint32(outLenBytes[:], uint32(masterSecretLength)) |
||||
result, err := m.Transact(method, 1, outLenBytes[:], pms, []byte(masterSecretLabel), clientHelloRandom, serverHelloRandom) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
binary.LittleEndian.PutUint32(outLenBytes[:], uint32(group.KeyBlockBits/8)) |
||||
// TLS 1.0, 1.1, and 1.2 use a different order for the client and server
|
||||
// randoms when computing the key block.
|
||||
result2, err := m.Transact(method, 1, outLenBytes[:], result[0], []byte(keyBlockLabel), serverRandom, clientRandom) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
response.Tests = append(response.Tests, tlsKDFTestResponse{ |
||||
ID: test.ID, |
||||
MasterSecretHex: hex.EncodeToString(result[0]), |
||||
KeyBlockHex: hex.EncodeToString(result2[0]), |
||||
}) |
||||
} |
||||
|
||||
ret = append(ret, response) |
||||
} |
||||
|
||||
return ret, nil |
||||
} |
Loading…
Reference in new issue