Enhance the encoder/decoder tests to allow testing with a non-default library context and configurable providers

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14587)
This commit is contained in:
Jon Spillett 2021-03-15 14:26:09 +10:00 committed by Tomas Mraz
parent 8ee66a092c
commit 169eca602c
13 changed files with 335 additions and 93 deletions

View File

@ -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));
}
static int i2b_PVK(unsigned char **out, const EVP_PKEY *pk, int enclevel,
pem_password_cb *cb, void *u)
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, 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);
}

View File

@ -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 \

View File

@ -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 <openssl/pem.h>
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<BIO>. It
attempts to automatically determine the key type. If the key is encrypted then
I<cb> is called with the user data I<u> in order to obtain a password to decrypt
the key. The supplied library context I<libctx> and property query
string I<propq> 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<pk> using MSBLOB format. If I<enclevel> is 1 then
a password obtained via I<pem_password_cb> is used to encrypt the private key.
If I<enclevel> is 0 then no encryption is applied. The user data in I<u> is
passed to the password callback. The supplied library context I<libctx> and
property query string I<propq> 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<EVP_KEY>
structure or B<NULL> if an error occurs. The error code can be obtained by calling
L<ERR_get_error(3)>.
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<ERR_get_error(3)>.
=head1 SEE ALSO
L<crypto(7)>,
L<d2i_PKCS8PrivateKey_bio(3)>
=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<https://www.openssl.org/source/license.html>.
=cut

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}
if (test_get_argument_count() != 2) {
TEST_error("usage: endecode_test %s", USAGE);
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 (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);
}

View File

@ -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;

View File

@ -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"])));
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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:

View File

@ -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)