summaryrefslogtreecommitdiffstats
path: root/crypto/store
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2017-02-11 01:16:07 +0100
committerRichard Levitte <levitte@openssl.org>2017-06-29 11:55:31 +0200
commita09003ea22fd99511cc0153314c8751a84d95496 (patch)
tree2e078852c2ba40927e36f1f7bf84c79d9a62af99 /crypto/store
parente61ec2d9babf30da3a4d94554e576bf10c1fc92c (diff)
STORE 'file' scheme loader: add support for the PKCS#12 container
Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/3542)
Diffstat (limited to 'crypto/store')
-rw-r--r--crypto/store/loader_file.c116
-rw-r--r--crypto/store/store_err.c6
2 files changed, 122 insertions, 0 deletions
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,
&params_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),