mirror of
https://github.com/openssl/openssl.git
synced 2025-01-24 13:55:42 +08:00
c319b6276b
The base functionality to implement the keypair encoders doesn't change much, but this results in a more massive amount of OSSL_DISPATCH and OSSL_ALGORITHM arrays, to support a fine grained selection of implementation based on what parts of the keypair structure (combinations of key parameters, public key and private key) should be output, the output type ("TEXT", "DER" or "PEM") and the outermost output structure ("pkcs8", "SubjectPublicKeyInfo", key type specific structures, ...). We add support for the generic structure name "type-specific", to allow selecting that without knowing the exact name of that structure. Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from https://github.com/openssl/openssl/pull/13167)
1390 lines
51 KiB
C
1390 lines
51 KiB
C
/*
|
|
* 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
|
|
*/
|
|
|
|
/*
|
|
* Low level APIs are deprecated for public use, but still ok for internal use.
|
|
*/
|
|
#include "internal/deprecated.h"
|
|
|
|
#include <openssl/core.h>
|
|
#include <openssl/core_dispatch.h>
|
|
#include <openssl/core_names.h>
|
|
#include <openssl/crypto.h>
|
|
#include <openssl/params.h>
|
|
#include <openssl/asn1.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/pem.h>
|
|
#include <openssl/x509.h>
|
|
#include <openssl/pkcs12.h> /* PKCS8_encrypt() */
|
|
#include <openssl/dh.h>
|
|
#include <openssl/dsa.h>
|
|
#include <openssl/ec.h>
|
|
#include "internal/passphrase.h"
|
|
#include "internal/cryptlib.h"
|
|
#include "crypto/ecx.h"
|
|
#include "crypto/rsa.h"
|
|
#include "prov/implementations.h"
|
|
#include "prov/providercommonerr.h"
|
|
#include "prov/bio.h"
|
|
#include "prov/provider_ctx.h"
|
|
#include "prov/der_rsa.h"
|
|
#include "endecoder_local.h"
|
|
|
|
struct key2any_ctx_st {
|
|
PROV_CTX *provctx;
|
|
|
|
/* Set to 1 if intending to encrypt/decrypt, otherwise 0 */
|
|
int cipher_intent;
|
|
|
|
EVP_CIPHER *cipher;
|
|
|
|
struct ossl_passphrase_data_st pwdata;
|
|
};
|
|
|
|
typedef int check_key_type_fn(const void *key, int nid);
|
|
typedef int key_to_paramstring_fn(const void *key, int nid,
|
|
void **str, int *strtype);
|
|
typedef int key_to_der_fn(BIO *out, const void *key,
|
|
int key_nid, const char *pemname,
|
|
key_to_paramstring_fn *p2s, i2d_of_void *k2d,
|
|
struct key2any_ctx_st *ctx);
|
|
typedef int write_bio_of_void_fn(BIO *bp, const void *x);
|
|
|
|
static PKCS8_PRIV_KEY_INFO *key_to_p8info(const void *key, int key_nid,
|
|
void *params, int params_type,
|
|
i2d_of_void *k2d)
|
|
{
|
|
/* der, derlen store the key DER output and its length */
|
|
unsigned char *der = NULL;
|
|
int derlen;
|
|
/* The final PKCS#8 info */
|
|
PKCS8_PRIV_KEY_INFO *p8info = NULL;
|
|
|
|
|
|
if ((p8info = PKCS8_PRIV_KEY_INFO_new()) == NULL
|
|
|| (derlen = k2d(key, &der)) <= 0
|
|
|| !PKCS8_pkey_set0(p8info, OBJ_nid2obj(key_nid), 0,
|
|
params_type, params, der, derlen)) {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
|
|
PKCS8_PRIV_KEY_INFO_free(p8info);
|
|
OPENSSL_free(der);
|
|
p8info = NULL;
|
|
}
|
|
|
|
return p8info;
|
|
}
|
|
|
|
static X509_SIG *p8info_to_encp8(PKCS8_PRIV_KEY_INFO *p8info,
|
|
struct key2any_ctx_st *ctx)
|
|
{
|
|
X509_SIG *p8 = NULL;
|
|
char kstr[PEM_BUFSIZE];
|
|
size_t klen = 0;
|
|
|
|
if (ctx->cipher == NULL)
|
|
return NULL;
|
|
|
|
if (!ossl_pw_get_passphrase(kstr, sizeof(kstr), &klen, NULL, 1,
|
|
&ctx->pwdata)) {
|
|
ERR_raise(ERR_LIB_PROV, PROV_R_READ_KEY);
|
|
return NULL;
|
|
}
|
|
/* First argument == -1 means "standard" */
|
|
p8 = PKCS8_encrypt(-1, ctx->cipher, kstr, klen, NULL, 0, 0, p8info);
|
|
OPENSSL_cleanse(kstr, klen);
|
|
return p8;
|
|
}
|
|
|
|
static X509_SIG *key_to_encp8(const void *key, int key_nid,
|
|
void *params, int params_type,
|
|
i2d_of_void *k2d, struct key2any_ctx_st *ctx)
|
|
{
|
|
PKCS8_PRIV_KEY_INFO *p8info =
|
|
key_to_p8info(key, key_nid, params, params_type, k2d);
|
|
X509_SIG *p8 = p8info_to_encp8(p8info, ctx);
|
|
|
|
PKCS8_PRIV_KEY_INFO_free(p8info);
|
|
return p8;
|
|
}
|
|
|
|
static X509_PUBKEY *key_to_pubkey(const void *key, int key_nid,
|
|
void *params, int params_type,
|
|
i2d_of_void k2d)
|
|
{
|
|
/* der, derlen store the key DER output and its length */
|
|
unsigned char *der = NULL;
|
|
int derlen;
|
|
/* The final X509_PUBKEY */
|
|
X509_PUBKEY *xpk = NULL;
|
|
|
|
|
|
if ((xpk = X509_PUBKEY_new()) == NULL
|
|
|| (derlen = k2d(key, &der)) <= 0
|
|
|| !X509_PUBKEY_set0_param(xpk, OBJ_nid2obj(key_nid),
|
|
params_type, params, der, derlen)) {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
|
|
X509_PUBKEY_free(xpk);
|
|
OPENSSL_free(der);
|
|
xpk = NULL;
|
|
}
|
|
|
|
return xpk;
|
|
}
|
|
|
|
/*
|
|
* key_to_pkcs8_* produce encoded output with the key data pkcs8
|
|
* in a structure. For private keys, that structure is PKCS#8, and for
|
|
* public keys, it's X.509 SubjectPublicKeyInfo. Parameters don't have
|
|
* any defined envelopment of that kind.
|
|
*/
|
|
static int key_to_pkcs8_der_priv_bio(BIO *out, const void *key,
|
|
int key_nid,
|
|
ossl_unused const char *pemname,
|
|
key_to_paramstring_fn *p2s,
|
|
i2d_of_void *k2d,
|
|
struct key2any_ctx_st *ctx)
|
|
{
|
|
int ret = 0;
|
|
void *str = NULL;
|
|
int strtype = V_ASN1_UNDEF;
|
|
|
|
if (p2s != NULL && !p2s(key, key_nid, &str, &strtype))
|
|
return 0;
|
|
|
|
if (ctx->cipher_intent) {
|
|
X509_SIG *p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx);
|
|
|
|
if (p8 != NULL)
|
|
ret = i2d_PKCS8_bio(out, p8);
|
|
|
|
X509_SIG_free(p8);
|
|
} else {
|
|
PKCS8_PRIV_KEY_INFO *p8info =
|
|
key_to_p8info(key, key_nid, str, strtype, k2d);
|
|
|
|
if (p8info != NULL)
|
|
ret = i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8info);
|
|
|
|
PKCS8_PRIV_KEY_INFO_free(p8info);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int key_to_pkcs8_pem_priv_bio(BIO *out, const void *key,
|
|
int key_nid,
|
|
ossl_unused const char *pemname,
|
|
key_to_paramstring_fn *p2s,
|
|
i2d_of_void *k2d,
|
|
struct key2any_ctx_st *ctx)
|
|
{
|
|
int ret = 0;
|
|
void *str = NULL;
|
|
int strtype = V_ASN1_UNDEF;
|
|
|
|
if (p2s != NULL && !p2s(key, key_nid, &str, &strtype))
|
|
return 0;
|
|
|
|
if (ctx->cipher_intent) {
|
|
X509_SIG *p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx);
|
|
|
|
if (p8 != NULL)
|
|
ret = PEM_write_bio_PKCS8(out, p8);
|
|
|
|
X509_SIG_free(p8);
|
|
} else {
|
|
PKCS8_PRIV_KEY_INFO *p8info =
|
|
key_to_p8info(key, key_nid, str, strtype, k2d);
|
|
|
|
if (p8info != NULL)
|
|
ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8info);
|
|
|
|
PKCS8_PRIV_KEY_INFO_free(p8info);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int key_to_spki_der_pub_bio(BIO *out, const void *key,
|
|
int key_nid,
|
|
ossl_unused const char *pemname,
|
|
key_to_paramstring_fn *p2s,
|
|
i2d_of_void *k2d,
|
|
struct key2any_ctx_st *ctx)
|
|
{
|
|
int ret = 0;
|
|
void *str = NULL;
|
|
int strtype = V_ASN1_UNDEF;
|
|
X509_PUBKEY *xpk = NULL;
|
|
|
|
if (p2s != NULL && !p2s(key, key_nid, &str, &strtype))
|
|
return 0;
|
|
|
|
xpk = key_to_pubkey(key, key_nid, str, strtype, k2d);
|
|
|
|
if (xpk != NULL)
|
|
ret = i2d_X509_PUBKEY_bio(out, xpk);
|
|
|
|
/* Also frees |str| */
|
|
X509_PUBKEY_free(xpk);
|
|
return ret;
|
|
}
|
|
|
|
static int key_to_spki_pem_pub_bio(BIO *out, const void *key,
|
|
int key_nid,
|
|
ossl_unused const char *pemname,
|
|
key_to_paramstring_fn *p2s,
|
|
i2d_of_void *k2d,
|
|
struct key2any_ctx_st *ctx)
|
|
{
|
|
int ret = 0;
|
|
void *str = NULL;
|
|
int strtype = V_ASN1_UNDEF;
|
|
X509_PUBKEY *xpk = NULL;
|
|
|
|
if (p2s != NULL && !p2s(key, key_nid, &str, &strtype))
|
|
return 0;
|
|
|
|
xpk = key_to_pubkey(key, key_nid, str, strtype, k2d);
|
|
|
|
if (xpk != NULL)
|
|
ret = PEM_write_bio_X509_PUBKEY(out, xpk);
|
|
|
|
/* Also frees |str| */
|
|
X509_PUBKEY_free(xpk);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* key_to_type_specific_* produce encoded output with type specific key data,
|
|
* no envelopment; the same kind of output as the type specific i2d_ and
|
|
* PEM_write_ functions, which is often a simple SEQUENCE of INTEGER.
|
|
*
|
|
* OpenSSL tries to discourage production of new keys in this form, because
|
|
* of the ambiguity when trying to recognise them, but can't deny that PKCS#1
|
|
* et al still are live standards.
|
|
*
|
|
* Note that these functions completely ignore p2s, and rather rely entirely
|
|
* on k2d to do the complete work.
|
|
*/
|
|
static int key_to_type_specific_der_bio(BIO *out, const void *key,
|
|
int key_nid,
|
|
ossl_unused const char *pemname,
|
|
key_to_paramstring_fn *p2s,
|
|
i2d_of_void *k2d,
|
|
struct key2any_ctx_st *ctx)
|
|
{
|
|
unsigned char *der = NULL;
|
|
int derlen;
|
|
int ret;
|
|
|
|
if ((derlen = k2d(key, &der)) <= 0) {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
ret = BIO_write(out, der, derlen);
|
|
OPENSSL_free(der);
|
|
return ret > 0;
|
|
}
|
|
#define key_to_type_specific_der_priv_bio key_to_type_specific_der_bio
|
|
#define key_to_type_specific_der_pub_bio key_to_type_specific_der_bio
|
|
#define key_to_type_specific_der_param_bio key_to_type_specific_der_bio
|
|
|
|
static int key_to_type_specific_pem_bio_cb(BIO *out, const void *key,
|
|
int key_nid, const char *pemname,
|
|
key_to_paramstring_fn *p2s,
|
|
i2d_of_void *k2d,
|
|
struct key2any_ctx_st *ctx,
|
|
pem_password_cb *cb, void *cbarg)
|
|
{
|
|
return
|
|
PEM_ASN1_write_bio(k2d, pemname, out, key, ctx->cipher,
|
|
NULL, 0, ossl_pw_pem_password, &ctx->pwdata) > 0;
|
|
}
|
|
|
|
static int key_to_type_specific_pem_priv_bio(BIO *out, const void *key,
|
|
int key_nid, const char *pemname,
|
|
key_to_paramstring_fn *p2s,
|
|
i2d_of_void *k2d,
|
|
struct key2any_ctx_st *ctx)
|
|
{
|
|
return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname,
|
|
p2s, k2d, ctx,
|
|
ossl_pw_pem_password, &ctx->pwdata);
|
|
}
|
|
|
|
static int key_to_type_specific_pem_pub_bio(BIO *out, const void *key,
|
|
int key_nid, const char *pemname,
|
|
key_to_paramstring_fn *p2s,
|
|
i2d_of_void *k2d,
|
|
struct key2any_ctx_st *ctx)
|
|
{
|
|
return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname,
|
|
p2s, k2d, ctx, NULL, NULL);
|
|
}
|
|
|
|
static int key_to_type_specific_pem_param_bio(BIO *out, const void *key,
|
|
int key_nid, const char *pemname,
|
|
key_to_paramstring_fn *p2s,
|
|
i2d_of_void *k2d,
|
|
struct key2any_ctx_st *ctx)
|
|
{
|
|
return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname,
|
|
p2s, k2d, ctx, NULL, NULL);
|
|
}
|
|
|
|
#define der_output_type "DER"
|
|
#define pem_output_type "PEM"
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
#ifndef OPENSSL_NO_DH
|
|
static int prepare_dh_params(const void *dh, int nid,
|
|
void **pstr, int *pstrtype)
|
|
{
|
|
ASN1_STRING *params = ASN1_STRING_new();
|
|
|
|
if (params == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
if (nid == EVP_PKEY_DHX)
|
|
params->length = i2d_DHxparams(dh, ¶ms->data);
|
|
else
|
|
params->length = i2d_DHparams(dh, ¶ms->data);
|
|
|
|
if (params->length <= 0) {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
|
|
ASN1_STRING_free(params);
|
|
return 0;
|
|
}
|
|
params->type = V_ASN1_SEQUENCE;
|
|
|
|
*pstr = params;
|
|
*pstrtype = V_ASN1_SEQUENCE;
|
|
return 1;
|
|
}
|
|
|
|
static int dh_spki_pub_to_der(const void *dh, unsigned char **pder)
|
|
{
|
|
const BIGNUM *bn = NULL;
|
|
ASN1_INTEGER *pub_key = NULL;
|
|
int ret;
|
|
|
|
if ((bn = DH_get0_pub_key(dh)) == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY);
|
|
return 0;
|
|
}
|
|
if ((pub_key = BN_to_ASN1_INTEGER(bn, NULL)) == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, PROV_R_BN_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
ret = i2d_ASN1_INTEGER(pub_key, pder);
|
|
|
|
ASN1_STRING_clear_free(pub_key);
|
|
return ret;
|
|
}
|
|
|
|
static int dh_pkcs8_priv_to_der(const void *dh, unsigned char **pder)
|
|
{
|
|
const BIGNUM *bn = NULL;
|
|
ASN1_INTEGER *priv_key = NULL;
|
|
int ret;
|
|
|
|
if ((bn = DH_get0_priv_key(dh)) == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY);
|
|
return 0;
|
|
}
|
|
if ((priv_key = BN_to_ASN1_INTEGER(bn, NULL)) == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, PROV_R_BN_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
ret = i2d_ASN1_INTEGER(priv_key, pder);
|
|
|
|
ASN1_STRING_clear_free(priv_key);
|
|
return ret;
|
|
}
|
|
|
|
static int dh_type_specific_params_to_der(const void *dh, unsigned char **pder)
|
|
{
|
|
if (DH_test_flags(dh, DH_FLAG_TYPE_DHX))
|
|
return i2d_DHxparams(dh, pder);
|
|
return i2d_DHparams(dh, pder);
|
|
}
|
|
|
|
/*
|
|
* DH doesn't have i2d_DHPrivateKey or i2d_DHPublicKey, so we can't make
|
|
* corresponding functions here.
|
|
*/
|
|
# define dh_type_specific_priv_to_der NULL
|
|
# define dh_type_specific_pub_to_der NULL
|
|
|
|
static int dh_check_key_type(const void *dh, int expected_type)
|
|
{
|
|
int type =
|
|
DH_test_flags(dh, DH_FLAG_TYPE_DHX) ? EVP_PKEY_DHX : EVP_PKEY_DH;
|
|
|
|
return type == expected_type;
|
|
}
|
|
|
|
# define dh_evp_type EVP_PKEY_DH
|
|
# define dhx_evp_type EVP_PKEY_DHX
|
|
# define dh_input_type "DH"
|
|
# define dhx_input_type "DHX"
|
|
# define dh_pem_type "DH"
|
|
# define dhx_pem_type "X9.42 DH"
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
#ifndef OPENSSL_NO_DSA
|
|
static int prepare_some_dsa_params(const void *dsa, int nid,
|
|
void **pstr, int *pstrtype)
|
|
{
|
|
ASN1_STRING *params = ASN1_STRING_new();
|
|
|
|
if (params == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
params->length = i2d_DSAparams(dsa, ¶ms->data);
|
|
|
|
if (params->length <= 0) {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
|
|
ASN1_STRING_free(params);
|
|
return 0;
|
|
}
|
|
|
|
*pstrtype = V_ASN1_SEQUENCE;
|
|
*pstr = params;
|
|
return 1;
|
|
}
|
|
|
|
static int prepare_all_dsa_params(const void *dsa, int nid,
|
|
void **pstr, int *pstrtype)
|
|
{
|
|
const BIGNUM *p = DSA_get0_p(dsa);
|
|
const BIGNUM *q = DSA_get0_q(dsa);
|
|
const BIGNUM *g = DSA_get0_g(dsa);
|
|
|
|
if (p != NULL && q != NULL && g != NULL)
|
|
return prepare_some_dsa_params(dsa, nid, pstr, pstrtype);
|
|
|
|
*pstr = NULL;
|
|
*pstrtype = V_ASN1_UNDEF;
|
|
return 1;
|
|
}
|
|
|
|
static int prepare_dsa_params(const void *dsa, int nid,
|
|
void **pstr, int *pstrtype)
|
|
{
|
|
/*
|
|
* TODO(v3.0) implement setting save_parameters, see dsa_pub_encode()
|
|
* in crypto/dsa/dsa_ameth.c
|
|
*/
|
|
int save_parameters = 1;
|
|
|
|
return save_parameters
|
|
? prepare_all_dsa_params(dsa, nid, pstr, pstrtype)
|
|
: prepare_some_dsa_params(dsa, nid, pstr, pstrtype);
|
|
}
|
|
|
|
static int dsa_spki_pub_to_der(const void *dsa, unsigned char **pder)
|
|
{
|
|
const BIGNUM *bn = NULL;
|
|
ASN1_INTEGER *pub_key = NULL;
|
|
int ret;
|
|
|
|
if ((bn = DSA_get0_pub_key(dsa)) == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY);
|
|
return 0;
|
|
}
|
|
if ((pub_key = BN_to_ASN1_INTEGER(bn, NULL)) == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, PROV_R_BN_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
ret = i2d_ASN1_INTEGER(pub_key, pder);
|
|
|
|
ASN1_STRING_clear_free(pub_key);
|
|
return ret;
|
|
}
|
|
|
|
static int dsa_pkcs8_priv_to_der(const void *dsa, unsigned char **pder)
|
|
{
|
|
const BIGNUM *bn = NULL;
|
|
ASN1_INTEGER *priv_key = NULL;
|
|
int ret;
|
|
|
|
if ((bn = DSA_get0_priv_key(dsa)) == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY);
|
|
return 0;
|
|
}
|
|
if ((priv_key = BN_to_ASN1_INTEGER(bn, NULL)) == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, PROV_R_BN_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
ret = i2d_ASN1_INTEGER(priv_key, pder);
|
|
|
|
ASN1_STRING_clear_free(priv_key);
|
|
return ret;
|
|
}
|
|
|
|
# define dsa_type_specific_priv_to_der (i2d_of_void *)i2d_DSAPrivateKey
|
|
# define dsa_type_specific_pub_to_der (i2d_of_void *)i2d_DSAPublicKey
|
|
# define dsa_type_specific_params_to_der (i2d_of_void *)i2d_DSAparams
|
|
|
|
# define dsa_check_key_type NULL
|
|
# define dsa_evp_type EVP_PKEY_DSA
|
|
# define dsa_input_type "DSA"
|
|
# define dsa_pem_type "DSA"
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
#ifndef OPENSSL_NO_EC
|
|
static int prepare_ec_explicit_params(const void *eckey,
|
|
void **pstr, int *pstrtype)
|
|
{
|
|
ASN1_STRING *params = ASN1_STRING_new();
|
|
|
|
if (params == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
params->length = i2d_ECParameters(eckey, ¶ms->data);
|
|
if (params->length <= 0) {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
|
|
ASN1_STRING_free(params);
|
|
return 0;
|
|
}
|
|
|
|
*pstrtype = V_ASN1_SEQUENCE;
|
|
*pstr = params;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* This implements EcpkParameters, where the CHOICE is based on whether there
|
|
* is a curve name (curve nid) to be found or not. See RFC 3279 for details.
|
|
* TODO: shouldn't we use i2d_ECPKParameters()?
|
|
*/
|
|
static int prepare_ec_params(const void *eckey, int nid,
|
|
void **pstr, int *pstrtype)
|
|
{
|
|
int curve_nid;
|
|
const EC_GROUP *group = EC_KEY_get0_group(eckey);
|
|
ASN1_OBJECT *params = NULL;
|
|
|
|
if (group == NULL)
|
|
return 0;
|
|
curve_nid = EC_GROUP_get_curve_name(group);
|
|
if (curve_nid != NID_undef) {
|
|
params = OBJ_nid2obj(curve_nid);
|
|
if (params == NULL)
|
|
return 0;
|
|
}
|
|
|
|
if (curve_nid != NID_undef
|
|
&& (EC_GROUP_get_asn1_flag(group) & OPENSSL_EC_NAMED_CURVE)) {
|
|
/* The CHOICE came to namedCurve */
|
|
if (OBJ_length(params) == 0) {
|
|
/* Some curves might not have an associated OID */
|
|
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_OID);
|
|
ASN1_OBJECT_free(params);
|
|
return 0;
|
|
}
|
|
*pstr = params;
|
|
*pstrtype = V_ASN1_OBJECT;
|
|
return 1;
|
|
} else {
|
|
/* The CHOICE came to ecParameters */
|
|
return prepare_ec_explicit_params(eckey, pstr, pstrtype);
|
|
}
|
|
}
|
|
|
|
static int ec_spki_pub_to_der(const void *eckey, unsigned char **pder)
|
|
{
|
|
return i2o_ECPublicKey(eckey, pder);
|
|
}
|
|
|
|
static int ec_pkcs8_priv_to_der(const void *veckey, unsigned char **pder)
|
|
{
|
|
EC_KEY *eckey = (EC_KEY *)veckey;
|
|
unsigned int old_flags;
|
|
int ret = 0;
|
|
|
|
/*
|
|
* For PKCS8 the curve name appears in the PKCS8_PRIV_KEY_INFO object
|
|
* as the pkeyalg->parameter field. (For a named curve this is an OID)
|
|
* The pkey field is an octet string that holds the encoded
|
|
* ECPrivateKey SEQUENCE with the optional parameters field omitted.
|
|
* We omit this by setting the EC_PKEY_NO_PARAMETERS flag.
|
|
*/
|
|
old_flags = EC_KEY_get_enc_flags(eckey); /* save old flags */
|
|
EC_KEY_set_enc_flags(eckey, old_flags | EC_PKEY_NO_PARAMETERS);
|
|
ret = i2d_ECPrivateKey(eckey, pder);
|
|
EC_KEY_set_enc_flags(eckey, old_flags); /* restore old flags */
|
|
return ret; /* return the length of the der encoded data */
|
|
}
|
|
|
|
# define ec_type_specific_params_to_der (i2d_of_void *)i2d_ECParameters
|
|
# define ec_type_specific_pub_to_der (i2d_of_void *)i2o_ECPublicKey
|
|
# define ec_type_specific_priv_to_der (i2d_of_void *)i2d_ECPrivateKey
|
|
|
|
# define ec_check_key_type NULL
|
|
# define ec_evp_type EVP_PKEY_EC
|
|
# define ec_input_type "EC"
|
|
# define ec_pem_type "EC"
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
#ifndef OPENSSL_NO_EC
|
|
# define prepare_ecx_params NULL
|
|
|
|
static int ecx_spki_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;
|
|
}
|
|
|
|
static int ecx_pkcs8_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;
|
|
}
|
|
|
|
/*
|
|
* ED25519, ED448, X25519 and X448 only has PKCS#8 / SubjectPublicKeyInfo
|
|
* representation, so we don't define ecx_type_specific_[priv,pub,params]_to_der.
|
|
*/
|
|
|
|
# define ecx_check_key_type NULL
|
|
|
|
# define ed25519_evp_type EVP_PKEY_ED25519
|
|
# define ed448_evp_type EVP_PKEY_ED448
|
|
# define x25519_evp_type EVP_PKEY_X25519
|
|
# define x448_evp_type EVP_PKEY_X448
|
|
# define ed25519_input_type "ED25519"
|
|
# define ed448_input_type "ED448"
|
|
# define x25519_input_type "X25519"
|
|
# define x448_input_type "X448"
|
|
# define ed25519_pem_type "ED25519"
|
|
# define ed448_pem_type "ED448"
|
|
# define x25519_pem_type "X25519"
|
|
# define x448_pem_type "X448"
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* Helper functions to prepare RSA-PSS params for encoding. We would
|
|
* have simply written the whole AlgorithmIdentifier, but existing libcrypto
|
|
* functionality doesn't allow that.
|
|
*/
|
|
|
|
static int prepare_rsa_params(const void *rsa, int nid,
|
|
void **pstr, int *pstrtype)
|
|
{
|
|
const RSA_PSS_PARAMS_30 *pss = ossl_rsa_get0_pss_params_30((RSA *)rsa);
|
|
|
|
*pstr = NULL;
|
|
|
|
switch (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK)) {
|
|
case RSA_FLAG_TYPE_RSA:
|
|
/* If plain RSA, the parameters shall be NULL */
|
|
*pstrtype = V_ASN1_NULL;
|
|
return 1;
|
|
case RSA_FLAG_TYPE_RSASSAPSS:
|
|
if (ossl_rsa_pss_params_30_is_unrestricted(pss)) {
|
|
*pstrtype = V_ASN1_UNDEF;
|
|
return 1;
|
|
} else {
|
|
ASN1_STRING *astr = NULL;
|
|
WPACKET pkt;
|
|
unsigned char *str = NULL;
|
|
size_t str_sz = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
switch (i) {
|
|
case 0:
|
|
if (!WPACKET_init_null_der(&pkt))
|
|
goto err;
|
|
break;
|
|
case 1:
|
|
if ((str = OPENSSL_malloc(str_sz)) == NULL
|
|
|| !WPACKET_init_der(&pkt, str, str_sz)) {
|
|
goto err;
|
|
}
|
|
break;
|
|
}
|
|
if (!ossl_DER_w_RSASSA_PSS_params(&pkt, -1, pss)
|
|
|| !WPACKET_finish(&pkt)
|
|
|| !WPACKET_get_total_written(&pkt, &str_sz))
|
|
goto err;
|
|
WPACKET_cleanup(&pkt);
|
|
|
|
/*
|
|
* If no PSS parameters are going to be written, there's no
|
|
* point going for another iteration.
|
|
* This saves us from getting |str| allocated just to have it
|
|
* immediately de-allocated.
|
|
*/
|
|
if (str_sz == 0)
|
|
break;
|
|
}
|
|
|
|
if ((astr = ASN1_STRING_new()) == NULL)
|
|
goto err;
|
|
*pstrtype = V_ASN1_SEQUENCE;
|
|
ASN1_STRING_set0(astr, str, (int)str_sz);
|
|
*pstr = astr;
|
|
|
|
return 1;
|
|
err:
|
|
OPENSSL_free(str);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Currently unsupported RSA key type */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* RSA is extremely simple, as PKCS#1 is used for the PKCS#8 |privateKey|
|
|
* field as well as the SubjectPublicKeyInfo |subjectPublicKey| field.
|
|
*/
|
|
#define rsa_pkcs8_priv_to_der rsa_type_specific_priv_to_der
|
|
#define rsa_spki_pub_to_der rsa_type_specific_pub_to_der
|
|
#define rsa_type_specific_priv_to_der (i2d_of_void *)i2d_RSAPrivateKey
|
|
#define rsa_type_specific_pub_to_der (i2d_of_void *)i2d_RSAPublicKey
|
|
#define rsa_type_specific_params_to_der NULL
|
|
|
|
static int rsa_check_key_type(const void *rsa, int expected_type)
|
|
{
|
|
switch (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK)) {
|
|
case RSA_FLAG_TYPE_RSA:
|
|
return expected_type == EVP_PKEY_RSA;
|
|
case RSA_FLAG_TYPE_RSASSAPSS:
|
|
return expected_type == EVP_PKEY_RSA_PSS;
|
|
}
|
|
|
|
/* Currently unsupported RSA key type */
|
|
return EVP_PKEY_NONE;
|
|
}
|
|
|
|
#define rsa_evp_type EVP_PKEY_RSA
|
|
#define rsapss_evp_type EVP_PKEY_RSA_PSS
|
|
#define rsa_input_type "RSA"
|
|
#define rsapss_input_type "RSA-PSS"
|
|
#define rsa_pem_type "RSA"
|
|
#define rsapss_pem_type "RSA-PSS"
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
static OSSL_FUNC_decoder_newctx_fn key2any_newctx;
|
|
static OSSL_FUNC_decoder_freectx_fn key2any_freectx;
|
|
|
|
static void *key2any_newctx(void *provctx)
|
|
{
|
|
struct key2any_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
|
|
|
|
if (ctx != NULL)
|
|
ctx->provctx = provctx;
|
|
|
|
return ctx;
|
|
}
|
|
|
|
static void key2any_freectx(void *vctx)
|
|
{
|
|
struct key2any_ctx_st *ctx = vctx;
|
|
|
|
ossl_pw_clear_passphrase_data(&ctx->pwdata);
|
|
EVP_CIPHER_free(ctx->cipher);
|
|
OPENSSL_free(ctx);
|
|
}
|
|
|
|
static const OSSL_PARAM *key2any_gettable_params(void *provctx, int structure)
|
|
{
|
|
static const OSSL_PARAM gettables[] = {
|
|
{ OSSL_ENCODER_PARAM_INPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
|
|
{ OSSL_ENCODER_PARAM_OUTPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
|
|
OSSL_PARAM_END,
|
|
};
|
|
|
|
static const OSSL_PARAM gettables_w_structure[] = {
|
|
{ OSSL_ENCODER_PARAM_INPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
|
|
{ OSSL_ENCODER_PARAM_OUTPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
|
|
{ OSSL_ENCODER_PARAM_OUTPUT_STRUCTURE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
|
|
OSSL_PARAM_END,
|
|
};
|
|
|
|
return structure ? gettables_w_structure : gettables;
|
|
}
|
|
|
|
static int key2any_get_params(OSSL_PARAM params[], const char *input_type,
|
|
const char *output_type,
|
|
const char *output_struct)
|
|
{
|
|
OSSL_PARAM *p;
|
|
|
|
p = OSSL_PARAM_locate(params, OSSL_ENCODER_PARAM_INPUT_TYPE);
|
|
if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, input_type))
|
|
return 0;
|
|
|
|
p = OSSL_PARAM_locate(params, OSSL_ENCODER_PARAM_OUTPUT_TYPE);
|
|
if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, output_type))
|
|
return 0;
|
|
|
|
if (output_struct != NULL) {
|
|
p = OSSL_PARAM_locate(params, OSSL_ENCODER_PARAM_OUTPUT_STRUCTURE);
|
|
if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, output_struct))
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static const OSSL_PARAM *key2any_settable_ctx_params(ossl_unused void *provctx)
|
|
{
|
|
static const OSSL_PARAM settables[] = {
|
|
OSSL_PARAM_utf8_string(OSSL_ENCODER_PARAM_CIPHER, NULL, 0),
|
|
OSSL_PARAM_utf8_string(OSSL_ENCODER_PARAM_PROPERTIES, NULL, 0),
|
|
OSSL_PARAM_END,
|
|
};
|
|
|
|
return settables;
|
|
}
|
|
|
|
static int key2any_set_ctx_params(void *vctx, const OSSL_PARAM params[])
|
|
{
|
|
struct key2any_ctx_st *ctx = vctx;
|
|
OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(ctx->provctx);
|
|
const OSSL_PARAM *cipherp =
|
|
OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_CIPHER);
|
|
const OSSL_PARAM *propsp =
|
|
OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_PROPERTIES);
|
|
|
|
if (cipherp != NULL) {
|
|
const char *ciphername = NULL;
|
|
const char *props = NULL;
|
|
|
|
if (!OSSL_PARAM_get_utf8_string_ptr(cipherp, &ciphername))
|
|
return 0;
|
|
if (propsp != NULL && !OSSL_PARAM_get_utf8_string_ptr(propsp, &props))
|
|
return 0;
|
|
|
|
EVP_CIPHER_free(ctx->cipher);
|
|
ctx->cipher = NULL;
|
|
ctx->cipher_intent = ciphername != NULL;
|
|
if (ciphername != NULL
|
|
&& ((ctx->cipher =
|
|
EVP_CIPHER_fetch(libctx, ciphername, props)) == NULL))
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int key2any_check_selection(int selection, int selection_mask)
|
|
{
|
|
/*
|
|
* The selections are kinda sorta "levels", i.e. each selection given
|
|
* here is assumed to include those following.
|
|
*/
|
|
int checks[] = {
|
|
OSSL_KEYMGMT_SELECT_PRIVATE_KEY,
|
|
OSSL_KEYMGMT_SELECT_PUBLIC_KEY,
|
|
OSSL_KEYMGMT_SELECT_ALL_PARAMETERS
|
|
};
|
|
size_t i;
|
|
|
|
/* The decoder implementations made here support guessing */
|
|
if (selection == 0)
|
|
return 1;
|
|
|
|
for (i = 0; i < OSSL_NELEM(checks); i++) {
|
|
int check1 = (selection & checks[i]) != 0;
|
|
int check2 = (selection_mask & checks[i]) != 0;
|
|
|
|
/*
|
|
* If the caller asked for the currently checked bit(s), return
|
|
* whether the decoder description says it's supported.
|
|
*/
|
|
if (check1)
|
|
return check2;
|
|
}
|
|
|
|
/* This should be dead code, but just to be safe... */
|
|
return 0;
|
|
}
|
|
|
|
static int key2any_encode(struct key2any_ctx_st *ctx, OSSL_CORE_BIO *cout,
|
|
const void *key, int type, const char *pemname,
|
|
check_key_type_fn *checker,
|
|
key_to_der_fn *writer,
|
|
OSSL_PASSPHRASE_CALLBACK *pwcb, void *pwcbarg,
|
|
key_to_paramstring_fn *key2paramstring,
|
|
i2d_of_void *key2der)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (key == NULL) {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
|
|
} else if (writer != NULL
|
|
&& (checker == NULL || checker(key, type))) {
|
|
BIO *out = bio_new_from_core_bio(ctx->provctx, cout);
|
|
|
|
if (out != NULL
|
|
&& (pwcb == NULL
|
|
|| ossl_pw_set_ossl_passphrase_cb(&ctx->pwdata, pwcb, pwcbarg)))
|
|
ret =
|
|
writer(out, key, type, pemname, key2paramstring, key2der, ctx);
|
|
|
|
BIO_free(out);
|
|
} else {
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#define DO_PRIVATE_KEY_selection_mask OSSL_KEYMGMT_SELECT_PRIVATE_KEY
|
|
#define DO_PRIVATE_KEY(impl, type, kind, output) \
|
|
if ((selection & DO_PRIVATE_KEY_selection_mask) != 0) \
|
|
return key2any_encode(ctx, cout, key, impl##_evp_type, \
|
|
impl##_pem_type " PRIVATE KEY", \
|
|
type##_check_key_type, \
|
|
key_to_##kind##_##output##_priv_bio, \
|
|
cb, cbarg, prepare_##type##_params, \
|
|
type##_##kind##_priv_to_der);
|
|
|
|
#define DO_PUBLIC_KEY_selection_mask OSSL_KEYMGMT_SELECT_PUBLIC_KEY
|
|
#define DO_PUBLIC_KEY(impl, type, kind, output) \
|
|
if ((selection & DO_PUBLIC_KEY_selection_mask) != 0) \
|
|
return key2any_encode(ctx, cout, key, impl##_evp_type, \
|
|
impl##_pem_type " PUBLIC KEY", \
|
|
type##_check_key_type, \
|
|
key_to_##kind##_##output##_pub_bio, \
|
|
cb, cbarg, prepare_##type##_params, \
|
|
type##_##kind##_pub_to_der);
|
|
|
|
#define DO_PARAMETERS_selection_mask OSSL_KEYMGMT_SELECT_ALL_PARAMETERS
|
|
#define DO_PARAMETERS(impl, type, kind, output) \
|
|
if ((selection & DO_PARAMETERS_selection_mask) != 0) \
|
|
return key2any_encode(ctx, cout, key, impl##_evp_type, \
|
|
impl##_pem_type " PARAMETERS", \
|
|
type##_check_key_type, \
|
|
key_to_##kind##_##output##_param_bio, \
|
|
NULL, NULL, NULL, \
|
|
type##_##kind##_params_to_der);
|
|
|
|
/*-
|
|
* Implement the kinds of output structure that can be produced. They are
|
|
* referred to by name, and for each name, the following macros are defined
|
|
* (braces not included):
|
|
*
|
|
* {kind}_output_structure
|
|
*
|
|
* A string that names the output structure. This is used as a selection
|
|
* criterion for each implementation. It may be NULL, which means that
|
|
* there is only one possible output structure for the implemented output
|
|
* type.
|
|
*
|
|
* DO_{kind}_selection_mask
|
|
*
|
|
* A mask of selection bits that must not be zero. This is used as a
|
|
* selection criterion for each implementation.
|
|
* This mask must never be zero.
|
|
*
|
|
* DO_{kind}
|
|
*
|
|
* The performing macro. It must use the DO_ macros defined above,
|
|
* always in this order:
|
|
*
|
|
* - DO_PRIVATE_KEY
|
|
* - DO_PUBLIC_KEY
|
|
* - DO_PARAMETERS
|
|
*
|
|
* Any of those may be omitted, but the relative order must still be
|
|
* the same.
|
|
*/
|
|
|
|
/* PKCS#8 is a structure for private keys only */
|
|
#define PKCS8_output_structure "pkcs8"
|
|
#define DO_PKCS8_selection_mask DO_PRIVATE_KEY_selection_mask
|
|
#define DO_PKCS8(impl, type, output) \
|
|
DO_PRIVATE_KEY(impl, type, pkcs8, output)
|
|
|
|
/* SubjectPublicKeyInfo is a structure for public keys only */
|
|
#define SubjectPublicKeyInfo_output_structure "SubjectPublicKeyInfo"
|
|
#define DO_SubjectPublicKeyInfo_selection_mask DO_PUBLIC_KEY_selection_mask
|
|
#define DO_SubjectPublicKeyInfo(impl, type, output) \
|
|
DO_PUBLIC_KEY(impl, type, spki, output)
|
|
|
|
/*
|
|
* "type-specific" is a uniform name for key type specific output for private
|
|
* and public keys as well as key parameters. This is used internally in
|
|
* libcrypto so it doesn't have to have special knowledge about select key
|
|
* types, but also when no better name has been found. If there are more
|
|
* expressive DO_ names above, those are preferred.
|
|
*
|
|
* Three forms exist:
|
|
*
|
|
* - type_specific_keypair Only supports private and public key
|
|
* - type_specific_params Only supports parameters
|
|
* - type_specific Supports all parts of an EVP_PKEY
|
|
* - type_specific_no_pub Supports all parts of an EVP_PKEY
|
|
* except public key
|
|
*/
|
|
#define type_specific_params_output_structure "type-specific"
|
|
#define DO_type_specific_params_selection_mask DO_PARAMETERS_selection_mask
|
|
#define DO_type_specific_params(impl, type, output) \
|
|
DO_PARAMETERS(impl, type, type_specific, output)
|
|
#define type_specific_keypair_output_structure "type-specific"
|
|
#define DO_type_specific_keypair_selection_mask \
|
|
( DO_PRIVATE_KEY_selection_mask | DO_PUBLIC_KEY_selection_mask )
|
|
#define DO_type_specific_keypair(impl, type, output) \
|
|
DO_PRIVATE_KEY(impl, type, type_specific, output) \
|
|
DO_PUBLIC_KEY(impl, type, type_specific, output)
|
|
#define type_specific_output_structure "type-specific"
|
|
#define DO_type_specific_selection_mask \
|
|
( DO_type_specific_keypair_selection_mask \
|
|
| DO_type_specific_params_selection_mask )
|
|
#define DO_type_specific(impl, type, output) \
|
|
DO_type_specific_keypair(impl, type, output) \
|
|
DO_type_specific_params(impl, type, output)
|
|
#define type_specific_no_pub_output_structure "type-specific"
|
|
#define DO_type_specific_no_pub_selection_mask \
|
|
( DO_PRIVATE_KEY_selection_mask | DO_PARAMETERS_selection_mask)
|
|
#define DO_type_specific_no_pub(impl, type, output) \
|
|
DO_PRIVATE_KEY(impl, type, type_specific, output) \
|
|
DO_type_specific_params(impl, type, output)
|
|
|
|
/*
|
|
* Type specific aliases for the cases where we need to refer to them by
|
|
* type name.
|
|
* This only covers key types that are represented with i2d_{TYPE}PrivateKey,
|
|
* i2d_{TYPE}PublicKey and i2d_{TYPE}params / i2d_{TYPE}Parameters.
|
|
*/
|
|
#define RSA_output_structure "rsa"
|
|
#define DO_RSA_selection_mask DO_type_specific_keypair_selection_mask
|
|
#define DO_RSA(impl, type, output) DO_type_specific_keypair(impl, type, output)
|
|
|
|
#define DH_output_structure "dh"
|
|
#define DO_DH_selection_mask DO_type_specific_params_selection_mask
|
|
#define DO_DH(impl, type, output) DO_type_specific_params(impl, type, output)
|
|
|
|
#define DHX_output_structure "dhx"
|
|
#define DO_DHX_selection_mask DO_type_specific_params_selection_mask
|
|
#define DO_DHX(impl, type, output) DO_type_specific_params(impl, type, output)
|
|
|
|
#define DSA_output_structure "dsa"
|
|
#define DO_DSA_selection_mask DO_type_specific_selection_mask
|
|
#define DO_DSA(impl, type, output) DO_type_specific(impl, type, output)
|
|
|
|
#define EC_output_structure "ec"
|
|
#define DO_EC_selection_mask DO_type_specific_selection_mask
|
|
#define DO_EC(impl, type, output) DO_type_specific(impl, type, output)
|
|
|
|
/* PKCS#1 defines a structure for RSA private and public keys */
|
|
#define PKCS1_output_structure "pkcs1"
|
|
#define DO_PKCS1_selection_mask DO_RSA_selection_mask
|
|
#define DO_PKCS1(impl, type, output) DO_RSA(impl, type, output)
|
|
|
|
/* PKCS#3 defines a structure for DH parameters */
|
|
#define PKCS3_output_structure "pkcs3"
|
|
#define DO_PKCS3_selection_mask DO_DH_selection_mask
|
|
#define DO_PKCS3(impl, type, output) DO_DH(impl, type, output)
|
|
/* X9.42 defines a structure for DHx parameters */
|
|
#define X9_42_output_structure "X9.42"
|
|
#define DO_X9_42_selection_mask DO_DHX_selection_mask
|
|
#define DO_X9_42(impl, type, output) DO_DHX(impl, type, output)
|
|
|
|
/* X9.62 defines a structure for EC keys and parameters */
|
|
#define X9_62_output_structure "X9.62"
|
|
#define DO_X9_62_selection_mask DO_EC_selection_mask
|
|
#define DO_X9_62(impl, type, output) DO_EC(impl, type, output)
|
|
|
|
/*
|
|
* MAKE_ENCODER is the single driver for creating OSSL_DISPATCH tables.
|
|
* It takes the following arguments:
|
|
*
|
|
* impl This is the key type name that's being implemented.
|
|
* type This is the type name for the set of functions that implement
|
|
* the key type. For example, ed25519, ed448, x25519 and x448
|
|
* are all implemented with the exact same set of functions.
|
|
* evp_type The corresponding EVP_PKEY_xxx type macro for each key.
|
|
* Necessary because we currently use EVP_PKEY with legacy
|
|
* native keys internally. This will need to be refactored
|
|
* when that legacy support goes away.
|
|
* kind What kind of support to implement. These translate into
|
|
* the DO_##kind macros above.
|
|
* output The output type to implement. may be der or pem.
|
|
*
|
|
* The resulting OSSL_DISPATCH array gets the following name (expressed in
|
|
* C preprocessor terms) from those arguments:
|
|
*
|
|
* ossl_##impl##_to_##kind##_##output##_encoder_functions
|
|
*/
|
|
#define MAKE_ENCODER(impl, type, evp_type, kind, output) \
|
|
static OSSL_FUNC_encoder_gettable_params_fn \
|
|
impl##_to_##kind##_##output##_gettable_params; \
|
|
static OSSL_FUNC_encoder_get_params_fn \
|
|
impl##_to_##kind##_##output##_get_params; \
|
|
static OSSL_FUNC_encoder_import_object_fn \
|
|
impl##_to_##kind##_##output##_import_object; \
|
|
static OSSL_FUNC_encoder_free_object_fn \
|
|
impl##_to_##kind##_##output##_free_object; \
|
|
static OSSL_FUNC_encoder_encode_fn \
|
|
impl##_to_##kind##_##output##_encode; \
|
|
\
|
|
static const OSSL_PARAM * \
|
|
impl##_to_##kind##_##output##_gettable_params(void *provctx) \
|
|
{ \
|
|
return key2any_gettable_params(provctx, \
|
|
kind##_output_structure != NULL); \
|
|
} \
|
|
static int \
|
|
impl##_to_##kind##_##output##_get_params(OSSL_PARAM params[]) \
|
|
{ \
|
|
return key2any_get_params(params, impl##_input_type, \
|
|
output##_output_type, \
|
|
kind##_output_structure); \
|
|
} \
|
|
static void * \
|
|
impl##_to_##kind##_##output##_import_object(void *vctx, int selection, \
|
|
const OSSL_PARAM params[]) \
|
|
{ \
|
|
struct key2any_ctx_st *ctx = vctx; \
|
|
\
|
|
return ossl_prov_import_key(ossl_##impl##_keymgmt_functions, \
|
|
ctx->provctx, selection, params); \
|
|
} \
|
|
static void impl##_to_##kind##_##output##_free_object(void *key) \
|
|
{ \
|
|
ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key); \
|
|
} \
|
|
static int impl##_to_##kind##_##output##_does_selection(void *ctx, \
|
|
int selection) \
|
|
{ \
|
|
return key2any_check_selection(selection, \
|
|
DO_##kind##_selection_mask); \
|
|
} \
|
|
static int \
|
|
impl##_to_##kind##_##output##_encode(void *ctx, OSSL_CORE_BIO *cout, \
|
|
const void *key, \
|
|
const OSSL_PARAM key_abstract[], \
|
|
int selection, \
|
|
OSSL_PASSPHRASE_CALLBACK *cb, \
|
|
void *cbarg) \
|
|
{ \
|
|
/* We don't deal with abstract objects */ \
|
|
if (key_abstract != NULL) { \
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); \
|
|
return 0; \
|
|
} \
|
|
DO_##kind(impl, type, output) \
|
|
\
|
|
ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); \
|
|
return 0; \
|
|
} \
|
|
const OSSL_DISPATCH \
|
|
ossl_##impl##_to_##kind##_##output##_encoder_functions[] = { \
|
|
{ OSSL_FUNC_ENCODER_NEWCTX, \
|
|
(void (*)(void))key2any_newctx }, \
|
|
{ OSSL_FUNC_ENCODER_FREECTX, \
|
|
(void (*)(void))key2any_freectx }, \
|
|
{ OSSL_FUNC_ENCODER_GETTABLE_PARAMS, \
|
|
(void (*)(void))impl##_to_##kind##_##output##_gettable_params }, \
|
|
{ OSSL_FUNC_ENCODER_GET_PARAMS, \
|
|
(void (*)(void))impl##_to_##kind##_##output##_get_params }, \
|
|
{ OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS, \
|
|
(void (*)(void))key2any_settable_ctx_params }, \
|
|
{ OSSL_FUNC_ENCODER_SET_CTX_PARAMS, \
|
|
(void (*)(void))key2any_set_ctx_params }, \
|
|
{ OSSL_FUNC_ENCODER_DOES_SELECTION, \
|
|
(void (*)(void))impl##_to_##kind##_##output##_does_selection }, \
|
|
{ OSSL_FUNC_ENCODER_IMPORT_OBJECT, \
|
|
(void (*)(void))impl##_to_##kind##_##output##_import_object }, \
|
|
{ OSSL_FUNC_ENCODER_FREE_OBJECT, \
|
|
(void (*)(void))impl##_to_##kind##_##output##_free_object }, \
|
|
{ OSSL_FUNC_ENCODER_ENCODE, \
|
|
(void (*)(void))impl##_to_##kind##_##output##_encode }, \
|
|
{ 0, NULL } \
|
|
}
|
|
|
|
/*
|
|
* Replacements for i2d_{TYPE}PrivateKey, i2d_{TYPE}PublicKey,
|
|
* i2d_{TYPE}params, as they exist.
|
|
*/
|
|
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, type_specific_keypair, der);
|
|
#ifndef OPENSSL_NO_DH
|
|
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, type_specific_params, der);
|
|
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, type_specific_params, der);
|
|
#endif
|
|
#ifndef OPENSSL_NO_DSA
|
|
MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, type_specific, der);
|
|
#endif
|
|
#ifndef OPENSSL_NO_EC
|
|
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, type_specific_no_pub, der);
|
|
#endif
|
|
|
|
/*
|
|
* Replacements for PEM_write_bio_{TYPE}PrivateKey,
|
|
* PEM_write_bio_{TYPE}PublicKey, PEM_write_bio_{TYPE}params, as they exist.
|
|
*/
|
|
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, type_specific_keypair, pem);
|
|
#ifndef OPENSSL_NO_DH
|
|
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, type_specific_params, pem);
|
|
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, type_specific_params, pem);
|
|
#endif
|
|
#ifndef OPENSSL_NO_DSA
|
|
MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, type_specific, pem);
|
|
#endif
|
|
#ifndef OPENSSL_NO_EC
|
|
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, type_specific_no_pub, pem);
|
|
#endif
|
|
|
|
/*
|
|
* PKCS#8 and SubjectPublicKeyInfo support. This may duplicate some of the
|
|
* implementations specified above, but are more specific.
|
|
* The SubjectPublicKeyInfo implementations also replace the
|
|
* PEM_write_bio_{TYPE}_PUBKEY functions.
|
|
* For PEM, these are expected to be used by PEM_write_bio_PrivateKey(),
|
|
* PEM_write_bio_PUBKEY() and PEM_write_bio_Parameters().
|
|
*/
|
|
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS8, der);
|
|
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS8, pem);
|
|
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, SubjectPublicKeyInfo, der);
|
|
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, SubjectPublicKeyInfo, pem);
|
|
MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS8, der);
|
|
MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS8, pem);
|
|
MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, SubjectPublicKeyInfo, der);
|
|
MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, SubjectPublicKeyInfo, pem);
|
|
#ifndef OPENSSL_NO_DH
|
|
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS8, der);
|
|
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS8, pem);
|
|
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, SubjectPublicKeyInfo, der);
|
|
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, SubjectPublicKeyInfo, pem);
|
|
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PKCS8, der);
|
|
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PKCS8, pem);
|
|
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, SubjectPublicKeyInfo, der);
|
|
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, SubjectPublicKeyInfo, pem);
|
|
#endif
|
|
#ifndef OPENSSL_NO_DSA
|
|
MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PKCS8, der);
|
|
MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PKCS8, pem);
|
|
MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, SubjectPublicKeyInfo, der);
|
|
MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, SubjectPublicKeyInfo, pem);
|
|
#endif
|
|
#ifndef OPENSSL_NO_EC
|
|
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PKCS8, der);
|
|
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PKCS8, pem);
|
|
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, der);
|
|
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, pem);
|
|
MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PKCS8, der);
|
|
MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PKCS8, pem);
|
|
MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, SubjectPublicKeyInfo, der);
|
|
MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, SubjectPublicKeyInfo, pem);
|
|
MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PKCS8, der);
|
|
MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PKCS8, pem);
|
|
MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, der);
|
|
MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, pem);
|
|
MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PKCS8, der);
|
|
MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PKCS8, pem);
|
|
MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, SubjectPublicKeyInfo, der);
|
|
MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, SubjectPublicKeyInfo, pem);
|
|
MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PKCS8, der);
|
|
MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PKCS8, pem);
|
|
MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, der);
|
|
MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, pem);
|
|
#endif
|
|
|
|
/*
|
|
* Support for key type specific output formats. Not all key types have
|
|
* this, we only aim to duplicate what is available in 1.1.1 as
|
|
* i2d_TYPEPrivateKey(), i2d_TYPEPublicKey() and i2d_TYPEparams().
|
|
* For example, there are no publicly available i2d_ function for
|
|
* ED25519, ED448, X25519 or X448, and they therefore only have PKCS#8
|
|
* and SubjectPublicKeyInfo implementations as implemented above.
|
|
*/
|
|
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, RSA, der);
|
|
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, RSA, pem);
|
|
#ifndef OPENSSL_NO_DH
|
|
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, DH, der);
|
|
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, DH, pem);
|
|
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, DHX, der);
|
|
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, DHX, pem);
|
|
#endif
|
|
#ifndef OPENSSL_NO_DSA
|
|
MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, DSA, der);
|
|
MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, DSA, pem);
|
|
#endif
|
|
#ifndef OPENSSL_NO_EC
|
|
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, EC, der);
|
|
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, EC, pem);
|
|
#endif
|
|
|
|
/* Convenience structure names */
|
|
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS1, der);
|
|
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS1, pem);
|
|
MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS1, der);
|
|
MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS1, pem);
|
|
#ifndef OPENSSL_NO_DH
|
|
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS3, der); /* parameters only */
|
|
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS3, pem); /* parameters only */
|
|
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, X9_42, der); /* parameters only */
|
|
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, X9_42, pem); /* parameters only */
|
|
#endif
|
|
#ifndef OPENSSL_NO_EC
|
|
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, X9_62, der);
|
|
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, X9_62, pem);
|
|
#endif
|