MIPS32R3 provides the EXT instruction to extract bits from
[openssl.git] / test / rsa_test.c
index e971295..cd9ca7f 100644 (file)
@@ -1,34 +1,49 @@
+/*
+ * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
 /* test vectors from p1ovect1.txt */
 
 #include <stdio.h>
 #include <string.h>
 
-#include "e_os.h"
+#include "internal/nelem.h"
 
 #include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
 #include <openssl/bn.h>
+
+#include "testutil.h"
+
 #ifdef OPENSSL_NO_RSA
-int main(int argc, char *argv[])
+int setup_tests(void)
 {
-    printf("No RSA support\n");
-    return (0);
+    /* No tests */
+    return 1;
 }
 #else
 # include <openssl/rsa.h>
 
 # define SetKey \
-  key->n = BN_bin2bn(n, sizeof(n)-1, key->n); \
-  key->e = BN_bin2bn(e, sizeof(e)-1, key->e); \
-  key->d = BN_bin2bn(d, sizeof(d)-1, key->d); \
-  key->p = BN_bin2bn(p, sizeof(p)-1, key->p); \
-  key->q = BN_bin2bn(q, sizeof(q)-1, key->q); \
-  key->dmp1 = BN_bin2bn(dmp1, sizeof(dmp1)-1, key->dmp1); \
-  key->dmq1 = BN_bin2bn(dmq1, sizeof(dmq1)-1, key->dmq1); \
-  key->iqmp = BN_bin2bn(iqmp, sizeof(iqmp)-1, key->iqmp); \
-  memcpy(c, ctext_ex, sizeof(ctext_ex) - 1); \
-  return (sizeof(ctext_ex) - 1);
+    RSA_set0_key(key,                                           \
+                 BN_bin2bn(n, sizeof(n)-1, NULL),               \
+                 BN_bin2bn(e, sizeof(e)-1, NULL),               \
+                 BN_bin2bn(d, sizeof(d)-1, NULL));              \
+    RSA_set0_factors(key,                                       \
+                     BN_bin2bn(p, sizeof(p)-1, NULL),           \
+                     BN_bin2bn(q, sizeof(q)-1, NULL));          \
+    RSA_set0_crt_params(key,                                    \
+                        BN_bin2bn(dmp1, sizeof(dmp1)-1, NULL),  \
+                        BN_bin2bn(dmq1, sizeof(dmq1)-1, NULL),  \
+                        BN_bin2bn(iqmp, sizeof(iqmp)-1, NULL)); \
+    memcpy(c, ctext_ex, sizeof(ctext_ex) - 1);                  \
+    return sizeof(ctext_ex) - 1;
 
 static int key1(RSA *key, unsigned char *c)
 {
@@ -201,17 +216,31 @@ static int pad_unknown(void)
     unsigned long l;
     while ((l = ERR_get_error()) != 0)
         if (ERR_GET_REASON(l) == RSA_R_UNKNOWN_PADDING_TYPE)
-            return (1);
-    return (0);
+            return 1;
+    return 0;
 }
 
-static const char rnd_seed[] =
-    "string to make the random number generator think it has entropy";
+static int rsa_setkey(RSA** key, unsigned char* ctext, int idx)
+{
+    int clen = 0;
+    *key = RSA_new();
+    switch (idx) {
+    case 0:
+        clen = key1(*key, ctext);
+        break;
+    case 1:
+        clen = key2(*key, ctext);
+        break;
+    case 2:
+        clen = key3(*key, ctext);
+        break;
+    }
+    return clen;
+}
 
