static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_INFO *result = NULL; ctx->errcnt = 0; ERR_clear_error(); if (ctx->type == is_dir) { do { char *newname = NULL; if (ctx->_.dir.last_entry == NULL) { if (!ctx->_.dir.end_reached) { char errbuf[256]; assert(ctx->_.dir.last_errno != 0); 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); } 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; /* * On the first call (with a NULL context), OPENSSL_DIR_read() * cares about the second argument. On the following calls, it * 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_errno = errno; if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0) ctx->_.dir.end_reached = 1; if (newname != NULL && (result = OSSL_STORE_INFO_new_NAME(newname)) == NULL) { OPENSSL_free(newname); OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_OSSL_STORE_LIB); return NULL; } } while (result == NULL && !file_eof(ctx)); } else { int matchcount = -1; again: result = file_load_try_repeat(ctx, ui_method, ui_data); if (result != NULL) return result; if (file_eof(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 */ long len = 0; /* DER encoded data length */ matchcount = -1; if (ctx->type == is_pem) { if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header, &data, &len, ui_method, ui_data, (ctx->flags & FILE_FLAG_SECMEM) != 0)) { ctx->errcnt++; goto endloop; } } else { if (!file_read_asn1(ctx->_.file.file, &data, &len)) { ctx->errcnt++; goto endloop; } } result = file_load_try_decode(ctx, pem_name, pem_header, data, len, ui_method, ui_data, &matchcount); if (result != NULL) goto endloop; /* * If a PEM name matches more than one handler, the handlers are * badly coded. */ if (!ossl_assert(pem_name == NULL || matchcount <= 1)) { ctx->errcnt++; goto endloop; } if (matchcount > 1) { OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE); } else if (matchcount == 1) { /* * If there are other errors on the stack, they already show * what the problem is. */ if (ERR_peek_error() == 0) { OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE); if (pem_name != NULL) ERR_add_error_data(3, "PEM type is '", pem_name, "'"); } } if (matchcount > 0) ctx->errcnt++; endloop: 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; }
static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx, const char *pem_name, const char *pem_header, unsigned char *data, size_t len, const UI_METHOD *ui_method, void *ui_data, int *matchcount) { OSSL_STORE_INFO *result = NULL; BUF_MEM *new_mem = NULL; char *new_pem_name = NULL; int t = 0; again: { size_t i = 0; void *handler_ctx = NULL; const FILE_HANDLER **matching_handlers = OPENSSL_zalloc(sizeof(*matching_handlers) * OSSL_NELEM(file_handlers)); if (matching_handlers == NULL) { OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD_TRY_DECODE, ERR_R_MALLOC_FAILURE); goto err; } *matchcount = 0; for (i = 0; i < OSSL_NELEM(file_handlers); i++) { const FILE_HANDLER *handler = file_handlers[i]; int try_matchcount = 0; void *tmp_handler_ctx = NULL; OSSL_STORE_INFO *tmp_result = handler->try_decode(pem_name, pem_header, data, len, &tmp_handler_ctx, &try_matchcount, ui_method, ui_data); if (try_matchcount > 0) { matching_handlers[*matchcount] = handler; if (handler_ctx) handler->destroy_ctx(&handler_ctx); handler_ctx = tmp_handler_ctx; if ((*matchcount += try_matchcount) > 1) { /* more than one match => ambiguous, kill any result */ OSSL_STORE_INFO_free(result); OSSL_STORE_INFO_free(tmp_result); if (handler->destroy_ctx != NULL) handler->destroy_ctx(&handler_ctx); handler_ctx = NULL; tmp_result = NULL; result = NULL; } if (result == NULL) result = tmp_result; } } if (*matchcount == 1 && matching_handlers[0]->repeatable) { ctx->_.file.last_handler = matching_handlers[0]; ctx->_.file.last_handler_ctx = handler_ctx; } OPENSSL_free(matching_handlers); } err: OPENSSL_free(new_pem_name); BUF_MEM_free(new_mem); if (result != NULL && (t = OSSL_STORE_INFO_get_type(result)) == OSSL_STORE_INFO_EMBEDDED) { pem_name = new_pem_name = ossl_store_info_get0_EMBEDDED_pem_name(result); new_mem = ossl_store_info_get0_EMBEDDED_buffer(result); data = (unsigned char *)new_mem->data; len = new_mem->length; OPENSSL_free(result); result = NULL; goto again; } if (result != NULL) ERR_clear_error(); return result; }
static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, int text, int noout, int recursive, int indent, BIO *out) { OSSL_STORE_CTX *store_ctx = NULL; int ret = 1, items = 0; if ((store_ctx = OSSL_STORE_open(uri, uimeth, uidata, NULL, NULL)) == NULL) { BIO_printf(bio_err, "Couldn't open file or uri %s\n", uri); ERR_print_errors(bio_err); return ret; } /* From here on, we count errors, and we'll return the count at the end */ ret = 0; for (;;) { OSSL_STORE_INFO *info = OSSL_STORE_load(store_ctx); int type = info == NULL ? 0 : OSSL_STORE_INFO_get_type(info); const char *infostr = info == NULL ? NULL : OSSL_STORE_INFO_type_string(type); if (info == NULL) { if (OSSL_STORE_eof(store_ctx)) break; if (OSSL_STORE_error(store_ctx)) { if (recursive) ERR_clear_error(); else ERR_print_errors(bio_err); ret++; continue; } BIO_printf(bio_err, "ERROR: OSSL_STORE_load() returned NULL without " "eof or error indications\n"); BIO_printf(bio_err, " This is an error in the loader\n"); ERR_print_errors(bio_err); ret++; break; } if (type == OSSL_STORE_INFO_NAME) { const char *name = OSSL_STORE_INFO_get0_NAME(info); const char *desc = OSSL_STORE_INFO_get0_NAME_description(info); indent_printf(indent, bio_out, "%d: %s: %s\n", items, infostr, name); if (desc != NULL) indent_printf(indent, bio_out, "%s\n", desc); } else { indent_printf(indent, bio_out, "%d: %s\n", items, infostr); } /* * Unfortunately, PEM_X509_INFO_write_bio() is sorely lacking in * functionality, so we must figure out how exactly to write things * ourselves... */ switch (type) { case OSSL_STORE_INFO_NAME: if (recursive) { const char *suburi = OSSL_STORE_INFO_get0_NAME(info); ret += process(suburi, uimeth, uidata, text, noout, recursive, indent + 2, out); } break; case OSSL_STORE_INFO_PARAMS: if (text) EVP_PKEY_print_params(out, OSSL_STORE_INFO_get0_PARAMS(info), 0, NULL); if (!noout) PEM_write_bio_Parameters(out, OSSL_STORE_INFO_get0_PARAMS(info)); break; case OSSL_STORE_INFO_PKEY: if (text) EVP_PKEY_print_private(out, OSSL_STORE_INFO_get0_PKEY(info), 0, NULL); if (!noout) PEM_write_bio_PrivateKey(out, OSSL_STORE_INFO_get0_PKEY(info), NULL, NULL, 0, NULL, NULL); break; case OSSL_STORE_INFO_CERT: if (text) X509_print(out, OSSL_STORE_INFO_get0_CERT(info)); if (!noout) PEM_write_bio_X509(out, OSSL_STORE_INFO_get0_CERT(info)); break; case OSSL_STORE_INFO_CRL: if (text) X509_CRL_print(out, OSSL_STORE_INFO_get0_CRL(info)); if (!noout) PEM_write_bio_X509_CRL(out, OSSL_STORE_INFO_get0_CRL(info)); break; default: BIO_printf(bio_err, "!!! Unknown code\n"); ret++; break; } items++; OSSL_STORE_INFO_free(info); } indent_printf(indent, out, "Total found: %d\n", items); if (!OSSL_STORE_close(store_ctx)) { ERR_print_errors(bio_err); ret++; } return ret; }