mirror of
https://github.com/openssl/openssl.git
synced 2024-11-27 05:21:51 +08:00
STORE 'file' scheme loader: refactor file_load to support decoding restart
Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/3542)
This commit is contained in:
parent
50ecedda40
commit
1aabc2445b
@ -726,6 +726,7 @@ 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_LOAD_TRY_DECODE:124:file_load_try_decode
|
||||
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
|
||||
|
@ -559,6 +559,174 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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];
|
||||
void *tmp_handler_ctx = NULL;
|
||||
OSSL_STORE_INFO *tmp_result =
|
||||
handler->try_decode(pem_name, pem_header, data, len,
|
||||
&tmp_handler_ctx, ui_method, ui_data);
|
||||
|
||||
if (tmp_result == NULL) {
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD_TRY_DECODE,
|
||||
OSSL_STORE_R_IS_NOT_A);
|
||||
ERR_add_error_data(1, handler->name);
|
||||
} else {
|
||||
if (matching_handlers)
|
||||
matching_handlers[*matchcount] = handler;
|
||||
|
||||
if (handler_ctx)
|
||||
handler->destroy_ctx(&handler_ctx);
|
||||
handler_ctx = tmp_handler_ctx;
|
||||
|
||||
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);
|
||||
if (handler->destroy_ctx != NULL)
|
||||
handler->destroy_ctx(&handler_ctx);
|
||||
handler_ctx = NULL;
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*matchcount > 1)
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD_TRY_DECODE,
|
||||
OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE);
|
||||
if (*matchcount == 0)
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD_TRY_DECODE,
|
||||
OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE);
|
||||
else if (matching_handlers[0]->repeatable) {
|
||||
if (ctx == NULL) {
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD_TRY_DECODE,
|
||||
OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE);
|
||||
OSSL_STORE_INFO_free(result);
|
||||
result = NULL;
|
||||
} else {
|
||||
ctx->last_handler = matching_handlers[0];
|
||||
ctx->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 OSSL_STORE_INFO *file_load_try_repeat(OSSL_STORE_LOADER_CTX *ctx,
|
||||
const UI_METHOD *ui_method,
|
||||
void *ui_data)
|
||||
{
|
||||
OSSL_STORE_INFO *result = NULL;
|
||||
|
||||
if (ctx->last_handler != NULL) {
|
||||
result = ctx->last_handler->try_decode(NULL, NULL, NULL, 0,
|
||||
&ctx->last_handler_ctx,
|
||||
ui_method, ui_data);
|
||||
|
||||
if (result == NULL) {
|
||||
ctx->last_handler->destroy_ctx(&ctx->last_handler_ctx);
|
||||
ctx->last_handler_ctx = NULL;
|
||||
ctx->last_handler = NULL;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
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 i = PEM_read_bio(bp, pem_name, pem_header, data, len);
|
||||
|
||||
if (i <= 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int file_read_asn1(BIO *bp, unsigned char **data, long *len)
|
||||
{
|
||||
BUF_MEM *mem = NULL;
|
||||
|
||||
if (asn1_d2i_read_bio(bp, &mem) < 0)
|
||||
return 0;
|
||||
|
||||
*data = (unsigned char *)mem->data;
|
||||
*len = (long)mem->length;
|
||||
OPENSSL_free(mem);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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,
|
||||
@ -567,18 +735,9 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
|
||||
OSSL_STORE_INFO *result = NULL;
|
||||
int matchcount = -1;
|
||||
|
||||
if (ctx->last_handler != NULL) {
|
||||
result = ctx->last_handler->try_decode(NULL, NULL, NULL, 0,
|
||||
&ctx->last_handler_ctx,
|
||||
ui_method, ui_data);
|
||||
|
||||
if (result != NULL)
|
||||
return result;
|
||||
|
||||
ctx->last_handler->destroy_ctx(&ctx->last_handler_ctx);
|
||||
ctx->last_handler_ctx = NULL;
|
||||
ctx->last_handler = NULL;
|
||||
}
|
||||
result = file_load_try_repeat(ctx, ui_method, ui_data);
|
||||
if (result != NULL)
|
||||
return result;
|
||||
|
||||
if (file_error(ctx))
|
||||
return NULL;
|
||||
@ -587,130 +746,37 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
|
||||
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;
|
||||
|
||||
matchcount = -1;
|
||||
if (ctx->is_pem) {
|
||||
r = PEM_read_bio(ctx->file, &pem_name, &pem_header, &data, &len);
|
||||
if (r <= 0) {
|
||||
if (!file_read_pem(ctx->file, &pem_name, &pem_header, &data, &len,
|
||||
ui_method, ui_data)) {
|
||||
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;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
if ((len = asn1_d2i_read_bio(ctx->file, &mem)) < 0) {
|
||||
if (!file_read_asn1(ctx->file, &data, &len)) {
|
||||
if (!file_eof(ctx))
|
||||
ctx->errcnt++;
|
||||
goto err;
|
||||
}
|
||||
|
||||
data = (unsigned char *)mem->data;
|
||||
len = (long)mem->length;
|
||||
}
|
||||
|
||||
result = NULL;
|
||||
|
||||
{
|
||||
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, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
matchcount = 0;
|
||||
for (i = 0; i < OSSL_NELEM(file_handlers); i++) {
|
||||
const FILE_HANDLER *handler = file_handlers[i];
|
||||
void *tmp_handler_ctx = NULL;
|
||||
OSSL_STORE_INFO *tmp_result =
|
||||
handler->try_decode(pem_name, pem_header, data, len,
|
||||
&tmp_handler_ctx, ui_method, ui_data);
|
||||
|
||||
if (tmp_result == NULL) {
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, OSSL_STORE_R_IS_NOT_A);
|
||||
ERR_add_error_data(1, handler->name);
|
||||
} else {
|
||||
if (matching_handlers)
|
||||
matching_handlers[matchcount] = handler;
|
||||
|
||||
if (handler_ctx)
|
||||
handler->destroy_ctx(&handler_ctx);
|
||||
handler_ctx = tmp_handler_ctx;
|
||||
|
||||
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);
|
||||
if (handler->destroy_ctx != NULL)
|
||||
handler->destroy_ctx(&handler_ctx);
|
||||
handler_ctx = NULL;
|
||||
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);
|
||||
else if (matching_handlers[0]->repeatable) {
|
||||
ctx->last_handler = matching_handlers[0];
|
||||
ctx->last_handler_ctx = handler_ctx;
|
||||
mem = NULL;
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
OPENSSL_free(matching_handlers);
|
||||
}
|
||||
|
||||
if (result)
|
||||
ERR_clear_error();
|
||||
matchcount = -1;
|
||||
result = file_load_try_decode(ctx, pem_name, pem_header, data, len,
|
||||
ui_method, ui_data, &matchcount);
|
||||
|
||||
err:
|
||||
OPENSSL_free(pem_name);
|
||||
OPENSSL_free(pem_header);
|
||||
if (mem == NULL)
|
||||
OPENSSL_free(data);
|
||||
else
|
||||
BUF_MEM_free(mem);
|
||||
OPENSSL_free(data);
|
||||
} while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx));
|
||||
|
||||
/* We bail out on ambiguity */
|
||||
if (matchcount > 1)
|
||||
return NULL;
|
||||
|
||||
end:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,8 @@ 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_LOAD_TRY_DECODE, 0),
|
||||
"file_load_try_decode"},
|
||||
{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"},
|
||||
|
@ -24,6 +24,7 @@ int ERR_load_OSSL_STORE_strings(void);
|
||||
*/
|
||||
# define OSSL_STORE_F_FILE_GET_PASS 118
|
||||
# define OSSL_STORE_F_FILE_LOAD 119
|
||||
# define OSSL_STORE_F_FILE_LOAD_TRY_DECODE 124
|
||||
# define OSSL_STORE_F_FILE_OPEN 120
|
||||
# define OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT 100
|
||||
# define OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT 101
|
||||
|
Loading…
Reference in New Issue
Block a user