-int main(int argc, char *argv[])
+static int test_rsa_pkcs1(int idx)
 {
-    int err = 0;
-    int v;
+    int ret = 0;
     RSA *key;
     unsigned char ptext[256];
     unsigned char ctext[256];
@@ -220,112 +249,150 @@ int main(int argc, char *argv[])
     int plen;
     int clen = 0;
     int num;
-    int n;
 
-    CRYPTO_malloc_debug_init();
-    CRYPTO_dbg_set_options(V_CRYPTO_MDEBUG_ALL);
-    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+    plen = sizeof(ptext_ex) - 1;
+    clen = rsa_setkey(&key, ctext_ex, idx);
+
+    num = RSA_public_encrypt(plen, ptext_ex, ctext, key,
+                             RSA_PKCS1_PADDING);
+    if (!TEST_int_eq(num, clen))
+        goto err;
 
-    RAND_seed(rnd_seed, sizeof rnd_seed); /* or OAEP may fail */
+    num = RSA_private_decrypt(num, ctext, ptext, key, RSA_PKCS1_PADDING);
+    if (!TEST_mem_eq(ptext, num, ptext_ex, plen))
+        goto err;
+
+    ret = 1;
+err:
+    RSA_free(key);
+    return ret;
+}
+
+static int test_rsa_oaep(int idx)
+{
+    int ret = 0;
+    RSA *key;
+    unsigned char ptext[256];
+    unsigned char ctext[256];
+    static unsigned char ptext_ex[] = "\x54\x85\x9b\x34\x2c\x49\xea\x2a";
+    unsigned char ctext_ex[256];
+    int plen;
+    int clen = 0;
+    int num;
+    int n;
 
     plen = sizeof(ptext_ex) - 1;
+    clen = rsa_setkey(&key, ctext_ex, idx);
+
+    num = RSA_public_encrypt(plen, ptext_ex, ctext, key,
+                             RSA_PKCS1_OAEP_PADDING);
+    if (num == -1 && pad_unknown()) {
+        TEST_info("Skipping: No OAEP support");
+        ret = 1;
+        goto err;
+    }
+    if (!TEST_int_eq(num, clen))
+        goto err;
+
+    num = RSA_private_decrypt(num, ctext, ptext, key,
+                              RSA_PKCS1_OAEP_PADDING);
+    if (!TEST_mem_eq(ptext, num, ptext_ex, plen))
+        goto err;
+
+    /* Different ciphertexts. Try decrypting ctext_ex */
+    num = RSA_private_decrypt(clen, ctext_ex, ptext, key,
+                              RSA_PKCS1_OAEP_PADDING);
+    if (!TEST_mem_eq(ptext, num, ptext_ex, plen))
+        goto err;
+
+    /* Try decrypting corrupted ciphertexts. */
+    for (n = 0; n < clen; ++n) {
+        ctext[n] ^= 1;
+        num = RSA_private_decrypt(clen, ctext, ptext, key,
+                                      RSA_PKCS1_OAEP_PADDING);
+        if (!TEST_int_le(num, 0))
+            goto err;
+        ctext[n] ^= 1;
+    }
 
-    for (v = 0; v < 6; v++) {
-        key = RSA_new();
-        switch (v % 3) {
-        case 0:
-            clen = key1(key, ctext_ex);
-            break;
-        case 1:
-            clen = key2(key, ctext_ex);
-            break;
-        case 2:
-            clen = key3(key, ctext_ex);
-            break;
-        }
-        if (v / 3 >= 1)
-            key->flags |= RSA_FLAG_NO_CONSTTIME;
-
-        num = RSA_public_encrypt(plen, ptext_ex, ctext, key,
-                                 RSA_PKCS1_PADDING);
-        if (num != clen) {
-            printf("PKCS#1 v1.5 encryption failed!\n");
-            err = 1;
-            goto oaep;
-        }
-
-        num = RSA_private_decrypt(num, ctext, ptext, key, RSA_PKCS1_PADDING);
-        if (num != plen || memcmp(ptext, ptext_ex, num) != 0) {
-            printf("PKCS#1 v1.5 decryption failed!\n");
-            err = 1;
-        } else
-            printf("PKCS #1 v1.5 encryption/decryption ok\n");
-
- oaep:
-        ERR_clear_error();
-        num = RSA_public_encrypt(plen, ptext_ex, ctext, key,
-                                 RSA_PKCS1_OAEP_PADDING);
-        if (num == -1 && pad_unknown()) {
-            printf("No OAEP support\n");
-            goto next;
-        }
-        if (num != clen) {
-            printf("OAEP encryption failed!\n");
-            err = 1;
-            goto next;
-        }
-
-        num = RSA_private_decrypt(num, ctext, ptext, key,
-                                  RSA_PKCS1_OAEP_PADDING);
-        if (num != plen || memcmp(ptext, ptext_ex, num) != 0) {
-            printf("OAEP decryption (encrypted data) failed!\n");
-            err = 1;
-        } else if (memcmp(ctext, ctext_ex, num) == 0)
-            printf("OAEP test vector %d passed!\n", v);
-
-        /*
-         * Different ciphertexts (rsa_oaep.c without -DPKCS_TESTVECT). Try
-         * decrypting ctext_ex
-         */
-
-        num = RSA_private_decrypt(clen, ctext_ex, ptext, key,
+    /* Test truncated ciphertexts, as well as negative length. */
+    for (n = -1; n < clen; ++n) {
+        num = RSA_private_decrypt(n, ctext, ptext, key,
                                   RSA_PKCS1_OAEP_PADDING);
-
-        if (num != plen || memcmp(ptext, ptext_ex, num) != 0) {
-            printf("OAEP decryption (test vector data) failed!\n");
-            err = 1;
-        } else
-            printf("OAEP encryption/decryption ok\n");
-
-        /* Try decrypting corrupted ciphertexts */
-        for (n = 0; n < clen; ++n) {
-            int b;
-            unsigned char saved = ctext[n];
-            for (b = 0; b < 256; ++b) {
-                if (b == saved)
-                    continue;
-                ctext[n] = b;
-                num = RSA_private_decrypt(num, ctext, ptext, key,
-                                          RSA_PKCS1_OAEP_PADDING);
-                if (num > 0) {
-                    printf("Corrupt data decrypted!\n");
-                    err = 1;
-                }
-            }
-        }
- next:
-        RSA_free(key);
+        if (!TEST_int_le(num, 0))
+            goto err;
     }
 
-    CRYPTO_cleanup_all_ex_data();
-    ERR_remove_thread_state(NULL);
+    ret = 1;
+err:
+    RSA_free(key);
+    return ret;
+}
 
-    CRYPTO_mem_leaks_fp(stderr);
+static const struct {
+    int bits;
+    unsigned int r;
+} rsa_security_bits_cases[] = {
+    /* NIST SP 800-56B rev 2 (draft) Appendix D Table 5 */
+    { 2048,     112 },
+    { 3072,     128 },
+    { 4096,     152 },
+    { 6144,     176 },
+    { 8192,     200 },
+    /* Older values */
+    { 256,      40  },
+    { 512,      56  },
+    { 1024,     80  },
+    /* Slightly different value to the 256 that NIST lists in their tables */
+    { 15360,    264 },
+    /* Some other values */
+    { 8888,     208 },
+    { 2468,     120 },
+    { 13456,    248 }
+};
+
+static int test_rsa_security_bit(int n)
+{
+    static const unsigned char vals[8] = {
+        0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40
+    };
+    RSA *key = RSA_new();
+    const int bits = rsa_security_bits_cases[n].bits;
+    const int result = rsa_security_bits_cases[n].r;
+    const int bytes = (bits + 7) / 8;
+    int r = 0;
+    unsigned char num[2000];
+
+    if (!TEST_ptr(key) || !TEST_int_le(bytes, (int)sizeof(num)))
+        goto err;
+
+    /*
+     * It is necessary to set the RSA key in order to ask for the strength.
+     * A BN of an appropriate size is created, in general it won't have the
+     * properties necessary for RSA to function.  This is okay here since
+     * the RSA key is never used.
+     */
+    memset(num, vals[bits % 8], bytes);
+
+    /*
+     * The 'e' parameter is set to the same value as 'n'.  This saves having
+     * an extra BN to hold a sensible value for 'e'.  This is safe since the
+     * RSA key is not used.  The 'd' parameter can be NULL safely.
+     */
+    if (TEST_true(RSA_set0_key(key, BN_bin2bn(num, bytes, NULL),
+                               BN_bin2bn(num, bytes, NULL), NULL))
+            && TEST_uint_eq(RSA_security_bits(key), result))
+        r = 1;
+err:
+    RSA_free(key);
+    return r;
+}
 
-# ifdef OPENSSL_SYS_NETWARE
-    if (err)
-        printf("ERROR: %d\n", err);
-# endif
-    return err;
+int setup_tests(void)
+{
+    ADD_ALL_TESTS(test_rsa_pkcs1, 3);
+    ADD_ALL_TESTS(test_rsa_oaep, 3);
+    ADD_ALL_TESTS(test_rsa_security_bit, OSSL_NELEM(rsa_security_bits_cases));
+    return 1;
 }
 #endif