From a09003ea22fd99511cc0153314c8751a84d95496 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Sat, 11 Feb 2017 01:16:07 +0100 Subject: [PATCH] STORE 'file' scheme loader: add support for the PKCS#12 container Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/3542) --- crypto/err/openssl.txt | 3 + crypto/store/loader_file.c | 116 +++++++++++++++++++++++++++++++++++++ crypto/store/store_err.c | 6 ++ include/openssl/storeerr.h | 3 + 4 files changed, 128 insertions(+) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index a00def173d..e03432cb29 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -750,6 +750,7 @@ OSSL_STORE_F_OSSL_STORE_REGISTER_LOADER_INT:117:ossl_store_register_loader_int OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT:116:\ ossl_store_unregister_loader_int OSSL_STORE_F_TRY_DECODE_PARAMS:121:try_decode_params +OSSL_STORE_F_TRY_DECODE_PKCS12:122:try_decode_PKCS12 PEM_F_B2I_DSS:127:b2i_dss PEM_F_B2I_PVK_BIO:128:b2i_PVK_bio PEM_F_B2I_RSA:129:b2i_rsa @@ -1977,6 +1978,7 @@ OCSP_R_UNKNOWN_MESSAGE_DIGEST:119:unknown message digest OCSP_R_UNKNOWN_NID:120:unknown nid OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE:129:unsupported requestorname type OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type +OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC:113:error verifying pkcs12 mac OSSL_STORE_R_INVALID_SCHEME:106:invalid scheme OSSL_STORE_R_IS_NOT_A:112:is not a OSSL_STORE_R_NOT_A_CERTIFICATE:100:not a certificate @@ -1984,6 +1986,7 @@ OSSL_STORE_R_NOT_A_CRL:101:not a crl OSSL_STORE_R_NOT_A_KEY:102:not a key OSSL_STORE_R_NOT_A_NAME:103:not a name OSSL_STORE_R_NOT_PARAMETERS:104:not parameters +OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR:114:passphrase callback error OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE:108:path must be absolute OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED:109:\ ui process interrupted or cancelled diff --git a/crypto/store/loader_file.c b/crypto/store/loader_file.c index 3a566c3289..558980a591 100644 --- a/crypto/store/loader_file.c +++ b/crypto/store/loader_file.c @@ -157,6 +157,121 @@ typedef struct file_handler_st { int repeatable; } FILE_HANDLER; +static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name, + const char *pem_header, + const unsigned char *blob, + size_t len, void **pctx, + const UI_METHOD *ui_method, + void *ui_data) +{ + OSSL_STORE_INFO *store_info = NULL; + STACK_OF(OSSL_STORE_INFO) *ctx = *pctx; + + if (ctx == NULL) { + /* Initial parsing */ + PKCS12 *p12; + int ok = 0; + + if (pem_name != NULL) + /* No match, there is no PEM PKCS12 tag */ + return NULL; + + if ((p12 = d2i_PKCS12(NULL, &blob, len)) != NULL) { + char *pass = NULL; + char tpass[PEM_BUFSIZE]; + EVP_PKEY *pkey = NULL; + X509 *cert = NULL; + STACK_OF(X509) *chain = NULL; + + if (PKCS12_verify_mac(p12, "", 0) + || PKCS12_verify_mac(p12, NULL, 0)) { + pass = ""; + } else { + if ((pass = file_get_pass(ui_method, tpass, PEM_BUFSIZE, + "PKCS12 import password", + ui_data)) == NULL) { + OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS12, + OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR); + goto p12_end; + } + if (!PKCS12_verify_mac(p12, pass, strlen(pass))) { + OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS12, + OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC); + goto p12_end; + } + } + + if (PKCS12_parse(p12, pass, &pkey, &cert, &chain)) { + OSSL_STORE_INFO *si_pkey = NULL; + OSSL_STORE_INFO *si_cert = NULL; + OSSL_STORE_INFO *si_ca = NULL; + + if ((ctx = sk_OSSL_STORE_INFO_new_null()) != NULL + && (si_pkey = OSSL_STORE_INFO_new_PKEY(pkey)) != NULL + && sk_OSSL_STORE_INFO_push(ctx, si_pkey) != 0 + && (si_cert = OSSL_STORE_INFO_new_CERT(cert)) != NULL + && sk_OSSL_STORE_INFO_push(ctx, si_cert) != 0) { + ok = 1; + si_pkey = NULL; + si_cert = NULL; + + while(sk_X509_num(chain) > 0) { + X509 *ca = sk_X509_value(chain, 0); + + if ((si_ca = OSSL_STORE_INFO_new_CERT(ca)) == NULL + || sk_OSSL_STORE_INFO_push(ctx, si_ca) == 0) { + ok = 0; + break; + } + si_ca = NULL; + (void)sk_X509_shift(chain); + } + } + if (!ok) { + OSSL_STORE_INFO_free(si_ca); + OSSL_STORE_INFO_free(si_cert); + OSSL_STORE_INFO_free(si_pkey); + sk_OSSL_STORE_INFO_pop_free(ctx, OSSL_STORE_INFO_free); + EVP_PKEY_free(pkey); + X509_free(cert); + sk_X509_pop_free(chain, X509_free); + ctx = NULL; + } + *pctx = ctx; + } + } + p12_end: + PKCS12_free(p12); + if (!ok) + return NULL; + } + + if (ctx != NULL) + store_info = sk_OSSL_STORE_INFO_shift(ctx); + + return store_info; +} +static int eof_PKCS12(void *ctx_) +{ + STACK_OF(OSSL_STORE_INFO) *ctx = ctx_; + + return ctx == NULL || sk_OSSL_STORE_INFO_num(ctx) == 0; +} +static void destroy_ctx_PKCS12(void **pctx) +{ + STACK_OF(OSSL_STORE_INFO) *ctx = *pctx; + + sk_OSSL_STORE_INFO_pop_free(ctx, OSSL_STORE_INFO_free); + *pctx = NULL; +} +static FILE_HANDLER PKCS12_handler = { + "PKCS12", + try_decode_PKCS12, + eof_PKCS12, + destroy_ctx_PKCS12, + 1 /* repeatable */ +}; + int pem_check_suffix(const char *pem_str, const char *suffix); static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name, const char *pem_header, @@ -352,6 +467,7 @@ static FILE_HANDLER X509CRL_handler = { }; static const FILE_HANDLER *file_handlers[] = { + &PKCS12_handler, &X509Certificate_handler, &X509CRL_handler, ¶ms_handler, diff --git a/crypto/store/store_err.c b/crypto/store/store_err.c index d3dd382aef..ab8439cfeb 100644 --- a/crypto/store/store_err.c +++ b/crypto/store/store_err.c @@ -57,12 +57,16 @@ static const ERR_STRING_DATA OSSL_STORE_str_functs[] = { "ossl_store_unregister_loader_int"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_TRY_DECODE_PARAMS, 0), "try_decode_params"}, + {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_TRY_DECODE_PKCS12, 0), + "try_decode_PKCS12"}, {0, NULL} }; static const ERR_STRING_DATA OSSL_STORE_str_reasons[] = { {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE), "ambiguous content type"}, + {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC), + "error verifying pkcs12 mac"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_INVALID_SCHEME), "invalid scheme"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_IS_NOT_A), "is not a"}, @@ -73,6 +77,8 @@ static const ERR_STRING_DATA OSSL_STORE_str_reasons[] = { {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_NAME), "not a name"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_PARAMETERS), "not parameters"}, + {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR), + "passphrase callback error"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE), "path must be absolute"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED), diff --git a/include/openssl/storeerr.h b/include/openssl/storeerr.h index 7782a6f717..1458574caa 100644 --- a/include/openssl/storeerr.h +++ b/include/openssl/storeerr.h @@ -45,11 +45,13 @@ int ERR_load_OSSL_STORE_strings(void); # define OSSL_STORE_F_OSSL_STORE_REGISTER_LOADER_INT 117 # define OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT 116 # define OSSL_STORE_F_TRY_DECODE_PARAMS 121 +# define OSSL_STORE_F_TRY_DECODE_PKCS12 122 /* * OSSL_STORE reason codes. */ # define OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE 107 +# define OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC 113 # define OSSL_STORE_R_INVALID_SCHEME 106 # define OSSL_STORE_R_IS_NOT_A 112 # define OSSL_STORE_R_NOT_A_CERTIFICATE 100 @@ -57,6 +59,7 @@ int ERR_load_OSSL_STORE_strings(void); # define OSSL_STORE_R_NOT_A_KEY 102 # define OSSL_STORE_R_NOT_A_NAME 103 # define OSSL_STORE_R_NOT_PARAMETERS 104 +# define OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR 114 # define OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE 108 # define OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED 109 # define OSSL_STORE_R_UNREGISTERED_SCHEME 105 -- GitLab