mirror of
https://github.com/openssl/openssl.git
synced 2024-12-03 05:41:46 +08:00
1640d48c5b
Exporting data from a provider owned domainparams or key is quite an ordeal, with having to figure out what parameter keys an implementation supports, call the export function a first time to find out how large each parameter buffer must be, allocate the necessary space for it, and call the export function again. So how about letting the export function build up the key data params and call back with that? This change implements exactly such a mechanism. Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/10414)
261 lines
7.9 KiB
C
261 lines
7.9 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 C3 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;
|
|
int factors_idx;
|
|
int exponents_idx;
|
|
int coefficients_idx;
|
|
int ret = 1; /* Ever so hopeful */
|
|
|
|
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])))
|
|
ret = 0;
|
|
|
|
for (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR),
|
|
factors_idx = P;
|
|
p != NULL && factors_idx <= F3;
|
|
p = OSSL_PARAM_locate_const(p + 1, OSSL_PKEY_PARAM_RSA_FACTOR),
|
|
factors_idx++)
|
|
if (!TEST_true(get_ulong_via_BN(p, &keydata[factors_idx])))
|
|
ret = 0;
|
|
for (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT),
|
|
exponents_idx = DP;
|
|
p != NULL && exponents_idx <= E3;
|
|
p = OSSL_PARAM_locate_const(p + 1, OSSL_PKEY_PARAM_RSA_EXPONENT),
|
|
exponents_idx++)
|
|
if (!TEST_true(get_ulong_via_BN(p, &keydata[exponents_idx])))
|
|
ret = 0;
|
|
for (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_COEFFICIENT),
|
|
coefficients_idx = QINV;
|
|
p != NULL && coefficients_idx <= C3;
|
|
p = OSSL_PARAM_locate_const(p + 1, OSSL_PKEY_PARAM_RSA_COEFFICIENT),
|
|
coefficients_idx++)
|
|
if (!TEST_true(get_ulong_via_BN(p, &keydata[coefficients_idx])))
|
|
ret = 0;
|
|
|
|
if (!TEST_int_le(factors_idx, F3)
|
|
|| !TEST_int_le(exponents_idx, E3)
|
|
|| !TEST_int_le(coefficients_idx, C3))
|
|
ret = 0;
|
|
return ret;
|
|
}
|
|
|
|
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 *provdata = NULL;
|
|
/*
|
|
* 32-bit RSA key, extracted from this command,
|
|
* executed with OpenSSL 1.0.2:
|
|
*
|
|
* openssl genrsa 32 | openssl rsa -text
|
|
*/
|
|
static BN_ULONG expected[] = {
|
|
0xbc747fc5, /* N */
|
|
0x10001, /* E */
|
|
0x7b133399, /* D */
|
|
0xe963, /* P */
|
|
0xceb7, /* Q */
|
|
0, /* F3 */
|
|
0x8599, /* DP */
|
|
0xbd87, /* DQ */
|
|
0, /* E3 */
|
|
0xcc3b, /* QINV */
|
|
0, /* 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(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(evp_keymgmt_export_to_provider(pk, km1, 0))
|
|
|| !TEST_ptr(provdata = evp_keymgmt_export_to_provider(pk, km2, 0)))
|
|
goto err;
|
|
|
|
if (!TEST_true(evp_keymgmt_exportkey(km2, provdata, &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;
|
|
}
|