1package subprocess 2 3import ( 4 "encoding/hex" 5 "encoding/json" 6 "fmt" 7) 8 9// The following structures reflect the JSON of KDF SSH tests. See 10// https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#name-test-vectors 11 12type sshTestVectorSet struct { 13 Algorithm string `json:"algorithm"` 14 Mode string `json:"mode"` 15 Groups []sshTestGroup `json:"testGroups"` 16} 17 18type sshTestGroup struct { 19 ID uint64 `json:"tgId"` 20 TestType string `json:"testType"` 21 HashAlg string `json:"hashAlg"` 22 Cipher string `json:"cipher"` 23 Tests []struct { 24 ID uint64 `json:"tcId"` 25 KHex string `json:"k"` 26 HHex string `json:"h"` 27 SessionIDHex string `json:"sessionID"` 28 } `json:"tests"` 29} 30 31type sshTestGroupResponse struct { 32 ID uint64 `json:"tgId"` 33 Tests []sshTestResponse `json:"tests"` 34} 35 36type sshTestResponse struct { 37 ID uint64 `json:"tcId"` 38 InitialIvClientHex string `json:"initialIvClient"` 39 InitialIvServerHex string `json:"initialIvServer"` 40 EncryptionKeyClientHex string `json:"encryptionKeyClient"` 41 EncryptionKeyServerHex string `json:"encryptionKeyServer"` 42 IntegrityKeyClientHex string `json:"integrityKeyClient"` 43 IntegrityKeyServerHex string `json:"integrityKeyServer"` 44} 45 46type ssh struct { 47} 48 49func (s *ssh) Process(vectorSet []byte, m Transactable) (any, error) { 50 var parsed sshTestVectorSet 51 if err := json.Unmarshal(vectorSet, &parsed); err != nil { 52 return nil, err 53 } 54 55 if parsed.Algorithm != "kdf-components" { 56 return nil, fmt.Errorf("unexpected algorithm: %q", parsed.Algorithm) 57 } 58 if parsed.Mode != "ssh" { 59 return nil, fmt.Errorf("unexpected mode: %q", parsed.Mode) 60 } 61 62 var ret []sshTestGroupResponse 63 for _, group := range parsed.Groups { 64 group := group 65 66 // Only the AFT test type is specified for SSH: 67 // https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#name-test-types 68 if group.TestType != "AFT" { 69 return nil, fmt.Errorf("test group %d had unexpected test type: %q", group.ID, group.TestType) 70 } 71 72 response := sshTestGroupResponse{ 73 ID: group.ID, 74 } 75 76 for _, test := range group.Tests { 77 test := test 78 79 resp := sshTestResponse{ 80 ID: test.ID, 81 } 82 83 k, err := hex.DecodeString(test.KHex) 84 if err != nil { 85 return nil, fmt.Errorf("failed to decode K hex in test case %d/%d: %s", group.ID, test.ID, err) 86 } 87 h, err := hex.DecodeString(test.HHex) 88 if err != nil { 89 return nil, fmt.Errorf("failed to decode H hex in test case %d/%d: %s", group.ID, test.ID, err) 90 } 91 sessionID, err := hex.DecodeString(test.SessionIDHex) 92 if err != nil { 93 return nil, fmt.Errorf("failed to decode session ID hex in test case %d/%d: %s", group.ID, test.ID, err) 94 } 95 96 cmd := fmt.Sprintf("SSHKDF/%s/client", group.HashAlg) 97 m.TransactAsync(cmd, 3, [][]byte{k, h, sessionID, []byte(group.Cipher)}, func(result [][]byte) error { 98 resp.InitialIvClientHex = hex.EncodeToString(result[0]) 99 resp.EncryptionKeyClientHex = hex.EncodeToString(result[1]) 100 resp.IntegrityKeyClientHex = hex.EncodeToString(result[2]) 101 return nil 102 }) 103 104 cmd = fmt.Sprintf("SSHKDF/%s/server", group.HashAlg) 105 m.TransactAsync(cmd, 3, [][]byte{k, h, sessionID, []byte(group.Cipher)}, func(result [][]byte) error { 106 resp.InitialIvServerHex = hex.EncodeToString(result[0]) 107 resp.EncryptionKeyServerHex = hex.EncodeToString(result[1]) 108 resp.IntegrityKeyServerHex = hex.EncodeToString(result[2]) 109 return nil 110 }) 111 112 m.Barrier(func() { 113 response.Tests = append(response.Tests, resp) 114 }) 115 } 116 117 m.Barrier(func() { 118 ret = append(ret, response) 119 }) 120 } 121 122 if err := m.Flush(); err != nil { 123 return nil, err 124 } 125 126 return ret, nil 127} 128