400 lines
11 KiB
Diff
400 lines
11 KiB
Diff
|
diff --git a/crypto/fips/fips_ecdsa_selftest.c b/crypto/fips/fips_ecdsa_selftest.c
|
||
|
index 9895aa8..77a1c77 100644
|
||
|
--- a/crypto/fips/fips_ecdsa_selftest.c
|
||
|
+++ b/crypto/fips/fips_ecdsa_selftest.c
|
||
|
@@ -65,102 +65,319 @@
|
||
|
#include <openssl/bn.h>
|
||
|
|
||
|
#ifdef OPENSSL_FIPS
|
||
|
+#include <openssl/rand.h>
|
||
|
+#include "internal/nelem.h"
|
||
|
+#include "fips_locl.h"
|
||
|
|
||
|
-static const char P_256_name[] = "ECDSA P-256";
|
||
|
+/* functions to change the RAND_METHOD */
|
||
|
+static int fbytes(unsigned char *buf, int num);
|
||
|
|
||
|
-static const unsigned char P_256_d[] = {
|
||
|
- 0x51, 0xbd, 0x06, 0xa1, 0x1c, 0xda, 0xe2, 0x12, 0x99, 0xc9, 0x52, 0x3f,
|
||
|
- 0xea, 0xa4, 0xd2, 0xd1, 0xf4, 0x7f, 0xd4, 0x3e, 0xbd, 0xf8, 0xfc, 0x87,
|
||
|
- 0xdc, 0x82, 0x53, 0x21, 0xee, 0xa0, 0xdc, 0x64
|
||
|
-};
|
||
|
+static RAND_METHOD fake_rand;
|
||
|
+static const RAND_METHOD *old_rand;
|
||
|
+static int use_fake = 0;
|
||
|
+static const unsigned char *numbers[2];
|
||
|
+static int numbers_len[2];
|
||
|
|
||
|
-static const unsigned char P_256_qx[] = {
|
||
|
- 0x23, 0x89, 0xe0, 0xf4, 0x69, 0xe0, 0x49, 0xe5, 0xc7, 0xe5, 0x40, 0x6e,
|
||
|
- 0x8f, 0x25, 0xdd, 0xad, 0x11, 0x16, 0x14, 0x9b, 0xab, 0x44, 0x06, 0x31,
|
||
|
- 0xbf, 0x5e, 0xa6, 0x44, 0xac, 0x86, 0x00, 0x07
|
||
|
-};
|
||
|
+static int change_rand(void)
|
||
|
+{
|
||
|
+ /* save old rand method */
|
||
|
+ old_rand = RAND_get_rand_method();
|
||
|
+ if (!old_rand)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ fake_rand = *old_rand;
|
||
|
+ /* use own random function */
|
||
|
+ fake_rand.bytes = fbytes;
|
||
|
+ /* set new RAND_METHOD */
|
||
|
+ if (!RAND_set_rand_method(&fake_rand))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ return 1;
|
||
|
+}
|
||
|
|
||
|
-static const unsigned char P_256_qy[] = {
|
||
|
- 0xb3, 0x05, 0x0d, 0xd0, 0xdc, 0xf7, 0x40, 0xe6, 0xf9, 0xd8, 0x6d, 0x7b,
|
||
|
- 0x63, 0xca, 0x97, 0xe6, 0x12, 0xf9, 0xd4, 0x18, 0x59, 0xbe, 0xb2, 0x5e,
|
||
|
- 0x4a, 0x6a, 0x77, 0x23, 0xf4, 0x11, 0x9d, 0xeb
|
||
|
-};
|
||
|
+static int restore_rand(void)
|
||
|
+{
|
||
|
+ if (!RAND_set_rand_method(old_rand))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
+static int fbytes(unsigned char *buf, int num)
|
||
|
+{
|
||
|
+ int ret = 0;
|
||
|
+ static int fbytes_counter = 0;
|
||
|
+
|
||
|
+ if (use_fake == 0)
|
||
|
+ return old_rand->bytes(buf, num);
|
||
|
+
|
||
|
+ use_fake = 0;
|
||
|
+
|
||
|
+ if (fbytes_counter >= OSSL_NELEM(numbers))
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ if (numbers_len[fbytes_counter] > num)
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* first zero out the buffer */
|
||
|
+ memset(buf, 0, num);
|
||
|
+
|
||
|
+ /* Now set the "random" values */
|
||
|
+ memcpy(buf + (num - numbers_len[fbytes_counter]), numbers[fbytes_counter], numbers_len[fbytes_counter]);
|
||
|
+
|
||
|
+ fbytes_counter = (fbytes_counter + 1) % OSSL_NELEM(numbers);
|
||
|
+ ret = 1;
|
||
|
+err:
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+
|
||
|
+/*-
|
||
|
+ * NIST CAVP ECDSA KATs
|
||
|
+ * 2 X9.62 KATs; one for prime fields and one for binary fields.
|
||
|
+ *
|
||
|
+ * Taken from:
|
||
|
+ * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/dss/186-3ecdsatestvectors.zip
|
||
|
+ */
|
||
|
|
||
|
typedef struct {
|
||
|
- int curve;
|
||
|
- const char *name;
|
||
|
- const unsigned char *x;
|
||
|
- size_t xlen;
|
||
|
- const unsigned char *y;
|
||
|
- size_t ylen;
|
||
|
- const unsigned char *d;
|
||
|
- size_t dlen;
|
||
|
-} EC_SELFTEST_DATA;
|
||
|
-
|
||
|
-# define make_ecdsa_test(nid, pr) { nid, pr##_name, \
|
||
|
- pr##_qx, sizeof(pr##_qx), \
|
||
|
- pr##_qy, sizeof(pr##_qy), \
|
||
|
- pr##_d, sizeof(pr##_d)}
|
||
|
-
|
||
|
-static EC_SELFTEST_DATA test_ec_data[] = {
|
||
|
- make_ecdsa_test(NID_X9_62_prime256v1, P_256),
|
||
|
-};
|
||
|
+ const int nid; /* curve NID */
|
||
|
+ const int md_nid; /* hash function NID */
|
||
|
+ const unsigned char *msg; /* message to sign */
|
||
|
+ size_t msglen;
|
||
|
+ const unsigned char *d; /* ECDSA private key */
|
||
|
+ size_t dlen;
|
||
|
+ const unsigned char *Q; /* ECDSA public key: (Qx,Qy) */
|
||
|
+ size_t Qlen;
|
||
|
+ const unsigned char *k; /* ECDSA nonce */
|
||
|
+ size_t klen;
|
||
|
+ const unsigned char *r; /* ECDSA signature (r,s) */
|
||
|
+ size_t rlen;
|
||
|
+ const unsigned char *s;
|
||
|
+ size_t slen;
|
||
|
+} ECDSA_KAT_SELFTEST_DATA;
|
||
|
|
||
|
-int FIPS_selftest_ecdsa()
|
||
|
-{
|
||
|
- EC_KEY *ec = NULL;
|
||
|
- BIGNUM *x = NULL, *y = NULL, *d = NULL;
|
||
|
- EVP_PKEY *pk = NULL;
|
||
|
- int rv = 0;
|
||
|
- size_t i;
|
||
|
|
||
|
- for (i = 0; i < sizeof(test_ec_data) / sizeof(EC_SELFTEST_DATA); i++) {
|
||
|
- EC_SELFTEST_DATA *ecd = test_ec_data + i;
|
||
|
+static const unsigned char data1_msg[] = {
|
||
|
+ 0x59, 0x05, 0x23, 0x88, 0x77, 0xc7, 0x74, 0x21,
|
||
|
+ 0xf7, 0x3e, 0x43, 0xee, 0x3d, 0xa6, 0xf2, 0xd9,
|
||
|
+ 0xe2, 0xcc, 0xad, 0x5f, 0xc9, 0x42, 0xdc, 0xec,
|
||
|
+ 0x0c, 0xbd, 0x25, 0x48, 0x29, 0x35, 0xfa, 0xaf,
|
||
|
+ 0x41, 0x69, 0x83, 0xfe, 0x16, 0x5b, 0x1a, 0x04,
|
||
|
+ 0x5e, 0xe2, 0xbc, 0xd2, 0xe6, 0xdc, 0xa3, 0xbd,
|
||
|
+ 0xf4, 0x6c, 0x43, 0x10, 0xa7, 0x46, 0x1f, 0x9a,
|
||
|
+ 0x37, 0x96, 0x0c, 0xa6, 0x72, 0xd3, 0xfe, 0xb5,
|
||
|
+ 0x47, 0x3e, 0x25, 0x36, 0x05, 0xfb, 0x1d, 0xdf,
|
||
|
+ 0xd2, 0x80, 0x65, 0xb5, 0x3c, 0xb5, 0x85, 0x8a,
|
||
|
+ 0x8a, 0xd2, 0x81, 0x75, 0xbf, 0x9b, 0xd3, 0x86,
|
||
|
+ 0xa5, 0xe4, 0x71, 0xea, 0x7a, 0x65, 0xc1, 0x7c,
|
||
|
+ 0xc9, 0x34, 0xa9, 0xd7, 0x91, 0xe9, 0x14, 0x91,
|
||
|
+ 0xeb, 0x37, 0x54, 0xd0, 0x37, 0x99, 0x79, 0x0f,
|
||
|
+ 0xe2, 0xd3, 0x08, 0xd1, 0x61, 0x46, 0xd5, 0xc9,
|
||
|
+ 0xb0, 0xd0, 0xde, 0xbd, 0x97, 0xd7, 0x9c, 0xe8
|
||
|
+};
|
||
|
|
||
|
- x = BN_bin2bn(ecd->x, ecd->xlen, x);
|
||
|
- y = BN_bin2bn(ecd->y, ecd->ylen, y);
|
||
|
- d = BN_bin2bn(ecd->d, ecd->dlen, d);
|
||
|
+static const unsigned char data1_d[] = {
|
||
|
+ 0x51, 0x9b, 0x42, 0x3d, 0x71, 0x5f, 0x8b, 0x58,
|
||
|
+ 0x1f, 0x4f, 0xa8, 0xee, 0x59, 0xf4, 0x77, 0x1a,
|
||
|
+ 0x5b, 0x44, 0xc8, 0x13, 0x0b, 0x4e, 0x3e, 0xac,
|
||
|
+ 0xca, 0x54, 0xa5, 0x6d, 0xda, 0x72, 0xb4, 0x64
|
||
|
+};
|
||
|
|
||
|
- if (!x || !y || !d)
|
||
|
- goto err;
|
||
|
+static const unsigned char data1_Q[] = {
|
||
|
+ 0x04, 0x0c, 0xec, 0x02, 0x8e, 0xe0, 0x8d, 0x09,
|
||
|
+ 0xe0, 0x26, 0x72, 0xa6, 0x83, 0x10, 0x81, 0x43,
|
||
|
+ 0x54, 0xf9, 0xea, 0xbf, 0xff, 0x0d, 0xe6, 0xda,
|
||
|
+ 0xcc, 0x1c, 0xd3, 0xa7, 0x74, 0x49, 0x60, 0x76,
|
||
|
+ 0xae, 0xef, 0xf4, 0x71, 0xfb, 0xa0, 0x40, 0x98,
|
||
|
+ 0x97, 0xb6, 0xa4, 0x8e, 0x88, 0x01, 0xad, 0x12,
|
||
|
+ 0xf9, 0x5d, 0x00, 0x09, 0xb7, 0x53, 0xcf, 0x8f,
|
||
|
+ 0x51, 0xc1, 0x28, 0xbf, 0x6b, 0x0b, 0xd2, 0x7f,
|
||
|
+ 0xbd
|
||
|
+};
|
||
|
|
||
|
- ec = EC_KEY_new_by_curve_name(ecd->curve);
|
||
|
- if (!ec)
|
||
|
- goto err;
|
||
|
+static const unsigned char data1_k[] = {
|
||
|
+ 0x94, 0xa1, 0xbb, 0xb1, 0x4b, 0x90, 0x6a, 0x61,
|
||
|
+ 0xa2, 0x80, 0xf2, 0x45, 0xf9, 0xe9, 0x3c, 0x7f,
|
||
|
+ 0x3b, 0x4a, 0x62, 0x47, 0x82, 0x4f, 0x5d, 0x33,
|
||
|
+ 0xb9, 0x67, 0x07, 0x87, 0x64, 0x2a, 0x68, 0xde
|
||
|
+};
|
||
|
|
||
|
- if (!EC_KEY_set_public_key_affine_coordinates(ec, x, y))
|
||
|
- goto err;
|
||
|
+static const unsigned char data1_r[] = {
|
||
|
+ 0xe3, 0x95, 0xf6, 0xdb, 0x12, 0x71, 0x90, 0xfa,
|
||
|
+ 0x70, 0xa6, 0x80, 0xeb, 0xf6, 0x8a, 0x18, 0x35,
|
||
|
+ 0x6f, 0xef, 0xf2, 0x36, 0x65, 0xb9, 0x31, 0xc3,
|
||
|
+ 0xa2, 0x14, 0x80, 0xdf, 0x86, 0xc4, 0xec, 0xbc
|
||
|
+};
|
||
|
|
||
|
- if (!EC_KEY_set_private_key(ec, d))
|
||
|
- goto err;
|
||
|
+static const unsigned char data1_s[] = {
|
||
|
+ 0xa5, 0x01, 0x04, 0x78, 0x93, 0xd9, 0x60, 0xcc,
|
||
|
+ 0x20, 0xce, 0xbd, 0xbb, 0x6f, 0x79, 0xb9, 0x7e,
|
||
|
+ 0x45, 0x23, 0x80, 0x73, 0x87, 0x83, 0x53, 0x63,
|
||
|
+ 0xe3, 0x80, 0x2b, 0x68, 0xcf, 0x32, 0xa1, 0xa2
|
||
|
+};
|
||
|
|
||
|
- if ((pk = EVP_PKEY_new()) == NULL)
|
||
|
- goto err;
|
||
|
|
||
|
- EVP_PKEY_assign_EC_KEY(pk, ec);
|
||
|
+# define make_ecdsa_kat_test(nid, md_nid, pr) { \
|
||
|
+nid, md_nid, \
|
||
|
+pr##_msg, sizeof(pr##_msg), \
|
||
|
+pr##_d, sizeof(pr##_d), \
|
||
|
+pr##_Q, sizeof(pr##_Q), \
|
||
|
+pr##_k, sizeof(pr##_k), \
|
||
|
+pr##_r, sizeof(pr##_r), \
|
||
|
+pr##_s, sizeof(pr##_s) \
|
||
|
+}
|
||
|
|
||
|
- if (!fips_pkey_signature_test(pk, NULL, 0,
|
||
|
- NULL, 0, EVP_sha256(), 0, ecd->name))
|
||
|
- goto err;
|
||
|
- }
|
||
|
+static ECDSA_KAT_SELFTEST_DATA test_ecdsa_data[] = {
|
||
|
+ make_ecdsa_kat_test(NID_secp256k1, NID_sha256, data1)
|
||
|
+};
|
||
|
|
||
|
- rv = 1;
|
||
|
+int FIPS_selftest_ecdsa()
|
||
|
+{
|
||
|
+ int rv;
|
||
|
+ size_t i, siglen, p_len;
|
||
|
+
|
||
|
+ for (i = 0; i < sizeof(test_ecdsa_data) / sizeof(ECDSA_KAT_SELFTEST_DATA); i++) {
|
||
|
+ EC_KEY *ec = NULL;
|
||
|
+ BIGNUM *r = NULL, *s = NULL;
|
||
|
+ BIGNUM *sig_r = NULL, *sig_s = NULL;
|
||
|
+ EVP_PKEY *pk = NULL;
|
||
|
+ unsigned char *sig = NULL;
|
||
|
+ unsigned char *tsig = NULL;
|
||
|
+ unsigned char *p_buf = NULL;
|
||
|
+ ECDSA_SIG *dsa_sig = NULL;
|
||
|
+ rv = 0;
|
||
|
+
|
||
|
+ ECDSA_KAT_SELFTEST_DATA *ecd = test_ecdsa_data + i;
|
||
|
+
|
||
|
+ /* Create the Message Digest Context */
|
||
|
+ EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
|
||
|
+ if (!mdctx) goto err;
|
||
|
+
|
||
|
+ r = BN_bin2bn(ecd->r, ecd->rlen, r);
|
||
|
+ s = BN_bin2bn(ecd->s, ecd->slen, s);
|
||
|
+
|
||
|
+ if (!r || !s)
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* d[] will be used to generate a key. */
|
||
|
+ /* k[] will be used for signature generation. */
|
||
|
+ numbers[0] = ecd->d;
|
||
|
+ numbers_len[0] = ecd->dlen;
|
||
|
+ numbers[1] = ecd->k;
|
||
|
+ numbers_len[1] = ecd->klen;
|
||
|
+ /* swap the RNG source */
|
||
|
+ if (!change_rand())
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ ec = EC_KEY_new_by_curve_name(ecd->nid);
|
||
|
+ if (!ec)
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Use d[] to generate key. */
|
||
|
+ use_fake = 1;
|
||
|
+ if (EC_KEY_generate_key(ec) != 1)
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ if ((pk = EVP_PKEY_new()) == NULL)
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ EVP_PKEY_assign_EC_KEY(pk, ec);
|
||
|
+
|
||
|
+ p_len = EC_KEY_key2buf(ec, POINT_CONVERSION_UNCOMPRESSED, &p_buf, NULL);
|
||
|
+ if (!p_len)
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Make sure generated public key matches */
|
||
|
+ if (p_len != ecd->Qlen)
|
||
|
+ goto err;
|
||
|
+ if (memcmp(p_buf, ecd->Q, p_len))
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Initialise the DigestSign operation */
|
||
|
+ if(1 != EVP_DigestSignInit(mdctx, NULL, EVP_get_digestbynid(ecd->md_nid), NULL, pk))
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Call update with the message */
|
||
|
+ if(1 != EVP_DigestSignUpdate(mdctx, ecd->msg, ecd->msglen))
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Finalise the DigestSign operation */
|
||
|
+ /* First call EVP_DigestSignFinal with a NULL sig parameter to */
|
||
|
+ /* obtain the length of the signature. Length is returned in slen */
|
||
|
+ if(1 != EVP_DigestSignFinal(mdctx, NULL, &siglen))
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Allocate memory for the signature based on size in slen */
|
||
|
+ if(!(sig = OPENSSL_malloc(siglen)))
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Use k[] for signature. */
|
||
|
+ use_fake = 1;
|
||
|
+
|
||
|
+ /* Obtain the signature */
|
||
|
+ if(1 != EVP_DigestSignFinal(mdctx, sig, &siglen))
|
||
|
+ goto err;
|
||
|
|
||
|
- err:
|
||
|
+ /* extract r and s */
|
||
|
+ tsig = sig;
|
||
|
+ dsa_sig = d2i_ECDSA_SIG(NULL, &tsig, siglen);
|
||
|
+ if (dsa_sig == NULL)
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ sig_r = ECDSA_SIG_get0_r(dsa_sig);
|
||
|
+ sig_s = ECDSA_SIG_get0_s(dsa_sig);
|
||
|
+ if ((sig_r == NULL) || (sig_s == NULL))
|
||
|
+ goto err;
|
||
|
|
||
|
- if (x)
|
||
|
- BN_clear_free(x);
|
||
|
- if (y)
|
||
|
- BN_clear_free(y);
|
||
|
- if (d)
|
||
|
- BN_clear_free(d);
|
||
|
+ /* Compare r and s against known. */
|
||
|
+ if ((BN_cmp(sig_r, r) != 0) || (BN_cmp(sig_s, s) != 0))
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Verify signature */
|
||
|
+ if(1 != EVP_DigestVerifyInit(mdctx, NULL, EVP_get_digestbynid(ecd->md_nid), NULL, pk))
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ if (EVP_DigestVerify(mdctx, sig, siglen, ecd->msg, ecd->msglen) != 1)
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ if (1 != restore_rand())
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ /* Success */
|
||
|
+ rv = 1;
|
||
|
+
|
||
|
+
|
||
|
+ err:
|
||
|
+
|
||
|
+ if (mdctx)
|
||
|
+ EVP_MD_CTX_free(mdctx);
|
||
|
+ if (r)
|
||
|
+ BN_clear_free(r);
|
||
|
+ if (s)
|
||
|
+ BN_clear_free(s);
|
||
|
+ if (sig)
|
||
|
+ OPENSSL_free(sig);
|
||
|
+ if (dsa_sig)
|
||
|
+ ECDSA_SIG_free(dsa_sig);
|
||
|
+ if (p_buf)
|
||
|
+ OPENSSL_free(p_buf);
|
||
|
if (pk)
|
||
|
- EVP_PKEY_free(pk);
|
||
|
+ EVP_PKEY_free(pk);
|
||
|
else if (ec)
|
||
|
- EC_KEY_free(ec);
|
||
|
-
|
||
|
- return rv;
|
||
|
+ EC_KEY_free(ec);
|
||
|
+
|
||
|
+ if (rv != 1) {
|
||
|
+ FIPSerr(FIPS_F_FIPS_SELFTEST_ECDSA, FIPS_R_SELFTEST_FAILED);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ }
|
||
|
|
||
|
+ return rv;
|
||
|
+
|
||
|
}
|
||
|
|
||
|
+
|
||
|
#endif
|
||
|
|