Added POWER8 implementation for AES/CTR+CBC-MAC (for CCM and EAX modes).
[BearSSL] / test / test_crypto.c
index acfabd0..dd2562c 100644 (file)
@@ -1074,6 +1074,41 @@ test_HMAC_DRBG(void)
        fflush(stdout);
 }
 
+static void
+test_AESCTR_DRBG(void)
+{
+       br_aesctr_drbg_context ctx;
+       const br_block_ctr_class *ictr;
+       unsigned char tmp1[64], tmp2[64];
+
+       printf("Test AESCTR_DRBG: ");
+       fflush(stdout);
+
+       ictr = br_aes_x86ni_ctr_get_vtable();
+       if (ictr == NULL) {
+               ictr = br_aes_pwr8_ctr_get_vtable();
+               if (ictr == NULL) {
+#if BR_64
+                       ictr = &br_aes_ct64_ctr_vtable;
+#else
+                       ictr = &br_aes_ct_ctr_vtable;
+#endif
+               }
+       }
+       br_aesctr_drbg_init(&ctx, ictr, NULL, 0);
+       ctx.vtable->generate(&ctx.vtable, tmp1, sizeof tmp1);
+       ctx.vtable->update(&ctx.vtable, "new seed", 8);
+       ctx.vtable->generate(&ctx.vtable, tmp2, sizeof tmp2);
+
+       if (memcmp(tmp1, tmp2, sizeof tmp1) == 0) {
+               fprintf(stderr, "AESCTR_DRBG failure\n");
+               exit(EXIT_FAILURE);
+       }
+
+       printf("done.\n");
+       fflush(stdout);
+}
+
 static void
 do_KAT_PRF(br_tls_prf_impl prf,
        const char *ssecret, const char *label, const char *sseed,
@@ -3629,6 +3664,19 @@ test_AES_CTRCBC_x86ni(void)
        }
 }
 
