/*
- * 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
* 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>
#include <openssl/ui.h>
#include <openssl/x509.h> /* For the PKCS8 stuff o.O */
#include "internal/asn1_int.h"
+#include "internal/ctype.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
+#ifndef S_ISDIR
+# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR)
+#endif
+
/*-
* Password prompting
* ------------------
}
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);
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
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)
#ifdef _WIN32
/* Windows file: URIs with a drive letter start with a / */
if (p[0] == '/' && p[2] == ':' && p[3] == '/') {
- p++;
- /* We know it's absolute, so no need to check */
- path_data[path_data_n].check_absolute = 0;
+ char c = ossl_tolower(p[1]);
+
+ if (c >= 'a' && c <= 'z') {
+ p++;
+ /* We know it's absolute, so no need to check */
+ path_data[path_data_n].check_absolute = 0;
+ }
}
#endif
path_data[path_data_n++].path = p;
return NULL;
}
- if ((st.st_mode & S_IFDIR) == S_IFDIR) {
+ if (S_ISDIR(st.st_mode)) {
/*
* Try to copy everything, even if we know that some of them must be
* NULL for the moment. This prevents errors in the future, when more
}
} 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) {
}
ctx->_.file.file = BIO_push(buff, ctx->_.file.file);
- if (BIO_buffer_peek(ctx->_.file.file, peekbuf, sizeof(peekbuf)-1) > 0) {
- peekbuf[sizeof(peekbuf)-1] = '\0';
+ if (BIO_buffer_peek(ctx->_.file.file, peekbuf, sizeof(peekbuf) - 1) > 0) {
+ peekbuf[sizeof(peekbuf) - 1] = '\0';
if (strstr(peekbuf, "-----BEGIN ") != NULL)
ctx->type = is_pem;
}
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)
{
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);
return result;
}
-static void pem_free_flag(void *pem_data, int secure)
+static void pem_free_flag(void *pem_data, int secure, size_t num)
{
if (secure)
- OPENSSL_secure_free(pem_data);
+ OPENSSL_secure_clear_free(pem_data, num);
else
OPENSSL_free(pem_data);
}
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,
}
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;
} else {
int matchcount = -1;
+ again:
result = file_load_try_repeat(ctx, ui_method, ui_data);
if (result != NULL)
return result;
ctx->errcnt++;
endloop:
- pem_free_flag(pem_name, (ctx->flags & FILE_FLAG_SECMEM) != 0);
- pem_free_flag(pem_header, (ctx->flags & FILE_FLAG_SECMEM) != 0);
- pem_free_flag(data, (ctx->flags & FILE_FLAG_SECMEM) != 0);
+ pem_free_flag(pem_name, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0);
+ pem_free_flag(pem_header, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0);
+ pem_free_flag(data, (ctx->flags & FILE_FLAG_SECMEM) != 0, len);
} while (matchcount == 0 && !file_eof(ctx) && !file_error(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;
NULL,
file_open,
file_ctrl,
+ file_expect,
+ file_find,
file_load,
file_eof,
file_error,