X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=test%2Fevp_test.c;h=029738f296c34111d24f1e72346dabd6ba39b64c;hp=a804a9f73a38db374fe4aa8cc4f99a396592be25;hb=25446a66b69a28c85d178e4454d2caed75d75293;hpb=4665244ce28add625d28c9ee9c52e39b42024705 diff --git a/test/evp_test.c b/test/evp_test.c index a804a9f73a..029738f296 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -1,7 +1,7 @@ /* - * Copyright 2015-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2015-2019 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -14,13 +14,18 @@ #include #include #include +#include #include #include #include +#include +#include #include "internal/numbers.h" +#include "internal/nelem.h" #include "testutil.h" #include "evp_test.h" +#define AAD_NUM 4 typedef struct evp_test_method_st EVP_TEST_METHOD; @@ -34,7 +39,6 @@ typedef struct evp_test_st { const EVP_TEST_METHOD *meth; /* method for this test */ const char *err, *aux_err; /* Error string for test */ char *expected_err; /* Expected error value of test */ - char *func; /* Expected error function string */ char *reason; /* Expected error reason string */ void *data; /* test specific data */ } EVP_TEST; @@ -74,6 +78,27 @@ static int find_key(EVP_PKEY **ppk, const char *name, KEY_LIST *lst); static int parse_bin(const char *value, unsigned char **buf, size_t *buflen); +/* + * Compare two memory regions for equality, returning zero if they differ. + * However, if there is expected to be an error and the actual error + * matches then the memory is expected to be different so handle this + * case without producing unnecessary test framework output. + */ +static int memory_err_compare(EVP_TEST *t, const char *err, + const void *expected, size_t expected_len, + const void *got, size_t got_len) +{ + int r; + + if (t->expected_err != NULL && strcmp(t->expected_err, err) == 0) + r = !TEST_mem_ne(expected, expected_len, got, got_len); + else + r = TEST_mem_eq(expected, expected_len, got, got_len); + if (!r) + t->err = err; + return r; +} + /* * Structure used to hold a list of blocks of memory to test * calls to "update" like functions. @@ -397,10 +422,11 @@ static int digest_test_run(EVP_TEST *t) t->err = "DIGEST_LENGTH_MISMATCH"; goto err; } - if (!TEST_mem_eq(expected->output, expected->output_len, got, got_len)) { - t->err = "DIGEST_MISMATCH"; + if (!memory_err_compare(t, "DIGEST_MISMATCH", + expected->output, expected->output_len, + got, got_len)) goto err; - } + t->err = NULL; err: @@ -435,11 +461,12 @@ typedef struct cipher_data_st { size_t plaintext_len; unsigned char *ciphertext; size_t ciphertext_len; - /* GCM, CCM only */ - unsigned char *aad; - size_t aad_len; + /* GCM, CCM, OCB and SIV only */ + unsigned char *aad[AAD_NUM]; + size_t aad_len[AAD_NUM]; unsigned char *tag; size_t tag_len; + int tag_late; } CIPHER_DATA; static int cipher_test_init(EVP_TEST *t, const char *alg) @@ -462,8 +489,9 @@ static int cipher_test_init(EVP_TEST *t, const char *alg) m = EVP_CIPHER_mode(cipher); if (m == EVP_CIPH_GCM_MODE || m == EVP_CIPH_OCB_MODE + || m == EVP_CIPH_SIV_MODE || m == EVP_CIPH_CCM_MODE) - cdat->aead = EVP_CIPHER_mode(cipher); + cdat->aead = m; else if (EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) cdat->aead = -1; else @@ -475,13 +503,15 @@ static int cipher_test_init(EVP_TEST *t, const char *alg) static void cipher_test_cleanup(EVP_TEST *t) { + int i; CIPHER_DATA *cdat = t->data; OPENSSL_free(cdat->key); OPENSSL_free(cdat->iv); OPENSSL_free(cdat->ciphertext); OPENSSL_free(cdat->plaintext); - OPENSSL_free(cdat->aad); + for (i = 0; i < AAD_NUM; i++) + OPENSSL_free(cdat->aad[i]); OPENSSL_free(cdat->tag); } @@ -489,6 +519,7 @@ static int cipher_test_parse(EVP_TEST *t, const char *keyword, const char *value) { CIPHER_DATA *cdat = t->data; + int i; if (strcmp(keyword, "Key") == 0) return parse_bin(value, &cdat->key, &cdat->key_len); @@ -499,10 +530,24 @@ static int cipher_test_parse(EVP_TEST *t, const char *keyword, if (strcmp(keyword, "Ciphertext") == 0) return parse_bin(value, &cdat->ciphertext, &cdat->ciphertext_len); if (cdat->aead) { - if (strcmp(keyword, "AAD") == 0) - return parse_bin(value, &cdat->aad, &cdat->aad_len); + if (strcmp(keyword, "AAD") == 0) { + for (i = 0; i < AAD_NUM; i++) { + if (cdat->aad[i] == NULL) + return parse_bin(value, &cdat->aad[i], &cdat->aad_len[i]); + } + return 0; + } if (strcmp(keyword, "Tag") == 0) return parse_bin(value, &cdat->tag, &cdat->tag_len); + if (strcmp(keyword, "SetTagLate") == 0) { + if (strcmp(value, "TRUE") == 0) + cdat->tag_late = 1; + else if (strcmp(value, "FALSE") == 0) + cdat->tag_late = 0; + else + return 0; + return 1; + } } if (strcmp(keyword, "Operation") == 0) { @@ -523,7 +568,7 @@ static int cipher_test_enc(EVP_TEST *t, int enc, CIPHER_DATA *expected = t->data; unsigned char *in, *expected_out, *tmp = NULL; size_t in_len, out_len, donelen = 0; - int ok = 0, tmplen, chunklen, tmpflen; + int ok = 0, tmplen, chunklen, tmpflen, i; EVP_CIPHER_CTX *ctx = NULL; t->err = "TEST_FAILURE"; @@ -588,7 +633,7 @@ static int cipher_test_enc(EVP_TEST *t, int enc, * If encrypting or OCB just set tag length initially, otherwise * set tag length and value. */ - if (enc || expected->aead == EVP_CIPH_OCB_MODE) { + if (enc || expected->aead == EVP_CIPH_OCB_MODE || expected->tag_late) { t->err = "TAG_LENGTH_SET_ERROR"; tag = NULL; } else { @@ -610,13 +655,13 @@ static int cipher_test_enc(EVP_TEST *t, int enc, t->err = "KEY_SET_ERROR"; goto err; } - - if (!enc && expected->aead == EVP_CIPH_OCB_MODE) { - if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, - expected->tag_len, expected->tag)) { - t->err = "TAG_SET_ERROR"; - goto err; - } + /* Check that we get the same IV back */ + if (expected->iv != NULL + && (EVP_CIPHER_flags(expected->cipher) & EVP_CIPH_CUSTOM_IV) == 0 + && !TEST_mem_eq(expected->iv, expected->iv_len, + EVP_CIPHER_CTX_iv(ctx), expected->iv_len)) { + t->err = "INVALID_IV"; + goto err; } if (expected->aead == EVP_CIPH_CCM_MODE) { @@ -625,34 +670,47 @@ static int cipher_test_enc(EVP_TEST *t, int enc, goto err; } } - if (expected->aad) { + if (expected->aad[0] != NULL) { t->err = "AAD_SET_ERROR"; if (!frag) { - if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad, - expected->aad_len)) - goto err; + for (i = 0; expected->aad[i] != NULL; i++) { + if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad[i], + expected->aad_len[i])) + goto err; + } } else { /* * Supply the AAD in chunks less than the block size where possible */ - if (expected->aad_len > 0) { - if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad, 1)) - goto err; - donelen++; - } - if (expected->aad_len > 2) { - if (!EVP_CipherUpdate(ctx, NULL, &chunklen, - expected->aad + donelen, - expected->aad_len - 2)) + for (i = 0; expected->aad[i] != NULL; i++) { + if (expected->aad_len[i] > 0) { + if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad[i], 1)) + goto err; + donelen++; + } + if (expected->aad_len[i] > 2) { + if (!EVP_CipherUpdate(ctx, NULL, &chunklen, + expected->aad[i] + donelen, + expected->aad_len[i] - 2)) + goto err; + donelen += expected->aad_len[i] - 2; + } + if (expected->aad_len[i] > 1 + && !EVP_CipherUpdate(ctx, NULL, &chunklen, + expected->aad[i] + donelen, 1)) goto err; - donelen += expected->aad_len - 2; } - if (expected->aad_len > 1 - && !EVP_CipherUpdate(ctx, NULL, &chunklen, - expected->aad + donelen, 1)) - goto err; } } + + if (!enc && (expected->aead == EVP_CIPH_OCB_MODE || expected->tag_late)) { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + expected->tag_len, expected->tag)) { + t->err = "TAG_SET_ERROR"; + goto err; + } + } + EVP_CIPHER_CTX_set_padding(ctx, 0); t->err = "CIPHERUPDATE_ERROR"; tmplen = 0; @@ -688,11 +746,9 @@ static int cipher_test_enc(EVP_TEST *t, int enc, t->err = "CIPHERFINAL_ERROR"; goto err; } - if (!TEST_mem_eq(expected_out, out_len, - tmp + out_misalign, tmplen + tmpflen)) { - t->err = "VALUE_MISMATCH"; + if (!memory_err_compare(t, "VALUE_MISMATCH", expected_out, out_len, + tmp + out_misalign, tmplen + tmpflen)) goto err; - } if (enc && expected->aead) { unsigned char rtag[16]; @@ -705,11 +761,10 @@ static int cipher_test_enc(EVP_TEST *t, int enc, t->err = "TAG_RETRIEVE_ERROR"; goto err; } - if (!TEST_mem_eq(expected->tag, expected->tag_len, - rtag, expected->tag_len)) { - t->err = "TAG_VALUE_MISMATCH"; + if (!memory_err_compare(t, "TAG_VALUE_MISMATCH", + expected->tag, expected->tag_len, + rtag, expected->tag_len)) goto err; - } } t->err = NULL; ok = 1; @@ -779,10 +834,11 @@ static int cipher_test_run(EVP_TEST *t) if (out_misalign == 1 && frag == 0) { /* - * XTS, CCM and Wrap modes have special requirements about input + * XTS, SIV, CCM and Wrap modes have special requirements about input * lengths so we don't fragment for those */ if (cdat->aead == EVP_CIPH_CCM_MODE + || EVP_CIPHER_mode(cdat->cipher) == EVP_CIPH_SIV_MODE || EVP_CIPHER_mode(cdat->cipher) == EVP_CIPH_XTS_MODE || EVP_CIPHER_mode(cdat->cipher) == EVP_CIPH_WRAP_MODE) break; @@ -811,64 +867,113 @@ static const EVP_TEST_METHOD cipher_test_method = { **/ typedef struct mac_data_st { - /* MAC type */ - int type; + /* MAC type in one form or another */ + EVP_MAC *mac; /* for mac_test_run_mac */ + int type; /* for mac_test_run_pkey */ /* Algorithm string for this MAC */ char *alg; /* MAC key */ unsigned char *key; size_t key_len; + /* MAC IV (GMAC) */ + unsigned char *iv; + size_t iv_len; /* Input to MAC */ unsigned char *input; size_t input_len; /* Expected output */ unsigned char *output; size_t output_len; + unsigned char *custom; + size_t custom_len; + /* MAC salt (blake2) */ + unsigned char *salt; + size_t salt_len; + /* Collection of controls */ + STACK_OF(OPENSSL_STRING) *controls; } MAC_DATA; static int mac_test_init(EVP_TEST *t, const char *alg) { - int type; + 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_MAC_fetch(NULL, alg, NULL)) == 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 (sz >= sizeof(epilogue) + && 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; } +/* Because OPENSSL_free is a macro, it can't be passed as a function pointer */ +static void openssl_free(char *m) +{ + OPENSSL_free(m); +} + static void mac_test_cleanup(EVP_TEST *t) { MAC_DATA *mdat = t->data; + EVP_MAC_free(mdat->mac); + sk_OPENSSL_STRING_pop_free(mdat->controls, openssl_free); OPENSSL_free(mdat->alg); OPENSSL_free(mdat->key); + OPENSSL_free(mdat->iv); + OPENSSL_free(mdat->custom); + OPENSSL_free(mdat->salt); OPENSSL_free(mdat->input); OPENSSL_free(mdat->output); } @@ -880,6 +985,12 @@ static int mac_test_parse(EVP_TEST *t, if (strcmp(keyword, "Key") == 0) return parse_bin(value, &mdata->key, &mdata->key_len); + if (strcmp(keyword, "IV") == 0) + return parse_bin(value, &mdata->iv, &mdata->iv_len); + if (strcmp(keyword, "Custom") == 0) + return parse_bin(value, &mdata->custom, &mdata->custom_len); + if (strcmp(keyword, "Salt") == 0) + return parse_bin(value, &mdata->salt, &mdata->salt_len); if (strcmp(keyword, "Algorithm") == 0) { mdata->alg = OPENSSL_strdup(value); if (!mdata->alg) @@ -890,10 +1001,35 @@ static int mac_test_parse(EVP_TEST *t, return parse_bin(value, &mdata->input, &mdata->input_len); if (strcmp(keyword, "Output") == 0) return parse_bin(value, &mdata->output, &mdata->output_len); + if (strcmp(keyword, "Ctrl") == 0) + return sk_OPENSSL_STRING_push(mdata->controls, + OPENSSL_strdup(value)) != 0; return 0; } -static int mac_test_run(EVP_TEST *t) +static int mac_test_ctrl_pkey(EVP_TEST *t, EVP_PKEY_CTX *pctx, + const char *value) +{ + int rv; + char *p, *tmpval; + + if (!TEST_ptr(tmpval = OPENSSL_strdup(value))) + return 0; + p = strchr(tmpval, ':'); + if (p != NULL) + *p++ = '\0'; + rv = EVP_PKEY_CTX_ctrl_str(pctx, tmpval, p); + if (rv == -2) + t->err = "PKEY_CTRL_INVALID"; + else if (rv <= 0) + t->err = "PKEY_CTRL_ERROR"; + else + rv = 1; + OPENSSL_free(tmpval); + return rv > 0; +} + +static int mac_test_run_pkey(EVP_TEST *t) { MAC_DATA *expected = t->data; EVP_MD_CTX *mctx = NULL; @@ -902,6 +1038,13 @@ static int mac_test_run(EVP_TEST *t) const EVP_MD *md = NULL; unsigned char *got = NULL; 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) { @@ -915,8 +1058,8 @@ static int mac_test_run(EVP_TEST *t) key = EVP_PKEY_new_CMAC_key(NULL, expected->key, expected->key_len, EVP_get_cipherbyname(expected->alg)); else - key = EVP_PKEY_new_private_key(expected->type, NULL, expected->key, - expected->key_len); + key = EVP_PKEY_new_raw_private_key(expected->type, NULL, expected->key, + expected->key_len); if (key == NULL) { t->err = "MAC_KEY_CREATE_ERROR"; goto err; @@ -936,7 +1079,13 @@ static int mac_test_run(EVP_TEST *t) t->err = "DIGESTSIGNINIT_ERROR"; goto err; } - + for (i = 0; i < sk_OPENSSL_STRING_num(expected->controls); i++) + if (!mac_test_ctrl_pkey(t, pctx, + sk_OPENSSL_STRING_value(expected->controls, + i))) { + t->err = "EVPPKEYCTXCTRL_ERROR"; + goto err; + } if (!EVP_DigestSignUpdate(mctx, expected->input, expected->input_len)) { t->err = "DIGESTSIGNUPDATE_ERROR"; goto err; @@ -950,8 +1099,9 @@ static int mac_test_run(EVP_TEST *t) goto err; } if (!EVP_DigestSignFinal(mctx, got, &got_len) - || !TEST_mem_eq(expected->output, expected->output_len, - 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; } @@ -964,6 +1114,144 @@ 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; + unsigned char *got = NULL; + size_t got_len; + int i; + OSSL_PARAM params[21]; + size_t params_n = 0; + size_t params_n_allocstart = 0; + const OSSL_PARAM *defined_params = + EVP_MAC_CTX_settable_params(expected->mac); + + 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 (expected->alg != NULL) + params[params_n++] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_ALGORITHM, + expected->alg, + strlen(expected->alg) + 1); + if (expected->key != NULL) + params[params_n++] = + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + expected->key, + expected->key_len); + if (expected->custom != NULL) + params[params_n++] = + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_CUSTOM, + expected->custom, + expected->custom_len); + if (expected->salt != NULL) + params[params_n++] = + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_SALT, + expected->salt, + expected->salt_len); + if (expected->iv != NULL) + params[params_n++] = + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_IV, + expected->iv, + expected->iv_len); + + /* + * Unknown controls. They must match parameters that the MAC recognises + */ + if (params_n + sk_OPENSSL_STRING_num(expected->controls) + >= OSSL_NELEM(params)) { + t->err = "MAC_TOO_MANY_PARAMETERS"; + goto err; + } + params_n_allocstart = params_n; + for (i = 0; i < sk_OPENSSL_STRING_num(expected->controls); i++) { + char *tmpkey, *tmpval; + char *value = sk_OPENSSL_STRING_value(expected->controls, i); + + if (!TEST_ptr(tmpkey = OPENSSL_strdup(value))) { + t->err = "MAC_PARAM_ERROR"; + goto err; + } + tmpval = strchr(tmpkey, ':'); + if (tmpval != NULL) + *tmpval++ = '\0'; + + if (!OSSL_PARAM_allocate_from_text(¶ms[params_n], defined_params, + tmpkey, tmpval, + strlen(tmpval))) { + OPENSSL_free(tmpkey); + t->err = "MAC_PARAM_ERROR"; + goto err; + } + params_n++; + + OPENSSL_free(tmpkey); + } + params[params_n] = OSSL_PARAM_construct_end(); + + if ((ctx = EVP_MAC_CTX_new(expected->mac)) == NULL) { + t->err = "MAC_CREATE_ERROR"; + goto err; + } + + if (!EVP_MAC_CTX_set_params(ctx, params)) { + t->err = "MAC_BAD_PARAMS"; + goto err; + } + if (!EVP_MAC_init(ctx)) { + t->err = "MAC_INIT_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, 0)) { + 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, 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: + while (params_n-- > params_n_allocstart) { + OPENSSL_free(params[params_n].data); + } + 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, @@ -1096,6 +1384,7 @@ static int pkey_test_run(EVP_TEST *t) PKEY_DATA *expected = t->data; unsigned char *got = NULL; size_t got_len; + EVP_PKEY_CTX *copy = NULL; if (expected->keyop(expected->ctx, NULL, &got_len, expected->input, expected->input_len) <= 0 @@ -1108,13 +1397,39 @@ static int pkey_test_run(EVP_TEST *t) t->err = "KEYOP_ERROR"; goto err; } - if (!TEST_mem_eq(expected->output, expected->output_len, got, got_len)) { - t->err = "KEYOP_MISMATCH"; + if (!memory_err_compare(t, "KEYOP_MISMATCH", + expected->output, expected->output_len, + got, got_len)) goto err; - } + t->err = NULL; + OPENSSL_free(got); + got = NULL; + + /* Repeat the test on a copy. */ + if (!TEST_ptr(copy = EVP_PKEY_CTX_dup(expected->ctx))) { + t->err = "INTERNAL_ERROR"; + goto err; + } + if (expected->keyop(copy, NULL, &got_len, expected->input, + expected->input_len) <= 0 + || !TEST_ptr(got = OPENSSL_malloc(got_len))) { + t->err = "KEYOP_LENGTH_ERROR"; + goto err; + } + if (expected->keyop(copy, got, &got_len, expected->input, + expected->input_len) <= 0) { + t->err = "KEYOP_ERROR"; + goto err; + } + if (!memory_err_compare(t, "KEYOP_MISMATCH", + expected->output, expected->output_len, + got, got_len)) + goto err; + err: OPENSSL_free(got); + EVP_PKEY_CTX_free(copy); return 1; } @@ -1226,10 +1541,10 @@ static int pderive_test_run(EVP_TEST *t) t->err = "DERIVE_ERROR"; goto err; } - if (!TEST_mem_eq(expected->output, expected->output_len, got, got_len)) { - t->err = "SHARED_SECRET_MISMATCH"; + if (!memory_err_compare(t, "SHARED_SECRET_MISMATCH", + expected->output, expected->output_len, + got, got_len)) goto err; - } t->err = NULL; err: @@ -1444,11 +1759,10 @@ static int pbe_test_run(EVP_TEST *t) goto err; } } - if (!TEST_mem_eq(expected->key, expected->key_len, - key, expected->key_len)) { - t->err = "KEY_MISMATCH"; + if (!memory_err_compare(t, "KEY_MISMATCH", expected->key, expected->key_len, + key, expected->key_len)) goto err; - } + t->err = NULL; err: OPENSSL_free(key); @@ -1497,15 +1811,18 @@ static int encode_test_init(EVP_TEST *t, const char *encoding) } else if (strcmp(encoding, "invalid") == 0) { edata->encoding = BASE64_INVALID_ENCODING; if (!TEST_ptr(t->expected_err = OPENSSL_strdup("DECODE_ERROR"))) - return 0; + goto err; } else { TEST_error("Bad encoding: %s." " Should be one of {canonical, valid, invalid}", encoding); - return 0; + goto err; } t->data = edata; return 1; +err: + OPENSSL_free(edata); + return 0; } static void encode_test_cleanup(EVP_TEST *t) @@ -1534,7 +1851,7 @@ static int encode_test_run(EVP_TEST *t) ENCODE_DATA *expected = t->data; unsigned char *encode_out = NULL, *decode_out = NULL; int output_len, chunk_len; - EVP_ENCODE_CTX *decode_ctx; + EVP_ENCODE_CTX *decode_ctx = NULL, *encode_ctx = NULL; if (!TEST_ptr(decode_ctx = EVP_ENCODE_CTX_new())) { t->err = "INTERNAL_ERROR"; @@ -1542,7 +1859,6 @@ static int encode_test_run(EVP_TEST *t) } if (expected->encoding == BASE64_CANONICAL_ENCODING) { - EVP_ENCODE_CTX *encode_ctx; if (!TEST_ptr(encode_ctx = EVP_ENCODE_CTX_new()) || !TEST_ptr(encode_out = @@ -1550,20 +1866,19 @@ static int encode_test_run(EVP_TEST *t) goto err; EVP_EncodeInit(encode_ctx); - EVP_EncodeUpdate(encode_ctx, encode_out, &chunk_len, - expected->input, expected->input_len); + if (!TEST_true(EVP_EncodeUpdate(encode_ctx, encode_out, &chunk_len, + expected->input, expected->input_len))) + goto err; + output_len = chunk_len; EVP_EncodeFinal(encode_ctx, encode_out + chunk_len, &chunk_len); output_len += chunk_len; - EVP_ENCODE_CTX_free(encode_ctx); - - if (!TEST_mem_eq(expected->output, expected->output_len, - encode_out, output_len)) { - t->err = "BAD_ENCODING"; + if (!memory_err_compare(t, "BAD_ENCODING", + expected->output, expected->output_len, + encode_out, output_len)) goto err; - } } if (!TEST_ptr(decode_out = @@ -1585,8 +1900,9 @@ static int encode_test_run(EVP_TEST *t) output_len += chunk_len; if (expected->encoding != BASE64_INVALID_ENCODING - && !TEST_mem_eq(expected->input, expected->input_len, - decode_out, output_len)) { + && !memory_err_compare(t, "BAD_DECODING", + expected->input, expected->input_len, + decode_out, output_len)) { t->err = "BAD_DECODING"; goto err; } @@ -1596,6 +1912,7 @@ static int encode_test_run(EVP_TEST *t) OPENSSL_free(encode_out); OPENSSL_free(decode_out); EVP_ENCODE_CTX_free(decode_ctx); + EVP_ENCODE_CTX_free(encode_ctx); return 1; } @@ -1607,13 +1924,14 @@ static const EVP_TEST_METHOD encode_test_method = { encode_test_run, }; + /** *** KDF TESTS **/ typedef struct kdf_data_st { /* Context for this operation */ - EVP_PKEY_CTX *ctx; + EVP_KDF_CTX *ctx; /* Expected output */ unsigned char *output; size_t output_len; @@ -1626,6 +1944,145 @@ typedef struct kdf_data_st { static int kdf_test_init(EVP_TEST *t, const char *name) { KDF_DATA *kdata; + const EVP_KDF *kdf; + +#ifdef OPENSSL_NO_SCRYPT + if (strcmp(name, "scrypt") == 0) { + t->skip = 1; + return 1; + } +#endif /* OPENSSL_NO_SCRYPT */ + +#ifdef OPENSSL_NO_CMS + if (strcmp(name, "X942KDF") == 0) { + t->skip = 1; + return 1; + } +#endif /* OPENSSL_NO_CMS */ + + kdf = EVP_get_kdfbyname(name); + if (kdf == NULL) + return 0; + + if (!TEST_ptr(kdata = OPENSSL_zalloc(sizeof(*kdata)))) + return 0; + kdata->ctx = EVP_KDF_CTX_new(kdf); + if (kdata->ctx == NULL) { + OPENSSL_free(kdata); + return 0; + } + t->data = kdata; + return 1; +} + +static void kdf_test_cleanup(EVP_TEST *t) +{ + KDF_DATA *kdata = t->data; + OPENSSL_free(kdata->output); + EVP_KDF_CTX_free(kdata->ctx); +} + +static int kdf_test_ctrl(EVP_TEST *t, EVP_KDF_CTX *kctx, + const char *value) +{ + int rv; + char *p, *tmpval; + + if (!TEST_ptr(tmpval = OPENSSL_strdup(value))) + return 0; + p = strchr(tmpval, ':'); + if (p != NULL) + *p++ = '\0'; + rv = EVP_KDF_ctrl_str(kctx, tmpval, p); + if (rv == -2) { + t->err = "KDF_CTRL_INVALID"; + rv = 1; + } else if (p != NULL && rv <= 0) { + /* If p has an OID and lookup fails assume disabled algorithm */ + int nid = OBJ_sn2nid(p); + + if (nid == NID_undef) + nid = OBJ_ln2nid(p); + if (nid != NID_undef + && EVP_get_digestbynid(nid) == NULL + && EVP_get_cipherbynid(nid) == NULL) { + t->skip = 1; + rv = 1; + } else { + t->err = "KDF_CTRL_ERROR"; + rv = 1; + } + } + OPENSSL_free(tmpval); + return rv > 0; +} + +static int kdf_test_parse(EVP_TEST *t, + const char *keyword, const char *value) +{ + KDF_DATA *kdata = t->data; + + if (strcmp(keyword, "Output") == 0) + return parse_bin(value, &kdata->output, &kdata->output_len); + if (strncmp(keyword, "Ctrl", 4) == 0) + return kdf_test_ctrl(t, kdata->ctx, value); + return 0; +} + +static int kdf_test_run(EVP_TEST *t) +{ + KDF_DATA *expected = t->data; + unsigned char *got = NULL; + size_t got_len = expected->output_len; + + if (!TEST_ptr(got = OPENSSL_malloc(got_len))) { + t->err = "INTERNAL_ERROR"; + goto err; + } + if (EVP_KDF_derive(expected->ctx, got, got_len) <= 0) { + t->err = "KDF_DERIVE_ERROR"; + goto err; + } + if (!memory_err_compare(t, "KDF_MISMATCH", + expected->output, expected->output_len, + got, got_len)) + goto err; + + t->err = NULL; + + err: + OPENSSL_free(got); + return 1; +} + +static const EVP_TEST_METHOD kdf_test_method = { + "KDF", + kdf_test_init, + kdf_test_cleanup, + kdf_test_parse, + kdf_test_run +}; + + +/** +*** PKEY KDF TESTS +**/ + +typedef struct pkey_kdf_data_st { + /* Context for this operation */ + EVP_PKEY_CTX *ctx; + /* Expected output */ + unsigned char *output; + size_t output_len; +} PKEY_KDF_DATA; + +/* + * Perform public key operation setup: lookup key, allocated ctx and call + * the appropriate initialisation function + */ +static int pkey_kdf_test_init(EVP_TEST *t, const char *name) +{ + PKEY_KDF_DATA *kdata; int kdf_nid = OBJ_sn2nid(name); #ifdef OPENSSL_NO_SCRYPT @@ -1633,7 +2090,14 @@ static int kdf_test_init(EVP_TEST *t, const char *name) t->skip = 1; return 1; } -#endif +#endif /* OPENSSL_NO_SCRYPT */ + +#ifdef OPENSSL_NO_CMS + if (strcmp(name, "X942KDF") == 0) { + t->skip = 1; + return 1; + } +#endif /* OPENSSL_NO_CMS */ if (kdf_nid == NID_undef) kdf_nid = OBJ_ln2nid(name); @@ -1654,17 +2118,17 @@ static int kdf_test_init(EVP_TEST *t, const char *name) return 1; } -static void kdf_test_cleanup(EVP_TEST *t) +static void pkey_kdf_test_cleanup(EVP_TEST *t) { - KDF_DATA *kdata = t->data; + PKEY_KDF_DATA *kdata = t->data; OPENSSL_free(kdata->output); EVP_PKEY_CTX_free(kdata->ctx); } -static int kdf_test_parse(EVP_TEST *t, - const char *keyword, const char *value) +static int pkey_kdf_test_parse(EVP_TEST *t, + const char *keyword, const char *value) { - KDF_DATA *kdata = t->data; + PKEY_KDF_DATA *kdata = t->data; if (strcmp(keyword, "Output") == 0) return parse_bin(value, &kdata->output, &kdata->output_len); @@ -1673,9 +2137,9 @@ static int kdf_test_parse(EVP_TEST *t, return 0; } -static int kdf_test_run(EVP_TEST *t) +static int pkey_kdf_test_run(EVP_TEST *t) { - KDF_DATA *expected = t->data; + PKEY_KDF_DATA *expected = t->data; unsigned char *got = NULL; size_t got_len = expected->output_len; @@ -1698,12 +2162,12 @@ static int kdf_test_run(EVP_TEST *t) return 1; } -static const EVP_TEST_METHOD kdf_test_method = { - "KDF", - kdf_test_init, - kdf_test_cleanup, - kdf_test_parse, - kdf_test_run +static const EVP_TEST_METHOD pkey_kdf_test_method = { + "PKEYKDF", + pkey_kdf_test_init, + pkey_kdf_test_cleanup, + pkey_kdf_test_parse, + pkey_kdf_test_run }; @@ -2079,11 +2543,12 @@ static int digestsign_test_run(EVP_TEST *t) t->err = "DIGESTSIGNFINAL_ERROR"; goto err; } - if (!TEST_mem_eq(expected->output, expected->output_len, got, got_len)) { - t->err = "SIGNATURE_MISMATCH"; + if (!memory_err_compare(t, "SIGNATURE_MISMATCH", + expected->output, expected->output_len, + got, got_len)) goto err; - } + t->err = NULL; err: OPENSSL_free(got); return 1; @@ -2156,11 +2621,12 @@ static int oneshot_digestsign_test_run(EVP_TEST *t) t->err = "DIGESTSIGN_ERROR"; goto err; } - if (!TEST_mem_eq(expected->output, expected->output_len, got, got_len)) { - t->err = "SIGNATURE_MISMATCH"; + if (!memory_err_compare(t, "SIGNATURE_MISMATCH", + expected->output, expected->output_len, + got, got_len)) goto err; - } + t->err = NULL; err: OPENSSL_free(got); return 1; @@ -2209,6 +2675,7 @@ static const EVP_TEST_METHOD *evp_test_list[] = { &digestverify_test_method, &encode_test_method, &kdf_test_method, + &pkey_kdf_test_method, &keypair_test_method, &keygen_test_method, &mac_test_method, @@ -2246,8 +2713,6 @@ static void clear_test(EVP_TEST *t) } OPENSSL_free(t->expected_err); t->expected_err = NULL; - OPENSSL_free(t->func); - t->func = NULL; OPENSSL_free(t->reason); t->reason = NULL; @@ -2290,10 +2755,10 @@ static int check_test_error(EVP_TEST *t) return 0; } - if (t->func == NULL && t->reason == NULL) + if (t->reason == NULL) return 1; - if (t->func == NULL || t->reason == NULL) { + if (t->reason == NULL) { TEST_info("%s:%d: Test is missing function or reason code", t->s.test_file, t->s.start); return 0; @@ -2301,25 +2766,25 @@ static int check_test_error(EVP_TEST *t) err = ERR_peek_error(); if (err == 0) { - TEST_info("%s:%d: Expected error \"%s:%s\" not set", - t->s.test_file, t->s.start, t->func, t->reason); + TEST_info("%s:%d: Expected error \"%s\" not set", + t->s.test_file, t->s.start, t->reason); return 0; } func = ERR_func_error_string(err); reason = ERR_reason_error_string(err); if (func == NULL && reason == NULL) { - TEST_info("%s:%d: Expected error \"%s:%s\", no strings available." + TEST_info("%s:%d: Expected error \"%s\", no strings available." " Assuming ok.", - t->s.test_file, t->s.start, t->func, t->reason); + t->s.test_file, t->s.start, t->reason); return 1; } - if (strcmp(func, t->func) == 0 && strcmp(reason, t->reason) == 0) + if (strcmp(reason, t->reason) == 0) return 1; - TEST_info("%s:%d: Expected error \"%s:%s\", got \"%s:%s\"", - t->s.test_file, t->s.start, t->func, t->reason, func, reason); + TEST_info("%s:%d: Expected error \"%s\", got \"%s\"", + t->s.test_file, t->s.start, t->reason, reason); return 0; } @@ -2378,7 +2843,7 @@ static void free_key_list(KEY_LIST *lst) /* * Is the key type an unsupported algorithm? */ -static int key_unsupported() +static int key_unsupported(void) { long err = ERR_peek_error(); @@ -2413,6 +2878,33 @@ static char *take_value(PAIR *pp) return p; } +/* + * Return 1 if one of the providers named in the string is available. + * The provider names are separated with whitespace. + * NOTE: destructive function, it inserts '\0' after each provider name. + */ +static int prov_available(char *providers) +{ + char *p; + int more = 1; + + while (more) { + for (; isspace(*providers); providers++) + continue; + if (*providers == '\0') + break; /* End of the road */ + for (p = providers; *p != '\0' && !isspace(*p); p++) + continue; + if (*p == '\0') + more = 0; + else + *p = '\0'; + if (OSSL_PROVIDER_available(NULL, providers)) + return 1; /* Found one */ + } + return 0; +} + /* * Read and parse one test. Return 0 if failure, 1 if okay. */ @@ -2439,6 +2931,7 @@ top: if (strcmp(pp->key, "PrivateKey") == 0) { pkey = PEM_read_bio_PrivateKey(t->s.key, NULL, 0, NULL); if (pkey == NULL && !key_unsupported()) { + EVP_PKEY_free(pkey); TEST_info("Can't read private key %s", pp->value); TEST_openssl_errors(); return 0; @@ -2447,6 +2940,7 @@ top: } else if (strcmp(pp->key, "PublicKey") == 0) { pkey = PEM_read_bio_PUBKEY(t->s.key, NULL, 0, NULL); if (pkey == NULL && !key_unsupported()) { + EVP_PKEY_free(pkey); TEST_info("Can't read public key %s", pp->value); TEST_openssl_errors(); return 0; @@ -2486,10 +2980,10 @@ top: return 0; } if (klist == &private_keys) - pkey = EVP_PKEY_new_private_key(nid, NULL, keybin, keylen); + pkey = EVP_PKEY_new_raw_private_key(nid, NULL, keybin, keylen); else - pkey = EVP_PKEY_new_public_key(nid, NULL, keybin, keylen); - if (pkey == NULL) { + pkey = EVP_PKEY_new_raw_public_key(nid, NULL, keybin, keylen); + if (pkey == NULL && !key_unsupported()) { TEST_info("Can't read %s data", pp->key); OPENSSL_free(keybin); TEST_openssl_errors(); @@ -2507,6 +3001,17 @@ top: if (!TEST_ptr(key = OPENSSL_malloc(sizeof(*key)))) return 0; key->name = take_value(pp); + + /* Hack to detect SM2 keys */ + if(pkey != NULL && strstr(key->name, "SM2") != NULL) { +#ifdef OPENSSL_NO_SM2 + EVP_PKEY_free(pkey); + pkey = NULL; +#else + EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2); +#endif + } + key->key = pkey; key->next = *klist; *klist = key; @@ -2530,18 +3035,21 @@ top: } for (pp++, i = 1; i < t->s.numpairs; pp++, i++) { - if (strcmp(pp->key, "Result") == 0) { + if (strcmp(pp->key, "Availablein") == 0) { + if (!prov_available(pp->value)) { + TEST_info("skipping, providers not available: %s:%d", + t->s.test_file, t->s.start); + t->skip = 1; + return 0; + } + } else if (strcmp(pp->key, "Result") == 0) { if (t->expected_err != NULL) { TEST_info("Line %d: multiple result lines", t->s.curr); return 0; } t->expected_err = take_value(pp); } else if (strcmp(pp->key, "Function") == 0) { - if (t->func != NULL) { - TEST_info("Line %d: multiple function lines\n", t->s.curr); - return 0; - } - t->func = take_value(pp); + /* Ignore old line. */ } else if (strcmp(pp->key, "Reason") == 0) { if (t->reason != NULL) { TEST_info("Line %d: multiple reason lines", t->s.curr); @@ -2557,8 +3065,8 @@ top: return 0; } if (rv < 0) { - TEST_info("Line %d: error processing keyword %s\n", - t->s.curr, pp->key); + TEST_info("Line %d: error processing keyword %s = %s\n", + t->s.curr, pp->key, pp->value); return 0; } } @@ -2582,8 +3090,10 @@ static int run_file_tests(int i) while (!BIO_eof(t->s.fp)) { c = parse(t); - if (t->skip) + if (t->skip) { + t->s.numskip++; continue; + } if (c == 0 || !run_test(t)) { t->s.errors++; break; @@ -2600,14 +3110,14 @@ static int run_file_tests(int i) return c == 0; } +OPT_TEST_DECLARE_USAGE("file...\n") + int setup_tests(void) { size_t n = test_get_argument_count(); - if (n == 0) { - TEST_error("Usage: %s file...", test_get_program_name()); + if (n == 0) return 0; - } ADD_ALL_TESTS(run_file_tests, n); return 1;