summaryrefslogtreecommitdiffstats
path: root/crypto/store
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2017-02-11 01:17:50 +0100
committerRichard Levitte <levitte@openssl.org>2017-06-29 11:55:32 +0200
commit1aabc2445b126f951707b287db9a9145b003f2ca (patch)
treeaeeda2157e35077ae728fbb4425234fedb592289 /crypto/store
parent50ecedda40d0e57c635d673c1e66cb688ed9719e (diff)
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)
Diffstat (limited to 'crypto/store')
-rw-r--r--crypto/store/loader_file.c288
-rw-r--r--crypto/store/store_err.c2
2 files changed, 179 insertions, 111 deletions
diff --git a/crypto/store/loader_file.c b/crypto/store/loader_file.c
index 558980a591..472e8197f8 100644
--- a/crypto/store/loader_file.c
+++ b/crypto/store/loader_file.c
@@ -559,26 +559,185 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
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)
+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;
- 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;
+ if (result == NULL) {
+ ctx->last_handler->destroy_ctx(&ctx->last_handler_ctx);
+ ctx->last_handler_ctx = NULL;
+ ctx->last_handler = NULL;
+ }
+ }
+ return result;
+}
- ctx->last_handler->destroy_ctx(&ctx->last_handler_ctx);
- ctx->last_handler_ctx = NULL;
- ctx->last_handler = NULL;
+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,
+ const UI_METHOD *ui_method, void *ui_data)
+{
+ OSSL_STORE_INFO *result = NULL;
+ int matchcount = -1;
+
+ 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;
}
diff --git a/crypto/store/store_err.c b/crypto/store/store_err.c
index 0f3a6a142e..57627ebdec 100644
--- a/crypto/store/store_err.c
+++ b/crypto/store/store_err.c
@@ -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"},