Drop CAVP code.
All FIPS testing is done with ACVP now. We can delete all the CAVP stuff. Change-Id: I459873474e40b0371f9cf760090a130ef9a90a8c Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51330 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: Adam Langley <agl@google.com>
This commit is contained in:
committed by
Boringssl LUCI CQ
parent
d04c32a3d8
commit
ea9fb94c35
+1
-1
@@ -593,7 +593,7 @@ add_subdirectory(crypto)
|
||||
add_subdirectory(ssl)
|
||||
add_subdirectory(ssl/test)
|
||||
add_subdirectory(tool)
|
||||
add_subdirectory(util/fipstools/cavp)
|
||||
add_subdirectory(util/fipstools)
|
||||
add_subdirectory(util/fipstools/acvp/modulewrapper)
|
||||
add_subdirectory(decrepit)
|
||||
|
||||
|
||||
@@ -13,12 +13,9 @@ BoringCrypto has undergone the following validations:
|
||||
1. 2019-08-08: certificate [#3678](https://csrc.nist.gov/Projects/Cryptographic-Module-Validation-Program/Certificate/3678), [security policy](/crypto/fipsmodule/policydocs/BoringCrypto-Security-Policy-20190808.docx) (in docx format).
|
||||
1. 2019-10-20: certificate [#3753](https://csrc.nist.gov/Projects/Cryptographic-Module-Validation-Program/Certificate/3753), [security policy](/crypto/fipsmodule/policydocs/BoringCrypto-Android-Security-Policy-20191020.docx) (in docx format).
|
||||
|
||||
## Running CAVP tests
|
||||
## Running ACVP tests
|
||||
|
||||
CAVP results are calculated by `util/fipstools/cavp`, but that binary is almost always run by `util/fipstools/run_cavp.go`. The latter knows the set of tests to be processed and the flags needed to configure `cavp` for each one. It must be run from the top of a CAVP directory and needs the following options:
|
||||
|
||||
1. `-oracle-bin`: points to the location of `util/fipstools/cavp`
|
||||
2. `-no-fax`: this is needed to suppress checking of the FAX files, which are only included in sample sets.
|
||||
See `util/fipstools/acvp/ACVP.md` for details of how ACVP testing is done.
|
||||
|
||||
## Breaking known-answer and continuous tests
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
include_directories(../../include)
|
||||
|
||||
if(FIPS)
|
||||
add_executable(
|
||||
test_fips
|
||||
|
||||
test_fips.c
|
||||
)
|
||||
|
||||
add_dependencies(test_fips global_target)
|
||||
target_link_libraries(test_fips crypto)
|
||||
endif()
|
||||
@@ -1,42 +0,0 @@
|
||||
include_directories(../../../include)
|
||||
|
||||
if(FIPS)
|
||||
add_executable(
|
||||
cavp
|
||||
|
||||
cavp_main.cc
|
||||
|
||||
cavp_aes_gcm_test.cc
|
||||
cavp_aes_test.cc
|
||||
cavp_ctr_drbg_test.cc
|
||||
cavp_ecdsa2_keypair_test.cc
|
||||
cavp_ecdsa2_pkv_test.cc
|
||||
cavp_ecdsa2_siggen_test.cc
|
||||
cavp_ecdsa2_sigver_test.cc
|
||||
cavp_hmac_test.cc
|
||||
cavp_kas_test.cc
|
||||
cavp_keywrap_test.cc
|
||||
cavp_rsa2_keygen_test.cc
|
||||
cavp_rsa2_siggen_test.cc
|
||||
cavp_rsa2_sigver_test.cc
|
||||
cavp_sha_monte_test.cc
|
||||
cavp_sha_test.cc
|
||||
cavp_tdes_test.cc
|
||||
cavp_tlskdf_test.cc
|
||||
|
||||
cavp_test_util.cc
|
||||
)
|
||||
|
||||
add_dependencies(cavp global_target)
|
||||
|
||||
add_executable(
|
||||
test_fips
|
||||
|
||||
test_fips.c
|
||||
)
|
||||
|
||||
add_dependencies(test_fips global_target)
|
||||
|
||||
target_link_libraries(cavp test_support_lib crypto)
|
||||
target_link_libraries(test_fips test_support_lib crypto)
|
||||
endif()
|
||||
@@ -1,166 +0,0 @@
|
||||
/* 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_aes_gcm_test processes a NIST CAVP AES GCM test vector request file and
|
||||
// emits the corresponding response.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/aead.h>
|
||||
#include <openssl/cipher.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestCtx {
|
||||
const EVP_AEAD *aead;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static const EVP_AEAD *GetAEAD(const std::string &name, const bool enc) {
|
||||
if (name == "aes-128-gcm") {
|
||||
return EVP_aead_aes_128_gcm();
|
||||
} else if (name == "aes-192-gcm") {
|
||||
return EVP_aead_aes_192_gcm();
|
||||
} else if (name == "aes-256-gcm") {
|
||||
return EVP_aead_aes_256_gcm();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool TestAEADEncrypt(FileTest *t, void *arg) {
|
||||
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
|
||||
|
||||
std::string key_len_str, iv_len_str, pt_len_str, aad_len_str, tag_len_str;
|
||||
if (!t->GetInstruction(&key_len_str, "Keylen") ||
|
||||
!t->GetInstruction(&iv_len_str, "IVlen") ||
|
||||
!t->GetInstruction(&pt_len_str, "PTlen") ||
|
||||
!t->GetInstruction(&aad_len_str, "AADlen") ||
|
||||
!t->GetInstruction(&tag_len_str, "Taglen")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string count;
|
||||
std::vector<uint8_t> key, iv, pt, aad, tag, ct;
|
||||
if (!t->GetAttribute(&count, "Count") ||
|
||||
!t->GetBytes(&key, "Key") ||
|
||||
!t->GetBytes(&iv, "IV") ||
|
||||
!t->GetBytes(&pt, "PT") ||
|
||||
!t->GetBytes(&aad, "AAD") ||
|
||||
key.size() * 8 != strtoul(key_len_str.c_str(), nullptr, 0) ||
|
||||
iv.size() * 8 != strtoul(iv_len_str.c_str(), nullptr, 0) ||
|
||||
pt.size() * 8 != strtoul(pt_len_str.c_str(), nullptr, 0) ||
|
||||
aad.size() * 8 != strtoul(aad_len_str.c_str(), nullptr, 0) ||
|
||||
iv.size() != 12) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t tag_len = strtoul(tag_len_str.c_str(), nullptr, 0) / 8;
|
||||
if (!AEADEncrypt(ctx->aead, &ct, &tag, tag_len, key, pt, aad, iv)) {
|
||||
return false;
|
||||
}
|
||||
printf("%s", t->CurrentTestToString().c_str());
|
||||
printf("CT = %s\r\n", EncodeHex(ct).c_str());
|
||||
printf("Tag = %s\r\n\r\n", EncodeHex(tag).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestAEADDecrypt(FileTest *t, void *arg) {
|
||||
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
|
||||
|
||||
std::string key_len, iv_len, pt_len_str, aad_len_str, tag_len;
|
||||
if (!t->GetInstruction(&key_len, "Keylen") ||
|
||||
!t->GetInstruction(&iv_len, "IVlen") ||
|
||||
!t->GetInstruction(&pt_len_str, "PTlen") ||
|
||||
!t->GetInstruction(&aad_len_str, "AADlen") ||
|
||||
!t->GetInstruction(&tag_len, "Taglen")) {
|
||||
t->PrintLine("Invalid instruction block.");
|
||||
return false;
|
||||
}
|
||||
size_t aad_len = strtoul(aad_len_str.c_str(), nullptr, 0) / 8;
|
||||
size_t pt_len = strtoul(pt_len_str.c_str(), nullptr, 0) / 8;
|
||||
|
||||
std::string count;
|
||||
std::vector<uint8_t> key, iv, ct, aad, tag, pt;
|
||||
if (!t->GetAttribute(&count, "Count") ||
|
||||
!t->GetBytes(&key, "Key") ||
|
||||
!t->GetBytes(&aad, "AAD") ||
|
||||
!t->GetBytes(&tag, "Tag") ||
|
||||
!t->GetBytes(&iv, "IV") ||
|
||||
!t->GetBytes(&ct, "CT") ||
|
||||
key.size() * 8 != strtoul(key_len.c_str(), nullptr, 0) ||
|
||||
iv.size() * 8 != strtoul(iv_len.c_str(), nullptr, 0) ||
|
||||
ct.size() != pt_len ||
|
||||
aad.size() != aad_len ||
|
||||
tag.size() * 8 != strtoul(tag_len.c_str(), nullptr, 0)) {
|
||||
t->PrintLine("Invalid test case");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("%s", t->CurrentTestToString().c_str());
|
||||
bool aead_result =
|
||||
AEADDecrypt(ctx->aead, &pt, pt_len, key, aad, ct, tag, iv);
|
||||
if (aead_result) {
|
||||
printf("PT = %s\r\n\r\n", EncodeHex(pt).c_str());
|
||||
} else {
|
||||
printf("FAIL\r\n\r\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int usage(char *arg) {
|
||||
fprintf(stderr, "usage: %s (enc|dec) <cipher> <test file>\n", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cavp_aes_gcm_test_main(int argc, char **argv) {
|
||||
if (argc != 4) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
const std::string mode(argv[1]);
|
||||
bool (*test_fn)(FileTest * t, void *arg);
|
||||
if (mode == "enc") {
|
||||
test_fn = &TestAEADEncrypt;
|
||||
} else if (mode == "dec") {
|
||||
test_fn = &TestAEADDecrypt;
|
||||
} else {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
const EVP_AEAD *aead = GetAEAD(argv[2], mode == "enc");
|
||||
if (aead == nullptr) {
|
||||
fprintf(stderr, "invalid aead: %s\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TestCtx ctx = {aead};
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[3];
|
||||
opts.callback = test_fn;
|
||||
opts.arg = &ctx;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
/* 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_aes_test processes a NIST CAVP AES test vector request file and emits
|
||||
// the corresponding response.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/cipher.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestCtx {
|
||||
const EVP_CIPHER *cipher;
|
||||
bool has_iv;
|
||||
enum Mode {
|
||||
kKAT, // Known Answer Test
|
||||
kMCT, // Monte Carlo Test
|
||||
};
|
||||
Mode mode;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static bool MonteCarlo(const TestCtx *ctx, FileTest *t,
|
||||
const EVP_CIPHER *cipher, std::vector<uint8_t> *out,
|
||||
bool encrypt, std::vector<uint8_t> key,
|
||||
std::vector<uint8_t> iv, std::vector<uint8_t> in) {
|
||||
const std::string in_label = encrypt ? "PLAINTEXT" : "CIPHERTEXT",
|
||||
result_label = encrypt ? "CIPHERTEXT" : "PLAINTEXT";
|
||||
std::vector<uint8_t> prev_result, result, prev_in;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
printf("COUNT = %d\r\nKEY = %s\r\n", i, EncodeHex(key).c_str());
|
||||
if (ctx->has_iv) {
|
||||
printf("IV = %s\r\n", EncodeHex(iv).c_str());
|
||||
}
|
||||
printf("%s = %s\r\n", in_label.c_str(), EncodeHex(in).c_str());
|
||||
|
||||
if (!ctx->has_iv) { // ECB mode
|
||||
for (int j = 0; j < 1000; j++) {
|
||||
prev_result = result;
|
||||
if (!CipherOperation(cipher, &result, encrypt, key, iv, in)) {
|
||||
return false;
|
||||
}
|
||||
in = result;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < 1000; j++) {
|
||||
prev_result = result;
|
||||
if (j > 0) {
|
||||
if (encrypt) {
|
||||
iv = result;
|
||||
} else {
|
||||
iv = prev_in;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CipherOperation(cipher, &result, encrypt, key, iv, in)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
prev_in = in;
|
||||
|
||||
if (j == 0) {
|
||||
in = iv;
|
||||
} else {
|
||||
in = prev_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s = %s\r\n\r\n", result_label.c_str(), EncodeHex(result).c_str());
|
||||
|
||||
const size_t key_len = key.size() * 8;
|
||||
if (key_len == 128) {
|
||||
for (size_t k = 0; k < key.size(); k++) {
|
||||
key[k] ^= result[k];
|
||||
}
|
||||
} else if (key_len == 192) {
|
||||
for (size_t k = 0; k < key.size(); k++) {
|
||||
// Key[i+1] = Key[i] xor (last 64-bits of CT[j-1] || CT[j])
|
||||
if (k < 8) {
|
||||
key[k] ^= prev_result[prev_result.size() - 8 + k];
|
||||
} else {
|
||||
key[k] ^= result[k - 8];
|
||||
}
|
||||
}
|
||||
} else { // key_len == 256
|
||||
for (size_t k = 0; k < key.size(); k++) {
|
||||
// Key[i+1] = Key[i] xor (CT[j-1] || CT[j])
|
||||
if (k < 16) {
|
||||
key[k] ^= prev_result[k];
|
||||
} else {
|
||||
key[k] ^= result[k - 16];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->has_iv) {
|
||||
iv = result;
|
||||
in = prev_result;
|
||||
} else {
|
||||
in = result;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestCipher(FileTest *t, void *arg) {
|
||||
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
|
||||
|
||||
if (t->HasInstruction("ENCRYPT") == t->HasInstruction("DECRYPT")) {
|
||||
t->PrintLine("Want either ENCRYPT or DECRYPT");
|
||||
return false;
|
||||
}
|
||||
enum {
|
||||
kEncrypt,
|
||||
kDecrypt,
|
||||
} operation = t->HasInstruction("ENCRYPT") ? kEncrypt : kDecrypt;
|
||||
|
||||
std::string count;
|
||||
std::vector<uint8_t> key, iv, in, result;
|
||||
if (!t->GetAttribute(&count, "COUNT") ||
|
||||
!t->GetBytes(&key, "KEY") ||
|
||||
(ctx->has_iv && !t->GetBytes(&iv, "IV"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const EVP_CIPHER *cipher = ctx->cipher;
|
||||
if (operation == kEncrypt) {
|
||||
if (!t->GetBytes(&in, "PLAINTEXT")) {
|
||||
return false;
|
||||
}
|
||||
} else { // operation == kDecrypt
|
||||
if (!t->GetBytes(&in, "CIPHERTEXT")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->mode == TestCtx::kKAT) {
|
||||
if (!CipherOperation(cipher, &result, operation == kEncrypt, key, iv, in)) {
|
||||
return false;
|
||||
}
|
||||
const std::string label =
|
||||
operation == kEncrypt ? "CIPHERTEXT" : "PLAINTEXT";
|
||||
printf("%s%s = %s\r\n\r\n", t->CurrentTestToString().c_str(), label.c_str(),
|
||||
EncodeHex(result).c_str());
|
||||
} else { // ctx->mode == kMCT
|
||||
const std::string op_label =
|
||||
operation == kEncrypt ? "[ENCRYPT]" : "[DECRYPT]";
|
||||
printf("%s\r\n\r\n", op_label.c_str());
|
||||
if (!MonteCarlo(ctx, t, cipher, &result, operation == kEncrypt, key, iv,
|
||||
in)) {
|
||||
return false;
|
||||
}
|
||||
if (operation == kEncrypt) {
|
||||
// MCT tests contain a stray blank line after the ENCRYPT section.
|
||||
printf("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int usage(char *arg) {
|
||||
fprintf(stderr, "usage: %s (kat|mct) <cipher> <test file>\n", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cavp_aes_test_main(int argc, char **argv) {
|
||||
if (argc != 4) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
const std::string tm(argv[1]);
|
||||
enum TestCtx::Mode test_mode;
|
||||
if (tm == "kat") {
|
||||
test_mode = TestCtx::kKAT;
|
||||
} else if (tm == "mct") {
|
||||
test_mode = TestCtx::kMCT;
|
||||
} else {
|
||||
fprintf(stderr, "invalid test_mode: %s\n", tm.c_str());
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
const std::string cipher_name(argv[2]);
|
||||
const EVP_CIPHER *cipher = GetCipher(argv[2]);
|
||||
if (cipher == nullptr) {
|
||||
fprintf(stderr, "invalid cipher: %s\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
const bool has_iv =
|
||||
(cipher_name != "aes-128-ecb" &&
|
||||
cipher_name != "aes-192-ecb" &&
|
||||
cipher_name != "aes-256-ecb");
|
||||
|
||||
TestCtx ctx = {cipher, has_iv, test_mode};
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[3];
|
||||
opts.callback = TestCipher;
|
||||
opts.arg = &ctx;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/* 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_ctr_drbg_test processes a NIST CAVP DRBG800-90A test vector request
|
||||
// file and emits the corresponding response.
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cavp_test_util.h"
|
||||
#include "../crypto/fipsmodule/rand/internal.h"
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
|
||||
|
||||
static bool TestCTRDRBG(FileTest *t, void *arg) {
|
||||
std::string test_type, prediction_resistance, entropy_input_len, nonce_len,
|
||||
personalization_str_len, additional_input_len, returned_bits_len;
|
||||
if (!t->GetInstruction(&test_type, "AES-256 no df") ||
|
||||
!t->GetInstruction(&prediction_resistance, "PredictionResistance") ||
|
||||
!t->GetInstruction(&entropy_input_len, "EntropyInputLen") ||
|
||||
!t->GetInstruction(&nonce_len, "NonceLen") ||
|
||||
!t->GetInstruction(&personalization_str_len,
|
||||
"PersonalizationStringLen") ||
|
||||
!t->GetInstruction(&additional_input_len, "AdditionalInputLen") ||
|
||||
!t->GetInstruction(&returned_bits_len, "ReturnedBitsLen") ||
|
||||
!test_type.empty() ||
|
||||
prediction_resistance != "False" ||
|
||||
strtoul(entropy_input_len.c_str(), nullptr, 0) !=
|
||||
CTR_DRBG_ENTROPY_LEN * 8 ||
|
||||
nonce_len != "0") {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string count;
|
||||
std::vector<uint8_t> entropy, nonce, personalization_str, ai1, ai2;
|
||||
if (!t->GetAttribute(&count, "COUNT") ||
|
||||
!t->GetBytes(&entropy, "EntropyInput") ||
|
||||
!t->GetBytes(&nonce, "Nonce") ||
|
||||
!t->GetBytes(&personalization_str, "PersonalizationString") ||
|
||||
!t->GetBytes(&ai1, "AdditionalInput") ||
|
||||
!t->GetBytes(&ai2, "AdditionalInput/2") ||
|
||||
entropy.size() * 8 != strtoul(entropy_input_len.c_str(), nullptr, 0) ||
|
||||
nonce.size() != 0 ||
|
||||
personalization_str.size() * 8 !=
|
||||
strtoul(personalization_str_len.c_str(), nullptr, 0) ||
|
||||
ai1.size() != ai2.size() ||
|
||||
ai1.size() * 8 != strtoul(additional_input_len.c_str(), nullptr, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CTR_DRBG_STATE drbg;
|
||||
CTR_DRBG_init(&drbg, entropy.data(),
|
||||
personalization_str.size() > 0 ? personalization_str.data()
|
||||
: nullptr,
|
||||
personalization_str.size());
|
||||
|
||||
uint64_t out_len = strtoul(returned_bits_len.c_str(), nullptr, 0);
|
||||
if (out_len == 0 || (out_len & 7) != 0) {
|
||||
return false;
|
||||
}
|
||||
out_len /= 8;
|
||||
|
||||
std::vector<uint8_t> out;
|
||||
out.resize(out_len);
|
||||
|
||||
CTR_DRBG_generate(&drbg, out.data(), out.size(),
|
||||
ai1.size() > 0 ? ai1.data() : nullptr, ai1.size());
|
||||
CTR_DRBG_generate(&drbg, out.data(), out.size(),
|
||||
ai2.size() > 0 ? ai2.data() : nullptr, ai2.size());
|
||||
|
||||
printf("%s", t->CurrentTestToString().c_str());
|
||||
printf("ReturnedBits = %s\r\n\r\n", EncodeHex(out).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int usage(char *arg) {
|
||||
fprintf(stderr, "usage: %s <test file>\n", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cavp_ctr_drbg_test_main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[1];
|
||||
opts.callback = TestCTRDRBG;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/* 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_keypair_test processes a NIST CAVP ECDSA2 KeyPair test vector
|
||||
// request file and emits the corresponding response.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ec_key.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/nid.h>
|
||||
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
static bool TestECDSA2KeyPair(FileTest *t, void *arg) {
|
||||
std::string n_str;
|
||||
const char *group_str;
|
||||
int nid = GetECGroupNIDFromInstruction(t, &group_str);
|
||||
if (nid == NID_undef ||
|
||||
!t->GetAttribute(&n_str, "N")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't use CurrentTestToString to avoid printing the N.
|
||||
printf(
|
||||
"[%s]\r\n\r\n[B.4.2 Key Pair Generation by Testing Candidates]\r\n\r\n",
|
||||
group_str);
|
||||
|
||||
unsigned long n = strtoul(n_str.c_str(), nullptr, 10);
|
||||
for (unsigned long i = 0; i < n; i++) {
|
||||
bssl::UniquePtr<BIGNUM> qx(BN_new()), qy(BN_new());
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
|
||||
if (!key ||
|
||||
!EC_KEY_generate_key_fips(key.get()) ||
|
||||
!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key.get()),
|
||||
EC_KEY_get0_public_key(key.get()),
|
||||
qx.get(), qy.get(), nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t degree_len =
|
||||
(EC_GROUP_get_degree(EC_KEY_get0_group(key.get())) + 7) / 8;
|
||||
size_t order_len =
|
||||
BN_num_bytes(EC_GROUP_get0_order(EC_KEY_get0_group(key.get())));
|
||||
std::vector<uint8_t> qx_bytes(degree_len), qy_bytes(degree_len);
|
||||
std::vector<uint8_t> d_bytes(order_len);
|
||||
if (!BN_bn2bin_padded(qx_bytes.data(), qx_bytes.size(), qx.get()) ||
|
||||
!BN_bn2bin_padded(qy_bytes.data(), qy_bytes.size(), qy.get()) ||
|
||||
!BN_bn2bin_padded(d_bytes.data(), d_bytes.size(),
|
||||
EC_KEY_get0_private_key(key.get()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("d = %s\r\nQx = %s\r\nQy = %s\r\n\r\n", EncodeHex(d_bytes).c_str(),
|
||||
EncodeHex(qx_bytes).c_str(), EncodeHex(qy_bytes).c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int cavp_ecdsa2_keypair_test_main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <test file>\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[1];
|
||||
opts.callback = TestECDSA2KeyPair;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/* 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_pkv_test processes a NIST CAVP ECDSA2 PKV test vector request file
|
||||
// and emits the corresponding response.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ec_key.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/nid.h>
|
||||
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
static bool TestECDSA2PKV(FileTest *t, void *arg) {
|
||||
int nid = GetECGroupNIDFromInstruction(t);
|
||||
if (nid == NID_undef) {
|
||||
return false;
|
||||
}
|
||||
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");
|
||||
if (!key || !qx || !qy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EC_KEY_set_public_key_affine_coordinates(key.get(), qx.get(), qy.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 cavp_ecdsa2_pkv_test_main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <test file>\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[1];
|
||||
opts.callback = TestECDSA2PKV;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/* 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_siggen_test processes NIST CAVP ECDSA2 SigGen and
|
||||
// SigGenComponent test vector request files and emits the corresponding
|
||||
// response.
|
||||
|
||||
#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 "../crypto/internal.h"
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
static bool TestECDSA2SigGenImpl(FileTest *t, bool is_component) {
|
||||
int nid = GetECGroupNIDFromInstruction(t);
|
||||
const EVP_MD *md = GetDigestFromInstruction(t);
|
||||
if (nid == NID_undef || md == nullptr) {
|
||||
return false;
|
||||
}
|
||||
bssl::UniquePtr<BIGNUM> qx(BN_new()), qy(BN_new());
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
|
||||
std::vector<uint8_t> msg;
|
||||
if (!qx || !qy || !key ||
|
||||
!EC_KEY_generate_key_fips(key.get()) ||
|
||||
!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key.get()),
|
||||
EC_KEY_get0_public_key(key.get()),
|
||||
qx.get(), qy.get(), nullptr) ||
|
||||
!t->GetBytes(&msg, "Msg")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t digest[EVP_MAX_MD_SIZE];
|
||||
unsigned digest_len;
|
||||
if (is_component) {
|
||||
if (msg.size() != EVP_MD_size(md)) {
|
||||
t->PrintLine("Bad input length.");
|
||||
return false;
|
||||
}
|
||||
digest_len = EVP_MD_size(md);
|
||||
OPENSSL_memcpy(digest, msg.data(), msg.size());
|
||||
} else if (!EVP_Digest(msg.data(), msg.size(), digest, &digest_len, md,
|
||||
nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_do_sign(digest, digest_len, key.get()));
|
||||
if (!sig) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t degree_len =
|
||||
(EC_GROUP_get_degree(EC_KEY_get0_group(key.get())) + 7) / 8;
|
||||
size_t order_len =
|
||||
BN_num_bytes(EC_GROUP_get0_order(EC_KEY_get0_group(key.get())));
|
||||
std::vector<uint8_t> qx_bytes(degree_len), qy_bytes(degree_len);
|
||||
std::vector<uint8_t> r_bytes(order_len), s_bytes(order_len);
|
||||
if (!BN_bn2bin_padded(qx_bytes.data(), qx_bytes.size(), qx.get()) ||
|
||||
!BN_bn2bin_padded(qy_bytes.data(), qy_bytes.size(), qy.get()) ||
|
||||
!BN_bn2bin_padded(r_bytes.data(), r_bytes.size(), sig->r) ||
|
||||
!BN_bn2bin_padded(s_bytes.data(), s_bytes.size(), sig->s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("%sQx = %s\r\nQy = %s\r\nR = %s\r\nS = %s\r\n\r\n",
|
||||
t->CurrentTestToString().c_str(), EncodeHex(qx_bytes).c_str(),
|
||||
EncodeHex(qy_bytes).c_str(), EncodeHex(r_bytes).c_str(),
|
||||
EncodeHex(s_bytes).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestECDSA2SigGen(FileTest *t, void *arg) {
|
||||
return TestECDSA2SigGenImpl(t, false);
|
||||
}
|
||||
|
||||
static bool TestECDSA2SigGenComponent(FileTest *t, void *arg) {
|
||||
return TestECDSA2SigGenImpl(t, true);
|
||||
}
|
||||
|
||||
int cavp_ecdsa2_siggen_test_main(int argc, char **argv) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: %s (SigGen|SigGenComponent) <test file>\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool (*test_func)(FileTest *, void *);
|
||||
if (strcmp(argv[1], "SigGen") == 0) {
|
||||
test_func = TestECDSA2SigGen;
|
||||
} else if (strcmp(argv[1], "SigGenComponent") == 0) {
|
||||
test_func = TestECDSA2SigGenComponent;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown test type: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[2];
|
||||
opts.callback = test_func;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/* 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.
|
||||
|
||||
#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 "../crypto/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 cavp_ecdsa2_sigver_test_main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <test file>\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[1];
|
||||
opts.callback = TestECDSA2SigVer;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/* 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_hmac_test processes a NIST CAVP HMAC test vector request file and emits
|
||||
// the corresponding response.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/span.h>
|
||||
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
static bool TestHMAC(FileTest *t, void *arg) {
|
||||
std::string md_len_str;
|
||||
if (!t->GetInstruction(&md_len_str, "L")) {
|
||||
return false;
|
||||
}
|
||||
const size_t md_len = strtoul(md_len_str.c_str(), nullptr, 0);
|
||||
|
||||
const EVP_MD *md;
|
||||
switch (md_len) {
|
||||
case 20:
|
||||
md = EVP_sha1();
|
||||
break;
|
||||
case 28:
|
||||
md = EVP_sha224();
|
||||
break;
|
||||
case 32:
|
||||
md = EVP_sha256();
|
||||
break;
|
||||
case 48:
|
||||
md = EVP_sha384();
|
||||
break;
|
||||
case 64:
|
||||
md = EVP_sha512();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string count_str, k_len_str, t_len_str;
|
||||
std::vector<uint8_t> key, msg;
|
||||
if (!t->GetAttribute(&count_str, "Count") ||
|
||||
!t->GetAttribute(&k_len_str, "Klen") ||
|
||||
!t->GetAttribute(&t_len_str, "Tlen") ||
|
||||
!t->GetBytes(&key, "Key") ||
|
||||
!t->GetBytes(&msg, "Msg")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t k_len = strtoul(k_len_str.c_str(), nullptr, 0);
|
||||
size_t t_len = strtoul(t_len_str.c_str(), nullptr, 0);
|
||||
if (key.size() < k_len) {
|
||||
return false;
|
||||
}
|
||||
unsigned out_len;
|
||||
uint8_t out[EVP_MAX_MD_SIZE];
|
||||
if (HMAC(md, key.data(), k_len, msg.data(), msg.size(), out, &out_len) ==
|
||||
NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out_len < t_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("%s", t->CurrentTestToString().c_str());
|
||||
printf("Mac = %s\r\n\r\n",
|
||||
EncodeHex(bssl::MakeConstSpan(out, t_len)).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int usage(char *arg) {
|
||||
fprintf(stderr, "usage: %s <test file>\n", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cavp_hmac_test_main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[1];
|
||||
opts.callback = TestHMAC;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
/* Copyright (c) 2018, 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_kas_test processes NIST CAVP ECC KAS test vector request files and
|
||||
// emits the corresponding response.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/digest.h>
|
||||
#include <openssl/ecdh.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/ec_key.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/nid.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/span.h>
|
||||
|
||||
#include "../crypto/internal.h"
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
static bool TestKAS(FileTest *t, void *arg) {
|
||||
const bool validate = *reinterpret_cast<bool *>(arg);
|
||||
|
||||
int nid = NID_undef;
|
||||
size_t digest_len = 0;
|
||||
|
||||
if (t->HasInstruction("EB - SHA224")) {
|
||||
nid = NID_secp224r1;
|
||||
digest_len = SHA224_DIGEST_LENGTH;
|
||||
} else if (t->HasInstruction("EC - SHA256")) {
|
||||
nid = NID_X9_62_prime256v1;
|
||||
digest_len = SHA256_DIGEST_LENGTH;
|
||||
} else if (t->HasInstruction("ED - SHA384")) {
|
||||
nid = NID_secp384r1;
|
||||
digest_len = SHA384_DIGEST_LENGTH;
|
||||
} else if (t->HasInstruction("EE - SHA512")) {
|
||||
nid = NID_secp521r1;
|
||||
digest_len = SHA512_DIGEST_LENGTH;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!t->HasAttribute("COUNT")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<BIGNUM> their_x(GetBIGNUM(t, "QeCAVSx"));
|
||||
bssl::UniquePtr<BIGNUM> their_y(GetBIGNUM(t, "QeCAVSy"));
|
||||
bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(nid));
|
||||
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
|
||||
if (!their_x || !their_y || !ec_key || !ctx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const EC_GROUP *const group = EC_KEY_get0_group(ec_key.get());
|
||||
bssl::UniquePtr<EC_POINT> their_point(EC_POINT_new(group));
|
||||
if (!their_point ||
|
||||
!EC_POINT_set_affine_coordinates_GFp(
|
||||
group, their_point.get(), their_x.get(), their_y.get(), ctx.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (validate) {
|
||||
bssl::UniquePtr<BIGNUM> our_k(GetBIGNUM(t, "deIUT"));
|
||||
if (!our_k ||
|
||||
!EC_KEY_set_private_key(ec_key.get(), our_k.get()) ||
|
||||
// These attributes are ignored.
|
||||
!t->HasAttribute("QeIUTx") ||
|
||||
!t->HasAttribute("QeIUTy")) {
|
||||
return false;
|
||||
}
|
||||
} else if (!EC_KEY_generate_key(ec_key.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t digest[EVP_MAX_MD_SIZE];
|
||||
if (!ECDH_compute_key_fips(digest, digest_len, their_point.get(),
|
||||
ec_key.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (validate) {
|
||||
std::vector<uint8_t> expected_shared_bytes;
|
||||
if (!t->GetBytes(&expected_shared_bytes, "CAVSHashZZ")) {
|
||||
return false;
|
||||
}
|
||||
const bool ok =
|
||||
digest_len == expected_shared_bytes.size() &&
|
||||
OPENSSL_memcmp(digest, expected_shared_bytes.data(), digest_len) == 0;
|
||||
|
||||
printf("%sIUTHashZZ = %s\r\nResult = %c\r\n\r\n\r\n",
|
||||
t->CurrentTestToString().c_str(),
|
||||
EncodeHex(bssl::MakeConstSpan(digest, digest_len)).c_str(),
|
||||
ok ? 'P' : 'F');
|
||||
} else {
|
||||
const EC_POINT *pub = EC_KEY_get0_public_key(ec_key.get());
|
||||
bssl::UniquePtr<BIGNUM> x(BN_new());
|
||||
bssl::UniquePtr<BIGNUM> y(BN_new());
|
||||
if (!x || !y ||
|
||||
!EC_POINT_get_affine_coordinates_GFp(group, pub, x.get(), y.get(),
|
||||
ctx.get())) {
|
||||
return false;
|
||||
}
|
||||
bssl::UniquePtr<char> x_hex(BN_bn2hex(x.get()));
|
||||
bssl::UniquePtr<char> y_hex(BN_bn2hex(y.get()));
|
||||
|
||||
printf("%sQeIUTx = %s\r\nQeIUTy = %s\r\nHashZZ = %s\r\n",
|
||||
t->CurrentTestToString().c_str(), x_hex.get(), y_hex.get(),
|
||||
EncodeHex(bssl::MakeConstSpan(digest, digest_len)).c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int cavp_kas_test_main(int argc, char **argv) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: %s (validity|function) <test file>\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool validity;
|
||||
if (strcmp(argv[1], "validity") == 0) {
|
||||
validity = true;
|
||||
} else if (strcmp(argv[1], "function") == 0) {
|
||||
validity = false;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown test type: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[2];
|
||||
opts.arg = &validity;
|
||||
opts.callback = TestKAS;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
opts.is_kas_test = true;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/* 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_keywrap_test processes a NIST CAVP AES test vector request file and
|
||||
// emits the corresponding response.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestCtx {
|
||||
bool encrypt;
|
||||
bool padding;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static bool AESKeyWrap(std::vector<uint8_t> *out, bool encrypt,
|
||||
const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &in) {
|
||||
size_t key_bits = key.size() * 8;
|
||||
if (key_bits != 128 && key_bits != 192 && key_bits != 256) {
|
||||
return false;
|
||||
}
|
||||
AES_KEY aes_key;
|
||||
|
||||
if (encrypt) {
|
||||
out->resize(in.size() + 8);
|
||||
if (AES_set_encrypt_key(key.data(), key_bits, &aes_key) ||
|
||||
AES_wrap_key(&aes_key, nullptr, out->data(), in.data(), in.size()) ==
|
||||
-1) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
out->resize(in.size() - 8);
|
||||
if (AES_set_decrypt_key(key.data(), key_bits, &aes_key) ||
|
||||
AES_unwrap_key(&aes_key, nullptr, out->data(), in.data(), in.size()) ==
|
||||
-1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool AESKeyWrapWithPadding(std::vector<uint8_t> *out, bool encrypt,
|
||||
const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &in) {
|
||||
const size_t key_bits = key.size() * 8;
|
||||
if (key_bits != 128 && key_bits != 192 && key_bits != 256) {
|
||||
return false;
|
||||
}
|
||||
AES_KEY aes_key;
|
||||
|
||||
size_t out_len;
|
||||
if (encrypt) {
|
||||
out->resize(in.size() + 15);
|
||||
if (AES_set_encrypt_key(key.data(), key_bits, &aes_key) ||
|
||||
!AES_wrap_key_padded(&aes_key, out->data(), &out_len, out->size(),
|
||||
in.data(), in.size())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
out->resize(in.size());
|
||||
if (AES_set_decrypt_key(key.data(), key_bits, &aes_key) ||
|
||||
!AES_unwrap_key_padded(&aes_key, out->data(), &out_len, out->size(),
|
||||
in.data(), in.size())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
out->resize(out_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestCipher(FileTest *t, void *arg) {
|
||||
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
|
||||
|
||||
std::string count, unused, in_label = ctx->encrypt ? "P" : "C",
|
||||
result_label = ctx->encrypt ? "C" : "P";
|
||||
std::vector<uint8_t> key, in, result;
|
||||
// clang-format off
|
||||
if (!t->GetInstruction(&unused, "PLAINTEXT LENGTH") ||
|
||||
!t->GetAttribute(&count, "COUNT") ||
|
||||
!t->GetBytes(&key, "K") ||
|
||||
!t->GetBytes(&in, in_label)) {
|
||||
return false;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
auto wrap_function = AESKeyWrap;
|
||||
if (ctx->padding) {
|
||||
wrap_function = AESKeyWrapWithPadding;
|
||||
}
|
||||
|
||||
printf("%s", t->CurrentTestToString().c_str());
|
||||
if (!wrap_function(&result, ctx->encrypt, key, in)) {
|
||||
if (ctx->encrypt) {
|
||||
return false;
|
||||
} else {
|
||||
printf("FAIL\r\n\r\n");
|
||||
}
|
||||
} else {
|
||||
printf("%s = %s\r\n\r\n", result_label.c_str(), EncodeHex(result).c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int usage(char *arg) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"usage: %s (enc|dec|enc-pad|dec-pad) (128|192|256) <test file>\n",
|
||||
arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cavp_keywrap_test_main(int argc, char **argv) {
|
||||
if (argc != 4) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
const std::string op(argv[1]);
|
||||
bool encrypt = false;
|
||||
bool padding = false;
|
||||
if (op == "enc") {
|
||||
encrypt = true;
|
||||
} else if (op == "dec") {
|
||||
} else if (op == "enc-pad") {
|
||||
encrypt = true;
|
||||
padding = true;
|
||||
} else if (op == "dec-pad") {
|
||||
padding = true;
|
||||
} else {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
TestCtx ctx = {encrypt, padding};
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[3];
|
||||
opts.callback = TestCipher;
|
||||
opts.arg = &ctx;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/* 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_main is a wrapper that invokes the main entry function of one of the
|
||||
// CAVP validation suite binaries.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
static int usage(char *arg) {
|
||||
fprintf(stderr, "usage: %s <validation suite> <args ...>\n", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct TestSuite {
|
||||
std::string name;
|
||||
int (*main_func)(int argc, char **argv);
|
||||
};
|
||||
|
||||
static TestSuite all_test_suites[] = {
|
||||
{"aes", &cavp_aes_test_main},
|
||||
{"aes_gcm", &cavp_aes_gcm_test_main},
|
||||
{"ctr_drbg", &cavp_ctr_drbg_test_main},
|
||||
{"ecdsa2_keypair", &cavp_ecdsa2_keypair_test_main},
|
||||
{"ecdsa2_pkv", &cavp_ecdsa2_pkv_test_main},
|
||||
{"ecdsa2_siggen", &cavp_ecdsa2_siggen_test_main},
|
||||
{"ecdsa2_sigver", &cavp_ecdsa2_sigver_test_main},
|
||||
{"hmac", &cavp_hmac_test_main},
|
||||
{"kas", &cavp_kas_test_main},
|
||||
{"keywrap", &cavp_keywrap_test_main},
|
||||
{"rsa2_keygen", &cavp_rsa2_keygen_test_main},
|
||||
{"rsa2_siggen", &cavp_rsa2_siggen_test_main},
|
||||
{"rsa2_sigver", &cavp_rsa2_sigver_test_main},
|
||||
{"tlskdf", &cavp_tlskdf_test_main},
|
||||
{"sha", &cavp_sha_test_main},
|
||||
{"sha_monte", &cavp_sha_monte_test_main},
|
||||
{"tdes", &cavp_tdes_test_main}
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CRYPTO_library_init();
|
||||
|
||||
if (argc < 3) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
const std::string suite(argv[1]);
|
||||
for (const TestSuite &s : all_test_suites) {
|
||||
if (s.name == suite) {
|
||||
return s.main_func(argc - 1, &argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "invalid test suite: %s\n\n", argv[1]);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/* 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_rsa2_keygen_test processes NIST CAVP RSA2 KeyGen test vector request
|
||||
// files and emits the corresponding response.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "../crypto/internal.h"
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
static bool TestRSA2KeyGen(FileTest *t, void *arg) {
|
||||
std::string mod_str, table, count_str;
|
||||
if (!t->GetInstruction(&mod_str, "mod") ||
|
||||
!t->GetInstruction(&table, "Table for M-R Test") ||
|
||||
table != "C.2" ||
|
||||
!t->GetAttribute(&count_str, "N")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("[mod = %s]\r\n", mod_str.c_str());
|
||||
printf("[Table for M-R Test = %s]\r\n\r\n", table.c_str());
|
||||
|
||||
size_t bits = strtoul(mod_str.c_str(), nullptr, 0);
|
||||
size_t count = strtoul(count_str.c_str(), nullptr, 0);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
bssl::UniquePtr<RSA> key(RSA_new());
|
||||
if (key == nullptr ||
|
||||
bits == 0 ||
|
||||
!RSA_generate_key_fips(key.get(), bits, nullptr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const BIGNUM *n, *e, *d, *p, *q;
|
||||
RSA_get0_key(key.get(), &n, &e, &d);
|
||||
RSA_get0_factors(key.get(), &p, &q);
|
||||
std::vector<uint8_t> n_bytes(BN_num_bytes(n)), e_bytes(BN_num_bytes(e)),
|
||||
d_bytes((bits + 7) / 8), p_bytes(BN_num_bytes(p)),
|
||||
q_bytes(BN_num_bytes(q));
|
||||
if (n == NULL ||
|
||||
BN_bn2bin(n, n_bytes.data()) != n_bytes.size() ||
|
||||
e == NULL ||
|
||||
BN_bn2bin(e, e_bytes.data()) != e_bytes.size() ||
|
||||
d == NULL ||
|
||||
!BN_bn2bin_padded(d_bytes.data(), d_bytes.size(), d) ||
|
||||
p == NULL ||
|
||||
BN_bn2bin(p, p_bytes.data()) != p_bytes.size() ||
|
||||
q == NULL ||
|
||||
BN_bn2bin(q, q_bytes.data()) != q_bytes.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("e = %s\r\np = %s\r\nq = %s\r\nn = %s\r\nd = %s\r\n\r\n",
|
||||
EncodeHex(e_bytes).c_str(), EncodeHex(p_bytes).c_str(),
|
||||
EncodeHex(q_bytes).c_str(), EncodeHex(n_bytes).c_str(),
|
||||
EncodeHex(d_bytes).c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int cavp_rsa2_keygen_test_main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <test file>\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[1];
|
||||
opts.callback = TestRSA2KeyGen;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/* 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_rsa2_siggen_test processes NIST CAVP RSA2 SigGen test vector request
|
||||
// files and emits the corresponding response.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/digest.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "../crypto/internal.h"
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestCtx {
|
||||
bssl::UniquePtr<RSA> key;
|
||||
bool is_pss;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static bool TestRSA2SigGen(FileTest *t, void *arg) {
|
||||
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
|
||||
|
||||
std::string mod_str, hash;
|
||||
std::vector<uint8_t> msg;
|
||||
if (!t->GetInstruction(&mod_str, "mod") ||
|
||||
!t->GetAttribute(&hash, "SHAAlg") ||
|
||||
!t->GetBytes(&msg, "Msg")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string test = t->CurrentTestToString();
|
||||
if (t->IsAtNewInstructionBlock()) {
|
||||
int mod_bits = strtoul(mod_str.c_str(), nullptr, 0);
|
||||
ctx->key = bssl::UniquePtr<RSA>(RSA_new());
|
||||
if (ctx->key == nullptr ||
|
||||
mod_bits == 0 ||
|
||||
!RSA_generate_key_fips(ctx->key.get(), mod_bits, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const BIGNUM *n, *e;
|
||||
RSA_get0_key(ctx->key.get(), &n, &e, nullptr);
|
||||
|
||||
std::vector<uint8_t> n_bytes(BN_num_bytes(n));
|
||||
std::vector<uint8_t> e_bytes(BN_num_bytes(e));
|
||||
if (!BN_bn2bin_padded(n_bytes.data(), n_bytes.size(), n) ||
|
||||
!BN_bn2bin_padded(e_bytes.data(), e_bytes.size(), e)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("[mod = %s]\r\n\r\nn = %s\r\n\r\ne = %s", mod_str.c_str(),
|
||||
EncodeHex(n_bytes).c_str(), EncodeHex(e_bytes).c_str());
|
||||
test = test.substr(test.find("]") + 3);
|
||||
}
|
||||
|
||||
const EVP_MD *md = EVP_get_digestbyname(hash.c_str());
|
||||
uint8_t digest_buf[EVP_MAX_MD_SIZE];
|
||||
std::vector<uint8_t> sig(RSA_size(ctx->key.get()));
|
||||
unsigned digest_len;
|
||||
size_t sig_len;
|
||||
if (md == NULL ||
|
||||
!EVP_Digest(msg.data(), msg.size(), digest_buf, &digest_len, md, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctx->is_pss) {
|
||||
if (!RSA_sign_pss_mgf1(ctx->key.get(), &sig_len, sig.data(), sig.size(),
|
||||
digest_buf, digest_len, md, md, -1)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
unsigned sig_len_u;
|
||||
if (!RSA_sign(EVP_MD_type(md), digest_buf, digest_len, sig.data(),
|
||||
&sig_len_u, ctx->key.get())) {
|
||||
return false;
|
||||
}
|
||||
sig_len = sig_len_u;
|
||||
}
|
||||
|
||||
sig.resize(sig_len);
|
||||
printf("%sS = %s\r\n\r\n", test.c_str(), EncodeHex(sig).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
int cavp_rsa2_siggen_test_main(int argc, char **argv) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: %s (pkcs15|pss) <test file>\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TestCtx ctx;
|
||||
if (strcmp(argv[1], "pkcs15") == 0) {
|
||||
ctx = {nullptr, false};
|
||||
} else if (strcmp(argv[1], "pss") == 0) {
|
||||
ctx = {nullptr, true};
|
||||
} else {
|
||||
fprintf(stderr, "Unknown test type: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[2];
|
||||
opts.callback = TestRSA2SigGen;
|
||||
opts.arg = &ctx;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/* 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_rsa2_sigver_test processes NIST CAVP RSA2 SigVer test vector request
|
||||
// files and emits the corresponding response.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/digest.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "../crypto/internal.h"
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestCtx {
|
||||
std::vector<uint8_t> N;
|
||||
bool is_pss;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static bool TestRSA2SigVer(FileTest *t, void *arg) {
|
||||
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
|
||||
|
||||
std::string mod_str;
|
||||
if (!t->GetInstruction(&mod_str, "mod")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("%s", t->CurrentTestToString().c_str());
|
||||
|
||||
if (t->HasAttribute("n")) {
|
||||
printf("\r\n");
|
||||
return t->GetBytes(&ctx->N, "n");
|
||||
}
|
||||
|
||||
std::string hash;
|
||||
std::vector<uint8_t> e_bytes, msg, sig;
|
||||
if (!t->GetAttribute(&hash, "SHAAlg") ||
|
||||
!t->GetBytes(&e_bytes, "e") ||
|
||||
!t->GetBytes(&msg, "Msg") ||
|
||||
!t->GetBytes(&sig, "S")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<RSA> key(RSA_new());
|
||||
key->n = BN_new();
|
||||
key->e = BN_new();
|
||||
if (key == nullptr ||
|
||||
!BN_bin2bn(ctx->N.data(), ctx->N.size(), key->n) ||
|
||||
!BN_bin2bn(e_bytes.data(), e_bytes.size(), key->e)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const EVP_MD *md = EVP_get_digestbyname(hash.c_str());
|
||||
uint8_t digest_buf[EVP_MAX_MD_SIZE];
|
||||
unsigned digest_len;
|
||||
if (md == NULL ||
|
||||
!EVP_Digest(msg.data(), msg.size(), digest_buf, &digest_len, md, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ok;
|
||||
if (ctx->is_pss) {
|
||||
ok = RSA_verify_pss_mgf1(key.get(), digest_buf, digest_len, md, md, -1,
|
||||
sig.data(), sig.size());
|
||||
} else {
|
||||
ok = RSA_verify(EVP_MD_type(md), digest_buf, digest_len, sig.data(),
|
||||
sig.size(), key.get());
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
printf("Result = P\r\n\r\n");
|
||||
} else {
|
||||
char buf[256];
|
||||
ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
|
||||
printf("Result = F (%s)\r\n\r\n", buf);
|
||||
}
|
||||
ERR_clear_error();
|
||||
return true;
|
||||
}
|
||||
|
||||
int cavp_rsa2_sigver_test_main(int argc, char **argv) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: %s (pkcs15|pss) <test file>\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TestCtx ctx;
|
||||
if (strcmp(argv[1], "pkcs15") == 0) {
|
||||
ctx = {std::vector<uint8_t>(), false};
|
||||
} else if (strcmp(argv[1], "pss") == 0) {
|
||||
ctx = {std::vector<uint8_t>(), true};
|
||||
} else {
|
||||
fprintf(stderr, "Unknown test type: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[2];
|
||||
opts.callback = TestRSA2SigVer;
|
||||
opts.arg = &ctx;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/* 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_sha_monte_test processes a NIST CAVP SHA-Monte test vector request file
|
||||
// and emits the corresponding response.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/digest.h>
|
||||
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestCtx {
|
||||
std::string hash;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static bool TestSHAMonte(FileTest *t, void *arg) {
|
||||
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
|
||||
|
||||
const EVP_MD *md = EVP_get_digestbyname(ctx->hash.c_str());
|
||||
if (md == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const size_t md_len = EVP_MD_size(md);
|
||||
|
||||
std::string out_len;
|
||||
if (!t->GetInstruction(&out_len, "L") ||
|
||||
md_len != strtoul(out_len.c_str(), nullptr, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> seed;
|
||||
if (!t->GetBytes(&seed, "Seed") ||
|
||||
seed.size() != md_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> out = seed;
|
||||
|
||||
printf("%s\r\n", t->CurrentTestToString().c_str());
|
||||
|
||||
for (int count = 0; count < 100; count++) {
|
||||
std::vector<uint8_t> msg;
|
||||
msg.insert(msg.end(), out.begin(), out.end());
|
||||
msg.insert(msg.end(), out.begin(), out.end());
|
||||
msg.insert(msg.end(), out.begin(), out.end());
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
unsigned digest_len;
|
||||
if (!EVP_Digest(msg.data(), msg.size(), out.data(), &digest_len, md,
|
||||
nullptr) ||
|
||||
digest_len != out.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
msg.erase(msg.begin(), msg.begin() + out.size());
|
||||
msg.insert(msg.end(), out.begin(), out.end());
|
||||
}
|
||||
printf("COUNT = %d\r\n", count);
|
||||
printf("MD = %s\r\n\r\n", EncodeHex(out).c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int usage(char *arg) {
|
||||
fprintf(stderr, "usage: %s <hash> <test file>\n", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cavp_sha_monte_test_main(int argc, char **argv) {
|
||||
if (argc != 3) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
TestCtx ctx = {std::string(argv[1])};
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[2];
|
||||
opts.callback = TestSHAMonte;
|
||||
opts.arg = &ctx;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/* 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_sha_test processes a NIST CAVP SHA test vector request file and emits
|
||||
// the corresponding response.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/digest.h>
|
||||
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestCtx {
|
||||
std::string hash;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static bool TestSHA(FileTest *t, void *arg) {
|
||||
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
|
||||
|
||||
const EVP_MD *md = EVP_get_digestbyname(ctx->hash.c_str());
|
||||
if (md == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const size_t md_len = EVP_MD_size(md);
|
||||
|
||||
std::string out_len;
|
||||
if (!t->GetInstruction(&out_len, "L") ||
|
||||
md_len != strtoul(out_len.c_str(), nullptr, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string msg_len_str;
|
||||
std::vector<uint8_t> msg;
|
||||
if (!t->GetAttribute(&msg_len_str, "Len") ||
|
||||
!t->GetBytes(&msg, "Msg")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t msg_len = strtoul(msg_len_str.c_str(), nullptr, 0);
|
||||
if (msg_len % 8 != 0 ||
|
||||
msg_len / 8 > msg.size()) {
|
||||
return false;
|
||||
}
|
||||
msg_len /= 8;
|
||||
|
||||
std::vector<uint8_t> out;
|
||||
out.resize(md_len);
|
||||
unsigned digest_len;
|
||||
if (!EVP_Digest(msg.data(), msg_len, out.data(), &digest_len, md, nullptr) ||
|
||||
digest_len != out.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("%s", t->CurrentTestToString().c_str());
|
||||
printf("MD = %s\r\n\r\n", EncodeHex(out).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int usage(char *arg) {
|
||||
fprintf(stderr, "usage: %s <hash> <test file>\n", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cavp_sha_test_main(int argc, char **argv) {
|
||||
if (argc != 3) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
TestCtx ctx = {std::string(argv[1])};
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[2];
|
||||
opts.callback = TestSHA;
|
||||
opts.arg = &ctx;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,336 +0,0 @@
|
||||
/* 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_tdes_test processes a NIST TMOVS test vector request file and emits the
|
||||
// corresponding response.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/cipher.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestCtx {
|
||||
const EVP_CIPHER *cipher;
|
||||
enum Mode {
|
||||
kKAT, // Known Answer Test
|
||||
kMCT, // Monte Carlo Test
|
||||
};
|
||||
bool has_iv;
|
||||
Mode mode;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static bool TestKAT(FileTest *t, void *arg) {
|
||||
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
|
||||
|
||||
if (t->HasInstruction("ENCRYPT") == t->HasInstruction("DECRYPT")) {
|
||||
t->PrintLine("Want either ENCRYPT or DECRYPT");
|
||||
return false;
|
||||
}
|
||||
enum {
|
||||
kEncrypt,
|
||||
kDecrypt,
|
||||
} operation = t->HasInstruction("ENCRYPT") ? kEncrypt : kDecrypt;
|
||||
|
||||
if (t->HasAttribute("NumKeys")) {
|
||||
// Another file format quirk: NumKeys is a single attribute line immediately
|
||||
// following an instruction and should probably have been an instruction
|
||||
// instead. If it is present, the file has separate attributes "KEY{1,2,3}".
|
||||
// If it is not, the keys are concatenated in a single attribute "KEYs".
|
||||
std::string num_keys;
|
||||
t->GetAttribute(&num_keys, "NumKeys");
|
||||
t->InjectInstruction("NumKeys", num_keys);
|
||||
|
||||
std::string header = operation == kEncrypt ? "[ENCRYPT]" : "[DECRYPT]";
|
||||
printf("%s\r\n\r\n", header.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enum {
|
||||
kNotPresent,
|
||||
kTwo,
|
||||
kThree,
|
||||
} num_keys = kNotPresent;
|
||||
if (t->HasInstruction("NumKeys")) {
|
||||
std::string num_keys_str;
|
||||
t->GetInstruction(&num_keys_str, "NumKeys");
|
||||
const int n = strtoul(num_keys_str.c_str(), nullptr, 0);
|
||||
if (n == 2) {
|
||||
num_keys = kTwo;
|
||||
} else if (n == 3) {
|
||||
num_keys = kThree;
|
||||
} else {
|
||||
t->PrintLine("invalid NumKeys value");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string count;
|
||||
std::vector<uint8_t> keys, key1, key2, key3, iv, in, result;
|
||||
const std::string in_label =
|
||||
operation == kEncrypt ? "PLAINTEXT" : "CIPHERTEXT";
|
||||
// clang-format off
|
||||
if (!t->GetAttribute(&count, "COUNT") ||
|
||||
(num_keys == 0 && !t->GetBytes(&keys, "KEYs")) ||
|
||||
(num_keys > 0 &&
|
||||
(!t->GetBytes(&key1, "KEY1") ||
|
||||
!t->GetBytes(&key2, "KEY2") ||
|
||||
!t->GetBytes(&key3, "KEY3"))) ||
|
||||
(ctx->has_iv && !t->GetBytes(&iv, "IV")) ||
|
||||
!t->GetBytes(&in, in_label)) {
|
||||
return false;
|
||||
}
|
||||
// clang-format on
|
||||
std::vector<uint8_t> key;
|
||||
if (num_keys != kNotPresent) {
|
||||
key.insert(key.end(), key1.begin(), key1.end());
|
||||
key.insert(key.end(), key2.begin(), key2.end());
|
||||
if (num_keys == kThree) {
|
||||
key.insert(key.end(), key3.begin(), key3.end());
|
||||
}
|
||||
} else {
|
||||
key.insert(key.end(), keys.begin(), keys.end());
|
||||
key.insert(key.end(), keys.begin(), keys.end());
|
||||
key.insert(key.end(), keys.begin(), keys.end());
|
||||
}
|
||||
|
||||
if (!CipherOperation(ctx->cipher, &result, operation == kEncrypt, key, iv,
|
||||
in)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TDES fax files output format differs from file to file, and the input
|
||||
// format is inconsistent with the output, so we construct the output manually
|
||||
// rather than printing CurrentTestToString().
|
||||
if (t->IsAtNewInstructionBlock() && num_keys == kNotPresent) {
|
||||
// If NumKeys is present, header is printed when parsing NumKeys.
|
||||
std::string header = operation == kEncrypt ? "[ENCRYPT]" : "[DECRYPT]";
|
||||
printf("%s\r\n", header.c_str());
|
||||
}
|
||||
const std::string result_label =
|
||||
operation == kEncrypt ? "CIPHERTEXT" : "PLAINTEXT";
|
||||
printf("COUNT = %s\r\n", count.c_str());
|
||||
if (num_keys == kNotPresent) {
|
||||
printf("KEYs = %s\r\n", EncodeHex(keys).c_str());
|
||||
} else {
|
||||
printf("KEY1 = %s\r\nKEY2 = %s\r\nKEY3 = %s\r\n", EncodeHex(key1).c_str(),
|
||||
EncodeHex(key2).c_str(), EncodeHex(key3).c_str());
|
||||
}
|
||||
if (ctx->has_iv) {
|
||||
printf("IV = %s\r\n", EncodeHex(iv).c_str());
|
||||
}
|
||||
printf("%s = %s\r\n", in_label.c_str(), EncodeHex(in).c_str());
|
||||
printf("%s = %s\r\n\r\n", result_label.c_str(), EncodeHex(result).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// XORKeyWithOddParityLSB sets |*key| to |key| XOR |value| and then writes
|
||||
// the LSB of each byte to establish odd parity for that byte. This parity-based
|
||||
// embedded of a DES key into 64 bits is an old tradition and something that
|
||||
// NIST's tests require.
|
||||
static void XORKeyWithOddParityLSB(std::vector<uint8_t> *key,
|
||||
const std::vector<uint8_t> &value) {
|
||||
for (size_t i = 0; i < key->size(); i++) {
|
||||
uint8_t v = (*key)[i] ^ value[i];
|
||||
|
||||
// Use LSB to establish odd parity.
|
||||
v |= 0x01;
|
||||
for (uint8_t j = 1; j < 8; j++) {
|
||||
v ^= ((v >> j) & 0x01);
|
||||
}
|
||||
(*key)[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
static bool TestMCT(FileTest *t, void *arg) {
|
||||
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);
|
||||
|
||||
if (t->HasInstruction("ENCRYPT") == t->HasInstruction("DECRYPT")) {
|
||||
t->PrintLine("Want either ENCRYPT or DECRYPT");
|
||||
return false;
|
||||
}
|
||||
enum {
|
||||
kEncrypt,
|
||||
kDecrypt,
|
||||
} operation = t->HasInstruction("ENCRYPT") ? kEncrypt : kDecrypt;
|
||||
|
||||
if (t->HasAttribute("NumKeys")) {
|
||||
// Another file format quirk: NumKeys is a single attribute line immediately
|
||||
// following an instruction and should probably have been an instruction
|
||||
// instead.
|
||||
std::string num_keys;
|
||||
t->GetAttribute(&num_keys, "NumKeys");
|
||||
t->InjectInstruction("NumKeys", num_keys);
|
||||
return true;
|
||||
}
|
||||
|
||||
enum {
|
||||
kTwo,
|
||||
kThree,
|
||||
} num_keys;
|
||||
std::string num_keys_str;
|
||||
if (!t->GetInstruction(&num_keys_str, "NumKeys")) {
|
||||
return false;
|
||||
} else {
|
||||
const int n = strtoul(num_keys_str.c_str(), nullptr, 0);
|
||||
if (n == 2) {
|
||||
num_keys = kTwo;
|
||||
} else if (n == 3) {
|
||||
num_keys = kThree;
|
||||
} else {
|
||||
t->PrintLine("invalid NumKeys value");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string count;
|
||||
std::vector<uint8_t> key1, key2, key3, iv, in, result;
|
||||
const std::string in_label =
|
||||
operation == kEncrypt ? "PLAINTEXT" : "CIPHERTEXT";
|
||||
// clang-format off
|
||||
if (!t->GetBytes(&key1, "KEY1") ||
|
||||
!t->GetBytes(&key2, "KEY2") ||
|
||||
!t->GetBytes(&key3, "KEY3") ||
|
||||
(ctx->has_iv && !t->GetBytes(&iv, "IV")) ||
|
||||
!t->GetBytes(&in, in_label)) {
|
||||
return false;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
for (int i = 0; i < 400; i++) {
|
||||
std::vector<uint8_t> current_iv = iv, current_in = in, prev_result,
|
||||
prev_prev_result;
|
||||
|
||||
std::vector<uint8_t> key(key1);
|
||||
key.insert(key.end(), key2.begin(), key2.end());
|
||||
key.insert(key.end(), key3.begin(), key3.end());
|
||||
|
||||
for (int j = 0; j < 10000; j++) {
|
||||
prev_prev_result = prev_result;
|
||||
prev_result = result;
|
||||
const EVP_CIPHER *cipher = ctx->cipher;
|
||||
if (!CipherOperation(cipher, &result, operation == kEncrypt, key,
|
||||
current_iv, current_in)) {
|
||||
t->PrintLine("CipherOperation failed");
|
||||
return false;
|
||||
}
|
||||
if (ctx->has_iv) {
|
||||
if (operation == kEncrypt) {
|
||||
if (j == 0) {
|
||||
current_in = current_iv;
|
||||
} else {
|
||||
current_in = prev_result;
|
||||
}
|
||||
current_iv = result;
|
||||
} else { // operation == kDecrypt
|
||||
current_iv = current_in;
|
||||
current_in = result;
|
||||
}
|
||||
} else {
|
||||
current_in = result;
|
||||
}
|
||||
}
|
||||
|
||||
// Output result for COUNT = i.
|
||||
const std::string result_label =
|
||||
operation == kEncrypt ? "CIPHERTEXT" : "PLAINTEXT";
|
||||
if (i == 0) {
|
||||
const std::string op_label =
|
||||
operation == kEncrypt ? "ENCRYPT" : "DECRYPT";
|
||||
printf("[%s]\n\n", op_label.c_str());
|
||||
}
|
||||
printf("COUNT = %d\r\nKEY1 = %s\r\nKEY2 = %s\r\nKEY3 = %s\r\n", i,
|
||||
EncodeHex(key1).c_str(), EncodeHex(key2).c_str(),
|
||||
EncodeHex(key3).c_str());
|
||||
if (ctx->has_iv) {
|
||||
printf("IV = %s\r\n", EncodeHex(iv).c_str());
|
||||
}
|
||||
printf("%s = %s\r\n", in_label.c_str(), EncodeHex(in).c_str());
|
||||
printf("%s = %s\r\n\r\n", result_label.c_str(), EncodeHex(result).c_str());
|
||||
|
||||
|
||||
XORKeyWithOddParityLSB(&key1, result);
|
||||
XORKeyWithOddParityLSB(&key2, prev_result);
|
||||
if (num_keys == kThree) {
|
||||
XORKeyWithOddParityLSB(&key3, prev_prev_result);
|
||||
} else {
|
||||
XORKeyWithOddParityLSB(&key3, result);
|
||||
}
|
||||
|
||||
if (ctx->has_iv) {
|
||||
if (operation == kEncrypt) {
|
||||
in = prev_result;
|
||||
iv = result;
|
||||
} else {
|
||||
iv = current_iv;
|
||||
in = current_in;
|
||||
}
|
||||
} else {
|
||||
in = result;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int usage(char *arg) {
|
||||
fprintf(stderr, "usage: %s (kat|mct) <cipher> <test file>\n", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cavp_tdes_test_main(int argc, char **argv) {
|
||||
if (argc != 4) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
const std::string tm(argv[1]);
|
||||
enum TestCtx::Mode test_mode;
|
||||
if (tm == "kat") {
|
||||
test_mode = TestCtx::kKAT;
|
||||
} else if (tm == "mct") {
|
||||
test_mode = TestCtx::kMCT;
|
||||
} else {
|
||||
fprintf(stderr, "invalid test_mode: %s\n", tm.c_str());
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
const std::string cipher_name(argv[2]);
|
||||
const EVP_CIPHER *cipher = GetCipher(argv[2]);
|
||||
if (cipher == nullptr) {
|
||||
fprintf(stderr, "invalid cipher: %s\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
bool has_iv = cipher_name != "des-ede" && cipher_name != "des-ede3";
|
||||
TestCtx ctx = {cipher, has_iv, test_mode};
|
||||
|
||||
FileTestFunc test_fn = test_mode == TestCtx::kKAT ? &TestKAT : &TestMCT;
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[3];
|
||||
opts.callback = test_fn;
|
||||
opts.arg = &ctx;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
/* 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. */
|
||||
|
||||
#include "cavp_test_util.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/digest.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/nid.h>
|
||||
|
||||
|
||||
const EVP_CIPHER *GetCipher(const std::string &name) {
|
||||
if (name == "des-cbc") {
|
||||
return EVP_des_cbc();
|
||||
} else if (name == "des-ecb") {
|
||||
return EVP_des_ecb();
|
||||
} else if (name == "des-ede") {
|
||||
return EVP_des_ede();
|
||||
} else if (name == "des-ede3") {
|
||||
return EVP_des_ede3();
|
||||
} else if (name == "des-ede-cbc") {
|
||||
return EVP_des_ede_cbc();
|
||||
} else if (name == "des-ede3-cbc") {
|
||||
return EVP_des_ede3_cbc();
|
||||
} else if (name == "rc4") {
|
||||
return EVP_rc4();
|
||||
} else if (name == "aes-128-ecb") {
|
||||
return EVP_aes_128_ecb();
|
||||
} else if (name == "aes-256-ecb") {
|
||||
return EVP_aes_256_ecb();
|
||||
} else if (name == "aes-128-cbc") {
|
||||
return EVP_aes_128_cbc();
|
||||
} else if (name == "aes-128-gcm") {
|
||||
return EVP_aes_128_gcm();
|
||||
} else if (name == "aes-128-ofb") {
|
||||
return EVP_aes_128_ofb();
|
||||
} else if (name == "aes-192-cbc") {
|
||||
return EVP_aes_192_cbc();
|
||||
} else if (name == "aes-192-ctr") {
|
||||
return EVP_aes_192_ctr();
|
||||
} else if (name == "aes-192-ecb") {
|
||||
return EVP_aes_192_ecb();
|
||||
} else if (name == "aes-256-cbc") {
|
||||
return EVP_aes_256_cbc();
|
||||
} else if (name == "aes-128-ctr") {
|
||||
return EVP_aes_128_ctr();
|
||||
} else if (name == "aes-256-ctr") {
|
||||
return EVP_aes_256_ctr();
|
||||
} else if (name == "aes-256-gcm") {
|
||||
return EVP_aes_256_gcm();
|
||||
} else if (name == "aes-256-ofb") {
|
||||
return EVP_aes_256_ofb();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CipherOperation(const EVP_CIPHER *cipher, std::vector<uint8_t> *out,
|
||||
bool encrypt, const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &iv,
|
||||
const std::vector<uint8_t> &in) {
|
||||
bssl::ScopedEVP_CIPHER_CTX ctx;
|
||||
if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr,
|
||||
encrypt ? 1 : 0)) {
|
||||
return false;
|
||||
}
|
||||
if (!iv.empty() && iv.size() != EVP_CIPHER_CTX_iv_length(ctx.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int result_len1 = 0, result_len2;
|
||||
*out = std::vector<uint8_t>(in.size());
|
||||
if (!EVP_CIPHER_CTX_set_key_length(ctx.get(), key.size()) ||
|
||||
!EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, key.data(), iv.data(),
|
||||
-1) ||
|
||||
!EVP_CIPHER_CTX_set_padding(ctx.get(), 0) ||
|
||||
!EVP_CipherUpdate(ctx.get(), out->data(), &result_len1, in.data(),
|
||||
in.size()) ||
|
||||
!EVP_CipherFinal_ex(ctx.get(), out->data() + result_len1, &result_len2)) {
|
||||
return false;
|
||||
}
|
||||
out->resize(result_len1 + result_len2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AEADEncrypt(const EVP_AEAD *aead, std::vector<uint8_t> *ct,
|
||||
std::vector<uint8_t> *tag, size_t tag_len,
|
||||
const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &pt,
|
||||
const std::vector<uint8_t> &aad,
|
||||
const std::vector<uint8_t> &iv) {
|
||||
bssl::ScopedEVP_AEAD_CTX ctx;
|
||||
if (!EVP_AEAD_CTX_init(ctx.get(), aead, key.data(), key.size(), tag_len,
|
||||
nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> out;
|
||||
out.resize(pt.size() + EVP_AEAD_max_overhead(aead));
|
||||
size_t out_len;
|
||||
if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(), iv.data(),
|
||||
iv.size(), pt.data(), pt.size(), aad.data(),
|
||||
aad.size())) {
|
||||
return false;
|
||||
}
|
||||
out.resize(out_len);
|
||||
|
||||
ct->assign(out.begin(), out.end() - tag_len);
|
||||
tag->assign(out.end() - tag_len, out.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AEADDecrypt(const EVP_AEAD *aead, std::vector<uint8_t> *pt, size_t pt_len,
|
||||
const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &aad,
|
||||
const std::vector<uint8_t> &ct,
|
||||
const std::vector<uint8_t> &tag,
|
||||
const std::vector<uint8_t> &iv) {
|
||||
bssl::ScopedEVP_AEAD_CTX ctx;
|
||||
if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(),
|
||||
tag.size(), evp_aead_open)) {
|
||||
return false;
|
||||
}
|
||||
std::vector<uint8_t> in = ct;
|
||||
in.reserve(ct.size() + tag.size());
|
||||
in.insert(in.end(), tag.begin(), tag.end());
|
||||
|
||||
pt->resize(pt_len);
|
||||
size_t out_pt_len;
|
||||
if (!EVP_AEAD_CTX_open(ctx.get(), pt->data(), &out_pt_len, pt->size(),
|
||||
iv.data(), iv.size(), in.data(), in.size(), aad.data(),
|
||||
aad.size()) ||
|
||||
out_pt_len != pt_len) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int HexToBIGNUM(bssl::UniquePtr<BIGNUM> *out, const char *in) {
|
||||
BIGNUM *raw = NULL;
|
||||
int ret = BN_hex2bn(&raw, in);
|
||||
out->reset(raw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *attribute) {
|
||||
std::string hex;
|
||||
if (!t->GetAttribute(&hex, attribute)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<BIGNUM> ret;
|
||||
if (HexToBIGNUM(&ret, hex.c_str()) != static_cast<int>(hex.size())) {
|
||||
t->PrintLine("Could not decode '%s'.", hex.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int GetECGroupNIDFromInstruction(FileTest *t, const char **out_str) {
|
||||
const char *dummy;
|
||||
if (out_str == nullptr) {
|
||||
out_str = &dummy;
|
||||
}
|
||||
|
||||
if (t->HasInstruction("P-224")) {
|
||||
*out_str = "P-224";
|
||||
return NID_secp224r1;
|
||||
}
|
||||
if (t->HasInstruction("P-256")) {
|
||||
*out_str = "P-256";
|
||||
return NID_X9_62_prime256v1;
|
||||
}
|
||||
if (t->HasInstruction("P-384")) {
|
||||
*out_str = "P-384";
|
||||
return NID_secp384r1;
|
||||
}
|
||||
if (t->HasInstruction("P-521")) {
|
||||
*out_str = "P-521";
|
||||
return NID_secp521r1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void EchoComment(const std::string& comment) {
|
||||
fwrite(comment.c_str(), comment.size(), 1, stdout);
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/* 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. */
|
||||
|
||||
#ifndef OPENSSL_HEADER_CRYPTO_FIPSMODULE_CAVP_TEST_UTIL_H
|
||||
#define OPENSSL_HEADER_CRYPTO_FIPSMODULE_CAVP_TEST_UTIL_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/aead.h>
|
||||
#include <openssl/cipher.h>
|
||||
|
||||
#include "../crypto/test/file_test.h"
|
||||
|
||||
|
||||
const EVP_CIPHER *GetCipher(const std::string &name);
|
||||
|
||||
bool CipherOperation(const EVP_CIPHER *cipher, std::vector<uint8_t> *out,
|
||||
bool encrypt, const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &iv,
|
||||
const std::vector<uint8_t> &in);
|
||||
|
||||
bool AEADEncrypt(const EVP_AEAD *aead, std::vector<uint8_t> *ct,
|
||||
std::vector<uint8_t> *tag, size_t tag_len,
|
||||
const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &pt,
|
||||
const std::vector<uint8_t> &aad,
|
||||
const std::vector<uint8_t> &iv);
|
||||
|
||||
bool AEADDecrypt(const EVP_AEAD *aead, std::vector<uint8_t> *pt, size_t pt_len,
|
||||
const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &aad,
|
||||
const std::vector<uint8_t> &ct,
|
||||
const std::vector<uint8_t> &tag,
|
||||
const std::vector<uint8_t> &iv);
|
||||
|
||||
bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *attribute);
|
||||
|
||||
int GetECGroupNIDFromInstruction(FileTest *t, const char **out_str = nullptr);
|
||||
|
||||
const EVP_MD *GetDigestFromInstruction(FileTest *t);
|
||||
|
||||
void EchoComment(const std::string& comment);
|
||||
|
||||
int cavp_aes_gcm_test_main(int argc, char **argv);
|
||||
int cavp_aes_test_main(int argc, char **argv);
|
||||
int cavp_ctr_drbg_test_main(int argc, char **argv);
|
||||
int cavp_ecdsa2_keypair_test_main(int argc, char **argv);
|
||||
int cavp_ecdsa2_pkv_test_main(int argc, char **argv);
|
||||
int cavp_ecdsa2_siggen_test_main(int argc, char **argv);
|
||||
int cavp_ecdsa2_sigver_test_main(int argc, char **argv);
|
||||
int cavp_hmac_test_main(int argc, char **argv);
|
||||
int cavp_kas_test_main(int argc, char **argv);
|
||||
int cavp_keywrap_test_main(int argc, char **argv);
|
||||
int cavp_rsa2_keygen_test_main(int argc, char **argv);
|
||||
int cavp_rsa2_siggen_test_main(int argc, char **argv);
|
||||
int cavp_rsa2_sigver_test_main(int argc, char **argv);
|
||||
int cavp_sha_monte_test_main(int argc, char **argv);
|
||||
int cavp_sha_test_main(int argc, char **argv);
|
||||
int cavp_tdes_test_main(int argc, char **argv);
|
||||
int cavp_tlskdf_test_main(int argc, char **argv);
|
||||
|
||||
|
||||
#endif // OPENSSL_HEADER_CRYPTO_FIPSMODULE_CAVP_TEST_UTIL_H
|
||||
@@ -1,113 +0,0 @@
|
||||
/* Copyright (c) 2018, 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_tlskdf_test processes NIST TLS KDF test vectors and emits the
|
||||
// corresponding response.
|
||||
// See https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/components/askdfvs.pdf, section 6.4.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <openssl/digest.h>
|
||||
|
||||
#include "cavp_test_util.h"
|
||||
#include "../crypto/fipsmodule/tls/internal.h"
|
||||
#include "../crypto/test/file_test.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
|
||||
|
||||
static bool TestTLSKDF(FileTest *t, void *arg) {
|
||||
const EVP_MD *md = nullptr;
|
||||
|
||||
if (t->HasInstruction("TLS 1.0/1.1")) {
|
||||
md = EVP_md5_sha1();
|
||||
} else if (t->HasInstruction("TLS 1.2")) {
|
||||
if (t->HasInstruction("SHA-256")) {
|
||||
md = EVP_sha256();
|
||||
} else if (t->HasInstruction("SHA-384")) {
|
||||
md = EVP_sha384();
|
||||
} else if (t->HasInstruction("SHA-512")) {
|
||||
md = EVP_sha512();
|
||||
}
|
||||
}
|
||||
|
||||
if (md == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string key_block_len_str;
|
||||
std::vector<uint8_t> premaster, server_random, client_random,
|
||||
key_block_server_random, key_block_client_random;
|
||||
if (!t->GetBytes(&premaster, "pre_master_secret") ||
|
||||
!t->GetBytes(&server_random, "serverHello_random") ||
|
||||
!t->GetBytes(&client_random, "clientHello_random") ||
|
||||
// The NIST tests specify different client and server randoms for the
|
||||
// expansion step from the master-secret step. This is impossible in TLS.
|
||||
!t->GetBytes(&key_block_server_random, "server_random") ||
|
||||
!t->GetBytes(&key_block_client_random, "client_random") ||
|
||||
!t->GetInstruction(&key_block_len_str, "key block length") ||
|
||||
// These are ignored.
|
||||
!t->HasAttribute("COUNT") ||
|
||||
!t->HasInstruction("pre-master secret length")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t master_secret[48];
|
||||
static const char kMasterSecretLabel[] = "master secret";
|
||||
if (!CRYPTO_tls1_prf(md, master_secret, sizeof(master_secret),
|
||||
premaster.data(), premaster.size(), kMasterSecretLabel,
|
||||
sizeof(kMasterSecretLabel) - 1, client_random.data(),
|
||||
client_random.size(), server_random.data(),
|
||||
server_random.size())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
const long int key_block_bits =
|
||||
strtol(key_block_len_str.c_str(), nullptr, 10);
|
||||
if (errno != 0 || key_block_bits <= 0 || (key_block_bits & 7) != 0) {
|
||||
return false;
|
||||
}
|
||||
const size_t key_block_len = key_block_bits / 8;
|
||||
std::vector<uint8_t> key_block(key_block_len);
|
||||
static const char kLabel[] = "key expansion";
|
||||
if (!CRYPTO_tls1_prf(
|
||||
md, key_block.data(), key_block.size(), master_secret,
|
||||
sizeof(master_secret), kLabel, sizeof(kLabel) - 1,
|
||||
key_block_server_random.data(), key_block_server_random.size(),
|
||||
key_block_client_random.data(), key_block_client_random.size())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("%smaster_secret = %s\r\nkey_block = %s\r\n\r\n",
|
||||
t->CurrentTestToString().c_str(), EncodeHex(master_secret).c_str(),
|
||||
EncodeHex(key_block).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int cavp_tlskdf_test_main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <test file>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileTest::Options opts;
|
||||
opts.path = argv[1];
|
||||
opts.callback = TestTLSKDF;
|
||||
opts.silent = true;
|
||||
opts.comment_callback = EchoComment;
|
||||
return FileTestMain(opts);
|
||||
}
|
||||
@@ -1,592 +0,0 @@
|
||||
// run_cavp.go processes CAVP input files and generates suitable response
|
||||
// files, optionally comparing the results against the provided FAX files.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
oraclePath = flag.String("oracle-bin", "", "Path to the oracle binary")
|
||||
suiteDir = flag.String("suite-dir", "", "Base directory containing the CAVP test suite")
|
||||
noFAX = flag.Bool("no-fax", false, "Skip comparing against FAX files")
|
||||
android = flag.Bool("android", false, "Run tests via ADB")
|
||||
)
|
||||
|
||||
const (
|
||||
androidTmpPath = "/data/local/tmp/"
|
||||
androidCAVPPath = androidTmpPath + "cavp"
|
||||
androidLibCryptoPath = androidTmpPath + "libcrypto.so"
|
||||
)
|
||||
|
||||
// test describes a single request file.
|
||||
type test struct {
|
||||
// inFile is the base of the filename without an extension, i.e.
|
||||
// “ECBMCT128”.
|
||||
inFile string
|
||||
// args are the arguments (not including the input filename) to the
|
||||
// oracle binary.
|
||||
args []string
|
||||
// noFAX, if true, indicates that the output cannot be compared against
|
||||
// the FAX file. (E.g. because the primitive is non-deterministic.)
|
||||
noFAX bool
|
||||
}
|
||||
|
||||
// nextLineState can be used by FAX next-line function to store state.
|
||||
type nextLineState struct {
|
||||
// State used by the KAS test.
|
||||
nextIsIUTHash bool
|
||||
}
|
||||
|
||||
// testSuite describes a series of tests that are handled by a single oracle
|
||||
// binary.
|
||||
type testSuite struct {
|
||||
// directory is the name of the directory in the CAVP input, i.e. “AES”.
|
||||
directory string
|
||||
// suite names the test suite to pass as the first command-line argument.
|
||||
suite string
|
||||
// nextLineFunc, if not nil, is the function used to read the next line
|
||||
// from the FAX file. This can be used to skip lines and/or mutate them
|
||||
// as needed. The second argument can be used by the scanner to store
|
||||
// state, if needed. If isWildcard is true on return then line is not
|
||||
// meaningful and any line from the response file should be accepted.
|
||||
nextLineFunc func(*bufio.Scanner, *nextLineState) (line string, isWildcard, ok bool)
|
||||
tests []test
|
||||
}
|
||||
|
||||
func (t *testSuite) getDirectory() string {
|
||||
return filepath.Join(*suiteDir, t.directory)
|
||||
}
|
||||
|
||||
var aesGCMTests = testSuite{
|
||||
"AES_GCM",
|
||||
"aes_gcm",
|
||||
nil,
|
||||
[]test{
|
||||
{"gcmDecrypt128", []string{"dec", "aes-128-gcm"}, false},
|
||||
{"gcmDecrypt192", []string{"dec", "aes-192-gcm"}, false},
|
||||
{"gcmDecrypt256", []string{"dec", "aes-256-gcm"}, false},
|
||||
{"gcmEncryptExtIV128", []string{"enc", "aes-128-gcm"}, false},
|
||||
{"gcmEncryptExtIV192", []string{"enc", "aes-192-gcm"}, false},
|
||||
{"gcmEncryptExtIV256", []string{"enc", "aes-256-gcm"}, false},
|
||||
},
|
||||
}
|
||||
|
||||
var aesTests = testSuite{
|
||||
"AES",
|
||||
"aes",
|
||||
nil,
|
||||
[]test{
|
||||
{"CBCGFSbox128", []string{"kat", "aes-128-cbc"}, false},
|
||||
{"CBCGFSbox192", []string{"kat", "aes-192-cbc"}, false},
|
||||
{"CBCGFSbox256", []string{"kat", "aes-256-cbc"}, false},
|
||||
{"CBCKeySbox128", []string{"kat", "aes-128-cbc"}, false},
|
||||
{"CBCKeySbox192", []string{"kat", "aes-192-cbc"}, false},
|
||||
{"CBCKeySbox256", []string{"kat", "aes-256-cbc"}, false},
|
||||
{"CBCMMT128", []string{"kat", "aes-128-cbc"}, false},
|
||||
{"CBCMMT192", []string{"kat", "aes-192-cbc"}, false},
|
||||
{"CBCMMT256", []string{"kat", "aes-256-cbc"}, false},
|
||||
{"CBCVarKey128", []string{"kat", "aes-128-cbc"}, false},
|
||||
{"CBCVarKey192", []string{"kat", "aes-192-cbc"}, false},
|
||||
{"CBCVarKey256", []string{"kat", "aes-256-cbc"}, false},
|
||||
{"CBCVarTxt128", []string{"kat", "aes-128-cbc"}, false},
|
||||
{"CBCVarTxt192", []string{"kat", "aes-192-cbc"}, false},
|
||||
{"CBCVarTxt256", []string{"kat", "aes-256-cbc"}, false},
|
||||
{"ECBGFSbox128", []string{"kat", "aes-128-ecb"}, false},
|
||||
{"ECBGFSbox192", []string{"kat", "aes-192-ecb"}, false},
|
||||
{"ECBGFSbox256", []string{"kat", "aes-256-ecb"}, false},
|
||||
{"ECBKeySbox128", []string{"kat", "aes-128-ecb"}, false},
|
||||
{"ECBKeySbox192", []string{"kat", "aes-192-ecb"}, false},
|
||||
{"ECBKeySbox256", []string{"kat", "aes-256-ecb"}, false},
|
||||
{"ECBMMT128", []string{"kat", "aes-128-ecb"}, false},
|
||||
{"ECBMMT192", []string{"kat", "aes-192-ecb"}, false},
|
||||
{"ECBMMT256", []string{"kat", "aes-256-ecb"}, false},
|
||||
{"ECBVarKey128", []string{"kat", "aes-128-ecb"}, false},
|
||||
{"ECBVarKey192", []string{"kat", "aes-192-ecb"}, false},
|
||||
{"ECBVarKey256", []string{"kat", "aes-256-ecb"}, false},
|
||||
{"ECBVarTxt128", []string{"kat", "aes-128-ecb"}, false},
|
||||
{"ECBVarTxt192", []string{"kat", "aes-192-ecb"}, false},
|
||||
{"ECBVarTxt256", []string{"kat", "aes-256-ecb"}, false},
|
||||
// AES Monte-Carlo tests
|
||||
{"ECBMCT128", []string{"mct", "aes-128-ecb"}, false},
|
||||
{"ECBMCT192", []string{"mct", "aes-192-ecb"}, false},
|
||||
{"ECBMCT256", []string{"mct", "aes-256-ecb"}, false},
|
||||
{"CBCMCT128", []string{"mct", "aes-128-cbc"}, false},
|
||||
{"CBCMCT192", []string{"mct", "aes-192-cbc"}, false},
|
||||
{"CBCMCT256", []string{"mct", "aes-256-cbc"}, false},
|
||||
},
|
||||
}
|
||||
|
||||
var ecdsa2KeyPairTests = testSuite{
|
||||
"ECDSA2",
|
||||
"ecdsa2_keypair",
|
||||
nil,
|
||||
[]test{{"KeyPair", nil, true}},
|
||||
}
|
||||
|
||||
var ecdsa2PKVTests = testSuite{
|
||||
"ECDSA2",
|
||||
"ecdsa2_pkv",
|
||||
nil,
|
||||
[]test{{"PKV", nil, false}},
|
||||
}
|
||||
|
||||
var ecdsa2SigGenTests = testSuite{
|
||||
"ECDSA2",
|
||||
"ecdsa2_siggen",
|
||||
nil,
|
||||
[]test{
|
||||
{"SigGen", []string{"SigGen"}, true},
|
||||
{"SigGenComponent", []string{"SigGenComponent"}, true},
|
||||
},
|
||||
}
|
||||
|
||||
var ecdsa2SigVerTests = testSuite{
|
||||
"ECDSA2",
|
||||
"ecdsa2_sigver",
|
||||
nil,
|
||||
[]test{{"SigVer", nil, false}},
|
||||
}
|
||||
|
||||
var rsa2KeyGenTests = testSuite{
|
||||
"RSA2",
|
||||
"rsa2_keygen",
|
||||
nil,
|
||||
[]test{
|
||||
{"KeyGen_RandomProbablyPrime3_3", nil, true},
|
||||
},
|
||||
}
|
||||
|
||||
var rsa2SigGenTests = testSuite{
|
||||
"RSA2",
|
||||
"rsa2_siggen",
|
||||
nil,
|
||||
[]test{
|
||||
{"SigGen15_186-3", []string{"pkcs15"}, true},
|
||||
{"SigGenPSS_186-3", []string{"pss"}, true},
|
||||
},
|
||||
}
|
||||
|
||||
var rsa2SigVerTests = testSuite{
|
||||
"RSA2",
|
||||
"rsa2_sigver",
|
||||
func(s *bufio.Scanner, state *nextLineState) (string, bool, bool) {
|
||||
for {
|
||||
if !s.Scan() {
|
||||
return "", false, false
|
||||
}
|
||||
|
||||
line := s.Text()
|
||||
if strings.HasPrefix(line, "p = ") || strings.HasPrefix(line, "d = ") || strings.HasPrefix(line, "SaltVal = ") || strings.HasPrefix(line, "EM with ") {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "q = ") {
|
||||
// Skip the "q = " line and an additional blank line.
|
||||
if !s.Scan() ||
|
||||
len(strings.TrimSpace(s.Text())) > 0 {
|
||||
return "", false, false
|
||||
}
|
||||
continue
|
||||
}
|
||||
return line, false, true
|
||||
}
|
||||
},
|
||||
[]test{
|
||||
{"SigVer15_186-3", []string{"pkcs15"}, false},
|
||||
{"SigVerPSS_186-3", []string{"pss"}, false},
|
||||
},
|
||||
}
|
||||
|
||||
var hmacTests = testSuite{
|
||||
"HMAC",
|
||||
"hmac",
|
||||
nil,
|
||||
[]test{{"HMAC", nil, false}},
|
||||
}
|
||||
|
||||
var shaTests = testSuite{
|
||||
"SHA",
|
||||
"sha",
|
||||
nil,
|
||||
[]test{
|
||||
{"SHA1LongMsg", []string{"SHA1"}, false},
|
||||
{"SHA1ShortMsg", []string{"SHA1"}, false},
|
||||
{"SHA224LongMsg", []string{"SHA224"}, false},
|
||||
{"SHA224ShortMsg", []string{"SHA224"}, false},
|
||||
{"SHA256LongMsg", []string{"SHA256"}, false},
|
||||
{"SHA256ShortMsg", []string{"SHA256"}, false},
|
||||
{"SHA384LongMsg", []string{"SHA384"}, false},
|
||||
{"SHA384ShortMsg", []string{"SHA384"}, false},
|
||||
{"SHA512LongMsg", []string{"SHA512"}, false},
|
||||
{"SHA512ShortMsg", []string{"SHA512"}, false},
|
||||
},
|
||||
}
|
||||
|
||||
var shaMonteTests = testSuite{
|
||||
"SHA",
|
||||
"sha_monte",
|
||||
nil,
|
||||
[]test{
|
||||
{"SHA1Monte", []string{"SHA1"}, false},
|
||||
{"SHA224Monte", []string{"SHA224"}, false},
|
||||
{"SHA256Monte", []string{"SHA256"}, false},
|
||||
{"SHA384Monte", []string{"SHA384"}, false},
|
||||
{"SHA512Monte", []string{"SHA512"}, false},
|
||||
},
|
||||
}
|
||||
|
||||
var ctrDRBGTests = testSuite{
|
||||
"DRBG800-90A",
|
||||
"ctr_drbg",
|
||||
nil,
|
||||
[]test{{"CTR_DRBG", nil, false}},
|
||||
}
|
||||
|
||||
var tdesTests = testSuite{
|
||||
"TDES",
|
||||
"tdes",
|
||||
nil,
|
||||
[]test{
|
||||
{"TCBCMMT2", []string{"kat", "des-ede-cbc"}, false},
|
||||
{"TCBCMMT3", []string{"kat", "des-ede3-cbc"}, false},
|
||||
{"TCBCMonte2", []string{"mct", "des-ede3-cbc"}, false},
|
||||
{"TCBCMonte3", []string{"mct", "des-ede3-cbc"}, false},
|
||||
{"TCBCinvperm", []string{"kat", "des-ede3-cbc"}, false},
|
||||
{"TCBCpermop", []string{"kat", "des-ede3-cbc"}, false},
|
||||
{"TCBCsubtab", []string{"kat", "des-ede3-cbc"}, false},
|
||||
{"TCBCvarkey", []string{"kat", "des-ede3-cbc"}, false},
|
||||
{"TCBCvartext", []string{"kat", "des-ede3-cbc"}, false},
|
||||
{"TECBMMT2", []string{"kat", "des-ede"}, false},
|
||||
{"TECBMMT3", []string{"kat", "des-ede3"}, false},
|
||||
{"TECBMonte2", []string{"mct", "des-ede3"}, false},
|
||||
{"TECBMonte3", []string{"mct", "des-ede3"}, false},
|
||||
{"TECBinvperm", []string{"kat", "des-ede3"}, false},
|
||||
{"TECBpermop", []string{"kat", "des-ede3"}, false},
|
||||
{"TECBsubtab", []string{"kat", "des-ede3"}, false},
|
||||
{"TECBvarkey", []string{"kat", "des-ede3"}, false},
|
||||
{"TECBvartext", []string{"kat", "des-ede3"}, false},
|
||||
},
|
||||
}
|
||||
|
||||
var keyWrapTests = testSuite{
|
||||
"KeyWrap38F",
|
||||
"keywrap",
|
||||
nil,
|
||||
[]test{
|
||||
{"KW_AD_128", []string{"dec", "128"}, false},
|
||||
{"KW_AD_192", []string{"dec", "192"}, false},
|
||||
{"KW_AD_256", []string{"dec", "256"}, false},
|
||||
{"KW_AE_128", []string{"enc", "128"}, false},
|
||||
{"KW_AE_192", []string{"enc", "192"}, false},
|
||||
{"KW_AE_256", []string{"enc", "256"}, false},
|
||||
{"KWP_AD_128", []string{"dec-pad", "128"}, false},
|
||||
{"KWP_AD_192", []string{"dec-pad", "192"}, false},
|
||||
{"KWP_AD_256", []string{"dec-pad", "256"}, false},
|
||||
{"KWP_AE_128", []string{"enc-pad", "128"}, false},
|
||||
{"KWP_AE_192", []string{"enc-pad", "192"}, false},
|
||||
{"KWP_AE_256", []string{"enc-pad", "256"}, false},
|
||||
},
|
||||
}
|
||||
|
||||
var kasTests = testSuite{
|
||||
"KAS",
|
||||
"kas",
|
||||
func(s *bufio.Scanner, state *nextLineState) (line string, isWildcard, ok bool) {
|
||||
for {
|
||||
// If the response file will include the IUT hash next,
|
||||
// return a wildcard signal because this cannot be
|
||||
// matched against the FAX file.
|
||||
if state.nextIsIUTHash {
|
||||
state.nextIsIUTHash = false
|
||||
return "", true, true
|
||||
}
|
||||
|
||||
if !s.Scan() {
|
||||
return "", false, false
|
||||
}
|
||||
|
||||
line := s.Text()
|
||||
if strings.HasPrefix(line, "deCAVS = ") || strings.HasPrefix(line, "Z = ") {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "CAVSHashZZ = ") {
|
||||
state.nextIsIUTHash = true
|
||||
}
|
||||
return line, false, true
|
||||
}
|
||||
},
|
||||
[]test{
|
||||
{"KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_init", []string{"function"}, true},
|
||||
{"KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_resp", []string{"function"}, true},
|
||||
{"KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_init", []string{"validity"}, false},
|
||||
{"KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_resp", []string{"validity"}, false},
|
||||
},
|
||||
}
|
||||
|
||||
var tlsKDFTests = testSuite{
|
||||
"KDF135",
|
||||
"tlskdf",
|
||||
nil,
|
||||
[]test{
|
||||
{"tls", nil, false},
|
||||
},
|
||||
}
|
||||
|
||||
var testSuites = []*testSuite{
|
||||
&aesGCMTests,
|
||||
&aesTests,
|
||||
&ctrDRBGTests,
|
||||
&ecdsa2KeyPairTests,
|
||||
&ecdsa2PKVTests,
|
||||
&ecdsa2SigGenTests,
|
||||
&ecdsa2SigVerTests,
|
||||
&hmacTests,
|
||||
&keyWrapTests,
|
||||
&rsa2KeyGenTests,
|
||||
&rsa2SigGenTests,
|
||||
&rsa2SigVerTests,
|
||||
&shaTests,
|
||||
&shaMonteTests,
|
||||
&tdesTests,
|
||||
&kasTests,
|
||||
&tlsKDFTests,
|
||||
}
|
||||
|
||||
// testInstance represents a specific test in a testSuite.
|
||||
type testInstance struct {
|
||||
suite *testSuite
|
||||
testIndex int
|
||||
}
|
||||
|
||||
func worker(wg *sync.WaitGroup, work <-chan testInstance) {
|
||||
defer wg.Done()
|
||||
|
||||
for ti := range work {
|
||||
test := ti.suite.tests[ti.testIndex]
|
||||
|
||||
if err := doTest(ti.suite, test); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
if !*noFAX && !test.noFAX {
|
||||
if err := compareFAX(ti.suite, test); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkAndroidPrereqs() error {
|
||||
// The cavp binary, and a matching libcrypto.so, are required to be placed
|
||||
// in /data/local/tmp before running this script.
|
||||
if err := exec.Command("adb", "shell", "ls", androidCAVPPath).Run(); err != nil {
|
||||
return errors.New("failed to list cavp binary; ensure that adb works and cavp binary is in place: " + err.Error())
|
||||
}
|
||||
if err := exec.Command("adb", "shell", "ls", androidLibCryptoPath).Run(); err != nil {
|
||||
return errors.New("failed to list libcrypto.so; ensure that library is in place: " + err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if *android {
|
||||
if err := checkAndroidPrereqs(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if len(*oraclePath) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "Must give -oracle-bin\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
work := make(chan testInstance)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
numWorkers := runtime.NumCPU()
|
||||
if *android {
|
||||
numWorkers = 1
|
||||
}
|
||||
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
wg.Add(1)
|
||||
go worker(&wg, work)
|
||||
}
|
||||
|
||||
for _, suite := range testSuites {
|
||||
for i := range suite.tests {
|
||||
work <- testInstance{suite, i}
|
||||
}
|
||||
}
|
||||
|
||||
close(work)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func doTest(suite *testSuite, test test) error {
|
||||
bin := *oraclePath
|
||||
var args []string
|
||||
|
||||
if *android {
|
||||
bin = "adb"
|
||||
args = []string{"shell", "LD_LIBRARY_PATH=" + androidTmpPath, androidCAVPPath}
|
||||
}
|
||||
|
||||
args = append(args, suite.suite)
|
||||
args = append(args, test.args...)
|
||||
reqPath := filepath.Join(suite.getDirectory(), "req", test.inFile+".req")
|
||||
var reqPathOnDevice string
|
||||
|
||||
if *android {
|
||||
reqPathOnDevice = path.Join(androidTmpPath, test.inFile+".req")
|
||||
if err := exec.Command("adb", "push", reqPath, reqPathOnDevice).Run(); err != nil {
|
||||
return errors.New("failed to push request file: " + err.Error())
|
||||
}
|
||||
args = append(args, reqPathOnDevice)
|
||||
} else {
|
||||
args = append(args, reqPath)
|
||||
}
|
||||
|
||||
respDir := filepath.Join(suite.getDirectory(), "resp")
|
||||
if err := os.Mkdir(respDir, 0755); err != nil && !os.IsExist(err) {
|
||||
return fmt.Errorf("cannot create resp directory: %s", err)
|
||||
}
|
||||
outPath := filepath.Join(respDir, test.inFile+".rsp")
|
||||
outFile, err := os.OpenFile(outPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot open output file for %q %q: %s", suite.getDirectory(), test.inFile, err)
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
cmd := exec.Command(bin, args...)
|
||||
cmd.Stdout = outFile
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
cmdLine := strings.Join(append([]string{bin}, args...), " ")
|
||||
startTime := time.Now()
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("cannot run command for %q %q (%s): %s", suite.getDirectory(), test.inFile, cmdLine, err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s (%ds)\n", cmdLine, int(time.Since(startTime).Seconds()))
|
||||
|
||||
if *android {
|
||||
exec.Command("adb", "shell", "rm", reqPathOnDevice).Run()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func canonicalizeLine(in string) string {
|
||||
if strings.HasPrefix(in, "Result = P (") {
|
||||
return "Result = P"
|
||||
}
|
||||
if strings.HasPrefix(in, "Result = F (") {
|
||||
return "Result = F"
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
func compareFAX(suite *testSuite, test test) error {
|
||||
nextLineFunc := suite.nextLineFunc
|
||||
if nextLineFunc == nil {
|
||||
nextLineFunc = func(s *bufio.Scanner, state *nextLineState) (string, bool, bool) {
|
||||
if !s.Scan() {
|
||||
return "", false, false
|
||||
}
|
||||
return s.Text(), false, true
|
||||
}
|
||||
}
|
||||
|
||||
respPath := filepath.Join(suite.getDirectory(), "resp", test.inFile+".rsp")
|
||||
respFile, err := os.Open(respPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read output of %q %q: %s", suite.getDirectory(), test.inFile, err)
|
||||
}
|
||||
defer respFile.Close()
|
||||
|
||||
faxPath := filepath.Join(suite.getDirectory(), "fax", test.inFile+".fax")
|
||||
faxFile, err := os.Open(faxPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot open fax file for %q %q: %s", suite.getDirectory(), test.inFile, err)
|
||||
}
|
||||
defer faxFile.Close()
|
||||
|
||||
respScanner := bufio.NewScanner(respFile)
|
||||
faxScanner := bufio.NewScanner(faxFile)
|
||||
var nextLineState nextLineState
|
||||
|
||||
lineNo := 0
|
||||
inHeader := true
|
||||
|
||||
for respScanner.Scan() {
|
||||
lineNo++
|
||||
respLine := respScanner.Text()
|
||||
var faxLine string
|
||||
var isWildcard, ok bool
|
||||
|
||||
if inHeader && (len(respLine) == 0 || respLine[0] == '#') {
|
||||
continue
|
||||
}
|
||||
|
||||
for {
|
||||
haveFaxLine := false
|
||||
|
||||
if inHeader {
|
||||
for {
|
||||
if faxLine, isWildcard, ok = nextLineFunc(faxScanner, &nextLineState); !ok {
|
||||
break
|
||||
}
|
||||
if len(faxLine) != 0 && faxLine[0] != '#' {
|
||||
haveFaxLine = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
inHeader = false
|
||||
} else {
|
||||
faxLine, isWildcard, haveFaxLine = nextLineFunc(faxScanner, &nextLineState)
|
||||
}
|
||||
|
||||
if !haveFaxLine {
|
||||
// Ignore blank lines at the end of the generated file.
|
||||
if len(respLine) == 0 {
|
||||
break
|
||||
}
|
||||
return fmt.Errorf("resp file is longer than fax for %q %q", suite.getDirectory(), test.inFile)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(faxLine, " (Reason: ") {
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if isWildcard || canonicalizeLine(faxLine) == canonicalizeLine(respLine) {
|
||||
continue
|
||||
}
|
||||
|
||||
return fmt.Errorf("resp and fax differ at line %d for %q %q: %q vs %q", lineNo, suite.getDirectory(), test.inFile, respLine, faxLine)
|
||||
}
|
||||
|
||||
if _, _, ok := nextLineFunc(faxScanner, &nextLineState); ok {
|
||||
return fmt.Errorf("fax file is longer than resp for %q %q", suite.getDirectory(), test.inFile)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
set -x
|
||||
set -e
|
||||
|
||||
TEST_FIPS_BIN="build/util/fipstools/cavp/test_fips"
|
||||
TEST_FIPS_BIN="build/util/fipstools/test_fips"
|
||||
|
||||
if [ ! -f $TEST_FIPS_BIN ]; then
|
||||
echo "$TEST_FIPS_BIN is missing. Run this script from the top level of a"
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "../crypto/fipsmodule/rand/internal.h"
|
||||
#include "../crypto/fipsmodule/tls/internal.h"
|
||||
#include "../crypto/internal.h"
|
||||
#include "../../crypto/fipsmodule/rand/internal.h"
|
||||
#include "../../crypto/fipsmodule/tls/internal.h"
|
||||
#include "../../crypto/internal.h"
|
||||
|
||||
|
||||
static void hexdump(const void *a, size_t len) {
|
||||
Reference in New Issue
Block a user