Adapt test/evp_test.c to deal with available EVP_MACs
authorRichard Levitte <levitte@openssl.org>
Wed, 24 Oct 2018 16:36:31 +0000 (18:36 +0200)
committerRichard Levitte <levitte@openssl.org>
Mon, 29 Oct 2018 12:35:19 +0000 (13:35 +0100)
If a MAC isn't available as an EVP_MAC, the MAC test falls back to the
corresponding EVP_PKEY method.

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/7393)

test/evp_test.c

index 2ac69e11da77621f02a634eb6a7e11959c228831..be18afb63d55ff7e9d75ad4a6b9f29239468b792 100644 (file)
@@ -832,8 +832,9 @@ static const EVP_TEST_METHOD cipher_test_method = {
 **/
 
 typedef struct mac_data_st {
-    /* MAC type */
-    int type;
+    /* MAC type in one form or another */
+    const EVP_MAC *mac;          /* for mac_test_run_mac */
+    int type;                    /* for mac_test_run_pkey */
     /* Algorithm string for this MAC */
     char *alg;
     /* MAC key */
@@ -851,37 +852,62 @@ typedef struct mac_data_st {
 
 static int mac_test_init(EVP_TEST *t, const char *alg)
 {
-    int type;
+    const EVP_MAC *mac = NULL;
+    int type = NID_undef;
     MAC_DATA *mdat;
 
-    if (strcmp(alg, "HMAC") == 0) {
-        type = EVP_PKEY_HMAC;
-    } else if (strcmp(alg, "CMAC") == 0) {
+    if ((mac = EVP_get_macbyname(alg)) == NULL) {
+        /*
+         * Since we didn't find an EVP_MAC, we check for known EVP_PKEY methods
+         * For debugging purposes, we allow 'NNNN by EVP_PKEY' to force running
+         * the EVP_PKEY method.
+         */
+        size_t sz = strlen(alg);
+        static const char epilogue[] = " by EVP_PKEY";
+
+        if (strcmp(alg + sz - (sizeof(epilogue) - 1), epilogue) == 0)
+            sz -= sizeof(epilogue) - 1;
+
+        if (strncmp(alg, "HMAC", sz) == 0) {
+            type = EVP_PKEY_HMAC;
+        } else if (strncmp(alg, "CMAC", sz) == 0) {
 #ifndef OPENSSL_NO_CMAC
-        type = EVP_PKEY_CMAC;
+            type = EVP_PKEY_CMAC;
 #else
-        t->skip = 1;
-        return 1;
+            t->skip = 1;
+            return 1;
 #endif
-    } else if (strcmp(alg, "Poly1305") == 0) {
+        } else if (strncmp(alg, "Poly1305", sz) == 0) {
 #ifndef OPENSSL_NO_POLY1305
-        type = EVP_PKEY_POLY1305;
+            type = EVP_PKEY_POLY1305;
 #else
-        t->skip = 1;
-        return 1;
+            t->skip = 1;
+            return 1;
 #endif
-    } else if (strcmp(alg, "SipHash") == 0) {
+        } else if (strncmp(alg, "SipHash", sz) == 0) {
 #ifndef OPENSSL_NO_SIPHASH
-        type = EVP_PKEY_SIPHASH;
+            type = EVP_PKEY_SIPHASH;
 #else
-        t->skip = 1;
-        return 1;
+            t->skip = 1;
+            return 1;
 #endif
-    } else
-        return 0;
+        } else {
+            /*
+             * Not a known EVP_PKEY method either.  If it's a known OID, then
+             * assume it's been disabled.
+             */
+            if (OBJ_sn2nid(alg) != NID_undef || OBJ_ln2nid(alg) != NID_undef) {
+                t->skip = 1;
+                return 1;
+            }
+
+            return 0;
+        }
+    }
 
     mdat = OPENSSL_zalloc(sizeof(*mdat));
     mdat->type = type;
+    mdat->mac = mac;
     mdat->controls = sk_OPENSSL_STRING_new_null();
     t->data = mdat;
     return 1;
@@ -927,7 +953,7 @@ static int mac_test_parse(EVP_TEST *t,
     return 0;
 }
 
-static int mac_test_run(EVP_TEST *t)
+static int mac_test_run_pkey(EVP_TEST *t)
 {
     MAC_DATA *expected = t->data;
     EVP_MD_CTX *mctx = NULL;
@@ -938,6 +964,12 @@ static int mac_test_run(EVP_TEST *t)
     size_t got_len;
     int i;
 
+    if (expected->alg == NULL)
+        TEST_info("Trying the EVP_PKEY %s test", OBJ_nid2sn(expected->type));
+    else
+        TEST_info("Trying the EVP_PKEY %s test with %s",
+                  OBJ_nid2sn(expected->type), expected->alg);
+
 #ifdef OPENSSL_NO_DES
     if (expected->alg != NULL && strstr(expected->alg, "DES") != NULL) {
         /* Skip DES */
@@ -1005,6 +1037,126 @@ static int mac_test_run(EVP_TEST *t)
     return 1;
 }
 
+static int mac_test_run_mac(EVP_TEST *t)
+{
+    MAC_DATA *expected = t->data;
+    EVP_MAC_CTX *ctx = NULL;
+    const void *algo = NULL;
+    int algo_ctrl = 0;
+    unsigned char *got = NULL;
+    size_t got_len;
+    int rv, i;
+
+    if (expected->alg == NULL)
+        TEST_info("Trying the EVP_MAC %s test", EVP_MAC_name(expected->mac));
+    else
+        TEST_info("Trying the EVP_MAC %s test with %s",
+                  EVP_MAC_name(expected->mac), expected->alg);
+
+#ifdef OPENSSL_NO_DES
+    if (expected->alg != NULL && strstr(expected->alg, "DES") != NULL) {
+        /* Skip DES */
+        t->err = NULL;
+        goto err;
+    }
+#endif
+
+    if ((ctx = EVP_MAC_CTX_new(expected->mac)) == NULL) {
+        t->err = "MAC_CREATE_ERROR";
+        goto err;
+    }
+
+    if (expected->alg != NULL
+        && ((algo_ctrl = EVP_MAC_CTRL_SET_CIPHER,
+             algo = EVP_get_cipherbyname(expected->alg)) == NULL
+            && (algo_ctrl = EVP_MAC_CTRL_SET_MD,
+                algo = EVP_get_digestbyname(expected->alg)) == NULL)) {
+        t->err = "MAC_BAD_ALGORITHM";
+        goto err;
+    }
+
+
+    if (algo_ctrl != 0) {
+        rv = EVP_MAC_ctrl(ctx, algo_ctrl, algo);
+        if (rv == -2) {
+            t->err = "MAC_CTRL_INVALID";
+            goto err;
+        } else if (rv <= 0) {
+            t->err = "MAC_CTRL_ERROR";
+            goto err;
+        }
+    }
+
+    rv = EVP_MAC_ctrl(ctx, EVP_MAC_CTRL_SET_KEY,
+                      expected->key, expected->key_len);
+    if (rv == -2) {
+        t->err = "MAC_CTRL_INVALID";
+        goto err;
+    } else if (rv <= 0) {
+        t->err = "MAC_CTRL_ERROR";
+        goto err;
+    }
+
+    if (!EVP_MAC_init(ctx)) {
+        t->err = "MAC_INIT_ERROR";
+        goto err;
+    }
+    for (i = 0; i < sk_OPENSSL_STRING_num(expected->controls); i++) {
+        char *p, *tmpval;
+        char *value = sk_OPENSSL_STRING_value(expected->controls, i);
+
+        if (!TEST_ptr(tmpval = OPENSSL_strdup(value))) {
+            t->err = "MAC_CTRL_ERROR";
+            goto err;
+        }
+        p = strchr(tmpval, ':');
+        if (p != NULL)
+            *p++ = '\0';
+        rv = EVP_MAC_ctrl_str(ctx, tmpval, p);
+        OPENSSL_free(tmpval);
+        if (rv == -2) {
+            t->err = "MAC_CTRL_INVALID";
+            goto err;
+        } else if (rv <= 0) {
+            t->err = "MAC_CTRL_ERROR";
+            goto err;
+        }
+    }
+    if (!EVP_MAC_update(ctx, expected->input, expected->input_len)) {
+        t->err = "MAC_UPDATE_ERROR";
+        goto err;
+    }
+    if (!EVP_MAC_final(ctx, NULL, &got_len)) {
+        t->err = "MAC_FINAL_LENGTH_ERROR";
+        goto err;
+    }
+    if (!TEST_ptr(got = OPENSSL_malloc(got_len))) {
+        t->err = "TEST_FAILURE";
+        goto err;
+    }
+    if (!EVP_MAC_final(ctx, got, &got_len)
+        || !memory_err_compare(t, "TEST_MAC_ERR",
+                               expected->output, expected->output_len,
+                               got, got_len)) {
+        t->err = "TEST_MAC_ERR";
+        goto err;
+    }
+    t->err = NULL;
+ err:
+    EVP_MAC_CTX_free(ctx);
+    OPENSSL_free(got);
+    return 1;
+}
+
+static int mac_test_run(EVP_TEST *t)
+{
+    MAC_DATA *expected = t->data;
+
+    if (expected->mac != NULL)
+        return mac_test_run_mac(t);
+    return mac_test_run_pkey(t);
+}
+
 static const EVP_TEST_METHOD mac_test_method = {
     "MAC",
     mac_test_init,