acvp: support RSA key generation tests. Change-Id: I40bbf6d10fcfd1e0fb506bef44f4cd6e9d2daac5 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/43644 Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/util/fipstools/acvp/acvptool/subprocess/rsa.go b/util/fipstools/acvp/acvptool/subprocess/rsa.go new file mode 100644 index 0000000..3133d91 --- /dev/null +++ b/util/fipstools/acvp/acvptool/subprocess/rsa.go
@@ -0,0 +1,115 @@ +// 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"` +} + +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 +} + +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) + default: + return nil, fmt.Errorf("Unknown RSA mode %q", parsed.Mode) + } +}
diff --git a/util/fipstools/acvp/acvptool/subprocess/subprocess.go b/util/fipstools/acvp/acvptool/subprocess/subprocess.go index 76442fa..6f450d4 100644 --- a/util/fipstools/acvp/acvptool/subprocess/subprocess.go +++ b/util/fipstools/acvp/acvptool/subprocess/subprocess.go
@@ -94,6 +94,7 @@ "hmacDRBG": &drbg{"hmacDRBG", map[string]bool{"SHA-1": true, "SHA2-224": true, "SHA2-256": true, "SHA2-384": true, "SHA2-512": true}}, "KDF": &kdfPrimitive{}, "CMAC-AES": &keyedMACPrimitive{"CMAC-AES"}, + "RSA": &rsa{}, } m.primitives["ECDSA"] = &ecdsa{"ECDSA", map[string]bool{"P-224": true, "P-256": true, "P-384": true, "P-521": true}, m.primitives}
diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index c782f67..48b96da 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
@@ -34,6 +34,7 @@ #include <openssl/ecdsa.h> #include <openssl/hmac.h> #include <openssl/obj.h> +#include <openssl/rsa.h> #include <openssl/sha.h> #include <openssl/span.h> @@ -396,6 +397,34 @@ }] }, { + "algorithm": "RSA", + "mode": "keyGen", + "revision": "FIPS186-4", + "infoGeneratedByServer": true, + "pubExpMode": "fixed", + "fixedPubExp": "010001", + "keyFormat": "standard", + "capabilities": [{ + "randPQ": "B.3.3", + "properties": [{ + "modulo": 2048, + "primeTest": [ + "tblC2" + ] + },{ + "modulo": 3072, + "primeTest": [ + "tblC2" + ] + },{ + "modulo": 4096, + "primeTest": [ + "tblC2" + ] + }] + }] + }, + { "algorithm": "CMAC-AES", "revision": "1.0", "capabilities": [{ @@ -1003,6 +1032,28 @@ return WriteReply(STDOUT_FILENO, Span<const uint8_t>(mac, mac_len)); } +static bool RSAKeyGen(const Span<const uint8_t> args[]) { + uint32_t bits; + if (args[0].size() != sizeof(bits)) { + return false; + } + memcpy(&bits, args[0].data(), sizeof(bits)); + + bssl::UniquePtr<RSA> key(RSA_new()); + if (!RSA_generate_key_fips(key.get(), bits, nullptr)) { + fprintf(stderr, "RSA_generate_key_fips failed for modulus length %u.\n", + bits); + return false; + } + + const BIGNUM *n, *e, *d, *p, *q; + RSA_get0_key(key.get(), &n, &e, &d); + RSA_get0_factors(key.get(), &p, &q); + + return WriteReply(STDOUT_FILENO, BIGNUMBytes(e), BIGNUMBytes(p), + BIGNUMBytes(q), BIGNUMBytes(n), BIGNUMBytes(d)); +} + static constexpr struct { const char name[kMaxNameLength + 1]; uint8_t expected_args; @@ -1043,6 +1094,7 @@ {"ECDSA/sigGen", 4, ECDSASigGen}, {"ECDSA/sigVer", 7, ECDSASigVer}, {"CMAC-AES", 3, CMAC_AES}, + {"RSA/keyGen", 1, RSAKeyGen}, }; int main() {