|  | // Copyright 2023 The BoringSSL Authors | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     https://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | package subprocess | 
|  |  | 
|  | import ( | 
|  | "crypto/sha256" | 
|  | "crypto/sha512" | 
|  | "encoding/hex" | 
|  | "encoding/json" | 
|  | "fmt" | 
|  | ) | 
|  |  | 
|  | // The following structures reflect the JSON of TLS 1.3 tests. See | 
|  | // https://pages.nist.gov/ACVP/draft-hammett-acvp-kdf-tls-v1.3.html | 
|  |  | 
|  | type tls13TestVectorSet struct { | 
|  | Groups []tls13TestGroup `json:"testGroups"` | 
|  | } | 
|  |  | 
|  | type tls13TestGroup struct { | 
|  | ID       uint64      `json:"tgId"` | 
|  | HashFunc string      `json:"hmacAlg"` | 
|  | Tests    []tls13Test `json:"tests"` | 
|  | } | 
|  |  | 
|  | type tls13Test struct { | 
|  | ID uint64 `json:"tcId"` | 
|  | // Although ACVP refers to these as client and server randoms, these | 
|  | // fields are misnamed and really contain portions of the handshake | 
|  | // transcript. Concatenated in order, they give the transcript up to | 
|  | // the named message. In case of HelloRetryRequest, ClientHelloHex | 
|  | // includes up to the second ClientHello. | 
|  | ClientHelloHex    string `json:"helloClientRandom"` | 
|  | ServerHelloHex    string `json:"helloServerRandom"` | 
|  | ServerFinishedHex string `json:"finishedServerRandom"` | 
|  | ClientFinishedHex string `json:"finishedClientRandom"` | 
|  | DHEInputHex       string `json:"dhe"` | 
|  | PSKInputHex       string `json:"psk"` | 
|  | } | 
|  |  | 
|  | type tls13TestGroupResponse struct { | 
|  | ID    uint64              `json:"tgId"` | 
|  | Tests []tls13TestResponse `json:"tests"` | 
|  | } | 
|  |  | 
|  | type tls13TestResponse struct { | 
|  | ID                                uint64 `json:"tcId"` | 
|  | ClientEarlyTrafficSecretHex       string `json:"clientEarlyTrafficSecret"` | 
|  | EarlyExporterMasterSecretHex      string `json:"earlyExporterMasterSecret"` | 
|  | ClientHandshakeTrafficSecretHex   string `json:"clientHandshakeTrafficSecret"` | 
|  | ServerHandshakeTrafficSecretHex   string `json:"serverHandshakeTrafficSecret"` | 
|  | ClientApplicationTrafficSecretHex string `json:"clientApplicationTrafficSecret"` | 
|  | ServerApplicationTrafficSecretHex string `json:"serverApplicationTrafficSecret"` | 
|  | ExporterMasterSecretHex           string `json:"exporterMasterSecret"` | 
|  | ResumptionMasterSecretHex         string `json:"resumptionMasterSecret"` | 
|  | } | 
|  |  | 
|  | type tls13 struct{} | 
|  |  | 
|  | func (k *tls13) Process(vectorSet []byte, m Transactable) (any, error) { | 
|  | var parsed tls13TestVectorSet | 
|  | if err := json.Unmarshal(vectorSet, &parsed); err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | var respGroups []tls13TestGroupResponse | 
|  | for _, group := range parsed.Groups { | 
|  | group := group | 
|  | groupResp := tls13TestGroupResponse{ID: group.ID} | 
|  |  | 
|  | for _, test := range group.Tests { | 
|  | test := test | 
|  | testResp := tls13TestResponse{ID: test.ID} | 
|  |  | 
|  | clientHello, err := hex.DecodeString(test.ClientHelloHex) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | serverHello, err := hex.DecodeString(test.ServerHelloHex) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | serverFinished, err := hex.DecodeString(test.ServerFinishedHex) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | clientFinished, err := hex.DecodeString(test.ClientFinishedHex) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | // See https://www.rfc-editor.org/rfc/rfc8446#section-7.1 | 
|  | var hashLen int | 
|  | var emptyHash []byte | 
|  | switch group.HashFunc { | 
|  | case "SHA2-256": | 
|  | hashLen = 256 / 8 | 
|  | digest := sha256.Sum256(nil) | 
|  | emptyHash = digest[:] | 
|  | case "SHA2-384": | 
|  | hashLen = 384 / 8 | 
|  | digest := sha512.Sum384(nil) | 
|  | emptyHash = digest[:] | 
|  | default: | 
|  | return nil, fmt.Errorf("hash function %q is not supported for TLS v1.3", group.HashFunc) | 
|  | } | 
|  | hashLenBytes := uint32le(uint32(hashLen)) | 
|  |  | 
|  | psk, err := hex.DecodeString(test.PSKInputHex) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | if len(psk) == 0 { | 
|  | psk = make([]byte, hashLen) | 
|  | } | 
|  |  | 
|  | dhe, err := hex.DecodeString(test.DHEInputHex) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | if len(dhe) == 0 { | 
|  | dhe = make([]byte, hashLen) | 
|  | } | 
|  |  | 
|  | zeros := make([]byte, hashLen) | 
|  | earlySecret, err := m.Transact("HKDFExtract/"+group.HashFunc, 1, psk, zeros) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExtract operation failed: %s", err) | 
|  | } | 
|  |  | 
|  | hashedToClientHello, err := m.Transact(group.HashFunc, 1, clientHello) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("%q operation failed: %s", group.HashFunc, err) | 
|  | } | 
|  | hashedToServerHello, err := m.Transact(group.HashFunc, 1, concat(clientHello, serverHello)) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("%q operation failed: %s", group.HashFunc, err) | 
|  | } | 
|  | hashedToServerFinished, err := m.Transact(group.HashFunc, 1, concat(clientHello, serverHello, serverFinished)) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("%q operation failed: %s", group.HashFunc, err) | 
|  | } | 
|  | hashedMessages, err := m.Transact(group.HashFunc, 1, concat(clientHello, serverHello, serverFinished, clientFinished)) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("%q operation failed: %s", group.HashFunc, err) | 
|  | } | 
|  |  | 
|  | clientEarlyTrafficSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, earlySecret[0], []byte("c e traffic"), hashedToClientHello[0]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) | 
|  | } | 
|  | testResp.ClientEarlyTrafficSecretHex = hex.EncodeToString(clientEarlyTrafficSecret[0]) | 
|  |  | 
|  | earlyExporter, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, earlySecret[0], []byte("e exp master"), hashedToClientHello[0]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) | 
|  | } | 
|  | testResp.EarlyExporterMasterSecretHex = hex.EncodeToString(earlyExporter[0]) | 
|  |  | 
|  | derivedSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, earlySecret[0], []byte("derived"), emptyHash[:]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) | 
|  | } | 
|  |  | 
|  | handshakeSecret, err := m.Transact("HKDFExtract/"+group.HashFunc, 1, dhe, derivedSecret[0]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExtract operation failed: %s", err) | 
|  | } | 
|  |  | 
|  | clientHandshakeTrafficSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, handshakeSecret[0], []byte("c hs traffic"), hashedToServerHello[0]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) | 
|  | } | 
|  | testResp.ClientHandshakeTrafficSecretHex = hex.EncodeToString(clientHandshakeTrafficSecret[0]) | 
|  |  | 
|  | serverHandshakeTrafficSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, handshakeSecret[0], []byte("s hs traffic"), hashedToServerHello[0]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) | 
|  | } | 
|  | testResp.ServerHandshakeTrafficSecretHex = hex.EncodeToString(serverHandshakeTrafficSecret[0]) | 
|  |  | 
|  | derivedSecret, err = m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, handshakeSecret[0], []byte("derived"), emptyHash[:]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) | 
|  | } | 
|  |  | 
|  | masterSecret, err := m.Transact("HKDFExtract/"+group.HashFunc, 1, zeros, derivedSecret[0]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExtract operation failed: %s", err) | 
|  | } | 
|  |  | 
|  | clientAppTrafficSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, masterSecret[0], []byte("c ap traffic"), hashedToServerFinished[0]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) | 
|  | } | 
|  | testResp.ClientApplicationTrafficSecretHex = hex.EncodeToString(clientAppTrafficSecret[0]) | 
|  |  | 
|  | serverAppTrafficSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, masterSecret[0], []byte("s ap traffic"), hashedToServerFinished[0]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) | 
|  | } | 
|  | testResp.ServerApplicationTrafficSecretHex = hex.EncodeToString(serverAppTrafficSecret[0]) | 
|  |  | 
|  | exporterSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, masterSecret[0], []byte("exp master"), hashedToServerFinished[0]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) | 
|  | } | 
|  | testResp.ExporterMasterSecretHex = hex.EncodeToString(exporterSecret[0]) | 
|  |  | 
|  | resumptionSecret, err := m.Transact("HKDFExpandLabel/"+group.HashFunc, 1, hashLenBytes, masterSecret[0], []byte("res master"), hashedMessages[0]) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("HKDFExpandLabel operation failed: %s", err) | 
|  | } | 
|  | testResp.ResumptionMasterSecretHex = hex.EncodeToString(resumptionSecret[0]) | 
|  |  | 
|  | groupResp.Tests = append(groupResp.Tests, testResp) | 
|  | } | 
|  | respGroups = append(respGroups, groupResp) | 
|  | } | 
|  |  | 
|  | return respGroups, nil | 
|  | } | 
|  |  | 
|  | func concat(slices ...[]byte) []byte { | 
|  | var ret []byte | 
|  | for _, slice := range slices { | 
|  | ret = append(ret, slice...) | 
|  | } | 
|  | return ret | 
|  | } |