X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fstore%2Floader_file.c;h=25ada817210c1baa91cf3a9389b1454580f502b7;hp=f6cb928ae3c306015ab76f1c0756732a9cfdabda;hb=fa339c69a6441ab79623c73f637e25018c735b49;hpb=a1df06b36347a31c17d09e6ca3e1464bdf7eb4d5 diff --git a/crypto/store/loader_file.c b/crypto/store/loader_file.c index f6cb928ae3..25ada81721 100644 --- a/crypto/store/loader_file.c +++ b/crypto/store/loader_file.c @@ -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 #include +#include #include #include @@ -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,