X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fstore%2Floader_file.c;h=9f6158ff793f4dfe7e87f4888ce3a4723bbc26d3;hp=02178b29a8dec80e632d3728d72cc195a7415e68;hb=f55838f34dd5c65420662f7eacf6c6ffd7f261a2;hpb=852c2ed260860b6b85c84f9fe96fb4d23d49c9f2 diff --git a/crypto/store/loader_file.c b/crypto/store/loader_file.c index 02178b29a8..9f6158ff79 100644 --- a/crypto/store/loader_file.c +++ b/crypto/store/loader_file.c @@ -18,6 +18,7 @@ #include #include #include +#include "internal/pem_int.h" #include /* For the PKCS8 stuff o.O */ #include /* For d2i_RSAPrivateKey */ #include @@ -48,7 +49,8 @@ DEFINE_STACK_OF(X509) */ static char *file_get_pass(const UI_METHOD *ui_method, char *pass, - size_t maxsize, const char *prompt_info, void *data) + size_t maxsize, const char *desc, const char *info, + void *data) { UI *ui = UI_new(); char *prompt = NULL; @@ -62,8 +64,7 @@ static char *file_get_pass(const UI_METHOD *ui_method, char *pass, UI_set_method(ui, ui_method); UI_add_user_data(ui, data); - if ((prompt = UI_construct_prompt(ui, "pass phrase", - prompt_info)) == NULL) { + if ((prompt = UI_construct_prompt(ui, desc, 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, @@ -94,18 +95,20 @@ static char *file_get_pass(const UI_METHOD *ui_method, char *pass, struct pem_pass_data { const UI_METHOD *ui_method; void *data; + const char *prompt_desc; const char *prompt_info; }; static int file_fill_pem_pass_data(struct pem_pass_data *pass_data, - const char *prompt_info, + const char *desc, const char *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; + pass_data->prompt_desc = desc; + pass_data->prompt_info = info; return 1; } @@ -114,7 +117,8 @@ 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); + pass_data->prompt_desc, pass_data->prompt_info, + pass_data->data); return pass == NULL ? 0 : strlen(pass); } @@ -168,7 +172,7 @@ 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, const char *uri, OPENSSL_CTX *libctx, const char *propq); /* @@ -205,7 +209,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, OPENSSL_CTX *libctx, + void *ui_data, const char *uri, + OPENSSL_CTX *libctx, const char *propq) { OSSL_STORE_INFO *store_info = NULL; @@ -234,7 +239,7 @@ static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name, pass = ""; } else { if ((pass = file_get_pass(ui_method, tpass, PEM_BUFSIZE, - "PKCS12 import password", + "PKCS12 import pass phrase", uri, ui_data)) == NULL) { OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS12, OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR); @@ -335,6 +340,7 @@ static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name, int *matchcount, const UI_METHOD *ui_method, void *ui_data, + const char *uri, OPENSSL_CTX *libctx, const char *propq) { @@ -366,7 +372,8 @@ static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name, } if ((pass = file_get_pass(ui_method, kbuf, PEM_BUFSIZE, - "PKCS8 decrypt password", ui_data)) == NULL) { + "PKCS8 decrypt pass phrase", uri, + ui_data)) == NULL) { OSSL_STOREerr(OSSL_STORE_F_TRY_DECODE_PKCS8ENCRYPTED, OSSL_STORE_R_BAD_PASSWORD_READ); goto nop8; @@ -412,7 +419,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, OPENSSL_CTX *libctx, + void *ui_data, const char *uri, + OPENSSL_CTX *libctx, const char *propq) { OSSL_STORE_INFO *store_info = NULL; @@ -491,7 +499,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, OPENSSL_CTX *libctx, + void *ui_data, const char *uri, + OPENSSL_CTX *libctx, const char *propq) { OSSL_STORE_INFO *store_info = NULL; @@ -526,7 +535,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, OPENSSL_CTX *libctx, + void *ui_data, const char *uri, + OPENSSL_CTX *libctx, const char *propq) { OSSL_STORE_INFO *store_info = NULL; @@ -611,6 +621,7 @@ static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name, int *matchcount, const UI_METHOD *ui_method, void *ui_data, + const char *uri, OPENSSL_CTX *libctx, const char *propq) { @@ -662,7 +673,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, OPENSSL_CTX *libctx, + void *ui_data, const char *uri, + OPENSSL_CTX *libctx, const char *propq) { OSSL_STORE_INFO *store_info = NULL; @@ -711,6 +723,7 @@ static const FILE_HANDLER *file_handlers[] = { */ struct ossl_store_loader_ctx_st { + char *uri; /* The URI we currently try to load */ enum { is_raw = 0, is_pem, @@ -718,6 +731,7 @@ struct ossl_store_loader_ctx_st { } type; int errcnt; #define FILE_FLAG_SECMEM (1<<0) +#define FILE_FLAG_ATTACHED (1<<1) unsigned int flags; union { struct { /* Used with is_raw and is_pem */ @@ -733,7 +747,6 @@ struct ossl_store_loader_ctx_st { struct { /* Used with is_dir */ OPENSSL_DIR_CTX *ctx; int end_reached; - char *uri; /* * When a search expression is given, these are filled in. @@ -761,9 +774,11 @@ struct ossl_store_loader_ctx_st { static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx) { - if (ctx->type == is_dir) { - OPENSSL_free(ctx->_.dir.uri); - } else { + if (ctx == NULL) + return; + + OPENSSL_free(ctx->uri); + if (ctx->type != is_dir) { if (ctx->_.file.last_handler != NULL) { ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx); ctx->_.file.last_handler_ctx = NULL; @@ -774,6 +789,23 @@ static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx) OPENSSL_free(ctx); } +static int file_find_type(OSSL_STORE_LOADER_CTX *ctx) +{ + BIO *buff = NULL; + char peekbuf[4096] = { 0, }; + + if ((buff = BIO_new(BIO_f_buffer())) == NULL) + return 0; + + 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 (strstr(peekbuf, "-----BEGIN ") != NULL) + ctx->type = is_pem; + } + return 1; +} + static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, const char *uri, const UI_METHOD *ui_method, @@ -865,19 +897,14 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE); return NULL; } + ctx->uri = OPENSSL_strdup(uri); + if (ctx->uri == NULL) { + OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE); + goto err; + } 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 - * components may be used. - */ - ctx->_.dir.uri = OPENSSL_strdup(uri); ctx->type = is_dir; - - if (ctx->_.dir.uri == NULL) - goto err; - ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, path); ctx->_.dir.last_errno = errno; if (ctx->_.dir.last_entry == NULL) { @@ -891,22 +918,10 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, } ctx->_.dir.end_reached = 1; } - } else { - BIO *buff = NULL; - char peekbuf[4096] = { 0, }; - - if ((buff = BIO_new(BIO_f_buffer())) == NULL - || (ctx->_.file.file = BIO_new_file(path, "rb")) == NULL) { - BIO_free_all(buff); - goto err; - } - - 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 (strstr(peekbuf, "-----BEGIN ") != NULL) - ctx->type = is_pem; - } + } else if ((ctx->_.file.file = BIO_new_file(path, "rb")) == NULL + || !file_find_type(ctx)) { + BIO_free_all(ctx->_.file.file); + goto err; } return ctx; @@ -915,6 +930,34 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, return NULL; } +static OSSL_STORE_LOADER_CTX *file_attach(const OSSL_STORE_LOADER *loader, + BIO *bp, OPENSSL_CTX *libctx, + const char *propq, + const UI_METHOD *ui_method, + void *ui_data) +{ + OSSL_STORE_LOADER_CTX *ctx; + + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL + || (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL)) { + OSSL_STOREerr(OSSL_STORE_F_FILE_ATTACH, ERR_R_MALLOC_FAILURE); + OSSL_STORE_LOADER_CTX_free(ctx); + return NULL; + } + + ctx->libctx = libctx; + ctx->flags |= FILE_FLAG_ATTACHED; + ctx->_.file.file = bp; + if (!file_find_type(ctx)) { + /* Safety measure */ + ctx->_.file.file = NULL; + OSSL_STORE_LOADER_CTX_free(ctx); + ctx = NULL; + } + + return ctx; +} + static int file_ctrl(OSSL_STORE_LOADER_CTX *ctx, int cmd, va_list args) { int ret = 1; @@ -984,36 +1027,6 @@ static int file_find(OSSL_STORE_LOADER_CTX *ctx, return 0; } -/* Internal function to decode an already opened PEM file */ -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)); - - if (ctx == NULL) { - OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_FILE_ATTACH_PEM_BIO_INT, - ERR_R_MALLOC_FAILURE); - return NULL; - } - - 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; -} - static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx, const char *pem_name, const char *pem_header, @@ -1048,7 +1061,8 @@ 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, ctx->libctx, ctx->propq); + ui_method, ui_data, ctx->uri, + ctx->libctx, ctx->propq); if (try_matchcount > 0) { @@ -1115,7 +1129,7 @@ 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->uri, ctx->libctx, ctx->propq); if (result == NULL) { @@ -1136,8 +1150,8 @@ static void pem_free_flag(void *pem_data, int secure, size_t num) } static int file_read_pem(BIO *bp, char **pem_name, char **pem_header, unsigned char **data, long *len, - const UI_METHOD *ui_method, - void *ui_data, int secure) + const UI_METHOD *ui_method, void *ui_data, + const char *uri, int secure) { int i = secure ? PEM_read_bio_ex(bp, pem_name, pem_header, data, len, @@ -1158,7 +1172,8 @@ static int file_read_pem(BIO *bp, char **pem_name, char **pem_header, 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) + || !file_fill_pem_pass_data(&pass_data, "PEM pass phrase", uri, + ui_method, ui_data) || !PEM_do_header(&cipher, *data, len, file_get_pem_pass, &pass_data)) { return 0; @@ -1167,6 +1182,84 @@ static int file_read_pem(BIO *bp, char **pem_name, char **pem_header, return 1; } +static OSSL_STORE_INFO *file_try_read_msblob(BIO *bp, int *matchcount) +{ +#ifdef OPENSSL_NO_DSA + return NULL; +#else + OSSL_STORE_INFO *result = NULL; + int ispub = -1; + + { + unsigned int magic = 0, bitlen = 0; + int isdss = 0; + unsigned char peekbuf[16] = { 0, }; + const unsigned char *p = peekbuf; + + if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0) + return 0; + if (!ossl_do_blob_header(&p, sizeof(peekbuf), &magic, &bitlen, + &isdss, &ispub)) + return 0; + } + + (*matchcount)++; + + { + EVP_PKEY *tmp = ispub + ? b2i_PublicKey_bio(bp) + : b2i_PrivateKey_bio(bp); + + if (tmp == NULL + || (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) { + EVP_PKEY_free(tmp); + return 0; + } + } + + return result; +#endif +} + +static OSSL_STORE_INFO *file_try_read_PVK(BIO *bp, const UI_METHOD *ui_method, + void *ui_data, const char *uri, + int *matchcount) +{ +#if defined(OPENSSL_NO_DSA) || defined(OPENSSL_NO_RC4) + return NULL; +#else + OSSL_STORE_INFO *result = NULL; + + { + unsigned int saltlen = 0, keylen = 0; + unsigned char peekbuf[24] = { 0, }; + const unsigned char *p = peekbuf; + + if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0) + return 0; + if (!ossl_do_PVK_header(&p, sizeof(peekbuf), 0, &saltlen, &keylen)) + return 0; + } + + (*matchcount)++; + + { + EVP_PKEY *tmp = NULL; + struct pem_pass_data pass_data; + + if (!file_fill_pem_pass_data(&pass_data, "PVK pass phrase", uri, + ui_method, ui_data) + || (tmp = b2i_PVK_bio(bp, file_get_pem_pass, &pass_data)) == NULL + || (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) { + EVP_PKEY_free(tmp); + return 0; + } + } + + return result; +#endif +} + static int file_read_asn1(BIO *bp, unsigned char **data, long *len) { BUF_MEM *mem = NULL; @@ -1201,8 +1294,8 @@ static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name, assert(name != NULL); assert(data != NULL); { - const char *pathsep = ends_with_dirsep(ctx->_.dir.uri) ? "" : "/"; - long calculated_length = strlen(ctx->_.dir.uri) + strlen(pathsep) + const char *pathsep = ends_with_dirsep(ctx->uri) ? "" : "/"; + long calculated_length = strlen(ctx->uri) + strlen(pathsep) + strlen(name) + 1 /* \0 */; *data = OPENSSL_zalloc(calculated_length); @@ -1211,7 +1304,7 @@ static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name, return 0; } - OPENSSL_strlcat(*data, ctx->_.dir.uri, calculated_length); + OPENSSL_strlcat(*data, ctx->uri, calculated_length); OPENSSL_strlcat(*data, pathsep, calculated_length); OPENSSL_strlcat(*data, name, calculated_length); } @@ -1318,8 +1411,7 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx, * only cares that it isn't NULL. Therefore, we can safely give * it our URI here. */ - ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, - ctx->_.dir.uri); + ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, ctx->uri); ctx->_.dir.last_errno = errno; if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0) ctx->_.dir.end_reached = 1; @@ -1351,12 +1443,19 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx, matchcount = -1; if (ctx->type == is_pem) { if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header, - &data, &len, ui_method, ui_data, + &data, &len, ui_method, ui_data, ctx->uri, (ctx->flags & FILE_FLAG_SECMEM) != 0)) { ctx->errcnt++; goto endloop; } } else { + if ((result = file_try_read_msblob(ctx->_.file.file, + &matchcount)) != NULL + || (result = file_try_read_PVK(ctx->_.file.file, + ui_method, ui_data, ctx->uri, + &matchcount)) != NULL) + goto endloop; + if (!file_read_asn1(ctx->_.file.file, &data, &len)) { ctx->errcnt++; goto endloop; @@ -1435,17 +1534,25 @@ static int file_eof(OSSL_STORE_LOADER_CTX *ctx) static int file_close(OSSL_STORE_LOADER_CTX *ctx) { - if (ctx->type == is_dir) { - OPENSSL_DIR_end(&ctx->_.dir.ctx); + if ((ctx->flags & FILE_FLAG_ATTACHED) == 0) { + if (ctx->type == is_dir) + OPENSSL_DIR_end(&ctx->_.dir.ctx); + else + BIO_free_all(ctx->_.file.file); } else { - BIO_free_all(ctx->_.file.file); - } - OSSL_STORE_LOADER_CTX_free(ctx); - return 1; -} + /* + * Because file_attach() called file_find_type(), we know that a + * BIO_f_buffer() has been pushed on top of the regular BIO. + */ + BIO *buff = ctx->_.file.file; -int ossl_store_file_detach_pem_bio_int(OSSL_STORE_LOADER_CTX *ctx) -{ + /* Detach buff */ + (void)BIO_pop(ctx->_.file.file); + /* Safety measure */ + ctx->_.file.file = NULL; + + BIO_free(buff); + } OSSL_STORE_LOADER_CTX_free(ctx); return 1; } @@ -1455,6 +1562,7 @@ static OSSL_STORE_LOADER file_loader = "file", NULL, file_open, + file_attach, file_ctrl, file_expect, file_find,