X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=test%2Fevp_test.c;h=14ea4a84966d2f912d9b021dfdb05ff4eac6fee9;hp=8bfa5da59b03f0c9496b6a8a621a4e653bea86fb;hb=7a810fac866c6c1d93015999633ee2a29f17b3d2;hpb=1f0fc03b8a21d139d4c5464106d5fd123c312469 diff --git a/test/evp_test.c b/test/evp_test.c index 8bfa5da59b..14ea4a8496 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-2020 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 @@ -11,22 +11,27 @@ #include #include #include +#include "../e_os.h" /* strcasecmp */ #include #include #include +#include #include #include #include +#include +#include #include "internal/numbers.h" +#include "internal/nelem.h" +#include "crypto/evp.h" #include "testutil.h" #include "evp_test.h" +#define AAD_NUM 4 typedef struct evp_test_method_st EVP_TEST_METHOD; -/* - * Structure holding test information - */ +/* Structure holding test information */ typedef struct evp_test_st { STANZA s; /* Common test stanza */ char *name; @@ -34,14 +39,11 @@ 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; -/* - * Test method structure - */ +/* Test method structure */ struct evp_test_method_st { /* Name of test as it appears in file */ const char *name; @@ -55,24 +57,55 @@ struct evp_test_method_st { int (*run_test) (EVP_TEST * t); }; - -/* - * Linked list of named keys. - */ +/* Linked list of named keys. */ typedef struct key_list_st { char *name; EVP_PKEY *key; struct key_list_st *next; } KEY_LIST; -/* - * List of public and private keys - */ +typedef enum OPTION_choice { + OPT_ERR = -1, + OPT_EOF = 0, + OPT_CONFIG_FILE, + OPT_TEST_ENUM +} OPTION_CHOICE; + +static OSSL_PROVIDER *prov_null = NULL; +static OPENSSL_CTX *libctx = NULL; + +/* List of public and private keys */ static KEY_LIST *private_keys; static KEY_LIST *public_keys; -static int find_key(EVP_PKEY **ppk, const char *name, KEY_LIST *lst); +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); +static int is_digest_disabled(const char *name); +static int is_pkey_disabled(const char *name); +static int is_mac_disabled(const char *name); +static int is_cipher_disabled(const char *name); +static int is_kdf_disabled(const char *name); + +/* + * 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 @@ -93,9 +126,7 @@ static void evp_test_buffer_free(EVP_TEST_BUFFER *db) } } -/* - * append buffer to a list - */ +/* append buffer to a list */ static int evp_test_buffer_append(const char *value, STACK_OF(EVP_TEST_BUFFER) **sk) { @@ -121,9 +152,7 @@ err: return 0; } -/* - * replace last buffer in list with copies of itself - */ +/* replace last buffer in list with copies of itself */ static int evp_test_buffer_ncopy(const char *value, STACK_OF(EVP_TEST_BUFFER) *sk) { @@ -151,9 +180,7 @@ static int evp_test_buffer_ncopy(const char *value, return 1; } -/* - * set repeat count for last buffer in list - */ +/* set repeat count for last buffer in list */ static int evp_test_buffer_set_count(const char *value, STACK_OF(EVP_TEST_BUFFER) *sk) { @@ -175,9 +202,7 @@ static int evp_test_buffer_set_count(const char *value, return 1; } -/* - * call "fn" with each element of the list in turn - */ +/* call "fn" with each element of the list in turn */ static int evp_test_buffer_do(STACK_OF(EVP_TEST_BUFFER) *sk, int (*fn)(void *ctx, const unsigned char *buf, @@ -292,38 +317,46 @@ static int parse_bin(const char *value, unsigned char **buf, size_t *buflen) return 1; } - /** -*** MESSAGE DIGEST TESTS -**/ + ** MESSAGE DIGEST TESTS + **/ typedef struct digest_data_st { /* Digest this test is for */ const EVP_MD *digest; + EVP_MD *fetched_digest; /* Input to digest */ STACK_OF(EVP_TEST_BUFFER) *input; /* Expected output */ unsigned char *output; size_t output_len; + /* Padding type */ + int pad_type; } DIGEST_DATA; static int digest_test_init(EVP_TEST *t, const char *alg) { DIGEST_DATA *mdat; const EVP_MD *digest; + EVP_MD *fetched_digest; - if ((digest = EVP_get_digestbyname(alg)) == NULL) { - /* If alg has an OID assume disabled algorithm */ - if (OBJ_sn2nid(alg) != NID_undef || OBJ_ln2nid(alg) != NID_undef) { - t->skip = 1; - return 1; - } - return 0; + if (is_digest_disabled(alg)) { + TEST_info("skipping, '%s' is disabled", alg); + t->skip = 1; + return 1; } + + if ((digest = fetched_digest = EVP_MD_fetch(libctx, alg, NULL)) == NULL + && (digest = EVP_get_digestbyname(alg)) == NULL) + return 0; if (!TEST_ptr(mdat = OPENSSL_zalloc(sizeof(*mdat)))) return 0; t->data = mdat; mdat->digest = digest; + mdat->fetched_digest = fetched_digest; + mdat->pad_type = 0; + if (fetched_digest != NULL) + TEST_info("%s is fetched", alg); return 1; } @@ -333,6 +366,7 @@ static void digest_test_cleanup(EVP_TEST *t) sk_EVP_TEST_BUFFER_pop_free(mdat->input, evp_test_buffer_free); OPENSSL_free(mdat->output); + EVP_MD_free(mdat->fetched_digest); } static int digest_test_parse(EVP_TEST *t, @@ -348,6 +382,8 @@ static int digest_test_parse(EVP_TEST *t, return evp_test_buffer_set_count(value, mdata->input); if (strcmp(keyword, "Ncopy") == 0) return evp_test_buffer_ncopy(value, mdata->input); + if (strcmp(keyword, "Padding") == 0) + return (mdata->pad_type = atoi(value)) > 0; return 0; } @@ -360,37 +396,84 @@ static int digest_test_run(EVP_TEST *t) { DIGEST_DATA *expected = t->data; EVP_MD_CTX *mctx; - unsigned char got[EVP_MAX_MD_SIZE]; + unsigned char *got = NULL; unsigned int got_len; + OSSL_PARAM params[2]; t->err = "TEST_FAILURE"; if (!TEST_ptr(mctx = EVP_MD_CTX_new())) goto err; + got = OPENSSL_malloc(expected->output_len > EVP_MAX_MD_SIZE ? + expected->output_len : EVP_MAX_MD_SIZE); + if (!TEST_ptr(got)) + goto err; + if (!EVP_DigestInit_ex(mctx, expected->digest, NULL)) { t->err = "DIGESTINIT_ERROR"; goto err; } + if (expected->pad_type > 0) { + params[0] = OSSL_PARAM_construct_int(OSSL_DIGEST_PARAM_PAD_TYPE, + &expected->pad_type); + params[1] = OSSL_PARAM_construct_end(); + if (!TEST_int_gt(EVP_MD_CTX_set_params(mctx, params), 0)) { + t->err = "PARAMS_ERROR"; + goto err; + } + } if (!evp_test_buffer_do(expected->input, digest_update_fn, mctx)) { t->err = "DIGESTUPDATE_ERROR"; goto err; } - if (!EVP_DigestFinal(mctx, got, &got_len)) { - t->err = "DIGESTFINAL_ERROR"; - goto err; + if (EVP_MD_flags(expected->digest) & EVP_MD_FLAG_XOF) { + EVP_MD_CTX *mctx_cpy; + char dont[] = "touch"; + + if (!TEST_ptr(mctx_cpy = EVP_MD_CTX_new())) { + goto err; + } + if (!EVP_MD_CTX_copy(mctx_cpy, mctx)) { + EVP_MD_CTX_free(mctx_cpy); + goto err; + } + if (!EVP_DigestFinalXOF(mctx_cpy, (unsigned char *)dont, 0)) { + EVP_MD_CTX_free(mctx_cpy); + t->err = "DIGESTFINALXOF_ERROR"; + goto err; + } + if (!TEST_str_eq(dont, "touch")) { + EVP_MD_CTX_free(mctx_cpy); + t->err = "DIGESTFINALXOF_ERROR"; + goto err; + } + EVP_MD_CTX_free(mctx_cpy); + + got_len = expected->output_len; + if (!EVP_DigestFinalXOF(mctx, got, got_len)) { + t->err = "DIGESTFINALXOF_ERROR"; + goto err; + } + } else { + if (!EVP_DigestFinal(mctx, got, &got_len)) { + t->err = "DIGESTFINAL_ERROR"; + goto err; + } } if (!TEST_int_eq(expected->output_len, got_len)) { 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: + OPENSSL_free(got); EVP_MD_CTX_free(mctx); return 1; } @@ -403,92 +486,135 @@ static const EVP_TEST_METHOD digest_test_method = { digest_test_run }; - /** *** CIPHER TESTS **/ typedef struct cipher_data_st { const EVP_CIPHER *cipher; + EVP_CIPHER *fetched_cipher; int enc; /* EVP_CIPH_GCM_MODE, EVP_CIPH_CCM_MODE or EVP_CIPH_OCB_MODE if AEAD */ int aead; unsigned char *key; size_t key_len; + size_t key_bits; /* Used by RC2 */ unsigned char *iv; + unsigned int rounds; size_t iv_len; unsigned char *plaintext; 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; + const char *cts_mode; size_t tag_len; + int tag_late; } CIPHER_DATA; static int cipher_test_init(EVP_TEST *t, const char *alg) { const EVP_CIPHER *cipher; + EVP_CIPHER *fetched_cipher; CIPHER_DATA *cdat; int m; - if ((cipher = EVP_get_cipherbyname(alg)) == NULL) { - /* If alg has an OID assume disabled algorithm */ - if (OBJ_sn2nid(alg) != NID_undef || OBJ_ln2nid(alg) != NID_undef) { - t->skip = 1; - return 1; - } - return 0; + if (is_cipher_disabled(alg)) { + t->skip = 1; + TEST_info("skipping, '%s' is disabled", alg); + return 1; } + + if ((cipher = fetched_cipher = EVP_CIPHER_fetch(libctx, alg, NULL)) == NULL + && (cipher = EVP_get_cipherbyname(alg)) == NULL) + return 0; + cdat = OPENSSL_zalloc(sizeof(*cdat)); cdat->cipher = cipher; + cdat->fetched_cipher = fetched_cipher; cdat->enc = -1; 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 cdat->aead = 0; t->data = cdat; + if (fetched_cipher != NULL) + TEST_info("%s is fetched", alg); return 1; } 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); + EVP_CIPHER_free(cdat->fetched_cipher); } 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); + if (strcmp(keyword, "Rounds") == 0) { + i = atoi(value); + if (i < 0) + return -1; + cdat->rounds = (unsigned int)i; + return 1; + } if (strcmp(keyword, "IV") == 0) return parse_bin(value, &cdat->iv, &cdat->iv_len); if (strcmp(keyword, "Plaintext") == 0) return parse_bin(value, &cdat->plaintext, &cdat->plaintext_len); if (strcmp(keyword, "Ciphertext") == 0) return parse_bin(value, &cdat->ciphertext, &cdat->ciphertext_len); + if (strcmp(keyword, "KeyBits") == 0) { + i = atoi(value); + if (i < 0) + return -1; + cdat->key_bits = (size_t)i; + return 1; + } 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 -1; + } 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 -1; + return 1; + } } if (strcmp(keyword, "Operation") == 0) { @@ -497,7 +623,11 @@ static int cipher_test_parse(EVP_TEST *t, const char *keyword, else if (strcmp(value, "DECRYPT") == 0) cdat->enc = 0; else - return 0; + return -1; + return 1; + } + if (strcmp(keyword, "CTSMode") == 0) { + cdat->cts_mode = value; return 1; } return 0; @@ -509,13 +639,16 @@ 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_base = NULL; EVP_CIPHER_CTX *ctx = NULL; t->err = "TEST_FAILURE"; + if (!TEST_ptr(ctx_base = EVP_CIPHER_CTX_new())) + goto err; if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())) goto err; - EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + EVP_CIPHER_CTX_set_flags(ctx_base, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); if (enc) { in = expected->plaintext; in_len = expected->plaintext_len; @@ -528,9 +661,7 @@ static int cipher_test_enc(EVP_TEST *t, int enc, out_len = expected->plaintext_len; } if (inp_misalign == (size_t)-1) { - /* - * Exercise in-place encryption - */ + /* Exercise in-place encryption */ tmp = OPENSSL_malloc(out_misalign + in_len + 2 * EVP_MAX_BLOCK_LENGTH); if (!tmp) goto err; @@ -552,18 +683,30 @@ static int cipher_test_enc(EVP_TEST *t, int enc, in = memcpy(tmp + out_misalign + in_len + 2 * EVP_MAX_BLOCK_LENGTH + inp_misalign, in, in_len); } - if (!EVP_CipherInit_ex(ctx, expected->cipher, NULL, NULL, NULL, enc)) { + if (!EVP_CipherInit_ex(ctx_base, expected->cipher, NULL, NULL, NULL, enc)) { t->err = "CIPHERINIT_ERROR"; goto err; } + if (expected->cts_mode != NULL) { + OSSL_PARAM params[2]; + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, + (char *)expected->cts_mode, + 0); + params[1] = OSSL_PARAM_construct_end(); + if (!EVP_CIPHER_CTX_set_params(ctx_base, params)) { + t->err = "INVALID_CTS_MODE"; + goto err; + } + } if (expected->iv) { if (expected->aead) { - if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, + if (!EVP_CIPHER_CTX_ctrl(ctx_base, EVP_CTRL_AEAD_SET_IVLEN, expected->iv_len, 0)) { t->err = "INVALID_IV_LENGTH"; goto err; } - } else if (expected->iv_len != (size_t)EVP_CIPHER_CTX_iv_length(ctx)) { + } else if (expected->iv_len != (size_t)EVP_CIPHER_CTX_iv_length(ctx_base)) { t->err = "INVALID_IV_LENGTH"; goto err; } @@ -574,7 +717,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 { @@ -582,63 +725,107 @@ static int cipher_test_enc(EVP_TEST *t, int enc, tag = expected->tag; } if (tag || expected->aead != EVP_CIPH_GCM_MODE) { - if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + if (!EVP_CIPHER_CTX_ctrl(ctx_base, EVP_CTRL_AEAD_SET_TAG, expected->tag_len, tag)) goto err; } } - if (!EVP_CIPHER_CTX_set_key_length(ctx, expected->key_len)) { + if (expected->rounds > 0) { + int rounds = (int)expected->rounds; + + if (!EVP_CIPHER_CTX_ctrl(ctx_base, EVP_CTRL_SET_RC5_ROUNDS, rounds, NULL)) { + t->err = "INVALID_ROUNDS"; + goto err; + } + } + + if (!EVP_CIPHER_CTX_set_key_length(ctx_base, expected->key_len)) { t->err = "INVALID_KEY_LENGTH"; goto err; } - if (!EVP_CipherInit_ex(ctx, NULL, NULL, expected->key, expected->iv, -1)) { + if (expected->key_bits > 0) { + int bits = (int)expected->key_bits; + + if (!EVP_CIPHER_CTX_ctrl(ctx_base, EVP_CTRL_SET_RC2_KEY_BITS, bits, NULL)) { + t->err = "INVALID KEY BITS"; + goto err; + } + } + if (!EVP_CipherInit_ex(ctx_base, NULL, NULL, expected->key, expected->iv, -1)) { 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"; + /* Check that we get the same IV back */ + if (expected->iv != NULL) { + /* Some (e.g., GCM) tests use IVs longer than EVP_MAX_IV_LENGTH. */ + unsigned char iv[128]; + if (!TEST_true(EVP_CIPHER_CTX_get_iv_state(ctx_base, iv, sizeof(iv))) + || ((EVP_CIPHER_flags(expected->cipher) & EVP_CIPH_CUSTOM_IV) == 0 + && !TEST_mem_eq(expected->iv, expected->iv_len, iv, + expected->iv_len))) { + t->err = "INVALID_IV"; goto err; } } + /* Test that the cipher dup functions correctly if it is supported */ + if (EVP_CIPHER_CTX_copy(ctx, ctx_base)) { + EVP_CIPHER_CTX_free(ctx_base); + ctx_base = NULL; + } else { + EVP_CIPHER_CTX_free(ctx); + ctx = ctx_base; + } + if (expected->aead == EVP_CIPH_CCM_MODE) { if (!EVP_CipherUpdate(ctx, NULL, &tmplen, NULL, out_len)) { t->err = "CCM_PLAINTEXT_LENGTH_SET_ERROR"; 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; @@ -674,11 +861,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]; @@ -691,16 +876,17 @@ 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; err: OPENSSL_free(tmp); + if (ctx != ctx_base) + EVP_CIPHER_CTX_free(ctx_base); EVP_CIPHER_CTX_free(ctx); return ok; } @@ -765,10 +951,12 @@ 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_flags(cdat->cipher) & EVP_CIPH_FLAG_CTS) != 0) + || 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; @@ -793,68 +981,100 @@ static const EVP_TEST_METHOD cipher_test_method = { /** -*** MAC TESTS -**/ + ** MAC TESTS + **/ typedef struct mac_data_st { - /* MAC type */ - int type; + /* MAC type in one form or another */ + char *mac_name; + 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) { -#ifndef OPENSSL_NO_CMAC - type = EVP_PKEY_CMAC; -#else - t->skip = 1; - return 1; -#endif - } else if (strcmp(alg, "Poly1305") == 0) { -#ifndef OPENSSL_NO_POLY1305 - type = EVP_PKEY_POLY1305; -#else - t->skip = 1; - return 1; -#endif - } else if (strcmp(alg, "SipHash") == 0) { -#ifndef OPENSSL_NO_SIPHASH - type = EVP_PKEY_SIPHASH; -#else + if (is_mac_disabled(alg)) { + TEST_info("skipping, '%s' is disabled", alg); t->skip = 1; return 1; -#endif - } else - return 0; + } + if ((mac = EVP_MAC_fetch(libctx, 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) + type = EVP_PKEY_CMAC; + else if (strncmp(alg, "Poly1305", sz) == 0) + type = EVP_PKEY_POLY1305; + else if (strncmp(alg, "SipHash", sz) == 0) + type = EVP_PKEY_SIPHASH; + else + return 0; + } mdat = OPENSSL_zalloc(sizeof(*mdat)); mdat->type = type; + mdat->mac_name = OPENSSL_strdup(alg); + 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); + OPENSSL_free(mdat->mac_name); + 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); } @@ -866,77 +1086,118 @@ 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) - return 0; + return -1; return 1; } if (strcmp(keyword, "Input") == 0) 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; EVP_PKEY_CTX *pctx = NULL, *genctx = NULL; EVP_PKEY *key = NULL; - const EVP_MD *md = NULL; + const char *mdname = NULL; + EVP_CIPHER *cipher = NULL; unsigned char *got = NULL; size_t got_len; + int i; -#ifdef OPENSSL_NO_DES - if (expected->alg != NULL && strstr(expected->alg, "DES") != NULL) { - /* Skip DES */ - t->err = NULL; - goto err; - } -#endif - - if (!TEST_ptr(genctx = EVP_PKEY_CTX_new_id(expected->type, NULL))) { - t->err = "MAC_PKEY_CTX_ERROR"; - goto err; - } + 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); - if (EVP_PKEY_keygen_init(genctx) <= 0) { - t->err = "MAC_KEYGEN_INIT_ERROR"; - goto err; - } - if (expected->type == EVP_PKEY_CMAC - && EVP_PKEY_CTX_ctrl_str(genctx, "cipher", expected->alg) <= 0) { - t->err = "MAC_ALGORITHM_SET_ERROR"; - goto err; + if (expected->type == EVP_PKEY_CMAC) { + if (expected->alg != NULL && is_cipher_disabled(expected->alg)) { + TEST_info("skipping, PKEY CMAC '%s' is disabled", expected->alg); + t->skip = 1; + t->err = NULL; + goto err; + } + if (!TEST_ptr(cipher = EVP_CIPHER_fetch(libctx, expected->alg, NULL))) { + t->err = "MAC_KEY_CREATE_ERROR"; + goto err; + } + key = EVP_PKEY_new_CMAC_key_with_libctx(expected->key, + expected->key_len, + EVP_CIPHER_name(cipher), + libctx, NULL); + } else { + key = EVP_PKEY_new_raw_private_key_with_libctx(libctx, + OBJ_nid2sn(expected->type), + NULL, expected->key, + expected->key_len); } - - if (EVP_PKEY_CTX_set_mac_key(genctx, expected->key, - expected->key_len) <= 0) { - t->err = "MAC_KEY_SET_ERROR"; + if (key == NULL) { + t->err = "MAC_KEY_CREATE_ERROR"; goto err; } - if (EVP_PKEY_keygen(genctx, &key) <= 0) { - t->err = "MAC_KEY_GENERATE_ERROR"; - goto err; - } - if (expected->type == EVP_PKEY_HMAC) { - if (!TEST_ptr(md = EVP_get_digestbyname(expected->alg))) { - t->err = "MAC_ALGORITHM_SET_ERROR"; + if (expected->type == EVP_PKEY_HMAC && expected->alg != NULL) { + if (is_digest_disabled(expected->alg)) { + TEST_info("skipping, HMAC '%s' is disabled", expected->alg); + t->skip = 1; + t->err = NULL; goto err; } + mdname = expected->alg; } if (!TEST_ptr(mctx = EVP_MD_CTX_new())) { t->err = "INTERNAL_ERROR"; goto err; } - if (!EVP_DigestSignInit(mctx, &pctx, md, NULL, key)) { + if (!EVP_DigestSignInit_with_libctx(mctx, &pctx, mdname, libctx, NULL, key)) { 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,13 +1211,15 @@ 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; } t->err = NULL; err: + EVP_CIPHER_free(cipher); EVP_MD_CTX_free(mctx); OPENSSL_free(got); EVP_PKEY_CTX_free(genctx); @@ -964,6 +1227,152 @@ 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_settable_ctx_params(expected->mac); + + if (expected->alg == NULL) + TEST_info("Trying the EVP_MAC %s test", expected->mac_name); + else + TEST_info("Trying the EVP_MAC %s test with %s", + expected->mac_name, expected->alg); + + if (expected->alg != NULL) { + /* + * The underlying algorithm may be a cipher or a digest. + * We don't know which it is, but we can ask the MAC what it + * should be and bet on that. + */ + if (OSSL_PARAM_locate_const(defined_params, + OSSL_MAC_PARAM_CIPHER) != NULL) { + params[params_n++] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, + expected->alg, 0); + } else if (OSSL_PARAM_locate_const(defined_params, + OSSL_MAC_PARAM_DIGEST) != NULL) { + params[params_n++] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, + expected->alg, 0); + } else { + t->err = "MAC_BAD_PARAMS"; + goto err; + } + } + 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 recognizes */ + 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 (tmpval == NULL + || !OSSL_PARAM_allocate_from_text(¶ms[params_n], + defined_params, + tmpkey, tmpval, + strlen(tmpval), NULL)) { + 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, @@ -974,9 +1383,9 @@ static const EVP_TEST_METHOD mac_test_method = { /** -*** PUBLIC KEY TESTS -*** These are all very similar and share much common code. -**/ + ** PUBLIC KEY TESTS + ** These are all very similar and share much common code. + **/ typedef struct pkey_data_st { /* Context for this operation */ @@ -1014,6 +1423,7 @@ static int pkey_test_init(EVP_TEST *t, const char *name, if (rv == 0) rv = find_key(&pkey, name, private_keys); if (rv == 0 || pkey == NULL) { + TEST_info("skipping, key '%s' is disabled", name); t->skip = 1; return 1; } @@ -1023,7 +1433,7 @@ static int pkey_test_init(EVP_TEST *t, const char *name, return 0; } kdata->keyop = keyop; - if (!TEST_ptr(kdata->ctx = EVP_PKEY_CTX_new(pkey, NULL))) { + if (!TEST_ptr(kdata->ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, NULL))) { EVP_PKEY_free(pkey); OPENSSL_free(kdata); return 0; @@ -1059,14 +1469,8 @@ static int pkey_test_ctrl(EVP_TEST *t, EVP_PKEY_CTX *pctx, t->err = "PKEY_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) { + if (is_digest_disabled(p) || is_cipher_disabled(p)) { + TEST_info("skipping, '%s' is disabled", p); t->skip = 1; rv = 1; } else { @@ -1096,6 +1500,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 +1513,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; } @@ -1182,7 +1613,6 @@ static const EVP_TEST_METHOD pverify_test_method = { verify_test_run }; - static int pderive_test_init(EVP_TEST *t, const char *name) { return pkey_test_init(t, name, 0, EVP_PKEY_derive_init, 0); @@ -1196,9 +1626,12 @@ static int pderive_test_parse(EVP_TEST *t, if (strcmp(keyword, "PeerKey") == 0) { EVP_PKEY *peer; if (find_key(&peer, value, public_keys) == 0) - return 0; - if (EVP_PKEY_derive_set_peer(kdata->ctx, peer) <= 0) - return 0; + return -1; + if (EVP_PKEY_derive_set_peer(kdata->ctx, peer) <= 0) { + t->err = "DERIVE_SET_PEER_ERROR"; + return 1; + } + t->err = NULL; return 1; } if (strcmp(keyword, "SharedSecret") == 0) @@ -1214,7 +1647,10 @@ static int pderive_test_run(EVP_TEST *t) unsigned char *got = NULL; size_t got_len; - got_len = expected->output_len; + if (EVP_PKEY_derive(expected->ctx, NULL, &got_len) <= 0) { + t->err = "DERIVE_ERROR"; + goto err; + } if (!TEST_ptr(got = OPENSSL_malloc(got_len))) { t->err = "DERIVE_ERROR"; goto err; @@ -1223,10 +1659,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: @@ -1244,8 +1680,8 @@ static const EVP_TEST_METHOD pderive_test_method = { /** -*** PBE TESTS -**/ + ** PBE TESTS + **/ typedef enum pbe_type_enum { PBE_TYPE_INVALID = 0, @@ -1271,9 +1707,7 @@ typedef struct pbe_data_st { } PBE_DATA; #ifndef OPENSSL_NO_SCRYPT -/* - * Parse unsigned decimal 64 bit integer value - */ +/* Parse unsigned decimal 64 bit integer value */ static int parse_uint64(const char *value, uint64_t *pr) { const char *p = value; @@ -1288,7 +1722,7 @@ static int parse_uint64(const char *value, uint64_t *pr) return -1; } *pr *= 10; - if (!TEST_true(isdigit(*p))) { + if (!TEST_true(isdigit((unsigned char)*p))) { TEST_error("Invalid character in string %s", value); return -1; } @@ -1354,13 +1788,13 @@ static int pbe_test_init(EVP_TEST *t, const char *alg) PBE_DATA *pdat; PBE_TYPE pbe_type = PBE_TYPE_INVALID; - if (strcmp(alg, "scrypt") == 0) { -#ifndef OPENSSL_NO_SCRYPT - pbe_type = PBE_TYPE_SCRYPT; -#else + if (is_kdf_disabled(alg)) { + TEST_info("skipping, '%s' is disabled", alg); t->skip = 1; return 1; -#endif + } + if (strcmp(alg, "scrypt") == 0) { + pbe_type = PBE_TYPE_SCRYPT; } else if (strcmp(alg, "pbkdf2") == 0) { pbe_type = PBE_TYPE_PBKDF2; } else if (strcmp(alg, "pkcs12") == 0) { @@ -1409,6 +1843,10 @@ static int pbe_test_run(EVP_TEST *t) { PBE_DATA *expected = t->data; unsigned char *key; + EVP_MD *fetched_digest = NULL; + OPENSSL_CTX *save_libctx; + + save_libctx = OPENSSL_CTX_set0_default(libctx); if (!TEST_ptr(key = OPENSSL_malloc(expected->key_len))) { t->err = "INTERNAL_ERROR"; @@ -1425,30 +1863,36 @@ static int pbe_test_run(EVP_TEST *t) #ifndef OPENSSL_NO_SCRYPT } else if (expected->pbe_type == PBE_TYPE_SCRYPT) { if (EVP_PBE_scrypt((const char *)expected->pass, expected->pass_len, - expected->salt, expected->salt_len, expected->N, - expected->r, expected->p, expected->maxmem, - key, expected->key_len) == 0) { + expected->salt, expected->salt_len, + expected->N, expected->r, expected->p, + expected->maxmem, key, expected->key_len) == 0) { t->err = "SCRYPT_ERROR"; goto err; } #endif } else if (expected->pbe_type == PBE_TYPE_PKCS12) { + fetched_digest = EVP_MD_fetch(libctx, EVP_MD_name(expected->md), NULL); + if (fetched_digest == NULL) { + t->err = "PKCS12_ERROR"; + goto err; + } if (PKCS12_key_gen_uni(expected->pass, expected->pass_len, expected->salt, expected->salt_len, expected->id, expected->iter, expected->key_len, - key, expected->md) == 0) { + key, fetched_digest) == 0) { t->err = "PKCS12_ERROR"; 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: + EVP_MD_free(fetched_digest); OPENSSL_free(key); + OPENSSL_CTX_set0_default(save_libctx); return 1; } @@ -1462,8 +1906,8 @@ static const EVP_TEST_METHOD pbe_test_method = { /** -*** BASE64 TESTS -**/ + ** BASE64 TESTS + **/ typedef enum { BASE64_CANONICAL_ENCODING = 0, @@ -1494,15 +1938,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) @@ -1531,7 +1978,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"; @@ -1539,7 +1986,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 = @@ -1547,110 +1993,551 @@ 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 (!memory_err_compare(t, "BAD_ENCODING", + expected->output, expected->output_len, + encode_out, output_len)) + goto err; + } + + if (!TEST_ptr(decode_out = + OPENSSL_malloc(EVP_DECODE_LENGTH(expected->output_len)))) + goto err; + + EVP_DecodeInit(decode_ctx); + if (EVP_DecodeUpdate(decode_ctx, decode_out, &chunk_len, expected->output, + expected->output_len) < 0) { + t->err = "DECODE_ERROR"; + goto err; + } + output_len = chunk_len; + + if (EVP_DecodeFinal(decode_ctx, decode_out + chunk_len, &chunk_len) != 1) { + t->err = "DECODE_ERROR"; + goto err; + } + output_len += chunk_len; + + if (expected->encoding != BASE64_INVALID_ENCODING + && !memory_err_compare(t, "BAD_DECODING", + expected->input, expected->input_len, + decode_out, output_len)) { + t->err = "BAD_DECODING"; + goto err; + } - if (!TEST_mem_eq(expected->output, expected->output_len, - encode_out, output_len)) { - t->err = "BAD_ENCODING"; + t->err = NULL; + err: + OPENSSL_free(encode_out); + OPENSSL_free(decode_out); + EVP_ENCODE_CTX_free(decode_ctx); + EVP_ENCODE_CTX_free(encode_ctx); + return 1; +} + +static const EVP_TEST_METHOD encode_test_method = { + "Encoding", + encode_test_init, + encode_test_cleanup, + encode_test_parse, + encode_test_run, +}; + + +/** + ** RAND TESTS + **/ +#define MAX_RAND_REPEATS 15 + +typedef struct rand_data_pass_st { + unsigned char *entropy; + unsigned char *reseed_entropy; + unsigned char *nonce; + unsigned char *pers; + unsigned char *reseed_addin; + unsigned char *addinA; + unsigned char *addinB; + unsigned char *pr_entropyA; + unsigned char *pr_entropyB; + unsigned char *output; + size_t entropy_len, nonce_len, pers_len, addinA_len, addinB_len, + pr_entropyA_len, pr_entropyB_len, output_len, reseed_entropy_len, + reseed_addin_len; +} RAND_DATA_PASS; + +typedef struct rand_data_st { + /* Context for this operation */ + EVP_RAND_CTX *ctx; + EVP_RAND_CTX *parent; + int n; + int prediction_resistance; + int use_df; + unsigned int generate_bits; + char *cipher; + char *digest; + + /* Expected output */ + RAND_DATA_PASS data[MAX_RAND_REPEATS]; +} RAND_DATA; + +static int rand_test_init(EVP_TEST *t, const char *name) +{ + RAND_DATA *rdata; + EVP_RAND *rand; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + unsigned int strength = 256; + + if (!TEST_ptr(rdata = OPENSSL_zalloc(sizeof(*rdata)))) + return 0; + + /* TEST-RAND is available in the FIPS provider but not with "fips=yes" */ + rand = EVP_RAND_fetch(libctx, "TEST-RAND", "-fips"); + if (rand == NULL) + goto err; + rdata->parent = EVP_RAND_CTX_new(rand, NULL); + EVP_RAND_free(rand); + if (rdata->parent == NULL) + goto err; + + *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, &strength); + if (!EVP_RAND_set_ctx_params(rdata->parent, params)) + goto err; + + rand = EVP_RAND_fetch(libctx, name, NULL); + if (rand == NULL) + goto err; + rdata->ctx = EVP_RAND_CTX_new(rand, rdata->parent); + EVP_RAND_free(rand); + if (rdata->ctx == NULL) + goto err; + + rdata->n = -1; + t->data = rdata; + return 1; + err: + EVP_RAND_CTX_free(rdata->parent); + OPENSSL_free(rdata); + return 0; +} + +static void rand_test_cleanup(EVP_TEST *t) +{ + RAND_DATA *rdata = t->data; + int i; + + OPENSSL_free(rdata->cipher); + OPENSSL_free(rdata->digest); + + for (i = 0; i <= rdata->n; i++) { + OPENSSL_free(rdata->data[i].entropy); + OPENSSL_free(rdata->data[i].reseed_entropy); + OPENSSL_free(rdata->data[i].nonce); + OPENSSL_free(rdata->data[i].pers); + OPENSSL_free(rdata->data[i].reseed_addin); + OPENSSL_free(rdata->data[i].addinA); + OPENSSL_free(rdata->data[i].addinB); + OPENSSL_free(rdata->data[i].pr_entropyA); + OPENSSL_free(rdata->data[i].pr_entropyB); + OPENSSL_free(rdata->data[i].output); + } + EVP_RAND_CTX_free(rdata->ctx); + EVP_RAND_CTX_free(rdata->parent); +} + +static int rand_test_parse(EVP_TEST *t, + const char *keyword, const char *value) +{ + RAND_DATA *rdata = t->data; + RAND_DATA_PASS *item; + const char *p; + int n; + + if ((p = strchr(keyword, '.')) != NULL) { + n = atoi(++p); + if (n >= MAX_RAND_REPEATS) + return 0; + if (n > rdata->n) + rdata->n = n; + item = rdata->data + n; + if (strncmp(keyword, "Entropy.", sizeof("Entropy")) == 0) + return parse_bin(value, &item->entropy, &item->entropy_len); + if (strncmp(keyword, "ReseedEntropy.", sizeof("ReseedEntropy")) == 0) + return parse_bin(value, &item->reseed_entropy, + &item->reseed_entropy_len); + if (strncmp(keyword, "Nonce.", sizeof("Nonce")) == 0) + return parse_bin(value, &item->nonce, &item->nonce_len); + if (strncmp(keyword, "PersonalisationString.", + sizeof("PersonalisationString")) == 0) + return parse_bin(value, &item->pers, &item->pers_len); + if (strncmp(keyword, "ReseedAdditionalInput.", + sizeof("ReseedAdditionalInput")) == 0) + return parse_bin(value, &item->reseed_addin, + &item->reseed_addin_len); + if (strncmp(keyword, "AdditionalInputA.", + sizeof("AdditionalInputA")) == 0) + return parse_bin(value, &item->addinA, &item->addinA_len); + if (strncmp(keyword, "AdditionalInputB.", + sizeof("AdditionalInputB")) == 0) + return parse_bin(value, &item->addinB, &item->addinB_len); + if (strncmp(keyword, "EntropyPredictionResistanceA.", + sizeof("EntropyPredictionResistanceA")) == 0) + return parse_bin(value, &item->pr_entropyA, &item->pr_entropyA_len); + if (strncmp(keyword, "EntropyPredictionResistanceB.", + sizeof("EntropyPredictionResistanceB")) == 0) + return parse_bin(value, &item->pr_entropyB, &item->pr_entropyB_len); + if (strncmp(keyword, "Output.", sizeof("Output")) == 0) + return parse_bin(value, &item->output, &item->output_len); + } else { + if (strcmp(keyword, "Cipher") == 0) + return TEST_ptr(rdata->cipher = OPENSSL_strdup(value)); + if (strcmp(keyword, "Digest") == 0) + return TEST_ptr(rdata->digest = OPENSSL_strdup(value)); + if (strcmp(keyword, "DerivationFunction") == 0) { + rdata->use_df = atoi(value) != 0; + return 1; + } + if (strcmp(keyword, "GenerateBits") == 0) { + if ((n = atoi(value)) <= 0 || n % 8 != 0) + return 0; + rdata->generate_bits = (unsigned int)n; + return 1; + } + if (strcmp(keyword, "PredictionResistance") == 0) { + rdata->prediction_resistance = atoi(value) != 0; + return 1; + } + } + return 0; +} + +static int rand_test_run(EVP_TEST *t) +{ + RAND_DATA *expected = t->data; + RAND_DATA_PASS *item; + unsigned char *got; + size_t got_len = expected->generate_bits / 8; + OSSL_PARAM params[5], *p = params; + int i = -1, ret = 0; + unsigned int strength; + unsigned char *z; + + if (!TEST_ptr(got = OPENSSL_malloc(got_len))) + return 0; + + *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_USE_DF, &expected->use_df); + if (expected->cipher != NULL) + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, + expected->cipher, 0); + if (expected->digest != NULL) + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, + expected->digest, 0); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_MAC, "HMAC", 0); + *p = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_RAND_set_ctx_params(expected->ctx, params))) + goto err; + + strength = EVP_RAND_strength(expected->ctx); + for (i = 0; i <= expected->n; i++) { + item = expected->data + i; + + p = params; + z = item->entropy != NULL ? item->entropy : (unsigned char *)""; + *p++ = OSSL_PARAM_construct_octet_string(OSSL_RAND_PARAM_TEST_ENTROPY, + z, item->entropy_len); + z = item->nonce != NULL ? item->nonce : (unsigned char *)""; + *p++ = OSSL_PARAM_construct_octet_string(OSSL_RAND_PARAM_TEST_NONCE, + z, item->nonce_len); + *p = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_RAND_set_ctx_params(expected->parent, params)) + || !TEST_true(EVP_RAND_instantiate(expected->parent, strength, + 0, NULL, 0))) goto err; + + z = item->pers != NULL ? item->pers : (unsigned char *)""; + if (!TEST_true(EVP_RAND_instantiate + (expected->ctx, strength, + expected->prediction_resistance, z, + item->pers_len))) + goto err; + + if (item->reseed_entropy != NULL) { + params[0] = OSSL_PARAM_construct_octet_string + (OSSL_RAND_PARAM_TEST_ENTROPY, item->reseed_entropy, + item->reseed_entropy_len); + params[1] = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_RAND_set_ctx_params(expected->parent, params))) + goto err; + + if (!TEST_true(EVP_RAND_reseed + (expected->ctx, expected->prediction_resistance, + NULL, 0, item->reseed_addin, + item->reseed_addin_len))) + goto err; + } + if (item->pr_entropyA != NULL) { + params[0] = OSSL_PARAM_construct_octet_string + (OSSL_RAND_PARAM_TEST_ENTROPY, item->pr_entropyA, + item->pr_entropyA_len); + params[1] = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_RAND_set_ctx_params(expected->parent, params))) + goto err; + } + if (!TEST_true(EVP_RAND_generate + (expected->ctx, got, got_len, + strength, expected->prediction_resistance, + item->addinA, item->addinA_len))) + goto err; + + if (item->pr_entropyB != NULL) { + params[0] = OSSL_PARAM_construct_octet_string + (OSSL_RAND_PARAM_TEST_ENTROPY, item->pr_entropyB, + item->pr_entropyB_len); + params[1] = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_RAND_set_ctx_params(expected->parent, params))) + return 0; + } + if (!TEST_true(EVP_RAND_generate + (expected->ctx, got, got_len, + strength, expected->prediction_resistance, + item->addinB, item->addinB_len))) + goto err; + if (!TEST_mem_eq(got, got_len, item->output, item->output_len)) + goto err; + if (!TEST_true(EVP_RAND_uninstantiate(expected->ctx)) + || !TEST_true(EVP_RAND_uninstantiate(expected->parent)) + || !TEST_true(EVP_RAND_verify_zeroization(expected->ctx)) + || !TEST_int_eq(EVP_RAND_state(expected->ctx), + EVP_RAND_STATE_UNINITIALISED)) + goto err; + } + t->err = NULL; + ret = 1; + + err: + if (ret == 0 && i >= 0) + TEST_info("Error in test case %d of %d\n", i, expected->n + 1); + OPENSSL_free(got); + return ret; +} + +static const EVP_TEST_METHOD rand_test_method = { + "RAND", + rand_test_init, + rand_test_cleanup, + rand_test_parse, + rand_test_run +}; + + +/** + ** KDF TESTS + **/ +typedef struct kdf_data_st { + /* Context for this operation */ + EVP_KDF_CTX *ctx; + /* Expected output */ + unsigned char *output; + size_t output_len; + OSSL_PARAM params[20]; + OSSL_PARAM *p; +} KDF_DATA; + +/* + * Perform public key operation setup: lookup key, allocated ctx and call + * the appropriate initialisation function + */ +static int kdf_test_init(EVP_TEST *t, const char *name) +{ + KDF_DATA *kdata; + EVP_KDF *kdf; + + if (is_kdf_disabled(name)) { + TEST_info("skipping, '%s' is disabled", name); + t->skip = 1; + return 1; + } + + if (!TEST_ptr(kdata = OPENSSL_zalloc(sizeof(*kdata)))) + return 0; + kdata->p = kdata->params; + *kdata->p = OSSL_PARAM_construct_end(); + + kdf = EVP_KDF_fetch(libctx, name, NULL); + if (kdf == NULL) { + OPENSSL_free(kdata); + return 0; + } + kdata->ctx = EVP_KDF_CTX_new(kdf); + EVP_KDF_free(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; + OSSL_PARAM *p; + + for (p = kdata->params; p->key != NULL; p++) + OPENSSL_free(p->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) +{ + KDF_DATA *kdata = t->data; + int rv; + char *p, *name; + const OSSL_PARAM *defs = EVP_KDF_settable_ctx_params(EVP_KDF_CTX_kdf(kctx)); + + if (!TEST_ptr(name = OPENSSL_strdup(value))) + return 0; + p = strchr(name, ':'); + if (p != NULL) + *p++ = '\0'; + + rv = OSSL_PARAM_allocate_from_text(kdata->p, defs, name, p, + p != NULL ? strlen(p) : 0, NULL); + *++kdata->p = OSSL_PARAM_construct_end(); + if (!rv) { + t->err = "KDF_PARAM_ERROR"; + OPENSSL_free(name); + return 0; + } + if (p != NULL && strcmp(name, "digest") == 0) { + if (is_digest_disabled(p)) { + TEST_info("skipping, '%s' is disabled", p); + t->skip = 1; } } + if (p != NULL && strcmp(name, "cipher") == 0) { + if (is_cipher_disabled(p)) { + TEST_info("skipping, '%s' is disabled", p); + t->skip = 1; + } + } + OPENSSL_free(name); + return 1; +} + +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; +} - if (!TEST_ptr(decode_out = - OPENSSL_malloc(EVP_DECODE_LENGTH(expected->output_len)))) - goto err; +static int kdf_test_run(EVP_TEST *t) +{ + KDF_DATA *expected = t->data; + unsigned char *got = NULL; + size_t got_len = expected->output_len; - EVP_DecodeInit(decode_ctx); - if (EVP_DecodeUpdate(decode_ctx, decode_out, &chunk_len, expected->output, - expected->output_len) < 0) { - t->err = "DECODE_ERROR"; - goto err; + if (!EVP_KDF_CTX_set_params(expected->ctx, expected->params)) { + t->err = "KDF_CTRL_ERROR"; + return 1; } - output_len = chunk_len; - - if (EVP_DecodeFinal(decode_ctx, decode_out + chunk_len, &chunk_len) != 1) { - t->err = "DECODE_ERROR"; + if (!TEST_ptr(got = OPENSSL_malloc(got_len))) { + t->err = "INTERNAL_ERROR"; goto err; } - output_len += chunk_len; - - if (expected->encoding != BASE64_INVALID_ENCODING - && !TEST_mem_eq(expected->input, expected->input_len, - decode_out, output_len)) { - t->err = "BAD_DECODING"; + 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(encode_out); - OPENSSL_free(decode_out); - EVP_ENCODE_CTX_free(decode_ctx); + OPENSSL_free(got); return 1; } -static const EVP_TEST_METHOD encode_test_method = { - "Encoding", - encode_test_init, - encode_test_cleanup, - encode_test_parse, - encode_test_run, +static const EVP_TEST_METHOD kdf_test_method = { + "KDF", + kdf_test_init, + kdf_test_cleanup, + kdf_test_parse, + kdf_test_run }; /** -*** KDF TESTS -**/ + ** PKEY KDF TESTS + **/ -typedef struct kdf_data_st { +typedef struct pkey_kdf_data_st { /* Context for this operation */ EVP_PKEY_CTX *ctx; /* Expected output */ unsigned char *output; size_t output_len; -} KDF_DATA; +} PKEY_KDF_DATA; /* * Perform public key operation setup: lookup key, allocated ctx and call * the appropriate initialisation function */ -static int kdf_test_init(EVP_TEST *t, const char *name) +static int pkey_kdf_test_init(EVP_TEST *t, const char *name) { - KDF_DATA *kdata; + PKEY_KDF_DATA *kdata = NULL; - if (!TEST_ptr(kdata = OPENSSL_zalloc(sizeof(*kdata)))) - return 0; - kdata->ctx = EVP_PKEY_CTX_new_id(OBJ_sn2nid(name), NULL); - if (kdata->ctx == NULL) { - OPENSSL_free(kdata); - return 0; + if (is_kdf_disabled(name)) { + TEST_info("skipping, '%s' is disabled", name); + t->skip = 1; + return 1; } - if (EVP_PKEY_derive_init(kdata->ctx) <= 0) { - EVP_PKEY_CTX_free(kdata->ctx); - OPENSSL_free(kdata); + + if (!TEST_ptr(kdata = OPENSSL_zalloc(sizeof(*kdata)))) return 0; - } + + kdata->ctx = EVP_PKEY_CTX_new_from_name(libctx, name, NULL); + if (kdata->ctx == NULL + || EVP_PKEY_derive_init(kdata->ctx) <= 0) + goto err; + t->data = kdata; return 1; +err: + EVP_PKEY_CTX_free(kdata->ctx); + OPENSSL_free(kdata); + return 0; } -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); @@ -1659,9 +2546,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; @@ -1684,18 +2571,17 @@ 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 }; - /** -*** KEYPAIR TESTS -**/ + ** KEYPAIR TESTS + **/ typedef struct keypair_test_data_st { EVP_PKEY *privk; @@ -1778,7 +2664,7 @@ static int keypair_test_run(EVP_TEST *t) goto end; } - if ((rv = EVP_PKEY_cmp(pair->privk, pair->pubk)) != 1 ) { + if ((rv = EVP_PKEY_eq(pair->privk, pair->pubk)) != 1 ) { if ( 0 == rv ) { t->err = "KEYPAIR_MISMATCH"; } else if ( -1 == rv ) { @@ -1810,8 +2696,8 @@ static const EVP_TEST_METHOD keypair_test_method = { }; /** -*** KEYGEN TEST -**/ + ** KEYGEN TEST + **/ typedef struct keygen_test_data_st { EVP_PKEY_CTX *genctx; /* Keygen context to use */ @@ -1830,11 +2716,12 @@ static int keygen_test_init(EVP_TEST *t, const char *alg) return 0; } - if (!TEST_ptr(genctx = EVP_PKEY_CTX_new_id(nid, NULL))) { - /* assume algorithm disabled */ + if (is_pkey_disabled(alg)) { t->skip = 1; return 1; } + if (!TEST_ptr(genctx = EVP_PKEY_CTX_new_from_name(libctx, alg, NULL))) + goto err; if (EVP_PKEY_keygen_init(genctx) <= 0) { t->err = "KEYGEN_INIT_ERROR"; @@ -1880,16 +2767,21 @@ static int keygen_test_run(EVP_TEST *t) { KEYGEN_TEST_DATA *keygen = t->data; EVP_PKEY *pkey = NULL; + int rv = 1; - t->err = NULL; if (EVP_PKEY_keygen(keygen->genctx, &pkey) <= 0) { t->err = "KEYGEN_GENERATE_ERROR"; goto err; } + if (!evp_pkey_is_provided(pkey)) { + TEST_info("Warning: legacy key generated %s", keygen->keyname); + goto err; + } if (keygen->keyname != NULL) { KEY_LIST *key; + rv = 0; if (find_key(NULL, keygen->keyname, private_keys)) { TEST_info("Duplicate key %s", keygen->keyname); goto err; @@ -1902,15 +2794,15 @@ static int keygen_test_run(EVP_TEST *t) key->key = pkey; key->next = private_keys; private_keys = key; + rv = 1; } else { EVP_PKEY_free(pkey); } - return 1; + t->err = NULL; err: - EVP_PKEY_free(pkey); - return 0; + return rv; } static const EVP_TEST_METHOD keygen_test_method = { @@ -1922,8 +2814,8 @@ static const EVP_TEST_METHOD keygen_test_method = { }; /** -*** DIGEST SIGN+VERIFY TESTS -**/ + ** DIGEST SIGN+VERIFY TESTS + **/ typedef struct { int is_verify; /* Set to 1 if verifying */ @@ -1945,14 +2837,13 @@ static int digestsigver_test_init(EVP_TEST *t, const char *alg, int is_verify, DIGESTSIGN_DATA *mdat; if (strcmp(alg, "NULL") != 0) { - if ((md = EVP_get_digestbyname(alg)) == NULL) { - /* If alg has an OID assume disabled algorithm */ - if (OBJ_sn2nid(alg) != NID_undef || OBJ_ln2nid(alg) != NID_undef) { - t->skip = 1; - return 1; - } - return 0; + if (is_digest_disabled(alg)) { + t->skip = 1; + return 1; } + md = EVP_get_digestbyname(alg); + if (md == NULL) + return 0; } if (!TEST_ptr(mdat = OPENSSL_zalloc(sizeof(*mdat)))) return 0; @@ -1992,6 +2883,7 @@ static int digestsigver_test_parse(EVP_TEST *t, if (strcmp(keyword, "Key") == 0) { EVP_PKEY *pkey = NULL; int rv = 0; + const char *name = mdata->md == NULL ? NULL : EVP_MD_name(mdata->md); if (mdata->is_verify) rv = find_key(&pkey, value, public_keys); @@ -2002,13 +2894,13 @@ static int digestsigver_test_parse(EVP_TEST *t, return 1; } if (mdata->is_verify) { - if (!EVP_DigestVerifyInit(mdata->ctx, &mdata->pctx, mdata->md, - NULL, pkey)) + if (!EVP_DigestVerifyInit_with_libctx(mdata->ctx, &mdata->pctx, + name, libctx, NULL, pkey)) t->err = "DIGESTVERIFYINIT_ERROR"; return 1; } - if (!EVP_DigestSignInit(mdata->ctx, &mdata->pctx, mdata->md, NULL, - pkey)) + if (!EVP_DigestSignInit_with_libctx(mdata->ctx, &mdata->pctx, + name, libctx, NULL, pkey)) t->err = "DIGESTSIGNINIT_ERROR"; return 1; } @@ -2029,7 +2921,7 @@ static int digestsigver_test_parse(EVP_TEST *t, } if (strcmp(keyword, "Ctrl") == 0) { if (mdata->pctx == NULL) - return 0; + return -1; return pkey_test_ctrl(t, mdata->pctx, value); } return 0; @@ -2065,11 +2957,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; @@ -2142,11 +3035,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; @@ -2185,16 +3079,18 @@ static const EVP_TEST_METHOD oneshot_digestverify_test_method = { /** -*** PARSING AND DISPATCH -**/ + ** PARSING AND DISPATCH + **/ static const EVP_TEST_METHOD *evp_test_list[] = { + &rand_test_method, &cipher_test_method, &digest_test_method, &digestsign_test_method, &digestverify_test_method, &encode_test_method, &kdf_test_method, + &pkey_kdf_test_method, &keypair_test_method, &keygen_test_method, &mac_test_method, @@ -2232,8 +3128,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; @@ -2243,13 +3137,10 @@ static void clear_test(EVP_TEST *t) t->meth = NULL; } -/* - * Check for errors in the test structure; return 1 if okay, else 0. - */ +/* Check for errors in the test structure; return 1 if okay, else 0. */ static int check_test_error(EVP_TEST *t) { unsigned long err; - const char *func; const char *reason; if (t->err == NULL && t->expected_err == NULL) @@ -2276,10 +3167,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; @@ -2287,32 +3178,29 @@ 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." + if (reason == NULL) { + 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; } -/* - * Run a parsed test. Log a message and return 0 on error. - */ +/* Run a parsed test. Log a message and return 0 on error. */ static int run_test(EVP_TEST *t) { if (t->meth == NULL) @@ -2364,12 +3252,12 @@ 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(); + long err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_EVP - && ERR_GET_REASON(err) == EVP_R_UNSUPPORTED_ALGORITHM) { + && (ERR_GET_REASON(err) == EVP_R_UNSUPPORTED_ALGORITHM)) { ERR_clear_error(); return 1; } @@ -2380,7 +3268,8 @@ static int key_unsupported() * disabled). */ if (ERR_GET_LIB(err) == ERR_LIB_EC - && ERR_GET_REASON(err) == EC_R_UNKNOWN_GROUP) { + && (ERR_GET_REASON(err) == EC_R_UNKNOWN_GROUP + || ERR_GET_REASON(err) == EC_R_INVALID_CURVE)) { ERR_clear_error(); return 1; } @@ -2388,9 +3277,7 @@ static int key_unsupported() return 0; } -/* - * NULL out the value from |pp| but return it. This "steals" a pointer. - */ +/* NULL out the value from |pp| but return it. This "steals" a pointer. */ static char *take_value(PAIR *pp) { char *p = pp->value; @@ -2400,14 +3287,39 @@ static char *take_value(PAIR *pp) } /* - * Read and parse one test. Return 0 if failure, 1 if okay. + * 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(libctx, providers)) + return 1; /* Found one */ + } + return 0; +} + +/* Read and parse one test. Return 0 if failure, 1 if okay. */ static int parse(EVP_TEST *t) { KEY_LIST *key, **klist; EVP_PKEY *pkey; PAIR *pp; - int i; + int i, skip_availablein = 0; top: do { @@ -2422,23 +3334,81 @@ top: /* Are we adding a key? */ klist = NULL; pkey = NULL; +start: if (strcmp(pp->key, "PrivateKey") == 0) { - pkey = PEM_read_bio_PrivateKey(t->s.key, NULL, 0, NULL); + pkey = PEM_read_bio_PrivateKey_ex(t->s.key, NULL, 0, NULL, libctx, 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; } klist = &private_keys; - } - else if (strcmp(pp->key, "PublicKey") == 0) { - pkey = PEM_read_bio_PUBKEY(t->s.key, NULL, 0, NULL); + } else if (strcmp(pp->key, "PublicKey") == 0) { + pkey = PEM_read_bio_PUBKEY_ex(t->s.key, NULL, 0, NULL, libctx, 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; } klist = &public_keys; + } else if (strcmp(pp->key, "PrivateKeyRaw") == 0 + || strcmp(pp->key, "PublicKeyRaw") == 0 ) { + char *strnid = NULL, *keydata = NULL; + unsigned char *keybin; + size_t keylen; + int nid; + + if (strcmp(pp->key, "PrivateKeyRaw") == 0) + klist = &private_keys; + else + klist = &public_keys; + + strnid = strchr(pp->value, ':'); + if (strnid != NULL) { + *strnid++ = '\0'; + keydata = strchr(strnid, ':'); + if (keydata != NULL) + *keydata++ = '\0'; + } + if (keydata == NULL) { + TEST_info("Failed to parse %s value", pp->key); + return 0; + } + + nid = OBJ_txt2nid(strnid); + if (nid == NID_undef) { + TEST_info("Unrecognised algorithm NID"); + return 0; + } + if (!parse_bin(keydata, &keybin, &keylen)) { + TEST_info("Failed to create binary key"); + return 0; + } + if (klist == &private_keys) + pkey = EVP_PKEY_new_raw_private_key_with_libctx(libctx, strnid, NULL, + keybin, keylen); + else + pkey = EVP_PKEY_new_raw_public_key_with_libctx(libctx, strnid, NULL, + keybin, keylen); + if (pkey == NULL && !key_unsupported()) { + TEST_info("Can't read %s data", pp->key); + OPENSSL_free(keybin); + TEST_openssl_errors(); + return 0; + } + OPENSSL_free(keybin); + } else if (strcmp(pp->key, "Availablein") == 0) { + if (!prov_available(pp->value)) { + TEST_info("skipping, '%s' provider not available: %s:%d", + pp->value, t->s.test_file, t->s.start); + t->skip = 1; + return 0; + } + skip_availablein++; + pp++; + goto start; } /* If we have a key add to list */ @@ -2455,7 +3425,7 @@ top: *klist = key; /* Go back and start a new stanza. */ - if (t->s.numpairs != 1) + if ((t->s.numpairs - skip_availablein) != 1) TEST_info("Line %d: missing blank line\n", t->s.curr); goto top; } @@ -2472,19 +3442,26 @@ top: return 0; } - for (pp++, i = 1; i < t->s.numpairs; pp++, i++) { - if (strcmp(pp->key, "Result") == 0) { + for (pp++, i = 1; i < (t->s.numpairs - skip_availablein); pp++, i++) { + if (strcmp(pp->key, "Securitycheck") == 0) { +#if defined(OPENSSL_NO_FIPS_SECURITYCHECKS) + TEST_info("skipping, securitycheck is not available: %s:%d", + t->s.test_file, t->s.start); + t->skip = 1; + return 0; +#endif + } else if (strcmp(pp->key, "Availablein") == 0) { + TEST_info("Line %d: 'Availablein' should be the first option", + t->s.curr); + 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); @@ -2500,8 +3477,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; } } @@ -2510,24 +3487,25 @@ top: return 1; } -static char * const *testfiles; - static int run_file_tests(int i) { EVP_TEST *t; + const char *testfile = test_get_argument(i); int c; if (!TEST_ptr(t = OPENSSL_zalloc(sizeof(*t)))) return 0; - if (!test_start_file(&t->s, testfiles[i])) { + if (!test_start_file(&t->s, testfile)) { OPENSSL_free(t); return 0; } 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; @@ -2544,15 +3522,228 @@ static int run_file_tests(int i) return c == 0; } -int test_main(int argc, char *argv[]) +const OPTIONS *test_get_options(void) +{ + static const OPTIONS test_options[] = { + OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("[file...]\n"), + { "config", OPT_CONFIG_FILE, '<', + "The configuration file to use for the libctx" }, + { OPT_HELP_STR, 1, '-', + "file\tFile to run tests on.\n" }, + { NULL } + }; + return test_options; +} + +int setup_tests(void) { - if (argc < 2) { - TEST_error("Usage: %s file...", argv[0]); + size_t n; + char *config_file = NULL; + + OPTION_CHOICE o; + + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_CONFIG_FILE: + config_file = opt_arg(); + break; + case OPT_TEST_CASES: + break; + default: + case OPT_ERR: + return 0; + } + } + + /* + * Load the 'null' provider into the default library context to ensure that + * the the tests do not fallback to using the default provider. + */ + prov_null = OSSL_PROVIDER_load(NULL, "null"); + if (prov_null == NULL) { + opt_printf_stderr("Failed to load null provider into default libctx\n"); + return 0; + } + + /* load the provider via configuration into the created library context */ + libctx = OPENSSL_CTX_new(); + if (libctx == NULL + || !OPENSSL_CTX_load_config(libctx, config_file)) { + TEST_error("Failed to load config %s\n", config_file); return 0; } - testfiles = &argv[1]; - ADD_ALL_TESTS(run_file_tests, argc - 1); + n = test_get_argument_count(); + if (n == 0) + return 0; + + ADD_ALL_TESTS(run_file_tests, n); + return 1; +} + +void cleanup_tests(void) +{ + OSSL_PROVIDER_unload(prov_null); + OPENSSL_CTX_free(libctx); +} + +#define STR_STARTS_WITH(str, pre) strncasecmp(pre, str, strlen(pre)) == 0 +#define STR_ENDS_WITH(str, pre) \ +strlen(str) < strlen(pre) ? 0 : (strcasecmp(pre, str + strlen(str) - strlen(pre)) == 0) + +static int is_digest_disabled(const char *name) +{ +#ifdef OPENSSL_NO_BLAKE2 + if (STR_STARTS_WITH(name, "BLAKE")) + return 1; +#endif +#ifdef OPENSSL_NO_MD2 + if (strcasecmp(name, "MD2") == 0) + return 1; +#endif +#ifdef OPENSSL_NO_MDC2 + if (strcasecmp(name, "MDC2") == 0) + return 1; +#endif +#ifdef OPENSSL_NO_MD4 + if (strcasecmp(name, "MD4") == 0) + return 1; +#endif +#ifdef OPENSSL_NO_MD5 + if (strcasecmp(name, "MD5") == 0) + return 1; +#endif +#ifdef OPENSSL_NO_RMD160 + if (strcasecmp(name, "RIPEMD160") == 0) + return 1; +#endif +#ifdef OPENSSL_NO_SM3 + if (strcasecmp(name, "SM3") == 0) + return 1; +#endif +#ifdef OPENSSL_NO_WHIRLPOOL + if (strcasecmp(name, "WHIRLPOOL") == 0) + return 1; +#endif + return 0; +} + +static int is_pkey_disabled(const char *name) +{ +#ifdef OPENSSL_NO_RSA + if (STR_STARTS_WITH(name, "RSA")) + return 1; +#endif +#ifdef OPENSSL_NO_EC + if (STR_STARTS_WITH(name, "EC")) + return 1; +#endif +#ifdef OPENSSL_NO_DH + if (STR_STARTS_WITH(name, "DH")) + return 1; +#endif +#ifdef OPENSSL_NO_DSA + if (STR_STARTS_WITH(name, "DSA")) + return 1; +#endif + return 0; +} + +static int is_mac_disabled(const char *name) +{ +#ifdef OPENSSL_NO_BLAKE2 + if (STR_STARTS_WITH(name, "BLAKE2BMAC") + || STR_STARTS_WITH(name, "BLAKE2SMAC")) + return 1; +#endif +#ifdef OPENSSL_NO_CMAC + if (STR_STARTS_WITH(name, "CMAC")) + return 1; +#endif +#ifdef OPENSSL_NO_POLY1305 + if (STR_STARTS_WITH(name, "Poly1305")) + return 1; +#endif +#ifdef OPENSSL_NO_SIPHASH + if (STR_STARTS_WITH(name, "SipHash")) + return 1; +#endif + return 0; +} +static int is_kdf_disabled(const char *name) +{ +#ifdef OPENSSL_NO_SCRYPT + if (STR_ENDS_WITH(name, "SCRYPT")) + return 1; +#endif +#ifdef OPENSSL_NO_CMS + if (strcasecmp(name, "X942KDF") == 0) + return 1; +#endif /* OPENSSL_NO_CMS */ + return 0; +} - return run_tests(argv[0]); +static int is_cipher_disabled(const char *name) +{ +#ifdef OPENSSL_NO_ARIA + if (STR_STARTS_WITH(name, "ARIA")) + return 1; +#endif +#ifdef OPENSSL_NO_BF + if (STR_STARTS_WITH(name, "BF")) + return 1; +#endif +#ifdef OPENSSL_NO_CAMELLIA + if (STR_STARTS_WITH(name, "CAMELLIA")) + return 1; +#endif +#ifdef OPENSSL_NO_CAST + if (STR_STARTS_WITH(name, "CAST")) + return 1; +#endif +#ifdef OPENSSL_NO_CHACHA + if (STR_STARTS_WITH(name, "CHACHA")) + return 1; +#endif +#ifdef OPENSSL_NO_POLY1305 + if (STR_ENDS_WITH(name, "Poly1305")) + return 1; +#endif +#ifdef OPENSSL_NO_DES + if (STR_STARTS_WITH(name, "DES")) + return 1; +#endif +#ifdef OPENSSL_NO_OCB + if (STR_ENDS_WITH(name, "OCB")) + return 1; +#endif +#ifdef OPENSSL_NO_IDEA + if (STR_STARTS_WITH(name, "IDEA")) + return 1; +#endif +#ifdef OPENSSL_NO_RC2 + if (STR_STARTS_WITH(name, "RC2")) + return 1; +#endif +#ifdef OPENSSL_NO_RC4 + if (STR_STARTS_WITH(name, "RC4")) + return 1; +#endif +#ifdef OPENSSL_NO_RC5 + if (STR_STARTS_WITH(name, "RC5")) + return 1; +#endif +#ifdef OPENSSL_NO_SEED + if (STR_STARTS_WITH(name, "SEED")) + return 1; +#endif +#ifdef OPENSSL_NO_SIV + if (STR_ENDS_WITH(name, "SIV")) + return 1; +#endif +#ifdef OPENSSL_NO_SM4 + if (STR_STARTS_WITH(name, "SM4")) + return 1; +#endif + return 0; }