Add a CAVP tool for ECDSA2 SigVer tests. Change-Id: If3510b207793870f330c8981ef8e996949042fdc Reviewed-on: https://boringssl-review.googlesource.com/15668 Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/fipsoracle/CMakeLists.txt b/crypto/fipsoracle/CMakeLists.txt index 68ac252..769b29e 100644 --- a/crypto/fipsoracle/CMakeLists.txt +++ b/crypto/fipsoracle/CMakeLists.txt
@@ -25,7 +25,16 @@ $<TARGET_OBJECTS:test_support> ) + add_executable( + cavp_ecdsa2_sigver_test + + cavp_ecdsa2_sigver_test.cc + cavp_test_util.cc + $<TARGET_OBJECTS:test_support> + ) + target_link_libraries(cavp_aes_test crypto) target_link_libraries(cavp_aes_gcm_test crypto) target_link_libraries(cavp_ecdsa2_pkv_test crypto) + target_link_libraries(cavp_ecdsa2_sigver_test crypto) endif()
diff --git a/crypto/fipsoracle/cavp_ecdsa2_sigver_test.cc b/crypto/fipsoracle/cavp_ecdsa2_sigver_test.cc new file mode 100644 index 0000000..e18016a --- /dev/null +++ b/crypto/fipsoracle/cavp_ecdsa2_sigver_test.cc
@@ -0,0 +1,88 @@ +/* Copyright (c) 2017, 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. */ + +// cavp_ecdsa2_sigver_test processes a NIST CAVP ECDSA2 SigVer test vector +// request file and emits the corresponding response. An optional sample vector +// file can be passed to verify the result. + +#include <vector> + +#include <openssl/bn.h> +#include <openssl/crypto.h> +#include <openssl/digest.h> +#include <openssl/ec_key.h> +#include <openssl/ecdsa.h> +#include <openssl/err.h> +#include <openssl/nid.h> + +#include "../test/file_test.h" +#include "cavp_test_util.h" + + +static bool TestECDSA2SigVer(FileTest *t, void *arg) { + int nid = GetECGroupNIDFromInstruction(t); + const EVP_MD *md = GetDigestFromInstruction(t); + if (nid == NID_undef || md == nullptr) { + return false; + } + bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new()); + bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid)); + bssl::UniquePtr<BIGNUM> qx = GetBIGNUM(t, "Qx"); + bssl::UniquePtr<BIGNUM> qy = GetBIGNUM(t, "Qy"); + bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R"); + bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S"); + std::vector<uint8_t> msg; + uint8_t digest[EVP_MAX_MD_SIZE]; + unsigned digest_len; + if (!sig || !key || !qx || !qy || !r || !s || + !EC_KEY_set_public_key_affine_coordinates(key.get(), qx.get(), + qy.get()) || + !t->GetBytes(&msg, "Msg") || + !EVP_Digest(msg.data(), msg.size(), digest, &digest_len, md, nullptr)) { + return false; + } + + BN_free(sig->r); + sig->r = r.release(); + BN_free(sig->s); + sig->s = s.release(); + + if (ECDSA_do_verify(digest, digest_len, sig.get(), key.get())) { + printf("%sResult = P\r\n\r\n", t->CurrentTestToString().c_str()); + } else { + char buf[256]; + ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); + printf("%sResult = F (%s)\r\n\r\n", t->CurrentTestToString().c_str(), buf); + } + ERR_clear_error(); + return true; +} + +int main(int argc, char **argv) { + CRYPTO_library_init(); + + if (argc != 2) { + fprintf(stderr, "usage: %s <test file>\n", + argv[0]); + return 1; + } + + printf("# Generated by"); + for (int i = 0; i < argc; i++) { + printf(" %s", argv[i]); + } + printf("\r\n\r\n"); + + return FileTestMainSilent(TestECDSA2SigVer, nullptr, argv[1]); +}
diff --git a/crypto/fipsoracle/cavp_test_util.cc b/crypto/fipsoracle/cavp_test_util.cc index 39bc773..c3d2cdf 100644 --- a/crypto/fipsoracle/cavp_test_util.cc +++ b/crypto/fipsoracle/cavp_test_util.cc
@@ -15,6 +15,7 @@ #include "cavp_test_util.h" #include <openssl/bn.h> +#include <openssl/digest.h> #include <openssl/ec.h> #include <openssl/nid.h> @@ -196,3 +197,23 @@ t->PrintLine("No supported group specified."); return NID_undef; } + +const EVP_MD *GetDigestFromInstruction(FileTest *t) { + if (t->HasInstruction("SHA-1")) { + return EVP_sha1(); + } + if (t->HasInstruction("SHA-224")) { + return EVP_sha224(); + } + if (t->HasInstruction("SHA-256")) { + return EVP_sha256(); + } + if (t->HasInstruction("SHA-384")) { + return EVP_sha384(); + } + if (t->HasInstruction("SHA-512")) { + return EVP_sha512(); + } + t->PrintLine("No supported digest function specified."); + return nullptr; +}
diff --git a/crypto/fipsoracle/cavp_test_util.h b/crypto/fipsoracle/cavp_test_util.h index fa7ac32..1402eff 100644 --- a/crypto/fipsoracle/cavp_test_util.h +++ b/crypto/fipsoracle/cavp_test_util.h
@@ -50,5 +50,7 @@ int GetECGroupNIDFromInstruction(FileTest *t); +const EVP_MD *GetDigestFromInstruction(FileTest *t); + #endif // OPENSSL_HEADER_CRYPTO_FIPSMODULE_CAVP_TEST_UTIL_H
diff --git a/crypto/fipsoracle/run_cavp.go b/crypto/fipsoracle/run_cavp.go index 08b6400..21c9c0a 100644 --- a/crypto/fipsoracle/run_cavp.go +++ b/crypto/fipsoracle/run_cavp.go
@@ -101,10 +101,17 @@ []test{{"PKV", nil, false}}, } +var ecdsa2SigVerTests = testSuite{ + "ECDSA2", + "cavp_ecdsa2_sigver_test", + []test{{"SigVer", nil, false}}, +} + var allTestSuites = []*testSuite{ &aesGCMTests, &aesTests, &ecdsa2PKVTests, + &ecdsa2SigVerTests, } func main() {
diff --git a/crypto/test/file_test.cc b/crypto/test/file_test.cc index 4f319f2..b330315 100644 --- a/crypto/test/file_test.cc +++ b/crypto/test/file_test.cc
@@ -151,9 +151,18 @@ current_test_ += kv + "\r\n"; kv = std::string(kv.begin() + 1, kv.end() - 1); - std::string key, value; - std::tie(key, value) = ParseKeyValue(kv.c_str(), kv.size()); - instructions_[key] = value; + for (;;) { + size_t idx = kv.find(","); + if (idx == std::string::npos) { + idx = kv.size(); + } + std::string key, value; + std::tie(key, value) = ParseKeyValue(kv.c_str(), idx); + instructions_[key] = value; + if (idx == kv.size()) + break; + kv = kv.substr(idx + 1); + } } else if (buf[0] != '#') { // Comment lines are ignored. if (in_instruction_block) { // Test cases should be separate blocks.
diff --git a/crypto/test/file_test.h b/crypto/test/file_test.h index 18d7e99..aac9289 100644 --- a/crypto/test/file_test.h +++ b/crypto/test/file_test.h
@@ -49,6 +49,15 @@ // // [Name] // +// Commas in instruction lines are treated as separate instructions. Thus this: +// +// [Name1,Name2] +// +// is the same as: +// +// [Name1] +// [Name2] +// // Either '=' or ':' may be used to delimit the name from the value. Both the // name and value have leading and trailing spaces stripped. //