X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fstore%2Floader_file.c;h=f253c06e5df96b301c2585fdb00c01977db49b2c;hp=7232b9858a18318462740749ee643d2d53e88ad8;hb=8755b085244c792bc8a78b38984b0f4061bc9f91;hpb=6541d9e2646d693b3879ce438a2e9b8d290907fc diff --git a/crypto/store/loader_file.c b/crypto/store/loader_file.c index 7232b9858a..f253c06e5d 100644 --- a/crypto/store/loader_file.c +++ b/crypto/store/loader_file.c @@ -1,7 +1,7 @@ /* * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -10,6 +10,7 @@ #include "e_os.h" #include #include +#include #include #include @@ -23,17 +24,22 @@ #include #include #include /* For the PKCS8 stuff o.O */ -#include "internal/asn1_int.h" -#include "internal/ctype.h" +#include "crypto/asn1.h" +#include "crypto/ctype.h" #include "internal/o_dir.h" #include "internal/cryptlib.h" -#include "internal/store_int.h" -#include "store_locl.h" +#include "crypto/store.h" +#include "crypto/evp.h" +#include "store_local.h" #ifdef _WIN32 # define stat _stat #endif +#ifndef S_ISDIR +# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) +#endif + /*- * Password prompting * ------------------ @@ -149,6 +155,8 @@ static int file_get_pem_pass(char *buf, int num, int w, void *data) * or any other interactive data. * ui_data: Application data to be passed to ui_method when * it's called. + * libctx: The library context to be used if applicable + * propq: The property query string for any algorithm fetches * Output: * a OSSL_STORE_INFO */ @@ -158,7 +166,9 @@ typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name, size_t len, void **handler_ctx, int *matchcount, const UI_METHOD *ui_method, - void *ui_data); + void *ui_data, + OPENSSL_CTX *libctx, + const char *propq); /* * The eof function should return 1 if there's no more data to be found * with the handler_ctx, otherwise 0. This is only used when the handler is @@ -167,7 +177,7 @@ typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name, typedef int (*file_eof_fn)(void *handler_ctx); /* * The destroy_ctx function is used to destroy the handler_ctx that was - * intiated by a repeatable try_decode fuction. This is only used when + * initiated by a repeatable try_decode function. This is only used when * the handler is marked repeatable. */ typedef void (*file_destroy_ctx_fn)(void **handler_ctx); @@ -193,7 +203,8 @@ static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name, size_t len, void **pctx, int *matchcount, const UI_METHOD *ui_method, - void *ui_data) + void *ui_data, OPENSSL_CTX *libctx, + const char *propq) { OSSL_STORE_INFO *store_info = NULL; STACK_OF(OSSL_STORE_INFO) *ctx = *pctx; @@ -235,35 +246,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); @@ -321,7 +332,9 @@ static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name, size_t len, void **pctx, int *matchcount, const UI_METHOD *ui_method, - void *ui_data) + void *ui_data, + OPENSSL_CTX *libctx, + const char *propq) { X509_SIG *p8 = NULL; char kbuf[PEM_BUFSIZE]; @@ -397,7 +410,8 @@ static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name, size_t len, void **pctx, int *matchcount, const UI_METHOD *ui_method, - void *ui_data) + void *ui_data, OPENSSL_CTX *libctx, + const char *propq) { OSSL_STORE_INFO *store_info = NULL; EVP_PKEY *pkey = NULL; @@ -410,7 +424,7 @@ static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name, *matchcount = 1; if (p8inf != NULL) - pkey = EVP_PKCS82PKEY(p8inf); + pkey = evp_pkcs82pkey_int(p8inf, libctx, propq); PKCS8_PRIV_KEY_INFO_free(p8inf); } else { int slen; @@ -419,7 +433,8 @@ static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name, && (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name, slen)) != NULL) { *matchcount = 1; - pkey = d2i_PrivateKey(ameth->pkey_id, NULL, &blob, len); + pkey = d2i_PrivateKey_ex(ameth->pkey_id, NULL, &blob, len, + libctx, propq); } } } else { @@ -433,7 +448,8 @@ static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name, if (ameth->pkey_flags & ASN1_PKEY_ALIAS) continue; - tmp_pkey = d2i_PrivateKey(ameth->pkey_id, NULL, &tmp_blob, len); + tmp_pkey = d2i_PrivateKey_ex(ameth->pkey_id, NULL, &tmp_blob, len, + libctx, propq); if (tmp_pkey != NULL) { if (pkey != NULL) EVP_PKEY_free(tmp_pkey); @@ -465,7 +481,7 @@ static FILE_HANDLER PrivateKey_handler = { }; /* - * Public key decoder. Only supports SubjectPublicKeyInfo formated keys. + * Public key decoder. Only supports SubjectPublicKeyInfo formatted keys. */ static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name, const char *pem_header, @@ -473,7 +489,8 @@ static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name, size_t len, void **pctx, int *matchcount, const UI_METHOD *ui_method, - void *ui_data) + void *ui_data, OPENSSL_CTX *libctx, + const char *propq) { OSSL_STORE_INFO *store_info = NULL; EVP_PKEY *pkey = NULL; @@ -507,7 +524,8 @@ static OSSL_STORE_INFO *try_decode_params(const char *pem_name, size_t len, void **pctx, int *matchcount, const UI_METHOD *ui_method, - void *ui_data) + void *ui_data, OPENSSL_CTX *libctx, + const char *propq) { OSSL_STORE_INFO *store_info = NULL; int slen = 0; @@ -590,7 +608,9 @@ static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name, size_t len, void **pctx, int *matchcount, const UI_METHOD *ui_method, - void *ui_data) + void *ui_data, + OPENSSL_CTX *libctx, + const char *propq) { OSSL_STORE_INFO *store_info = NULL; X509 *cert = NULL; @@ -640,7 +660,8 @@ static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name, size_t len, void **pctx, int *matchcount, const UI_METHOD *ui_method, - void *ui_data) + void *ui_data, OPENSSL_CTX *libctx, + const char *propq) { OSSL_STORE_INFO *store_info = NULL; X509_CRL *crl = NULL; @@ -712,6 +733,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 @@ -724,6 +752,9 @@ struct ossl_store_loader_ctx_st { /* Expected object type. May be unspecified */ int expected_type; + + OPENSSL_CTX *libctx; + char *propq; }; static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx) @@ -737,6 +768,7 @@ static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx) ctx->_.file.last_handler = NULL; } } + OPENSSL_free(ctx->propq); OPENSSL_free(ctx); } @@ -812,8 +844,9 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, } if (stat(path_data[i].path, &st) < 0) { - SYSerr(SYS_F_STAT, errno); - ERR_add_error_data(1, path_data[i].path); + ERR_raise_data(ERR_LIB_SYS, errno, + "calling stat(%s)", + path_data[i].path); } else { path = path_data[i].path; } @@ -831,7 +864,7 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, 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 @@ -848,10 +881,10 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, if (ctx->_.dir.last_entry == NULL) { if (ctx->_.dir.last_errno != 0) { char errbuf[256]; - errno = ctx->_.dir.last_errno; - openssl_strerror_r(errno, errbuf, sizeof(errbuf)); OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_SYS_LIB); - ERR_add_error_data(1, errbuf); + errno = ctx->_.dir.last_errno; + if (openssl_strerror_r(errno, errbuf, sizeof(errbuf))) + ERR_add_error_data(1, errbuf); goto err; } ctx->_.dir.end_reached = 1; @@ -917,8 +950,42 @@ static int file_expect(OSSL_STORE_LOADER_CTX *ctx, int expected) return 1; } +static int file_find(OSSL_STORE_LOADER_CTX *ctx, + const 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) +OSSL_STORE_LOADER_CTX *ossl_store_file_attach_pem_bio_int(BIO *bp, + OPENSSL_CTX *libctx, + const char *propq) { OSSL_STORE_LOADER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); @@ -931,6 +998,17 @@ OSSL_STORE_LOADER_CTX *ossl_store_file_attach_pem_bio_int(BIO *bp) ctx->_.file.file = bp; ctx->type = is_pem; + ctx->libctx = libctx; + if (propq != NULL) { + ctx->propq = OPENSSL_strdup(propq); + if (ctx->propq == NULL) { + OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_FILE_ATTACH_PEM_BIO_INT, + ERR_R_MALLOC_FAILURE); + OPENSSL_free(ctx); + return NULL; + } + } + return ctx; } @@ -968,7 +1046,7 @@ static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx, OSSL_STORE_INFO *tmp_result = handler->try_decode(pem_name, pem_header, data, len, &tmp_handler_ctx, &try_matchcount, - ui_method, ui_data); + ui_method, ui_data, ctx->libctx, ctx->propq); if (try_matchcount > 0) { @@ -1035,7 +1113,8 @@ static OSSL_STORE_INFO *file_load_try_repeat(OSSL_STORE_LOADER_CTX *ctx, ctx->_.file.last_handler->try_decode(NULL, NULL, NULL, 0, &ctx->_.file.last_handler_ctx, &try_matchcount, - ui_method, ui_data); + ui_method, ui_data, + ctx->libctx, ctx->propq); if (result == NULL) { ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx); @@ -1137,6 +1216,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, @@ -1155,16 +1296,17 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx, if (!ctx->_.dir.end_reached) { char errbuf[256]; assert(ctx->_.dir.last_errno != 0); + OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_SYS_LIB); errno = ctx->_.dir.last_errno; ctx->errcnt++; - openssl_strerror_r(errno, errbuf, sizeof(errbuf)); - OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_SYS_LIB); - ERR_add_error_data(1, errbuf); + if (openssl_strerror_r(errno, errbuf, sizeof(errbuf))) + ERR_add_error_data(1, errbuf); } return NULL; } 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; @@ -1313,6 +1455,7 @@ static OSSL_STORE_LOADER file_loader = file_open, file_ctrl, file_expect, + file_find, file_load, file_eof, file_error,