/*
* Copyright 2020 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
* https://www.openssl.org/source/license.html
*/
#include <string.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/params.h>
#include <openssl/encoder.h>
#include <openssl/decoder.h>
#include "internal/pem.h" /* For PVK and "blob" PEM headers */
#include "internal/cryptlib.h" /* ossl_assert */
#include "testutil.h"
/*
* TODO(3.0) Modify PEM_write_bio_PrivateKey_traditional() to handle
* provider side EVP_PKEYs (which don't necessarily have an ameth)
*
* In the mean time, we use separate "downgraded" EVP_PKEYs to test
* encoding/decoding with "traditional" keys.
*/
static EVP_PKEY *make_template(const char *type, OSSL_PARAM *genparams)
{
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, type, NULL);
/*
* No real need to check the errors other than for the cascade
* effect. |pkey| will simply remain NULL if something goes wrong.
*/
(void)(ctx != NULL
&& EVP_PKEY_paramgen_init(ctx) > 0
&& (genparams == NULL
|| EVP_PKEY_CTX_set_params(ctx, genparams) > 0)
&& EVP_PKEY_gen(ctx, &pkey) > 0);
EVP_PKEY_CTX_free(ctx);
return pkey;
}
static EVP_PKEY *make_key(const char *type, EVP_PKEY *template,
OSSL_PARAM *genparams, int make_legacy)
{
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);
/*
* No real need to check the errors other than for the cascade
* effect. |pkey| will simply remain NULL if something goes wrong.
*/
(void)(ctx != NULL
&& EVP_PKEY_keygen_init(ctx) > 0
&& (genparams == NULL
|| EVP_PKEY_CTX_set_params(ctx, genparams) > 0)
&& EVP_PKEY_keygen(ctx, &pkey) > 0);
EVP_PKEY_CTX_free(ctx);
if (make_legacy && EVP_PKEY_get0(pkey) == NULL) {
EVP_PKEY_free(pkey);
pkey = NULL;
}
return pkey;
}
/* Main test driver */
/*
* TODO(3.0) For better error output, changed the callbacks to take __FILE__
* and __LINE__ as first two arguments, and have them use the lower case
* functions, such as test_strn_eq(), rather than the uppercase macros
* (TEST_strn2_eq(), for example).
*/
typedef int (encoder)(void **encoded, long *encoded_len,
void *object, const char *pass, const char *pcipher,
const char *encoder_propq);
typedef int (decoder)(void **object,
void *encoded, long encoded_len,
const char *pass);
typedef int (tester)(const void *data1, size_t data1_len,
const void *data2, size_t data2_len);
typedef int (checker)(const char *type, const void *data, size_t data_len);
typedef void (dumper)(const char *label, const void *data, size_t data_len);
static int test_encode_decode(const char *type, EVP_PKEY *pkey,
const char *pass, const char *pcipher,
encoder *encode_cb,
decoder *decode_cb,
tester *test_cb,
checker *check_cb, dumper *dump_cb,
const char *encoder_propq, int make_legacy)
{
void *encoded = NULL;
long encoded_len = 0;
EVP_PKEY *pkey2 = NULL;
void *encoded2 = NULL;
long encoded2_len = 0;
int ok = 0;
if (!encode_cb(&encoded, &encoded_len, pkey,
pass, pcipher, encoder_propq)
|| !check_cb(type, encoded, encoded_len)
|| !decode_cb((void **)&pkey2, encoded, encoded_len,
pass)
|| !TEST_int_eq(EVP_PKEY_eq(pkey, pkey2), 1))
goto end;
/*
* TODO(3.0) Remove this when PEM_write_bio_PrivateKey_traditional()
* handles provider side keys.
*/
if (make_legacy
&& !TEST_ptr(EVP_PKEY_get0(pkey2)))
goto end;
/*
* Double check the encoding, but only for unprotected keys,
* as protected keys have a random component, which makes the output
* differ.
*/
if ((pass == NULL && pcipher == NULL)
&& (!encode_cb(&encoded2, &encoded2_len, pkey2,
pass, pcipher, encoder_propq)
|| !test_cb(encoded, encoded_len,
encoded2, encoded2_len)))
goto end;
ok = 1;
end:
if (!ok) {
if (encoded !=