+static void
+test_AES_CTRCBC_pwr8(void)
+{
+       const br_block_ctrcbc_class *vt;
+
+       vt = br_aes_pwr8_ctrcbc_get_vtable();
+       if (vt != NULL) {
+               test_AES_CTRCBC_inner("pwr8", vt);
+       } else {
+               printf("Test AES CTR/CBC-MAC pwr8: UNAVAILABLE\n");
+       }
+}
+
 /*
  * DES known-answer tests. Order: plaintext, key, ciphertext.
  * (mostly from NIST SP 800-20).
@@ -5686,8 +5734,9 @@ test_RSA_OAEP(const char *name,
 }
 
 static void
-test_RSA_keygen(const char *name, br_rsa_keygen kg,
-       br_rsa_pkcs1_sign sign, br_rsa_pkcs1_vrfy vrfy)
+test_RSA_keygen(const char *name, br_rsa_keygen kg, br_rsa_compute_modulus cm,
+       br_rsa_compute_pubexp ce, br_rsa_compute_privexp cd,
+       br_rsa_public pub, br_rsa_pkcs1_sign sign, br_rsa_pkcs1_vrfy vrfy)
 {
        br_hmac_drbg_context rng;
        int i;
@@ -5697,25 +5746,30 @@ test_RSA_keygen(const char *name, br_rsa_keygen kg,
 
        br_hmac_drbg_init(&rng, &br_sha256_vtable, "seed for RSA keygen", 19);
 
-       for (i = 0; i < 40; i ++) {
+       for (i = 0; i <= 42; i ++) {
                unsigned size;
-               uint32_t pubexp;
+               uint32_t pubexp, z;
                br_rsa_private_key sk;
-               br_rsa_public_key pk;
+               br_rsa_public_key pk, pk2;
                unsigned char kbuf_priv[BR_RSA_KBUF_PRIV_SIZE(2048)];
                unsigned char kbuf_pub[BR_RSA_KBUF_PUB_SIZE(2048)];
+               unsigned char n2[256], d[256], msg1[256], msg2[256];
                uint32_t mod[256];
                uint32_t cc;
                size_t u, v;
                unsigned char sig[257], hv[32], hv2[sizeof hv];
                unsigned mask1, mask2;
+               int j;
 
                if (i <= 35) {
                        size = 1024 + i;
                        pubexp = 17;
-               } else {
+               } else if (i <= 40) {
                        size = 2048;
                        pubexp = (i << 1) - 69;
+               } else {
+                       size = 2048;
+                       pubexp = 0xFFFFFFFF;
                }
 
                if (!kg(&rng.vtable,
@@ -5725,14 +5779,15 @@ test_RSA_keygen(const char *name, br_rsa_keygen kg,
                        exit(EXIT_FAILURE);
                }
 
+               z = pubexp;
                for (u = pk.elen; u > 0; u --) {
-                       if (pk.e[u - 1] != (pubexp & 0xFF)) {
+                       if (pk.e[u - 1] != (z & 0xFF)) {
                                fprintf(stderr, "wrong public exponent\n");
                                exit(EXIT_FAILURE);
                        }
-                       pubexp >>= 8;
+                       z >>= 8;
                }
-               if (pubexp != 0) {
+               if (z != 0) {
                        fprintf(stderr, "truncated public exponent\n");
                        exit(EXIT_FAILURE);
                }
@@ -5771,28 +5826,86 @@ test_RSA_keygen(const char *name, br_rsa_keygen kg,
                        exit(EXIT_FAILURE);
                }
 
-               rng.vtable->generate(&rng.vtable, hv, sizeof hv);
-               memset(sig, 0, sizeof sig);
-               sig[pk.nlen] = 0x00;
-               if (!sign(BR_HASH_OID_SHA256, hv, sizeof hv, &sk, sig)) {
-                       fprintf(stderr, "signature error\n");
+               if (cm(NULL, &sk) != pk.nlen) {
+                       fprintf(stderr, "wrong recomputed modulus length\n");
                        exit(EXIT_FAILURE);
                }
-               if (sig[pk.nlen] != 0x00) {
-                       fprintf(stderr, "signature length error\n");
+               if (cm(n2, &sk) != pk.nlen || memcmp(pk.n, n2, pk.nlen) != 0) {
+                       fprintf(stderr, "wrong recomputed modulus value\n");
                        exit(EXIT_FAILURE);
                }
-               if (!vrfy(sig, pk.nlen, BR_HASH_OID_SHA256, sizeof hv,
-                       &pk, hv2))
-               {
-                       fprintf(stderr, "signature verification error (1)\n");
+
+               z = ce(&sk);
+               if (z != pubexp) {
+                       fprintf(stderr,
+                               "wrong recomputed pubexp: %lu (exp: %lu)\n",
+                               (unsigned long)z, (unsigned long)pubexp);
+                       exit(EXIT_FAILURE);
+               }
+
+               if (cd(NULL, &sk, pubexp) != pk.nlen) {
+                       fprintf(stderr,
+                               "wrong recomputed privexp length (1)\n");
+                       exit(EXIT_FAILURE);
+               }
+               if (cd(d, &sk, pubexp) != pk.nlen) {
+                       fprintf(stderr,
+                               "wrong recomputed privexp length (2)\n");
+                       exit(EXIT_FAILURE);
+               }
+               /*
+                * To check that the private exponent is correct, we make
+                * it into a _public_ key, and use the public-key operation
+                * to perform the modular exponentiation.
+                */
+               pk2 = pk;
+               pk2.e = d;
+               pk2.elen = pk.nlen;
+               rng.vtable->generate(&rng.vtable, msg1, pk.nlen);
+               msg1[0] = 0x00;
+               memcpy(msg2, msg1, pk.nlen);
+               if (!pub(msg2, pk.nlen, &pk2) || !pub(msg2, pk.nlen, &pk)) {
+                       fprintf(stderr, "public-key operation error\n");
                        exit(EXIT_FAILURE);
                }
-               if (memcmp(hv, hv2, sizeof hv) != 0) {
-                       fprintf(stderr, "signature verification error (2)\n");
+               if (memcmp(msg1, msg2, pk.nlen) != 0) {
+                       fprintf(stderr, "wrong recomputed privexp\n");
                        exit(EXIT_FAILURE);
                }
 
+               /*
+                * We test the RSA operation over a some random messages.
+                */
+               for (j = 0; j < 20; j ++) {
+                       rng.vtable->generate(&rng.vtable, hv, sizeof hv);
+                       memset(sig, 0, sizeof sig);
+                       sig[pk.nlen] = 0x00;
+                       if (!sign(BR_HASH_OID_SHA256,
+                               hv, sizeof hv, &sk, sig))
+                       {
+                               fprintf(stderr,
+                                       "signature error (%d)\n", j);
+                               exit(EXIT_FAILURE);
+                       }
+                       if (sig[pk.nlen] != 0x00) {
+                               fprintf(stderr,
+                                       "signature length error (%d)\n", j);
+                               exit(EXIT_FAILURE);
+                       }
+                       if (!vrfy(sig, pk.nlen, BR_HASH_OID_SHA256, sizeof hv,
+                               &pk, hv2))
+                       {
+                               fprintf(stderr,
+                                       "signature verif error (%d)\n", j);
+                               exit(EXIT_FAILURE);
+                       }
+                       if (memcmp(hv, hv2, sizeof hv) != 0) {
+                               fprintf(stderr,
+                                       "signature extract error (%d)\n", j);
+                               exit(EXIT_FAILURE);
+                       }
+               }
+
                printf(".");
                fflush(stdout);
        }
