diff options
| author | Enji Cooper <ngie@FreeBSD.org> | 2023-03-01 04:21:31 +0000 |
|---|---|---|
| committer | Enji Cooper <ngie@FreeBSD.org> | 2023-03-06 20:41:29 +0000 |
| commit | e4520c8bd1d300a7a338d0ed4af171a2d0e583ef (patch) | |
| tree | 26fed32699a59a50cfbc90a2eb4dac39b498d9ae /providers/implementations/encode_decode | |
| parent | 3c320f4e5ee3d575d48eee7edddbafa059bce3c9 (diff) | |
Diffstat (limited to 'providers/implementations/encode_decode')
13 files changed, 4725 insertions, 0 deletions
diff --git a/providers/implementations/encode_decode/build.info b/providers/implementations/encode_decode/build.info new file mode 100644 index 000000000000..d3f6ca4abdef --- /dev/null +++ b/providers/implementations/encode_decode/build.info @@ -0,0 +1,20 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$ENCODER_GOAL=../../libdefault.a +$DECODER_GOAL=../../libdefault.a + +SOURCE[$ENCODER_GOAL]=endecoder_common.c + +SOURCE[$DECODER_GOAL]=decode_der2key.c decode_epki2pki.c decode_pem2der.c \ + decode_msblob2key.c decode_pvk2key.c \ + decode_spki2typespki.c + +SOURCE[$ENCODER_GOAL]=encode_key2any.c encode_key2text.c encode_key2ms.c +# encode_key2blob.c is only being included when EC is enabled, because we +# currently only define a "blob" output type for EC public keys. This may +# change in the future. +IF[{- !$disabled{ec} -}] + SOURCE[$ENCODER_GOAL]=encode_key2blob.c +ENDIF +DEPEND[encode_key2any.o]=../../common/include/prov/der_rsa.h diff --git a/providers/implementations/encode_decode/decode_der2key.c b/providers/implementations/encode_decode/decode_der2key.c new file mode 100644 index 000000000000..b9cee2571bf3 --- /dev/null +++ b/providers/implementations/encode_decode/decode_der2key.c @@ -0,0 +1,793 @@ +/* + * Copyright 2020-2023 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_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/params.h> +#include <openssl/pem.h> /* PEM_BUFSIZE and public PEM functions */ +#include <openssl/pkcs12.h> +#include <openssl/x509.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" /* ossl_assert() */ +#include "internal/asn1.h" +#include "crypto/dh.h" +#include "crypto/dsa.h" +#include "crypto/ec.h" +#include "crypto/evp.h" +#include "crypto/ecx.h" +#include "crypto/rsa.h" +#include "crypto/x509.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +struct der2key_ctx_st; /* Forward declaration */ +typedef int check_key_fn(void *, struct der2key_ctx_st *ctx); +typedef void adjust_key_fn(void *, struct der2key_ctx_st *ctx); +typedef void free_key_fn(void *); +typedef void *d2i_PKCS8_fn(void **, const unsigned char **, long, + struct der2key_ctx_st *); +struct keytype_desc_st { + const char *keytype_name; + const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */ + + /* The input structure name */ + const char *structure_name; + + /* + * The EVP_PKEY_xxx type macro. Should be zero for type specific + * structures, non-zero when the outermost structure is PKCS#8 or + * SubjectPublicKeyInfo. This determines which of the function + * pointers below will be used. + */ + int evp_type; + + /* The selection mask for OSSL_FUNC_decoder_does_selection() */ + int selection_mask; + + /* For type specific decoders, we use the corresponding d2i */ + d2i_of_void *d2i_private_key; /* From type-specific DER */ + d2i_of_void *d2i_public_key; /* From type-specific DER */ + d2i_of_void *d2i_key_params; /* From type-specific DER */ + d2i_PKCS8_fn *d2i_PKCS8; /* Wrapped in a PrivateKeyInfo */ + d2i_of_void *d2i_PUBKEY; /* Wrapped in a SubjectPublicKeyInfo */ + + /* + * For any key, we may need to check that the key meets expectations. + * This is useful when the same functions can decode several variants + * of a key. + */ + check_key_fn *check_key; + + /* + * For any key, we may need to make provider specific adjustments, such + * as ensure the key carries the correct library context. + */ + adjust_key_fn *adjust_key; + /* {type}_free() */ + free_key_fn *free_key; +}; + +/* + * Context used for DER to key decoding. + */ +struct der2key_ctx_st { + PROV_CTX *provctx; + const struct keytype_desc_st *desc; + /* The selection that is passed to der2key_decode() */ + int selection; + /* Flag used to signal that a failure is fatal */ + unsigned int flag_fatal : 1; +}; + +typedef void *key_from_pkcs8_t(const PKCS8_PRIV_KEY_INFO *p8inf, + OSSL_LIB_CTX *libctx, const char *propq); +static void *der2key_decode_p8(const unsigned char **input_der, + long input_der_len, struct der2key_ctx_st *ctx, + key_from_pkcs8_t *key_from_pkcs8) +{ + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + const X509_ALGOR *alg = NULL; + void *key = NULL; + + if ((p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, input_der, input_der_len)) != NULL + && PKCS8_pkey_get0(NULL, NULL, NULL, &alg, p8inf) + && OBJ_obj2nid(alg->algorithm) == ctx->desc->evp_type) + key = key_from_pkcs8(p8inf, PROV_LIBCTX_OF(ctx->provctx), NULL); + PKCS8_PRIV_KEY_INFO_free(p8inf); + + return key; +} + +/* ---------------------------------------------------------------------- */ + +static OSSL_FUNC_decoder_freectx_fn der2key_freectx; +static OSSL_FUNC_decoder_decode_fn der2key_decode; +static OSSL_FUNC_decoder_export_object_fn der2key_export_object; + +static struct der2key_ctx_st * +der2key_newctx(void *provctx, const struct keytype_desc_st *desc) +{ + struct der2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + ctx->desc = desc; + } + return ctx; +} + +static void der2key_freectx(void *vctx) +{ + struct der2key_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static int der2key_check_selection(int selection, + const struct keytype_desc_st *desc) +{ + /* + * 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 = (desc->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 der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct der2key_ctx_st *ctx = vctx; + unsigned char *der = NULL; + const unsigned char *derp; + long der_len = 0; + void *key = NULL; + int ok = 0; + + ctx->selection = selection; + /* + * The caller is allowed to specify 0 as a selection mark, to have the + * structure and key type guessed. For type-specific structures, this + * is not recommended, as some structures are very similar. + * Note that 0 isn't the same as OSSL_KEYMGMT_SELECT_ALL, as the latter + * signifies a private key structure, where everything else is assumed + * to be present as well. + */ + if (selection == 0) + selection = ctx->desc->selection_mask; + if ((selection & ctx->desc->selection_mask) == 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + ok = ossl_read_der(ctx->provctx, cin, &der, &der_len); + if (!ok) + goto next; + + ok = 0; /* Assume that we fail */ + + ERR_set_mark(); + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + derp = der; + if (ctx->desc->d2i_PKCS8 != NULL) { + key = ctx->desc->d2i_PKCS8(NULL, &derp, der_len, ctx); + if (ctx->flag_fatal) { + ERR_clear_last_mark(); + goto end; + } + } else if (ctx->desc->d2i_private_key != NULL) { + key = ctx->desc->d2i_private_key(NULL, &derp, der_len); + } + if (key == NULL && ctx->selection != 0) { + ERR_clear_last_mark(); + goto next; + } + } + if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + derp = der; + if (ctx->desc->d2i_PUBKEY != NULL) + key = ctx->desc->d2i_PUBKEY(NULL, &derp, der_len); + else if (ctx->desc->d2i_public_key != NULL) + key = ctx->desc->d2i_public_key(NULL, &derp, der_len); + if (key == NULL && ctx->selection != 0) { + ERR_clear_last_mark(); + goto next; + } + } + if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) { + derp = der; + if (ctx->desc->d2i_key_params != NULL) + key = ctx->desc->d2i_key_params(NULL, &derp, der_len); + if (key == NULL && ctx->selection != 0) { + ERR_clear_last_mark(); + goto next; + } + } + if (key == NULL) + ERR_clear_last_mark(); + else + ERR_pop_to_mark(); + + /* + * Last minute check to see if this was the correct type of key. This + * should never lead to a fatal error, i.e. the decoding itself was + * correct, it was just an unexpected key type. This is generally for + * classes of key types that have subtle variants, like RSA-PSS keys as + * opposed to plain RSA keys. + */ + if (key != NULL + && ctx->desc->check_key != NULL + && !ctx->desc->check_key(key, ctx)) { + ctx->desc->free_key(key); + key = NULL; + } + + if (key != NULL && ctx->desc->adjust_key != NULL) + ctx->desc->adjust_key(key, ctx); + + next: + /* + * Indicated that we successfully decoded something, or not at all. + * Ending up "empty handed" is not an error. + */ + ok = 1; + + /* + * We free memory here so it's not held up during the callback, because + * we know the process is recursive and the allocated chunks of memory + * add up. + */ + OPENSSL_free(der); + der = NULL; + + if (key != NULL) { + OSSL_PARAM params[4]; + int object_type = OSSL_OBJECT_PKEY; + + params[0] = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type); + params[1] = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + (char *)ctx->desc->keytype_name, + 0); + /* The address of the key becomes the octet string */ + params[2] = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE, + &key, sizeof(key)); + params[3] = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + + end: + ctx->desc->free_key(key); + OPENSSL_free(der); + + return ok; +} + +static int der2key_export_object(void *vctx, + const void *reference, size_t reference_sz, + OSSL_CALLBACK *export_cb, void *export_cbarg) +{ + struct der2key_ctx_st *ctx = vctx; + OSSL_FUNC_keymgmt_export_fn *export = + ossl_prov_get_keymgmt_export(ctx->desc->fns); + void *keydata; + + if (reference_sz == sizeof(keydata) && export != NULL) { + /* The contents of the reference is the address to our object */ + keydata = *(void **)reference; + + return export(keydata, ctx->selection, export_cb, export_cbarg); + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DH +# define dh_evp_type EVP_PKEY_DH +# define dh_d2i_private_key NULL +# define dh_d2i_public_key NULL +# define dh_d2i_key_params (d2i_of_void *)d2i_DHparams + +static void *dh_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_dh_key_from_pkcs8); +} + +# define dh_d2i_PUBKEY (d2i_of_void *)ossl_d2i_DH_PUBKEY +# define dh_free (free_key_fn *)DH_free +# define dh_check NULL + +static void dh_adjust(void *key, struct der2key_ctx_st *ctx) +{ + ossl_dh_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +# define dhx_evp_type EVP_PKEY_DHX +# define dhx_d2i_private_key NULL +# define dhx_d2i_public_key NULL +# define dhx_d2i_key_params (d2i_of_void *)d2i_DHxparams +# define dhx_d2i_PKCS8 dh_d2i_PKCS8 +# define dhx_d2i_PUBKEY (d2i_of_void *)ossl_d2i_DHx_PUBKEY +# define dhx_free (free_key_fn *)DH_free +# define dhx_check NULL +# define dhx_adjust dh_adjust +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DSA +# define dsa_evp_type EVP_PKEY_DSA +# define dsa_d2i_private_key (d2i_of_void *)d2i_DSAPrivateKey +# define dsa_d2i_public_key (d2i_of_void *)d2i_DSAPublicKey +# define dsa_d2i_key_params (d2i_of_void *)d2i_DSAparams + +static void *dsa_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_dsa_key_from_pkcs8); +} + +# define dsa_d2i_PUBKEY (d2i_of_void *)ossl_d2i_DSA_PUBKEY +# define dsa_free (free_key_fn *)DSA_free +# define dsa_check NULL + +static void dsa_adjust(void *key, struct der2key_ctx_st *ctx) +{ + ossl_dsa_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_EC +# define ec_evp_type EVP_PKEY_EC +# define ec_d2i_private_key (d2i_of_void *)d2i_ECPrivateKey +# define ec_d2i_public_key NULL +# define ec_d2i_key_params (d2i_of_void *)d2i_ECParameters + +static void *ec_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_ec_key_from_pkcs8); +} + +# define ec_d2i_PUBKEY (d2i_of_void *)d2i_EC_PUBKEY +# define ec_free (free_key_fn *)EC_KEY_free + +static int ec_check(void *key, struct der2key_ctx_st *ctx) +{ + /* We're trying to be clever by comparing two truths */ + + int sm2 = (EC_KEY_get_flags(key) & EC_FLAG_SM2_RANGE) != 0; + + return sm2 == (ctx->desc->evp_type == EVP_PKEY_SM2); +} + +static void ec_adjust(void *key, struct der2key_ctx_st *ctx) +{ + ossl_ec_key_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +/* + * ED25519, ED448, X25519, X448 only implement PKCS#8 and SubjectPublicKeyInfo, + * so no d2i functions to be had. + */ + +static void *ecx_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_ecx_key_from_pkcs8); +} + +static void ecx_key_adjust(void *key, struct der2key_ctx_st *ctx) +{ + ossl_ecx_key_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +# define ed25519_evp_type EVP_PKEY_ED25519 +# define ed25519_d2i_private_key NULL +# define ed25519_d2i_public_key NULL +# define ed25519_d2i_key_params NULL +# define ed25519_d2i_PKCS8 ecx_d2i_PKCS8 +# define ed25519_d2i_PUBKEY (d2i_of_void *)ossl_d2i_ED25519_PUBKEY +# define ed25519_free (free_key_fn *)ossl_ecx_key_free +# define ed25519_check NULL +# define ed25519_adjust ecx_key_adjust + +# define ed448_evp_type EVP_PKEY_ED448 +# define ed448_d2i_private_key NULL +# define ed448_d2i_public_key NULL +# define ed448_d2i_key_params NULL +# define ed448_d2i_PKCS8 ecx_d2i_PKCS8 +# define ed448_d2i_PUBKEY (d2i_of_void *)ossl_d2i_ED448_PUBKEY +# define ed448_free (free_key_fn *)ossl_ecx_key_free +# define ed448_check NULL +# define ed448_adjust ecx_key_adjust + +# define x25519_evp_type EVP_PKEY_X25519 +# define x25519_d2i_private_key NULL +# define x25519_d2i_public_key NULL +# define x25519_d2i_key_params NULL +# define x25519_d2i_PKCS8 ecx_d2i_PKCS8 +# define x25519_d2i_PUBKEY (d2i_of_void *)ossl_d2i_X25519_PUBKEY +# define x25519_free (free_key_fn *)ossl_ecx_key_free +# define x25519_check NULL +# define x25519_adjust ecx_key_adjust + +# define x448_evp_type EVP_PKEY_X448 +# define x448_d2i_private_key NULL +# define x448_d2i_public_key NULL +# define x448_d2i_key_params NULL +# define x448_d2i_PKCS8 ecx_d2i_PKCS8 +# define x448_d2i_PUBKEY (d2i_of_void *)ossl_d2i_X448_PUBKEY +# define x448_free (free_key_fn *)ossl_ecx_key_free +# define x448_check NULL +# define x448_adjust ecx_key_adjust + +# ifndef OPENSSL_NO_SM2 +# define sm2_evp_type EVP_PKEY_SM2 +# define sm2_d2i_private_key (d2i_of_void *)d2i_ECPrivateKey +# define sm2_d2i_public_key NULL +# define sm2_d2i_key_params (d2i_of_void *)d2i_ECParameters + +static void *sm2_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_ec_key_from_pkcs8); +} + +# define sm2_d2i_PUBKEY (d2i_of_void *)d2i_EC_PUBKEY +# define sm2_free (free_key_fn *)EC_KEY_free +# define sm2_check ec_check +# define sm2_adjust ec_adjust +# endif +#endif + +/* ---------------------------------------------------------------------- */ + +#define rsa_evp_type EVP_PKEY_RSA +#define rsa_d2i_private_key (d2i_of_void *)d2i_RSAPrivateKey +#define rsa_d2i_public_key (d2i_of_void *)d2i_RSAPublicKey +#define rsa_d2i_key_params NULL + +static void *rsa_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_rsa_key_from_pkcs8); +} + +#define rsa_d2i_PUBKEY (d2i_of_void *)d2i_RSA_PUBKEY +#define rsa_free (free_key_fn *)RSA_free + +static int rsa_check(void *key, struct der2key_ctx_st *ctx) +{ + switch (RSA_test_flags(key, RSA_FLAG_TYPE_MASK)) { + case RSA_FLAG_TYPE_RSA: + return ctx->desc->evp_type == EVP_PKEY_RSA; + case RSA_FLAG_TYPE_RSASSAPSS: + return ctx->desc->evp_type == EVP_PKEY_RSA_PSS; + } + + /* Currently unsupported RSA key type */ + return 0; +} + +static void rsa_adjust(void *key, struct der2key_ctx_st *ctx) +{ + ossl_rsa_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +#define rsapss_evp_type EVP_PKEY_RSA_PSS +#define rsapss_d2i_private_key (d2i_of_void *)d2i_RSAPrivateKey +#define rsapss_d2i_public_key (d2i_of_void *)d2i_RSAPublicKey +#define rsapss_d2i_key_params NULL +#define rsapss_d2i_PKCS8 rsa_d2i_PKCS8 +#define rsapss_d2i_PUBKEY (d2i_of_void *)d2i_RSA_PUBKEY +#define rsapss_free (free_key_fn *)RSA_free +#define rsapss_check rsa_check +#define rsapss_adjust rsa_adjust + +/* ---------------------------------------------------------------------- */ + +/* + * The DO_ macros help define the selection mask and the method functions + * for each kind of object we want to decode. + */ +#define DO_type_specific_keypair(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_KEYPAIR ), \ + keytype##_d2i_private_key, \ + keytype##_d2i_public_key, \ + NULL, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_type_specific_pub(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PUBLIC_KEY ), \ + NULL, \ + keytype##_d2i_public_key, \ + NULL, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_type_specific_priv(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY ), \ + keytype##_d2i_private_key, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_type_specific_params(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + NULL, \ + NULL, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_type_specific(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_ALL ), \ + keytype##_d2i_private_key, \ + keytype##_d2i_public_key, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_type_specific_no_pub(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY \ + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + keytype##_d2i_private_key, \ + NULL, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_PrivateKeyInfo(keytype) \ + "PrivateKeyInfo", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY ), \ + NULL, \ + NULL, \ + NULL, \ + keytype##_d2i_PKCS8, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_SubjectPublicKeyInfo(keytype) \ + "SubjectPublicKeyInfo", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PUBLIC_KEY ), \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + keytype##_d2i_PUBKEY, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_DH(keytype) \ + "DH", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + NULL, \ + NULL, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_DHX(keytype) \ + "DHX", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + NULL, \ + NULL, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_DSA(keytype) \ + "DSA", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_ALL ), \ + keytype##_d2i_private_key, \ + keytype##_d2i_public_key, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_EC(keytype) \ + "EC", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY \ + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + keytype##_d2i_private_key, \ + NULL, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_RSA(keytype) \ + "RSA", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_KEYPAIR ), \ + keytype##_d2i_private_key, \ + keytype##_d2i_public_key, \ + NULL, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +/* + * MAKE_DECODER is the single driver for creating OSSL_DISPATCH tables. + * It takes the following arguments: + * + * keytype_name The implementation key type as a string. + * keytype The implementation key type. This must correspond exactly + * to our existing keymgmt keytype names... in other words, + * there must exist an ossl_##keytype##_keymgmt_functions. + * type The type name for the set of functions that implement the + * decoder for the key type. This isn't necessarily the same + * as keytype. For example, the key types ed25519, ed448, + * x25519 and x448 are all handled by the same functions with + * the common type name ecx. + * kind The kind of support to implement. This translates into + * the DO_##kind macros above, to populate the keytype_desc_st + * structure. + */ +#define MAKE_DECODER(keytype_name, keytype, type, kind) \ + static const struct keytype_desc_st kind##_##keytype##_desc = \ + { keytype_name, ossl_##keytype##_keymgmt_functions, \ + DO_##kind(keytype) }; \ + \ + static OSSL_FUNC_decoder_newctx_fn kind##_der2##keytype##_newctx; \ + \ + static void *kind##_der2##keytype##_newctx(void *provctx) \ + { \ + return der2key_newctx(provctx, &kind##_##keytype##_desc); \ + } \ + static int kind##_der2##keytype##_does_selection(void *provctx, \ + int selection) \ + { \ + return der2key_check_selection(selection, \ + &kind##_##keytype##_desc); \ + } \ + const OSSL_DISPATCH \ + ossl_##kind##_der_to_##keytype##_decoder_functions[] = { \ + { OSSL_FUNC_DECODER_NEWCTX, \ + (void (*)(void))kind##_der2##keytype##_newctx }, \ + { OSSL_FUNC_DECODER_FREECTX, \ + (void (*)(void))der2key_freectx }, \ + { OSSL_FUNC_DECODER_DOES_SELECTION, \ + (void (*)(void))kind##_der2##keytype##_does_selection }, \ + { OSSL_FUNC_DECODER_DECODE, \ + (void (*)(void))der2key_decode }, \ + { OSSL_FUNC_DECODER_EXPORT_OBJECT, \ + (void (*)(void))der2key_export_object }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_DH +MAKE_DECODER("DH", dh, dh, PrivateKeyInfo); +MAKE_DECODER("DH", dh, dh, SubjectPublicKeyInfo); +MAKE_DECODER("DH", dh, dh, type_specific_params); +MAKE_DECODER("DH", dh, dh, DH); +MAKE_DECODER("DHX", dhx, dhx, PrivateKeyInfo); +MAKE_DECODER("DHX", dhx, dhx, SubjectPublicKeyInfo); +MAKE_DECODER("DHX", dhx, dhx, type_specific_params); +MAKE_DECODER("DHX", dhx, dhx, DHX); +#endif +#ifndef OPENSSL_NO_DSA +MAKE_DECODER("DSA", dsa, dsa, PrivateKeyInfo); +MAKE_DECODER("DSA", dsa, dsa, SubjectPublicKeyInfo); +MAKE_DECODER("DSA", dsa, dsa, type_specific); +MAKE_DECODER("DSA", dsa, dsa, DSA); +#endif +#ifndef OPENSSL_NO_EC +MAKE_DECODER("EC", ec, ec, PrivateKeyInfo); +MAKE_DECODER("EC", ec, ec, SubjectPublicKeyInfo); +MAKE_DECODER("EC", ec, ec, type_specific_no_pub); +MAKE_DECODER("EC", ec, ec, EC); +MAKE_DECODER("X25519", x25519, ecx, PrivateKeyInfo); +MAKE_DECODER("X25519", x25519, ecx, SubjectPublicKeyInfo); +MAKE_DECODER("X448", x448, ecx, PrivateKeyInfo); +MAKE_DECODER("X448", x448, ecx, SubjectPublicKeyInfo); +MAKE_DECODER("ED25519", ed25519, ecx, PrivateKeyInfo); +MAKE_DECODER("ED25519", ed25519, ecx, SubjectPublicKeyInfo); +MAKE_DECODER("ED448", ed448, ecx, PrivateKeyInfo); +MAKE_DECODER("ED448", ed448, ecx, SubjectPublicKeyInfo); +# ifndef OPENSSL_NO_SM2 +MAKE_DECODER("SM2", sm2, ec, PrivateKeyInfo); +MAKE_DECODER("SM2", sm2, ec, SubjectPublicKeyInfo); +# endif +#endif +MAKE_DECODER("RSA", rsa, rsa, PrivateKeyInfo); +MAKE_DECODER("RSA", rsa, rsa, SubjectPublicKeyInfo); +MAKE_DECODER("RSA", rsa, rsa, type_specific_keypair); +MAKE_DECODER("RSA", rsa, rsa, RSA); +MAKE_DECODER("RSA-PSS", rsapss, rsapss, PrivateKeyInfo); +MAKE_DECODER("RSA-PSS", rsapss, rsapss, SubjectPublicKeyInfo); diff --git a/providers/implementations/encode_decode/decode_epki2pki.c b/providers/implementations/encode_decode/decode_epki2pki.c new file mode 100644 index 000000000000..9cea80b616d6 --- /dev/null +++ b/providers/implementations/encode_decode/decode_epki2pki.c @@ -0,0 +1,158 @@ +/* + * Copyright 2020-2022 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.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/asn1.h> +#include <openssl/err.h> +#include <openssl/objects.h> +#include <openssl/pkcs12.h> +#include <openssl/x509.h> +#include <openssl/proverr.h> +#include "internal/asn1.h" +#include "internal/sizes.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +static OSSL_FUNC_decoder_newctx_fn epki2pki_newctx; +static OSSL_FUNC_decoder_freectx_fn epki2pki_freectx; +static OSSL_FUNC_decoder_decode_fn epki2pki_decode; + +/* + * Context used for EncryptedPrivateKeyInfo to PrivateKeyInfo decoding. + */ +struct epki2pki_ctx_st { + PROV_CTX *provctx; +}; + +static void *epki2pki_newctx(void *provctx) +{ + struct epki2pki_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) + ctx->provctx = provctx; + return ctx; +} + +static void epki2pki_freectx(void *vctx) +{ + struct epki2pki_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +/* + * The selection parameter in epki2pki_decode() is not used by this function + * because it's not relevant just to decode EncryptedPrivateKeyInfo to + * PrivateKeyInfo. + */ +static int epki2pki_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct epki2pki_ctx_st *ctx = vctx; + BUF_MEM *mem = NULL; + unsigned char *der = NULL; + const unsigned char *pder = NULL; + long der_len = 0; + X509_SIG *p8 = NULL; + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + const X509_ALGOR *alg = NULL; + BIO *in = ossl_bio_new_from_core_bio(ctx->provctx, cin); + int ok = 0; + + if (in == NULL) + return 0; + + ok = (asn1_d2i_read_bio(in, &mem) >= 0); + BIO_free(in); + + /* We return "empty handed". This is not an error. */ + if (!ok) + return 1; + + pder = der = (unsigned char *)mem->data; + der_len = (long)mem->length; + OPENSSL_free(mem); + + ok = 1; /* Assume good */ + ERR_set_mark(); + if ((p8 = d2i_X509_SIG(NULL, &pder, der_len)) != NULL) { + char pbuf[1024]; + size_t plen = 0; + + ERR_clear_last_mark(); + + if (!pw_cb(pbuf, sizeof(pbuf), &plen, NULL, pw_cbarg)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PASSPHRASE); + ok = 0; + } else { + const ASN1_OCTET_STRING *oct; + unsigned char *new_der = NULL; + int new_der_len = 0; + + X509_SIG_get0(p8, &alg, &oct); + if (!PKCS12_pbe_crypt_ex(alg, pbuf, plen, + oct->data, oct->length, + &new_der, &new_der_len, 0, + PROV_LIBCTX_OF(ctx->provctx), NULL)) { + ok = 0; + } else { + OPENSSL_free(der); + der = new_der; + der_len = new_der_len; + } + alg = NULL; + } + X509_SIG_free(p8); + } else { + ERR_pop_to_mark(); + } + + ERR_set_mark(); + pder = der; + p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &pder, der_len); + ERR_pop_to_mark(); + + if (p8inf != NULL && PKCS8_pkey_get0(NULL, NULL, NULL, &alg, p8inf)) { + /* + * We have something and recognised it as PrivateKeyInfo, so let's + * pass all the applicable data to the callback. + */ + char keytype[OSSL_MAX_NAME_SIZE]; + OSSL_PARAM params[5], *p = params; + int objtype = OSSL_OBJECT_PKEY; + + OBJ_obj2txt(keytype, sizeof(keytype), alg->algorithm, 0); + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + keytype, 0); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, + "PrivateKeyInfo", 0); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, + der, der_len); + *p++ = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); + *p = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + PKCS8_PRIV_KEY_INFO_free(p8inf); + OPENSSL_free(der); + return ok; +} + +const OSSL_DISPATCH ossl_EncryptedPrivateKeyInfo_der_to_der_decoder_functions[] = { + { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))epki2pki_newctx }, + { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))epki2pki_freectx }, + { OSSL_FUNC_DECODER_DECODE, (void (*)(void))epki2pki_decode }, + { 0, NULL } +}; diff --git a/providers/implementations/encode_decode/decode_msblob2key.c b/providers/implementations/encode_decode/decode_msblob2key.c new file mode 100644 index 000000000000..501957faba01 --- /dev/null +++ b/providers/implementations/encode_decode/decode_msblob2key.c @@ -0,0 +1,273 @@ +/* + * Copyright 2020-2022 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 <string.h> + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/crypto.h> +#include <openssl/params.h> +#include <openssl/pem.h> /* For public PVK functions */ +#include <openssl/x509.h> +#include <openssl/err.h> +#include "internal/passphrase.h" +#include "crypto/pem.h" /* For internal PVK and "blob" headers */ +#include "crypto/rsa.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +struct msblob2key_ctx_st; /* Forward declaration */ +typedef void *b2i_of_void_fn(const unsigned char **in, unsigned int bitlen, + int ispub); +typedef void adjust_key_fn(void *, struct msblob2key_ctx_st *ctx); +typedef void free_key_fn(void *); +struct keytype_desc_st { + int type; /* EVP key type */ + const char *name; /* Keytype */ + const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */ + + b2i_of_void_fn *read_private_key; + b2i_of_void_fn *read_public_key; + adjust_key_fn *adjust_key; + free_key_fn *free_key; +}; + +static OSSL_FUNC_decoder_freectx_fn msblob2key_freectx; +static OSSL_FUNC_decoder_decode_fn msblob2key_decode; +static OSSL_FUNC_decoder_export_object_fn msblob2key_export_object; + +/* + * Context used for DER to key decoding. + */ +struct msblob2key_ctx_st { + PROV_CTX *provctx; + const struct keytype_desc_st *desc; + /* The selection that is passed to msblob2key_decode() */ + int selection; +}; + +static struct msblob2key_ctx_st * +msblob2key_newctx(void *provctx, const struct keytype_desc_st *desc) +{ + struct msblob2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + ctx->desc = desc; + } + return ctx; +} + +static void msblob2key_freectx(void *vctx) +{ + struct msblob2key_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static int msblob2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct msblob2key_ctx_st *ctx = vctx; + BIO *in = ossl_bio_new_from_core_bio(ctx->provctx, cin); + const unsigned char *p; + unsigned char hdr_buf[16], *buf = NULL; + unsigned int bitlen, magic, length; + int isdss = -1; + int ispub = -1; + void *key = NULL; + int ok = 0; + + if (in == NULL) + return 0; + + if (BIO_read(in, hdr_buf, 16) != 16) { + ERR_raise(ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT); + goto next; + } + ERR_set_mark(); + p = hdr_buf; + ok = ossl_do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) > 0; + ERR_pop_to_mark(); + if (!ok) + goto next; + + ctx->selection = selection; + ok = 0; /* Assume that we fail */ + + if ((isdss && ctx->desc->type != EVP_PKEY_DSA) + || (!isdss && ctx->desc->type != EVP_PKEY_RSA)) + goto next; + + length = ossl_blob_length(bitlen, isdss, ispub); + if (length > BLOB_MAX_LENGTH) { + ERR_raise(ERR_LIB_PEM, PEM_R_HEADER_TOO_LONG); + goto next; + } + buf = OPENSSL_malloc(length); + if (buf == NULL) { + ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE); + goto end; + } + p = buf; + if (BIO_read(in, buf, length) != (int)length) { + ERR_raise(ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT); + goto next; + } + + if ((selection == 0 + || (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + && !ispub + && ctx->desc->read_private_key != NULL) { + struct ossl_passphrase_data_st pwdata; + + memset(&pwdata, 0, sizeof(pwdata)); + if (!ossl_pw_set_ossl_passphrase_cb(&pwdata, pw_cb, pw_cbarg)) + goto end; + p = buf; + key = ctx->desc->read_private_key(&p, bitlen, ispub); + if (selection != 0 && key == NULL) + goto next; + } + if (key == NULL && (selection == 0 + || (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + && ispub + && ctx->desc->read_public_key != NULL) { + p = buf; + key = ctx->desc->read_public_key(&p, bitlen, ispub); + if (selection != 0 && key == NULL) + goto next; + } + + if (key != NULL && ctx->desc->adjust_key != NULL) + ctx->desc->adjust_key(key, ctx); + + next: + /* + * Indicated that we successfully decoded something, or not at all. + * Ending up "empty handed" is not an error. + */ + ok = 1; + + /* + * We free resources here so it's not held up during the callback, because + * we know the process is recursive and the allocated chunks of memory + * add up. + */ + OPENSSL_free(buf); + BIO_free(in); + buf = NULL; + in = NULL; + + if (key != NULL) { + OSSL_PARAM params[4]; + int object_type = OSSL_OBJECT_PKEY; + + params[0] = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type); + params[1] = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + (char *)ctx->desc->name, 0); + /* The address of the key becomes the octet string */ + params[2] = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE, + &key, sizeof(key)); + params[3] = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + + end: + BIO_free(in); + OPENSSL_free(buf); + ctx->desc->free_key(key); + + return ok; +} + +static int +msblob2key_export_object(void *vctx, + const void *reference, size_t reference_sz, + OSSL_CALLBACK *export_cb, void *export_cbarg) +{ + struct msblob2key_ctx_st *ctx = vctx; + OSSL_FUNC_keymgmt_export_fn *export = + ossl_prov_get_keymgmt_export(ctx->desc->fns); + void *keydata; + + if (reference_sz == sizeof(keydata) && export != NULL) { + /* The contents of the reference is the address to our object */ + keydata = *(void **)reference; + + return export(keydata, ctx->selection, export_cb, export_cbarg); + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +#define dsa_decode_private_key (b2i_of_void_fn *)ossl_b2i_DSA_after_header +#define dsa_decode_public_key (b2i_of_void_fn *)ossl_b2i_DSA_after_header +#define dsa_adjust NULL +#define dsa_free (void (*)(void *))DSA_free + +/* ---------------------------------------------------------------------- */ + +#define rsa_decode_private_key (b2i_of_void_fn *)ossl_b2i_RSA_after_header +#define rsa_decode_public_key (b2i_of_void_fn *)ossl_b2i_RSA_after_header + +static void rsa_adjust(void *key, struct msblob2key_ctx_st *ctx) +{ + ossl_rsa_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +#define rsa_free (void (*)(void *))RSA_free + +/* ---------------------------------------------------------------------- */ + +#define IMPLEMENT_MSBLOB(KEYTYPE, keytype) \ + static const struct keytype_desc_st mstype##2##keytype##_desc = { \ + EVP_PKEY_##KEYTYPE, #KEYTYPE, \ + ossl_##keytype##_keymgmt_functions, \ + keytype##_decode_private_key, \ + keytype##_decode_public_key, \ + keytype##_adjust, \ + keytype##_free \ + }; \ + static OSSL_FUNC_decoder_newctx_fn msblob2##keytype##_newctx; \ + static void *msblob2##keytype##_newctx(void *provctx) \ + { \ + return msblob2key_newctx(provctx, &mstype##2##keytype##_desc); \ + } \ + const OSSL_DISPATCH \ + ossl_msblob_to_##keytype##_decoder_functions[] = { \ + { OSSL_FUNC_DECODER_NEWCTX, \ + (void (*)(void))msblob2##keytype##_newctx }, \ + { OSSL_FUNC_DECODER_FREECTX, \ + (void (*)(void))msblob2key_freectx }, \ + { OSSL_FUNC_DECODER_DECODE, \ + (void (*)(void))msblob2key_decode }, \ + { OSSL_FUNC_DECODER_EXPORT_OBJECT, \ + (void (*)(void))msblob2key_export_object }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_DSA +IMPLEMENT_MSBLOB(DSA, dsa); +#endif +IMPLEMENT_MSBLOB(RSA, rsa); diff --git a/providers/implementations/encode_decode/decode_pem2der.c b/providers/implementations/encode_decode/decode_pem2der.c new file mode 100644 index 000000000000..bc937ffb9d27 --- /dev/null +++ b/providers/implementations/encode_decode/decode_pem2der.c @@ -0,0 +1,219 @@ +/* + * Copyright 2020-2022 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/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/params.h> +#include <openssl/pem.h> +#include <openssl/proverr.h> +#include "internal/nelem.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +static int read_pem(PROV_CTX *provctx, OSSL_CORE_BIO *cin, + char **pem_name, char **pem_header, + unsigned char **data, long *len) +{ + BIO *in = ossl_bio_new_from_core_bio(provctx, cin); + int ok; + + if (in == NULL) + return 0; + ok = (PEM_read_bio(in, pem_name, pem_header, data, len) > 0); + + BIO_free(in); + return ok; +} + +static OSSL_FUNC_decoder_newctx_fn pem2der_newctx; +static OSSL_FUNC_decoder_freectx_fn pem2der_freectx; +static OSSL_FUNC_decoder_decode_fn pem2der_decode; + +/* + * Context used for PEM to DER decoding. + */ +struct pem2der_ctx_st { + PROV_CTX *provctx; +}; + +static void *pem2der_newctx(void *provctx) +{ + struct pem2der_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) + ctx->provctx = provctx; + return ctx; +} + +static void pem2der_freectx(void *vctx) +{ + struct pem2der_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +/* pem_password_cb compatible function */ +struct pem2der_pass_data_st { + OSSL_PASSPHRASE_CALLBACK *cb; + void *cbarg; +}; + +static int pem2der_pass_helper(char *buf, int num, int w, void *data) +{ + struct pem2der_pass_data_st *pass_data = data; + size_t plen; + + if (pass_data == NULL + || pass_data->cb == NULL + || !pass_data->cb(buf, num, &plen, NULL, pass_data->cbarg)) + return -1; + return (int)plen; +} + +/* + * The selection parameter in pem2der_decode() is not used by this function + * because it's not relevant just to decode PEM to DER. + */ +static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + /* + * PEM names we recognise. Other PEM names should be recognised by + * other decoder implementations. + */ + static struct pem_name_map_st { + const char *pem_name; + int object_type; + const char *data_type; + const char *data_structure; + } pem_name_map[] = { + /* PKCS#8 and SubjectPublicKeyInfo */ + { PEM_STRING_PKCS8, OSSL_OBJECT_PKEY, NULL, "EncryptedPrivateKeyInfo" }, + { PEM_STRING_PKCS8INF, OSSL_OBJECT_PKEY, NULL, "PrivateKeyInfo" }, + { PEM_STRING_PUBLIC, OSSL_OBJECT_PKEY, NULL, "SubjectPublicKeyInfo" }, + + /* Our set of type specific PEM types */ + { PEM_STRING_DHPARAMS, OSSL_OBJECT_PKEY, "DH", "type-specific" }, + { PEM_STRING_DHXPARAMS, OSSL_OBJECT_PKEY, "X9.42 DH", "type-specific" }, + { PEM_STRING_DSA, OSSL_OBJECT_PKEY, "DSA", "type-specific" }, + { PEM_STRING_DSA_PUBLIC, OSSL_OBJECT_PKEY, "DSA", "type-specific" }, + { PEM_STRING_DSAPARAMS, OSSL_OBJECT_PKEY, "DSA", "type-specific" }, + { PEM_STRING_ECPRIVATEKEY, OSSL_OBJECT_PKEY, "EC", "type-specific" }, + { PEM_STRING_ECPARAMETERS, OSSL_OBJECT_PKEY, "EC", "type-specific" }, + { PEM_STRING_RSA, OSSL_OBJECT_PKEY, "RSA", "type-specific" }, + { PEM_STRING_RSA_PUBLIC, OSSL_OBJECT_PKEY, "RSA", "type-specific" }, + + /* + * A few others that there is at least have an object type for, even + * though there is no provider interface to handle such objects, yet. + * However, this is beneficial for the OSSL_STORE result handler. + */ + { PEM_STRING_X509, OSSL_OBJECT_CERT, NULL, "Certificate" }, + { PEM_STRING_X509_TRUSTED, OSSL_OBJECT_CERT, NULL, "Certificate" }, + { PEM_STRING_X509_OLD, OSSL_OBJECT_CERT, NULL, "Certificate" }, + { PEM_STRING_X509_CRL, OSSL_OBJECT_CRL, NULL, "CertificateList" } + }; + struct pem2der_ctx_st *ctx = vctx; + char *pem_name = NULL, *pem_header = NULL; + size_t i; + unsigned char *der = NULL; + long der_len = 0; + int ok = 0; + int objtype = OSSL_OBJECT_UNKNOWN; + + ok = read_pem(ctx->provctx, cin, &pem_name, &pem_header, + &der, &der_len) > 0; + /* We return "empty handed". This is not an error. */ + if (!ok) + return 1; + + /* + * 10 is the number of characters in "Proc-Type:", which + * PEM_get_EVP_CIPHER_INFO() requires to be present. + * If the PEM header has less characters than that, it's + * not worth spending cycles on it. + */ + if (strlen(pem_header) > 10) { + EVP_CIPHER_INFO cipher; + struct pem2der_pass_data_st pass_data; + + ok = 0; /* Assume that we fail */ + pass_data.cb = pw_cb; + pass_data.cbarg = pw_cbarg; + if (!PEM_get_EVP_CIPHER_INFO(pem_header, &cipher) + || !PEM_do_header(&cipher, der, &der_len, + pem2der_pass_helper, &pass_data)) + goto end; + } + + /* + * Indicated that we successfully decoded something, or not at all. + * Ending up "empty handed" is not an error. + */ + ok = 1; + + /* Have a look to see if we recognise anything */ + for (i = 0; i < OSSL_NELEM(pem_name_map); i++) + if (strcmp(pem_name, pem_name_map[i].pem_name) == 0) + break; + + if (i < OSSL_NELEM(pem_name_map)) { + OSSL_PARAM params[5], *p = params; + /* We expect these to be read only so casting away the const is ok */ + char *data_type = (char *)pem_name_map[i].data_type; + char *data_structure = (char *)pem_name_map[i].data_structure; + + objtype = pem_name_map[i].object_type; + if (data_type != NULL) + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + data_type, 0); + + /* We expect this to be read only so casting away the const is ok */ + if (data_structure != NULL) + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, + data_structure, 0); + *p++ = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, + der, der_len); + *p++ = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); + + *p = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + + end: + OPENSSL_free(pem_name); + OPENSSL_free(pem_header); + OPENSSL_free(der); + return ok; +} + +const OSSL_DISPATCH ossl_pem_to_der_decoder_functions[] = { + { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))pem2der_newctx }, + { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))pem2der_freectx }, + { OSSL_FUNC_DECODER_DECODE, (void (*)(void))pem2der_decode }, + { 0, NULL } +}; diff --git a/providers/implementations/encode_decode/decode_pvk2key.c b/providers/implementations/encode_decode/decode_pvk2key.c new file mode 100644 index 000000000000..c6424165b03b --- /dev/null +++ b/providers/implementations/encode_decode/decode_pvk2key.c @@ -0,0 +1,239 @@ +/* + * Copyright 2020-2022 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 <string.h> + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/crypto.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/pem.h> /* For public PVK functions */ +#include <openssl/x509.h> +#include "internal/passphrase.h" +#include "crypto/pem.h" /* For internal PVK and "blob" headers */ +#include "crypto/rsa.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +struct pvk2key_ctx_st; /* Forward declaration */ +typedef int check_key_fn(void *, struct pvk2key_ctx_st *ctx); +typedef void adjust_key_fn(void *, struct pvk2key_ctx_st *ctx); +typedef void *b2i_PVK_of_bio_pw_fn(BIO *in, pem_password_cb *cb, void *u, + OSSL_LIB_CTX *libctx, const char *propq); +typedef void free_key_fn(void *); +struct keytype_desc_st { + int type; /* EVP key type */ + const char *name; /* Keytype */ + const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */ + + b2i_PVK_of_bio_pw_fn *read_private_key; + adjust_key_fn *adjust_key; + free_key_fn *free_key; +}; + +static OSSL_FUNC_decoder_freectx_fn pvk2key_freectx; +static OSSL_FUNC_decoder_decode_fn pvk2key_decode; +static OSSL_FUNC_decoder_export_object_fn pvk2key_export_object; + +/* + * Context used for DER to key decoding. + */ +struct pvk2key_ctx_st { + PROV_CTX *provctx; + const struct keytype_desc_st *desc; + /* The selection that is passed to der2key_decode() */ + int selection; +}; + +static struct pvk2key_ctx_st * +pvk2key_newctx(void *provctx, const struct keytype_desc_st *desc) +{ + struct pvk2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + ctx->desc = desc; + } + return ctx; +} + +static void pvk2key_freectx(void *vctx) +{ + struct pvk2key_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static int pvk2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct pvk2key_ctx_st *ctx = vctx; + BIO *in = ossl_bio_new_from_core_bio(ctx->provctx, cin); + void *key = NULL; + int ok = 0; + + if (in == NULL) + return 0; + + ctx->selection = selection; + + if ((selection == 0 + || (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + && ctx->desc->read_private_key != NULL) { + struct ossl_passphrase_data_st pwdata; + int err, lib, reason; + + memset(&pwdata, 0, sizeof(pwdata)); + if (!ossl_pw_set_ossl_passphrase_cb(&pwdata, pw_cb, pw_cbarg)) + goto end; + + key = ctx->desc->read_private_key(in, ossl_pw_pvk_password, &pwdata, + PROV_LIBCTX_OF(ctx->provctx), NULL); + + /* + * Because the PVK API doesn't have a separate decrypt call, we need + * to check the error queue for certain well known errors that are + * considered fatal and which we pass through, while the rest gets + * thrown away. + */ + err = ERR_peek_last_error(); + lib = ERR_GET_LIB(err); + reason = ERR_GET_REASON(err); + if (lib == ERR_LIB_PEM + && (reason == PEM_R_BAD_PASSWORD_READ + || reason == PEM_R_BAD_DECRYPT)) { + ERR_clear_last_mark(); + goto end; + } + + if (selection != 0 && key == NULL) + goto next; + } + + if (key != NULL && ctx->desc->adjust_key != NULL) + ctx->desc->adjust_key(key, ctx); + + next: + /* + * Indicated that we successfully decoded something, or not at all. + * Ending up "empty handed" is not an error. + */ + ok = 1; + + /* + * We free resources here so it's not held up during the callback, because + * we know the process is recursive and the allocated chunks of memory + * add up. + */ + BIO_free(in); + in = NULL; + + if (key != NULL) { + OSSL_PARAM params[4]; + int object_type = OSSL_OBJECT_PKEY; + + params[0] = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type); + params[1] = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + (char *)ctx->desc->name, 0); + /* The address of the key becomes the octet string */ + params[2] = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE, + &key, sizeof(key)); + params[3] = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + + end: + BIO_free(in); + ctx->desc->free_key(key); + + return ok; +} + +static int pvk2key_export_object(void *vctx, + const void *reference, size_t reference_sz, + OSSL_CALLBACK *export_cb, void *export_cbarg) +{ + struct pvk2key_ctx_st *ctx = vctx; + OSSL_FUNC_keymgmt_export_fn *export = + ossl_prov_get_keymgmt_export(ctx->desc->fns); + void *keydata; + + if (reference_sz == sizeof(keydata) && export != NULL) { + /* The contents of the reference is the address to our object */ + keydata = *(void **)reference; + + return export(keydata, ctx->selection, export_cb, export_cbarg); + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +#define dsa_private_key_bio (b2i_PVK_of_bio_pw_fn *)b2i_DSA_PVK_bio_ex +#define dsa_adjust NULL +#define dsa_free (void (*)(void *))DSA_free + +/* ---------------------------------------------------------------------- */ + +#define rsa_private_key_bio (b2i_PVK_of_bio_pw_fn *)b2i_RSA_PVK_bio_ex + +static void rsa_adjust(void *key, struct pvk2key_ctx_st *ctx) +{ + ossl_rsa_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +#define rsa_free (void (*)(void *))RSA_free + +/* ---------------------------------------------------------------------- */ + +#define IMPLEMENT_MS(KEYTYPE, keytype) \ + static const struct keytype_desc_st \ + pvk2##keytype##_desc = { \ + EVP_PKEY_##KEYTYPE, #KEYTYPE, \ + ossl_##keytype##_keymgmt_functions, \ + keytype##_private_key_bio, \ + keytype##_adjust, \ + keytype##_free \ + }; \ + static OSSL_FUNC_decoder_newctx_fn pvk2##keytype##_newctx; \ + static void *pvk2##keytype##_newctx(void *provctx) \ + { \ + return pvk2key_newctx(provctx, &pvk2##keytype##_desc); \ + } \ + const OSSL_DISPATCH \ + ossl_##pvk_to_##keytype##_decoder_functions[] = { \ + { OSSL_FUNC_DECODER_NEWCTX, \ + (void (*)(void))pvk2##keytype##_newctx }, \ + { OSSL_FUNC_DECODER_FREECTX, \ + (void (*)(void))pvk2key_freectx }, \ + { OSSL_FUNC_DECODER_DECODE, \ + (void (*)(void))pvk2key_decode }, \ + { OSSL_FUNC_DECODER_EXPORT_OBJECT, \ + (void (*)(void))pvk2key_export_object }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_DSA +IMPLEMENT_MS(DSA, dsa); +#endif +IMPLEMENT_MS(RSA, rsa); diff --git a/providers/implementations/encode_decode/decode_spki2typespki.c b/providers/implementations/encode_decode/decode_spki2typespki.c new file mode 100644 index 000000000000..a5dbbb31adf8 --- /dev/null +++ b/providers/implementations/encode_decode/decode_spki2typespki.c @@ -0,0 +1,124 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> +#include <openssl/asn1t.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/params.h> +#include <openssl/x509.h> +#include "internal/sizes.h" +#include "crypto/x509.h" +#include "crypto/ec.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +static OSSL_FUNC_decoder_newctx_fn spki2typespki_newctx; +static OSSL_FUNC_decoder_freectx_fn spki2typespki_freectx; +static OSSL_FUNC_decoder_decode_fn spki2typespki_decode; + +/* + * Context used for SubjectPublicKeyInfo to Type specific SubjectPublicKeyInfo + * decoding. + */ +struct spki2typespki_ctx_st { + PROV_CTX *provctx; +}; + +static void *spki2typespki_newctx(void *provctx) +{ + struct spki2typespki_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) + ctx->provctx = provctx; + return ctx; +} + +static void spki2typespki_freectx(void *vctx) +{ + struct spki2typespki_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static int spki2typespki_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct spki2typespki_ctx_st *ctx = vctx; + unsigned char *der, *derp; + long len; + int ok = 0; + int objtype = OSSL_OBJECT_PKEY; + X509_PUBKEY *xpub = NULL; + X509_ALGOR *algor = NULL; + const ASN1_OBJECT *oid = NULL; + char dataname[OSSL_MAX_NAME_SIZE]; + OSSL_PARAM params[5], *p = params; + + if (!ossl_read_der(ctx->provctx, cin, &der, &len)) + return 1; + derp = der; + xpub = ossl_d2i_X509_PUBKEY_INTERNAL((const unsigned char **)&derp, len, + PROV_LIBCTX_OF(ctx->provctx)); + + + if (xpub == NULL) { + /* We return "empty handed". This is not an error. */ + ok = 1; + goto end; + } + + if (!X509_PUBKEY_get0_param(NULL, NULL, NULL, &algor, xpub)) + goto end; + X509_ALGOR_get0(&oid, NULL, NULL, algor); + +#ifndef OPENSSL_NO_EC + /* SM2 abuses the EC oid, so this could actually be SM2 */ + if (OBJ_obj2nid(oid) == NID_X9_62_id_ecPublicKey + && ossl_x509_algor_is_sm2(algor)) + strcpy(dataname, "SM2"); + else +#endif + if (OBJ_obj2txt(dataname, sizeof(dataname), oid, 0) <= 0) + goto end; + + ossl_X509_PUBKEY_INTERNAL_free(xpub); + xpub = NULL; + + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + dataname, 0); + + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, + "SubjectPublicKeyInfo", + 0); + *p++ = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, der, len); + *p++ = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); + + *p = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + + end: + ossl_X509_PUBKEY_INTERNAL_free(xpub); + OPENSSL_free(der); + return ok; +} + +const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_der_decoder_functions[] = { + { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))spki2typespki_newctx }, + { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))spki2typespki_freectx }, + { OSSL_FUNC_DECODER_DECODE, (void (*)(void))spki2typespki_decode }, + { 0, NULL } +}; diff --git a/providers/implementations/encode_decode/encode_key2any.c b/providers/implementations/encode_decode/encode_key2any.c new file mode 100644 index 000000000000..c7b01cb2b3e5 --- /dev/null +++ b/providers/implementations/encode_decode/encode_key2any.c @@ -0,0 +1,1465 @@ +/* + * Copyright 2020-2021 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 <openssl/proverr.h> +#include "internal/passphrase.h" +#include "internal/cryptlib.h" +#include "crypto/ecx.h" +#include "crypto/rsa.h" +#include "prov/implementations.h" +#include "prov/bio.h" +#include "prov/provider_ctx.h" +#include "prov/der_rsa.h" +#include "endecoder_local.h" + +#if defined(OPENSSL_NO_DH) && defined(OPENSSL_NO_DSA) && defined(OPENSSL_NO_EC) +# define OPENSSL_NO_KEYPARAMS +#endif + +struct key2any_ctx_st { + PROV_CTX *provctx; + + /* Set to 0 if parameters should not be saved (dsa only) */ + int save_parameters; + + /* 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, int save, + 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); + + +/* Free the blob allocated during key_to_paramstring_fn */ +static void free_asn1_data(int type, void *data) +{ + switch(type) { + case V_ASN1_OBJECT: + ASN1_OBJECT_free(data); + break; + case V_ASN1_SEQUENCE: + ASN1_STRING_free(data); + break; + } +} + +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; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + + 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_UNABLE_TO_GET_PASSPHRASE); + return NULL; + } + /* First argument == -1 means "standard" */ + p8 = PKCS8_encrypt_ex(-1, ctx->cipher, kstr, klen, NULL, 0, 0, p8info, libctx, NULL); + 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 = NULL; + + if (p8info == NULL) { + free_asn1_data(params_type, params); + } else { + 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_epki_* produce encoded output with the private key data in a + * EncryptedPrivateKeyInfo structure (defined by PKCS#8). They require + * that there's an intent to encrypt, anything else is an error. + * + * key_to_pki_* primarly produce encoded output with the private key data + * in a PrivateKeyInfo structure (also defined by PKCS#8). However, if + * there is an intent to encrypt the data, the corresponding key_to_epki_* + * function is used instead. + * + * key_to_spki_* produce encoded output with the public key data in an + * X.509 SubjectPublicKeyInfo. + * + * Key parameters don't have any defined envelopment of this kind, but are + * included in some manner in the output from the functions described above, + * either in the AlgorithmIdentifier's parameter field, or as part of the + * key data itself. + */ + +static int key_to_epki_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; + X509_SIG *p8; + + if (!ctx->cipher_intent) + return 0; + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx); + if (p8 != NULL) + ret = i2d_PKCS8_bio(out, p8); + + X509_SIG_free(p8); + + return ret; +} + +static int key_to_epki_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; + X509_SIG *p8; + + if (!ctx->cipher_intent) + return 0; + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + 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); + + return ret; +} + +static int key_to_pki_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; + PKCS8_PRIV_KEY_INFO *p8info; + + if (ctx->cipher_intent) + return key_to_epki_der_priv_bio(out, key, key_nid, pemname, + p2s, k2d, ctx); + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8info = key_to_p8info(key, key_nid, str, strtype, k2d); + + if (p8info != NULL) + ret = i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8info); + else + free_asn1_data(strtype, str); + + PKCS8_PRIV_KEY_INFO_free(p8info); + + return ret; +} + +static int key_to_pki_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; + PKCS8_PRIV_KEY_INFO *p8info; + + if (ctx->cipher_intent) + return key_to_epki_pem_priv_bio(out, key, key_nid, pemname, + p2s, k2d, ctx); + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8info = key_to_p8info(key, key_nid, str, strtype, k2d); + + if (p8info != NULL) + ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8info); + else + free_asn1_data(strtype, str); + + 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, ctx->save_parameters, + &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, ctx->save_parameters, + &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); + else + free_asn1_data(strtype, str); + + /* 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, cb, cbarg) > 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); +} + +#ifndef OPENSSL_NO_KEYPARAMS +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); +} +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DH +static int prepare_dh_params(const void *dh, int nid, int save, + 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_pki_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; +} + +# define dh_epki_priv_to_der dh_pki_priv_to_der + +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 encode_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_dsa_params(const void *dsa, int nid, int save, + 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 (save && p != NULL && q != NULL && g != NULL) + return encode_dsa_params(dsa, nid, pstr, pstrtype); + + *pstr = NULL; + *pstrtype = V_ASN1_UNDEF; + return 1; +} + +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_pki_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_epki_priv_to_der dsa_pki_priv_to_der + +# 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. + */ +static int prepare_ec_params(const void *eckey, int nid, int save, + 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) +{ + if (EC_KEY_get0_public_key(eckey) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + return i2o_ECPublicKey(eckey, pder); +} + +static int ec_pki_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_epki_priv_to_der ec_pki_priv_to_der + +# define ec_type_specific_params_to_der (i2d_of_void *)i2d_ECParameters +/* No ec_type_specific_pub_to_der, there simply is no such thing */ +# 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" + +# ifndef OPENSSL_NO_SM2 +# define sm2_evp_type EVP_PKEY_SM2 +# define sm2_input_type "SM2" +# define sm2_pem_type "SM2" +# endif +#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_pki_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; +} + +# define ecx_epki_priv_to_der ecx_pki_priv_to_der + +/* + * 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, int save, + 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_pki_priv_to_der rsa_type_specific_priv_to_der +#define rsa_epki_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; + ctx->save_parameters = 1; + } + + 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_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); + const OSSL_PARAM *save_paramsp = + OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_SAVE_PARAMETERS); + + 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; + } + + if (save_paramsp != NULL) { + if (!OSSL_PARAM_get_int(save_paramsp, &ctx->save_parameters)) + 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 = ossl_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): + * + * 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 defines two structures for private keys only: + * - PrivateKeyInfo (raw unencrypted form) + * - EncryptedPrivateKeyInfo (encrypted wrapping) + * + * To allow a certain amount of flexibility, we allow the routines + * for PrivateKeyInfo to also produce EncryptedPrivateKeyInfo if a + * passphrase callback has been passed to them. + */ +#define DO_PrivateKeyInfo_selection_mask DO_PRIVATE_KEY_selection_mask +#define DO_PrivateKeyInfo(impl, type, output) \ + DO_PRIVATE_KEY(impl, type, pki, output) + +#define DO_EncryptedPrivateKeyInfo_selection_mask DO_PRIVATE_KEY_selection_mask +#define DO_EncryptedPrivateKeyInfo(impl, type, output) \ + DO_PRIVATE_KEY(impl, type, epki, output) + +/* SubjectPublicKeyInfo is a structure for public keys only */ +#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 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 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 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 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 DO_RSA_selection_mask DO_type_specific_keypair_selection_mask +#define DO_RSA(impl, type, output) DO_type_specific_keypair(impl, type, output) + +#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 DO_DHX_selection_mask DO_type_specific_params_selection_mask +#define DO_DHX(impl, type, output) DO_type_specific_params(impl, type, output) + +#define DO_DSA_selection_mask DO_type_specific_selection_mask +#define DO_DSA(impl, type, output) DO_type_specific(impl, type, output) + +#define DO_EC_selection_mask DO_type_specific_no_pub_selection_mask +#define DO_EC(impl, type, output) DO_type_specific_no_pub(impl, type, output) + +#define DO_SM2_selection_mask DO_type_specific_no_pub_selection_mask +#define DO_SM2(impl, type, output) DO_type_specific_no_pub(impl, type, output) + +/* PKCS#1 defines a structure for RSA private and public keys */ +#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 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 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 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_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 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_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); +# ifndef OPENSSL_NO_SM2 +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, type_specific_no_pub, der); +# endif +#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); +# ifndef OPENSSL_NO_SM2 +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, type_specific_no_pub, pem); +# endif +#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, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PrivateKeyInfo, der); +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PrivateKeyInfo, 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, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PrivateKeyInfo, der); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PrivateKeyInfo, 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, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PrivateKeyInfo, der); +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PrivateKeyInfo, 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, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PrivateKeyInfo, der); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PrivateKeyInfo, 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, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PrivateKeyInfo, der); +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PrivateKeyInfo, 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, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PrivateKeyInfo, der); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PrivateKeyInfo, pem); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, der); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, pem); +# ifndef OPENSSL_NO_SM2 +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, PrivateKeyInfo, der); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, PrivateKeyInfo, pem); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, der); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, pem); +# endif +MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PrivateKeyInfo, der); +MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PrivateKeyInfo, 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, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, der); +MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, 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, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PrivateKeyInfo, der); +MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PrivateKeyInfo, 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, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, der); +MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, 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); +# ifndef OPENSSL_NO_SM2 +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, SM2, der); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, SM2, pem); +# endif +#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 diff --git a/providers/implementations/encode_decode/encode_key2blob.c b/providers/implementations/encode_decode/encode_key2blob.c new file mode 100644 index 000000000000..550bceb09f58 --- /dev/null +++ b/providers/implementations/encode_decode/encode_key2blob.c @@ -0,0 +1,179 @@ +/* + * Copyright 2021-2022 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/params.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/ec.h> +#include "internal/passphrase.h" +#include "internal/nelem.h" +#include "prov/implementations.h" +#include "prov/bio.h" +#include "prov/provider_ctx.h" +#include "endecoder_local.h" + +static int write_blob(void *provctx, OSSL_CORE_BIO *cout, + void *data, int len) +{ + BIO *out = ossl_bio_new_from_core_bio(provctx, cout); + int ret; + + if (out == NULL) + return 0; + ret = BIO_write(out, data, len); + + BIO_free(out); + return ret; +} + +static OSSL_FUNC_encoder_newctx_fn key2blob_newctx; +static OSSL_FUNC_encoder_freectx_fn key2blob_freectx; + +static void *key2blob_newctx(void *provctx) +{ + return provctx; +} + +static void key2blob_freectx(void *vctx) +{ +} + +static int key2blob_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 key2blob_encode(void *vctx, const void *key, int selection, + OSSL_CORE_BIO *cout) +{ + int pubkey_len = 0, ok = 0; + unsigned char *pubkey = NULL; + + pubkey_len = i2o_ECPublicKey(key, &pubkey); + if (pubkey_len > 0 && pubkey != NULL) + ok = write_blob(vctx, cout, pubkey, pubkey_len); + OPENSSL_free(pubkey); + return ok; +} + +/* + * MAKE_BLOB_ENCODER() Makes an OSSL_DISPATCH table for a particular key->blob + * encoder + * + * impl: The keytype to encode + * type: The C structure type holding the key data + * selection_name: The acceptable selections. This translates into + * the macro EVP_PKEY_##selection_name. + * + * The selection is understood as a "level" rather than an exact set of + * requests from the caller. The encoder has to decide what contents fit + * the encoded format. For example, the EC public key blob will only contain + * the encoded public key itself, no matter if the selection bits include + * OSSL_KEYMGMT_SELECT_PARAMETERS or not. However, if the selection includes + * OSSL_KEYMGMT_SELECT_PRIVATE_KEY, the same encoder will simply refuse to + * cooperate, because it cannot output the private key. + * + * EVP_PKEY_##selection_name are convenience macros that combine "typical" + * OSSL_KEYMGMT_SELECT_ macros for a certain type of EVP_PKEY content. + */ +#define MAKE_BLOB_ENCODER(impl, type, selection_name) \ + static OSSL_FUNC_encoder_import_object_fn \ + impl##2blob_import_object; \ + static OSSL_FUNC_encoder_free_object_fn impl##2blob_free_object; \ + static OSSL_FUNC_encoder_does_selection_fn \ + impl##2blob_does_selection; \ + static OSSL_FUNC_encoder_encode_fn impl##2blob_encode; \ + \ + static void *impl##2blob_import_object(void *ctx, int selection, \ + const OSSL_PARAM params[]) \ + { \ + return ossl_prov_import_key(ossl_##impl##_keymgmt_functions, \ + ctx, selection, params); \ + } \ + static void impl##2blob_free_object(void *key) \ + { \ + ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key); \ + } \ + static int impl##2blob_does_selection(void *ctx, int selection) \ + { \ + return key2blob_check_selection(selection, \ + EVP_PKEY_##selection_name); \ + } \ + static int impl##2blob_encode(void *vctx, 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; \ + } \ + return key2blob_encode(vctx, key, selection, cout); \ + } \ + const OSSL_DISPATCH ossl_##impl##_to_blob_encoder_functions[] = { \ + { OSSL_FUNC_ENCODER_NEWCTX, \ + (void (*)(void))key2blob_newctx }, \ + { OSSL_FUNC_ENCODER_FREECTX, \ + (void (*)(void))key2blob_freectx }, \ + { OSSL_FUNC_ENCODER_DOES_SELECTION, \ + (void (*)(void))impl##2blob_does_selection }, \ + { OSSL_FUNC_ENCODER_IMPORT_OBJECT, \ + (void (*)(void))impl##2blob_import_object }, \ + { OSSL_FUNC_ENCODER_FREE_OBJECT, \ + (void (*)(void))impl##2blob_free_object }, \ + { OSSL_FUNC_ENCODER_ENCODE, \ + (void (*)(void))impl##2blob_encode }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_EC +MAKE_BLOB_ENCODER(ec, ec, PUBLIC_KEY); +# ifndef OPENSSL_NO_SM2 +MAKE_BLOB_ENCODER(sm2, ec, PUBLIC_KEY); +# endif +#endif diff --git a/providers/implementations/encode_decode/encode_key2ms.c b/providers/implementations/encode_decode/encode_key2ms.c new file mode 100644 index 000000000000..fe8c2dce4316 --- /dev/null +++ b/providers/implementations/encode_decode/encode_key2ms.c @@ -0,0 +1,234 @@ +/* + * Copyright 2020-2022 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 <string.h> +#include <openssl/core.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/pem.h> /* Functions for writing MSBLOB and PVK */ +#include <openssl/dsa.h> +#include "internal/passphrase.h" +#include "crypto/rsa.h" +#include "prov/implementations.h" +#include "prov/bio.h" +#include "prov/provider_ctx.h" +#include "endecoder_local.h" + +struct key2ms_ctx_st { + PROV_CTX *provctx; + + int pvk_encr_level; + + struct ossl_passphrase_data_st pwdata; +}; + +static int write_msblob(struct key2ms_ctx_st *ctx, OSSL_CORE_BIO *cout, + EVP_PKEY *pkey, int ispub) +{ + BIO *out = ossl_bio_new_from_core_bio(ctx->provctx, cout); + int ret; + + if (out == NULL) + return 0; + ret = ispub ? i2b_PublicKey_bio(out, pkey) : i2b_PrivateKey_bio(out, pkey); + + BIO_free(out); + return ret; +} + +static int write_pvk(struct key2ms_ctx_st *ctx, OSSL_CORE_BIO *cout, + EVP_PKEY *pkey) +{ + BIO *out = NULL; + int ret; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + + out = ossl_bio_new_from_core_bio(ctx->provctx, cout); + if (out == NULL) + return 0; + ret = i2b_PVK_bio_ex(out, pkey, ctx->pvk_encr_level, + ossl_pw_pvk_password, &ctx->pwdata, libctx, NULL); + BIO_free(out); + return ret; +} + +static OSSL_FUNC_encoder_freectx_fn key2ms_freectx; +static OSSL_FUNC_encoder_does_selection_fn key2ms_does_selection; + +static struct key2ms_ctx_st *key2ms_newctx(void *provctx) +{ + struct key2ms_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + /* This is the strongest encryption level */ + ctx->pvk_encr_level = 2; + } + return ctx; +} + +static void key2ms_freectx(void *vctx) +{ + struct key2ms_ctx_st *ctx = vctx; + + ossl_pw_clear_passphrase_data(&ctx->pwdata); + OPENSSL_free(ctx); +} + +static const OSSL_PARAM *key2pvk_settable_ctx_params(ossl_unused void *provctx) +{ + static const OSSL_PARAM settables[] = { + OSSL_PARAM_int(OSSL_ENCODER_PARAM_ENCRYPT_LEVEL, NULL), + OSSL_PARAM_END, + }; + + return settables; +} + +static int key2pvk_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct key2ms_ctx_st *ctx = vctx; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_ENCRYPT_LEVEL); + if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->pvk_encr_level)) + return 0; + return 1; +} + +static int key2ms_does_selection(void *vctx, int selection) +{ + return (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0; +} + +/* + * The real EVP_PKEY_set1_TYPE() functions take a non-const key, while the key + * pointer in the encode function is a const pointer. We violate the constness + * knowingly, since we know that the key comes from the same provider, is never + * actually const, and the implied reference count change is safe. + * + * EVP_PKEY_assign() can't be used, because there's no way to clear the internal + * key using that function without freeing the existing internal key. + */ +typedef int evp_pkey_set1_fn(EVP_PKEY *, const void *key); + +static int key2msblob_encode(void *vctx, const void *key, int selection, + OSSL_CORE_BIO *cout, evp_pkey_set1_fn *set1_key, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct key2ms_ctx_st *ctx = vctx; + int ispub = -1; + EVP_PKEY *pkey = NULL; + int ok = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ispub = 0; + else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ispub = 1; + else + return 0; /* Error */ + + if ((pkey = EVP_PKEY_new()) != NULL && set1_key(pkey, key)) + ok = write_msblob(ctx, cout, pkey, ispub); + EVP_PKEY_free(pkey); + return ok; +} + +static int key2pvk_encode(void *vctx, const void *key, int selection, + OSSL_CORE_BIO *cout, evp_pkey_set1_fn *set1_key, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct key2ms_ctx_st *ctx = vctx; + EVP_PKEY *pkey = NULL; + int ok = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) == 0) + return 0; /* Error */ + + if ((pkey = EVP_PKEY_new()) != NULL && set1_key(pkey, key) + && (pw_cb == NULL + || ossl_pw_set_ossl_passphrase_cb(&ctx->pwdata, pw_cb, pw_cbarg))) + ok = write_pvk(ctx, cout, pkey); + EVP_PKEY_free(pkey); + return ok; +} + +#define dsa_set1 (evp_pkey_set1_fn *)EVP_PKEY_set1_DSA +#define rsa_set1 (evp_pkey_set1_fn *)EVP_PKEY_set1_RSA + +#define msblob_set_params +#define pvk_set_params \ + { OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))key2pvk_settable_ctx_params }, \ + { OSSL_FUNC_ENCODER_SET_CTX_PARAMS, \ + (void (*)(void))key2pvk_set_ctx_params }, + +#define MAKE_MS_ENCODER(impl, output, type) \ + static OSSL_FUNC_encoder_import_object_fn \ + impl##2##output##_import_object; \ + static OSSL_FUNC_encoder_free_object_fn impl##2##output##_free_object; \ + static OSSL_FUNC_encoder_encode_fn impl##2##output##_encode; \ + \ + static void * \ + impl##2##output##_import_object(void *ctx, int selection, \ + const OSSL_PARAM params[]) \ + { \ + return ossl_prov_import_key(ossl_##impl##_keymgmt_functions, \ + ctx, selection, params); \ + } \ + static void impl##2##output##_free_object(void *key) \ + { \ + ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key); \ + } \ + static int impl##2##output##_encode(void *vctx, 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; \ + } \ + return key2##output##_encode(vctx, key, selection, cout, type##_set1, \ + cb, cbarg); \ + } \ + const OSSL_DISPATCH ossl_##impl##_to_##output##_encoder_functions[] = { \ + { OSSL_FUNC_ENCODER_NEWCTX, \ + (void (*)(void))key2ms_newctx }, \ + { OSSL_FUNC_ENCODER_FREECTX, \ + (void (*)(void))key2ms_freectx }, \ + output##_set_params \ + { OSSL_FUNC_ENCODER_DOES_SELECTION, \ + (void (*)(void))key2ms_does_selection }, \ + { OSSL_FUNC_ENCODER_IMPORT_OBJECT, \ + (void (*)(void))impl##2##output##_import_object }, \ + { OSSL_FUNC_ENCODER_FREE_OBJECT, \ + (void (*)(void))impl##2##output##_free_object }, \ + { OSSL_FUNC_ENCODER_ENCODE, \ + (void (*)(void))impl##2##output##_encode }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_DSA +MAKE_MS_ENCODER(dsa, pvk, dsa); +MAKE_MS_ENCODER(dsa, msblob, dsa); +#endif + +MAKE_MS_ENCODER(rsa, pvk, rsa); +MAKE_MS_ENCODER(rsa, msblob, rsa); diff --git a/providers/implementations/encode_decode/encode_key2text.c b/providers/implementations/encode_decode/encode_key2text.c new file mode 100644 index 000000000000..7d983f5e51c6 --- /dev/null +++ b/providers/implementations/encode_decode/encode_key2text.c @@ -0,0 +1,889 @@ +/* + * Copyright 2020-2022 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 <ctype.h> + +#include <openssl/core.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/safestack.h> +#include <openssl/proverr.h> +#include "internal/ffc.h" +#include "crypto/bn.h" /* bn_get_words() */ +#include "crypto/dh.h" /* ossl_dh_get0_params() */ +#include "crypto/dsa.h" /* ossl_dsa_get0_params() */ +#include "crypto/ec.h" /* ossl_ec_key_get_libctx */ +#include "crypto/ecx.h" /* ECX_KEY, etc... */ +#include "crypto/rsa.h" /* RSA_PSS_PARAMS_30, etc... */ +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +DEFINE_SPECIAL_STACK_OF_CONST(BIGNUM_const, BIGNUM) + +# ifdef SIXTY_FOUR_BIT_LONG +# define BN_FMTu "%lu" +# define BN_FMTx "%lx" +# endif + +# ifdef SIXTY_FOUR_BIT +# define BN_FMTu "%llu" +# define BN_FMTx "%llx" +# endif + +# ifdef THIRTY_TWO_BIT +# define BN_FMTu "%u" +# define BN_FMTx "%x" +# endif + +static int print_labeled_bignum(BIO *out, const char *label, const BIGNUM *bn) +{ + int ret = 0, use_sep = 0; + char *hex_str = NULL, *p; + const char spaces[] = " "; + const char *post_label_spc = " "; + + const char *neg = ""; + int bytes; + + if (bn == NULL) + return 0; + if (label == NULL) { + label = ""; + post_label_spc = ""; + } + + if (BN_is_zero(bn)) + return BIO_printf(out, "%s%s0\n", label, post_label_spc); + + if (BN_num_bytes(bn) <= BN_BYTES) { + BN_ULONG *words = bn_get_words(bn); + + if (BN_is_negative(bn)) + neg = "-"; + + return BIO_printf(out, "%s%s%s" BN_FMTu " (%s0x" BN_FMTx ")\n", + label, post_label_spc, neg, words[0], neg, words[0]); + } + + hex_str = BN_bn2hex(bn); + if (hex_str == NULL) + return 0; + + p = hex_str; + if (*p == '-') { + ++p; + neg = " (Negative)"; + } + if (BIO_printf(out, "%s%s\n", label, neg) <= 0) + goto err; + + /* Keep track of how many bytes we have printed out so far */ + bytes = 0; + + if (BIO_printf(out, "%s", spaces) <= 0) + goto err; + + /* Add a leading 00 if the top bit is set */ + if (*p >= '8') { + if (BIO_printf(out, "%02x", 0) <= 0) + goto err; + ++bytes; + use_sep = 1; + } + while (*p != '\0') { + /* Do a newline after every 15 hex bytes + add the space indent */ + if ((bytes % 15) == 0 && bytes > 0) { + if (BIO_printf(out, ":\n%s", spaces) <= 0) + goto err; + use_sep = 0; /* The first byte on the next line doesnt have a : */ + } + if (BIO_printf(out, "%s%c%c", use_sep ? ":" : "", + tolower(p[0]), tolower(p[1])) <= 0) + goto err; + ++bytes; + p += 2; + use_sep = 1; + } + if (BIO_printf(out, "\n") <= 0) + goto err; + ret = 1; +err: + OPENSSL_free(hex_str); + return ret; +} + +/* Number of octets per line */ +#define LABELED_BUF_PRINT_WIDTH 15 + +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_EC) +static int print_labeled_buf(BIO *out, const char *label, + const unsigned char *buf, size_t buflen) +{ + size_t i; + + if (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 && BIO_printf(out, "\n") <= 0) + return 0; + if (BIO_printf(out, " ") <= 0) + return 0; + } + + if (BIO_printf(out, "%02x%s", buf[i], + (i == buflen - 1) ? "" : ":") <= 0) + return 0; + } + if (BIO_printf(out, "\n") <= 0) + return 0; + + return 1; +} +#endif + +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_DSA) +static int ffc_params_to_text(BIO *out, const FFC_PARAMS *ffc) +{ + if (ffc->nid != NID_undef) { +#ifndef OPENSSL_NO_DH + const DH_NAMED_GROUP *group = ossl_ffc_uid_to_dh_named_group(ffc->nid); + const char *name = ossl_ffc_named_group_get_name(group); + + if (name == NULL) + goto err; + if (BIO_printf(out, "GROUP: %s\n", name) <= 0) + goto err; + return 1; +#else + /* How could this be? We should not have a nid in a no-dh build. */ + goto err; +#endif + } + + if (!print_labeled_bignum(out, "P: ", ffc->p)) + goto err; + if (ffc->q != NULL) { + if (!print_labeled_bignum(out, "Q: ", ffc->q)) + goto err; + } + if (!print_labeled_bignum(out, "G: ", ffc->g)) + goto err; + if (ffc->j != NULL) { + if (!print_labeled_bignum(out, "J: ", ffc->j)) + goto err; + } + if (ffc->seed != NULL) { + if (!print_labeled_buf(out, "SEED:", ffc->seed, ffc->seedlen)) + goto err; + } + if (ffc->gindex != -1) { + if (BIO_printf(out, "gindex: %d\n", ffc->gindex) <= 0) + goto err; + } + if (ffc->pcounter != -1) { + if (BIO_printf(out, "pcounter: %d\n", ffc->pcounter) <= 0) + goto err; + } + if (ffc->h != 0) { + if (BIO_printf(out, "h: %d\n", ffc->h) <= 0) + goto err; + } + return 1; +err: + return 0; +} +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DH +static int dh_to_text(BIO *out, const void *key, int selection) +{ + const DH *dh = key; + const char *type_label = NULL; + const BIGNUM *priv_key = NULL, *pub_key = NULL; + const FFC_PARAMS *params = NULL; + const BIGNUM *p = NULL; + long length; + + if (out == NULL || dh == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + type_label = "DH Private-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + type_label = "DH Public-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + type_label = "DH Parameters"; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + priv_key = DH_get0_priv_key(dh); + if (priv_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } + } + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + pub_key = DH_get0_pub_key(dh); + if (pub_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + } + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + params = ossl_dh_get0_params((DH *)dh); + if (params == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_PARAMETERS); + return 0; + } + } + + p = DH_get0_p(dh); + if (p == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + + if (BIO_printf(out, "%s: (%d bit)\n", type_label, BN_num_bits(p)) <= 0) + return 0; + if (priv_key != NULL + && !print_labeled_bignum(out, "private-key:", priv_key)) + return 0; + if (pub_key != NULL + && !print_labeled_bignum(out, "public-key:", pub_key)) + return 0; + if (params != NULL + && !ffc_params_to_text(out, params)) + return 0; + length = DH_get_length(dh); + if (length > 0 + && BIO_printf(out, "recommended-private-length: %ld bits\n", + length) <= 0) + return 0; + + return 1; +} + +# define dh_input_type "DH" +# define dhx_input_type "DHX" +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DSA +static int dsa_to_text(BIO *out, const void *key, int selection) +{ + const DSA *dsa = key; + const char *type_label = NULL; + const BIGNUM *priv_key = NULL, *pub_key = NULL; + const FFC_PARAMS *params = NULL; + const BIGNUM *p = NULL; + + if (out == NULL || dsa == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + type_label = "Private-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + type_label = "Public-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + type_label = "DSA-Parameters"; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + priv_key = DSA_get0_priv_key(dsa); + if (priv_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } + } + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + pub_key = DSA_get0_pub_key(dsa); + if (pub_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + } + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + params = ossl_dsa_get0_params((DSA *)dsa); + if (params == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_PARAMETERS); + return 0; + } + } + + p = DSA_get0_p(dsa); + if (p == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + + if (BIO_printf(out, "%s: (%d bit)\n", type_label, BN_num_bits(p)) <= 0) + return 0; + if (priv_key != NULL + && !print_labeled_bignum(out, "priv:", priv_key)) + return 0; + if (pub_key != NULL + && !print_labeled_bignum(out, "pub: ", pub_key)) + return 0; + if (params != NULL + && !ffc_params_to_text(out, params)) + return 0; + + return 1; +} + +# define dsa_input_type "DSA" +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_EC +static int ec_param_explicit_curve_to_text(BIO *out, const EC_GROUP *group, + BN_CTX *ctx) +{ + const char *plabel = "Prime:"; + BIGNUM *p = NULL, *a = NULL, *b = NULL; + + p = BN_CTX_get(ctx); + a = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + if (b == NULL + || !EC_GROUP_get_curve(group, p, a, b, ctx)) + return 0; + + if (EC_GROUP_get_field_type(group) == NID_X9_62_characteristic_two_field) { + int basis_type = EC_GROUP_get_basis_type(group); + + /* print the 'short name' of the base type OID */ + if (basis_type == NID_undef + || BIO_printf(out, "Basis Type: %s\n", OBJ_nid2sn(basis_type)) <= 0) + return 0; + plabel = "Polynomial:"; + } + return print_labeled_bignum(out, plabel, p) + && print_labeled_bignum(out, "A: ", a) + && print_labeled_bignum(out, "B: ", b); +} + +static int ec_param_explicit_gen_to_text(BIO *out, const EC_GROUP *group, + BN_CTX *ctx) +{ + int ret; + size_t buflen; + point_conversion_form_t form; + const EC_POINT *point = NULL; + const char *glabel = NULL; + unsigned char *buf = NULL; + + form = EC_GROUP_get_point_conversion_form(group); + point = EC_GROUP_get0_generator(group); + + if (point == NULL) + return 0; + + switch (form) { + case POINT_CONVERSION_COMPRESSED: + glabel = "Generator (compressed):"; + break; + case POINT_CONVERSION_UNCOMPRESSED: + glabel = "Generator (uncompressed):"; + break; + case POINT_CONVERSION_HYBRID: + glabel = "Generator (hybrid):"; + break; + default: + return 0; + } + + buflen = EC_POINT_point2buf(group, point, form, &buf, ctx); + if (buflen == 0) + return 0; + + ret = print_labeled_buf(out, glabel, buf, buflen); + OPENSSL_clear_free(buf, buflen); + return ret; +} + +/* Print explicit parameters */ +static int ec_param_explicit_to_text(BIO *out, const EC_GROUP *group, + OSSL_LIB_CTX *libctx) +{ + int ret = 0, tmp_nid; + BN_CTX *ctx = NULL; + const BIGNUM *order = NULL, *cofactor = NULL; + const unsigned char *seed; + size_t seed_len = 0; + + ctx = BN_CTX_new_ex(libctx); + if (ctx == NULL) + return 0; + BN_CTX_start(ctx); + + tmp_nid = EC_GROUP_get_field_type(group); + order = EC_GROUP_get0_order(group); + if (order == NULL) + goto err; + + seed = EC_GROUP_get0_seed(group); + if (seed != NULL) + seed_len = EC_GROUP_get_seed_len(group); + cofactor = EC_GROUP_get0_cofactor(group); + + /* print the 'short name' of the field type */ + if (BIO_printf(out, "Field Type: %s\n", OBJ_nid2sn(tmp_nid)) <= 0 + || !ec_param_explicit_curve_to_text(out, group, ctx) + || !ec_param_explicit_gen_to_text(out, group, ctx) + || !print_labeled_bignum(out, "Order: ", order) + || (cofactor != NULL + && !print_labeled_bignum(out, "Cofactor: ", cofactor)) + || (seed != NULL + && !print_labeled_buf(out, "Seed:", seed, seed_len))) + goto err; + ret = 1; +err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ret; +} + +static int ec_param_to_text(BIO *out, const EC_GROUP *group, + OSSL_LIB_CTX *libctx) +{ + if (EC_GROUP_get_asn1_flag(group) & OPENSSL_EC_NAMED_CURVE) { + const char *curve_name; + int curve_nid = EC_GROUP_get_curve_name(group); + + /* Explicit parameters */ + if (curve_nid == NID_undef) + return 0; + + if (BIO_printf(out, "%s: %s\n", "ASN1 OID", OBJ_nid2sn(curve_nid)) <= 0) + return 0; + + curve_name = EC_curve_nid2nist(curve_nid); + return (curve_name == NULL + || BIO_printf(out, "%s: %s\n", "NIST CURVE", curve_name) > 0); + } else { + return ec_param_explicit_to_text(out, group, libctx); + } +} + +static int ec_to_text(BIO *out, const void *key, int selection) +{ + const EC_KEY *ec = key; + const char *type_label = NULL; + unsigned char *priv = NULL, *pub = NULL; + size_t priv_len = 0, pub_len = 0; + const EC_GROUP *group; + int ret = 0; + + if (out == NULL || ec == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((group = EC_KEY_get0_group(ec)) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + type_label = "Private-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + type_label = "Public-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + type_label = "EC-Parameters"; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + const BIGNUM *priv_key = EC_KEY_get0_private_key(ec); + + if (priv_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + goto err; + } + priv_len = EC_KEY_priv2buf(ec, &priv); + if (priv_len == 0) + goto err; + } + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + const EC_POINT *pub_pt = EC_KEY_get0_public_key(ec); + + if (pub_pt == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + goto err; + } + + pub_len = EC_KEY_key2buf(ec, EC_KEY_get_conv_form(ec), &pub, NULL); + if (pub_len == 0) + goto err; + } + + if (BIO_printf(out, "%s: (%d bit)\n", type_label, + EC_GROUP_order_bits(group)) <= 0) + goto err; + if (priv != NULL + && !print_labeled_buf(out, "priv:", priv, priv_len)) + goto err; + if (pub != NULL + && !print_labeled_buf(out, "pub:", pub, pub_len)) + goto err; + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + ret = ec_param_to_text(out, group, ossl_ec_key_get_libctx(ec)); +err: + OPENSSL_clear_free(priv, priv_len); + OPENSSL_free(pub); + return ret; +} + +# define ec_input_type "EC" + +# ifndef OPENSSL_NO_SM2 +# define sm2_input_type "SM2" +# endif +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_EC +static int ecx_to_text(BIO *out, const void *key, int selection) +{ + const ECX_KEY *ecx = key; + const char *type_label = NULL; + + if (out == NULL || ecx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + if (ecx->privkey == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } + + switch (ecx->type) { + case ECX_KEY_TYPE_X25519: + type_label = "X25519 Private-Key"; + break; + case ECX_KEY_TYPE_X448: + type_label = "X448 Private-Key"; + break; + case ECX_KEY_TYPE_ED25519: + type_label = "ED25519 Private-Key"; + break; + case ECX_KEY_TYPE_ED448: + type_label = "ED448 Private-Key"; + break; + } + } else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + /* ecx->pubkey is an array, not a pointer... */ + if (!ecx->haspubkey) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + + switch (ecx->type) { + case ECX_KEY_TYPE_X25519: + type_label = "X25519 Public-Key"; + break; + case ECX_KEY_TYPE_X448: + type_label = "X448 Public-Key"; + break; + case ECX_KEY_TYPE_ED25519: + type_label = "ED25519 Public-Key"; + break; + case ECX_KEY_TYPE_ED448: + type_label = "ED448 Public-Key"; + break; + } + } + + if (BIO_printf(out, "%s:\n", type_label) <= 0) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0 + && !print_labeled_buf(out, "priv:", ecx->privkey, ecx->keylen)) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0 + && !print_labeled_buf(out, "pub:", ecx->pubkey, ecx->keylen)) + return 0; + + return 1; +} + +# define ed25519_input_type "ED25519" +# define ed448_input_type "ED448" +# define x25519_input_type "X25519" +# define x448_input_type "X448" +#endif + +/* ---------------------------------------------------------------------- */ + +static int rsa_to_text(BIO *out, const void *key, int selection) +{ + const RSA *rsa = key; + const char *type_label = "RSA key"; + const char *modulus_label = NULL; + const char *exponent_label = NULL; + const BIGNUM *rsa_d = NULL, *rsa_n = NULL, *rsa_e = NULL; + STACK_OF(BIGNUM_const) *factors = NULL; + STACK_OF(BIGNUM_const) *exps = NULL; + STACK_OF(BIGNUM_const) *coeffs = NULL; + int primes; + const RSA_PSS_PARAMS_30 *pss_params = ossl_rsa_get0_pss_params_30((RSA *)rsa); + int ret = 0; + + if (out == NULL || rsa == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + + factors = sk_BIGNUM_const_new_null(); + exps = sk_BIGNUM_const_new_null(); + coeffs = sk_BIGNUM_const_new_null(); + + if (factors == NULL || exps == NULL || coeffs == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + type_label = "Private-Key"; + modulus_label = "modulus:"; + exponent_label = "publicExponent:"; + } else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + type_label = "Public-Key"; + modulus_label = "Modulus:"; + exponent_label = "Exponent:"; + } + + RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d); + ossl_rsa_get0_all_params((RSA *)rsa, factors, exps, coeffs); + primes = sk_BIGNUM_const_num(factors); + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + if (BIO_printf(out, "%s: (%d bit, %d primes)\n", + type_label, BN_num_bits(rsa_n), primes) <= 0) + goto err; + } else { + if (BIO_printf(out, "%s: (%d bit)\n", + type_label, BN_num_bits(rsa_n)) <= 0) + goto err; + } + + if (!print_labeled_bignum(out, modulus_label, rsa_n)) + goto err; + if (!print_labeled_bignum(out, exponent_label, rsa_e)) + goto err; + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + int i; + + if (!print_labeled_bignum(out, "privateExponent:", rsa_d)) + goto err; + if (!print_labeled_bignum(out, "prime1:", + sk_BIGNUM_const_value(factors, 0))) + goto err; + if (!print_labeled_bignum(out, "prime2:", + sk_BIGNUM_const_value(factors, 1))) + goto err; + if (!print_labeled_bignum(out, "exponent1:", + sk_BIGNUM_const_value(exps, 0))) + goto err; + if (!print_labeled_bignum(out, "exponent2:", + sk_BIGNUM_const_value(exps, 1))) + goto err; + if (!print_labeled_bignum(out, "coefficient:", + sk_BIGNUM_const_value(coeffs, 0))) + goto err; + for (i = 2; i < sk_BIGNUM_const_num(factors); i++) { + if (BIO_printf(out, "prime%d:", i + 1) <= 0) + goto err; + if (!print_labeled_bignum(out, NULL, + sk_BIGNUM_const_value(factors, i))) + goto err; + if (BIO_printf(out, "exponent%d:", i + 1) <= 0) + goto err; + if (!print_labeled_bignum(out, NULL, + sk_BIGNUM_const_value(exps, i))) + goto err; + if (BIO_printf(out, "coefficient%d:", i + 1) <= 0) + goto err; + if (!print_labeled_bignum(out, NULL, + sk_BIGNUM_const_value(coeffs, i - 1))) + goto err; + } + } + + if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0) { + switch (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK)) { + case RSA_FLAG_TYPE_RSA: + if (!ossl_rsa_pss_params_30_is_unrestricted(pss_params)) { + if (BIO_printf(out, "(INVALID PSS PARAMETERS)\n") <= 0) + goto err; + } + break; + case RSA_FLAG_TYPE_RSASSAPSS: + if (ossl_rsa_pss_params_30_is_unrestricted(pss_params)) { + if (BIO_printf(out, "No PSS parameter restrictions\n") <= 0) + goto err; + } else { + int hashalg_nid = ossl_rsa_pss_params_30_hashalg(pss_params); + int maskgenalg_nid = + ossl_rsa_pss_params_30_maskgenalg(pss_params); + int maskgenhashalg_nid = + ossl_rsa_pss_params_30_maskgenhashalg(pss_params); + int saltlen = ossl_rsa_pss_params_30_saltlen(pss_params); + int trailerfield = + ossl_rsa_pss_params_30_trailerfield(pss_params); + + if (BIO_printf(out, "PSS parameter restrictions:\n") <= 0) + goto err; + if (BIO_printf(out, " Hash Algorithm: %s%s\n", + ossl_rsa_oaeppss_nid2name(hashalg_nid), + (hashalg_nid == NID_sha1 + ? " (default)" : "")) <= 0) + goto err; + if (BIO_printf(out, " Mask Algorithm: %s with %s%s\n", + ossl_rsa_mgf_nid2name(maskgenalg_nid), + ossl_rsa_oaeppss_nid2name(maskgenhashalg_nid), + (maskgenalg_nid == NID_mgf1 + && maskgenhashalg_nid == NID_sha1 + ? " (default)" : "")) <= 0) + goto err; + if (BIO_printf(out, " Minimum Salt Length: %d%s\n", + saltlen, + (saltlen == 20 ? " (default)" : "")) <= 0) + goto err; + if (BIO_printf(out, " Trailer Field: 0x%x%s\n", + trailerfield, + (trailerfield == 1 ? " (default)" : "")) <= 0) + goto err; + } + break; + } + } + + ret = 1; + err: + sk_BIGNUM_const_free(factors); + sk_BIGNUM_const_free(exps); + sk_BIGNUM_const_free(coeffs); + return ret; +} + +#define rsa_input_type "RSA" +#define rsapss_input_type "RSA-PSS" + +/* ---------------------------------------------------------------------- */ + +static void *key2text_newctx(void *provctx) +{ + return provctx; +} + +static void key2text_freectx(ossl_unused void *vctx) +{ +} + +static int key2text_encode(void *vctx, const void *key, int selection, + OSSL_CORE_BIO *cout, + int (*key2text)(BIO *out, const void *key, + int selection), + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + BIO *out = ossl_bio_new_from_core_bio(vctx, cout); + int ret; + + if (out == NULL) + return 0; + + ret = key2text(out, key, selection); + BIO_free(out); + + return ret; +} + +#define MAKE_TEXT_ENCODER(impl, type) \ + static OSSL_FUNC_encoder_import_object_fn \ + impl##2text_import_object; \ + static OSSL_FUNC_encoder_free_object_fn \ + impl##2text_free_object; \ + static OSSL_FUNC_encoder_encode_fn impl##2text_encode; \ + \ + static void *impl##2text_import_object(void *ctx, int selection, \ + const OSSL_PARAM params[]) \ + { \ + return ossl_prov_import_key(ossl_##impl##_keymgmt_functions, \ + ctx, selection, params); \ + } \ + static void impl##2text_free_object(void *key) \ + { \ + ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key); \ + } \ + static int impl##2text_encode(void *vctx, 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; \ + } \ + return key2text_encode(vctx, key, selection, cout, \ + type##_to_text, cb, cbarg); \ + } \ + const OSSL_DISPATCH ossl_##impl##_to_text_encoder_functions[] = { \ + { OSSL_FUNC_ENCODER_NEWCTX, \ + (void (*)(void))key2text_newctx }, \ + { OSSL_FUNC_ENCODER_FREECTX, \ + (void (*)(void))key2text_freectx }, \ + { OSSL_FUNC_ENCODER_IMPORT_OBJECT, \ + (void (*)(void))impl##2text_import_object }, \ + { OSSL_FUNC_ENCODER_FREE_OBJECT, \ + (void (*)(void))impl##2text_free_object }, \ + { OSSL_FUNC_ENCODER_ENCODE, \ + (void (*)(void))impl##2text_encode }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_DH +MAKE_TEXT_ENCODER(dh, dh); +MAKE_TEXT_ENCODER(dhx, dh); +#endif +#ifndef OPENSSL_NO_DSA +MAKE_TEXT_ENCODER(dsa, dsa); +#endif +#ifndef OPENSSL_NO_EC +MAKE_TEXT_ENCODER(ec, ec); +# ifndef OPENSSL_NO_SM2 +MAKE_TEXT_ENCODER(sm2, ec); +# endif +MAKE_TEXT_ENCODER(ed25519, ecx); +MAKE_TEXT_ENCODER(ed448, ecx); +MAKE_TEXT_ENCODER(x25519, ecx); +MAKE_TEXT_ENCODER(x448, ecx); +#endif +MAKE_TEXT_ENCODER(rsa, rsa); +MAKE_TEXT_ENCODER(rsapss, rsa); diff --git a/providers/implementations/encode_decode/endecoder_common.c b/providers/implementations/encode_decode/endecoder_common.c new file mode 100644 index 000000000000..c4ea2f853cfc --- /dev/null +++ b/providers/implementations/encode_decode/endecoder_common.c @@ -0,0 +1,104 @@ +/* + * Copyright 2020-2022 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.h> +#include <openssl/buffer.h> +#include "internal/asn1.h" +#include "prov/bio.h" +#include "endecoder_local.h" + +OSSL_FUNC_keymgmt_new_fn * +ossl_prov_get_keymgmt_new(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_NEW) + return OSSL_FUNC_keymgmt_new(fns); + + return NULL; +} + +OSSL_FUNC_keymgmt_free_fn * +ossl_prov_get_keymgmt_free(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_FREE) + return OSSL_FUNC_keymgmt_free(fns); + + return NULL; +} + +OSSL_FUNC_keymgmt_import_fn * +ossl_prov_get_keymgmt_import(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_IMPORT) + return OSSL_FUNC_keymgmt_import(fns); + + return NULL; +} + +OSSL_FUNC_keymgmt_export_fn * +ossl_prov_get_keymgmt_export(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_EXPORT) + return OSSL_FUNC_keymgmt_export(fns); + + return NULL; +} + +void *ossl_prov_import_key(const OSSL_DISPATCH *fns, void *provctx, + int selection, const OSSL_PARAM params[]) +{ + OSSL_FUNC_keymgmt_new_fn *kmgmt_new = ossl_prov_get_keymgmt_new(fns); + OSSL_FUNC_keymgmt_free_fn *kmgmt_free = ossl_prov_get_keymgmt_free(fns); + OSSL_FUNC_keymgmt_import_fn *kmgmt_import = + ossl_prov_get_keymgmt_import(fns); + void *key = NULL; + + if (kmgmt_new != NULL && kmgmt_import != NULL && kmgmt_free != NULL) { + if ((key = kmgmt_new(provctx)) == NULL + || !kmgmt_import(key, selection, params)) { + kmgmt_free(key); + key = NULL; + } + } + return key; +} + +void ossl_prov_free_key(const OSSL_DISPATCH *fns, void *key) +{ + OSSL_FUNC_keymgmt_free_fn *kmgmt_free = ossl_prov_get_keymgmt_free(fns); + + if (kmgmt_free != NULL) + kmgmt_free(key); +} + +int ossl_read_der(PROV_CTX *provctx, OSSL_CORE_BIO *cin, unsigned char **data, + long *len) +{ + BUF_MEM *mem = NULL; + BIO *in = ossl_bio_new_from_core_bio(provctx, cin); + int ok; + + if (in == NULL) + return 0; + ok = (asn1_d2i_read_bio(in, &mem) >= 0); + if (ok) { + *data = (unsigned char *)mem->data; + *len = (long)mem->length; + OPENSSL_free(mem); + } + BIO_free(in); + return ok; +} diff --git a/providers/implementations/encode_decode/endecoder_local.h b/providers/implementations/encode_decode/endecoder_local.h new file mode 100644 index 000000000000..a65d05ffaeac --- /dev/null +++ b/providers/implementations/encode_decode/endecoder_local.h @@ -0,0 +1,28 @@ +/* + * Copyright 2020-2021 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.h> +#include <openssl/core_dispatch.h> +#include <openssl/types.h> +#include "prov/provider_ctx.h" + +OSSL_FUNC_keymgmt_new_fn *ossl_prov_get_keymgmt_new(const OSSL_DISPATCH *fns); +OSSL_FUNC_keymgmt_free_fn *ossl_prov_get_keymgmt_free(const OSSL_DISPATCH *fns); +OSSL_FUNC_keymgmt_import_fn *ossl_prov_get_keymgmt_import(const OSSL_DISPATCH *fns); +OSSL_FUNC_keymgmt_export_fn *ossl_prov_get_keymgmt_export(const OSSL_DISPATCH *fns); + +int ossl_prov_der_from_p8(unsigned char **new_der, long *new_der_len, + unsigned char *input_der, long input_der_len, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg); + +void *ossl_prov_import_key(const OSSL_DISPATCH *fns, void *provctx, + int selection, const OSSL_PARAM params[]); +void ossl_prov_free_key(const OSSL_DISPATCH *fns, void *key); +int ossl_read_der(PROV_CTX *provctx, OSSL_CORE_BIO *cin, unsigned char **data, + long *len); |
