openssl-1_1/bsc1185319-FIPS-KAT-for-ECDSA.patch

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