From 169eca602c67f37abf0a44e1605998d5e7f04fa6 Mon Sep 17 00:00:00 2001 From: Jon Spillett Date: Mon, 15 Mar 2021 14:26:09 +1000 Subject: Enhance the encoder/decoder tests to allow testing with a non-default library context and configurable providers Reviewed-by: Shane Lontis Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/14587) --- crypto/pem/pvkfmt.c | 99 ++++++++---- doc/build.info | 6 + doc/man3/b2i_PVK_bio_ex.pod | 69 +++++++++ include/openssl/pem.h | 5 + .../implementations/encode_decode/encode_key2any.c | 4 +- .../implementations/encode_decode/encode_key2ms.c | 5 +- test/endecode_test.c | 166 ++++++++++++++++----- test/evp_libctx_test.c | 2 +- test/recipes/04-test_encoder_decoder.t | 43 ++++-- test/testutil.h | 7 + test/testutil/provider.c | 14 +- util/libcrypto.num | 2 + util/missingcrypto.txt | 2 - 13 files changed, 333 insertions(+), 91 deletions(-) create mode 100644 doc/man3/b2i_PVK_bio_ex.pod diff --git a/crypto/pem/pvkfmt.c b/crypto/pem/pvkfmt.c index 51d3ec476b..d08fab4ba8 100644 --- a/crypto/pem/pvkfmt.c +++ b/crypto/pem/pvkfmt.c @@ -792,22 +792,27 @@ int ossl_do_PVK_header(const unsigned char **in, unsigned int length, #ifndef OPENSSL_NO_RC4 static int derive_pvk_key(unsigned char *key, const unsigned char *salt, unsigned int saltlen, - const unsigned char *pass, int passlen) + const unsigned char *pass, int passlen, + OSSL_LIB_CTX *libctx, const char *propq) { EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - EVP_MD *md = EVP_MD_fetch(NULL, SN_sha1, NULL); - int rv = 1; + int rv = 0; + EVP_MD *sha1 = NULL; - if (md == NULL - || mctx == NULL - || !EVP_DigestInit_ex(mctx, md, NULL) + if ((sha1 = EVP_MD_fetch(libctx, SN_sha1, propq)) == NULL) + goto err; + + if (mctx == NULL + || !EVP_DigestInit_ex(mctx, sha1, NULL) || !EVP_DigestUpdate(mctx, salt, saltlen) || !EVP_DigestUpdate(mctx, pass, passlen) || !EVP_DigestFinal_ex(mctx, key, NULL)) - rv = 0; + goto err; + rv = 1; +err: EVP_MD_CTX_free(mctx); - EVP_MD_free(md); + EVP_MD_free(sha1); return rv; } #endif @@ -815,14 +820,18 @@ static int derive_pvk_key(unsigned char *key, static void *do_PVK_body_key(const unsigned char **in, unsigned int saltlen, unsigned int keylen, pem_password_cb *cb, void *u, - int *isdss, int *ispub) + int *isdss, int *ispub, + OSSL_LIB_CTX *libctx, const char *propq) { const unsigned char *p = *in; unsigned char *enctmp = NULL; unsigned char keybuf[20]; void *key = NULL; - +#ifndef OPENSSL_NO_RC4 + EVP_CIPHER *rc4 = NULL; +#endif EVP_CIPHER_CTX *cctx = EVP_CIPHER_CTX_new(); + if (saltlen) { #ifndef OPENSSL_NO_RC4 unsigned int magic; @@ -844,7 +853,7 @@ static void *do_PVK_body_key(const unsigned char **in, goto err; } if (!derive_pvk_key(keybuf, p, saltlen, - (unsigned char *)psbuf, inlen)) + (unsigned char *)psbuf, inlen, libctx, propq)) goto err; p += saltlen; /* Copy BLOBHEADER across, decrypt rest */ @@ -856,7 +865,9 @@ static void *do_PVK_body_key(const unsigned char **in, } inlen = keylen - 8; q = enctmp + 8; - if (!EVP_DecryptInit_ex(cctx, EVP_rc4(), NULL, keybuf, NULL)) + if ((rc4 = EVP_CIPHER_fetch(libctx, "RC4", propq)) == NULL) + goto err; + if (!EVP_DecryptInit_ex(cctx, rc4, NULL, keybuf, NULL)) goto err; if (!EVP_DecryptUpdate(cctx, q, &enctmplen, p, inlen)) goto err; @@ -866,7 +877,7 @@ static void *do_PVK_body_key(const unsigned char **in, if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) { q = enctmp + 8; memset(keybuf + 5, 0, 11); - if (!EVP_DecryptInit_ex(cctx, EVP_rc4(), NULL, keybuf, NULL)) + if (!EVP_DecryptInit_ex(cctx, rc4, NULL, keybuf, NULL)) goto err; if (!EVP_DecryptUpdate(cctx, q, &enctmplen, p, inlen)) goto err; @@ -888,6 +899,9 @@ static void *do_PVK_body_key(const unsigned char **in, key = do_b2i_key(&p, keylen, isdss, ispub); err: EVP_CIPHER_CTX_free(cctx); +#ifndef OPENSSL_NO_RC4 + EVP_CIPHER_free(rc4); +#endif if (enctmp != NULL) { OPENSSL_cleanse(keybuf, sizeof(keybuf)); OPENSSL_free(enctmp); @@ -896,7 +910,8 @@ static void *do_PVK_body_key(const unsigned char **in, } static void *do_PVK_key_bio(BIO *in, pem_password_cb *cb, void *u, - int *isdss, int *ispub) + int *isdss, int *ispub, + OSSL_LIB_CTX *libctx, const char *propq) { unsigned char pvk_hdr[24], *buf = NULL; const unsigned char *p; @@ -923,7 +938,7 @@ static void *do_PVK_key_bio(BIO *in, pem_password_cb *cb, void *u, ERR_raise(ERR_LIB_PEM, PEM_R_PVK_DATA_TOO_SHORT); goto err; } - key = do_PVK_body_key(&p, saltlen, keylen, cb, u, isdss, ispub); + key = do_PVK_body_key(&p, saltlen, keylen, cb, u, isdss, ispub, libctx, propq); err: OPENSSL_clear_free(buf, buflen); @@ -936,7 +951,7 @@ DSA *b2i_DSA_PVK_bio(BIO *in, pem_password_cb *cb, void *u) int isdss = 1; int ispub = 0; /* PVK keys are always private */ - return do_PVK_key_bio(in, cb, u, &isdss, &ispub); + return do_PVK_key_bio(in, cb, u, &isdss, &ispub, NULL, NULL); } #endif @@ -945,26 +960,35 @@ RSA *b2i_RSA_PVK_bio(BIO *in, pem_password_cb *cb, void *u) int isdss = 0; int ispub = 0; /* PVK keys are always private */ - return do_PVK_key_bio(in, cb, u, &isdss, &ispub); + return do_PVK_key_bio(in, cb, u, &isdss, &ispub, NULL, NULL); } -EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u) +EVP_PKEY *b2i_PVK_bio_ex(BIO *in, pem_password_cb *cb, void *u, + OSSL_LIB_CTX *libctx, const char *propq) { int isdss = -1; int ispub = -1; - void *key = do_PVK_key_bio(in, cb, u, &isdss, &ispub); + void *key = do_PVK_key_bio(in, cb, u, &isdss, &ispub, NULL, NULL); return evp_pkey_new0_key(key, isdss_to_evp_type(isdss)); } +EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u) +{ + return b2i_PVK_bio_ex(in, cb, u, NULL, NULL); +} + static int i2b_PVK(unsigned char **out, const EVP_PKEY *pk, int enclevel, - pem_password_cb *cb, void *u) + pem_password_cb *cb, void *u, OSSL_LIB_CTX *libctx, + const char *propq) { + int ret = -1; int outlen = 24, pklen; unsigned char *p = NULL, *start = NULL; EVP_CIPHER_CTX *cctx = NULL; #ifndef OPENSSL_NO_RC4 unsigned char *salt = NULL; + EVP_CIPHER *rc4 = NULL; #endif if (enclevel) @@ -1002,7 +1026,7 @@ static int i2b_PVK(unsigned char **out, const EVP_PKEY *pk, int enclevel, write_ledword(&p, pklen); if (enclevel) { #ifndef OPENSSL_NO_RC4 - if (RAND_bytes(p, PVK_SALTLEN) <= 0) + if (RAND_bytes_ex(libctx, p, PVK_SALTLEN, 0) <= 0) goto error; salt = p; p += PVK_SALTLEN; @@ -1014,7 +1038,6 @@ static int i2b_PVK(unsigned char **out, const EVP_PKEY *pk, int enclevel, char psbuf[PEM_BUFSIZE]; unsigned char keybuf[20]; int enctmplen, inlen; - if (cb) inlen = cb(psbuf, PEM_BUFSIZE, 1, u); else @@ -1024,12 +1047,14 @@ static int i2b_PVK(unsigned char **out, const EVP_PKEY *pk, int enclevel, goto error; } if (!derive_pvk_key(keybuf, salt, PVK_SALTLEN, - (unsigned char *)psbuf, inlen)) + (unsigned char *)psbuf, inlen, libctx, propq)) + goto error; + if ((rc4 = EVP_CIPHER_fetch(libctx, "RC4", propq)) == NULL) goto error; if (enclevel == 1) memset(keybuf + 5, 0, 11); p = salt + PVK_SALTLEN + 8; - if (!EVP_EncryptInit_ex(cctx, EVP_rc4(), NULL, keybuf, NULL)) + if (!EVP_EncryptInit_ex(cctx, rc4, NULL, keybuf, NULL)) goto error; OPENSSL_cleanse(keybuf, 20); if (!EVP_EncryptUpdate(cctx, p, &enctmplen, p, pklen - 8)) @@ -1042,27 +1067,28 @@ static int i2b_PVK(unsigned char **out, const EVP_PKEY *pk, int enclevel, #endif } - EVP_CIPHER_CTX_free(cctx); - if (*out == NULL) *out = start; - - return outlen; - + ret = outlen; error: EVP_CIPHER_CTX_free(cctx); +#ifndef OPENSSL_NO_RC4 + EVP_CIPHER_free(rc4); +#endif if (*out == NULL) OPENSSL_free(start); - return -1; + + return ret; } -int i2b_PVK_bio(BIO *out, const EVP_PKEY *pk, int enclevel, - pem_password_cb *cb, void *u) +int i2b_PVK_bio_ex(BIO *out, const EVP_PKEY *pk, int enclevel, + pem_password_cb *cb, void *u, OSSL_LIB_CTX *libctx, + const char *propq) { unsigned char *tmp = NULL; int outlen, wrlen; - outlen = i2b_PVK(&tmp, pk, enclevel, cb, u); + outlen = i2b_PVK(&tmp, pk, enclevel, cb, u, libctx, propq); if (outlen < 0) return -1; wrlen = BIO_write(out, tmp, outlen); @@ -1073,3 +1099,10 @@ int i2b_PVK_bio(BIO *out, const EVP_PKEY *pk, int enclevel, ERR_raise(ERR_LIB_PEM, PEM_R_BIO_WRITE_FAILURE); return -1; } + +int i2b_PVK_bio(BIO *out, const EVP_PKEY *pk, int enclevel, + pem_password_cb *cb, void *u) +{ + return i2b_PVK_bio_ex(out, pk, enclevel, cb, u, NULL, NULL); +} + diff --git a/doc/build.info b/doc/build.info index b77c04d2b6..42c1804d6c 100644 --- a/doc/build.info +++ b/doc/build.info @@ -2779,6 +2779,10 @@ DEPEND[html/man3/X509v3_get_ext_by_NID.html]=man3/X509v3_get_ext_by_NID.pod GENERATE[html/man3/X509v3_get_ext_by_NID.html]=man3/X509v3_get_ext_by_NID.pod DEPEND[man/man3/X509v3_get_ext_by_NID.3]=man3/X509v3_get_ext_by_NID.pod GENERATE[man/man3/X509v3_get_ext_by_NID.3]=man3/X509v3_get_ext_by_NID.pod +DEPEND[html/man3/b2i_PVK_bio_ex.html]=man3/b2i_PVK_bio_ex.pod +GENERATE[html/man3/b2i_PVK_bio_ex.html]=man3/b2i_PVK_bio_ex.pod +DEPEND[man/man3/b2i_PVK_bio_ex.3]=man3/b2i_PVK_bio_ex.pod +GENERATE[man/man3/b2i_PVK_bio_ex.3]=man3/b2i_PVK_bio_ex.pod DEPEND[html/man3/d2i_PKCS8PrivateKey_bio.html]=man3/d2i_PKCS8PrivateKey_bio.pod GENERATE[html/man3/d2i_PKCS8PrivateKey_bio.html]=man3/d2i_PKCS8PrivateKey_bio.pod DEPEND[man/man3/d2i_PKCS8PrivateKey_bio.3]=man3/d2i_PKCS8PrivateKey_bio.pod @@ -3398,6 +3402,7 @@ html/man3/X509_sign.html \ html/man3/X509_verify.html \ html/man3/X509_verify_cert.html \ html/man3/X509v3_get_ext_by_NID.html \ +html/man3/b2i_PVK_bio_ex.html \ html/man3/d2i_PKCS8PrivateKey_bio.html \ html/man3/d2i_PrivateKey.html \ html/man3/d2i_RSAPrivateKey.html \ @@ -3986,6 +3991,7 @@ man/man3/X509_sign.3 \ man/man3/X509_verify.3 \ man/man3/X509_verify_cert.3 \ man/man3/X509v3_get_ext_by_NID.3 \ +man/man3/b2i_PVK_bio_ex.3 \ man/man3/d2i_PKCS8PrivateKey_bio.3 \ man/man3/d2i_PrivateKey.3 \ man/man3/d2i_RSAPrivateKey.3 \ diff --git a/doc/man3/b2i_PVK_bio_ex.pod b/doc/man3/b2i_PVK_bio_ex.pod new file mode 100644 index 0000000000..bd670b2614 --- /dev/null +++ b/doc/man3/b2i_PVK_bio_ex.pod @@ -0,0 +1,69 @@ +=pod + +=head1 NAME + +b2i_PVK_bio, b2i_PVK_bio_ex, i2b_PVK_bio, i2b_PVK_bio_ex - Decode and encode +functions for reading and writing MSBLOB format private keys + +=head1 SYNOPSIS + + #include + + EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u); + EVP_PKEY *b2i_PVK_bio_ex(BIO *in, pem_password_cb *cb, void *u, + OSSL_LIB_CTX *libctx, const char *propq); + int i2b_PVK_bio(BIO *out, const EVP_PKEY *pk, int enclevel, + pem_password_cb *cb, void *u); + int i2b_PVK_bio_ex(BIO *out, const EVP_PKEY *pk, int enclevel, + pem_password_cb *cb, void *u, + OSSL_LIB_CTX *libctx, const char *propq); + +=head1 DESCRIPTION + +b2i_PVK_bio_ex() decodes a private key of MSBLOB format read from a B. It +attempts to automatically determine the key type. If the key is encrypted then +I is called with the user data I in order to obtain a password to decrypt +the key. The supplied library context I and property query +string I are used in any decrypt operation. + +b2i_PVK_bio() does the same as b2i_PVK_bio_ex() except that the default +library context and property query string are used. + +i2b_PVK_bio_ex() encodes I using MSBLOB format. If I is 1 then +a password obtained via I is used to encrypt the private key. +If I is 0 then no encryption is applied. The user data in I is +passed to the password callback. The supplied library context I and +property query string I are used in any decrypt operation. + +i2b_PVK_bio() does the same as i2b_PVK_bio_ex() except that the default +library context and property query string are used. + +=head1 RETURN VALUES + +The b2i_PVK_bio() and b2i_PVK_bio_ex() functions return a valid B +structure or B if an error occurs. The error code can be obtained by calling +L. + +i2b_PVK_bio() and i2b_PVK_bio_ex() return the number of bytes successfully +encoded or a negative value if an error occurs. The error code can be obtained +by calling L. + +=head1 SEE ALSO + +L, +L + +=head1 HISTORY + +b2i_PVK_bio_ex() and i2b_PVK_bio_ex() were added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/include/openssl/pem.h b/include/openssl/pem.h index aaf4e262af..80940dfa96 100644 --- a/include/openssl/pem.h +++ b/include/openssl/pem.h @@ -524,8 +524,13 @@ EVP_PKEY *b2i_PublicKey_bio(BIO *in); int i2b_PrivateKey_bio(BIO *out, const EVP_PKEY *pk); int i2b_PublicKey_bio(BIO *out, const EVP_PKEY *pk); EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u); +EVP_PKEY *b2i_PVK_bio_ex(BIO *in, pem_password_cb *cb, void *u, + OSSL_LIB_CTX *libctx, const char *propq); int i2b_PVK_bio(BIO *out, const EVP_PKEY *pk, int enclevel, pem_password_cb *cb, void *u); +int i2b_PVK_bio_ex(BIO *out, const EVP_PKEY *pk, int enclevel, + pem_password_cb *cb, void *u, + OSSL_LIB_CTX *libctx, const char *propq); # ifdef __cplusplus } diff --git a/providers/implementations/encode_decode/encode_key2any.c b/providers/implementations/encode_decode/encode_key2any.c index 93f725d906..cd2c3f8daa 100644 --- a/providers/implementations/encode_decode/encode_key2any.c +++ b/providers/implementations/encode_decode/encode_key2any.c @@ -106,6 +106,7 @@ static X509_SIG *p8info_to_encp8(PKCS8_PRIV_KEY_INFO *p8info, X509_SIG *p8 = NULL; char kstr[PEM_BUFSIZE]; size_t klen = 0; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); if (ctx->cipher == NULL) return NULL; @@ -116,7 +117,8 @@ static X509_SIG *p8info_to_encp8(PKCS8_PRIV_KEY_INFO *p8info, return NULL; } /* First argument == -1 means "standard" */ - p8 = PKCS8_encrypt(-1, ctx->cipher, kstr, klen, NULL, 0, 0, p8info); + p8 = PKCS8_encrypt_ex(-1, ctx->cipher, kstr, klen, NULL, 0, 0, p8info, + libctx, NULL); OPENSSL_cleanse(kstr, klen); return p8; } diff --git a/providers/implementations/encode_decode/encode_key2ms.c b/providers/implementations/encode_decode/encode_key2ms.c index 81dfcd0ecc..79012e673e 100644 --- a/providers/implementations/encode_decode/encode_key2ms.c +++ b/providers/implementations/encode_decode/encode_key2ms.c @@ -52,10 +52,11 @@ static int write_pvk(struct key2ms_ctx_st *ctx, OSSL_CORE_BIO *cout, { BIO *out = NULL; int ret = 0; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); out = ossl_bio_new_from_core_bio(ctx->provctx, cout); - ret = i2b_PVK_bio(out, pkey, ctx->pvk_encr_level, - ossl_pw_pem_password, &ctx->pwdata); + ret = i2b_PVK_bio_ex(out, pkey, ctx->pvk_encr_level, + ossl_pw_pem_password, &ctx->pwdata, libctx, NULL); BIO_free(out); return ret; diff --git a/test/endecode_test.c b/test/endecode_test.c index f851f73ffd..f800d7738c 100644 --- a/test/endecode_test.c +++ b/test/endecode_test.c @@ -41,6 +41,17 @@ # define OPENSSL_NO_KEYPARAMS #endif +static int default_libctx = 1; +static int is_fips = 0; + +static OSSL_LIB_CTX *testctx = NULL; +static OSSL_LIB_CTX *keyctx = NULL; +static char *testpropq = NULL; + +static OSSL_PROVIDER *nullprov = NULL; +static OSSL_PROVIDER *deflprov = NULL; +static OSSL_PROVIDER *keyprov = NULL; + #ifndef OPENSSL_NO_EC static BN_CTX *bnctx = NULL; static OSSL_PARAM_BLD *bld_prime_nc = NULL; @@ -68,16 +79,17 @@ static EVP_PKEY *make_template(const char *type, OSSL_PARAM *genparams) * for testing only. Use a minimum key size of 2048 for security purposes. */ if (strcmp(type, "DH") == 0) - return get_dh512(NULL); + return get_dh512(keyctx); + if (strcmp(type, "X9.42 DH") == 0) - return get_dhx512(NULL); + return get_dhx512(keyctx); # endif /* * No real need to check the errors other than for the cascade * effect. |pkey| will simply remain NULL if something goes wrong. */ - (void)((ctx = EVP_PKEY_CTX_new_from_name(NULL, type, NULL)) != NULL + (void)((ctx = EVP_PKEY_CTX_new_from_name(keyctx, type, testpropq)) != NULL && EVP_PKEY_paramgen_init(ctx) > 0 && (genparams == NULL || EVP_PKEY_CTX_set_params(ctx, genparams) > 0) @@ -95,8 +107,8 @@ static EVP_PKEY *make_key(const char *type, EVP_PKEY *template, EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = template != NULL - ? EVP_PKEY_CTX_new(template, NULL) - : EVP_PKEY_CTX_new_from_name(NULL, type, NULL); + ? EVP_PKEY_CTX_new_from_pkey(keyctx, template, testpropq) + : EVP_PKEY_CTX_new_from_name(keyctx, type, testpropq); /* * No real need to check the errors other than for the cascade @@ -215,7 +227,7 @@ static int encode_EVP_PKEY_prov(const char *file, const int line, if (!TEST_FL_ptr(ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, output_type, output_structure, - NULL)) + testpropq)) || !TEST_FL_int_gt(OSSL_ENCODER_CTX_get_num_encoders(ectx), 0) || (pass != NULL && !TEST_FL_true(OSSL_ENCODER_CTX_set_passphrase(ectx, upass, @@ -278,7 +290,7 @@ static int decode_EVP_PKEY_prov(const char *file, const int line, structure_type, keytype, selection, - NULL, NULL)) + testctx, testpropq)) || (pass != NULL && !OSSL_DECODER_CTX_set_passphrase(dctx, upass, strlen(pass))) || !TEST_FL_int_gt(BIO_reset(encoded_bio), 0) @@ -331,7 +343,7 @@ static int encode_EVP_PKEY_legacy_PEM(const char *file, const int line, if (pcipher != NULL && pass != NULL) { passlen = strlen(pass); - if (!TEST_FL_ptr(cipher = EVP_CIPHER_fetch(NULL, pcipher, NULL))) + if (!TEST_FL_ptr(cipher = EVP_CIPHER_fetch(testctx, pcipher, testpropq))) goto end; } if (!TEST_FL_ptr(mem_ser = BIO_new(BIO_s_mem())) @@ -416,8 +428,8 @@ static int encode_EVP_PKEY_PVK(const char *file, const int line, if (!TEST_FL_true(ossl_assert((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)) || !TEST_FL_ptr(mem_ser = BIO_new(BIO_s_mem())) - || !TEST_FL_int_ge(i2b_PVK_bio(mem_ser, pkey, enc, - pass_pw, (void *)pass), 0) + || !TEST_FL_int_ge(i2b_PVK_bio_ex(mem_ser, pkey, enc, + pass_pw, (void *)pass, testctx, testpropq), 0) || !TEST_FL_true(BIO_get_mem_ptr(mem_ser, &mem_buf) > 0) || !TEST_FL_ptr(*encoded = mem_buf->data) || !TEST_FL_long_gt(*encoded_len = mem_buf->length, 0)) @@ -491,7 +503,7 @@ static int check_unprotected_PKCS8_DER(const char *file, const int line, int ok = 0; if (TEST_FL_ptr(p8inf)) { - EVP_PKEY *pkey = EVP_PKCS82PKEY(p8inf); + EVP_PKEY *pkey = EVP_PKCS82PKEY_ex(p8inf, testctx, testpropq); char *namelist = NULL; if (TEST_FL_ptr(pkey)) { @@ -513,7 +525,7 @@ static int test_unprotected_via_DER(const char *type, EVP_PKEY *key) { return test_encode_decode(__FILE__, __LINE__, type, key, OSSL_KEYMGMT_SELECT_KEYPAIR - | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, "DER", "pkcs8", NULL, NULL, encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, test_mem, check_unprotected_PKCS8_DER, @@ -533,8 +545,9 @@ static int check_unprotected_PKCS8_PEM(const char *file, const int line, static int test_unprotected_via_PEM(const char *type, EVP_PKEY *key) { - return test_encode_decode(__FILE__, __LINE__, type, key, OSSL_KEYMGMT_SELECT_KEYPAIR - | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + return test_encode_decode(__FILE__, __LINE__, type, key, + OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, "PEM", "pkcs8", NULL, NULL, encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, test_text, check_unprotected_PKCS8_PEM, @@ -615,6 +628,9 @@ static int check_unprotected_legacy_PEM(const char *file, const int line, static int test_unprotected_via_legacy_PEM(const char *type, EVP_PKEY *key) { + if (!default_libctx || is_fips) + return TEST_skip("Test not available if using a non-default library context or FIPS provider"); + return test_encode_decode(__FILE__, __LINE__, type, key, OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, @@ -731,6 +747,9 @@ static int check_protected_legacy_PEM(const char *file, const int line, static int test_protected_via_legacy_PEM(const char *type, EVP_PKEY *key) { + if (!default_libctx || is_fips) + return TEST_skip("Test not available if using a non-default library context or FIPS provider"); + return test_encode_decode(__FILE__, __LINE__, type, key, OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, @@ -743,12 +762,19 @@ static int test_protected_via_legacy_PEM(const char *type, EVP_PKEY *key) #ifndef OPENSSL_NO_RC4 static int test_protected_via_PVK(const char *type, EVP_PKEY *key) { - return test_encode_decode(__FILE__, __LINE__, type, key, + int ret = 0; + OSSL_PROVIDER *lgcyprov = OSSL_PROVIDER_load(testctx, "legacy"); + if (lgcyprov == NULL) + return TEST_skip("Legacy provider not available"); + + ret = test_encode_decode(__FILE__, __LINE__, type, key, OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, "PVK", NULL, pass, NULL, encode_EVP_PKEY_PVK, decode_EVP_PKEY_prov, test_mem, check_PVK, dump_der, 0); + OSSL_PROVIDER_unload(lgcyprov); + return ret; } #endif @@ -756,7 +782,7 @@ static int check_public_DER(const char *file, const int line, const char *type, const void *data, size_t data_len) { const unsigned char *datap = data; - EVP_PKEY *pkey = d2i_PUBKEY(NULL, &datap, data_len); + EVP_PKEY *pkey = d2i_PUBKEY_ex(NULL, &datap, data_len, testctx, testpropq); int ok = (TEST_FL_ptr(pkey) && TEST_FL_true(EVP_PKEY_is_a(pkey, type))); EVP_PKEY_free(pkey); @@ -767,7 +793,7 @@ static int test_public_via_DER(const char *type, EVP_PKEY *key) { return test_encode_decode(__FILE__, __LINE__, type, key, OSSL_KEYMGMT_SELECT_PUBLIC_KEY - | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, "DER", "SubjectPublicKeyInfo", NULL, NULL, encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, test_mem, check_public_DER, dump_der, 0); @@ -788,7 +814,7 @@ static int test_public_via_PEM(const char *type, EVP_PKEY *key) { return test_encode_decode(__FILE__, __LINE__, type, key, OSSL_KEYMGMT_SELECT_PUBLIC_KEY - | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, "PEM", "SubjectPublicKeyInfo", NULL, NULL, encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, test_text, check_public_PEM, dump_pem, 0); @@ -1184,14 +1210,42 @@ static int create_ec_explicit_trinomial_params(OSSL_PARAM_BLD *bld) # endif /* OPENSSL_NO_EC2M */ #endif /* OPENSSL_NO_EC */ -#define USAGE "rsa-key.pem rsa-pss-key.pem\n" -OPT_TEST_DECLARE_USAGE(USAGE) +typedef enum OPTION_choice { + OPT_ERR = -1, + OPT_EOF = 0, + OPT_CONTEXT, + OPT_RSA_FILE, + OPT_RSA_PSS_FILE, + OPT_CONFIG_FILE, + OPT_PROVIDER_NAME, + OPT_TEST_ENUM +} OPTION_CHOICE; + +const OPTIONS *test_get_options(void) +{ + static const OPTIONS options[] = { + OPT_TEST_OPTIONS_DEFAULT_USAGE, + { "context", OPT_CONTEXT, '-', + "Explicitly use a non-default library context" }, + { "rsa", OPT_RSA_FILE, '<', + "PEM format RSA key file to encode/decode" }, + { "pss", OPT_RSA_PSS_FILE, '<', + "PEM format RSA-PSS key file to encode/decode" }, + { "config", OPT_CONFIG_FILE, '<', + "The configuration file to use for the library context" }, + { "provider", OPT_PROVIDER_NAME, 's', + "The provider to load (The default value is 'default')" }, + { NULL } + }; + return options; +} int setup_tests(void) { -# ifndef OPENSSL_NO_RC4 - int use_legacy = OSSL_PROVIDER_available(NULL, "legacy"); -#endif + const char *rsa_file = NULL; + const char *rsa_pss_file = NULL; + const char *prov_name = "default"; + char *config_file = NULL; int ok = 1; #ifndef OPENSSL_NO_DSA @@ -1212,17 +1266,51 @@ int setup_tests(void) }; #endif - if (!test_skip_common_options()) { - TEST_error("Error parsing test options\n"); - return 0; + OPTION_CHOICE o; + + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_CONTEXT: + default_libctx = 0; + break; + case OPT_PROVIDER_NAME: + prov_name = opt_arg(); + break; + case OPT_CONFIG_FILE: + config_file = opt_arg(); + break; + case OPT_RSA_FILE: + rsa_file = opt_arg(); + break; + case OPT_RSA_PSS_FILE: + rsa_pss_file = opt_arg(); + break; + case OPT_TEST_CASES: + break; + default: + return 0; + } } - if (test_get_argument_count() != 2) { - TEST_error("usage: endecode_test %s", USAGE); - return 0; + + if (strcmp(prov_name, "fips") == 0) + is_fips = 1; + + if (default_libctx) { + if (!test_get_libctx(NULL, NULL, config_file, &deflprov, prov_name)) + return 0; + } else { + if (!test_get_libctx(&testctx, &nullprov, config_file, &deflprov, prov_name)) + return 0; } + /* Separate provider/ctx for generating the test data */ + if (!TEST_ptr(keyctx = OSSL_LIB_CTX_new())) + return 0; + if (!TEST_ptr(keyprov = OSSL_PROVIDER_load(keyctx, "default"))) + return 0; + #ifndef OPENSSL_NO_EC - if (!TEST_ptr(bnctx = BN_CTX_new_ex(NULL)) + if (!TEST_ptr(bnctx = BN_CTX_new_ex(testctx)) || !TEST_ptr(bld_prime_nc = OSSL_PARAM_BLD_new()) || !TEST_ptr(bld_prime = OSSL_PARAM_BLD_new()) || !create_ec_explicit_prime_params_namedcurve(bld_prime_nc) @@ -1267,9 +1355,9 @@ int setup_tests(void) MAKE_KEYS(X448, "X448", NULL); #endif TEST_info("Loading RSA key..."); - ok = ok && TEST_ptr(key_RSA = load_pkey_pem(test_get_argument(0), NULL)); + ok = ok && TEST_ptr(key_RSA = load_pkey_pem(rsa_file, keyctx)); TEST_info("Loading RSA_PSS key..."); - ok = ok && TEST_ptr(key_RSA_PSS = load_pkey_pem(test_get_argument(1), NULL)); + ok = ok && TEST_ptr(key_RSA_PSS = load_pkey_pem(rsa_pss_file, keyctx)); TEST_info("Generating keys done"); if (ok) { @@ -1290,9 +1378,7 @@ int setup_tests(void) ADD_TEST_SUITE_MSBLOB(DSA); ADD_TEST_SUITE_UNPROTECTED_PVK(DSA); # ifndef OPENSSL_NO_RC4 - if (use_legacy) { - ADD_TEST_SUITE_PROTECTED_PVK(DSA); - } + ADD_TEST_SUITE_PROTECTED_PVK(DSA); # endif #endif #ifndef OPENSSL_NO_EC @@ -1328,9 +1414,7 @@ int setup_tests(void) ADD_TEST_SUITE_MSBLOB(RSA); ADD_TEST_SUITE_UNPROTECTED_PVK(RSA); # ifndef OPENSSL_NO_RC4 - if (use_legacy) { - ADD_TEST_SUITE_PROTECTED_PVK(RSA); - } + ADD_TEST_SUITE_PROTECTED_PVK(RSA); # endif } @@ -1375,4 +1459,10 @@ void cleanup_tests(void) #endif FREE_KEYS(RSA); FREE_KEYS(RSA_PSS); + + OSSL_PROVIDER_unload(nullprov); + OSSL_PROVIDER_unload(deflprov); + OSSL_PROVIDER_unload(keyprov); + OSSL_LIB_CTX_free(testctx); + OSSL_LIB_CTX_free(keyctx); } diff --git a/test/evp_libctx_test.c b/test/evp_libctx_test.c index 5e8f436cca..f51de88c55 100644 --- a/test/evp_libctx_test.c +++ b/test/evp_libctx_test.c @@ -55,7 +55,7 @@ const OPTIONS *test_get_options(void) { "config", OPT_CONFIG_FILE, '<', "The configuration file to use for the libctx" }, { "provider", OPT_PROVIDER_NAME, 's', - "The provider to load (The default value is 'default'" }, + "The provider to load (The default value is 'default')" }, { NULL } }; return test_options; diff --git a/test/recipes/04-test_encoder_decoder.t b/test/recipes/04-test_encoder_decoder.t index 0152519716..19541610a9 100644 --- a/test/recipes/04-test_encoder_decoder.t +++ b/test/recipes/04-test_encoder_decoder.t @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -9,18 +9,43 @@ use strict; use warnings; -use OpenSSL::Test::Simple; -use OpenSSL::Test qw/:DEFAULT srctop_file bldtop_dir/; -use Cwd qw(abs_path); +use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file bldtop_dir bldtop_file/; +use OpenSSL::Test::Utils; -setup("test_encoder_decoder"); +BEGIN { + setup("test_encoder_decoder"); +} -plan tests => 1; +use lib srctop_dir('Configurations'); +use lib bldtop_dir('.'); +use platform; -$ENV{OPENSSL_MODULES} = abs_path(bldtop_dir("providers")); -$ENV{OPENSSL_CONF} = abs_path(srctop_file("test", "default-and-legacy.cnf")); +my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0); my $rsa_key = srctop_file("test", "certs", "ee-key.pem"); my $pss_key = srctop_file("test", "certs", "ca-pss-key.pem"); -ok(run(test(["endecode_test", $rsa_key, $pss_key]))); +plan tests => ($no_fips ? 0 : 1) + 2; # FIPS install test + test + +my $conf = srctop_file("test", "default.cnf"); +ok(run(test(["endecode_test", "-rsa", $rsa_key, + "-pss", $pss_key, + "-config", $conf, + "-provider", "default"]))); + +# Run with non-default library context +ok(run(test(["endecode_test", "-rsa", $rsa_key, + "-pss", $pss_key, + "-context", + "-config", $conf, + "-provider", "default"]))); + +unless ($no_fips) { + # Run with fips library context + my $conf = srctop_file("test", "fips-and-base.cnf"); + ok(run(test(["endecode_test", "-rsa", $rsa_key, + "-pss", $pss_key, + "-config", $conf, + "-provider", "fips"]))); +} + diff --git a/test/testutil.h b/test/testutil.h index 9311e2ce58..710f51c147 100644 --- a/test/testutil.h +++ b/test/testutil.h @@ -206,6 +206,13 @@ size_t test_get_argument_count(void); */ int test_skip_common_options(void); +/* + * Get a library context for the tests, populated with the specified provider + * and configuration. If default_null_prov is not NULL, a "null" provider is + * loaded into the default library context to prevent it being used. + * If libctx is NULL, the specified provider is loaded into the default library + * context. + */ int test_get_libctx(OSSL_LIB_CTX **libctx, OSSL_PROVIDER **default_null_prov, const char *config_file, OSSL_PROVIDER **provider, const char *module_name); diff --git a/test/testutil/provider.c b/test/testutil/provider.c index c50ef035fc..5a571bf5de 100644 --- a/test/testutil/provider.c +++ b/test/testutil/provider.c @@ -15,9 +15,13 @@ int test_get_libctx(OSSL_LIB_CTX **libctx, OSSL_PROVIDER **default_null_prov, const char *config_file, OSSL_PROVIDER **provider, const char *module_name) { - if ((*libctx = OSSL_LIB_CTX_new()) == NULL) { - opt_printf_stderr("Failed to create libctx\n"); - goto err; + OSSL_LIB_CTX *new_libctx = NULL; + + if (libctx != NULL) { + if ((new_libctx = *libctx = OSSL_LIB_CTX_new()) == NULL) { + opt_printf_stderr("Failed to create libctx\n"); + goto err; + } } if (default_null_prov != NULL @@ -27,13 +31,13 @@ int test_get_libctx(OSSL_LIB_CTX **libctx, OSSL_PROVIDER **default_null_prov, } if (config_file != NULL - && !OSSL_LIB_CTX_load_config(*libctx, config_file)) { + && !OSSL_LIB_CTX_load_config(new_libctx, config_file)) { opt_printf_stderr("Error loading config from file %s\n", config_file); goto err; } if (module_name != NULL - && (*provider = OSSL_PROVIDER_load(*libctx, module_name)) == NULL) { + && (*provider = OSSL_PROVIDER_load(new_libctx, module_name)) == NULL) { opt_printf_stderr("Failed to load provider %s\n", module_name); goto err; } diff --git a/util/libcrypto.num b/util/libcrypto.num index 1016d9c327..c7d89421a2 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5416,3 +5416,5 @@ OSSL_PROVIDER_get0_dispatch 5543 3_0_0 EXIST::FUNCTION: PKCS5_PBE_keyivgen_ex 5544 3_0_0 EXIST::FUNCTION: EVP_MAC_CTX_get_block_size 5545 3_0_0 EXIST::FUNCTION: BIO_debug_callback_ex 5546 3_0_0 EXIST::FUNCTION: +b2i_PVK_bio_ex 5547 3_0_0 EXIST::FUNCTION: +i2b_PVK_bio_ex 5548 3_0_0 EXIST::FUNCTION: diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt index 04eace5da7..df71963deb 100644 --- a/util/missingcrypto.txt +++ b/util/missingcrypto.txt @@ -1413,7 +1413,6 @@ a2i_ASN1_STRING(3) a2i_GENERAL_NAME(3) a2i_IPADDRESS(3) a2i_IPADDRESS_NC(3) -b2i_PVK_bio(3) b2i_PrivateKey(3) b2i_PrivateKey_bio(3) b2i_PublicKey(3) @@ -1429,7 +1428,6 @@ i2a_ASN1_ENUMERATED(3) i2a_ASN1_INTEGER(3) i2a_ASN1_OBJECT(3) i2a_ASN1_STRING(3) -i2b_PVK_bio(3) i2b_PrivateKey_bio(3) i2b_PublicKey_bio(3) i2d_X509_bio(3) -- cgit v1.2.3