1// Copyright 2020 The BoringSSL Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package subprocess 16 17import ( 18 "bytes" 19 "encoding/hex" 20 "encoding/json" 21 "fmt" 22) 23 24type kasDHVectorSet struct { 25 Groups []kasDHTestGroup `json:"testGroups"` 26} 27 28type kasDHTestGroup struct { 29 ID uint64 `json:"tgId"` 30 Type string `json:"testType"` 31 Role string `json:"kasRole"` 32 Mode string `json:"kasMode"` 33 Scheme string `json:"scheme"` 34 PHex string `json:"p"` 35 QHex string `json:"q"` 36 GHex string `json:"g"` 37 Tests []kasDHTest `json:"tests"` 38} 39 40type kasDHTest struct { 41 ID uint64 `json:"tcId"` 42 PeerPublicHex string `json:"ephemeralPublicServer"` 43 PrivateKeyHex string `json:"ephemeralPrivateIut"` 44 PublicKeyHex string `json:"ephemeralPublicIut"` 45 ResultHex string `json:"z"` 46} 47 48type kasDHTestGroupResponse struct { 49 ID uint64 `json:"tgId"` 50 Tests []kasDHTestResponse `json:"tests"` 51} 52 53type kasDHTestResponse struct { 54 ID uint64 `json:"tcId"` 55 LocalPublicHex string `json:"ephemeralPublicIut,omitempty"` 56 ResultHex string `json:"z,omitempty"` 57 Passed *bool `json:"testPassed,omitempty"` 58} 59 60type kasDH struct{} 61 62func (k *kasDH) Process(vectorSet []byte, m Transactable) (any, error) { 63 var parsed kasDHVectorSet 64 if err := json.Unmarshal(vectorSet, &parsed); err != nil { 65 return nil, err 66 } 67 68 // See https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ffc-sp800-56ar3.html 69 var ret []kasDHTestGroupResponse 70 for _, group := range parsed.Groups { 71 group := group 72 response := kasDHTestGroupResponse{ 73 ID: group.ID, 74 } 75 76 var privateKeyGiven bool 77 switch group.Type { 78 case "AFT": 79 privateKeyGiven = false 80 case "VAL": 81 privateKeyGiven = true 82 default: 83 return nil, fmt.Errorf("unknown test type %q", group.Type) 84 } 85 86 switch group.Role { 87 case "initiator", "responder": 88 break 89 default: 90 return nil, fmt.Errorf("unknown role %q", group.Role) 91 } 92 93 if group.Scheme != "dhEphem" { 94 return nil, fmt.Errorf("unknown scheme %q", group.Scheme) 95 } 96 97 p, err := hex.DecodeString(group.PHex) 98 if err != nil { 99 return nil, err 100 } 101 102 q, err := hex.DecodeString(group.QHex) 103 if err != nil { 104 return nil, err 105 } 106 107 g, err := hex.DecodeString(group.GHex) 108 if err != nil { 109 return nil, err 110 } 111 112 const method = "FFDH" 113 for _, test := range group.Tests { 114 test := test 115 116 if len(test.PeerPublicHex) == 0 { 117 return nil, fmt.Errorf("%d/%d is missing peer's key", group.ID, test.ID) 118 } 119 120 peerPublic, err := hex.DecodeString(test.PeerPublicHex) 121 if err != nil { 122 return nil, err 123 } 124 125 if (len(test.PrivateKeyHex) != 0) != privateKeyGiven { 126 return nil, fmt.Errorf("%d/%d incorrect private key presence", group.ID, test.ID) 127 } 128 129 if privateKeyGiven { 130 privateKey, err := hex.DecodeString(test.PrivateKeyHex) 131 if err != nil { 132 return nil, err 133 } 134 135 publicKey, err := hex.DecodeString(test.PublicKeyHex) 136 if err != nil { 137 return nil, err 138 } 139 140 expectedOutput, err := hex.DecodeString(test.ResultHex) 141 if err != nil { 142 return nil, err 143 } 144 145 m.TransactAsync(method, 2, [][]byte{p, q, g, peerPublic, privateKey, publicKey}, func(result [][]byte) error { 146 ok := bytes.Equal(result[1], expectedOutput) 147 response.Tests = append(response.Tests, kasDHTestResponse{ 148 ID: test.ID, 149 Passed: &ok, 150 }) 151 return nil 152 }) 153 } else { 154 m.TransactAsync(method, 2, [][]byte{p, q, g, peerPublic, nil, nil}, func(result [][]byte) error { 155 response.Tests = append(response.Tests, kasDHTestResponse{ 156 ID: test.ID, 157 LocalPublicHex: hex.EncodeToString(result[0]), 158 ResultHex: hex.EncodeToString(result[1]), 159 }) 160 return nil 161 }) 162 } 163 } 164 165 m.Barrier(func() { 166 ret = append(ret, response) 167 }) 168 } 169 170 if err := m.Flush(); err != nil { 171 return nil, err 172 } 173 174 return ret, nil 175} 176