For Windows, use _stat rather than stat
[openssl.git] / crypto / store / loader_file.c
index 8c8b81eb74a3cc7743501267bce47154e08caf6e..06094bf2746e73be2ff0bb82e96314c8531677ce 100644 (file)
 #include "internal/asn1_int.h"
 #include "internal/o_dir.h"
 #include "internal/cryptlib.h"
+#include "internal/store_int.h"
 #include "store_locl.h"
 
 #include "e_os.h"
 
-/*
+#ifdef _WIN32
+# define stat    _stat
+#endif
+
+/*-
  *  Password prompting
+ *  ------------------
  */
 
 static char *file_get_pass(const UI_METHOD *ui_method, char *pass,
@@ -82,6 +88,7 @@ struct pem_pass_data {
     void *data;
     const char *prompt_info;
 };
+
 static int file_fill_pem_pass_data(struct pem_pass_data *pass_data,
                                    const char *prompt_info,
                                    const UI_METHOD *ui_method, void *ui_data)
@@ -93,6 +100,8 @@ static int file_fill_pem_pass_data(struct pem_pass_data *pass_data,
     pass_data->prompt_info = prompt_info;
     return 1;
 }
+
+/* This is used anywhere a pem_password_cb is needed */
 static int file_get_pem_pass(char *buf, int num, int w, void *data)
 {
     struct pem_pass_data *pass_data = data;
@@ -102,8 +111,14 @@ static int file_get_pem_pass(char *buf, int num, int w, void *data)
     return pass == NULL ? 0 : strlen(pass);
 }
 
-/*
- *  The file scheme handlers
+/*-
+ *  The file scheme decoders
+ *  ------------------------
+ *
+ *  Each possible data type has its own decoder, which either operates
+ *  through a given PEM name, or attempts to decode to see if the blob
+ *  it's given is decodable for its data type.  The assumption is that
+ *  only the correct data type will match the content.
  */
 
 /*-
@@ -167,6 +182,11 @@ typedef struct file_handler_st {
     int repeatable;
 } FILE_HANDLER;
 
+/*
+ * PKCS#12 decoder.  It operates by decoding all of the blob content,
+ * extracting all the interesting data from it and storing them internally,
+ * then serving them one piece at a time.
+ */
 static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name,
                                           const char *pem_header,
                                           const unsigned char *blob,
@@ -266,12 +286,14 @@ static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name,
 
     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;
@@ -279,6 +301,7 @@ static void destroy_ctx_PKCS12(void **pctx)
     sk_OSSL_STORE_INFO_pop_free(ctx, OSSL_STORE_INFO_free);
     *pctx = NULL;
 }
+
 static FILE_HANDLER PKCS12_handler = {
     "PKCS12",
     try_decode_PKCS12,
@@ -287,6 +310,11 @@ static FILE_HANDLER PKCS12_handler = {
     1                            /* repeatable */
 };
 
+/*
+ * Encrypted PKCS#8 decoder.  It operates by just decrypting the given blob
+ * into a new blob, which is returned as an EMBEDDED STORE_INFO.  The whole
+ * decoding process will then start over with the new blob.
+ */
 static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name,
                                                   const char *pem_header,
                                                   const unsigned char *blob,
@@ -351,11 +379,17 @@ static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name,
     BUF_MEM_free(mem);
     return NULL;
 }
+
 static FILE_HANDLER PKCS8Encrypted_handler = {
     "PKCS8Encrypted",
     try_decode_PKCS8Encrypted
 };
 
+/*
+ * Private key decoder.  Decodes all sorts of private keys, both PKCS#8
+ * encoded ones and old style PEM ones (with the key type is encoded into
+ * the PEM name).
+ */
 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,
@@ -424,11 +458,15 @@ static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name,
 
     return store_info;
 }
+
 static FILE_HANDLER PrivateKey_handler = {
     "PrivateKey",
     try_decode_PrivateKey
 };
 
+/*
+ * Public key decoder.  Only supports SubjectPublicKeyInfo formated keys.
+ */
 static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name,
                                           const char *pem_header,
                                           const unsigned char *blob,
@@ -454,11 +492,15 @@ static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name,
 
     return store_info;
 }
+
 static FILE_HANDLER PUBKEY_handler = {
     "PUBKEY",
     try_decode_PUBKEY
 };
 
