Loading crypto/err/openssl.txt +10 −0 Original line number Diff line number Diff line Loading @@ -724,6 +724,9 @@ OCSP_F_OCSP_REQUEST_SIGN:110:OCSP_request_sign OCSP_F_OCSP_REQUEST_VERIFY:116:OCSP_request_verify OCSP_F_OCSP_RESPONSE_GET1_BASIC:111:OCSP_response_get1_basic OCSP_F_PARSE_HTTP_LINE1:118:parse_http_line1 OSSL_STORE_F_FILE_GET_PASS:118:file_get_pass OSSL_STORE_F_FILE_LOAD:119:file_load OSSL_STORE_F_FILE_OPEN:120:file_open OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT:100:ossl_store_get0_loader_int OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT:101:OSSL_STORE_INFO_get1_CERT OSSL_STORE_F_OSSL_STORE_INFO_GET1_CRL:102:OSSL_STORE_INFO_get1_CRL Loading @@ -746,6 +749,7 @@ OSSL_STORE_F_OSSL_STORE_OPEN_INT:115:* OSSL_STORE_F_OSSL_STORE_REGISTER_LOADER_INT:117:ossl_store_register_loader_int OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT:116:\ ossl_store_unregister_loader_int OSSL_STORE_F_TRY_DECODE_PARAMS:121:try_decode_params PEM_F_B2I_DSS:127:b2i_dss PEM_F_B2I_PVK_BIO:128:b2i_PVK_bio PEM_F_B2I_RSA:129:b2i_rsa Loading Loading @@ -1972,13 +1976,19 @@ OCSP_R_STATUS_TOO_OLD:127:status too old OCSP_R_UNKNOWN_MESSAGE_DIGEST:119:unknown message digest OCSP_R_UNKNOWN_NID:120:unknown nid OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE:129:unsupported requestorname type OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type OSSL_STORE_R_INVALID_SCHEME:106:invalid scheme OSSL_STORE_R_NOT_A_CERTIFICATE:100:not a certificate OSSL_STORE_R_NOT_A_CRL:101:not a crl OSSL_STORE_R_NOT_A_KEY:102:not a key OSSL_STORE_R_NOT_A_NAME:103:not a name OSSL_STORE_R_NOT_PARAMETERS:104:not parameters OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE:108:path must be absolute OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED:109:\ ui process interrupted or cancelled OSSL_STORE_R_UNREGISTERED_SCHEME:105:unregistered scheme OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE:110:unsupported content type OSSL_STORE_R_URI_AUTHORITY_UNSUPPORED:111:uri authority unsuppored PEM_R_BAD_BASE64_DECODE:100:bad base64 decode PEM_R_BAD_DECRYPT:101:bad decrypt PEM_R_BAD_END_LINE:102:bad end line Loading crypto/store/build.info +2 −1 Original line number Diff line number Diff line LIBS=../../libcrypto SOURCE[../../libcrypto]=\ store_err.c store_init.c store_lib.c store_register.c store_strings.c store_err.c store_init.c store_lib.c store_register.c store_strings.c \ loader_file.c crypto/store/loader_file.c 0 → 100644 +583 −0 Original line number Diff line number Diff line /* * Copyright 2016-2017 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 * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include <string.h> #include <openssl/bio.h> #include <openssl/dsa.h> /* For d2i_DSAPrivateKey */ #include <openssl/err.h> #include <openssl/evp.h> #include <openssl/pem.h> #include <openssl/pkcs12.h> /* For the PKCS8 stuff o.O */ #include <openssl/rsa.h> /* For d2i_RSAPrivateKey */ #include <openssl/safestack.h> #include <openssl/store.h> #include <openssl/ui.h> #include <openssl/x509.h> /* For the PKCS8 stuff o.O */ #include "internal/asn1_int.h" #include "store_locl.h" #include "e_os.h" /* * Password prompting */ static char *file_get_pass(const UI_METHOD *ui_method, char *pass, size_t maxsize, const char *prompt_info, void *data) { UI *ui = UI_new(); char *prompt = NULL; if (ui == NULL) { OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_MALLOC_FAILURE); return NULL; } if (ui_method != NULL) UI_set_method(ui, ui_method); UI_add_user_data(ui, data); if ((prompt = UI_construct_prompt(ui, "pass phrase", prompt_info)) == NULL) { OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_MALLOC_FAILURE); pass = NULL; } else if (!UI_add_input_string(ui, prompt, UI_INPUT_FLAG_DEFAULT_PWD, pass, 0, maxsize - 1)) { OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_UI_LIB); pass = NULL; } else { switch (UI_process(ui)) { case -2: OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED); pass = NULL; break; case -1: OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_UI_LIB); pass = NULL; break; default: break; } } OPENSSL_free(prompt); UI_free(ui); return pass; } struct pem_pass_data { const UI_METHOD *ui_method; 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) { if (pass_data == NULL) return 0; pass_data->ui_method = ui_method; pass_data->data = ui_data; pass_data->prompt_info = prompt_info; return 1; } static int file_get_pem_pass(char *buf, int num, int w, void *data) { struct pem_pass_data *pass_data = data; char *pass = file_get_pass(pass_data->ui_method, buf, num, pass_data->prompt_info, pass_data->data); return pass == NULL ? 0 : strlen(pass); } /* * The file scheme handlers */ /*- * The try_decode function is called to check if the blob of data can * be used by this handler, and if it can, decodes it into a supported * OpenSSL type and returns a OSSL_STORE_INFO with the decoded data. * Input: * pem_name: If this blob comes from a PEM file, this holds * the PEM name. If it comes from another type of * file, this is NULL. * pem_header: If this blob comes from a PEM file, this holds * the PEM headers. If it comes from another type of * file, this is NULL. * blob: The blob of data to match with what this handler * can use. * len: The length of the blob. * ui_method: Application UI method for getting a password, pin * or any other interactive data. * ui_data: Application data to be passed to ui_method when * it's called. * Output: * a OSSL_STORE_INFO */ typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name, const char *pem_header, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data); typedef struct file_handler_st { const char *name; file_try_decode_fn try_decode; } FILE_HANDLER; 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, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *store_info = NULL; EVP_PKEY *pkey = NULL; const EVP_PKEY_ASN1_METHOD *ameth = NULL; if (pem_name != NULL) { int slen; if ((slen = pem_check_suffix(pem_name, "PRIVATE KEY")) > 0 && (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name, slen)) != NULL) pkey = d2i_PrivateKey(ameth->pkey_id, NULL, &blob, len); } else { int i; for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { ameth = EVP_PKEY_asn1_get0(i); if (ameth->pkey_flags & ASN1_PKEY_ALIAS) continue; pkey = d2i_PrivateKey(ameth->pkey_id, NULL, &blob, len); if (pkey != NULL) break; } } if (pkey == NULL) /* No match */ return NULL; store_info = OSSL_STORE_INFO_new_PKEY(pkey); if (store_info == NULL) EVP_PKEY_free(pkey); return store_info; } static FILE_HANDLER PrivateKey_handler = { "PrivateKey", try_decode_PrivateKey }; static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name, const char *pem_header, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *store_info = NULL; EVP_PKEY *pkey = NULL; if (pem_name != NULL && strcmp(pem_name, PEM_STRING_PUBLIC) != 0) /* No match */ return NULL; if ((pkey = d2i_PUBKEY(NULL, &blob, len)) != NULL) store_info = OSSL_STORE_INFO_new_PKEY(pkey); return store_info; } static FILE_HANDLER PUBKEY_handler = { "PUBKEY", try_decode_PUBKEY }; static OSSL_STORE_INFO *try_decode_params(const char *pem_name, const char *pem_header, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *store_info = NULL; EVP_PKEY *pkey = EVP_PKEY_new(); const EVP_PKEY_ASN1_METHOD *ameth = NULL; int ok = 0; if (pkey == NULL) { OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PARAMS, ERR_R_EVP_LIB); return NULL; } if (pem_name != NULL) { int slen; if ((slen = pem_check_suffix(pem_name, "PARAMETERS")) > 0 && EVP_PKEY_set_type_str(pkey, pem_name, slen) && (ameth = EVP_PKEY_get0_asn1(pkey)) != NULL && ameth->param_decode != NULL && ameth->param_decode(pkey, &blob, len)) ok = 1; } else { int i; for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { 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 && ameth->param_decode != NULL && ameth->param_decode(pkey, &blob, len)) { ok = 1; break; } } } if (ok) store_info = OSSL_STORE_INFO_new_PARAMS(pkey); if (store_info == NULL) EVP_PKEY_free(pkey); return store_info; } static FILE_HANDLER params_handler = { "params", try_decode_params }; static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name, const char *pem_header, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *store_info = NULL; X509 *cert = NULL; /* * In most cases, we can try to interpret the serialized data as a trusted * cert (X509 + X509_AUX) and fall back to reading it as a normal cert * (just X509), but if the PEM name specifically declares it as a trusted * cert, then no fallback should be engaged. |ignore_trusted| tells if * the fallback can be used (1) or not (0). */ int ignore_trusted = 1; if (pem_name != NULL) { if (strcmp(pem_name, PEM_STRING_X509_TRUSTED) == 0) ignore_trusted = 0; else if (strcmp(pem_name, PEM_STRING_X509_OLD) != 0 && strcmp(pem_name, PEM_STRING_X509) != 0) /* No match */ return NULL; } if ((cert = d2i_X509_AUX(NULL, &blob, len)) != NULL || (ignore_trusted && (cert = d2i_X509(NULL, &blob, len)) != NULL)) store_info = OSSL_STORE_INFO_new_CERT(cert); if (store_info == NULL) X509_free(cert); return store_info; } static FILE_HANDLER X509Certificate_handler = { "X509Certificate", try_decode_X509Certificate }; static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name, const char *pem_header, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *store_info = NULL; X509_CRL *crl = NULL; if (pem_name != NULL && strcmp(pem_name, PEM_STRING_X509_CRL) != 0) /* No match */ return NULL; if ((crl = d2i_X509_CRL(NULL, &blob, len)) != NULL) store_info = OSSL_STORE_INFO_new_CRL(crl); if (store_info == NULL) X509_CRL_free(crl); return store_info; } static FILE_HANDLER X509CRL_handler = { "X509CRL", try_decode_X509CRL }; static const FILE_HANDLER *file_handlers[] = { &X509Certificate_handler, &X509CRL_handler, ¶ms_handler, &PUBKEY_handler, &PrivateKey_handler, }; /* * The loader itself */ struct ossl_store_loader_ctx_st { BIO *file; int is_pem; int errcnt; }; static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, const char *uri, const UI_METHOD *ui_method, void *ui_data) { BIO *buff = NULL; char peekbuf[4096]; OSSL_STORE_LOADER_CTX *ctx = NULL; const char *path = NULL; if (strncasecmp(uri, "file:", 5) == 0) { if (strncmp(&uri[5], "//localhost/", 12) == 0) { path = &uri[16]; } else if (strncmp(&uri[5], "///", 3) == 0) { path = &uri[7]; } else if (strncmp(&uri[5], "//", 2) != 0) { path = &uri[5]; } else { OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, OSSL_STORE_R_URI_AUTHORITY_UNSUPPORED); return NULL; } /* * If the scheme "file" was an explicit part of the URI, the path must * be absolute. So says RFC 8089 */ if (path[0] != '/') { OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE); return NULL; } #ifdef _WIN32 /* Windows file: URIs with a drive letter start with a / */ if (path[0] == '/' && path[2] == ':' && path[3] == '/') path++; #endif } else { path = uri; } ctx = OPENSSL_zalloc(sizeof(*ctx)); if (ctx == NULL) { OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE); return NULL; } if ((buff = BIO_new(BIO_f_buffer())) == NULL) goto err; if ((ctx->file = BIO_new_file(path, "rb")) == NULL) { goto err; } ctx->file = BIO_push(buff, ctx->file); if (BIO_buffer_peek(ctx->file, peekbuf, sizeof(peekbuf)-1) > 0) { peekbuf[sizeof(peekbuf)-1] = '\0'; if (strstr(peekbuf, "-----BEGIN ") != NULL) ctx->is_pem = 1; } return ctx; err: if (buff != NULL) BIO_free(buff); OPENSSL_free(ctx); return NULL; } 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, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *result = NULL; int matchcount = -1; if (file_error(ctx)) return NULL; do { char *pem_name = NULL; /* PEM record name */ char *pem_header = NULL; /* PEM record header */ unsigned char *data = NULL; /* DER encoded data */ BUF_MEM *mem = NULL; long len = 0; /* DER encoded data length */ int r = 0; size_t i = 0; file_try_decode_fn *matching_functions = NULL; matchcount = -1; if (ctx->is_pem) { r = PEM_read_bio(ctx->file, &pem_name, &pem_header, &data, &len); if (r <= 0) { if (!file_eof(ctx)) ctx->errcnt++; goto end; } /* * 10 is the number of characters in "Proc-Type:", which * PEM_get_EVP_CIPHER_INFO() requires to be present. * If the PEM header has less characters than that, it's * not worth spending cycles on it. */ if (strlen(pem_header) > 10) { EVP_CIPHER_INFO cipher; struct pem_pass_data pass_data; if (!PEM_get_EVP_CIPHER_INFO(pem_header, &cipher) || !file_fill_pem_pass_data(&pass_data, "PEM", ui_method, ui_data) || !PEM_do_header(&cipher, data, &len, file_get_pem_pass, &pass_data)) { ctx->errcnt++; goto err; } } } else { #if 0 /* PKCS12 not yet ready */ PKCS12 *pkcs12 =NULL; #endif if ((len = asn1_d2i_read_bio(ctx->file, &mem)) < 0) { if (!file_eof(ctx)) ctx->errcnt++; goto err; } data = (unsigned char *)mem->data; len = (long)mem->length; #if 0 /* PKCS12 not yet ready */ /* Try and see if we loaded a PKCS12 */ pkcs12 = d2i_PKCS12(NULL, &data, len); #endif } result = NULL; matchcount = 0; matching_functions = OPENSSL_zalloc(sizeof(*matching_functions) * OSSL_NELEM(file_handlers)); for (i = 0; i < OSSL_NELEM(file_handlers); i++) { const FILE_HANDLER *handler = file_handlers[i]; OSSL_STORE_INFO *tmp_result = handler->try_decode(pem_name, pem_header, data, len, ui_method, ui_data); if (tmp_result != NULL) { if (matching_functions) matching_functions[matchcount] = handler->try_decode; if (++matchcount == 1) { result = tmp_result; tmp_result = NULL; } else { /* more than one match => ambiguous, kill any result */ OSSL_STORE_INFO_free(result); OSSL_STORE_INFO_free(tmp_result); result = NULL; } } } if (matchcount > 1) OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE); if (matchcount == 0) OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE); if (result) ERR_clear_error(); err: OPENSSL_free(matching_functions); OPENSSL_free(pem_name); OPENSSL_free(pem_header); if (mem == NULL) OPENSSL_free(data); else BUF_MEM_free(mem); } while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx)); /* We bail out on ambiguity */ if (matchcount > 1) return NULL; end: return result; } static int file_error(OSSL_STORE_LOADER_CTX *ctx) { return ctx->errcnt > 0; } static int file_eof(OSSL_STORE_LOADER_CTX *ctx) { return BIO_eof(ctx->file); } static int file_close(OSSL_STORE_LOADER_CTX *ctx) { BIO_free_all(ctx->file); OPENSSL_free(ctx); return 1; } static OSSL_STORE_LOADER file_loader = { "file", file_open, NULL, file_load, file_eof, file_error, file_close }; static void store_file_loader_deinit(void) { ossl_store_unregister_loader_int(file_loader.scheme); } int ossl_store_file_loader_init(void) { int ret = ossl_store_register_loader_int(&file_loader); OPENSSL_atexit(store_file_loader_deinit); return ret; } crypto/store/store_err.c +16 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,10 @@ #ifndef OPENSSL_NO_ERR static const ERR_STRING_DATA OSSL_STORE_str_functs[] = { {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_GET_PASS, 0), "file_get_pass"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_LOAD, 0), "file_load"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_OPEN, 0), "file_open"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT, 0), "ossl_store_get0_loader_int"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT, 0), Loading Loading @@ -51,10 +55,14 @@ static const ERR_STRING_DATA OSSL_STORE_str_functs[] = { "ossl_store_register_loader_int"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT, 0), "ossl_store_unregister_loader_int"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_TRY_DECODE_PARAMS, 0), "try_decode_params"}, {0, NULL} }; static const ERR_STRING_DATA OSSL_STORE_str_reasons[] = { {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE), "ambiguous content type"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_INVALID_SCHEME), "invalid scheme"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_CERTIFICATE), Loading @@ -64,8 +72,16 @@ static const ERR_STRING_DATA OSSL_STORE_str_reasons[] = { {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_NAME), "not a name"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_PARAMETERS), "not parameters"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE), "path must be absolute"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED), "ui process interrupted or cancelled"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_UNREGISTERED_SCHEME), "unregistered scheme"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE), "unsupported content type"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_URI_AUTHORITY_UNSUPPORED), "uri authority unsuppored"}, {0, NULL} }; Loading crypto/store/store_init.c +2 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,8 @@ static CRYPTO_ONCE store_init = CRYPTO_ONCE_STATIC_INIT; DEFINE_RUN_ONCE_STATIC(do_store_init) { return OPENSSL_init_crypto(0, NULL); return OPENSSL_init_crypto(0, NULL) && ossl_store_file_loader_init(); } int ossl_store_init_once() Loading Loading
crypto/err/openssl.txt +10 −0 Original line number Diff line number Diff line Loading @@ -724,6 +724,9 @@ OCSP_F_OCSP_REQUEST_SIGN:110:OCSP_request_sign OCSP_F_OCSP_REQUEST_VERIFY:116:OCSP_request_verify OCSP_F_OCSP_RESPONSE_GET1_BASIC:111:OCSP_response_get1_basic OCSP_F_PARSE_HTTP_LINE1:118:parse_http_line1 OSSL_STORE_F_FILE_GET_PASS:118:file_get_pass OSSL_STORE_F_FILE_LOAD:119:file_load OSSL_STORE_F_FILE_OPEN:120:file_open OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT:100:ossl_store_get0_loader_int OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT:101:OSSL_STORE_INFO_get1_CERT OSSL_STORE_F_OSSL_STORE_INFO_GET1_CRL:102:OSSL_STORE_INFO_get1_CRL Loading @@ -746,6 +749,7 @@ OSSL_STORE_F_OSSL_STORE_OPEN_INT:115:* OSSL_STORE_F_OSSL_STORE_REGISTER_LOADER_INT:117:ossl_store_register_loader_int OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT:116:\ ossl_store_unregister_loader_int OSSL_STORE_F_TRY_DECODE_PARAMS:121:try_decode_params PEM_F_B2I_DSS:127:b2i_dss PEM_F_B2I_PVK_BIO:128:b2i_PVK_bio PEM_F_B2I_RSA:129:b2i_rsa Loading Loading @@ -1972,13 +1976,19 @@ OCSP_R_STATUS_TOO_OLD:127:status too old OCSP_R_UNKNOWN_MESSAGE_DIGEST:119:unknown message digest OCSP_R_UNKNOWN_NID:120:unknown nid OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE:129:unsupported requestorname type OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type OSSL_STORE_R_INVALID_SCHEME:106:invalid scheme OSSL_STORE_R_NOT_A_CERTIFICATE:100:not a certificate OSSL_STORE_R_NOT_A_CRL:101:not a crl OSSL_STORE_R_NOT_A_KEY:102:not a key OSSL_STORE_R_NOT_A_NAME:103:not a name OSSL_STORE_R_NOT_PARAMETERS:104:not parameters OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE:108:path must be absolute OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED:109:\ ui process interrupted or cancelled OSSL_STORE_R_UNREGISTERED_SCHEME:105:unregistered scheme OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE:110:unsupported content type OSSL_STORE_R_URI_AUTHORITY_UNSUPPORED:111:uri authority unsuppored PEM_R_BAD_BASE64_DECODE:100:bad base64 decode PEM_R_BAD_DECRYPT:101:bad decrypt PEM_R_BAD_END_LINE:102:bad end line Loading
crypto/store/build.info +2 −1 Original line number Diff line number Diff line LIBS=../../libcrypto SOURCE[../../libcrypto]=\ store_err.c store_init.c store_lib.c store_register.c store_strings.c store_err.c store_init.c store_lib.c store_register.c store_strings.c \ loader_file.c
crypto/store/loader_file.c 0 → 100644 +583 −0 Original line number Diff line number Diff line /* * Copyright 2016-2017 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 * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include <string.h> #include <openssl/bio.h> #include <openssl/dsa.h> /* For d2i_DSAPrivateKey */ #include <openssl/err.h> #include <openssl/evp.h> #include <openssl/pem.h> #include <openssl/pkcs12.h> /* For the PKCS8 stuff o.O */ #include <openssl/rsa.h> /* For d2i_RSAPrivateKey */ #include <openssl/safestack.h> #include <openssl/store.h> #include <openssl/ui.h> #include <openssl/x509.h> /* For the PKCS8 stuff o.O */ #include "internal/asn1_int.h" #include "store_locl.h" #include "e_os.h" /* * Password prompting */ static char *file_get_pass(const UI_METHOD *ui_method, char *pass, size_t maxsize, const char *prompt_info, void *data) { UI *ui = UI_new(); char *prompt = NULL; if (ui == NULL) { OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_MALLOC_FAILURE); return NULL; } if (ui_method != NULL) UI_set_method(ui, ui_method); UI_add_user_data(ui, data); if ((prompt = UI_construct_prompt(ui, "pass phrase", prompt_info)) == NULL) { OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_MALLOC_FAILURE); pass = NULL; } else if (!UI_add_input_string(ui, prompt, UI_INPUT_FLAG_DEFAULT_PWD, pass, 0, maxsize - 1)) { OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_UI_LIB); pass = NULL; } else { switch (UI_process(ui)) { case -2: OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED); pass = NULL; break; case -1: OSSL_STOREerr(OSSL_STORE_F_FILE_GET_PASS, ERR_R_UI_LIB); pass = NULL; break; default: break; } } OPENSSL_free(prompt); UI_free(ui); return pass; } struct pem_pass_data { const UI_METHOD *ui_method; 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) { if (pass_data == NULL) return 0; pass_data->ui_method = ui_method; pass_data->data = ui_data; pass_data->prompt_info = prompt_info; return 1; } static int file_get_pem_pass(char *buf, int num, int w, void *data) { struct pem_pass_data *pass_data = data; char *pass = file_get_pass(pass_data->ui_method, buf, num, pass_data->prompt_info, pass_data->data); return pass == NULL ? 0 : strlen(pass); } /* * The file scheme handlers */ /*- * The try_decode function is called to check if the blob of data can * be used by this handler, and if it can, decodes it into a supported * OpenSSL type and returns a OSSL_STORE_INFO with the decoded data. * Input: * pem_name: If this blob comes from a PEM file, this holds * the PEM name. If it comes from another type of * file, this is NULL. * pem_header: If this blob comes from a PEM file, this holds * the PEM headers. If it comes from another type of * file, this is NULL. * blob: The blob of data to match with what this handler * can use. * len: The length of the blob. * ui_method: Application UI method for getting a password, pin * or any other interactive data. * ui_data: Application data to be passed to ui_method when * it's called. * Output: * a OSSL_STORE_INFO */ typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name, const char *pem_header, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data); typedef struct file_handler_st { const char *name; file_try_decode_fn try_decode; } FILE_HANDLER; 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, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *store_info = NULL; EVP_PKEY *pkey = NULL; const EVP_PKEY_ASN1_METHOD *ameth = NULL; if (pem_name != NULL) { int slen; if ((slen = pem_check_suffix(pem_name, "PRIVATE KEY")) > 0 && (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name, slen)) != NULL) pkey = d2i_PrivateKey(ameth->pkey_id, NULL, &blob, len); } else { int i; for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { ameth = EVP_PKEY_asn1_get0(i); if (ameth->pkey_flags & ASN1_PKEY_ALIAS) continue; pkey = d2i_PrivateKey(ameth->pkey_id, NULL, &blob, len); if (pkey != NULL) break; } } if (pkey == NULL) /* No match */ return NULL; store_info = OSSL_STORE_INFO_new_PKEY(pkey); if (store_info == NULL) EVP_PKEY_free(pkey); return store_info; } static FILE_HANDLER PrivateKey_handler = { "PrivateKey", try_decode_PrivateKey }; static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name, const char *pem_header, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *store_info = NULL; EVP_PKEY *pkey = NULL; if (pem_name != NULL && strcmp(pem_name, PEM_STRING_PUBLIC) != 0) /* No match */ return NULL; if ((pkey = d2i_PUBKEY(NULL, &blob, len)) != NULL) store_info = OSSL_STORE_INFO_new_PKEY(pkey); return store_info; } static FILE_HANDLER PUBKEY_handler = { "PUBKEY", try_decode_PUBKEY }; static OSSL_STORE_INFO *try_decode_params(const char *pem_name, const char *pem_header, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *store_info = NULL; EVP_PKEY *pkey = EVP_PKEY_new(); const EVP_PKEY_ASN1_METHOD *ameth = NULL; int ok = 0; if (pkey == NULL) { OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PARAMS, ERR_R_EVP_LIB); return NULL; } if (pem_name != NULL) { int slen; if ((slen = pem_check_suffix(pem_name, "PARAMETERS")) > 0 && EVP_PKEY_set_type_str(pkey, pem_name, slen) && (ameth = EVP_PKEY_get0_asn1(pkey)) != NULL && ameth->param_decode != NULL && ameth->param_decode(pkey, &blob, len)) ok = 1; } else { int i; for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { 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 && ameth->param_decode != NULL && ameth->param_decode(pkey, &blob, len)) { ok = 1; break; } } } if (ok) store_info = OSSL_STORE_INFO_new_PARAMS(pkey); if (store_info == NULL) EVP_PKEY_free(pkey); return store_info; } static FILE_HANDLER params_handler = { "params", try_decode_params }; static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name, const char *pem_header, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *store_info = NULL; X509 *cert = NULL; /* * In most cases, we can try to interpret the serialized data as a trusted * cert (X509 + X509_AUX) and fall back to reading it as a normal cert * (just X509), but if the PEM name specifically declares it as a trusted * cert, then no fallback should be engaged. |ignore_trusted| tells if * the fallback can be used (1) or not (0). */ int ignore_trusted = 1; if (pem_name != NULL) { if (strcmp(pem_name, PEM_STRING_X509_TRUSTED) == 0) ignore_trusted = 0; else if (strcmp(pem_name, PEM_STRING_X509_OLD) != 0 && strcmp(pem_name, PEM_STRING_X509) != 0) /* No match */ return NULL; } if ((cert = d2i_X509_AUX(NULL, &blob, len)) != NULL || (ignore_trusted && (cert = d2i_X509(NULL, &blob, len)) != NULL)) store_info = OSSL_STORE_INFO_new_CERT(cert); if (store_info == NULL) X509_free(cert); return store_info; } static FILE_HANDLER X509Certificate_handler = { "X509Certificate", try_decode_X509Certificate }; static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name, const char *pem_header, const unsigned char *blob, size_t len, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *store_info = NULL; X509_CRL *crl = NULL; if (pem_name != NULL && strcmp(pem_name, PEM_STRING_X509_CRL) != 0) /* No match */ return NULL; if ((crl = d2i_X509_CRL(NULL, &blob, len)) != NULL) store_info = OSSL_STORE_INFO_new_CRL(crl); if (store_info == NULL) X509_CRL_free(crl); return store_info; } static FILE_HANDLER X509CRL_handler = { "X509CRL", try_decode_X509CRL }; static const FILE_HANDLER *file_handlers[] = { &X509Certificate_handler, &X509CRL_handler, ¶ms_handler, &PUBKEY_handler, &PrivateKey_handler, }; /* * The loader itself */ struct ossl_store_loader_ctx_st { BIO *file; int is_pem; int errcnt; }; static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, const char *uri, const UI_METHOD *ui_method, void *ui_data) { BIO *buff = NULL; char peekbuf[4096]; OSSL_STORE_LOADER_CTX *ctx = NULL; const char *path = NULL; if (strncasecmp(uri, "file:", 5) == 0) { if (strncmp(&uri[5], "//localhost/", 12) == 0) { path = &uri[16]; } else if (strncmp(&uri[5], "///", 3) == 0) { path = &uri[7]; } else if (strncmp(&uri[5], "//", 2) != 0) { path = &uri[5]; } else { OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, OSSL_STORE_R_URI_AUTHORITY_UNSUPPORED); return NULL; } /* * If the scheme "file" was an explicit part of the URI, the path must * be absolute. So says RFC 8089 */ if (path[0] != '/') { OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE); return NULL; } #ifdef _WIN32 /* Windows file: URIs with a drive letter start with a / */ if (path[0] == '/' && path[2] == ':' && path[3] == '/') path++; #endif } else { path = uri; } ctx = OPENSSL_zalloc(sizeof(*ctx)); if (ctx == NULL) { OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE); return NULL; } if ((buff = BIO_new(BIO_f_buffer())) == NULL) goto err; if ((ctx->file = BIO_new_file(path, "rb")) == NULL) { goto err; } ctx->file = BIO_push(buff, ctx->file); if (BIO_buffer_peek(ctx->file, peekbuf, sizeof(peekbuf)-1) > 0) { peekbuf[sizeof(peekbuf)-1] = '\0'; if (strstr(peekbuf, "-----BEGIN ") != NULL) ctx->is_pem = 1; } return ctx; err: if (buff != NULL) BIO_free(buff); OPENSSL_free(ctx); return NULL; } 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, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *result = NULL; int matchcount = -1; if (file_error(ctx)) return NULL; do { char *pem_name = NULL; /* PEM record name */ char *pem_header = NULL; /* PEM record header */ unsigned char *data = NULL; /* DER encoded data */ BUF_MEM *mem = NULL; long len = 0; /* DER encoded data length */ int r = 0; size_t i = 0; file_try_decode_fn *matching_functions = NULL; matchcount = -1; if (ctx->is_pem) { r = PEM_read_bio(ctx->file, &pem_name, &pem_header, &data, &len); if (r <= 0) { if (!file_eof(ctx)) ctx->errcnt++; goto end; } /* * 10 is the number of characters in "Proc-Type:", which * PEM_get_EVP_CIPHER_INFO() requires to be present. * If the PEM header has less characters than that, it's * not worth spending cycles on it. */ if (strlen(pem_header) > 10) { EVP_CIPHER_INFO cipher; struct pem_pass_data pass_data; if (!PEM_get_EVP_CIPHER_INFO(pem_header, &cipher) || !file_fill_pem_pass_data(&pass_data, "PEM", ui_method, ui_data) || !PEM_do_header(&cipher, data, &len, file_get_pem_pass, &pass_data)) { ctx->errcnt++; goto err; } } } else { #if 0 /* PKCS12 not yet ready */ PKCS12 *pkcs12 =NULL; #endif if ((len = asn1_d2i_read_bio(ctx->file, &mem)) < 0) { if (!file_eof(ctx)) ctx->errcnt++; goto err; } data = (unsigned char *)mem->data; len = (long)mem->length; #if 0 /* PKCS12 not yet ready */ /* Try and see if we loaded a PKCS12 */ pkcs12 = d2i_PKCS12(NULL, &data, len); #endif } result = NULL; matchcount = 0; matching_functions = OPENSSL_zalloc(sizeof(*matching_functions) * OSSL_NELEM(file_handlers)); for (i = 0; i < OSSL_NELEM(file_handlers); i++) { const FILE_HANDLER *handler = file_handlers[i]; OSSL_STORE_INFO *tmp_result = handler->try_decode(pem_name, pem_header, data, len, ui_method, ui_data); if (tmp_result != NULL) { if (matching_functions) matching_functions[matchcount] = handler->try_decode; if (++matchcount == 1) { result = tmp_result; tmp_result = NULL; } else { /* more than one match => ambiguous, kill any result */ OSSL_STORE_INFO_free(result); OSSL_STORE_INFO_free(tmp_result); result = NULL; } } } if (matchcount > 1) OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE); if (matchcount == 0) OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE); if (result) ERR_clear_error(); err: OPENSSL_free(matching_functions); OPENSSL_free(pem_name); OPENSSL_free(pem_header); if (mem == NULL) OPENSSL_free(data); else BUF_MEM_free(mem); } while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx)); /* We bail out on ambiguity */ if (matchcount > 1) return NULL; end: return result; } static int file_error(OSSL_STORE_LOADER_CTX *ctx) { return ctx->errcnt > 0; } static int file_eof(OSSL_STORE_LOADER_CTX *ctx) { return BIO_eof(ctx->file); } static int file_close(OSSL_STORE_LOADER_CTX *ctx) { BIO_free_all(ctx->file); OPENSSL_free(ctx); return 1; } static OSSL_STORE_LOADER file_loader = { "file", file_open, NULL, file_load, file_eof, file_error, file_close }; static void store_file_loader_deinit(void) { ossl_store_unregister_loader_int(file_loader.scheme); } int ossl_store_file_loader_init(void) { int ret = ossl_store_register_loader_int(&file_loader); OPENSSL_atexit(store_file_loader_deinit); return ret; }
crypto/store/store_err.c +16 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,10 @@ #ifndef OPENSSL_NO_ERR static const ERR_STRING_DATA OSSL_STORE_str_functs[] = { {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_GET_PASS, 0), "file_get_pass"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_LOAD, 0), "file_load"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_OPEN, 0), "file_open"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT, 0), "ossl_store_get0_loader_int"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT, 0), Loading Loading @@ -51,10 +55,14 @@ static const ERR_STRING_DATA OSSL_STORE_str_functs[] = { "ossl_store_register_loader_int"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT, 0), "ossl_store_unregister_loader_int"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_TRY_DECODE_PARAMS, 0), "try_decode_params"}, {0, NULL} }; static const ERR_STRING_DATA OSSL_STORE_str_reasons[] = { {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE), "ambiguous content type"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_INVALID_SCHEME), "invalid scheme"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_CERTIFICATE), Loading @@ -64,8 +72,16 @@ static const ERR_STRING_DATA OSSL_STORE_str_reasons[] = { {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_NAME), "not a name"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_PARAMETERS), "not parameters"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE), "path must be absolute"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED), "ui process interrupted or cancelled"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_UNREGISTERED_SCHEME), "unregistered scheme"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE), "unsupported content type"}, {ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_URI_AUTHORITY_UNSUPPORED), "uri authority unsuppored"}, {0, NULL} }; Loading
crypto/store/store_init.c +2 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,8 @@ static CRYPTO_ONCE store_init = CRYPTO_ONCE_STATIC_INIT; DEFINE_RUN_ONCE_STATIC(do_store_init) { return OPENSSL_init_crypto(0, NULL); return OPENSSL_init_crypto(0, NULL) && ossl_store_file_loader_init(); } int ossl_store_init_once() Loading