STORE 'file' scheme loader: add support for the PKCS#12 container
authorRichard Levitte <levitte@openssl.org>
Sat, 11 Feb 2017 00:16:07 +0000 (01:16 +0100)
committerRichard Levitte <levitte@openssl.org>
Thu, 29 Jun 2017 09:55:31 +0000 (11:55 +0200)
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3542)

crypto/err/openssl.txt
crypto/store/loader_file.c
crypto/store/store_err.c
include/openssl/storeerr.h

index a00def173dcd057111474173b2bd45770b4da2b4..e03432cb29a9dfedf2bf13e6ee746b0a5fdfcd15 100644 (file)
@@ -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
index 3a566c328913e8aef21fb89905df45cb06f432d4..558980a591394091145c4b0a155eed33ebbb3619 100644 (file)
@@ -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,
index d3dd382aef82682895843118774f82c789c4bdf6..ab8439cfeba8454b70c051a9d1a27c375bd0b8a3 100644 (file)
@@ -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),
index 7782a6f7172c3adcd1ea710521973f6f49230c00..1458574caa42d1e6d3a39ca7ab4c71a53a39a322 100644 (file)
@@ -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