store/loader_file.c: fix char-subscripts warning.
[openssl.git] / crypto / store / loader_file.c
index f6cb928ae3c306015ab76f1c0756732a9cfdabda..25ada817210c1baa91cf3a9389b1454580f502b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -7,8 +7,10 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include "e_os.h"
 #include <string.h>
 #include <sys/stat.h>
+#include <ctype.h>
 #include <assert.h>
 
 #include <openssl/bio.h>
@@ -29,8 +31,6 @@
 #include "internal/store_int.h"
 #include "store_locl.h"
 
-#include "e_os.h"
-
 #ifdef _WIN32
 # define stat    _stat
 #endif
@@ -236,35 +236,35 @@ static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name,
             }
 
             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;
+                OSSL_STORE_INFO *osi_pkey = NULL;
+                OSSL_STORE_INFO *osi_cert = NULL;
+                OSSL_STORE_INFO *osi_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) {
+                    && (osi_pkey = OSSL_STORE_INFO_new_PKEY(pkey)) != NULL
+                    && sk_OSSL_STORE_INFO_push(ctx, osi_pkey) != 0
+                    && (osi_cert = OSSL_STORE_INFO_new_CERT(cert)) != NULL
+                    && sk_OSSL_STORE_INFO_push(ctx, osi_cert) != 0) {
                     ok = 1;
-                    si_pkey = NULL;
-                    si_cert = NULL;
+                    osi_pkey = NULL;
+                    osi_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) {
+                        if ((osi_ca = OSSL_STORE_INFO_new_CERT(ca)) == NULL
+                            || sk_OSSL_STORE_INFO_push(ctx, osi_ca) == 0) {
                             ok = 0;
                             break;
                         }
-                        si_ca = NULL;
+                        osi_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);
+                    OSSL_STORE_INFO_free(osi_ca);
+                    OSSL_STORE_INFO_free(osi_cert);
+                    OSSL_STORE_INFO_free(osi_pkey);
                     sk_OSSL_STORE_INFO_pop_free(ctx, OSSL_STORE_INFO_free);
                     EVP_PKEY_free(pkey);
                     X509_free(cert);
@@ -713,6 +713,13 @@ struct ossl_store_loader_ctx_st {
             int end_reached;
             char *uri;
 
+            /*
+             * When a search expression is given, these are filled in.
+             * |search_name| contains the file basename to look for.
+             * The string is exactly 8 characters long.
+             */
+            char search_name[9];
+
             /*
              * The directory reading utility we have combines opening with
              * reading the first name.  To make sure we can detect the end
@@ -722,6 +729,9 @@ struct ossl_store_loader_ctx_st {
             int last_errno;
         } dir;
     } _;
+
+    /* Expected object type.  May be unspecified */
+    int expected_type;
 };
 
 static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx)