@@ -5810,6 +5923,8 @@ test_RSA_i15(void)
        test_RSA_OAEP("RSA i15 OAEP",
                &br_rsa_i15_oaep_encrypt, &br_rsa_i15_oaep_decrypt);
        test_RSA_keygen("RSA i15 keygen", &br_rsa_i15_keygen,
+               &br_rsa_i15_compute_modulus, &br_rsa_i15_compute_pubexp,
+               &br_rsa_i15_compute_privexp, &br_rsa_i15_public,
                &br_rsa_i15_pkcs1_sign, &br_rsa_i15_pkcs1_vrfy);
 }
 
@@ -5822,6 +5937,8 @@ test_RSA_i31(void)
        test_RSA_OAEP("RSA i31 OAEP",
                &br_rsa_i31_oaep_encrypt, &br_rsa_i31_oaep_decrypt);
        test_RSA_keygen("RSA i31 keygen", &br_rsa_i31_keygen,
+               &br_rsa_i31_compute_modulus, &br_rsa_i31_compute_pubexp,
+               &br_rsa_i31_compute_privexp, &br_rsa_i31_public,
                &br_rsa_i31_pkcs1_sign, &br_rsa_i31_pkcs1_vrfy);
 }
 
@@ -5861,7 +5978,10 @@ test_RSA_i62(void)
                test_RSA_core("RSA i62 core", pub, priv);
                test_RSA_sign("RSA i62 sign", priv, sign, vrfy);
                test_RSA_OAEP("RSA i62 OAEP", menc, mdec);
