| // Copyright (c) 2020, Google Inc. |
| // |
| // Permission to use, copy, modify, and/or distribute this software for any |
| // purpose with or without fee is hereby granted, provided that the above |
| // copyright notice and this permission notice appear in all copies. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| |
| package subprocess |
| |
| import ( |
| "encoding/hex" |
| "encoding/json" |
| "fmt" |
| ) |
| |
| // See https://usnistgov.github.io/ACVP/draft-celi-acvp-rsa.html#section-7.4 |
| // although, at the time of writing, that spec doesn't match what the NIST demo |
| // server actually produces. This code matches the server. |
| |
| type rsaTestVectorSet struct { |
| Mode string `json:"mode"` |
| } |
| |
| type rsaKeyGenTestVectorSet struct { |
| Groups []rsaKeyGenGroup `json:"testGroups"` |
| } |
| |
| type rsaKeyGenGroup struct { |
| ID uint64 `json:"tgId"` |
| Type string `json:"testType"` |
| ModulusBits uint32 `json:"modulo"` |
| Tests []rsaKeyGenTest `json:"tests"` |
| } |
| |
| type rsaKeyGenTest struct { |
| ID uint64 `json:"tcId"` |
| } |
| |
| type rsaKeyGenTestGroupResponse struct { |
| ID uint64 `json:"tgId"` |
| Tests []rsaKeyGenTestResponse `json:"tests"` |
| } |
| |
| type rsaKeyGenTestResponse struct { |
| ID uint64 `json:"tcId"` |
| E string `json:"e"` |
| P string `json:"p"` |
| Q string `json:"q"` |
| N string `json:"n"` |
| D string `json:"d"` |
| } |
| |
| type rsaSigGenTestVectorSet struct { |
| Groups []rsaSigGenGroup `json:"testGroups"` |
| } |
| |
| type rsaSigGenGroup struct { |
| ID uint64 `json:"tgId"` |
| Type string `json:"testType"` |
| SigType string `json:"sigType"` |
| ModulusBits uint32 `json:"modulo"` |
| Hash string `json:"hashAlg"` |
| Tests []rsaSigGenTest `json:"tests"` |
| } |
| |
| type rsaSigGenTest struct { |
| ID uint64 `json:"tcId"` |
| MessageHex string `json:"message"` |
| } |
| |
| type rsaSigGenTestGroupResponse struct { |
| ID uint64 `json:"tgId"` |
| N string `json:"n"` |
| E string `json:"e"` |
| Tests []rsaSigGenTestResponse `json:"tests"` |
| } |
| |
| type rsaSigGenTestResponse struct { |
| ID uint64 `json:"tcId"` |
| Sig string `json:"signature"` |
| } |
| |
| type rsaSigVerTestVectorSet struct { |
| Groups []rsaSigVerGroup `json:"testGroups"` |
| } |
| |
| type rsaSigVerGroup struct { |
| ID uint64 `json:"tgId"` |
| Type string `json:"testType"` |
| SigType string `json:"sigType"` |
| Hash string `json:"hashAlg"` |
| N string `json:"n"` |
| E string `json:"e"` |
| Tests []rsaSigVerTest `json:"tests"` |
| } |
| |
| type rsaSigVerTest struct { |
| ID uint64 `json:"tcId"` |
| MessageHex string `json:"message"` |
| SignatureHex string `json:"signature"` |
| } |
| |
| type rsaSigVerTestGroupResponse struct { |
| ID uint64 `json:"tgId"` |
| Tests []rsaSigVerTestResponse `json:"tests"` |
| } |
| |
| type rsaSigVerTestResponse struct { |
| ID uint64 `json:"tcId"` |
| Passed bool `json:"testPassed"` |
| } |
| |
| func processKeyGen(vectorSet []byte, m Transactable) (interface{}, error) { |
| var parsed rsaKeyGenTestVectorSet |
| if err := json.Unmarshal(vectorSet, &parsed); err != nil { |
| return nil, err |
| } |
| |
| var ret []rsaKeyGenTestGroupResponse |
| |
| for _, group := range parsed.Groups { |
| // GDT means "Generated data test", i.e. "please generate an RSA key". |
| const expectedType = "GDT" |
| if group.Type != expectedType { |
| return nil, fmt.Errorf("RSA KeyGen test group has type %q, but only generation tests (%q) are supported", group.Type, expectedType) |
| } |
| |
| response := rsaKeyGenTestGroupResponse{ |
| ID: group.ID, |
| } |
| |
| for _, test := range group.Tests { |
| results, err := m.Transact("RSA/keyGen", 5, uint32le(group.ModulusBits)) |
| if err != nil { |
| return nil, err |
| } |
| |
| response.Tests = append(response.Tests, rsaKeyGenTestResponse{ |
| ID: test.ID, |
| E: hex.EncodeToString(results[0]), |
| P: hex.EncodeToString(results[1]), |
| Q: hex.EncodeToString(results[2]), |
| N: hex.EncodeToString(results[3]), |
| D: hex.EncodeToString(results[4]), |
| }) |
| } |
| |
| ret = append(ret, response) |
| } |
| |
| return ret, nil |
| } |
| |
| func processSigGen(vectorSet []byte, m Transactable) (interface{}, error) { |
| var parsed rsaSigGenTestVectorSet |
| if err := json.Unmarshal(vectorSet, &parsed); err != nil { |
| return nil, err |
| } |
| |
| var ret []rsaSigGenTestGroupResponse |
| |
| for _, group := range parsed.Groups { |
| // GDT means "Generated data test", i.e. "please generate an RSA signature". |
| const expectedType = "GDT" |
| if group.Type != expectedType { |
| return nil, fmt.Errorf("RSA SigGen test group has type %q, but only generation tests (%q) are supported", group.Type, expectedType) |
| } |
| |
| response := rsaSigGenTestGroupResponse{ |
| ID: group.ID, |
| } |
| |
| operation := "RSA/sigGen/" + group.Hash + "/" + group.SigType |
| |
| for _, test := range group.Tests { |
| msg, err := hex.DecodeString(test.MessageHex) |
| if err != nil { |
| return nil, fmt.Errorf("test case %d/%d contains invalid hex: %s", group.ID, test.ID, err) |
| } |
| |
| results, err := m.Transact(operation, 3, uint32le(group.ModulusBits), msg) |
| if err != nil { |
| return nil, err |
| } |
| |
| if len(response.N) == 0 { |
| response.N = hex.EncodeToString(results[0]) |
| response.E = hex.EncodeToString(results[1]) |
| } else if response.N != hex.EncodeToString(results[0]) { |
| return nil, fmt.Errorf("module wrapper returned different RSA keys for the same SigGen configuration") |
| } |
| |
| response.Tests = append(response.Tests, rsaSigGenTestResponse{ |
| ID: test.ID, |
| Sig: hex.EncodeToString(results[2]), |
| }) |
| } |
| |
| ret = append(ret, response) |
| } |
| |
| return ret, nil |
| } |
| |
| func processSigVer(vectorSet []byte, m Transactable) (interface{}, error) { |
| var parsed rsaSigVerTestVectorSet |
| if err := json.Unmarshal(vectorSet, &parsed); err != nil { |
| return nil, err |
| } |
| |
| var ret []rsaSigVerTestGroupResponse |
| |
| for _, group := range parsed.Groups { |
| // GDT means "Generated data test", which makes no sense in this context. |
| const expectedType = "GDT" |
| if group.Type != expectedType { |
| return nil, fmt.Errorf("RSA SigVer test group has type %q, but only 'generation' tests (%q) are supported", group.Type, expectedType) |
| } |
| |
| n, err := hex.DecodeString(group.N) |
| if err != nil { |
| return nil, fmt.Errorf("test group %d contains invalid hex: %s", group.ID, err) |
| } |
| e, err := hex.DecodeString(group.E) |
| if err != nil { |
| return nil, fmt.Errorf("test group %d contains invalid hex: %s", group.ID, err) |
| } |
| |
| response := rsaSigVerTestGroupResponse{ |
| ID: group.ID, |
| } |
| |
| operation := "RSA/sigVer/" + group.Hash + "/" + group.SigType |
| |
| for _, test := range group.Tests { |
| msg, err := hex.DecodeString(test.MessageHex) |
| if err != nil { |
| return nil, fmt.Errorf("test case %d/%d contains invalid hex: %s", group.ID, test.ID, err) |
| } |
| sig, err := hex.DecodeString(test.SignatureHex) |
| if err != nil { |
| return nil, fmt.Errorf("test case %d/%d contains invalid hex: %s", group.ID, test.ID, err) |
| } |
| |
| results, err := m.Transact(operation, 1, n, e, msg, sig) |
| if err != nil { |
| return nil, err |
| } |
| |
| response.Tests = append(response.Tests, rsaSigVerTestResponse{ |
| ID: test.ID, |
| Passed: len(results[0]) == 1 && results[0][0] == 1, |
| }) |
| } |
| |
| ret = append(ret, response) |
| } |
| |
| return ret, nil |
| } |
| |
| type rsa struct{} |
| |
| func (*rsa) Process(vectorSet []byte, m Transactable) (interface{}, error) { |
| var parsed rsaTestVectorSet |
| if err := json.Unmarshal(vectorSet, &parsed); err != nil { |
| return nil, err |
| } |
| |
| switch parsed.Mode { |
| case "keyGen": |
| return processKeyGen(vectorSet, m) |
| case "sigGen": |
| return processSigGen(vectorSet, m) |
| case "sigVer": |
| return processSigVer(vectorSet, m) |
| default: |
| return nil, fmt.Errorf("Unknown RSA mode %q", parsed.Mode) |
| } |
| } |