blob: 1a9df28add9ad4c1dbbe9c3258396cb7ae33f142 [file] [log] [blame]
package subprocess
import (
"encoding/hex"
"encoding/json"
"fmt"
)
// The following structures reflect the JSON of KDF SSH tests. See
// https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#name-test-vectors
type sshTestVectorSet struct {
Algorithm string `json:"algorithm"`
Mode string `json:"mode"`
Groups []sshTestGroup `json:"testGroups"`
}
type sshTestGroup struct {
ID uint64 `json:"tgId"`
TestType string `json:"testType"`
HashAlg string `json:"hashAlg"`
Cipher string `json:"cipher"`
Tests []struct {
ID uint64 `json:"tcId"`
KHex string `json:"k"`
HHex string `json:"h"`
SessionIDHex string `json:"sessionID"`
} `json:"tests"`
}
type sshTestGroupResponse struct {
ID uint64 `json:"tgId"`
Tests []sshTestResponse `json:"tests"`
}
type sshTestResponse struct {
ID uint64 `json:"tcId"`
InitialIvClientHex string `json:"initialIvClient"`
InitialIvServerHex string `json:"initialIvServer"`
EncryptionKeyClientHex string `json:"encryptionKeyClient"`
EncryptionKeyServerHex string `json:"encryptionKeyServer"`
IntegrityKeyClientHex string `json:"integrityKeyClient"`
IntegrityKeyServerHex string `json:"integrityKeyServer"`
}
type ssh struct {
}
func (s *ssh) Process(vectorSet []byte, m Transactable) (any, error) {
var parsed sshTestVectorSet
if err := json.Unmarshal(vectorSet, &parsed); err != nil {
return nil, err
}
if parsed.Algorithm != "kdf-components" {
return nil, fmt.Errorf("unexpected algorithm: %q", parsed.Algorithm)
}
if parsed.Mode != "ssh" {
return nil, fmt.Errorf("unexpected mode: %q", parsed.Mode)
}
var ret []sshTestGroupResponse
for _, group := range parsed.Groups {
group := group
// Only the AFT test type is specified for SSH:
// https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#name-test-types
if group.TestType != "AFT" {
return nil, fmt.Errorf("test group %d had unexpected test type: %q", group.ID, group.TestType)
}
response := sshTestGroupResponse{
ID: group.ID,
}
for _, test := range group.Tests {
test := test
resp := sshTestResponse{
ID: test.ID,
}
k, err := hex.DecodeString(test.KHex)
if err != nil {
return nil, fmt.Errorf("failed to decode K hex in test case %d/%d: %s", group.ID, test.ID, err)
}
h, err := hex.DecodeString(test.HHex)
if err != nil {
return nil, fmt.Errorf("failed to decode H hex in test case %d/%d: %s", group.ID, test.ID, err)
}
sessionID, err := hex.DecodeString(test.SessionIDHex)
if err != nil {
return nil, fmt.Errorf("failed to decode session ID hex in test case %d/%d: %s", group.ID, test.ID, err)
}
cmd := fmt.Sprintf("SSHKDF/%s/client", group.HashAlg)
m.TransactAsync(cmd, 3, [][]byte{k, h, sessionID, []byte(group.Cipher)}, func(result [][]byte) error {
resp.InitialIvClientHex = hex.EncodeToString(result[0])
resp.EncryptionKeyClientHex = hex.EncodeToString(result[1])
resp.IntegrityKeyClientHex = hex.EncodeToString(result[2])
return nil
})
cmd = fmt.Sprintf("SSHKDF/%s/server", group.HashAlg)
m.TransactAsync(cmd, 3, [][]byte{k, h, sessionID, []byte(group.Cipher)}, func(result [][]byte) error {
resp.InitialIvServerHex = hex.EncodeToString(result[0])
resp.EncryptionKeyServerHex = hex.EncodeToString(result[1])
resp.IntegrityKeyServerHex = hex.EncodeToString(result[2])
return nil
})
m.Barrier(func() {
response.Tests = append(response.Tests, resp)
})
}
m.Barrier(func() {
ret = append(ret, response)
})
}
if err := m.Flush(); err != nil {
return nil, err
}
return ret, nil
}