Latest update.

This commit is contained in:
2020-03-03 19:16:19 +09:00
parent f85de4da03
commit b412d79e8b
310 changed files with 32765 additions and 19720 deletions
@@ -3,6 +3,7 @@
$DH_GOAL=../../libimplementations.a
$ECX_GOAL=../../libimplementations.a
$ECDH_GOAL=../../libimplementations.a
IF[{- !$disabled{dh} -}]
SOURCE[$DH_GOAL]=dh_exch.c
@@ -21,4 +22,5 @@ ENDIF
IF[{- !$disabled{ec} -}]
SOURCE[$ECX_GOAL]=ecx_exch.c
DEFINE[$ECX_GOAL]=$ECDEF
SOURCE[$ECDH_GOAL]=ecdh_exch.c
ENDIF
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* DH low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/crypto.h>
#include <openssl/core_numbers.h>
#include <openssl/core_names.h>
@@ -0,0 +1,533 @@
/*
* 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
*/
/*
* ECDH low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/core_numbers.h>
#include <openssl/core_names.h>
#include <openssl/ec.h>
#include <openssl/params.h>
#include <openssl/err.h>
#include "prov/provider_ctx.h"
#include "prov/implementations.h"
#include "crypto/ec.h" /* ecdh_KDF_X9_63() */
static OSSL_OP_keyexch_newctx_fn ecdh_newctx;
static OSSL_OP_keyexch_init_fn ecdh_init;
static OSSL_OP_keyexch_set_peer_fn ecdh_set_peer;
static OSSL_OP_keyexch_derive_fn ecdh_derive;
static OSSL_OP_keyexch_freectx_fn ecdh_freectx;
static OSSL_OP_keyexch_dupctx_fn ecdh_dupctx;
static OSSL_OP_keyexch_set_ctx_params_fn ecdh_set_ctx_params;
static OSSL_OP_keyexch_settable_ctx_params_fn ecdh_settable_ctx_params;
static OSSL_OP_keyexch_get_ctx_params_fn ecdh_get_ctx_params;
static OSSL_OP_keyexch_gettable_ctx_params_fn ecdh_gettable_ctx_params;
enum kdf_type {
PROV_ECDH_KDF_NONE = 0,
PROV_ECDH_KDF_X9_63
};
/*
* What's passed as an actual key is defined by the KEYMGMT interface.
* We happen to know that our KEYMGMT simply passes EC_KEY structures, so
* we use that here too.
*/
typedef struct {
OPENSSL_CTX *libctx;
EC_KEY *k;
EC_KEY *peerk;
/*
* ECDH cofactor mode:
*
* . 0 disabled
* . 1 enabled
* . -1 use cofactor mode set for k
*/
int cofactor_mode;
/************
* ECDH KDF *
************/
/* KDF (if any) to use for ECDH */
enum kdf_type kdf_type;
/* Message digest to use for key derivation */
EVP_MD *kdf_md;
/* User key material */
unsigned char *kdf_ukm;
size_t kdf_ukmlen;
/* KDF output length */
size_t kdf_outlen;
} PROV_ECDH_CTX;
static
void *ecdh_newctx(void *provctx)
{
PROV_ECDH_CTX *pectx = OPENSSL_zalloc(sizeof(*pectx));
if (pectx == NULL)
return NULL;
pectx->libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
pectx->cofactor_mode = -1;
pectx->kdf_type = PROV_ECDH_KDF_NONE;
return (void *)pectx;
}
static
int ecdh_init(void *vpecdhctx, void *vecdh)
{
PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
if (pecdhctx == NULL || vecdh == NULL || !EC_KEY_up_ref(vecdh))
return 0;
EC_KEY_free(pecdhctx->k);
pecdhctx->k = vecdh;
pecdhctx->cofactor_mode = -1;
pecdhctx->kdf_type = PROV_ECDH_KDF_NONE;
return 1;
}
static
int ecdh_set_peer(void *vpecdhctx, void *vecdh)
{
PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
if (pecdhctx == NULL || vecdh == NULL || !EC_KEY_up_ref(vecdh))
return 0;
EC_KEY_free(pecdhctx->peerk);
pecdhctx->peerk = vecdh;
return 1;
}
static
void ecdh_freectx(void *vpecdhctx)
{
PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
EC_KEY_free(pecdhctx->k);
EC_KEY_free(pecdhctx->peerk);
EVP_MD_free(pecdhctx->kdf_md);
OPENSSL_clear_free(pecdhctx->kdf_ukm, pecdhctx->kdf_ukmlen);
OPENSSL_free(pecdhctx);
}
static
void *ecdh_dupctx(void *vpecdhctx)
{
PROV_ECDH_CTX *srcctx = (PROV_ECDH_CTX *)vpecdhctx;
PROV_ECDH_CTX *dstctx;
dstctx = OPENSSL_zalloc(sizeof(*srcctx));
if (dstctx == NULL)
return NULL;
*dstctx = *srcctx;
/* clear all pointers */
dstctx->k= NULL;
dstctx->peerk = NULL;
dstctx->kdf_md = NULL;
dstctx->kdf_ukm = NULL;
/* up-ref all ref-counted objects referenced in dstctx */
if (srcctx->k != NULL && !EC_KEY_up_ref(srcctx->k))
goto err;
else
dstctx->k = srcctx->k;
if (srcctx->peerk != NULL && !EC_KEY_up_ref(srcctx->peerk))
goto err;
else
dstctx->peerk = srcctx->peerk;
if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md))
goto err;
else
dstctx->kdf_md = srcctx->kdf_md;
/* Duplicate UKM data if present */
if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) {
dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm,
srcctx->kdf_ukmlen);
if (dstctx->kdf_ukm == NULL)
goto err;
}
return dstctx;
err:
ecdh_freectx(dstctx);
return NULL;
}
static
int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[])
{
char name[80] = { '\0' }; /* should be big enough */
char *str = NULL;
PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
const OSSL_PARAM *p;
if (pectx == NULL || params == NULL)
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE);
if (p != NULL) {
int mode;
if (!OSSL_PARAM_get_int(p, &mode))
return 0;
if (mode < -1 || mode > 1)
return 0;
pectx->cofactor_mode = mode;
}
p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
if (p != NULL) {
str = name;
if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
return 0;
if (name[0] == '\0')
pectx->kdf_type = PROV_ECDH_KDF_NONE;
else if (strcmp(name, OSSL_KDF_NAME_X963KDF) == 0)
pectx->kdf_type = PROV_ECDH_KDF_X9_63;
else
return 0;
}
p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
if (p != NULL) {
char mdprops[80] = { '\0' }; /* should be big enough */
str = name;
if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
return 0;
str = mdprops;
p = OSSL_PARAM_locate_const(params,
OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS);
if (p != NULL) {
if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))
return 0;
}
EVP_MD_free(pectx->kdf_md);
pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops);
if (pectx->kdf_md == NULL)
return 0;
}
p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
if (p != NULL) {
size_t outlen;
if (!OSSL_PARAM_get_size_t(p, &outlen))
return 0;
pectx->kdf_outlen = outlen;
}
p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
if (p != NULL) {
void *tmp_ukm = NULL;
size_t tmp_ukmlen;
if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen))
return 0;
OPENSSL_free(pectx->kdf_ukm);
pectx->kdf_ukm = tmp_ukm;
pectx->kdf_ukmlen = tmp_ukmlen;
}
return 1;
}
static const OSSL_PARAM known_settable_ctx_params[] = {
OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL),
OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0),
OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0),
OSSL_PARAM_END
};
static
const OSSL_PARAM *ecdh_settable_ctx_params(void)
{
return known_settable_ctx_params;
}
static
int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[])
{
PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
OSSL_PARAM *p;
if (pectx == NULL || params == NULL)
return 0;
p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE);
if (p != NULL) {
int mode = pectx->cofactor_mode;
if (mode == -1) {
/* check what is the default for pecdhctx->k */
mode = EC_KEY_get_flags(pectx->k) & EC_FLAG_COFACTOR_ECDH ? 1 : 0;
}
if (!OSSL_PARAM_set_int(p, mode))
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
if (p != NULL) {
const char *kdf_type = NULL;
switch (pectx->kdf_type) {
case PROV_ECDH_KDF_NONE:
kdf_type = "";
break;
case PROV_ECDH_KDF_X9_63:
kdf_type = OSSL_KDF_NAME_X963KDF;
break;
default:
return 0;
}
if (!OSSL_PARAM_set_utf8_string(p, kdf_type))
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
if (p != NULL
&& !OSSL_PARAM_set_utf8_string(p, pectx->kdf_md == NULL
? ""
: EVP_MD_name(pectx->kdf_md))){
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, pectx->kdf_outlen))
return 0;
p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
if (p != NULL && !OSSL_PARAM_set_octet_ptr(p, pectx->kdf_ukm, 0))
return 0;
p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM_LEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, pectx->kdf_ukmlen))
return 0;
return 1;
}
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL),
OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR,
NULL, 0),
OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_UKM_LEN, NULL),
OSSL_PARAM_END
};
static
const OSSL_PARAM *ecdh_gettable_ctx_params(void)
{
return known_gettable_ctx_params;
}
static ossl_inline
size_t ecdh_size(const EC_KEY *k)
{
size_t degree = 0;
const EC_GROUP *group;
if (k == NULL
|| (group = EC_KEY_get0_group(k)) == NULL)
return 0;
degree = EC_GROUP_get_degree(group);
return (degree + 7) / 8;
}
static ossl_inline
int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret,
size_t *psecretlen, size_t outlen)
{
PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
int retlen, ret = 0;
size_t ecdhsize, size;
const EC_POINT *ppubkey = NULL;
EC_KEY *privk = NULL;
const EC_GROUP *group;
const BIGNUM *cofactor;
int key_cofactor_mode;
if (pecdhctx->k == NULL || pecdhctx->peerk == NULL) {
ERR_raise(ERR_LIB_PROV, EC_R_KEYS_NOT_SET);
return 0;
}
ecdhsize = ecdh_size(pecdhctx->k);
if (secret == NULL) {
*psecretlen = ecdhsize;
return 1;
}
if ((group = EC_KEY_get0_group(pecdhctx->k)) == NULL
|| (cofactor = EC_GROUP_get0_cofactor(group)) == NULL )
return 0;
/*
* NB: unlike PKCS#3 DH, if outlen is less than maximum size this is not
* an error, the result is truncated.
*/
size = outlen < ecdhsize ? outlen : ecdhsize;
/*
* The ctx->cofactor_mode flag has precedence over the
* cofactor_mode flag set on ctx->k.
*
* - if ctx->cofactor_mode == -1, use ctx->k directly
* - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly
* - if ctx->cofactor_mode != key_cofactor_mode:
* - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use
* ctx->k directly
* - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag
* set to ctx->cofactor_mode
*/
key_cofactor_mode =
(EC_KEY_get_flags(pecdhctx->k) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0;
if (pecdhctx->cofactor_mode != -1
&& pecdhctx->cofactor_mode != key_cofactor_mode
&& !BN_is_one(cofactor)) {
if ((privk = EC_KEY_dup(pecdhctx->k)) == NULL)
return 0;
if (pecdhctx->cofactor_mode == 1)
EC_KEY_set_flags(privk, EC_FLAG_COFACTOR_ECDH);
else
EC_KEY_clear_flags(privk, EC_FLAG_COFACTOR_ECDH);
} else {
privk = pecdhctx->k;
}
ppubkey = EC_KEY_get0_public_key(pecdhctx->peerk);
retlen = ECDH_compute_key(secret, size, ppubkey, privk, NULL);
if (retlen <= 0)
goto end;
*psecretlen = retlen;
ret = 1;
end:
if (privk != pecdhctx->k)
EC_KEY_free(privk);
return ret;
}
static ossl_inline
int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret,
size_t *psecretlen, size_t outlen)
{
PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
unsigned char *stmp = NULL;
size_t stmplen;
int ret = 0;
if (secret == NULL) {
*psecretlen = pecdhctx->kdf_outlen;
return 1;
}
if (pecdhctx->kdf_outlen > outlen)
return 0;
if (!ecdh_plain_derive(vpecdhctx, NULL, &stmplen, 0))
return 0;
if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL) {
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return 0;
}
if (!ecdh_plain_derive(vpecdhctx, stmp, &stmplen, stmplen))
goto err;
/* Do KDF stuff */
if (!ecdh_KDF_X9_63(secret, pecdhctx->kdf_outlen,
stmp, stmplen,
pecdhctx->kdf_ukm,
pecdhctx->kdf_ukmlen,
pecdhctx->kdf_md))
goto err;
*psecretlen = pecdhctx->kdf_outlen;
ret = 1;
err:
OPENSSL_secure_clear_free(stmp, stmplen);
return ret;
}
static
int ecdh_derive(void *vpecdhctx, unsigned char *secret,
size_t *psecretlen, size_t outlen)
{
PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
switch (pecdhctx->kdf_type) {
case PROV_ECDH_KDF_NONE:
return ecdh_plain_derive(vpecdhctx, secret, psecretlen, outlen);
case PROV_ECDH_KDF_X9_63:
return ecdh_X9_63_kdf_derive(vpecdhctx, secret, psecretlen, outlen);
}
return 0;
}
const OSSL_DISPATCH ecdh_keyexch_functions[] = {
{ OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdh_newctx },
{ OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdh_init },
{ OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdh_derive },
{ OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecdh_set_peer },
{ OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecdh_freectx },
{ OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecdh_dupctx },
{ OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))ecdh_set_ctx_params },
{ OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
(void (*)(void))ecdh_settable_ctx_params },
{ OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))ecdh_get_ctx_params },
{ OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,
(void (*)(void))ecdh_gettable_ctx_params },
{ 0, NULL }
};
@@ -259,14 +259,17 @@ extern const OSSL_DISPATCH dsa_keymgmt_functions[];
extern const OSSL_DISPATCH rsa_keymgmt_functions[];
extern const OSSL_DISPATCH x25519_keymgmt_functions[];
extern const OSSL_DISPATCH x448_keymgmt_functions[];
extern const OSSL_DISPATCH ec_keymgmt_functions[];
/* Key Exchange */
extern const OSSL_DISPATCH dh_keyexch_functions[];
extern const OSSL_DISPATCH x25519_keyexch_functions[];
extern const OSSL_DISPATCH x448_keyexch_functions[];
extern const OSSL_DISPATCH ecdh_keyexch_functions[];
/* Signature */
extern const OSSL_DISPATCH dsa_signature_functions[];
extern const OSSL_DISPATCH rsa_signature_functions[];
/* Asym Cipher */
extern const OSSL_DISPATCH rsa_asym_cipher_functions[];
@@ -278,6 +281,7 @@ extern const OSSL_DISPATCH rsa_priv_der_serializer_functions[];
extern const OSSL_DISPATCH rsa_pub_der_serializer_functions[];
extern const OSSL_DISPATCH rsa_priv_pem_serializer_functions[];
extern const OSSL_DISPATCH rsa_pub_pem_serializer_functions[];
extern const OSSL_DISPATCH dh_priv_text_serializer_functions[];
extern const OSSL_DISPATCH dh_pub_text_serializer_functions[];
extern const OSSL_DISPATCH dh_param_text_serializer_functions[];
@@ -287,6 +291,7 @@ extern const OSSL_DISPATCH dh_param_der_serializer_functions[];
extern const OSSL_DISPATCH dh_priv_pem_serializer_functions[];
extern const OSSL_DISPATCH dh_pub_pem_serializer_functions[];
extern const OSSL_DISPATCH dh_param_pem_serializer_functions[];
extern const OSSL_DISPATCH dsa_priv_text_serializer_functions[];
extern const OSSL_DISPATCH dsa_pub_text_serializer_functions[];
extern const OSSL_DISPATCH dsa_param_text_serializer_functions[];
@@ -296,3 +301,17 @@ extern const OSSL_DISPATCH dsa_param_der_serializer_functions[];
extern const OSSL_DISPATCH dsa_priv_pem_serializer_functions[];
extern const OSSL_DISPATCH dsa_pub_pem_serializer_functions[];
extern const OSSL_DISPATCH dsa_param_pem_serializer_functions[];
extern const OSSL_DISPATCH x25519_priv_print_serializer_functions[];
extern const OSSL_DISPATCH x25519_pub_print_serializer_functions[];
extern const OSSL_DISPATCH x25519_priv_der_serializer_functions[];
extern const OSSL_DISPATCH x25519_pub_der_serializer_functions[];
extern const OSSL_DISPATCH x25519_priv_pem_serializer_functions[];
extern const OSSL_DISPATCH x25519_pub_pem_serializer_functions[];
extern const OSSL_DISPATCH x448_priv_print_serializer_functions[];
extern const OSSL_DISPATCH x448_pub_print_serializer_functions[];
extern const OSSL_DISPATCH x448_priv_der_serializer_functions[];
extern const OSSL_DISPATCH x448_pub_der_serializer_functions[];
extern const OSSL_DISPATCH x448_priv_pem_serializer_functions[];
extern const OSSL_DISPATCH x448_pub_pem_serializer_functions[];
@@ -3,6 +3,7 @@
$DH_GOAL=../../libimplementations.a
$DSA_GOAL=../../libimplementations.a
$EC_GOAL=../../libimplementations.a
$RSA_GOAL=../../libimplementations.a
$ECX_GOAL=../../libimplementations.a
@@ -12,6 +13,9 @@ ENDIF
IF[{- !$disabled{dsa} -}]
SOURCE[$DSA_GOAL]=dsa_kmgmt.c
ENDIF
IF[{- !$disabled{ec} -}]
SOURCE[$EC_GOAL]=ec_kmgmt.c
ENDIF
SOURCE[$RSA_GOAL]=rsa_kmgmt.c
IF[{- !$disabled{ec} -}]
SOURCE[$ECX_GOAL]=ecx_kmgmt.c
+28 -1
View File
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* DH low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/core_numbers.h>
#include <openssl/core_names.h>
#include <openssl/bn.h>
@@ -23,6 +29,7 @@ static OSSL_OP_keymgmt_free_fn dh_freedata;
static OSSL_OP_keymgmt_get_params_fn dh_get_params;
static OSSL_OP_keymgmt_gettable_params_fn dh_gettable_params;
static OSSL_OP_keymgmt_has_fn dh_has;
static OSSL_OP_keymgmt_match_fn dh_match;
static OSSL_OP_keymgmt_import_fn dh_import;
static OSSL_OP_keymgmt_import_types_fn dh_import_types;
static OSSL_OP_keymgmt_export_fn dh_export;
@@ -111,7 +118,7 @@ static int params_to_key(DH *dh, const OSSL_PARAM params[])
return 1;
err:
BN_free(priv_key);
BN_clear_free(priv_key);
BN_free(pub_key);
return 0;
}
@@ -163,6 +170,25 @@ static int dh_has(void *keydata, int selection)
return ok;
}
static int dh_match(const void *keydata1, const void *keydata2, int selection)
{
const DH *dh1 = keydata1;
const DH *dh2 = keydata2;
int ok = 1;
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
ok = ok && BN_cmp(DH_get0_pub_key(dh1), DH_get0_pub_key(dh2)) == 0;
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
ok = ok && BN_cmp(DH_get0_priv_key(dh1), DH_get0_priv_key(dh2)) == 0;
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
FFC_PARAMS *dhparams1 = dh_get0_params((DH *)dh1);
FFC_PARAMS *dhparams2 = dh_get0_params((DH *)dh2);
ok = ok && ffc_params_cmp(dhparams1, dhparams2, 1);
}
return ok;
}
static int dh_import(void *keydata, int selection, const OSSL_PARAM params[])
{
DH *dh = keydata;
@@ -296,6 +322,7 @@ const OSSL_DISPATCH dh_keymgmt_functions[] = {
{ OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params },
{ OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params },
{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dh_has },
{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dh_match },
{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dh_import },
{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dh_import_types },
{ OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dh_export },
+24 -1
View File
@@ -29,6 +29,7 @@ static OSSL_OP_keymgmt_free_fn dsa_freedata;
static OSSL_OP_keymgmt_get_params_fn dsa_get_params;
static OSSL_OP_keymgmt_gettable_params_fn dsa_gettable_params;
static OSSL_OP_keymgmt_has_fn dsa_has;
static OSSL_OP_keymgmt_match_fn dsa_match;
static OSSL_OP_keymgmt_import_fn dsa_import;
static OSSL_OP_keymgmt_import_types_fn dsa_import_types;
static OSSL_OP_keymgmt_export_fn dsa_export;
@@ -123,7 +124,7 @@ static int params_to_key(DSA *dsa, const OSSL_PARAM params[])
return 1;
err:
BN_free(priv_key);
BN_clear_free(priv_key);
BN_free(pub_key);
return 0;
}
@@ -175,6 +176,27 @@ static int dsa_has(void *keydata, int selection)
return ok;
}
static int dsa_match(const void *keydata1, const void *keydata2, int selection)
{
const DSA *dsa1 = keydata1;
const DSA *dsa2 = keydata2;
int ok = 1;
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
ok = ok
&& BN_cmp(DSA_get0_pub_key(dsa1), DSA_get0_pub_key(dsa2)) == 0;
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
ok = ok
&& BN_cmp(DSA_get0_priv_key(dsa1), DSA_get0_priv_key(dsa2)) == 0;
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
FFC_PARAMS *dsaparams1 = dsa_get0_params((DSA *)dsa1);
FFC_PARAMS *dsaparams2 = dsa_get0_params((DSA *)dsa2);
ok = ok && ffc_params_cmp(dsaparams1, dsaparams2, 1);
}
return ok;
}
static int dsa_import(void *keydata, int selection, const OSSL_PARAM params[])
{
DSA *dsa = keydata;
@@ -313,6 +335,7 @@ const OSSL_DISPATCH dsa_keymgmt_functions[] = {
{ OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dsa_get_params },
{ OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dsa_gettable_params },
{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dsa_has },
{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dsa_match },
{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dsa_import },
{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dsa_import_types },
{ OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dsa_export },
@@ -0,0 +1,749 @@
/*
* 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
*/
/*
* ECDH/ECDSA low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/core_numbers.h>
#include <openssl/core_names.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/objects.h>
#include <openssl/params.h>
#include "crypto/bn.h"
#include "internal/param_build.h"
#include "prov/implementations.h"
#include "prov/providercommon.h"
static OSSL_OP_keymgmt_new_fn ec_newdata;
static OSSL_OP_keymgmt_free_fn ec_freedata;
static OSSL_OP_keymgmt_get_params_fn ec_get_params;
static OSSL_OP_keymgmt_gettable_params_fn ec_gettable_params;
static OSSL_OP_keymgmt_set_params_fn ec_set_params;
static OSSL_OP_keymgmt_settable_params_fn ec_settable_params;
static OSSL_OP_keymgmt_has_fn ec_has;
static OSSL_OP_keymgmt_match_fn ec_match;
static OSSL_OP_keymgmt_import_fn ec_import;
static OSSL_OP_keymgmt_import_types_fn ec_import_types;
static OSSL_OP_keymgmt_export_fn ec_export;
static OSSL_OP_keymgmt_export_types_fn ec_export_types;
static OSSL_OP_keymgmt_query_operation_name_fn ec_query_operation_name;
#define EC_POSSIBLE_SELECTIONS \
(OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS )
static
const char *ec_query_operation_name(int operation_id)
{
switch (operation_id) {
case OSSL_OP_KEYEXCH:
return "ECDH";
#if 0
case OSSL_OP_SIGNATURE:
return deflt_signature;
#endif
}
return NULL;
}
static ossl_inline
int params_to_domparams(EC_KEY *ec, const OSSL_PARAM params[])
{
const OSSL_PARAM *param_ec_name;
EC_GROUP *ecg = NULL;
char *curve_name = NULL;
int ok = 0;
if (ec == NULL)
return 0;
param_ec_name = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_NAME);
if (param_ec_name == NULL) {
/* explicit parameters */
/*
* TODO(3.0): should we support explicit parameters curves?
*/
return 0;
} else {
/* named curve */
int curve_nid;
if (!OSSL_PARAM_get_utf8_string(param_ec_name, &curve_name, 0)
|| curve_name == NULL
|| (curve_nid = OBJ_sn2nid(curve_name)) == NID_undef)
goto err;
if ((ecg = EC_GROUP_new_by_curve_name(curve_nid)) == NULL)
goto err;
}
if (!EC_KEY_set_group(ec, ecg))
goto err;
/*
* TODO(3.0): if the group has changed, should we invalidate the private and
* public key?
*/
ok = 1;
err:
OPENSSL_free(curve_name);
EC_GROUP_free(ecg);
return ok;
}
static ossl_inline
int domparams_to_params(const EC_KEY *ec, OSSL_PARAM_BLD *tmpl)
{
const EC_GROUP *ecg;
int curve_nid;
if (ec == NULL)
return 0;
ecg = EC_KEY_get0_group(ec);
if (ecg == NULL)
return 0;
curve_nid = EC_GROUP_get_curve_name(ecg);
if (curve_nid == NID_undef) {
/* explicit parameters */
/*
* TODO(3.0): should we support explicit parameters curves?
*/
return 0;
} else {
/* named curve */
const char *curve_name = NULL;
if ((curve_name = OBJ_nid2sn(curve_nid)) == NULL)
return 0;
if (!ossl_param_bld_push_utf8_string(tmpl, OSSL_PKEY_PARAM_EC_NAME, curve_name, 0))
return 0;
}
return 1;
}
/*
* Callers of params_to_key MUST make sure that params_to_domparams has been
* called before!
*
* This function only imports the bare keypair, domain parameters and other
* parameters are imported separately, and domain parameters are required to
* define a keypair.
*/
static ossl_inline
int params_to_key(EC_KEY *ec, const OSSL_PARAM params[], int include_private)
{
const OSSL_PARAM *param_priv_key, *param_pub_key;
BIGNUM *priv_key = NULL;
unsigned char *pub_key = NULL;
size_t pub_key_len;
const EC_GROUP *ecg = NULL;
EC_POINT *pub_point = NULL;
int ok = 0;
ecg = EC_KEY_get0_group(ec);
if (ecg == NULL)
return 0;
param_priv_key =
OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
param_pub_key =
OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
/*
* We want to have at least a public key either way, so we end up
* requiring it unconditionally.
*/
if (param_pub_key == NULL
|| !OSSL_PARAM_get_octet_string(param_pub_key,
(void **)&pub_key, 0, &pub_key_len)
|| (pub_point = EC_POINT_new(ecg)) == NULL
|| !EC_POINT_oct2point(ecg, pub_point,
pub_key, pub_key_len, NULL))
goto err;
if (param_priv_key != NULL && include_private) {
int fixed_top;
const BIGNUM *order;
/*
* Key import/export should never leak the bit length of the secret
* scalar in the key.
*
* For this reason, on export we use padded BIGNUMs with fixed length.
*
* When importing we also should make sure that, even if short lived,
* the newly created BIGNUM is marked with the BN_FLG_CONSTTIME flag as
* soon as possible, so that any processing of this BIGNUM might opt for
* constant time implementations in the backend.
*
* Setting the BN_FLG_CONSTTIME flag alone is never enough, we also have
* to preallocate the BIGNUM internal buffer to a fixed public size big
* enough that operations performed during the processing never trigger
* a realloc which would leak the size of the scalar through memory
* accesses.
*
* Fixed Length
* ------------
*
* The order of the large prime subgroup of the curve is our choice for
* a fixed public size, as that is generally the upper bound for
* generating a private key in EC cryptosystems and should fit all valid
* secret scalars.
*
* For padding on export we just use the bit length of the order
* converted to bytes (rounding up).
*
* For preallocating the BIGNUM storage we look at the number of "words"
* required for the internal representation of the order, and we
* preallocate 2 extra "words" in case any of the subsequent processing
* might temporarily overflow the order length.
*/
order = EC_GROUP_get0_order(ecg);
if (order == NULL || BN_is_zero(order))
goto err;
fixed_top = bn_get_top(order) + 2;
if ((priv_key = BN_new()) == NULL)
goto err;
if (bn_wexpand(priv_key, fixed_top) == NULL)
goto err;
BN_set_flags(priv_key, BN_FLG_CONSTTIME);
if (!OSSL_PARAM_get_BN(param_priv_key, &priv_key))
goto err;
}
if (priv_key != NULL
&& !EC_KEY_set_private_key(ec, priv_key))
goto err;
if (!EC_KEY_set_public_key(ec, pub_point))
goto err;
ok = 1;
err:
BN_clear_free(priv_key);
OPENSSL_free(pub_key);
EC_POINT_free(pub_point);
return ok;
}
/*
* Callers of key_to_params MUST make sure that domparams_to_params is also
* called!
*
* This function only exports the bare keypair, domain parameters and other
* parameters are exported separately.
*/
static ossl_inline
int key_to_params(const EC_KEY *eckey, OSSL_PARAM_BLD *tmpl, int include_private)
{
const BIGNUM *priv_key = NULL;
const EC_POINT *pub_point = NULL;
const EC_GROUP *ecg = NULL;
unsigned char *pub_key = NULL;
size_t pub_key_len = 0;
int ret = 0;
if (eckey == NULL)
return 0;
ecg = EC_KEY_get0_group(eckey);
priv_key = EC_KEY_get0_private_key(eckey);
pub_point = EC_KEY_get0_public_key(eckey);
/* group and public_key must be present, priv_key is optional */
if (ecg == NULL || pub_point == NULL)
return 0;
if ((pub_key_len = EC_POINT_point2buf(ecg, pub_point,
POINT_CONVERSION_COMPRESSED,
&pub_key, NULL)) == 0)
return 0;
if (!ossl_param_bld_push_octet_string(tmpl,
OSSL_PKEY_PARAM_PUB_KEY,
pub_key, pub_key_len))
goto err;
if (priv_key != NULL && include_private) {
size_t sz;
int ecbits;
/*
* Key import/export should never leak the bit length of the secret
* scalar in the key.
*
* For this reason, on export we use padded BIGNUMs with fixed length.
*
* When importing we also should make sure that, even if short lived,
* the newly created BIGNUM is marked with the BN_FLG_CONSTTIME flag as
* soon as possible, so that any processing of this BIGNUM might opt for
* constant time implementations in the backend.
*
* Setting the BN_FLG_CONSTTIME flag alone is never enough, we also have
* to preallocate the BIGNUM internal buffer to a fixed public size big
* enough that operations performed during the processing never trigger
* a realloc which would leak the size of the scalar through memory
* accesses.
*
* Fixed Length
* ------------
*
* The order of the large prime subgroup of the curve is our choice for
* a fixed public size, as that is generally the upper bound for
* generating a private key in EC cryptosystems and should fit all valid
* secret scalars.
*
* For padding on export we just use the bit length of the order
* converted to bytes (rounding up).
*
* For preallocating the BIGNUM storage we look at the number of "words"
* required for the internal representation of the order, and we
* preallocate 2 extra "words" in case any of the subsequent processing
* might temporarily overflow the order length.
*/
ecbits = EC_GROUP_order_bits(ecg);
if (ecbits <= 0)
goto err;
sz = (ecbits + 7 ) / 8;
if (!ossl_param_bld_push_BN_pad(tmpl,
OSSL_PKEY_PARAM_PRIV_KEY,
priv_key, sz))
goto err;
}
ret = 1;
err:
OPENSSL_free(pub_key);
return ret;
}
static ossl_inline
int ec_set_param_ecdh_cofactor_mode(EC_KEY *ec, const OSSL_PARAM *p)
{
const EC_GROUP *ecg = EC_KEY_get0_group(ec);
const BIGNUM *cofactor;
int mode;
if (!OSSL_PARAM_get_int(p, &mode))
return 0;
/*
* mode can be only 0 for disable, or 1 for enable here.
*
* This is in contrast with the same parameter on an ECDH EVP_PKEY_CTX that
* also supports mode == -1 with the meaning of "reset to the default for
* the associated key".
*/
if (mode < 0 || mode > 1)
return 0;
if ((cofactor = EC_GROUP_get0_cofactor(ecg)) == NULL )
return 0;
/* ECDH cofactor mode has no effect if cofactor is 1 */
if (BN_is_one(cofactor))
return 1;
if (mode == 1)
EC_KEY_set_flags(ec, EC_FLAG_COFACTOR_ECDH);
else if (mode == 0)
EC_KEY_clear_flags(ec, EC_FLAG_COFACTOR_ECDH);
return 1;
}
static ossl_inline
int params_to_otherparams(EC_KEY *ec, const OSSL_PARAM params[])
{
const OSSL_PARAM *p;
if (ec == NULL)
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_USE_COFACTOR_ECDH);
if (p != NULL && !ec_set_param_ecdh_cofactor_mode(ec, p))
return 0;
return 1;
}
static ossl_inline
int otherparams_to_params(const EC_KEY *ec, OSSL_PARAM_BLD *tmpl)
{
int ecdh_cofactor_mode = 0;
if (ec == NULL)
return 0;
ecdh_cofactor_mode =
(EC_KEY_get_flags(ec) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0;
if (!ossl_param_bld_push_int(tmpl,
OSSL_PKEY_PARAM_USE_COFACTOR_ECDH,
ecdh_cofactor_mode))
return 0;
return 1;
}
static
void *ec_newdata(void *provctx)
{
return EC_KEY_new();
}
static
void ec_freedata(void *keydata)
{
EC_KEY_free(keydata);
}
static
int ec_has(void *keydata, int selection)
{
EC_KEY *ec = keydata;
int ok = 0;
if ((selection & EC_POSSIBLE_SELECTIONS) != 0)
ok = 1;
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
ok = ok && (EC_KEY_get0_public_key(ec) != NULL);
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
ok = ok && (EC_KEY_get0_private_key(ec) != NULL);
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
ok = ok && (EC_KEY_get0_group(ec) != NULL);
/*
* We consider OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS to always be available,
* so no extra check is needed other than the previous one against
* EC_POSSIBLE_SELECTIONS.
*/
return ok;
}
static int ec_match(const void *keydata1, const void *keydata2, int selection)
{
const EC_KEY *ec1 = keydata1;
const EC_KEY *ec2 = keydata2;
const EC_GROUP *group_a = EC_KEY_get0_group(ec1);
const EC_GROUP *group_b = EC_KEY_get0_group(ec2);
int ok = 1;
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
ok = ok && group_a != NULL && group_b != NULL
&& EC_GROUP_cmp(group_a, group_b, NULL) == 0;
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
const BIGNUM *pa = EC_KEY_get0_private_key(ec1);
const BIGNUM *pb = EC_KEY_get0_private_key(ec2);
ok = ok && BN_cmp(pa, pb) == 0;
}
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
const EC_POINT *pa = EC_KEY_get0_public_key(ec1);
const EC_POINT *pb = EC_KEY_get0_public_key(ec2);
ok = ok && EC_POINT_cmp(group_b, pa, pb, NULL);
}
return ok;
}
static
int ec_import(void *keydata, int selection, const OSSL_PARAM params[])
{
EC_KEY *ec = keydata;
int ok = 0;
if (ec == NULL)
return 0;
/*
* In this implementation, we can export/import only keydata in the
* following combinations:
* - domain parameters only
* - public key with associated domain parameters (+optional other params)
* - private key with associated public key and domain parameters
* (+optional other params)
*
* This means:
* - domain parameters must always be requested
* - private key must be requested alongside public key
* - other parameters must be requested only alongside a key
*/
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) == 0)
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0
&& (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0)
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0
&& (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
ok = ok && params_to_domparams(ec, params);
if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
int include_private =
selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
ok = ok && params_to_key(ec, params, include_private);
}
if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0)
ok = ok && params_to_otherparams(ec, params);
return ok;
}
static
int ec_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
void *cbarg)
{
EC_KEY *ec = keydata;
OSSL_PARAM_BLD tmpl;
OSSL_PARAM *params = NULL;
int ok = 1;
if (ec == NULL)
return 0;
/*
* In this implementation, we can export/import only keydata in the
* following combinations:
* - domain parameters only
* - public key with associated domain parameters (+optional other params)
* - private key with associated public key and domain parameters
* (+optional other params)
*
* This means:
* - domain parameters must always be requested
* - private key must be requested alongside public key
* - other parameters must be requested only alongside a key
*/
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) == 0)
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0
&& (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0)
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0
&& (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
return 0;
ossl_param_bld_init(&tmpl);
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
ok = ok && domparams_to_params(ec, &tmpl);
if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
int include_private =
selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
ok = ok && key_to_params(ec, &tmpl, include_private);
}
if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0)
ok = ok && otherparams_to_params(ec, &tmpl);
if (!ok
|| (params = ossl_param_bld_to_param(&tmpl)) == NULL)
return 0;
ok = param_cb(params, cbarg);
ossl_param_bld_free(params);
return ok;
}
/* IMEXPORT = IMPORT + EXPORT */
# define EC_IMEXPORTABLE_DOM_PARAMETERS \
OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_NAME, NULL, 0)
# define EC_IMEXPORTABLE_PUBLIC_KEY \
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0)
# define EC_IMEXPORTABLE_PRIVATE_KEY \
OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0)
# define EC_IMEXPORTABLE_OTHER_PARAMETERS \
OSSL_PARAM_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, NULL)
/*
* Include all the possible combinations of OSSL_PARAM arrays for
* ec_imexport_types().
*
* They are in a separate file as it is ~100 lines of unreadable and
* uninteresting machine generated stuff.
*
* TODO(3.0): the generated list looks quite ugly, as to cover all possible
* combinations of the bits in `selection`, it also includes combinations that
* are not really useful: we might want to consider alternatives to this
* solution.
*/
#include "ec_kmgmt_imexport.inc"
static ossl_inline
const OSSL_PARAM *ec_imexport_types(int selection)
{
int type_select = 0;
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
type_select += 1;
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
type_select += 2;
if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
type_select += 4;
if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0)
type_select += 8;
return ec_types[type_select];
}
static
const OSSL_PARAM *ec_import_types(int selection)
{
return ec_imexport_types(selection);
}
static
const OSSL_PARAM *ec_export_types(int selection)
{
return ec_imexport_types(selection);
}
static
int ec_get_params(void *key, OSSL_PARAM params[])
{
EC_KEY *eck = key;
const EC_GROUP *ecg = NULL;
OSSL_PARAM *p;
ecg = EC_KEY_get0_group(eck);
if (ecg == NULL)
return 0;
if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL
&& !OSSL_PARAM_set_int(p, ECDSA_size(eck)))
return 0;
if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL
&& !OSSL_PARAM_set_int(p, EC_GROUP_order_bits(ecg)))
return 0;
if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL) {
int ecbits, sec_bits;
ecbits = EC_GROUP_order_bits(ecg);
/*
* The following estimates are based on the values published
* in Table 2 of "NIST Special Publication 800-57 Part 1 Revision 4"
* at http://dx.doi.org/10.6028/NIST.SP.800-57pt1r4 .
*
* Note that the above reference explicitly categorizes algorithms in a
* discrete set of values {80, 112, 128, 192, 256}, and that it is
* relevant only for NIST approved Elliptic Curves, while OpenSSL
* applies the same logic also to other curves.
*
* Classifications produced by other standardazing bodies might differ,
* so the results provided for "bits of security" by this provider are
* to be considered merely indicative, and it is the users'
* responsibility to compare these values against the normative
* references that may be relevant for their intent and purposes.
*/
if (ecbits >= 512)
sec_bits = 256;
else if (ecbits >= 384)
sec_bits = 192;
else if (ecbits >= 256)
sec_bits = 128;
else if (ecbits >= 224)
sec_bits = 112;
else if (ecbits >= 160)
sec_bits = 80;
else
sec_bits = ecbits / 2;
if (!OSSL_PARAM_set_int(p, sec_bits))
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_USE_COFACTOR_ECDH);
if (p != NULL) {
int ecdh_cofactor_mode = 0;
ecdh_cofactor_mode =
(EC_KEY_get_flags(eck) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0;
if (!OSSL_PARAM_set_int(p, ecdh_cofactor_mode))
return 0;
}
return 1;
}
static const OSSL_PARAM ec_known_gettable_params[] = {
OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
OSSL_PARAM_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, NULL),
OSSL_PARAM_END
};
static
const OSSL_PARAM *ec_gettable_params(void)
{
return ec_known_gettable_params;
}
static const OSSL_PARAM ec_known_settable_params[] = {
OSSL_PARAM_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, NULL),
OSSL_PARAM_END
};
static
const OSSL_PARAM *ec_settable_params(void)
{
return ec_known_settable_params;
}
static
int ec_set_params(void *key, const OSSL_PARAM params[])
{
EC_KEY *eck = key;
const OSSL_PARAM *p;
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_USE_COFACTOR_ECDH);
if (p != NULL && !ec_set_param_ecdh_cofactor_mode(eck, p))
return 0;
return 1;
}
const OSSL_DISPATCH ec_keymgmt_functions[] = {
{ OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_newdata },
{ OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ec_freedata },
{ OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))ec_get_params },
{ OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))ec_gettable_params },
{ OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))ec_set_params },
{ OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))ec_settable_params },
{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ec_has },
{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ec_match },
{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ec_import },
{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ec_import_types },
{ OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_export },
{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ec_export_types },
{ OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
(void (*)(void))ec_query_operation_name },
{ 0, NULL }
};
@@ -0,0 +1,100 @@
/*
* This file is meant to be included from ec_kmgmt.c
*/
static const OSSL_PARAM ec_private_key_types[] = {
EC_IMEXPORTABLE_PRIVATE_KEY,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_public_key_types[] = {
EC_IMEXPORTABLE_PUBLIC_KEY,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_key_types[] = {
EC_IMEXPORTABLE_PRIVATE_KEY,
EC_IMEXPORTABLE_PUBLIC_KEY,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_dom_parameters_types[] = {
EC_IMEXPORTABLE_DOM_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_5_types[] = {
EC_IMEXPORTABLE_PRIVATE_KEY,
EC_IMEXPORTABLE_DOM_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_6_types[] = {
EC_IMEXPORTABLE_PUBLIC_KEY,
EC_IMEXPORTABLE_DOM_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_key_domp_types[] = {
EC_IMEXPORTABLE_PRIVATE_KEY,
EC_IMEXPORTABLE_PUBLIC_KEY,
EC_IMEXPORTABLE_DOM_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_other_parameters_types[] = {
EC_IMEXPORTABLE_OTHER_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_9_types[] = {
EC_IMEXPORTABLE_PRIVATE_KEY,
EC_IMEXPORTABLE_OTHER_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_10_types[] = {
EC_IMEXPORTABLE_PUBLIC_KEY,
EC_IMEXPORTABLE_OTHER_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_11_types[] = {
EC_IMEXPORTABLE_PRIVATE_KEY,
EC_IMEXPORTABLE_PUBLIC_KEY,
EC_IMEXPORTABLE_OTHER_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_all_parameters_types[] = {
EC_IMEXPORTABLE_DOM_PARAMETERS,
EC_IMEXPORTABLE_OTHER_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_13_types[] = {
EC_IMEXPORTABLE_PRIVATE_KEY,
EC_IMEXPORTABLE_DOM_PARAMETERS,
EC_IMEXPORTABLE_OTHER_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_14_types[] = {
EC_IMEXPORTABLE_PUBLIC_KEY,
EC_IMEXPORTABLE_DOM_PARAMETERS,
EC_IMEXPORTABLE_OTHER_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM ec_all_types[] = {
EC_IMEXPORTABLE_PRIVATE_KEY,
EC_IMEXPORTABLE_PUBLIC_KEY,
EC_IMEXPORTABLE_DOM_PARAMETERS,
EC_IMEXPORTABLE_OTHER_PARAMETERS,
OSSL_PARAM_END
};
static const OSSL_PARAM *ec_types[] = {
NULL,
ec_private_key_types,
ec_public_key_types,
ec_key_types,
ec_dom_parameters_types,
ec_5_types,
ec_6_types,
ec_key_domp_types,
ec_other_parameters_types,
ec_9_types,
ec_10_types,
ec_11_types,
ec_all_parameters_types,
ec_13_types,
ec_14_types,
ec_all_types
};
@@ -154,8 +154,8 @@ static int ecx_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
}
static const OSSL_PARAM ecx_key_types[] = {
OSSL_PARAM_BN(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),
OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),
OSSL_PARAM_END
};
static const OSSL_PARAM *ecx_imexport_types(int selection)
@@ -26,6 +26,7 @@ static OSSL_OP_keymgmt_free_fn rsa_freedata;
static OSSL_OP_keymgmt_get_params_fn rsa_get_params;
static OSSL_OP_keymgmt_gettable_params_fn rsa_gettable_params;
static OSSL_OP_keymgmt_has_fn rsa_has;
static OSSL_OP_keymgmt_match_fn rsa_match;
static OSSL_OP_keymgmt_validate_fn rsa_validate;
static OSSL_OP_keymgmt_import_fn rsa_import;
static OSSL_OP_keymgmt_import_types_fn rsa_import_types;
@@ -197,6 +198,21 @@ static int rsa_has(void *keydata, int selection)
return ok;
}
static int rsa_match(const void *keydata1, const void *keydata2, int selection)
{
const RSA *rsa1 = keydata1;
const RSA *rsa2 = keydata2;
int ok = 1;
/* There is always an |e| */
ok = ok && BN_cmp(RSA_get0_e(rsa1), RSA_get0_e(rsa2)) == 0;
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
ok = ok && BN_cmp(RSA_get0_n(rsa1), RSA_get0_n(rsa2)) == 0;
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
ok = ok && BN_cmp(RSA_get0_d(rsa1), RSA_get0_d(rsa2)) == 0;
return ok;
}
static int rsa_import(void *keydata, int selection, const OSSL_PARAM params[])
{
RSA *rsa = keydata;
@@ -393,6 +409,7 @@ const OSSL_DISPATCH rsa_keymgmt_functions[] = {
{ OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))rsa_get_params },
{ OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))rsa_gettable_params },
{ OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))rsa_has },
{ OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))rsa_match },
{ OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))rsa_validate },
{ OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))rsa_import },
{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))rsa_import_types },
@@ -5,6 +5,7 @@ $SERIALIZER_GOAL=../../libimplementations.a
$RSA_GOAL=../../libimplementations.a
$DH_GOAL=../../libimplementations.a
$DSA_GOAL=../../libimplementations.a
$ECX_GOAL=../../libimplementations.a
SOURCE[$SERIALIZER_GOAL]=serializer_common.c
SOURCE[$RSA_GOAL]=serializer_rsa.c serializer_rsa_priv.c serializer_rsa_pub.c
@@ -14,3 +15,6 @@ ENDIF
IF[{- !$disabled{dsa} -}]
SOURCE[$DSA_GOAL]=serializer_dsa.c serializer_dsa_priv.c serializer_dsa_pub.c serializer_dsa_param.c
ENDIF
IF[{- !$disabled{ec} -}]
SOURCE[$ECX_GOAL]=serializer_ecx.c serializer_ecx_priv.c serializer_ecx_pub.c
ENDIF
@@ -243,6 +243,36 @@ int ossl_prov_print_labeled_bignum(BIO *out, const char *label,
return 1;
}
/* Number of octets per line */
#define LABELED_BUF_PRINT_WIDTH 15
int ossl_prov_print_labeled_buf(BIO *out, const char *label,
const unsigned char *buf, size_t buflen)
{
size_t i;
if (ossl_prov_bio_printf(out, "%s\n", label) <= 0)
return 0;
for (i = 0; i < buflen; i++) {
if ((i % LABELED_BUF_PRINT_WIDTH) == 0) {
if (i > 0 && ossl_prov_bio_printf(out, "\n") <= 0)
return 0;
if (ossl_prov_bio_printf(out, " ") <= 0)
return 0;
}
if (ossl_prov_bio_printf(out, "%02x%s", buf[i],
(i == buflen - 1) ? "" : ":") <= 0)
return 0;
}
if (ossl_prov_bio_printf(out, "\n") <= 0)
return 0;
return 1;
}
/* p2s = param to asn1_string, k2d = key to der */
int ossl_prov_write_priv_der_from_obj(BIO *out, const void *obj, int obj_nid,
int (*p2s)(const void *obj, int nid,
@@ -254,7 +284,7 @@ int ossl_prov_write_priv_der_from_obj(BIO *out, const void *obj, int obj_nid,
{
int ret = 0;
ASN1_STRING *str = NULL;
int strtype = 0;
int strtype = V_ASN1_UNDEF;
if (p2s != NULL && !p2s(obj, obj_nid, &str, &strtype))
return 0;
@@ -290,7 +320,7 @@ int ossl_prov_write_priv_pem_from_obj(BIO *out, const void *obj, int obj_nid,
{
int ret = 0;
ASN1_STRING *str = NULL;
int strtype = 0;
int strtype = V_ASN1_UNDEF;
if (p2s != NULL && !p2s(obj, obj_nid, &str, &strtype))
return 0;
@@ -325,7 +355,7 @@ int ossl_prov_write_pub_der_from_obj(BIO *out, const void *obj, int obj_nid,
{
int ret = 0;
ASN1_STRING *str = NULL;
int strtype = 0;
int strtype = V_ASN1_UNDEF;
X509_PUBKEY *xpk = NULL;
if (p2s != NULL && !p2s(obj, obj_nid, &str, &strtype))
@@ -350,7 +380,7 @@ int ossl_prov_write_pub_pem_from_obj(BIO *out, const void *obj, int obj_nid,
{
int ret = 0;
ASN1_STRING *str = NULL;
int strtype = 0;
int strtype = V_ASN1_UNDEF;
X509_PUBKEY *xpk = NULL;
if (p2s != NULL && !p2s(obj, obj_nid, &str, &strtype))
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* DH low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/dh.h>
#include <openssl/err.h>
#include "prov/bio.h" /* ossl_prov_bio_printf() */
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* DH low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/core_numbers.h>
#include <openssl/pem.h>
#include <openssl/dh.h>
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* DH low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/core_numbers.h>
#include <openssl/core_names.h>
#include <openssl/err.h>
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* DH low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/core_numbers.h>
#include <openssl/err.h>
#include <openssl/pem.h>
@@ -126,7 +132,7 @@ static int dh_pub_print_data(void *ctx, const OSSL_PARAM params[], BIO *out,
static int dh_pub_print(void *ctx, void *dh, BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
return ossl_prov_print_dh(out, dh, 0);
return ossl_prov_print_dh(out, dh, dh_print_pub);
}
const OSSL_DISPATCH dh_pub_der_serializer_functions[] = {
@@ -0,0 +1,125 @@
/*
* 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 <openssl/err.h>
#include "crypto/ecx.h"
#include "prov/bio.h" /* ossl_prov_bio_printf() */
#include "prov/implementations.h" /* ecx_keymgmt_functions */
#include "serializer_local.h"
void ecx_get_new_free_import(ECX_KEY_TYPE type,
OSSL_OP_keymgmt_new_fn **ecx_new,
OSSL_OP_keymgmt_free_fn **ecx_free,
OSSL_OP_keymgmt_import_fn **ecx_import)
{
if (type == ECX_KEY_TYPE_X25519) {
*ecx_new = ossl_prov_get_keymgmt_new(x25519_keymgmt_functions);
*ecx_free = ossl_prov_get_keymgmt_free(x25519_keymgmt_functions);
*ecx_import = ossl_prov_get_keymgmt_import(x25519_keymgmt_functions);
} else if (type == ECX_KEY_TYPE_X448) {
*ecx_new = ossl_prov_get_keymgmt_new(x448_keymgmt_functions);
*ecx_free = ossl_prov_get_keymgmt_free(x448_keymgmt_functions);
*ecx_import = ossl_prov_get_keymgmt_import(x448_keymgmt_functions);
} else {
*ecx_new = NULL;
*ecx_free = NULL;
*ecx_import = NULL;
}
}
int ossl_prov_print_ecx(BIO *out, ECX_KEY *ecxkey, enum ecx_print_type type)
{
const char *type_label = NULL;
switch (type) {
case ecx_print_priv:
switch (ecxkey->keylen) {
case X25519_KEYLEN:
type_label = "X25519 Private-Key";
break;
case X448_KEYLEN:
type_label = "X448 Private-Key";
break;
}
break;
case ecx_print_pub:
switch (ecxkey->keylen) {
case X25519_KEYLEN:
type_label = "X25519 Public-Key";
break;
case X448_KEYLEN:
type_label = "X448 Public-Key";
break;
}
break;
}
if (type == ecx_print_priv && ecxkey->privkey == NULL) {
ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (ossl_prov_bio_printf(out, "%s:\n", type_label) <= 0)
return 0;
if (type == ecx_print_priv
&& !ossl_prov_print_labeled_buf(out, "priv:", ecxkey->privkey,
ecxkey->keylen))
return 0;
if (!ossl_prov_print_labeled_buf(out, "pub:", ecxkey->pubkey,
ecxkey->keylen))
return 0;
return 1;
}
int ossl_prov_ecx_pub_to_der(const void *vecxkey, unsigned char **pder)
{
const ECX_KEY *ecxkey = vecxkey;
unsigned char *keyblob;
if (ecxkey == NULL) {
ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
keyblob = OPENSSL_memdup(ecxkey->pubkey, ecxkey->keylen);
if (keyblob == NULL) {
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return 0;
}
*pder = keyblob;
return ecxkey->keylen;
}
int ossl_prov_ecx_priv_to_der(const void *vecxkey, unsigned char **pder)
{
const ECX_KEY *ecxkey = vecxkey;
ASN1_OCTET_STRING oct;
int keybloblen;
if (ecxkey == NULL || ecxkey->privkey == NULL) {
ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
oct.data = ecxkey->privkey;
oct.length = ecxkey->keylen;
oct.flags = 0;
keybloblen = i2d_ASN1_OCTET_STRING(&oct, pder);
if (keybloblen < 0) {
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return 0;
}
return keybloblen;
}
@@ -0,0 +1,270 @@
/*
* 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 <openssl/core_numbers.h>
#include <openssl/core_names.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/types.h>
#include <openssl/params.h>
#include "prov/bio.h"
#include "prov/implementations.h"
#include "serializer_local.h"
static OSSL_OP_serializer_newctx_fn x25519_priv_newctx;
static OSSL_OP_serializer_newctx_fn x448_priv_newctx;
static OSSL_OP_serializer_freectx_fn ecx_priv_freectx;
static OSSL_OP_serializer_set_ctx_params_fn ecx_priv_set_ctx_params;
static OSSL_OP_serializer_settable_ctx_params_fn ecx_priv_settable_ctx_params;
static OSSL_OP_serializer_serialize_data_fn ecx_priv_der_data;
static OSSL_OP_serializer_serialize_object_fn ecx_priv_der;
static OSSL_OP_serializer_serialize_data_fn ecx_priv_pem_data;
static OSSL_OP_serializer_serialize_object_fn ecx_priv_pem;
static OSSL_OP_serializer_serialize_data_fn ecx_priv_print_data;
static OSSL_OP_serializer_serialize_object_fn ecx_priv_print;
/*
* Context used for private key serialization.
*/
struct ecx_priv_ctx_st {
void *provctx;
struct pkcs8_encrypt_ctx_st sc;
ECX_KEY_TYPE type;
};
/* Private key : context */
static void *ecx_priv_newctx(void *provctx, ECX_KEY_TYPE type)
{
struct ecx_priv_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx != NULL) {
ctx->provctx = provctx;
/* -1 is the "whatever" indicator, i.e. the PKCS8 library default PBE */
ctx->sc.pbe_nid = -1;
ctx->type = type;
}
return ctx;
}
static void *x25519_priv_newctx(void *provctx)
{
return ecx_priv_newctx(provctx, ECX_KEY_TYPE_X25519);
}
static void *x448_priv_newctx(void *provctx)
{
return ecx_priv_newctx(provctx, ECX_KEY_TYPE_X448);
}
static void ecx_priv_freectx(void *vctx)
{
struct ecx_priv_ctx_st *ctx = vctx;
EVP_CIPHER_free(ctx->sc.cipher);
OPENSSL_free(ctx->sc.cipher_pass);
OPENSSL_free(ctx);
}
static const OSSL_PARAM *ecx_priv_settable_ctx_params(void)
{
static const OSSL_PARAM settables[] = {
OSSL_PARAM_utf8_string(OSSL_SERIALIZER_PARAM_CIPHER, NULL, 0),
OSSL_PARAM_octet_string(OSSL_SERIALIZER_PARAM_PASS, NULL, 0),
OSSL_PARAM_END,
};
return settables;
}
static int ecx_priv_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
struct ecx_priv_ctx_st *ctx = vctx;
const OSSL_PARAM *p;
p = OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_CIPHER);
if (p != NULL) {
const OSSL_PARAM *propsp =
OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_PROPERTIES);
const char *props;
if (p->data_type != OSSL_PARAM_UTF8_STRING)
return 0;
if (propsp != NULL && propsp->data_type != OSSL_PARAM_UTF8_STRING)
return 0;
props = (propsp != NULL ? propsp->data : NULL);
EVP_CIPHER_free(ctx->sc.cipher);
ctx->sc.cipher_intent = p->data != NULL;
if (p->data != NULL
&& ((ctx->sc.cipher = EVP_CIPHER_fetch(NULL, p->data, props))
== NULL))
return 0;
}
p = OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_PASS);
if (p != NULL) {
OPENSSL_free(ctx->sc.cipher_pass);
ctx->sc.cipher_pass = NULL;
if (!OSSL_PARAM_get_octet_string(p, &ctx->sc.cipher_pass, 0,
&ctx->sc.cipher_pass_length))
return 0;
}
return 1;
}
/* Private key : DER */
static int ecx_priv_der_data(void *vctx, const OSSL_PARAM params[], BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
struct ecx_priv_ctx_st *ctx = vctx;
OSSL_OP_keymgmt_new_fn *ecx_new;
OSSL_OP_keymgmt_free_fn *ecx_free;
OSSL_OP_keymgmt_import_fn *ecx_import;
int ok = 0;
ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import);
if (ecx_import != NULL) {
ECX_KEY *ecxkey;
if ((ecxkey = ecx_new(ctx->provctx)) != NULL
&& ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params)
&& ecx_priv_der(ctx, ecxkey, out, cb, cbarg))
ok = 1;
ecx_free(ecxkey);
}
return ok;
}
static int ecx_priv_der(void *vctx, void *vecxkey, BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
struct ecx_priv_ctx_st *ctx = vctx;
ECX_KEY *ecxkey = vecxkey;
int ret;
int type = (ctx->type == ECX_KEY_TYPE_X25519) ? EVP_PKEY_X25519
: EVP_PKEY_X448;
ctx->sc.cb = cb;
ctx->sc.cbarg = cbarg;
ret = ossl_prov_write_priv_der_from_obj(out, ecxkey,
type,
NULL,
ossl_prov_ecx_priv_to_der,
&ctx->sc);
return ret;
}
/* Private key : PEM */
static int ecx_priv_pem_data(void *vctx, const OSSL_PARAM params[], BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
struct ecx_priv_ctx_st *ctx = vctx;
OSSL_OP_keymgmt_new_fn *ecx_new;
OSSL_OP_keymgmt_free_fn *ecx_free;
OSSL_OP_keymgmt_import_fn *ecx_import;
int ok = 0;
ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import);
if (ecx_import != NULL) {
ECX_KEY *ecxkey;
if ((ecxkey = ecx_new(ctx->provctx)) != NULL
&& ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params)
&& ecx_priv_pem(ctx->provctx, ecxkey, out, cb, cbarg))
ok = 1;
ecx_free(ecxkey);
}
return ok;
}
static int ecx_priv_pem(void *vctx, void *ecxkey, BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
struct ecx_priv_ctx_st *ctx = vctx;
int ret;
int type = (ctx->type == ECX_KEY_TYPE_X25519) ? EVP_PKEY_X25519
: EVP_PKEY_X448;
ctx->sc.cb = cb;
ctx->sc.cbarg = cbarg;
ret = ossl_prov_write_priv_pem_from_obj(out, ecxkey,
type,
NULL,
ossl_prov_ecx_priv_to_der,
&ctx->sc);
return ret;
}
static int ecx_priv_print_data(void *vctx, const OSSL_PARAM params[], BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
struct ecx_priv_ctx_st *ctx = vctx;
OSSL_OP_keymgmt_new_fn *ecx_new;
OSSL_OP_keymgmt_free_fn *ecx_free;
OSSL_OP_keymgmt_import_fn *ecx_import;
int ok = 0;
ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import);
if (ecx_import != NULL) {
ECX_KEY *ecxkey;
if ((ecxkey = ecx_new(ctx->provctx)) != NULL
&& ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params)
&& ecx_priv_print(ctx, ecxkey, out, cb, cbarg))
ok = 1;
ecx_free(ecxkey);
}
return ok;
}
static int ecx_priv_print(void *ctx, void *ecxkey, BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
return ossl_prov_print_ecx(out, ecxkey, ecx_print_priv);
}
#define MAKE_SERIALIZER_FUNCTIONS(alg, type) \
const OSSL_DISPATCH alg##_priv_##type##_serializer_functions[] = { \
{ OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))alg##_priv_newctx }, \
{ OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ecx_priv_freectx }, \
{ OSSL_FUNC_SERIALIZER_SET_CTX_PARAMS, \
(void (*)(void))ecx_priv_set_ctx_params }, \
{ OSSL_FUNC_SERIALIZER_SETTABLE_CTX_PARAMS, \
(void (*)(void))ecx_priv_settable_ctx_params }, \
{ OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, \
(void (*)(void))ecx_priv_##type##_data }, \
{ OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, \
(void (*)(void))ecx_priv_##type }, \
{ 0, NULL } \
};
#define MAKE_SERIALIZER_FUNCTIONS_GROUP(alg) \
MAKE_SERIALIZER_FUNCTIONS(alg, der) \
MAKE_SERIALIZER_FUNCTIONS(alg, pem) \
const OSSL_DISPATCH alg##_priv_print_serializer_functions[] = { \
{ OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))alg##_priv_newctx }, \
{ OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ecx_priv_freectx }, \
{ OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, \
(void (*)(void))ecx_priv_print }, \
{ OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, \
(void (*)(void))ecx_priv_print_data }, \
{ 0, NULL } \
};
MAKE_SERIALIZER_FUNCTIONS_GROUP(x25519)
MAKE_SERIALIZER_FUNCTIONS_GROUP(x448)
@@ -0,0 +1,184 @@
/*
* 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 <openssl/core_numbers.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/types.h>
#include <openssl/params.h>
#include "prov/bio.h"
#include "prov/implementations.h"
#include "serializer_local.h"
static OSSL_OP_serializer_newctx_fn x25519_pub_newctx;
static OSSL_OP_serializer_newctx_fn x448_pub_newctx;
static OSSL_OP_serializer_freectx_fn ecx_pub_freectx;
static OSSL_OP_serializer_serialize_data_fn ecx_pub_der_data;
static OSSL_OP_serializer_serialize_object_fn ecx_pub_der;
static OSSL_OP_serializer_serialize_data_fn ecx_pub_pem_data;
static OSSL_OP_serializer_serialize_object_fn ecx_pub_pem;
static OSSL_OP_serializer_serialize_data_fn ecx_pub_print_data;
static OSSL_OP_serializer_serialize_object_fn ecx_pub_print;
/*
* Context used for public key serialization.
*/
struct ecx_pub_ctx_st {
void *provctx;
ECX_KEY_TYPE type;
};
/* Public key : context */
static void *ecx_pub_newctx(void *provctx, ECX_KEY_TYPE type)
{
struct ecx_pub_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx != NULL) {
ctx->provctx = provctx;
ctx->type = type;
}
return ctx;
}
static void *x25519_pub_newctx(void *provctx)
{
return ecx_pub_newctx(provctx, ECX_KEY_TYPE_X25519);
}
static void *x448_pub_newctx(void *provctx)
{
return ecx_pub_newctx(provctx, ECX_KEY_TYPE_X448);
}
static void ecx_pub_freectx(void *ctx)
{
OPENSSL_free(ctx);
}
/* Public key : DER */
static int ecx_pub_der_data(void *vctx, const OSSL_PARAM params[], BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
struct ecx_pub_ctx_st *ctx = vctx;
OSSL_OP_keymgmt_new_fn *ecx_new;
OSSL_OP_keymgmt_free_fn *ecx_free;
OSSL_OP_keymgmt_import_fn *ecx_import;
int ok = 0;
ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import);
if (ecx_import != NULL) {
ECX_KEY *ecxkey;
if ((ecxkey = ecx_new(ctx->provctx)) != NULL
&& ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params)
&& ecx_pub_der(ctx, ecxkey, out, cb, cbarg))
ok = 1;
ecx_free(ecxkey);
}
return ok;
}
static int ecx_pub_der(void *vctx, void *ecxkey, BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
struct ecx_pub_ctx_st *ctx = vctx;
return ossl_prov_write_pub_der_from_obj(out, ecxkey,
ctx->type == ECX_KEY_TYPE_X25519
? EVP_PKEY_X25519 : EVP_PKEY_X448,
NULL,
ossl_prov_ecx_pub_to_der);
}
/* Public key : PEM */
static int ecx_pub_pem_data(void *vctx, const OSSL_PARAM params[], BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
struct ecx_pub_ctx_st *ctx = vctx;
OSSL_OP_keymgmt_new_fn *ecx_new;
OSSL_OP_keymgmt_free_fn *ecx_free;
OSSL_OP_keymgmt_import_fn *ecx_import;
int ok = 0;
ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import);
if (ecx_import != NULL) {
ECX_KEY *ecxkey;
if ((ecxkey = ecx_new(ctx->provctx)) != NULL
&& ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params)
&& ecx_pub_pem(ctx, ecxkey, out, cb, cbarg))
ok = 1;
ecx_free(ecxkey);
}
return ok;
}
static int ecx_pub_pem(void *vctx, void *ecxkey, BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
struct ecx_pub_ctx_st *ctx = vctx;
return ossl_prov_write_pub_pem_from_obj(out, ecxkey,
ctx->type == ECX_KEY_TYPE_X25519
? EVP_PKEY_X25519 : EVP_PKEY_X448,
NULL,
ossl_prov_ecx_pub_to_der);
}
static int ecx_pub_print_data(void *vctx, const OSSL_PARAM params[], BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
struct ecx_pub_ctx_st *ctx = vctx;
OSSL_OP_keymgmt_new_fn *ecx_new;
OSSL_OP_keymgmt_free_fn *ecx_free;
OSSL_OP_keymgmt_import_fn *ecx_import;
int ok = 0;
ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import);
if (ecx_import != NULL) {
ECX_KEY *ecxkey;
if ((ecxkey = ecx_new(ctx)) != NULL
&& ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params)
&& ecx_pub_print(ctx, ecxkey, out, cb, cbarg))
ok = 1;
ecx_free(ecxkey);
}
return ok;
}
static int ecx_pub_print(void *ctx, void *ecxkey, BIO *out,
OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
{
return ossl_prov_print_ecx(out, ecxkey, ecx_print_pub);
}
#define MAKE_SERIALIZER_FUNCTIONS(alg, type) \
const OSSL_DISPATCH alg##_pub_##type##_serializer_functions[] = { \
{ OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))alg##_pub_newctx }, \
{ OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ecx_pub_freectx }, \
{ OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, \
(void (*)(void))ecx_pub_##type##_data }, \
{ OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, \
(void (*)(void))ecx_pub_##type }, \
{ 0, NULL } \
};
#define MAKE_SERIALIZER_FUNCTIONS_GROUP(alg) \
MAKE_SERIALIZER_FUNCTIONS(alg, der) \
MAKE_SERIALIZER_FUNCTIONS(alg, pem) \
MAKE_SERIALIZER_FUNCTIONS(alg, print)
MAKE_SERIALIZER_FUNCTIONS_GROUP(x25519)
MAKE_SERIALIZER_FUNCTIONS_GROUP(x448)
@@ -13,6 +13,7 @@
#include <openssl/asn1.h> /* i2d_of_void */
#include <openssl/x509.h> /* X509_SIG */
#include <openssl/types.h>
#include <crypto/ecx.h>
struct pkcs8_encrypt_ctx_st {
/* Set to 1 if intending to encrypt/decrypt, otherwise 0 */
@@ -30,6 +31,11 @@ struct pkcs8_encrypt_ctx_st {
void *cbarg;
};
typedef enum {
ECX_KEY_TYPE_X25519,
ECX_KEY_TYPE_X448
} ECX_KEY_TYPE;
OSSL_OP_keymgmt_new_fn *ossl_prov_get_keymgmt_new(const OSSL_DISPATCH *fns);
OSSL_OP_keymgmt_free_fn *ossl_prov_get_keymgmt_free(const OSSL_DISPATCH *fns);
OSSL_OP_keymgmt_import_fn *ossl_prov_get_keymgmt_import(const OSSL_DISPATCH *fns);
@@ -49,8 +55,15 @@ int ossl_prov_prepare_dh_params(const void *dh, int nid,
int ossl_prov_dh_pub_to_der(const void *dh, unsigned char **pder);
int ossl_prov_dh_priv_to_der(const void *dh, unsigned char **pder);
void ecx_get_new_free_import(ECX_KEY_TYPE type,
OSSL_OP_keymgmt_new_fn **ecx_new,
OSSL_OP_keymgmt_free_fn **ecx_free,
OSSL_OP_keymgmt_import_fn **ecx_import);
int ossl_prov_ecx_pub_to_der(const void *ecxkey, unsigned char **pder);
int ossl_prov_ecx_priv_to_der(const void *ecxkey, unsigned char **pder);
int ossl_prov_prepare_dsa_params(const void *dsa, int nid,
ASN1_STRING **pstr, int *pstrtype);
ASN1_STRING **pstr, int *pstrtype);
/*
* Special variant of ossl_prov_prepare_dsa_params() that requires all
* three parameters (P, Q and G) to be set. This is used when serializing
@@ -63,6 +76,8 @@ int ossl_prov_dsa_priv_to_der(const void *dsa, unsigned char **pder);
int ossl_prov_print_labeled_bignum(BIO *out, const char *label,
const BIGNUM *bn);
int ossl_prov_print_labeled_buf(BIO *out, const char *label,
const unsigned char *buf, size_t buflen);
int ossl_prov_print_rsa(BIO *out, RSA *rsa, int priv);
enum dh_print_type {
@@ -81,6 +96,15 @@ enum dsa_print_type {
int ossl_prov_print_dsa(BIO *out, DSA *dsa, enum dsa_print_type type);
enum ecx_print_type {
ecx_print_priv,
ecx_print_pub
};
#ifndef OPENSSL_NO_EC
int ossl_prov_print_ecx(BIO *out, ECX_KEY *ecxkey, enum ecx_print_type type);
#endif
int ossl_prov_write_priv_der_from_obj(BIO *out, const void *obj, int obj_nid,
int (*p2s)(const void *obj, int nid,
ASN1_STRING **str,
@@ -2,9 +2,12 @@
# switch each to the Legacy provider when needed.
$DSA_GOAL=../../libimplementations.a
$RSA_GOAL=../../libimplementations.a
IF[{- !$disabled{dsa} -}]
SOURCE[$DSA_GOAL]=dsa.c
ENDIF
SOURCE[$RSA_GOAL]=rsa.c
+1115
View File
@@ -0,0 +1,1115 @@
/*
* 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
*/
/*
* RSA low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/core_numbers.h>
#include <openssl/core_names.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/params.h>
#include <openssl/evp.h>
#include "internal/cryptlib.h"
#include "internal/nelem.h"
#include "internal/sizes.h"
#include "crypto/rsa.h"
#include "prov/providercommonerr.h"
#include "prov/implementations.h"
#include "prov/provider_ctx.h"
static OSSL_OP_signature_newctx_fn rsa_newctx;
static OSSL_OP_signature_sign_init_fn rsa_signature_init;
static OSSL_OP_signature_verify_init_fn rsa_signature_init;
static OSSL_OP_signature_verify_recover_init_fn rsa_signature_init;
static OSSL_OP_signature_sign_fn rsa_sign;
static OSSL_OP_signature_verify_fn rsa_verify;
static OSSL_OP_signature_verify_recover_fn rsa_verify_recover;
static OSSL_OP_signature_digest_sign_init_fn rsa_digest_signverify_init;
static OSSL_OP_signature_digest_sign_update_fn rsa_digest_signverify_update;
static OSSL_OP_signature_digest_sign_final_fn rsa_digest_sign_final;
static OSSL_OP_signature_digest_verify_init_fn rsa_digest_signverify_init;
static OSSL_OP_signature_digest_verify_update_fn rsa_digest_signverify_update;
static OSSL_OP_signature_digest_verify_final_fn rsa_digest_verify_final;
static OSSL_OP_signature_freectx_fn rsa_freectx;
static OSSL_OP_signature_dupctx_fn rsa_dupctx;
static OSSL_OP_signature_get_ctx_params_fn rsa_get_ctx_params;
static OSSL_OP_signature_gettable_ctx_params_fn rsa_gettable_ctx_params;
static OSSL_OP_signature_set_ctx_params_fn rsa_set_ctx_params;
static OSSL_OP_signature_settable_ctx_params_fn rsa_settable_ctx_params;
static OSSL_OP_signature_get_ctx_md_params_fn rsa_get_ctx_md_params;
static OSSL_OP_signature_gettable_ctx_md_params_fn rsa_gettable_ctx_md_params;
static OSSL_OP_signature_set_ctx_md_params_fn rsa_set_ctx_md_params;
static OSSL_OP_signature_settable_ctx_md_params_fn rsa_settable_ctx_md_params;
static OSSL_ITEM padding_item[] = {
{ RSA_PKCS1_PADDING, "pkcs1" },
{ RSA_SSLV23_PADDING, "sslv23" },
{ RSA_NO_PADDING, "none" },
{ RSA_PKCS1_OAEP_PADDING, "oaep" }, /* Correct spelling first */
{ RSA_PKCS1_OAEP_PADDING, "oeap" },
{ RSA_X931_PADDING, "x931" },
{ RSA_PKCS1_PSS_PADDING, "pss" },
{ 0, NULL }
};
/*
* What's passed as an actual key is defined by the KEYMGMT interface.
* We happen to know that our KEYMGMT simply passes RSA structures, so
* we use that here too.
*/
typedef struct {
OPENSSL_CTX *libctx;
RSA *rsa;
/*
* Flag to determine if the hash function can be changed (1) or not (0)
* Because it's dangerous to change during a DigestSign or DigestVerify
* operation, this flag is cleared by their Init function, and set again
* by their Final function.
*/
unsigned int flag_allow_md : 1;
/* The Algorithm Identifier of the combined signature agorithm */
unsigned char aid[128];
size_t aid_len;
/* main digest */
EVP_MD *md;
EVP_MD_CTX *mdctx;
int mdnid;
char mdname[OSSL_MAX_NAME_SIZE]; /* Purely informational */
/* RSA padding mode */
int pad_mode;
/* message digest for MGF1 */
EVP_MD *mgf1_md;
char mgf1_mdname[OSSL_MAX_NAME_SIZE]; /* Purely informational */
/* PSS salt length */
int saltlen;
/* Minimum salt length or -1 if no PSS parameter restriction */
int min_saltlen;
/* Temp buffer */
unsigned char *tbuf;
} PROV_RSA_CTX;
static size_t rsa_get_md_size(const PROV_RSA_CTX *prsactx)
{
if (prsactx->md != NULL)
return EVP_MD_size(prsactx->md);
return 0;
}
static int rsa_get_md_nid(const EVP_MD *md)
{
/*
* Because the RSA library deals with NIDs, we need to translate.
* We do so using EVP_MD_is_a(), and therefore need a name to NID
* map.
*/
static const OSSL_ITEM name_to_nid[] = {
{ NID_sha1, OSSL_DIGEST_NAME_SHA1 },
{ NID_sha224, OSSL_DIGEST_NAME_SHA2_224 },
{ NID_sha256, OSSL_DIGEST_NAME_SHA2_256 },
{ NID_sha384, OSSL_DIGEST_NAME_SHA2_384 },
{ NID_sha512, OSSL_DIGEST_NAME_SHA2_512 },
{ NID_md5, OSSL_DIGEST_NAME_MD5 },
{ NID_md5_sha1, OSSL_DIGEST_NAME_MD5_SHA1 },
{ NID_md2, OSSL_DIGEST_NAME_MD2 },
{ NID_md4, OSSL_DIGEST_NAME_MD4 },
{ NID_mdc2, OSSL_DIGEST_NAME_MDC2 },
{ NID_ripemd160, OSSL_DIGEST_NAME_RIPEMD160 },
{ NID_sha3_224, OSSL_DIGEST_NAME_SHA3_224 },
{ NID_sha3_256, OSSL_DIGEST_NAME_SHA3_256 },
{ NID_sha3_384, OSSL_DIGEST_NAME_SHA3_384 },
{ NID_sha3_512, OSSL_DIGEST_NAME_SHA3_512 },
};
size_t i;
int mdnid = NID_undef;
if (md == NULL)
goto end;
for (i = 0; i < OSSL_NELEM(name_to_nid); i++) {
if (EVP_MD_is_a(md, name_to_nid[i].ptr)) {
mdnid = (int)name_to_nid[i].id;
break;
}
}
if (mdnid == NID_undef)
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST);
end:
return mdnid;
}
static int rsa_check_padding(int mdnid, int padding)
{
if (padding == RSA_NO_PADDING) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE);
return 0;
}
if (padding == RSA_X931_PADDING) {
if (RSA_X931_hash_id(mdnid) == -1) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_X931_DIGEST);
return 0;
}
}
return 1;
}
static void *rsa_newctx(void *provctx)
{
PROV_RSA_CTX *prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX));
if (prsactx == NULL)
return NULL;
prsactx->libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
prsactx->flag_allow_md = 1;
return prsactx;
}
/* True if PSS parameters are restricted */
#define rsa_pss_restricted(prsactx) (prsactx->min_saltlen != -1)
static int rsa_signature_init(void *vprsactx, void *vrsa)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
if (prsactx == NULL || vrsa == NULL || !RSA_up_ref(vrsa))
return 0;
RSA_free(prsactx->rsa);
prsactx->rsa = vrsa;
if (RSA_get0_pss_params(prsactx->rsa) != NULL)
prsactx->pad_mode = RSA_PKCS1_PSS_PADDING;
else
prsactx->pad_mode = RSA_PKCS1_PADDING;
/* Maximum for sign, auto for verify */
prsactx->saltlen = RSA_PSS_SALTLEN_AUTO;
prsactx->min_saltlen = -1;
return 1;
}
static int rsa_setup_md(PROV_RSA_CTX *ctx, const char *mdname,
const char *mdprops)
{
if (mdname != NULL) {
EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops);
int md_nid = rsa_get_md_nid(md);
size_t algorithmidentifier_len = 0;
const unsigned char *algorithmidentifier = NULL;
if (md == NULL)
return 0;
if (!rsa_check_padding(md_nid, ctx->pad_mode)) {
EVP_MD_free(md);
return 0;
}
EVP_MD_CTX_free(ctx->mdctx);
EVP_MD_free(ctx->md);
ctx->md = NULL;
ctx->mdctx = NULL;
ctx->mdname[0] = '\0';
ctx->aid[0] = '\0';
ctx->aid_len = 0;
algorithmidentifier =
rsa_algorithmidentifier_encoding(md_nid, &algorithmidentifier_len);
ctx->md = md;
ctx->mdnid = md_nid;
OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname));
if (algorithmidentifier != NULL) {
memcpy(ctx->aid, algorithmidentifier, algorithmidentifier_len);
ctx->aid_len = algorithmidentifier_len;
}
}
return 1;
}
static int rsa_setup_mgf1_md(PROV_RSA_CTX *ctx, const char *mdname,
const char *props)
{
if (ctx->mgf1_mdname[0] != '\0')
EVP_MD_free(ctx->mgf1_md);
if ((ctx->mgf1_md = EVP_MD_fetch(ctx->libctx, mdname, props)) == NULL)
return 0;
OPENSSL_strlcpy(ctx->mgf1_mdname, mdname, sizeof(ctx->mgf1_mdname));
return 1;
}
static int setup_tbuf(PROV_RSA_CTX *ctx)
{
if (ctx->tbuf != NULL)
return 1;
if ((ctx->tbuf = OPENSSL_malloc(RSA_size(ctx->rsa))) == NULL) {
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return 0;
}
return 1;
}
static void clean_tbuf(PROV_RSA_CTX *ctx)
{
if (ctx->tbuf != NULL)
OPENSSL_cleanse(ctx->tbuf, RSA_size(ctx->rsa));
}
static void free_tbuf(PROV_RSA_CTX *ctx)
{
OPENSSL_clear_free(ctx->tbuf, RSA_size(ctx->rsa));
ctx->tbuf = NULL;
}
static int rsa_sign(void *vprsactx, unsigned char *sig, size_t *siglen,
size_t sigsize, const unsigned char *tbs, size_t tbslen)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
int ret;
size_t rsasize = RSA_size(prsactx->rsa);
size_t mdsize = rsa_get_md_size(prsactx);
if (sig == NULL) {
*siglen = rsasize;
return 1;
}
if (sigsize < (size_t)rsasize)
return 0;
if (mdsize != 0) {
if (tbslen != mdsize) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH);
return 0;
}
#ifndef FIPS_MODE
if (EVP_MD_is_a(prsactx->md, OSSL_DIGEST_NAME_MDC2)) {
unsigned int sltmp;
if (prsactx->pad_mode != RSA_PKCS1_PADDING) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
"only PKCS#1 padding supported with MDC2");
return 0;
}
ret = RSA_sign_ASN1_OCTET_STRING(0, tbs, tbslen, sig, &sltmp,
prsactx->rsa);
if (ret <= 0) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
ret = sltmp;
goto end;
}
#endif
switch (prsactx->pad_mode) {
case RSA_X931_PADDING:
if ((size_t)RSA_size(prsactx->rsa) < tbslen + 1) {
ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL);
return 0;
}
if (!setup_tbuf(prsactx)) {
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return 0;
}
memcpy(prsactx->tbuf, tbs, tbslen);
prsactx->tbuf[tbslen] = RSA_X931_hash_id(prsactx->mdnid);
ret = RSA_private_encrypt(tbslen + 1, prsactx->tbuf,
sig, prsactx->rsa, RSA_X931_PADDING);
clean_tbuf(prsactx);
break;
case RSA_PKCS1_PADDING:
{
unsigned int sltmp;
ret = RSA_sign(prsactx->mdnid, tbs, tbslen, sig, &sltmp,
prsactx->rsa);
if (ret <= 0) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
ret = sltmp;
}
break;
case RSA_PKCS1_PSS_PADDING:
/* Check PSS restrictions */
if (rsa_pss_restricted(prsactx)) {
switch (prsactx->saltlen) {
case RSA_PSS_SALTLEN_DIGEST:
if (prsactx->min_saltlen > EVP_MD_size(prsactx->md)) {
ERR_raise(ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL);
return 0;
}
/* FALLTHRU */
default:
if (prsactx->saltlen >= 0
&& prsactx->saltlen < prsactx->min_saltlen) {
ERR_raise(ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL);
return 0;
}
break;
}
}
if (!setup_tbuf(prsactx))
return 0;
if (!RSA_padding_add_PKCS1_PSS_mgf1(prsactx->rsa,
prsactx->tbuf, tbs,
prsactx->md, prsactx->mgf1_md,
prsactx->saltlen)) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
ret = RSA_private_encrypt(RSA_size(prsactx->rsa), prsactx->tbuf,
sig, prsactx->rsa, RSA_NO_PADDING);
clean_tbuf(prsactx);
break;
default:
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
"Only X.931, PKCS#1 v1.5 or PSS padding allowed");
return 0;
}
} else {
ret = RSA_private_encrypt(tbslen, tbs, sig, prsactx->rsa,
prsactx->pad_mode);
}
#ifndef FIPS_MODE
end:
#endif
if (ret <= 0) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
*siglen = ret;
return 1;
}
static int rsa_verify_recover(void *vprsactx,
unsigned char *rout,
size_t *routlen,
size_t routsize,
const unsigned char *sig,
size_t siglen)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
int ret;
if (rout == NULL) {
*routlen = RSA_size(prsactx->rsa);
return 1;
}
if (prsactx->md != NULL) {
switch (prsactx->pad_mode) {
case RSA_X931_PADDING:
if (!setup_tbuf(prsactx))
return 0;
ret = RSA_public_decrypt(siglen, sig, prsactx->tbuf, prsactx->rsa,
RSA_X931_PADDING);
if (ret < 1) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
ret--;
if (prsactx->tbuf[ret] != RSA_X931_hash_id(prsactx->mdnid)) {
ERR_raise(ERR_LIB_PROV, PROV_R_ALGORITHM_MISMATCH);
return 0;
}
if (ret != EVP_MD_size(prsactx->md)) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH,
"Should be %d, but got %d",
EVP_MD_size(prsactx->md), ret);
return 0;
}
*routlen = ret;
if (routsize < (size_t)ret) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
memcpy(rout, prsactx->tbuf, ret);
break;
case RSA_PKCS1_PADDING:
{
size_t sltmp;
ret = int_rsa_verify(prsactx->mdnid, NULL, 0, rout, &sltmp,
sig, siglen, prsactx->rsa);
if (ret <= 0) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
ret = sltmp;
}
break;
default:
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
"Only X.931 or PKCS#1 v1.5 padding allowed");
return 0;
}
} else {
ret = RSA_public_decrypt(siglen, sig, rout, prsactx->rsa,
prsactx->pad_mode);
if (ret < 0) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
}
*routlen = ret;
return 1;
}
static int rsa_verify(void *vprsactx, const unsigned char *sig, size_t siglen,
const unsigned char *tbs, size_t tbslen)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
size_t rslen;
if (prsactx->md != NULL) {
switch (prsactx->pad_mode) {
case RSA_PKCS1_PADDING:
if (!RSA_verify(prsactx->mdnid, tbs, tbslen, sig, siglen,
prsactx->rsa)) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
return 1;
case RSA_X931_PADDING:
if (rsa_verify_recover(prsactx, NULL, &rslen, 0, sig, siglen) <= 0)
return 0;
break;
case RSA_PKCS1_PSS_PADDING:
{
int ret;
size_t mdsize;
/* Check PSS restrictions */
if (rsa_pss_restricted(prsactx)) {
switch (prsactx->saltlen) {
case RSA_PSS_SALTLEN_AUTO:
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PSS_SALTLEN);
return 0;
case RSA_PSS_SALTLEN_DIGEST:
if (prsactx->min_saltlen > EVP_MD_size(prsactx->md)) {
ERR_raise(ERR_LIB_PROV,
PROV_R_PSS_SALTLEN_TOO_SMALL);
return 0;
}
/* FALLTHRU */
default:
if (prsactx->saltlen >= 0
&& prsactx->saltlen < prsactx->min_saltlen) {
ERR_raise(ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL);
return 0;
}
break;
}
}
/*
* We need to check this for the RSA_verify_PKCS1_PSS_mgf1()
* call
*/
mdsize = rsa_get_md_size(prsactx);
if (tbslen != mdsize) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH,
"Should be %d, but got %d",
mdsize, tbslen);
return 0;
}
if (!setup_tbuf(prsactx))
return 0;
ret = RSA_public_decrypt(siglen, sig, prsactx->tbuf,
prsactx->rsa, RSA_NO_PADDING);
if (ret <= 0) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
ret = RSA_verify_PKCS1_PSS_mgf1(prsactx->rsa, tbs,
prsactx->md, prsactx->mgf1_md,
prsactx->tbuf,
prsactx->saltlen);
if (ret <= 0) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
return 1;
}
default:
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
"Only X.931, PKCS#1 v1.5 or PSS padding allowed");
return 0;
}
} else {
if (!setup_tbuf(prsactx))
return 0;
rslen = RSA_public_decrypt(siglen, sig, prsactx->tbuf, prsactx->rsa,
prsactx->pad_mode);
if (rslen == 0) {
ERR_raise(ERR_LIB_PROV, ERR_LIB_RSA);
return 0;
}
}
if ((rslen != tbslen) || memcmp(tbs, prsactx->tbuf, rslen))
return 0;
return 1;
}
static int rsa_digest_signverify_init(void *vprsactx, const char *mdname,
const char *props, void *vrsa)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
prsactx->flag_allow_md = 0;
if (!rsa_signature_init(vprsactx, vrsa)
|| !rsa_setup_md(prsactx, mdname, props))
return 0;
prsactx->mdctx = EVP_MD_CTX_new();
if (prsactx->mdctx == NULL)
goto error;
if (!EVP_DigestInit_ex(prsactx->mdctx, prsactx->md, NULL))
goto error;
return 1;
error:
EVP_MD_CTX_free(prsactx->mdctx);
EVP_MD_free(prsactx->md);
prsactx->mdctx = NULL;
prsactx->md = NULL;
return 0;
}
int rsa_digest_signverify_update(void *vprsactx, const unsigned char *data,
size_t datalen)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
if (prsactx == NULL || prsactx->mdctx == NULL)
return 0;
return EVP_DigestUpdate(prsactx->mdctx, data, datalen);
}
int rsa_digest_sign_final(void *vprsactx, unsigned char *sig, size_t *siglen,
size_t sigsize)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int dlen = 0;
prsactx->flag_allow_md = 1;
if (prsactx == NULL || prsactx->mdctx == NULL)
return 0;
/*
* If sig is NULL then we're just finding out the sig size. Other fields
* are ignored. Defer to rsa_sign.
*/
if (sig != NULL) {
/*
* TODO(3.0): There is the possibility that some externally provided
* digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow -
* but that problem is much larger than just in RSA.
*/
if (!EVP_DigestFinal_ex(prsactx->mdctx, digest, &dlen))
return 0;
}
return rsa_sign(vprsactx, sig, siglen, sigsize, digest, (size_t)dlen);
}
int rsa_digest_verify_final(void *vprsactx, const unsigned char *sig,
size_t siglen)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int dlen = 0;
prsactx->flag_allow_md = 1;
if (prsactx == NULL || prsactx->mdctx == NULL)
return 0;
/*
* TODO(3.0): There is the possibility that some externally provided
* digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow -
* but that problem is much larger than just in RSA.
*/
if (!EVP_DigestFinal_ex(prsactx->mdctx, digest, &dlen))
return 0;
return rsa_verify(vprsactx, sig, siglen, digest, (size_t)dlen);
}
static void rsa_freectx(void *vprsactx)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
if (prsactx == NULL)
return;
RSA_free(prsactx->rsa);
EVP_MD_CTX_free(prsactx->mdctx);
EVP_MD_free(prsactx->md);
EVP_MD_free(prsactx->mgf1_md);
free_tbuf(prsactx);
OPENSSL_clear_free(prsactx, sizeof(prsactx));
}
static void *rsa_dupctx(void *vprsactx)
{
PROV_RSA_CTX *srcctx = (PROV_RSA_CTX *)vprsactx;
PROV_RSA_CTX *dstctx;
dstctx = OPENSSL_zalloc(sizeof(*srcctx));
if (dstctx == NULL)
return NULL;
*dstctx = *srcctx;
dstctx->rsa = NULL;
dstctx->md = NULL;
dstctx->mdctx = NULL;
dstctx->tbuf = NULL;
if (srcctx->rsa != NULL && !RSA_up_ref(srcctx->rsa))
goto err;
dstctx->rsa = srcctx->rsa;
if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md))
goto err;
dstctx->md = srcctx->md;
if (srcctx->mgf1_md != NULL && !EVP_MD_up_ref(srcctx->mgf1_md))
goto err;
dstctx->mgf1_md = srcctx->mgf1_md;
if (srcctx->mdctx != NULL) {
dstctx->mdctx = EVP_MD_CTX_new();
if (dstctx->mdctx == NULL
|| !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx))
goto err;
}
return dstctx;
err:
rsa_freectx(dstctx);
return NULL;
}
static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
OSSL_PARAM *p;
if (prsactx == NULL || params == NULL)
return 0;
p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
if (p != NULL
&& !OSSL_PARAM_set_octet_string(p, prsactx->aid, prsactx->aid_len))
return 0;
p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PAD_MODE);
if (p != NULL)
switch (p->data_type) {
case OSSL_PARAM_INTEGER:
if (!OSSL_PARAM_set_int(p, prsactx->pad_mode))
return 0;
break;
case OSSL_PARAM_UTF8_STRING:
{
int i;
const char *word = NULL;
for (i = 0; padding_item[i].id != 0; i++) {
if (prsactx->pad_mode == (int)padding_item[i].id) {
word = padding_item[i].ptr;
break;
}
}
if (word != NULL) {
if (!OSSL_PARAM_set_utf8_string(p, word))
return 0;
} else {
ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
}
}
break;
default:
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST);
if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->mdname))
return 0;
p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_MGF1_DIGEST);
if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->mgf1_mdname))
return 0;
p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN);
if (p != NULL) {
if (p->data_type == OSSL_PARAM_INTEGER) {
if (!OSSL_PARAM_set_int(p, prsactx->saltlen))
return 0;
} else if (p->data_type == OSSL_PARAM_UTF8_STRING) {
switch (prsactx->saltlen) {
case RSA_PSS_SALTLEN_DIGEST:
if (!OSSL_PARAM_set_utf8_string(p, "digest"))
return 0;
break;
case RSA_PSS_SALTLEN_MAX:
if (!OSSL_PARAM_set_utf8_string(p, "max"))
return 0;
break;
case RSA_PSS_SALTLEN_AUTO:
if (!OSSL_PARAM_set_utf8_string(p, "auto"))
return 0;
break;
default:
if (BIO_snprintf(p->data, p->data_size, "%d", prsactx->saltlen)
<= 0)
return 0;
break;
}
}
}
return 1;
}
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0),
OSSL_PARAM_END
};
static const OSSL_PARAM *rsa_gettable_ctx_params(void)
{
return known_gettable_ctx_params;
}
static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
const OSSL_PARAM *p;
if (prsactx == NULL || params == NULL)
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST);
/* Not allowed during certain operations */
if (p != NULL && !prsactx->flag_allow_md)
return 0;
if (p != NULL) {
char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = mdname;
char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = mdprops;
const OSSL_PARAM *propsp =
OSSL_PARAM_locate_const(params,
OSSL_SIGNATURE_PARAM_PROPERTIES);
if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname)))
return 0;
if (propsp != NULL
&& !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops)))
return 0;
/* TODO(3.0) PSS check needs more work */
if (rsa_pss_restricted(prsactx)) {
/* TODO(3.0) figure out what to do for prsactx->md == NULL */
if (prsactx->md == NULL || EVP_MD_is_a(prsactx->md, mdname))
return 1;
ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED);
return 0;
}
/* non-PSS code follows */
if (!rsa_setup_md(prsactx, mdname, mdprops))
return 0;
}
p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PAD_MODE);
if (p != NULL) {
int pad_mode = 0;
switch (p->data_type) {
case OSSL_PARAM_INTEGER: /* Support for legacy pad mode number */
if (!OSSL_PARAM_get_int(p, &pad_mode))
return 0;
break;
case OSSL_PARAM_UTF8_STRING:
{
int i;
if (p->data == NULL)
return 0;
for (i = 0; padding_item[i].id != 0; i++) {
if (strcmp(p->data, padding_item[i].ptr) == 0) {
pad_mode = padding_item[i].id;
break;
}
}
}
break;
default:
return 0;
}
switch (pad_mode) {
case RSA_PKCS1_OAEP_PADDING:
/*
* OAEP padding is for asymmetric cipher only so is not compatible
* with signature use.
*/
ERR_raise_data(ERR_LIB_PROV,
PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE,
"OAEP padding not allowed for signing / verifying");
return 0;
case RSA_PKCS1_PSS_PADDING:
if (prsactx->mdname[0] == '\0')
rsa_setup_md(prsactx, "SHA1", "");
goto cont;
case RSA_PKCS1_PADDING:
case RSA_SSLV23_PADDING:
case RSA_NO_PADDING:
case RSA_X931_PADDING:
if (RSA_get0_pss_params(prsactx->rsa) != NULL) {
ERR_raise_data(ERR_LIB_PROV,
PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE,
"X.931 padding not allowed with RSA-PSS");
return 0;
}
cont:
if (!rsa_check_padding(prsactx->mdnid, pad_mode))
return 0;
break;
default:
return 0;
}
prsactx->pad_mode = pad_mode;
}
p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN);
if (p != NULL) {
int saltlen;
if (prsactx->pad_mode != RSA_PKCS1_PSS_PADDING) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED,
"PSS saltlen can only be specified if "
"PSS padding has been specified first");
return 0;
}
switch (p->data_type) {
case OSSL_PARAM_INTEGER: /* Support for legacy pad mode number */
if (!OSSL_PARAM_get_int(p, &saltlen))
return 0;
break;
case OSSL_PARAM_UTF8_STRING:
if (strcmp(p->data, "digest") == 0)
saltlen = RSA_PSS_SALTLEN_DIGEST;
else if (strcmp(p->data, "max") == 0)
saltlen = RSA_PSS_SALTLEN_MAX;
else if (strcmp(p->data, "auto") == 0)
saltlen = RSA_PSS_SALTLEN_AUTO;
else
saltlen = atoi(p->data);
break;
default:
return 0;
}
/*
* RSA_PSS_SALTLEN_MAX seems curiously named in this check.
* Contrary to what it's name suggests, it's the currently
* lowest saltlen number possible.
*/
if (saltlen < RSA_PSS_SALTLEN_MAX) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PSS_SALTLEN);
return 0;
}
prsactx->saltlen = saltlen;
}
p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MGF1_DIGEST);
if (p != NULL) {
char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = mdname;
char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = mdprops;
const OSSL_PARAM *propsp =
OSSL_PARAM_locate_const(params,
OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES);
if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname)))
return 0;
if (propsp != NULL
&& !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops)))
return 0;
if (prsactx->pad_mode != RSA_PKCS1_PSS_PADDING) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MGF1_MD);
return 0;
}
/* TODO(3.0) PSS check needs more work */
if (rsa_pss_restricted(prsactx)) {
/* TODO(3.0) figure out what to do for prsactx->md == NULL */
if (prsactx->mgf1_md == NULL
|| EVP_MD_is_a(prsactx->mgf1_md, mdname))
return 1;
ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED);
return 0;
}
/* non-PSS code follows */
if (!rsa_setup_mgf1_md(prsactx, mdname, mdprops))
return 0;
}
return 1;
}
static const OSSL_PARAM known_settable_ctx_params[] = {
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0),
OSSL_PARAM_END
};
static const OSSL_PARAM *rsa_settable_ctx_params(void)
{
/*
* TODO(3.0): Should this function return a different set of settable ctx
* params if the ctx is being used for a DigestSign/DigestVerify? In that
* case it is not allowed to set the digest size/digest name because the
* digest is explicitly set as part of the init.
*/
return known_settable_ctx_params;
}
static int rsa_get_ctx_md_params(void *vprsactx, OSSL_PARAM *params)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
if (prsactx->mdctx == NULL)
return 0;
return EVP_MD_CTX_get_params(prsactx->mdctx, params);
}
static const OSSL_PARAM *rsa_gettable_ctx_md_params(void *vprsactx)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
if (prsactx->md == NULL)
return 0;
return EVP_MD_gettable_ctx_params(prsactx->md);
}
static int rsa_set_ctx_md_params(void *vprsactx, const OSSL_PARAM params[])
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
if (prsactx->mdctx == NULL)
return 0;
return EVP_MD_CTX_set_params(prsactx->mdctx, params);
}
static const OSSL_PARAM *rsa_settable_ctx_md_params(void *vprsactx)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
if (prsactx->md == NULL)
return 0;
return EVP_MD_settable_ctx_params(prsactx->md);
}
const OSSL_DISPATCH rsa_signature_functions[] = {
{ OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))rsa_newctx },
{ OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))rsa_signature_init },
{ OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))rsa_sign },
{ OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))rsa_signature_init },
{ OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))rsa_verify },
{ OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT, (void (*)(void))rsa_signature_init },
{ OSSL_FUNC_SIGNATURE_VERIFY_RECOVER, (void (*)(void))rsa_verify_recover },
{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,
(void (*)(void))rsa_digest_signverify_init },
{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE,
(void (*)(void))rsa_digest_signverify_update },
{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL,
(void (*)(void))rsa_digest_sign_final },
{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT,
(void (*)(void))rsa_digest_signverify_init },
{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE,
(void (*)(void))rsa_digest_signverify_update },
{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL,
(void (*)(void))rsa_digest_verify_final },
{ OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))rsa_freectx },
{ OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))rsa_dupctx },
{ OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))rsa_get_ctx_params },
{ OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,
(void (*)(void))rsa_gettable_ctx_params },
{ OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))rsa_set_ctx_params },
{ OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
(void (*)(void))rsa_settable_ctx_params },
{ OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS,
(void (*)(void))rsa_get_ctx_md_params },
{ OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS,
(void (*)(void))rsa_gettable_ctx_md_params },
{ OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS,
(void (*)(void))rsa_set_ctx_md_params },
{ OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS,
(void (*)(void))rsa_settable_ctx_md_params },
{ 0, NULL }
};