+/*
+ * Key parameter decoder.
+ */
 static OSSL_STORE_INFO *try_decode_params(const char *pem_name,
                                           const char *pem_header,
                                           const unsigned char *blob,
@@ -479,12 +521,13 @@ static OSSL_STORE_INFO *try_decode_params(const char *pem_name,
         *matchcount = 1;
     }
 
-    if ((pkey = EVP_PKEY_new()) == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PARAMS, ERR_R_EVP_LIB);
-        return NULL;
-    }
-
     if (slen > 0) {
+        if ((pkey = EVP_PKEY_new()) == NULL) {
+            OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PARAMS, ERR_R_EVP_LIB);
+            return NULL;
+        }
+
+
         if (EVP_PKEY_set_type_str(pkey, pem_name, slen)
             && (ameth = EVP_PKEY_get0_asn1(pkey)) != NULL
             && ameth->param_decode != NULL
@@ -492,22 +535,37 @@ static OSSL_STORE_INFO *try_decode_params(const char *pem_name,
             ok = 1;
     } else {
         int i;
+        EVP_PKEY *tmp_pkey = NULL;
 
         for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {
             const unsigned char *tmp_blob = blob;
 
+            if (tmp_pkey == NULL && (tmp_pkey = EVP_PKEY_new()) == NULL) {
+                OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PARAMS, ERR_R_EVP_LIB);
+                break;
+            }
+
             ameth = EVP_PKEY_asn1_get0(i);
             if (ameth->pkey_flags & ASN1_PKEY_ALIAS)
                 continue;
-            if (EVP_PKEY_set_type(pkey, ameth->pkey_id)
-                && (ameth = EVP_PKEY_get0_asn1(pkey)) != NULL
+
+            if (EVP_PKEY_set_type(tmp_pkey, ameth->pkey_id)
+                && (ameth = EVP_PKEY_get0_asn1(tmp_pkey)) != NULL
                 && ameth->param_decode != NULL
-                && ameth->param_decode(pkey, &tmp_blob, len)) {
+                && ameth->param_decode(tmp_pkey, &tmp_blob, len)) {
+                if (pkey != NULL)
+                    EVP_PKEY_free(tmp_pkey);
+                else
+                    pkey = tmp_pkey;
+                tmp_pkey = NULL;
                 (*matchcount)++;
-                ok = 1;
-                break;
             }
         }
+
+        EVP_PKEY_free(tmp_pkey);
+        if (*matchcount == 1) {
+            ok = 1;
+        }
     }
 
     if (ok)
@@ -517,11 +575,15 @@ static OSSL_STORE_INFO *try_decode_params(const char *pem_name,
 
     return store_info;
 }
+
 static FILE_HANDLER params_handler = {
     "params",
     try_decode_params
 };
 
+/*
+ * X.509 certificate decoder.
+ */
 static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name,
                                                    const char *pem_header,
                                                    const unsigned char *blob,
@@ -563,11 +625,15 @@ static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name,
 
     return store_info;
 }
+
 static FILE_HANDLER X509Certificate_handler = {
     "X509Certificate",
     try_decode_X509Certificate
 };
 
+/*
+ * X.509 CRL decoder.
+ */
 static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name,
                                            const char *pem_header,
                                            const unsigned char *blob,
@@ -596,11 +662,15 @@ static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name,
 
     return store_info;
 }
+
 static FILE_HANDLER X509CRL_handler = {
     "X509CRL",
     try_decode_X509CRL
 };
 
+/*
+ * To finish it all off, we collect all the handlers.
+ */
 static const FILE_HANDLER *file_handlers[] = {
     &PKCS12_handler,
     &PKCS8Encrypted_handler,
@@ -612,8 +682,9 @@ static const FILE_HANDLER *file_handlers[] = {
 };
 
 
-/*
+/*-
  *  The loader itself
+ *  -----------------
  */
 
 struct ossl_store_loader_ctx_st {
@@ -676,7 +747,7 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
     const char *path = NULL;
 
     if (strncasecmp(uri, "file:", 5) == 0) {
-        if (strncmp(&uri[5], "//localhost/", 12) == 0) {
+        if (strncasecmp(&uri[5], "//localhost/", 12) == 0) {
             path = &uri[16];
         } else if (strncmp(&uri[5], "///", 3) == 0) {
             path = &uri[7];
@@ -800,6 +871,23 @@ static int file_ctrl(OSSL_STORE_LOADER_CTX *ctx, int cmd, va_list args)
     return ret;
 }
 
+/* Internal function to decode an already opened PEM file */
+OSSL_STORE_LOADER_CTX *ossl_store_file_attach_pem_bio_int(BIO *bp)
+{
+    OSSL_STORE_LOADER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+    if (ctx == NULL) {
+        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_FILE_ATTACH_PEM_BIO_INT,
+                      ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    ctx->_.file.file = bp;
+    ctx->type = is_pem;
+
+    return ctx;
+}
+
 static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx,
                                              const char *pem_name,
                                              const char *pem_header,
@@ -1158,6 +1246,12 @@ static int file_close(OSSL_STORE_LOADER_CTX *ctx)
     return 1;
 }
 
+int ossl_store_file_detach_pem_bio_int(OSSL_STORE_LOADER_CTX *ctx)
+{
+    OSSL_STORE_LOADER_CTX_free(ctx);
+    return 1;
+}
+
 static OSSL_STORE_LOADER file_loader =
     {
         "file",