-               test_RSA_keygen("RSA i62 keygen", kgen, sign, vrfy);
+               test_RSA_keygen("RSA i62 keygen", kgen,
+                       &br_rsa_i31_compute_modulus, &br_rsa_i31_compute_pubexp,
+                       &br_rsa_i31_compute_privexp, pub,
+                       sign, vrfy);
        } else {
                if (priv || sign || vrfy || menc || mdec || kgen) {
                        fprintf(stderr, "Inconsistent i62 availability\n");
@@ -6732,6 +6852,13 @@ test_EAX(void)
        } else {
                printf("Test EAX aes_x86ni: UNAVAILABLE\n");
        }
+
+       x_ctrcbc = br_aes_pwr8_ctrcbc_get_vtable();
+       if (x_ctrcbc != NULL) {
+               test_EAX_inner("aes_pwr8", x_ctrcbc);
+       } else {
+               printf("Test EAX aes_pwr8: UNAVAILABLE\n");
+       }
 }
 
 /*
@@ -6944,6 +7071,13 @@ test_CCM(void)
        } else {
                printf("Test CCM aes_x86ni: UNAVAILABLE\n");
        }
+
+       x_ctrcbc = br_aes_pwr8_ctrcbc_get_vtable();
+       if (x_ctrcbc != NULL) {
+               test_CCM_inner("aes_pwr8", x_ctrcbc);
+       } else {
+               printf("Test CCM aes_pwr8: UNAVAILABLE\n");
+       }
 }
 
 static void
@@ -7174,7 +7308,6 @@ test_EC_P256_carry(const br_ec_impl *impl)
 static void
 test_EC_KAT(const char *name, const br_ec_impl *impl, uint32_t curve_mask)
 {
-
        printf("Test %s: ", name);
        fflush(stdout);
 
@@ -7202,6 +7335,155 @@ test_EC_KAT(const char *name, const br_ec_impl *impl, uint32_t curve_mask)
        fflush(stdout);
 }
 
+static void
+test_EC_keygen(const char *name, const br_ec_impl *impl, uint32_t curves)
+{
+       int curve;
+       br_hmac_drbg_context rng;
+
+       printf("Test %s keygen: ", name);
+       fflush(stdout);
+
+       br_hmac_drbg_init(&rng, &br_sha256_vtable, "seed for EC keygen", 18);
+       br_hmac_drbg_update(&rng, name, strlen(name));
+
+       for (curve = -1; curve <= 35; curve ++) {
+               br_ec_private_key sk;
+               br_ec_public_key pk;
+               unsigned char kbuf_priv[BR_EC_KBUF_PRIV_MAX_SIZE];
+               unsigned char kbuf_pub[BR_EC_KBUF_PUB_MAX_SIZE];
+
+               if (curve < 0 || curve >= 32 || ((curves >> curve) & 1) == 0) {
+                       if (br_ec_keygen(&rng.vtable, impl,
+                               &sk, kbuf_priv, curve) != 0)
+                       {
+                               fprintf(stderr, "br_ec_keygen() did not"
+                                       " reject unsupported curve %d\n",
+                                       curve);
+                               exit(EXIT_FAILURE);
+                       }
+                       sk.curve = curve;
+                       if (br_ec_compute_pub(impl, NULL, NULL, &sk) != 0) {
+                               fprintf(stderr, "br_ec_keygen() did not"
+                                       " reject unsupported curve %d\n",
+                                       curve);
+                               exit(EXIT_FAILURE);
+                       }
+               } else {
+                       size_t len, u;
+                       unsigned char tmp_priv[sizeof kbuf_priv];
+                       unsigned char tmp_pub[sizeof kbuf_pub];
+                       unsigned z;
+
+                       len = br_ec_keygen(&rng.vtable, impl,
+                               NULL, NULL, curve);
+                       if (len == 0) {
+                               fprintf(stderr, "br_ec_keygen() rejects"
+                                       " supported curve %d\n", curve);
+                               exit(EXIT_FAILURE);
+                       }
+                       if (len > sizeof kbuf_priv) {
+                               fprintf(stderr, "oversized kbuf_priv\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       memset(kbuf_priv, 0, sizeof kbuf_priv);
+                       if (br_ec_keygen(&rng.vtable, impl,
+                               NULL, kbuf_priv, curve) != len)
+                       {
+                               fprintf(stderr, "kbuf_priv length mismatch\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       z = 0;
+                       for (u = 0; u < len; u ++) {
+                               z |= kbuf_priv[u];
+                       }
+                       if (z == 0) {
+                               fprintf(stderr, "kbuf_priv not initialized\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       for (u = len; u < sizeof kbuf_priv; u ++) {
+                               if (kbuf_priv[u] != 0) {
+                                       fprintf(stderr, "kbuf_priv overflow\n");
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+                       if (br_ec_keygen(&rng.vtable, impl,
+                               NULL, tmp_priv, curve) != len)
+                       {
+                               fprintf(stderr, "tmp_priv length mismatch\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       if (memcmp(kbuf_priv, tmp_priv, len) == 0) {
+                               fprintf(stderr, "keygen stutter\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       memset(&sk, 0, sizeof sk);
+                       if (br_ec_keygen(&rng.vtable, impl,
+                               &sk, kbuf_priv, curve) != len)
+                       {
+                               fprintf(stderr,
+                                       "kbuf_priv length mismatch (2)\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       if (sk.curve != curve || sk.x != kbuf_priv
+                               || sk.xlen != len)
+                       {
+                               fprintf(stderr, "sk not initialized\n");
+                               exit(EXIT_FAILURE);
+                       }
+
+                       len = br_ec_compute_pub(impl, NULL, NULL, &sk);
+                       if (len > sizeof kbuf_pub) {
+                               fprintf(stderr, "oversized kbuf_pub\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       memset(kbuf_pub, 0, sizeof kbuf_pub);
+                       if (br_ec_compute_pub(impl, NULL,
+                               kbuf_pub, &sk) != len)
+                       {
+                               fprintf(stderr, "kbuf_pub length mismatch\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       for (u = len; u < sizeof kbuf_pub; u ++) {
+                               if (kbuf_pub[u] != 0) {
+                                       fprintf(stderr, "kbuf_pub overflow\n");
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+                       memset(&pk, 0, sizeof pk);
+                       if (br_ec_compute_pub(impl, &pk,
+                               tmp_pub, &sk) != len)
+                       {
+                               fprintf(stderr, "tmp_pub length mismatch\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       if (memcmp(kbuf_pub, tmp_pub, len) != 0) {
+                               fprintf(stderr, "pubkey mismatch\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       if (pk.curve != curve || pk.q != tmp_pub
+                               || pk.qlen != len)
+                       {
+                               fprintf(stderr, "pk not initialized\n");
+                               exit(EXIT_FAILURE);
+                       }
+
+                       if (impl->mulgen(kbuf_pub,
+                               sk.x, sk.xlen, curve) != len
+                               || memcmp(pk.q, kbuf_pub, len) != 0)
+                       {
+                               fprintf(stderr, "wrong pubkey\n");
+                               exit(EXIT_FAILURE);
+                       }
+               }
+               printf(".");
+               fflush(stdout);
+       }
+
+       printf(" done.\n");
+       fflush(stdout);
+}
+
 static void
 test_EC_prime_i15(void)
 {
@@ -7209,6 +7491,10 @@ test_EC_prime_i15(void)
                (uint32_t)1 << BR_EC_secp256r1
                | (uint32_t)1 << BR_EC_secp384r1
                | (uint32_t)1 << BR_EC_secp521r1);
+       test_EC_keygen("EC_prime_i15", &br_ec_prime_i15,
+               (uint32_t)1 << BR_EC_secp256r1
+               | (uint32_t)1 << BR_EC_secp384r1
+               | (uint32_t)1 << BR_EC_secp521r1);
 }
 
 static void
@@ -7218,6 +7504,10 @@ test_EC_prime_i31(void)
                (uint32_t)1 << BR_EC_secp256r1
                | (uint32_t)1 << BR_EC_secp384r1
                | (uint32_t)1 << BR_EC_secp521r1);
+       test_EC_keygen("EC_prime_i31", &br_ec_prime_i31,
+               (uint32_t)1 << BR_EC_secp256r1
+               | (uint32_t)1 << BR_EC_secp384r1
+               | (uint32_t)1 << BR_EC_secp521r1);
 }
 
 static void
@@ -7225,6 +7515,8 @@ test_EC_p256_m15(void)
 {
        test_EC_KAT("EC_p256_m15", &br_ec_p256_m15,
                (uint32_t)1 << BR_EC_secp256r1);
+       test_EC_keygen("EC_p256_m15", &br_ec_p256_m15,
+               (uint32_t)1 << BR_EC_secp256r1);
 }
 
 static void
@@ -7232,6 +7524,8 @@ test_EC_p256_m31(void)
 {
        test_EC_KAT("EC_p256_m31", &br_ec_p256_m31,
                (uint32_t)1 << BR_EC_secp256r1);
+       test_EC_keygen("EC_p256_m31", &br_ec_p256_m31,
+               (uint32_t)1 << BR_EC_secp256r1);
 }
 
 const struct {
@@ -7318,24 +7612,32 @@ static void
 test_EC_c25519_i15(void)
 {
        test_EC_c25519("EC_c25519_i15", &br_ec_c25519_i15);
+       test_EC_keygen("EC_c25519_i15", &br_ec_c25519_i15,
+               (uint32_t)1 << BR_EC_curve25519);
 }
 
 static void
 test_EC_c25519_i31(void)
 {
        test_EC_c25519("EC_c25519_i31", &br_ec_c25519_i31);
+       test_EC_keygen("EC_c25519_i31", &br_ec_c25519_i31,
+               (uint32_t)1 << BR_EC_curve25519);
 }
 
 static void
 test_EC_c25519_m15(void)
 {
        test_EC_c25519("EC_c25519_m15", &br_ec_c25519_m15);
+       test_EC_keygen("EC_c25519_m15", &br_ec_c25519_m15,
+               (uint32_t)1 << BR_EC_curve25519);
 }
 
 static void
 test_EC_c25519_m31(void)
 {
        test_EC_c25519("EC_c25519_m31", &br_ec_c25519_m31);
+       test_EC_keygen("EC_c25519_m31", &br_ec_c25519_m31,
+               (uint32_t)1 << BR_EC_curve25519);
 }
 
 static const unsigned char EC_P256_PUB_POINT[] = {
@@ -7965,6 +8267,7 @@ static const struct {
        STU(multihash),
        STU(HMAC),
        STU(HMAC_DRBG),
+       STU(AESCTR_DRBG),
        STU(PRF),
        STU(AES_big),
        STU(AES_small),
@@ -7977,6 +8280,7 @@ static const struct {
        STU(AES_CTRCBC_ct),
        STU(AES_CTRCBC_ct64),
        STU(AES_CTRCBC_x86ni),
+       STU(AES_CTRCBC_pwr8),
        STU(DES_tab),
        STU(DES_ct),
        STU(ChaCha20_ct),