@@ -856,7 +866,7 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
         }
     } else {
         BIO *buff = NULL;
-        char peekbuf[4096];
+        char peekbuf[4096] = { 0, };
 
         if ((buff = BIO_new(BIO_f_buffer())) == NULL
             || (ctx->_.file.file = BIO_new_file(path, "rb")) == NULL) {
@@ -909,6 +919,43 @@ static int file_ctrl(OSSL_STORE_LOADER_CTX *ctx, int cmd, va_list args)
     return ret;
 }
 
+static int file_expect(OSSL_STORE_LOADER_CTX *ctx, int expected)
+{
+    ctx->expected_type = expected;
+    return 1;
+}
+
+static int file_find(OSSL_STORE_LOADER_CTX *ctx, OSSL_STORE_SEARCH *search)
+{
+    /*
+     * If ctx == NULL, the library is looking to know if this loader supports
+     * the given search type.
+     */
+
+    if (OSSL_STORE_SEARCH_get_type(search) == OSSL_STORE_SEARCH_BY_NAME) {
+        unsigned long hash = 0;
+
+        if (ctx == NULL)
+            return 1;
+
+        if (ctx->type != is_dir) {
+            OSSL_STOREerr(OSSL_STORE_F_FILE_FIND,
+                          OSSL_STORE_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES);
+            return 0;
+        }
+
+        hash = X509_NAME_hash(OSSL_STORE_SEARCH_get0_name(search));
+        BIO_snprintf(ctx->_.dir.search_name, sizeof(ctx->_.dir.search_name),
+                     "%08lx", hash);
+        return 1;
+    }
+
+    if (ctx != NULL)
+        OSSL_STOREerr(OSSL_STORE_F_FILE_FIND,
+                      OSSL_STORE_R_UNSUPPORTED_SEARCH_TYPE);
+    return 0;
+}
+
 /* Internal function to decode an already opened PEM file */
 OSSL_STORE_LOADER_CTX *ossl_store_file_attach_pem_bio_int(BIO *bp)
 {
@@ -963,8 +1010,8 @@ static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx,
                                     ui_method, ui_data);
 
             if (try_matchcount > 0) {
-                if (matching_handlers)
-                    matching_handlers[*matchcount] = handler;
+
+                matching_handlers[*matchcount] = handler;
 
                 if (handler_ctx)
                     handler->destroy_ctx(&handler_ctx);
@@ -1129,6 +1176,68 @@ static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name,
     return 1;
 }
 
+static int file_name_check(OSSL_STORE_LOADER_CTX *ctx, const char *name)
+{
+    const char *p = NULL;
+
+    /* If there are no search criteria, all names are accepted */
+    if (ctx->_.dir.search_name[0] == '\0')
+        return 1;
+
+    /* If the expected type isn't supported, no name is accepted */
+    if (ctx->expected_type != 0
+        && ctx->expected_type != OSSL_STORE_INFO_CERT
+        && ctx->expected_type != OSSL_STORE_INFO_CRL)
+        return 0;
+
+    /*
+     * First, check the basename
+     */
+    if (strncasecmp(name, ctx->_.dir.search_name,
+                    sizeof(ctx->_.dir.search_name) - 1) != 0
+        || name[sizeof(ctx->_.dir.search_name) - 1] != '.')
+        return 0;
+    p = &name[sizeof(ctx->_.dir.search_name)];
+
+    /*
+     * Then, if the expected type is a CRL, check that the extension starts
+     * with 'r'
+     */
+    if (*p == 'r') {
+        p++;
+        if (ctx->expected_type != 0
+            && ctx->expected_type != OSSL_STORE_INFO_CRL)
+            return 0;
+    } else if (ctx->expected_type == OSSL_STORE_INFO_CRL) {
+        return 0;
+    }
+
+    /*
+     * Last, check that the rest of the extension is a decimal number, at
+     * least one digit long.
+     */
+    if (!ossl_isdigit(*p))
+        return 0;
+    while (ossl_isdigit(*p))
+        p++;
+
+# ifdef __VMS
+    /*
+     * One extra step here, check for a possible generation number.
+     */
+    if (*p == ';')
+        for (p++; *p != '\0'; p++)
+            if (!ossl_isdigit(*p))
+                break;
+# endif
+
+    /*
+     * If we've reached the end of the string at this point, we've successfully
+     * found a fitting file name.
+     */
+    return *p == '\0';
+}
+
 static int file_eof(OSSL_STORE_LOADER_CTX *ctx);
 static int file_error(OSSL_STORE_LOADER_CTX *ctx);
 static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
@@ -1157,6 +1266,7 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
             }
 
             if (ctx->_.dir.last_entry[0] != '.'
+                && file_name_check(ctx, ctx->_.dir.last_entry)
                 && !file_name_to_uri(ctx, ctx->_.dir.last_entry, &newname))
                 return NULL;
 
@@ -1182,6 +1292,7 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
     } else {
         int matchcount = -1;
 
+     again:
         result = file_load_try_repeat(ctx, ui_method, ui_data);
         if (result != NULL)
             return result;
@@ -1252,6 +1363,13 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
         /* We bail out on ambiguity */
         if (matchcount > 1)
             return NULL;
+
+        if (result != NULL
+            && ctx->expected_type != 0
+            && ctx->expected_type != OSSL_STORE_INFO_get_type(result)) {
+            OSSL_STORE_INFO_free(result);
+            goto again;
+        }
     }
 
     return result;
@@ -1296,6 +1414,8 @@ static OSSL_STORE_LOADER file_loader =
         NULL,
         file_open,
         file_ctrl,
+        file_expect,
+        file_find,
         file_load,
         file_eof,
         file_error,