Adapt our decoder implementations to the new way to indicate succes / failure

This includes the special decoder used in our STOREMGMT 'file:' implementation

Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14834)
This commit is contained in:
Richard Levitte 2021-04-12 12:20:20 +02:00
parent f99659535d
commit 9cc97ddf3c
5 changed files with 91 additions and 51 deletions

View File

@ -36,26 +36,6 @@
#include "prov/implementations.h"
#include "endecoder_local.h"
#define SET_ERR_MARK() ERR_set_mark()
#define CLEAR_ERR_MARK() \
do { \
int err = ERR_peek_last_error(); \
\
if (ERR_GET_LIB(err) == ERR_LIB_ASN1 \
&& (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG \
|| ERR_GET_REASON(err) == ASN1_R_UNSUPPORTED_TYPE \
|| ERR_GET_REASON(err) == ERR_R_NESTED_ASN1_ERROR \
|| ERR_GET_REASON(err) == ASN1_R_NOT_ENOUGH_DATA)) \
ERR_pop_to_mark(); \
else \
ERR_clear_last_mark(); \
} while(0)
#define RESET_ERR_MARK() \
do { \
CLEAR_ERR_MARK(); \
SET_ERR_MARK(); \
} while(0)
struct der2key_ctx_st; /* Forward declaration */
typedef int check_key_fn(void *, struct der2key_ctx_st *ctx);
typedef void adjust_key_fn(void *, struct der2key_ctx_st *ctx);
@ -143,6 +123,7 @@ static void *der2key_decode_p8(const unsigned char **input_der,
void *key = NULL;
ctx->flag_fatal = 0;
if ((p8 = d2i_X509_SIG(NULL, input_der, input_der_len)) != NULL) {
char pbuf[PEM_BUFSIZE];
size_t plen = 0;
@ -162,6 +143,7 @@ static void *der2key_decode_p8(const unsigned char **input_der,
&& OBJ_obj2nid(alg->algorithm) == ctx->desc->evp_type)
key = key_from_pkcs8(p8inf, PROV_LIBCTX_OF(ctx->provctx), NULL);
PKCS8_PRIV_KEY_INFO_free(p8inf);
return key;
}
@ -284,12 +266,13 @@ static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
return 0;
}
SET_ERR_MARK();
if (!read_der(ctx->provctx, cin, &der, &der_len))
ok = read_der(ctx->provctx, cin, &der, &der_len);
if (!ok)
goto next;
ok = 0; /* Assume that we fail */
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
RESET_ERR_MARK();
derp = der;
if (ctx->desc->d2i_PKCS8 != NULL) {
key = ctx->desc->d2i_PKCS8(NULL, &derp, der_len, ctx,
@ -303,7 +286,6 @@ static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
goto next;
}
if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
RESET_ERR_MARK();
derp = der;
if (ctx->desc->d2i_PUBKEY != NULL)
key = ctx->desc->d2i_PUBKEY(NULL, &derp, der_len);
@ -313,19 +295,25 @@ static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
goto next;
}
if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) {
RESET_ERR_MARK();
derp = der;
if (ctx->desc->d2i_key_params != NULL)
key = ctx->desc->d2i_key_params(NULL, &derp, der_len);
if (key == NULL && orig_selection != 0)
goto next;
}
RESET_ERR_MARK();
/*
* Last minute check to see if this was the correct type of key. This
* should never lead to a fatal error, i.e. the decoding itself was
* correct, it was just an unexpected key type. This is generally for
* classes of key types that have subtle variants, like RSA-PSS keys as
* opposed to plain RSA keys.
*/
if (key != NULL
&& ctx->desc->check_key != NULL
&& !ctx->desc->check_key(key, ctx)) {
CLEAR_ERR_MARK();
goto end;
ctx->desc->free_key(key);
key = NULL;
}
if (key != NULL && ctx->desc->adjust_key != NULL)
@ -333,11 +321,10 @@ static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
next:
/*
* Prune low-level ASN.1 parse errors from error queue, assuming
* that this is called by decoder_process() in a loop trying several
* formats.
* Indicated that we successfully decoded something, or not at all.
* Ending up "empty handed" is not an error.
*/
CLEAR_ERR_MARK();
ok = 1;
/*
* We free memory here so it's not held up during the callback, because

View File

@ -116,30 +116,35 @@ static int msblob2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
if (BIO_read(in, hdr_buf, 16) != 16) {
ERR_raise(ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT);
goto err;
goto next;
}
ERR_set_mark();
p = hdr_buf;
if (ossl_do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) <= 0)
goto err;
ok = ossl_do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) > 0;
ERR_pop_to_mark();
if (!ok)
goto next;
ok = 0; /* Assume that we fail */
if ((isdss && ctx->desc->type != EVP_PKEY_DSA)
|| (!isdss && ctx->desc->type != EVP_PKEY_RSA))
goto err;
goto next;
length = ossl_blob_length(bitlen, isdss, ispub);
if (length > BLOB_MAX_LENGTH) {
ERR_raise(ERR_LIB_PEM, PEM_R_HEADER_TOO_LONG);
goto err;
goto next;
}
buf = OPENSSL_malloc(length);
if (buf == NULL) {
ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
goto err;
goto end;
}
p = buf;
if (BIO_read(in, buf, length) != (int)length) {
ERR_raise(ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT);
goto err;
goto next;
}
if ((selection == 0
@ -150,7 +155,7 @@ static int msblob2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
memset(&pwdata, 0, sizeof(pwdata));
if (!ossl_pw_set_ossl_passphrase_cb(&pwdata, pw_cb, pw_cbarg))
goto err;
goto end;
p = buf;
key = ctx->desc->read_private_key(&p, bitlen, ispub);
if (selection != 0 && key == NULL)
@ -170,6 +175,12 @@ static int msblob2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
ctx->desc->adjust_key(key, ctx);
next:
/*
* Indicated that we successfully decoded something, or not at all.
* Ending up "empty handed" is not an error.
*/
ok = 1;
/*
* We free resources here so it's not held up during the callback, because
* we know the process is recursive and the allocated chunks of memory
@ -198,7 +209,7 @@ static int msblob2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
ok = data_cb(params, data_cbarg);
}
err:
end:
BIO_free(in);
OPENSSL_free(buf);
ctx->desc->free_key(key);

View File

@ -145,9 +145,11 @@ static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
int objtype = OSSL_OBJECT_UNKNOWN;
const char *data_structure = NULL;
if (read_pem(ctx->provctx, cin, &pem_name, &pem_header,
&der, &der_len) <= 0)
return 0;
ok = read_pem(ctx->provctx, cin, &pem_name, &pem_header,
&der, &der_len) > 0;
/* We return "empty handed". This is not an error. */
if (!ok)
return 1;
/*
* 10 is the number of characters in "Proc-Type:", which
@ -159,6 +161,7 @@ static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
EVP_CIPHER_INFO cipher;
struct pem2der_pass_data_st pass_data;
ok = 0; /* Assume that we fail */
pass_data.cb = pw_cb;
pass_data.cbarg = pw_cbarg;
if (!PEM_get_EVP_CIPHER_INFO(pem_header, &cipher)
@ -167,6 +170,12 @@ static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
goto end;
}
/*
* Indicated that we successfully decoded something, or not at all.
* Ending up "empty handed" is not an error.
*/
ok = 1;
/*
* Peal off certain strings from the end of |pem_name|, as they serve
* no further purpose.

View File

@ -20,6 +20,7 @@
#include <openssl/core_object.h>
#include <openssl/crypto.h>
#include <openssl/params.h>
#include <openssl/err.h>
#include <openssl/pem.h> /* For public PVK functions */
#include <openssl/x509.h>
#include "internal/passphrase.h"
@ -111,11 +112,30 @@ static int pvk2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
|| (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
&& ctx->desc->read_private_key != NULL) {
struct ossl_passphrase_data_st pwdata;
int err, lib, reason;
memset(&pwdata, 0, sizeof(pwdata));
if (!ossl_pw_set_ossl_passphrase_cb(&pwdata, pw_cb, pw_cbarg))
goto end;
key = ctx->desc->read_private_key(in, ossl_pw_pem_password, &pwdata);
/*
* Because the PVK API doesn't have a separate decrypt call, we need
* to check the error queue for certain well known errors that are
* considered fatal and which we pass through, while the rest gets
* thrown away.
*/
err = ERR_peek_last_error();
lib = ERR_GET_LIB(err);
reason = ERR_GET_REASON(err);
if (lib == ERR_LIB_PEM
&& (reason == PEM_R_BAD_PASSWORD_READ
|| reason == PEM_R_BAD_DECRYPT)) {
ERR_clear_last_mark();
goto end;
}
if (selection != 0 && key == NULL)
goto next;
}
@ -124,6 +144,12 @@ static int pvk2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
ctx->desc->adjust_key(key, ctx);
next:
/*
* Indicated that we successfully decoded something, or not at all.
* Ending up "empty handed" is not an error.
*/
ok = 1;
/*
* We free resources here so it's not held up during the callback, because
* we know the process is recursive and the allocated chunks of memory

View File

@ -98,16 +98,22 @@ static int der2obj_decode(void *provctx, OSSL_CORE_BIO *cin, int selection,
* Prune low-level ASN.1 parse errors from error queue, assuming that
* this is called by decoder_process() in a loop trying several formats.
*/
err = ERR_peek_last_error();
if (ERR_GET_LIB(err) == ERR_LIB_ASN1
if (!ok) {
err = ERR_peek_last_error();
if (ERR_GET_LIB(err) == ERR_LIB_ASN1
&& (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG
|| ERR_GET_REASON(err) == ASN1_R_UNSUPPORTED_TYPE
|| ERR_GET_REASON(err) == ERR_R_NESTED_ASN1_ERROR
|| ERR_GET_REASON(err) == ASN1_R_NOT_ENOUGH_DATA))
ERR_pop_to_mark();
else
ERR_clear_last_mark();
if (ok) {
|| ERR_GET_REASON(err) == ASN1_R_NOT_ENOUGH_DATA)) {
ERR_pop_to_mark();
} else {
ERR_clear_last_mark();
goto end;
}
}
ok = 1;
if (mem != NULL) {
OSSL_PARAM params[3];
int object_type = OSSL_OBJECT_UNKNOWN;
@ -122,6 +128,7 @@ static int der2obj_decode(void *provctx, OSSL_CORE_BIO *cin, int selection,
OPENSSL_free(mem->data);
OPENSSL_free(mem);
}
end:
BIO_free(in);
return ok;
}