1071 lines
47 KiB
C
1071 lines
47 KiB
C
/* Copyright (c) (2012,2013,2014,2015,2016,2017,2018,2019,2020) Apple Inc. All rights reserved.
|
||
*
|
||
* corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which
|
||
* is contained in the License.txt file distributed with corecrypto) and only to
|
||
* people who accept that license. IMPORTANT: Any license rights granted to you by
|
||
* Apple Inc. (if any) are limited to internal use within your organization only on
|
||
* devices and computers you own or control, for the sole purpose of verifying the
|
||
* security characteristics and correct functioning of the Apple Software. You may
|
||
* not, directly or indirectly, redistribute the Apple Software or any portions thereof.
|
||
*/
|
||
#include "testmore.h"
|
||
#include "testbyteBuffer.h"
|
||
#include "testccnBuffer.h"
|
||
|
||
#if (CCEC == 0)
|
||
entryPoint(ccec_tests, "ccec")
|
||
#else
|
||
|
||
#include <corecrypto/ccec.h>
|
||
#include <corecrypto/ccec_priv.h>
|
||
#include "ccec_internal.h"
|
||
#include <corecrypto/ccrng_test.h>
|
||
#include <corecrypto/ccsha1.h>
|
||
#include <corecrypto/ccsha2.h>
|
||
#include <corecrypto/ccrng_pbkdf2_prng.h>
|
||
#include <corecrypto/ccrng_sequence.h>
|
||
#include "crypto_test_ec.h"
|
||
#include <corecrypto/ccder.h>
|
||
|
||
static int verbose = 1;
|
||
|
||
#define MAXKEYSPACE 8192
|
||
|
||
struct ccec_pbkdf2_keygen_vector {
|
||
ccec_const_cp_t (*cp)(void);
|
||
char *password;
|
||
size_t iterations;
|
||
char *str_salt;
|
||
char *str_legacy_x963_full_key;
|
||
char *str_fips_x963_full_key;
|
||
char *str_compact_x963_full_key;
|
||
};
|
||
|
||
const struct ccec_pbkdf2_keygen_vector ccec_pbkdf2_keygen_vectors[] = {
|
||
{
|
||
.cp = &ccec_cp_192,
|
||
.password = "foofoofoo",
|
||
.iterations = 1024,
|
||
.str_salt = "4141414141414141",
|
||
.str_legacy_x963_full_key = "04b2c06c91874594ac7a9a11e015021dbfce8be82937c44ee8f49736d538ed23af7d57b64ef11aed308b405deb6a"
|
||
"6712f54cd97af15879dc056f76061796f8f71efafdf368622fddab",
|
||
.str_fips_x963_full_key = "044ea8feee26902c7df26d4fec83592c6a1fba2c2ee5463ee0467ff1c12001aa7f00ffff2e9eacad923336ded5d9b1"
|
||
"fdd3d020c30e2d7767d712049879327387988f2c5ee37b1cd2ba",
|
||
.str_compact_x963_full_key = "044ea8feee26902c7df26d4fec83592c6a1fba2c2ee5463ee0467ff1c12001aa7f00ffff2e9eacad923336ded5d"
|
||
"9b1fdd3d020c30e2d7767d712049879327387988f2c5ee37b1cd2ba",
|
||
},
|
||
{
|
||
.cp = &ccec_cp_224,
|
||
.password = "foofoofoo",
|
||
.iterations = 1024,
|
||
.str_salt = "4141414141414141",
|
||
.str_legacy_x963_full_key = "048ff2fc917799d97633df4a431cb1a2b02418a2a40c3b8153533a48d6a9f93112ff6bce3c3c9852e32a62ea7b98"
|
||
"9801f1ced7d6212b9e67ae7b1cd2b94cd97af15879dc056f76061796f8f71efafdf368622fddab",
|
||
#if CCN_UNIT_SIZE == 8
|
||
.str_fips_x963_full_key = "04c3312a8817ea34d7eb72a5af0bbd9804558904e7ea070835545f60d875e09171c9d992c3440d14d2f3587bd33594"
|
||
"83968ec6683d0b38a0bc00e5745c885181d60a580111d020c30e2d7767d71204987932738799",
|
||
#elif CCN_UNIT_SIZE == 4
|
||
.str_fips_x963_full_key = "043b468f17be760e163c76eaf61468a8fede4e57032b5747301241be09aa70886d8d9e79fe2ee49c49c98fc62dae64"
|
||
"ceec37cf30647acfd9b9885181d60a580111d020c30e2d7767d712049879327387988f2c5ee4",
|
||
#endif
|
||
},
|
||
{
|
||
.cp = &ccec_cp_256,
|
||
.password = "foofoofoo",
|
||
.iterations = 1024,
|
||
.str_salt = "4141414141414141",
|
||
.str_legacy_x963_full_key =
|
||
"044c20da234c2cd2d674c42cd322de2f6c4b51ad3f9b3915342dba188a85fe48b9e4103add4611308a3b951e894dbaddb8593a520c89f39cc0a5"
|
||
"b546518ebaf38f8f2c5ee37b1cd2b94cd97af15879dc056f76061796f8f71efafdf368622fddab",
|
||
.str_fips_x963_full_key =
|
||
"049767be9128a7f6d0ac245931cf17b84846c4120bf95e5cc276a8f43d670f9d1a8d74ad12d38c776eb0baaab07301a5636b6de55aaae5c996b0"
|
||
"a5cea771f632d9f383216100e5745c885181d60a580111d020c30e2d7767d71204987932738799",
|
||
.str_compact_x963_full_key =
|
||
"049767be9128a7f6d0ac245931cf17b84846c4120bf95e5cc276a8f43d670f9d1a728b52ec2c7388924f45554f8cfe5a9c94921aa6551a36694f"
|
||
"5a31588e09cd260c7cde9dff1a8ba477ae7e29f5a7feedecc6379f79a036ade1b53249c9ef9db8",
|
||
},
|
||
{
|
||
.cp = &ccec_cp_384,
|
||
.password = "foofoofoo",
|
||
.iterations = 1024,
|
||
.str_salt = "4141414141414141",
|
||
.str_legacy_x963_full_key =
|
||
"04954955319fa1e463a7bef143e8231f347ef6fa36c25e935d00008cb7837f427207a5a93eb9dcd04a9c8b7d6501050f0982d185e05e5a632869"
|
||
"608ad7621b3a40558cd8608c1b5dd2f1705d286ca2e5f87d837cb9727df8949ed4b4fd4b6c98d1d020c30e2d7767d712049879327387988f2c5e"
|
||
"e37b1cd2b94cd97af15879dc056f76061796f8f71efafdf368622fddab",
|
||
.str_fips_x963_full_key =
|
||
"043546cb3667a75a375f7e1cddc5f133389d0fd4dcc759b8e74d80df4c4b94ece497bcd544d782f1ad84336c9decd525e4bc9f24c13826a467ba"
|
||
"e79e404befa3bc76701b62f65138736fb025b7f335add145d0cffbe534bca6c3afc1ed99b12062835a04461534742d76701b8fd0959f90913923"
|
||
"e79bbec5a393ddb9d7d69aabebf383216100e5745c885181d60a580112",
|
||
.str_compact_x963_full_key =
|
||
"043546cb3667a75a375f7e1cddc5f133389d0fd4dcc759b8e74d80df4c4b94ece497bcd544d782f1ad84336c9decd525e44360db3ec7d95b9845"
|
||
"1861bfb4105c43898fe49d09aec78c904fda480cca522dba2f30031acb43593c503e13664edf9d7ca5fbb9eacb8bd2898fe4702f6a606f6ec6dc"
|
||
"1864413a5c338593aa1d9c81f36496ec5147cb331e649a9794c26d2861",
|
||
},
|
||
{
|
||
.cp = &ccec_cp_521,
|
||
.password = "foofoofoo",
|
||
.iterations = 1024,
|
||
.str_salt = "4141414141414141",
|
||
.str_legacy_x963_full_key =
|
||
"0400c968e680dc020dea239817ba7ac407b14fc92059f3757f63d037869cd262fadbcae8ca005cc9a86f3dbcd15328084667cff94e1a4fd3b8d1"
|
||
"d529a29955c92a620f012c5aa28b4aab652b2654d5e19da7f90ce4f6be300e09072d0cc676814043aeb564c38f7f74db3fb27cfe7bd19322a2f7"
|
||
"727f26989a49c97cd135cfe986472e024a01ebf383216100e5745c885181d60a580111d020c30e2d7767d712049879327387988f2c5ee37b1cd2"
|
||
"b94cd97af15879dc056f76061796f8f71efafdf368622fddab",
|
||
#if CCN_UNIT_SIZE == 8
|
||
.str_fips_x963_full_key =
|
||
"040122a5b2a09234374c143614d4ee897c6aba09a674cf748de994ca2c2e2debc4b198b2259b780ccf71204492b38595b9efc6a0e8f3a5f83ebb"
|
||
"6a28b20f79a4d223a8014a9575f2cde7bae68f502ccfe39a04db658eff2714b3e6c19b3d634dfbd6c36c6a6f201e5f483f3e942310bedebf1e50"
|
||
"ad7600c32d9f795496d12bee9f6036236001129e9e8ecba2f709fb2a1a8969ec192a0e93a43b6963d38ee902929da64df51c7317ad70ff94e3e6"
|
||
"f1835a04461534742d76701b8fd0959f90913923e79bbec5a4",
|
||
#elif CCN_UNIT_SIZE == 4
|
||
.str_fips_x963_full_key =
|
||
"0401edd47f457e722edd62a432f2eb90ccc2dfa8c018c3ca2c3cd2afeadceec71801fd98ee99e555ffb67229d4d0f0e0d7c8cbb7a754e05191e6"
|
||
"1d4aa09e356c08e9f70186b37bcb63bb89a3d543d6049077c22ffc4a39f6935c422e20ba15946ba77b9918fdad631677c6df396202ac785bfa04"
|
||
"9415da185908231af7ec6810500fb715c300cba2f709fb2a1a8969ec192a0e93a43b6963d38ee902929da64df51c7317ad70ff94e3e6f1835a04"
|
||
"461534742d76701b8fd0959f90913923e79bbec5a393ddb9d8",
|
||
#endif
|
||
#if CCN_UNIT_SIZE == 8
|
||
.str_compact_x963_full_key =
|
||
"040122a5b2a09234374c143614d4ee897c6aba09a674cf748de994ca2c2e2debc4b198b2259b780ccf71204492b38595b9efc6a0e8f3a5f83ebb"
|
||
"6a28b20f79a4d223a800b56a8a0d3218451970afd3301c65fb249a7100d8eb4c193e64c29cb204293c939590dfe1a0b7c0c16bdcef412140e1af"
|
||
"5289ff3cd26086ab692ed411609fc9dc9f00ed616171345d08f604d5e5769613e6d5f16c5bc4969c2c7116fd6d6259b20ae38739d916842a4baf"
|
||
"79fc71fd02e1d531a2c545ae28b906a81e2a369336f5799e65",
|
||
#elif CCN_UNIT_SIZE == 4
|
||
.str_compact_x963_full_key =
|
||
"0401edd47f457e722edd62a432f2eb90ccc2dfa8c018c3ca2c3cd2afeadceec71801fd98ee99e555ffb67229d4d0f0e0d7c8cbb7a754e05191e6"
|
||
"1d4aa09e356c08e9f700794c84349c44765c2abc29fb6f883dd003b5c6096ca3bdd1df45ea6b94588466e702529ce9883920c69dfd5387a405fb"
|
||
"6bea25e7a6f7dce5081397efaff048ea3c01345d08f604d5e5769613e6d5f16c5bc4969c2c7116fd6d6259b20ae38ce8528efabca2a0923bd592"
|
||
"256a978d1b80998a406b202a27f86323c71fb0f17afd5aaa31",
|
||
#endif
|
||
},
|
||
};
|
||
|
||
static int ccec_keys_are_equal(ccec_full_ctx_t full_key, byteBuffer x963_ec_full_key, size_t test_nb)
|
||
{
|
||
int status = 1;
|
||
// Export key
|
||
size_t bufsiz = ccec_x963_export_size(1, ccec_ctx_pub(full_key));
|
||
uint8_t buf[bufsiz];
|
||
ccec_x963_export(1, buf, full_key);
|
||
|
||
// Compare with expect value
|
||
status &= is(x963_ec_full_key->len, bufsiz, "Key size mismatch for test");
|
||
status &=
|
||
ok_memcmp(buf, x963_ec_full_key->bytes, bufsiz, "%d bit EC Key mismatch for test %d", ccec_ctx_bitlen(full_key), test_nb);
|
||
return status;
|
||
}
|
||
|
||
static int ECStaticGenTest(void)
|
||
{
|
||
for (size_t i = 0; i < sizeof(ccec_pbkdf2_keygen_vectors) / sizeof(ccec_pbkdf2_keygen_vectors[0]); i++) {
|
||
const struct ccec_pbkdf2_keygen_vector *test_vector = &ccec_pbkdf2_keygen_vectors[i];
|
||
ccec_const_cp_t cp = test_vector->cp();
|
||
struct ccrng_pbkdf2_prng_state pbkdf2_prng;
|
||
ccec_full_ctx_decl_cp(cp, full_key);
|
||
|
||
size_t iterations = 1024;
|
||
|
||
struct ccrng_state *rng2 = (struct ccrng_state *)&pbkdf2_prng;
|
||
byteBuffer x963_ec_full_key_legacy = hexStringToBytes(test_vector->str_legacy_x963_full_key);
|
||
byteBuffer x963_ec_full_key_fips = hexStringToBytes(test_vector->str_fips_x963_full_key);
|
||
byteBuffer x963_ec_full_key_compact = hexStringToBytes(test_vector->str_compact_x963_full_key);
|
||
byteBuffer x963_ec_full_key_default = hexStringToBytes(test_vector->str_fips_x963_full_key); // Default is FIPS
|
||
byteBuffer salt = hexStringToBytes(test_vector->str_salt);
|
||
|
||
// Legacy
|
||
ok_or_fail(ccrng_pbkdf2_prng_init(&pbkdf2_prng,
|
||
2 * ccn_sizeof(ccec_cp_order_bitlen(cp)),
|
||
strlen(test_vector->password),
|
||
test_vector->password,
|
||
salt->len,
|
||
salt->bytes,
|
||
iterations) == 0,
|
||
"pbkdf2 init");
|
||
if (x963_ec_full_key_legacy->len && (is(ccec_generate_key_legacy(cp, rng2, full_key), 0, "Generate Legacy"))) {
|
||
ok(ccec_keys_are_equal(full_key, x963_ec_full_key_legacy, i), "Check legacy key");
|
||
}
|
||
|
||
// FIPS
|
||
ok_or_fail(ccrng_pbkdf2_prng_init(&pbkdf2_prng,
|
||
8 * ccn_sizeof(ccec_cp_order_bitlen(cp)),
|
||
strlen(test_vector->password),
|
||
test_vector->password,
|
||
salt->len,
|
||
salt->bytes,
|
||
iterations) == 0,
|
||
"pbkdf2 init");
|
||
if (x963_ec_full_key_fips->len && (is(ccec_generate_key_fips(cp, rng2, full_key), 0, "Generate FIPS"))) {
|
||
ok(ccec_keys_are_equal(full_key, x963_ec_full_key_fips, i), "Check FIPS key");
|
||
}
|
||
|
||
// Compact
|
||
ok_or_fail(ccrng_pbkdf2_prng_init(&pbkdf2_prng,
|
||
8 * ccn_sizeof(ccec_cp_order_bitlen(cp)),
|
||
strlen(test_vector->password),
|
||
test_vector->password,
|
||
salt->len,
|
||
salt->bytes,
|
||
iterations) == 0,
|
||
"pbkdf2 init");
|
||
if (x963_ec_full_key_compact->len && (is(ccec_compact_generate_key(cp, rng2, full_key), 0, "Generate compact"))) {
|
||
ok(ccec_keys_are_equal(full_key, x963_ec_full_key_compact, i), "Check compact key");
|
||
}
|
||
|
||
// Default
|
||
ok_or_fail(ccrng_pbkdf2_prng_init(&pbkdf2_prng,
|
||
8 * ccn_sizeof(ccec_cp_order_bitlen(cp)),
|
||
strlen(test_vector->password),
|
||
test_vector->password,
|
||
salt->len,
|
||
salt->bytes,
|
||
iterations) == 0,
|
||
"pbkdf2 init");
|
||
if (x963_ec_full_key_default->len && (is(ccec_generate_key(cp, rng2, full_key), 0, "Generate default"))) {
|
||
ok(ccec_keys_are_equal(full_key, x963_ec_full_key_default, i), "Check default key");
|
||
}
|
||
|
||
ok(ccecdh_pairwise_consistency_check(full_key, NULL, global_test_rng), "Key is good");
|
||
|
||
free(x963_ec_full_key_legacy);
|
||
free(x963_ec_full_key_fips);
|
||
free(x963_ec_full_key_compact);
|
||
free(x963_ec_full_key_default);
|
||
free(salt);
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
static void fill(int *guard)
|
||
{
|
||
guard[0] = -1;
|
||
guard[1] = -1;
|
||
guard[2] = -1;
|
||
guard[3] = -1;
|
||
}
|
||
|
||
static int chkit(int *guard)
|
||
{
|
||
return guard[0] == -1 && guard[1] == -1 && guard[2] == -1 && guard[3] == -1;
|
||
}
|
||
|
||
static int ccec_diversify_pub_twin_tests()
|
||
{
|
||
ccec_const_cp_t cp = ccec_cp_256();
|
||
|
||
ccec_pub_ctx_decl_cp(cp, pub_in);
|
||
ccec_pub_ctx_decl_cp(cp, pub_out);
|
||
ccec_ctx_init(cp, pub_in);
|
||
ccec_ctx_init(cp, pub_out);
|
||
|
||
ccec_full_ctx_decl_cp(cp, full_in);
|
||
ccec_full_ctx_decl_cp(cp, full_out);
|
||
ccec_ctx_init(cp, full_in);
|
||
ccec_ctx_init(cp, full_out);
|
||
|
||
// Test vectors created/checked with SageMath.
|
||
// clang-format off
|
||
const cc_unit d[CCN256_N] = {
|
||
CCN256_C(00,01,02,03,04,05,06,07,08,09,0a,0b,0c,0d,0e,0f,10,11,12,13,14,15,16,17,18,19,1a,1b,1c,1d,1e,1f)
|
||
};
|
||
const cc_unit x[CCN256_N] = {
|
||
CCN256_C(b9,c6,a6,d7,9a,5f,60,ce,9c,3a,0a,f3,8c,80,74,dd,4f,57,8e,ca,ce,6d,d7,c5,ff,92,13,b8,35,34,6a,73)
|
||
};
|
||
const cc_unit y[CCN256_N] = {
|
||
CCN256_C(a3,a5,17,b2,11,de,0b,75,65,a4,cd,ac,c2,b1,65,1a,b9,9f,bc,e4,8b,82,4c,71,5b,9d,34,76,58,d9,9b,4d)
|
||
};
|
||
// clang-format on
|
||
|
||
// Some entropy with different values for each scalar.
|
||
const uint8_t entropy[80] = {
|
||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
|
||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
|
||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
|
||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1
|
||
};
|
||
|
||
int rv = ccec_make_pub_from_priv(cp, global_test_rng, d, NULL, pub_in);
|
||
is(rv, 0, "Make public key");
|
||
|
||
cc_assert(sizeof(entropy) == 2 * ccec_diversify_min_entropy_len(cp));
|
||
rv = ccec_diversify_pub_twin(cp, pub_in, sizeof(entropy), entropy, global_test_rng, pub_out);
|
||
is(rv, 0, "ccec_diversify_pub_twin failed");
|
||
|
||
ok_ccn_cmp(CCN256_N, ccec_ctx_x(pub_out), x, "Unexpected x-coordinate");
|
||
ok_ccn_cmp(CCN256_N, ccec_ctx_y(pub_out), y, "Unexpected y-coordinate");
|
||
|
||
// len(entropy) must be a multiple of two.
|
||
rv = ccec_diversify_pub_twin(cp, pub_in, sizeof(entropy) - 1, entropy, global_test_rng, pub_out);
|
||
is(rv, CCERR_PARAMETER, "ccec_diversify_pub_twin should fail");
|
||
|
||
// len(entropy) must be >= 2 * ccec_diversify_min_entropy_len(cp).
|
||
rv = ccec_diversify_pub_twin(cp, pub_in, sizeof(entropy) - 2, entropy, global_test_rng, pub_out);
|
||
is(rv, CCERR_PARAMETER, "ccec_diversify_pub_twin should fail");
|
||
|
||
// Test vectors created/checked with SageMath.
|
||
// clang-format off
|
||
const cc_unit x2[CCN256_N] = {
|
||
CCN256_C(0d,0a,69,9e,d7,99,e1,25,96,ad,af,8d,04,79,28,36,02,af,ce,ad,cf,97,d1,3b,44,ec,15,a9,39,58,89,ff)
|
||
};
|
||
const cc_unit y2[CCN256_N] = {
|
||
CCN256_C(b1,e1,96,9a,42,5d,6d,be,4f,ce,32,63,a3,67,e3,0f,a6,aa,96,2f,1d,c8,dd,97,e7,fd,43,c2,de,b0,b4,e8)
|
||
};
|
||
// clang-format on
|
||
|
||
// More entropy with different values for each scalar.
|
||
const uint8_t entropy_long[96] = { 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
|
||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
|
||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
|
||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
|
||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
|
||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
|
||
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1 };
|
||
|
||
rv = ccec_diversify_pub_twin(cp, pub_in, sizeof(entropy_long), entropy_long, global_test_rng, pub_out);
|
||
is(rv, 0, "ccec_diversify_pub_twin failed");
|
||
|
||
ok_ccn_cmp(CCN256_N, ccec_ctx_x(pub_out), x2, "Unexpected x-coordinate");
|
||
ok_ccn_cmp(CCN256_N, ccec_ctx_y(pub_out), y2, "Unexpected y-coordinate");
|
||
|
||
// Point to diversify must be on the curve.
|
||
(void)ccn_add1(CCN256_N, ccec_ctx_x(pub_in), ccec_ctx_x(pub_in), 1);
|
||
rv = ccec_diversify_pub_twin(cp, pub_in, sizeof(entropy), entropy, global_test_rng, pub_out);
|
||
isnt(rv, 0, "ccec_diversify_pub_twin should fail");
|
||
|
||
// Construct a private key.
|
||
ccn_set(CCN256_N, ccec_ctx_k(full_in), d);
|
||
ccn_seti(CCN256_N, ccec_ctx_z(full_in), 1);
|
||
rv = ccec_make_pub_from_priv(cp, global_test_rng, d, NULL, ccec_ctx_pub(full_in));
|
||
is(rv, 0, "Make private key");
|
||
|
||
// Compute a delegate.
|
||
rv = ccec_diversify_priv_twin(cp, ccec_ctx_k(full_in), sizeof(entropy), entropy, global_test_rng, full_out);
|
||
is(rv, 0, "ccec_diversify_priv_twin failed");
|
||
|
||
ok_ccn_cmp(CCN256_N, ccec_ctx_x(full_out), x, "Unexpected x-coordinate");
|
||
ok_ccn_cmp(CCN256_N, ccec_ctx_y(full_out), y, "Unexpected y-coordinate");
|
||
ok(ccec_pairwise_consistency_check(full_out, global_test_rng), "Invalid private key");
|
||
|
||
// len(entropy) must be a multiple of two.
|
||
rv = ccec_diversify_priv_twin(cp, ccec_ctx_k(full_in), sizeof(entropy) - 1, entropy, global_test_rng, full_out);
|
||
is(rv, CCERR_PARAMETER, "ccec_diversify_priv_twin should fail");
|
||
|
||
// len(entropy) must be >= 2 * ccec_diversify_min_entropy_len(cp).
|
||
rv = ccec_diversify_priv_twin(cp, ccec_ctx_k(full_in), sizeof(entropy) - 2, entropy, global_test_rng, full_out);
|
||
is(rv, CCERR_PARAMETER, "ccec_diversify_priv_twin should fail");
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int ccec_cczp_mod_prime_tests(size_t bits, ccec_const_cp_t cp)
|
||
{
|
||
cczp_const_t zp = (cczp_const_t)cp;
|
||
cc_size n = cczp_n(zp);
|
||
cc_unit a[n], b[n], r[n], s[n];
|
||
|
||
cc_unit t[n * 2];
|
||
ccn_clear(n * 2, t);
|
||
|
||
// A few random tests.
|
||
for (size_t i = 0; i < 10000; i++) {
|
||
ccn_clear(n, a);
|
||
ccn_clear(n, b);
|
||
ccn_clear(n, r);
|
||
ccn_clear(n, s);
|
||
|
||
ccn_random_bits(bits, a, global_test_rng);
|
||
ccn_random_bits(bits, b, global_test_rng);
|
||
|
||
ccn_mul(n, t, a, b);
|
||
cczp_modn(zp, s, n * 2, t);
|
||
|
||
cczp_to(zp, a, a);
|
||
cczp_to(zp, b, b);
|
||
cczp_mul(zp, r, a, b);
|
||
cczp_from(zp, r, r);
|
||
|
||
ok_ccn_cmp(n, r, s, "Results don't match");
|
||
|
||
CC_DECL_WORKSPACE_OR_FAIL(ws,
|
||
CC_MAX_EVAL(CCZP_MOD_WORKSPACE_N(n), CCN_DIV_EUCLID_WORKSPACE_SIZE(n * 2, n)));
|
||
cczp_mod_ws(ws, zp, r, t);
|
||
ok_ccn_cmp(n, r, s, "Results don't match");
|
||
|
||
// cczp_modn() and cczp_mod_ws() above use the reciprocal given by the
|
||
// ccec_const_cp_t structure. Check that we get the same result when
|
||
// re-computing the reciprocal on the fly.
|
||
ccn_mod_ws(ws, n, r, n * 2, t, n, cczp_prime(zp));
|
||
ok_ccn_cmp(n, r, s, "Results don't match");
|
||
CC_FREE_WORKSPACE(ws);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static void ccec_test_xcoord_internal(ccec_const_cp_t cp, size_t y_length, uint8_t *y)
|
||
{
|
||
int rc;
|
||
uint8_t x[1] = { 0 };
|
||
uint8_t *shared_secret = malloc(y_length);
|
||
size_t shared_secret_len = y_length;
|
||
|
||
ccec_pub_ctx_decl_cp(cp, public_key);
|
||
ccec_full_ctx_decl_cp(cp, private_key);
|
||
|
||
rc = ccec_make_pub(ccec_cp_prime_bitlen(cp), sizeof(x), x, y_length, y, public_key);
|
||
is(rc, CCERR_OK, "Couldn't make public key with xcoord 0");
|
||
|
||
rc = ccecdh_generate_key(cp, global_test_rng, private_key);
|
||
is(rc, CCERR_OK, "Couldn't generate a full key");
|
||
|
||
rc = ccecdh_compute_shared_secret(private_key, public_key, &shared_secret_len, shared_secret, global_test_rng);
|
||
isnt(rc, 0, "Shared secret computation should fail");
|
||
free(shared_secret);
|
||
}
|
||
|
||
static int ccec_test_xcoord_zero(void)
|
||
{
|
||
uint8_t y256[32] = { 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 0x49,
|
||
0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 0x0b };
|
||
|
||
uint8_t y384[48] = { 0x3c, 0xf9, 0x9e, 0xf0, 0x4f, 0x51, 0xa5, 0xea, 0x63, 0x0b, 0xa3, 0xf9, 0xf9, 0x60, 0xdd, 0x59,
|
||
0x3a, 0x14, 0xc9, 0xbe, 0x39, 0xfd, 0x2b, 0xd2, 0x15, 0xd3, 0xb4, 0xb0, 0x8a, 0xaa, 0xf8, 0x6b,
|
||
0xbf, 0x92, 0x7f, 0x2c, 0x46, 0xe5, 0x2a, 0xb0, 0x6f, 0xb7, 0x42, 0xb8, 0x85, 0x0e, 0x52, 0x1e };
|
||
|
||
ccec_test_xcoord_internal(ccec_cp_256(), sizeof(y256), y256);
|
||
ccec_test_xcoord_internal(ccec_cp_384(), sizeof(y384), y384);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int ccec_generate_rng_edgecases(ccec_const_cp_t cp)
|
||
{
|
||
int top[4];
|
||
ccec_full_ctx_decl_cp(cp, key);
|
||
ccec_ctx_init(cp, key);
|
||
int bot[4];
|
||
fill(top);
|
||
fill(bot);
|
||
|
||
struct ccrng_sequence_state sequence_prng;
|
||
struct ccrng_state *fake_rng = (struct ccrng_state *)&sequence_prng;
|
||
uint8_t fake_rng_buf[MAXKEYSPACE];
|
||
|
||
// Rng always return 0
|
||
memset(fake_rng_buf, 0, sizeof(fake_rng_buf));
|
||
ccrng_sequence_init(&sequence_prng, sizeof(fake_rng_buf), fake_rng_buf);
|
||
ok_or_fail(ccec_generate_key_fips(cp, fake_rng, key) == 0, "ccec_generate_key_fips failure (should succeed)");
|
||
|
||
ok_or_fail(ccec_generate_key_legacy(cp, fake_rng, key) != 0, "Don't create EC key with 0 for K");
|
||
|
||
// Rng always returns order, needs to fail.
|
||
memcpy(fake_rng_buf, (const uint8_t *)cczp_prime(ccec_cp_zq(cp)), ccec_cp_order_size(cp));
|
||
ccrng_sequence_init(&sequence_prng, sizeof(fake_rng_buf), fake_rng_buf);
|
||
ok_or_fail(ccec_generate_key_fips(cp, fake_rng, key) != 0, "EC key gen fips with q (should fail)");
|
||
|
||
// Rng always returns order - 1, needs to fail.
|
||
memset(fake_rng_buf, 0xff, sizeof(fake_rng_buf));
|
||
memcpy(fake_rng_buf, (const uint8_t *)cczp_prime(ccec_cp_zq(cp)), ccec_cp_order_size(cp));
|
||
ccn_sub1(ccec_cp_n(cp), (cc_unit *)fake_rng_buf, (cc_unit *)fake_rng_buf, 1);
|
||
ccrng_sequence_init(&sequence_prng, sizeof(fake_rng_buf), fake_rng_buf);
|
||
ok_or_fail(ccec_generate_key_fips(cp, fake_rng, key) != 0, "EC key gen fips with q - 1 (should fail)");
|
||
|
||
// Rng always returns order - 2, needs to fail.
|
||
memset(fake_rng_buf, 0xff, sizeof(fake_rng_buf));
|
||
memcpy(fake_rng_buf, (const uint8_t *)cczp_prime(ccec_cp_zq(cp)), ccec_cp_order_size(cp));
|
||
ccn_sub1(ccec_cp_n(cp), (cc_unit *)fake_rng_buf, (cc_unit *)fake_rng_buf, 2);
|
||
ccrng_sequence_init(&sequence_prng, sizeof(fake_rng_buf), fake_rng_buf);
|
||
ok_or_fail(ccec_generate_key_fips(cp, fake_rng, key) == 0, "EC key gen fips with q - 2 (should succeed)");
|
||
|
||
// Rng always returns ff: we will never get a scalar is in the appropriate range
|
||
memset(fake_rng_buf, 0xff, sizeof(fake_rng_buf));
|
||
ccrng_sequence_init(&sequence_prng, sizeof(fake_rng_buf), fake_rng_buf);
|
||
ok_or_fail(ccec_generate_key_fips(cp, fake_rng, key) != 0, "Can't pickup scalar in range (should fail)");
|
||
ok_or_fail(chkit(top), "Generate fips wrote memory of `top`");
|
||
ok_or_fail(chkit(bot), "Generate fips wrote memory of `bot`");
|
||
|
||
return 1;
|
||
}
|
||
|
||
static int key_exchange(ccec_const_cp_t cp, ccec_full_ctx_t key1, ccec_full_ctx_t key2)
|
||
{
|
||
size_t p_len = ccn_write_uint_size(ccec_cp_n(cp), ccec_cp_p(cp));
|
||
size_t ss1_len = p_len;
|
||
size_t ss2_len = p_len;
|
||
uint8_t ss1[ss1_len];
|
||
uint8_t ss2[ss2_len];
|
||
|
||
#pragma clang diagnostic push
|
||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||
ok_or_fail(ccec_compute_key(key1, ccec_ctx_pub(key2), &ss1_len, ss1) == 0, "ccec_compute_key 1");
|
||
ok_or_fail(ccec_compute_key(key2, ccec_ctx_pub(key1), &ss2_len, ss2) == 0, "ccec_compute_key 2");
|
||
#pragma clang diagnostic pop
|
||
ok_or_fail(ss1_len == ss2_len, "ccec_compute_key length's not equal");
|
||
ok_memcmp_or_fail(ss1, ss2, ss1_len, "ccec_compute_key shared secret's differ");
|
||
|
||
ss1_len = p_len;
|
||
ss2_len = p_len;
|
||
ok_or_fail(ccecdh_compute_shared_secret(key1, ccec_ctx_pub(key2), &ss1_len, ss1, global_test_rng) == 0,
|
||
"ccecdh_compute_shared_secret 1");
|
||
ok_or_fail(ccecdh_compute_shared_secret(key2, ccec_ctx_pub(key1), &ss2_len, ss2, global_test_rng) == 0,
|
||
"ccecdh_compute_shared_secret 2");
|
||
|
||
ok_or_fail(ss1_len == ss2_len, "ccecdh_compute_shared_secret length's not equal");
|
||
ok_memcmp_or_fail(ss1, ss2, ss1_len, "ccecdh_compute_shared_secret shared secret's differ");
|
||
return 1;
|
||
}
|
||
|
||
static int verify_msg_digest(ccec_pub_ctx_t pub,
|
||
const struct ccdigest_info *di,
|
||
size_t msg_len,
|
||
uint8_t *msg,
|
||
size_t digest_len,
|
||
uint8_t *digest,
|
||
size_t sig_len,
|
||
uint8_t *signature,
|
||
char *label)
|
||
{
|
||
uint8_t r_buffer[ccec_signature_r_s_size(pub)]; // Buffer to hold r from signature
|
||
uint8_t rdigest[di->output_size]; // Digest we compute from r (r_buffer)
|
||
cc_fault_canary_t ecc_canary;
|
||
bool valid = false;
|
||
|
||
ok_status_or_goto(ccec_extract_rs(pub, sig_len, signature, r_buffer, NULL), "extract_rs failure", err);
|
||
ccdigest(di, ccec_signature_r_s_size(pub), r_buffer, rdigest);
|
||
|
||
// ccec_verify
|
||
ok_status_or_goto(ccec_verify(pub, digest_len, digest, sig_len, signature, &valid), "ccec_verify failure", err);
|
||
is_or_goto(valid, true, "ccec_verify failure bool", err);
|
||
|
||
// ccec_verify_strict
|
||
ok_status_or_goto(ccec_verify_strict(pub, digest_len, digest, sig_len, signature, &valid), "ccec_verify_strict failure", err);
|
||
is_or_goto(valid, true, "ccec_verify_strict failure bool", err);
|
||
|
||
// ccec_verify_msg(NULL)
|
||
ok_status_or_goto(ccec_verify_msg(pub, di, msg_len, msg, sig_len, signature, NULL), "ccec_verify_msg(NULL) failure", err);
|
||
|
||
// ccec_verify_msg(!NULL)
|
||
ok_status_or_goto(
|
||
ccec_verify_msg(pub, di, msg_len, msg, sig_len, signature, ecc_canary), "ccec_verify_msg(!NULL) failure", err);
|
||
bool canary_equal = CC_FAULT_CANARY_EQUAL(CCEC_FAULT_CANARY, ecc_canary);
|
||
is_or_goto(canary_equal, true, "ccec_verify_msg(!NULL) canary not equal", err);
|
||
|
||
|
||
// ccec_verify_digest(NULL)
|
||
ok_status_or_goto(
|
||
ccec_verify_digest(pub, digest_len, digest, sig_len, signature, NULL), "ccec_verify_digest(NULL) failure", err);
|
||
|
||
// ccec_verify_digest(!NULL)
|
||
ok_status_or_goto(ccec_verify_digest(pub, digest_len, digest, sig_len, signature, ecc_canary),
|
||
"ccec_verify_digest(!NULL) failure",
|
||
err);
|
||
canary_equal = CC_FAULT_CANARY_EQUAL(CCEC_FAULT_CANARY, ecc_canary);
|
||
is_or_goto(canary_equal, true, "ccec_verify_msg(!NULL) canary not equal", err);
|
||
|
||
return 0;
|
||
err:
|
||
diag("Verification failures: %s", label);
|
||
return 1;
|
||
}
|
||
|
||
static int verify_composite_msg_digest(ccec_pub_ctx_t pub,
|
||
const struct ccdigest_info *di,
|
||
size_t msg_len,
|
||
uint8_t *msg,
|
||
size_t digest_len,
|
||
uint8_t *digest,
|
||
uint8_t *sig_r,
|
||
uint8_t *sig_s,
|
||
char *label)
|
||
{
|
||
uint8_t rdigest[di->output_size]; // Digest we compute from r (r_buffer)
|
||
cc_fault_canary_t fault_canary;
|
||
bool valid = false;
|
||
|
||
ccdigest(di, ccec_signature_r_s_size(pub), sig_r, rdigest);
|
||
|
||
// ccec_verify_composite
|
||
ok_status_or_goto(ccec_verify_composite(pub, digest_len, digest, sig_r, sig_s, &valid), "ccec_verify_composite failure", err);
|
||
is_or_goto(valid, true, "ccec_verify_composite failure bool", err);
|
||
|
||
// ccec_verify_composite_msg(NULL)
|
||
ok_status_or_goto(
|
||
ccec_verify_composite_msg(pub, di, msg_len, msg, sig_r, sig_s, NULL), "cec_verify_composite_msg(NULL) failure", err);
|
||
|
||
// ccec_verify_composite_msg(!NULL)
|
||
ok_status_or_goto(ccec_verify_composite_msg(pub, di, msg_len, msg, sig_r, sig_s, fault_canary),
|
||
"ccec_verify_composite_msg(!NULL) failure",
|
||
err);
|
||
bool canary_equal = CC_FAULT_CANARY_EQUAL(CCEC_FAULT_CANARY, fault_canary);
|
||
is_or_goto(canary_equal, true, "ccec_verify_composite_msg canary not equal", err);
|
||
|
||
// ccec_verify_composite_digest(NULL)
|
||
ok_status_or_goto(ccec_verify_composite_digest(pub, digest_len, digest, sig_r, sig_s, NULL),
|
||
"cec_verify_composite_digest(NULL) failure",
|
||
err);
|
||
|
||
// ccec_verify_composite_digest(!NULL)
|
||
ok_status_or_goto(ccec_verify_composite_digest(pub, digest_len, digest, sig_r, sig_s, fault_canary),
|
||
"cec_verify_composite_digest(!NULL) failure",
|
||
err);
|
||
canary_equal = CC_FAULT_CANARY_EQUAL(CCEC_FAULT_CANARY, fault_canary);
|
||
is_or_goto(canary_equal, true, "ccec_verify_composite_msg canary not equal", err);
|
||
|
||
return 0;
|
||
err:
|
||
diag("Verification failures: %s", label);
|
||
return 1;
|
||
}
|
||
|
||
static int sign_verify(ccec_const_cp_t cp,
|
||
ccec_full_ctx_t sk,
|
||
ccec_full_ctx_t vk,
|
||
const struct ccdigest_info *di,
|
||
size_t msg_len,
|
||
uint8_t *msg)
|
||
{
|
||
uint8_t digest[di->output_size];
|
||
ccdigest(di, msg_len, msg, digest);
|
||
|
||
size_t sig_len = ccec_sign_max_size(cp);
|
||
uint8_t signature[sig_len];
|
||
uint8_t *sig_r = signature;
|
||
uint8_t *sig_s = signature + ccec_signature_r_s_size(ccec_ctx_pub(sk));
|
||
|
||
/*
|
||
ccec_sign
|
||
*/
|
||
ok_status_or_goto(
|
||
ccec_sign(sk, di->output_size, digest, &sig_len, signature, global_test_rng), "ccec_sign: Signing failure", err);
|
||
|
||
ok_status_or_goto(
|
||
verify_msg_digest(ccec_ctx_pub(vk), di, msg_len, msg, di->output_size, digest, sig_len, signature, "ccec_sign"),
|
||
"ccec_sign: verify_msg_digest failure",
|
||
err);
|
||
|
||
/*
|
||
ccec_sign_msg
|
||
*/
|
||
cc_clear(sig_len, signature);
|
||
sig_len = ccec_sign_max_size(cp);
|
||
ok_status_or_goto(
|
||
ccec_sign_msg(sk, di, msg_len, msg, &sig_len, signature, global_test_rng), "ccec_sign_msg: Signing failure", err);
|
||
|
||
ok_status_or_goto(
|
||
verify_msg_digest(ccec_ctx_pub(vk), di, msg_len, msg, di->output_size, digest, sig_len, signature, "ccec_sign_msg"),
|
||
"ccec_sign_msg: verify_msg_digest failure",
|
||
err);
|
||
|
||
/*
|
||
ccec_sign_composite
|
||
*/
|
||
cc_clear(sig_len, signature);
|
||
sig_len = ccec_sign_max_size(cp);
|
||
ok_status_or_goto(ccec_sign_composite(sk, di->output_size, digest, sig_r, sig_s, global_test_rng),
|
||
"ccec_sign_composite: Signing failure",
|
||
err);
|
||
ok_status_or_goto(verify_composite_msg_digest(
|
||
ccec_ctx_pub(vk), di, msg_len, msg, di->output_size, digest, sig_r, sig_s, "ccec_sign_composite"),
|
||
"ccec_sign_composite: verify_composite_msg_digest failure",
|
||
err);
|
||
|
||
/*
|
||
ccec_sign_composite_msg
|
||
*/
|
||
cc_clear(sig_len, signature);
|
||
sig_len = ccec_sign_max_size(cp);
|
||
ok_status_or_goto(ccec_sign_composite_msg(sk, di, msg_len, msg, sig_r, sig_s, global_test_rng),
|
||
"ccec_sign_composite_msg: Signing failure",
|
||
err);
|
||
ok_status_or_goto(verify_composite_msg_digest(
|
||
ccec_ctx_pub(vk), di, msg_len, msg, di->output_size, digest, sig_r, sig_s, "ccec_sign_composite_msg"),
|
||
"ccec_sign_composite_msg: verify_composite_msg_digest failure",
|
||
err);
|
||
|
||
return 1;
|
||
err:
|
||
return 0;
|
||
}
|
||
|
||
static int ie_copy(ccec_full_ctx_t fk, ccec_full_ctx_t ipub, ccec_full_ctx_t ipriv)
|
||
{
|
||
memcpy(ipub, fk, ccec_full_ctx_size(ccec_ccn_size(ccec_ctx_cp(fk))));
|
||
memcpy(ipriv, fk, ccec_full_ctx_size(ccec_ccn_size(ccec_ctx_cp(fk))));
|
||
return 1;
|
||
}
|
||
|
||
static int ie_x963(ccec_full_ctx_t fk, ccec_full_ctx_t ipub, ccec_full_ctx_t ipriv)
|
||
{
|
||
ccec_const_cp_t cp = ccec_ctx_cp(fk);
|
||
size_t cz = ccec_cp_prime_bitlen(cp);
|
||
|
||
size_t export_pubsize = ccec_x963_export_size(0, ccec_ctx_pub(fk));
|
||
is(export_pubsize, ccec_x963_export_size_cp(0, cp), "x963: Export size incorrect (pubkey)[cp%zu]", cz);
|
||
size_t export_privsize = ccec_x963_export_size(1, ccec_ctx_pub(fk));
|
||
is(export_privsize, ccec_x963_export_size_cp(1, cp), "x963: Export size incorrect (pubkey+privkey)[cp%zu]", cz);
|
||
|
||
uint8_t exported_pubkey[export_pubsize];
|
||
uint8_t exported_privkey[export_privsize];
|
||
ccec_x963_export(0, exported_pubkey, fk);
|
||
ccec_x963_export(1, exported_privkey, fk);
|
||
|
||
// Now we'll import the key using x963
|
||
// -----------------------------------
|
||
size_t import_pubsize = ccec_x963_import_pub_size(export_pubsize);
|
||
size_t import_privsize = ccec_x963_import_priv_size(export_privsize);
|
||
|
||
is(import_pubsize, ccec_ctx_bitlen(fk), "x963: Import size incorrect (pubkey)[cp%zu]", cz);
|
||
is(import_privsize, ccec_ctx_bitlen(fk), "x963: Import size incorrect (pubkey+privkey)[cp%zu]", cz);
|
||
ok_status_or_goto(
|
||
ccec_x963_import_pub(cp, export_pubsize, exported_pubkey, ccec_ctx_pub(ipub)), "ccec_x963_import_pub failure", err);
|
||
is_or_goto(ccec_ctx_bitlen(ipub), ccec_ctx_bitlen(fk), "x963: Incorrect imported public key size", err);
|
||
ok_status_or_goto(ccec_x963_import_priv(cp, export_privsize, exported_privkey, ipriv), "ccec_x963_import_priv failure", err);
|
||
ok_status_or_goto(
|
||
ccec_x963_import_pub(cp, export_pubsize, exported_pubkey, ccec_ctx_pub(ipriv)), "ccec_x963_import_pub failure", err);
|
||
is_or_goto(ccec_ctx_bitlen(ipriv), ccec_ctx_bitlen(fk), "x963: Incorrect imported private key size", err);
|
||
|
||
return 1;
|
||
err:
|
||
diag("x963 import / export error cp%zu", cz);
|
||
return 0;
|
||
}
|
||
|
||
static int ie_raw(ccec_full_ctx_t fk, ccec_full_ctx_t ipub, ccec_full_ctx_t ipriv)
|
||
{
|
||
ccec_const_cp_t cp = ccec_ctx_cp(fk);
|
||
size_t cz = ccec_cp_prime_bitlen(cp);
|
||
|
||
size_t export_pubsize = ccec_x963_export_size(0, ccec_ctx_pub(fk));
|
||
is(export_pubsize, ccec_x963_export_size_cp(0, cp), "x963: Export size incorrect (pubkey)[cp%zu]", cz);
|
||
size_t export_privsize = ccec_x963_export_size(1, ccec_ctx_pub(fk));
|
||
is(export_privsize, ccec_x963_export_size_cp(1, cp), "x963: Export size incorrect (pubkey+privkey)[cp%zu]", cz);
|
||
size_t es = (export_privsize - 1) / 3;
|
||
|
||
uint8_t exported_pubkey[export_pubsize];
|
||
uint8_t exported_privkey[export_privsize];
|
||
ccec_x963_export(0, exported_pubkey, fk);
|
||
ccec_x963_export(1, exported_privkey, fk);
|
||
|
||
ok_status_or_goto(
|
||
ccec_raw_import_pub(cp, export_pubsize - 1, exported_pubkey + 1, ccec_ctx_pub(ipub)), "ccec_raw_import_pub failure", err);
|
||
is_or_goto(ccec_ctx_bitlen(ipub), ccec_ctx_bitlen(fk), "raw: Incorrect imported public key size", err);
|
||
ok_status_or_goto(
|
||
ccec_raw_import_priv_only(cp, es, exported_privkey + 2 * es + 1, ipriv), "ccec_raw_import_priv_only failure", err);
|
||
ok_status_or_goto(ccec_raw_import_pub(cp, export_pubsize - 1, exported_pubkey + 1, ccec_ctx_pub(ipriv)),
|
||
"ccec_raw_import_pub failure (private key)",
|
||
err);
|
||
is_or_goto(ccec_ctx_bitlen(ipriv), ccec_ctx_bitlen(fk), "raw: Incorrect imported private key size", err);
|
||
|
||
return 1;
|
||
err:
|
||
diag("raw import / export error cp%zu", cz);
|
||
return 0;
|
||
}
|
||
|
||
static int ie_components(ccec_full_ctx_t fk, ccec_full_ctx_t ipub, ccec_full_ctx_t ipriv)
|
||
{
|
||
ccec_const_cp_t cp = ccec_ctx_cp(fk);
|
||
size_t cz = ccec_cp_prime_bitlen(cp);
|
||
|
||
cc_size n = ccec_cp_n(cp);
|
||
size_t xsize, ysize, dsize, nbits, xy_excessize_size;
|
||
xsize = ysize = dsize = nbits = ccn_sizeof_n(n);
|
||
xy_excessize_size = 2 * ccn_sizeof_n(n);
|
||
|
||
uint8_t x[xsize], y[ysize], d[dsize];
|
||
uint8_t xy_excessive[xy_excessize_size];
|
||
memset(xy_excessive, 0, xy_excessize_size);
|
||
|
||
ok_status_or_goto(
|
||
ccec_get_fullkey_components(fk, &nbits, x, &xsize, y, &ysize, d, &dsize), "ccec_get_fullkey_components failure", err);
|
||
|
||
// Negative testing
|
||
xy_excessive[0] |= 0x80; // Set the MSB so the parser thinks the entire key is valid
|
||
ok_or_goto(0 != ccec_make_pub(nbits, xsize, x, xy_excessize_size, xy_excessive, ccec_ctx_pub(ipub)),
|
||
"ccec_make_pub excessive y should fail",
|
||
err);
|
||
ok_or_goto(0 != ccec_make_pub(nbits, xy_excessize_size, xy_excessive, ysize, y, ccec_ctx_pub(ipub)),
|
||
"ccec_make_pub excessive x should fail",
|
||
err);
|
||
ok_or_goto(0 != ccec_make_priv(nbits, xsize, x, xy_excessize_size, xy_excessive, dsize, d, ipriv),
|
||
"ccec_make_priv excessive y should fail",
|
||
err);
|
||
ok_or_goto(0 != ccec_make_priv(nbits, xy_excessize_size, xy_excessive, ysize, y, dsize, d, ipriv),
|
||
"ccec_make_priv excessive x should fail",
|
||
err);
|
||
ok_or_goto(0 != ccec_make_priv(nbits, xsize, x, ysize, y, xy_excessize_size, xy_excessive, ipriv),
|
||
"ccec_make_priv excessive d should fail",
|
||
err);
|
||
|
||
// Now actually import it
|
||
ok_status_or_goto(ccec_make_pub(nbits, xsize, x, ysize, y, ccec_ctx_pub(ipub)), "ccec_make_pub failure", err);
|
||
ok_status_or_goto(ccec_make_priv(nbits, xsize, x, ysize, y, dsize, d, ipriv), "ccec_make_priv failure", err);
|
||
|
||
return 1;
|
||
err:
|
||
diag("components import / export error cp%zu", cz);
|
||
return 0;
|
||
}
|
||
|
||
static int ie_compact(ccec_full_ctx_t fk, ccec_full_ctx_t ipub, ccec_full_ctx_t ipriv)
|
||
{
|
||
ccec_const_cp_t cp = ccec_ctx_cp(fk);
|
||
size_t cz = ccec_cp_prime_bitlen(cp);
|
||
|
||
size_t export_pubsize = ccec_compact_export_size(0, ccec_ctx_pub(fk));
|
||
is(export_pubsize, ccec_compact_export_size_cp(0, cp), "Export compact size incorrect (pubkey)[%zu]", cz);
|
||
size_t export_privsize = ccec_compact_export_size(1, ccec_ctx_pub(fk));
|
||
is(export_privsize, ccec_compact_export_size_cp(1, cp), "Export compact size incorrect (pubkey+privkey)[%zu]", cz);
|
||
|
||
uint8_t exported_pubkey[export_pubsize];
|
||
uint8_t exported_pubkey2[export_pubsize];
|
||
uint8_t exported_privkey[export_privsize];
|
||
ccec_compact_export(0, exported_pubkey, fk);
|
||
ccec_compact_export_pub(exported_pubkey2, ccec_ctx_pub(fk));
|
||
ccec_compact_export(1, exported_privkey, fk);
|
||
ok_memcmp_or_goto(exported_pubkey, exported_pubkey2, export_pubsize, err, "Exported public keys neq");
|
||
|
||
ok_status_or_goto(
|
||
ccec_compact_import_pub(cp, export_pubsize, exported_pubkey, ccec_ctx_pub(ipub)), "ccec_compact_import_pub failure", err);
|
||
is_or_goto(ccec_ctx_bitlen(ipub), ccec_ctx_bitlen(fk), "compact: Incorrect imported public key size", err);
|
||
ok_status_or_goto(
|
||
ccec_compact_import_priv(cp, export_privsize, exported_privkey, ipriv), "ccec_compact_import_priv failure", err);
|
||
is_or_goto(ccec_ctx_bitlen(ipriv), ccec_ctx_bitlen(fk), "compact: Incorrect imported private key size", err);
|
||
|
||
return 1;
|
||
err:
|
||
diag("compact import / export error cp%zu", cz);
|
||
return 0;
|
||
}
|
||
|
||
static const struct ccdigest_info *get_digest(int n)
|
||
{
|
||
switch (n) {
|
||
case 1:
|
||
return ccsha1_di();
|
||
case 224:
|
||
return ccsha224_di();
|
||
case 256:
|
||
return ccsha256_di();
|
||
case 384:
|
||
return ccsha384_di();
|
||
case 512:
|
||
return ccsha512_di();
|
||
case 512256:
|
||
return ccsha512_256_di();
|
||
default:
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
struct ccec_test_import_export_func {
|
||
int (*func)(ccec_full_ctx_t fk, ccec_full_ctx_t imported_pub_x963, ccec_full_ctx_t imported_priv_x963);
|
||
char *name;
|
||
bool compact;
|
||
};
|
||
|
||
static int blind_unblind(ccec_const_cp_t cp, ccec_pub_ctx_t pub)
|
||
{
|
||
// Initialized by ccec_generate_blinding_keys
|
||
ccec_full_ctx_decl_cp(cp, blinding_key);
|
||
ccec_full_ctx_decl_cp(cp, unblinding_key);
|
||
|
||
ccec_pub_ctx_decl_cp(cp, pub_blinded);
|
||
ccec_ctx_init(cp, pub_blinded);
|
||
ccec_pub_ctx_decl_cp(cp, pub_unblinded);
|
||
ccec_ctx_init(cp, pub_unblinded);
|
||
|
||
size_t pub_export_sz = ccec_export_pub_size(pub);
|
||
uint8_t pub_input[pub_export_sz];
|
||
uint8_t pub_calced[pub_export_sz];
|
||
|
||
is_or_goto(ccec_generate_blinding_keys(cp, global_test_rng, blinding_key, unblinding_key), CCERR_OK, "Generate twin keys error", err);
|
||
is_or_goto(ccec_blind(global_test_rng, blinding_key, pub, pub_blinded), CCERR_OK, "Twin keys blind error", err);
|
||
is_or_goto(ccec_unblind(global_test_rng, unblinding_key, pub_blinded, pub_unblinded), CCERR_OK, "Twin keys unblind error", err);
|
||
|
||
ccec_export_pub(pub, pub_input);
|
||
ccec_export_pub(pub_unblinded, pub_calced);
|
||
|
||
ok_memcmp_or_goto(pub_input, pub_calced, pub_export_sz, err, "Unblinded pubkey isn't equal to input key !");
|
||
|
||
return 1;
|
||
err:
|
||
return 0;
|
||
}
|
||
|
||
static int individual_key_tests(ccec_const_cp_t cp, ccec_full_ctx_t fk, bool compact_enabled)
|
||
{
|
||
static struct ccec_test_import_export_func ccec_test_import_export_funcs[] = {
|
||
{ .func = ie_copy, .name = "Copy", .compact = false },
|
||
{ .func = ie_x963, .name = "x963", .compact = false },
|
||
{ .func = ie_raw, .name = "raw", .compact = false },
|
||
{ .func = ie_components, .name = "components", .compact = false },
|
||
{ .func = ie_compact, .name = "compact", .compact = true },
|
||
};
|
||
const size_t ccec_test_import_export_funcs_len =
|
||
sizeof(ccec_test_import_export_funcs) / sizeof(ccec_test_import_export_funcs[0]);
|
||
const int ccec_test_valid_digests[] = { 1, 224, 224, 256, 384, 512, 512256 };
|
||
const size_t ccec_test_valid_digests_len = sizeof(ccec_test_valid_digests) / sizeof(ccec_test_valid_digests[0]);
|
||
uint8_t msg[74] = "We are good testers and will check all of the curve / digest combinations!";
|
||
|
||
size_t cz = ccec_cp_prime_bitlen(cp);
|
||
ccec_full_ctx_decl_cp(cp, ie_pub);
|
||
ccec_full_ctx_decl_cp(cp, ie_priv);
|
||
|
||
for (size_t j = 0; j < ccec_test_import_export_funcs_len; j++) {
|
||
ccec_full_ctx_clear_cp(cp, ie_pub);
|
||
ccec_full_ctx_clear_cp(cp, ie_priv);
|
||
|
||
struct ccec_test_import_export_func ief = ccec_test_import_export_funcs[j];
|
||
int status = ief.func(fk, ie_pub, ie_priv);
|
||
|
||
ok(status, "Import / Export failure - %s", ief.name);
|
||
if (!status) {
|
||
continue;
|
||
}
|
||
|
||
ok(key_exchange(cp, ie_priv, fk), "Key exchange error[cp%zu, %s]", cz, ief.name);
|
||
ok(blind_unblind(cp, ccec_ctx_pub(fk)), "Blind Unblind error[cp%zu, %s]", cz, ief.name);
|
||
if (!compact_enabled && ief.compact) {
|
||
continue;
|
||
}
|
||
for (size_t i = 0; i < ccec_test_valid_digests_len; i++) {
|
||
const struct ccdigest_info *di = get_digest(ccec_test_valid_digests[i]);
|
||
ok(sign_verify(cp, ie_priv, ie_pub, di, sizeof(msg), msg),
|
||
"Sign / Verify error [cp%zu, %s, sha%d]",
|
||
cz,
|
||
ief.name,
|
||
ccec_test_valid_digests[i]);
|
||
}
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
struct ccec_test_key_generation_func {
|
||
int (*func)(ccec_const_cp_t cp, struct ccrng_state *rng, ccec_full_ctx_t key);
|
||
char *name;
|
||
bool compact_enabled;
|
||
};
|
||
|
||
static int ccec_cp_tests(ccec_const_cp_t cp)
|
||
{
|
||
static struct ccec_test_key_generation_func ccec_test_key_generation_funcs[] = {
|
||
{ .func = ccec_generate_key_fips, .name = "FIPS", .compact_enabled = false },
|
||
{ .func = ccecdh_generate_key, .name = "Normal", .compact_enabled = false },
|
||
{ .func = ccec_compact_generate_key, .name = "Compact", .compact_enabled = true },
|
||
};
|
||
const size_t ccec_test_key_generation_funcs_len =
|
||
sizeof(ccec_test_key_generation_funcs) / sizeof(ccec_test_key_generation_funcs[0]);
|
||
|
||
struct ccrng_state *rng = global_test_rng;
|
||
ccec_full_ctx_decl_cp(cp, key);
|
||
ccec_ctx_init(cp, key);
|
||
|
||
for (size_t i = 0; i < ccec_test_key_generation_funcs_len; i++) {
|
||
struct ccec_test_key_generation_func kgf = ccec_test_key_generation_funcs[i];
|
||
|
||
int status = kgf.func(cp, rng, key);
|
||
is(status, 0, "Generate key failure: %s", kgf.name);
|
||
if (status) {
|
||
continue;
|
||
}
|
||
ok(ccecdh_pairwise_consistency_check(key, NULL, rng), "Key doesn't pass consistency checks");
|
||
ok(individual_key_tests(cp, key, kgf.compact_enabled), "Individual key tests failed");
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
static int ccec_random_tests(void)
|
||
{
|
||
int status = 0; // Failure
|
||
static const size_t ccec_test_valid_key_sizes[] = { 192, 224, 256, 384, 521 };
|
||
static const size_t ccec_test_valid_key_sizes_len = sizeof(ccec_test_valid_key_sizes) / sizeof(ccec_test_valid_key_sizes[0]);
|
||
const size_t invalid_key_sizes[] = { 100, 200, 300, 400, 500, 600 };
|
||
const size_t invalid_key_sizes_len = sizeof(invalid_key_sizes) / sizeof(invalid_key_sizes[0]);
|
||
|
||
for (size_t i = 0; i < ccec_test_valid_key_sizes_len; i++) {
|
||
size_t key_size = ccec_test_valid_key_sizes[i];
|
||
ok_or_goto(ccec_keysize_is_supported(key_size), "Key size valid yet deemed invalid", err);
|
||
ccec_const_cp_t cp = ccec_get_cp(key_size);
|
||
ok_or_goto(cp != NULL, "ccec_get_cp failed for valid key size", err);
|
||
|
||
ok(ccec_generate_rng_edgecases(cp), "ccec_generate_rng_edgecases failure");
|
||
is(ccec_cczp_mod_prime_tests(key_size, cp), 0, "ccec_cczp_mod_prime_tests failure");
|
||
ok(ccec_cp_tests(cp), "ccec_cp_tests failure");
|
||
}
|
||
|
||
for (size_t i = 0; i < invalid_key_sizes_len; i++) {
|
||
size_t key_size = invalid_key_sizes[i];
|
||
ok(!ccec_keysize_is_supported(key_size), "Invalid key size deemed valid");
|
||
|
||
ccec_const_cp_t params = ccec_get_cp(key_size);
|
||
ok(params == NULL, "ccec_get_cp succeeded for invalid key size");
|
||
}
|
||
|
||
status = 1;
|
||
err:
|
||
return status;
|
||
}
|
||
|
||
int ccec_tests(TM_UNUSED int argc, TM_UNUSED char *const *argv)
|
||
{
|
||
int ntests = 22718;
|
||
ntests += 30001 * 5; // ccec_cczp_mod_prime_tests
|
||
ntests += 67; // eckeygen_tests
|
||
ntests += 180; // ecdsa_known_answer_tests
|
||
ntests += 294; // ecdsa_negative_tests
|
||
ntests += 55; // ecdh_known_answer_tests
|
||
ntests += 56; // ecdh_negative_tests
|
||
ntests += 102; // ECStaticGenTest
|
||
ntests += 1277; // ecwrapping_tests
|
||
ntests += 18; // ccec_diversify_pub_twin_tests
|
||
ntests += 19; // keyroll_tests
|
||
ntests += 7; // ccec_test_xcoord_zero
|
||
ntests += 375; // blind_unblind
|
||
plan_tests(ntests);
|
||
|
||
ok(ccec_random_tests(), "ccec_random_tests failure");
|
||
|
||
if (verbose)
|
||
diag("KeyGen KATs");
|
||
ok(eckeygen_tests(), "KeyGen KATs");
|
||
|
||
if (verbose)
|
||
diag("ECDSA KATs");
|
||
ok(ecdsa_known_answer_tests(), "ECDSA KATs");
|
||
|
||
if (verbose)
|
||
diag("ECDSA Negative tests");
|
||
ok(ecdsa_negative_tests(), "ECDSA Negative tests");
|
||
|
||
if (verbose)
|
||
diag("ECDH KATs");
|
||
ok(ecdh_known_answer_tests(), "ECDH KATs");
|
||
|
||
if (verbose)
|
||
diag("ECDH Negative tests");
|
||
ok(ecdh_negative_tests(), "ECDH Negative tests");
|
||
|
||
if (verbose)
|
||
diag("Static Gen Tests");
|
||
ok(ECStaticGenTest(), "Generate Static EC Key Pairs");
|
||
|
||
if (verbose)
|
||
diag("EC Wrapping Tests");
|
||
ok(ecwrapping_tests(), "EC Wrapping tests");
|
||
|
||
if (verbose)
|
||
diag("Public key diversification tests");
|
||
is(ccec_diversify_pub_twin_tests(), 0, "Public key diversification");
|
||
|
||
if (verbose)
|
||
diag("Keyroll tests");
|
||
ok(keyroll_tests(), "Keyroll tests");
|
||
|
||
is(ccec_test_xcoord_zero(), 0, "x = 0 tests");
|
||
|
||
return 0;
|
||
}
|
||
|
||
#endif
|