openssl/test/keymgmt_internal_test.c
Shane Lontis 96ebe52e89 Add EVP_PKEY_gettable_params support for accessing EVP_PKEY key data fields
Currently only RSA, EC and ECX are supported (DH and DSA need to be added to the keygen
PR's seperately because the fields supported have changed significantly).

The API's require the keys to be provider based.

Made the keymanagement export and get_params functions share the same code by supplying
support functions that work for both a OSSL_PARAM_BLD as well as a OSSL_PARAM[].
This approach means that complex code is not required to build an
empty OSSL_PARAM[] with the correct sized fields before then doing a second
pass to populate the array.

The RSA factor arrays have been changed to use unique key names to simplify the interface
needed by the user.

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11365)
2020-04-01 15:51:18 +10:00

266 lines
8.5 KiB
C

/*
* Copyright 2019 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/bio.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/provider.h>
#include <openssl/core_names.h>
#include "internal/core.h"
#include "internal/nelem.h"
#include "crypto/evp.h" /* For the internal API */
#include "testutil.h"
typedef struct {
OPENSSL_CTX *ctx1;
OSSL_PROVIDER *prov1;
OPENSSL_CTX *ctx2;
OSSL_PROVIDER *prov2;
} FIXTURE;
static void tear_down(FIXTURE *fixture)
{
if (fixture != NULL) {
OSSL_PROVIDER_unload(fixture->prov1);
OSSL_PROVIDER_unload(fixture->prov2);
OPENSSL_CTX_free(fixture->ctx1);
OPENSSL_CTX_free(fixture->ctx2);
OPENSSL_free(fixture);
}
}
static FIXTURE *set_up(const char *testcase_name)
{
FIXTURE *fixture;
if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture)))
|| !TEST_ptr(fixture->ctx1 = OPENSSL_CTX_new())
|| !TEST_ptr(fixture->prov1 = OSSL_PROVIDER_load(fixture->ctx1,
"default"))
|| !TEST_ptr(fixture->ctx2 = OPENSSL_CTX_new())
|| !TEST_ptr(fixture->prov2 = OSSL_PROVIDER_load(fixture->ctx2,
"default"))) {
tear_down(fixture);
return NULL;
}
return fixture;
}
/* Array indexes */
#define N 0
#define E 1
#define D 2
#define P 3
#define Q 4
#define F3 5 /* Extra factor */
#define DP 6
#define DQ 7
#define E3 8 /* Extra exponent */
#define QINV 9
#define C2 10 /* Extra coefficient */
/*
* We have to do this because OSSL_PARAM_get_ulong() can't handle params
* holding data that isn't exactly sizeof(uint32_t) or sizeof(uint64_t),
* and because the other end deals with BIGNUM, the resulting param might
* be any size. In this particular test, we know that the expected data
* fits within an unsigned long, and we want to get the data in that form
* to make testing of values easier.
*/
static int get_ulong_via_BN(const OSSL_PARAM *p, unsigned long *goal)
{
BIGNUM *n = NULL;
int ret = 1; /* Ever so hopeful */
if (!TEST_true(OSSL_PARAM_get_BN(p, &n))
|| !TEST_true(BN_bn2nativepad(n, (unsigned char *)goal, sizeof(*goal))))
ret = 0;
BN_free(n);
return ret;
}
static int export_cb(const OSSL_PARAM *params, void *arg)
{
unsigned long *keydata = arg;
const OSSL_PARAM *p = NULL;
if (keydata == NULL)
return 0;
if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N))
|| !TEST_true(get_ulong_via_BN(p, &keydata[N]))
|| !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E))
|| !TEST_true(get_ulong_via_BN(p, &keydata[E]))
|| !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D))
|| !TEST_true(get_ulong_via_BN(p, &keydata[D])))
return 0;
if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR1))
|| !TEST_true(get_ulong_via_BN(p, &keydata[P]))
|| !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR2))
|| !TEST_true(get_ulong_via_BN(p, &keydata[Q]))
|| !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR3))
|| !TEST_true(get_ulong_via_BN(p, &keydata[F3])))
return 0;
if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT1))
|| !TEST_true(get_ulong_via_BN(p, &keydata[DP]))
|| !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT2))
|| !TEST_true(get_ulong_via_BN(p, &keydata[DQ]))
|| !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT3))
|| !TEST_true(get_ulong_via_BN(p, &keydata[E3])))
return 0;
if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_COEFFICIENT1))
|| !TEST_true(get_ulong_via_BN(p, &keydata[QINV]))
|| !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_COEFFICIENT2))
|| !TEST_true(get_ulong_via_BN(p, &keydata[C2])))
return 0;
return 1;
}
static int test_pass_rsa(FIXTURE *fixture)
{
size_t i;
int ret = 0;
RSA *rsa = NULL;
BIGNUM *bn1 = NULL, *bn2 = NULL, *bn3 = NULL;
EVP_PKEY *pk = NULL;
EVP_KEYMGMT *km1 = NULL, *km2 = NULL;
void *provkey = NULL;
BIGNUM *bn_primes[1] = { NULL };
BIGNUM *bn_exps[1] = { NULL };
BIGNUM *bn_coeffs[1] = { NULL };
/*
* 32-bit RSA key, extracted from this command,
* executed with OpenSSL 1.0.2:
* An extra factor was added just for testing purposes.
*
* openssl genrsa 32 | openssl rsa -text
*/
static BN_ULONG expected[] = {
0xbc747fc5, /* N */
0x10001, /* E */
0x7b133399, /* D */
0xe963, /* P */
0xceb7, /* Q */
1, /* F3 */
0x8599, /* DP */
0xbd87, /* DQ */
2, /* E3 */
0xcc3b, /* QINV */
3, /* C3 */
0 /* Extra, should remain zero */
};
static unsigned long keydata[OSSL_NELEM(expected)] = { 0, };
if (!TEST_ptr(rsa = RSA_new()))
goto err;
if (!TEST_ptr(bn1 = BN_new())
|| !TEST_true(BN_set_word(bn1, expected[N]))
|| !TEST_ptr(bn2 = BN_new())
|| !TEST_true(BN_set_word(bn2, expected[E]))
|| !TEST_ptr(bn3 = BN_new())
|| !TEST_true(BN_set_word(bn3, expected[D]))
|| !TEST_true(RSA_set0_key(rsa, bn1, bn2, bn3)))
goto err;
if (!TEST_ptr(bn1 = BN_new())
|| !TEST_true(BN_set_word(bn1, expected[P]))
|| !TEST_ptr(bn2 = BN_new())
|| !TEST_true(BN_set_word(bn2, expected[Q]))
|| !TEST_true(RSA_set0_factors(rsa, bn1, bn2)))
goto err;
if (!TEST_ptr(bn1 = BN_new())
|| !TEST_true(BN_set_word(bn1, expected[DP]))
|| !TEST_ptr(bn2 = BN_new())
|| !TEST_true(BN_set_word(bn2, expected[DQ]))
|| !TEST_ptr(bn3 = BN_new())
|| !TEST_true(BN_set_word(bn3, expected[QINV]))
|| !TEST_true(RSA_set0_crt_params(rsa, bn1, bn2, bn3)))
goto err;
bn1 = bn2 = bn3 = NULL;
if (!TEST_ptr(bn_primes[0] = BN_new())
|| !TEST_true(BN_set_word(bn_primes[0], expected[F3]))
|| !TEST_ptr(bn_exps[0] = BN_new())
|| !TEST_true(BN_set_word(bn_exps[0], expected[E3]))
|| !TEST_ptr(bn_coeffs[0] = BN_new())
|| !TEST_true(BN_set_word(bn_coeffs[0], expected[C2]))
|| !TEST_true(RSA_set0_multi_prime_params(rsa, bn_primes, bn_exps,
bn_coeffs, 1)))
goto err;
if (!TEST_ptr(pk = EVP_PKEY_new())
|| !TEST_true(EVP_PKEY_assign_RSA(pk, rsa)))
goto err;
rsa = NULL;
if (!TEST_ptr(km1 = EVP_KEYMGMT_fetch(fixture->ctx1, "RSA", NULL))
|| !TEST_ptr(km2 = EVP_KEYMGMT_fetch(fixture->ctx2, "RSA", NULL))
|| !TEST_ptr_ne(km1, km2))
goto err;
if (!TEST_ptr(provkey = evp_pkey_export_to_provider(pk, NULL, &km1, NULL))
|| !TEST_true(evp_keymgmt_export(km2, provkey,
OSSL_KEYMGMT_SELECT_KEYPAIR,
&export_cb, keydata)))
goto err;
/*
* At this point, the hope is that keydata will have all the numbers
* from the key.
*/
for (i = 0; i < OSSL_NELEM(expected); i++) {
int rv = TEST_int_eq(expected[i], keydata[i]);
if (!rv)
TEST_info("i = %zu", i);
else
ret++;
}
ret = (ret == OSSL_NELEM(expected));
err:
RSA_free(rsa);
BN_free(bn1);
BN_free(bn2);
BN_free(bn3);
EVP_PKEY_free(pk);
EVP_KEYMGMT_free(km1);
EVP_KEYMGMT_free(km2);
return ret;
}
static int (*tests[])(FIXTURE *) = {
test_pass_rsa
};
static int test_pass_key(int n)
{
SETUP_TEST_FIXTURE(FIXTURE, set_up);
EXECUTE_TEST(tests[n], tear_down);
return result;
}
int setup_tests(void)
{
ADD_ALL_TESTS(test_pass_key, 1);
return 1;
}