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 "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) (interface{}, 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 response := kasDHTestGroupResponse{ 72 ID: group.ID, 73 } 74 75 var privateKeyGiven bool 76 switch group.Type { 77 case "AFT": 78 privateKeyGiven = false 79 case "VAL": 80 privateKeyGiven = true 81 default: 82 return nil, fmt.Errorf("unknown test type %q", group.Type) 83 } 84 85 switch group.Role { 86 case "initiator", "responder": 87 break 88 default: 89 return nil, fmt.Errorf("unknown role %q", group.Role) 90 } 91 92 if group.Scheme != "dhEphem" { 93 return nil, fmt.Errorf("unknown scheme %q", group.Scheme) 94 } 95 96 p, err := hex.DecodeString(group.PHex) 97 if err != nil { 98 return nil, err 99 } 100 101 q, err := hex.DecodeString(group.QHex) 102 if err != nil { 103 return nil, err 104 } 105 106 g, err := hex.DecodeString(group.GHex) 107 if err != nil { 108 return nil, err 109 } 110 111 const method = "FFDH" 112 for _, test := range group.Tests { 113 if len(test.PeerPublicHex) == 0 { 114 return nil, fmt.Errorf("%d/%d is missing peer's key", group.ID, test.ID) 115 } 116 117 peerPublic, err := hex.DecodeString(test.PeerPublicHex) 118 if err != nil { 119 return nil, err 120 } 121 122 if (len(test.PrivateKeyHex) != 0) != privateKeyGiven { 123 return nil, fmt.Errorf("%d/%d incorrect private key presence", group.ID, test.ID) 124 } 125 126 if privateKeyGiven { 127 privateKey, err := hex.DecodeString(test.PrivateKeyHex) 128 if err != nil { 129 return nil, err 130 } 131 132 publicKey, err := hex.DecodeString(test.PublicKeyHex) 133 if err != nil { 134 return nil, err 135 } 136 137 expectedOutput, err := hex.DecodeString(test.ResultHex) 138 if err != nil { 139 return nil, err 140 } 141 142 result, err := m.Transact(method, 2, p, q, g, peerPublic, privateKey, publicKey) 143 if err != nil { 144 return nil, err 145 } 146 147 ok := bytes.Equal(result[1], expectedOutput) 148 response.Tests = append(response.Tests, kasDHTestResponse{ 149 ID: test.ID, 150 Passed: &ok, 151 }) 152 } else { 153 result, err := m.Transact(method, 2, p, q, g, peerPublic, nil, nil) 154 if err != nil { 155 return nil, err 156 } 157 158 response.Tests = append(response.Tests, kasDHTestResponse{ 159 ID: test.ID, 160 LocalPublicHex: hex.EncodeToString(result[0]), 161 ResultHex: hex.EncodeToString(result[1]), 162 }) 163 } 164 } 165 166 ret = append(ret, response) 167 } 168 169 return ret, nil 170} 171