diff options
author | Richard Levitte <levitte@openssl.org> | 2020-07-20 10:46:49 +0200 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2020-07-24 16:47:20 +0200 |
commit | 436623f89f01a40c12327a67af0885a6219338b4 (patch) | |
tree | 9f18e2b8d1893bdf1e9d24dbeb190bc66d3a55fd | |
parent | 3ecbea6a0999cdd7caaac2871e1d198294dc494a (diff) |
PROV: Update the PEM to DER deserializer to handle encrypted legacy PEM
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12410)
-rw-r--r-- | providers/implementations/serializers/deserialize_pem2der.c | 107 |
1 files changed, 93 insertions, 14 deletions
diff --git a/providers/implementations/serializers/deserialize_pem2der.c b/providers/implementations/serializers/deserialize_pem2der.c index 53dd317bf4..490f041703 100644 --- a/providers/implementations/serializers/deserialize_pem2der.c +++ b/providers/implementations/serializers/deserialize_pem2der.c @@ -13,13 +13,17 @@ */ #include "internal/deprecated.h" +#include <string.h> + #include <openssl/core_dispatch.h> #include <openssl/core_names.h> #include <openssl/crypto.h> +#include <openssl/err.h> #include <openssl/params.h> #include <openssl/pem.h> #include "prov/bio.h" -#include "prov/implementations.h" +#include "prov/bio.h" +#include "prov/providercommonerr.h" #include "serializer_local.h" static OSSL_FUNC_deserializer_newctx_fn pem2der_newctx; @@ -28,13 +32,42 @@ static OSSL_FUNC_deserializer_gettable_params_fn pem2der_gettable_params; static OSSL_FUNC_deserializer_get_params_fn pem2der_get_params; static OSSL_FUNC_deserializer_deserialize_fn pem2der_deserialize; +/* + * Context used for PEM to DER deserialization. + */ +struct pem2der_ctx_st { + PROV_CTX *provctx; + + /* Set to 1 if intending to encrypt/decrypt, otherwise 0 */ + int cipher_intent; + + EVP_CIPHER *cipher; + + /* Passphrase that was passed by the caller */ + void *cipher_pass; + size_t cipher_pass_length; + + /* This callback is only used if |cipher_pass| is NULL */ + OSSL_PASSPHRASE_CALLBACK *cb; + void *cbarg; +}; + static void *pem2der_newctx(void *provctx) { - return 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; + + EVP_CIPHER_free(ctx->cipher); + OPENSSL_clear_free(ctx->cipher_pass, ctx->cipher_pass_length); + OPENSSL_free(ctx); } static const OSSL_PARAM *pem2der_gettable_params(void) @@ -58,39 +91,79 @@ static int pem2der_get_params(OSSL_PARAM params[]) return 1; } +static const OSSL_PARAM *pem2der_settable_ctx_params(void) +{ + static const OSSL_PARAM settables[] = { + OSSL_PARAM_octet_string(OSSL_DESERIALIZER_PARAM_PASS, NULL, 0), + OSSL_PARAM_END, + }; + + return settables; +} + +static int pem2der_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct pem2der_ctx_st *ctx = vctx; + const OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_DESERIALIZER_PARAM_PASS)) + != NULL) { + OPENSSL_clear_free(ctx->cipher_pass, ctx->cipher_pass_length); + ctx->cipher_pass = NULL; + if (!OSSL_PARAM_get_octet_string(p, &ctx->cipher_pass, 0, + &ctx->cipher_pass_length)) + return 0; + } + return 1; +} + +/* pem_password_cb compatible function */ +static int pem2der_pass_helper(char *buf, int num, int w, void *data) +{ + struct pem2der_ctx_st *ctx = data; + size_t plen; + + if (ctx->cipher_pass != NULL) { + if (ctx->cipher_pass_length < (size_t)num - 1) { + strncpy(buf, ctx->cipher_pass, ctx->cipher_pass_length); + buf[ctx->cipher_pass_length] = '\0'; + } else { + OPENSSL_strlcpy(buf, ctx->cipher_pass, num); + } + } else if (ctx->cb == NULL + || !ctx->cb(buf, num, &plen, NULL, ctx->cbarg)) { + return -1; + } + return (int)ctx->cipher_pass_length; +} + static int pem2der_deserialize(void *vctx, OSSL_CORE_BIO *cin, OSSL_CALLBACK *data_cb, void *data_cbarg, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) { - PROV_CTX *ctx = vctx; + struct pem2der_ctx_st *ctx = vctx; char *pem_name = NULL, *pem_header = NULL; unsigned char *der = NULL; long der_len = 0; int ok = 0; - if (ossl_prov_read_pem(ctx, cin, &pem_name, &pem_header, + if (ossl_prov_read_pem(ctx->provctx, cin, &pem_name, &pem_header, &der, &der_len) <= 0) return 0; -#if 0 /* PEM decryption coming soon */ /* * 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) { + if (strlen(pem_header) > 10) { EVP_CIPHER_INFO cipher; - struct pem_pass_data pass_data; - if (!PEM_get_EVP_CIPHER_INFO(*pem_header, &cipher) - || !file_fill_pem_pass_data(&pass_data, "PEM pass phrase", uri, - ui_method, ui_data) - || !PEM_do_header(&cipher, *data, len, file_get_pem_pass, - &pass_data)) + if (!PEM_get_EVP_CIPHER_INFO(pem_header, &cipher) + || !PEM_do_header(&cipher, der, &der_len, pem2der_pass_helper, ctx)) goto end; } -#endif { OSSL_PARAM params[3]; @@ -106,6 +179,7 @@ static int pem2der_deserialize(void *vctx, OSSL_CORE_BIO *cin, ok = data_cb(params, data_cbarg); } + end: OPENSSL_free(pem_name); OPENSSL_free(pem_header); OPENSSL_free(der); @@ -117,7 +191,12 @@ const OSSL_DISPATCH pem_to_der_deserializer_functions[] = { { OSSL_FUNC_DESERIALIZER_FREECTX, (void (*)(void))pem2der_freectx }, { OSSL_FUNC_DESERIALIZER_GETTABLE_PARAMS, (void (*)(void))pem2der_gettable_params }, - { OSSL_FUNC_DESERIALIZER_GET_PARAMS, (void (*)(void))pem2der_get_params }, + { OSSL_FUNC_DESERIALIZER_GET_PARAMS, + (void (*)(void))pem2der_get_params }, + { OSSL_FUNC_DESERIALIZER_SETTABLE_CTX_PARAMS, + (void (*)(void))pem2der_settable_ctx_params }, + { OSSL_FUNC_DESERIALIZER_SET_CTX_PARAMS, + (void (*)(void))pem2der_set_ctx_params }, { OSSL_FUNC_DESERIALIZER_DESERIALIZE, (void (*)(void))pem2der_deserialize }, { 0, NULL } }; |