The branch master has been updated via 113adc1f61ce56cc3fcb7404fb521988b792750c (commit) via 25cf949fc620ff7053e51acca3ec4d0fd094f8b0 (commit) from 3094351625f0b222f92c22ce4943461df8c7e301 (commit)
- Log ----------------------------------------------------------------- commit 113adc1f61ce56cc3fcb7404fb521988b792750c Author: Richard Levitte <levi...@openssl.org> Date: Mon Oct 5 14:27:37 2020 +0200 Adapt some code to OSSL_ENCODER_to_data() / OSSL_DECODER_from_data() The functions i2d_PrivateKey(), try_key_value() i store_result.c and X509_PUBKEY_set() were all essentially duplicating this functionality to some degree. Reviewed-by: Tomas Mraz <tm...@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/13094) commit 25cf949fc620ff7053e51acca3ec4d0fd094f8b0 Author: Richard Levitte <levi...@openssl.org> Date: Mon Oct 5 14:23:55 2020 +0200 ENCODER / DECODER: Add functions to encode/decode to/from a buffer This adds OSSL_ENCODER_to_data() and OSSL_DECODER_from_data(). These functions allow fairly simple rewrites of type-specific i2d and d2i calls. Reviewed-by: Tomas Mraz <tm...@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/13094) ----------------------------------------------------------------------- Summary of changes: crypto/asn1/i2d_pr.c | 32 +++++++------------------ crypto/encode_decode/decoder_lib.c | 21 +++++++++++++++++ crypto/encode_decode/encoder_lib.c | 48 ++++++++++++++++++++++++++++++++++++++ crypto/store/store_result.c | 10 +++----- crypto/x509/x_pubkey.c | 14 +++++------ doc/man3/OSSL_DECODER_from_bio.pod | 9 +++++++ doc/man3/OSSL_ENCODER_to_bio.pod | 30 ++++++++++++++++++------ include/openssl/decoder.h | 2 ++ include/openssl/encoder.h | 2 ++ util/libcrypto.num | 2 ++ 10 files changed, 126 insertions(+), 44 deletions(-) diff --git a/crypto/asn1/i2d_pr.c b/crypto/asn1/i2d_pr.c index e35781f4bd..80cfde9a22 100644 --- a/crypto/asn1/i2d_pr.c +++ b/crypto/asn1/i2d_pr.c @@ -8,6 +8,7 @@ */ #include <stdio.h> +#include <limits.h> #include "internal/cryptlib.h" #include <openssl/evp.h> #include <openssl/encoder.h> @@ -30,35 +31,20 @@ int i2d_PrivateKey(const EVP_PKEY *a, unsigned char **pp) } return ret; } - if (a->keymgmt != NULL) { + if (evp_pkey_is_provided(a)) { + /* |*pp| is unbounded, so we need an upper limit */ + size_t length = INT_MAX; /* The private key includes everything */ int selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS | OSSL_KEYMGMT_SELECT_KEYPAIR; - OSSL_ENCODER_CTX *ctx = - OSSL_ENCODER_CTX_new_by_EVP_PKEY(a, "DER", selection, NULL, NULL); - BIO *out = BIO_new(BIO_s_mem()); - BUF_MEM *buf = NULL; int ret = -1; + OSSL_ENCODER_CTX *ctx; - if (ctx != NULL - && out != NULL + if ((ctx = OSSL_ENCODER_CTX_new_by_EVP_PKEY(a, "DER", selection, + NULL, NULL)) != NULL && OSSL_ENCODER_CTX_get_num_encoders(ctx) != 0 - && OSSL_ENCODER_to_bio(ctx, out) - && BIO_get_mem_ptr(out, &buf) > 0) { - ret = buf->length; - - if (pp != NULL) { - if (*pp == NULL) { - *pp = (unsigned char *)buf->data; - buf->length = 0; - buf->data = NULL; - } else { - memcpy(*pp, buf->data, ret); - *pp += ret; - } - } - } - BIO_free(out); + && OSSL_ENCODER_to_data(ctx, pp, &length)) + ret = (int)length; OSSL_ENCODER_CTX_free(ctx); return ret; } diff --git a/crypto/encode_decode/decoder_lib.c b/crypto/encode_decode/decoder_lib.c index e44ca8cbd4..192d33089b 100644 --- a/crypto/encode_decode/decoder_lib.c +++ b/crypto/encode_decode/decoder_lib.c @@ -77,6 +77,27 @@ int OSSL_DECODER_from_fp(OSSL_DECODER_CTX *ctx, FILE *fp) } #endif +int OSSL_DECODER_from_data(OSSL_DECODER_CTX *ctx, const unsigned char **pdata, + size_t *pdata_len) +{ + BIO *membio; + int ret = 0; + + if (pdata == NULL || *pdata == NULL || pdata_len == NULL) { + ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + membio = BIO_new_mem_buf(*pdata, (int)*pdata_len); + if (OSSL_DECODER_from_bio(ctx, membio)) { + *pdata_len = (size_t)BIO_get_mem_data(membio, pdata); + ret = 1; + } + BIO_free(membio); + + return ret; +} + int OSSL_DECODER_CTX_set_input_type(OSSL_DECODER_CTX *ctx, const char *input_type) { diff --git a/crypto/encode_decode/encoder_lib.c b/crypto/encode_decode/encoder_lib.c index 179c6d3dc3..6d3aa279d7 100644 --- a/crypto/encode_decode/encoder_lib.c +++ b/crypto/encode_decode/encoder_lib.c @@ -49,6 +49,54 @@ int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp) } #endif +int OSSL_ENCODER_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata, + size_t *pdata_len) +{ + BIO *out = BIO_new(BIO_s_mem()); + BUF_MEM *buf = NULL; + int ret = 0; + + if (pdata_len == NULL) { + ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (OSSL_ENCODER_to_bio(ctx, out) + && BIO_get_mem_ptr(out, &buf) > 0) { + ret = 1; /* Hope for the best. A too small buffer will clear this */ + + if (pdata != NULL && *pdata != NULL) { + if (*pdata_len < buf->length) + /* + * It's tempting to do |*pdata_len = (size_t)buf->length| + * However, it's believed to be confusing more than helpful, + * so we don't. + */ + ret = 0; + else + *pdata_len -= buf->length; + } else { + /* The buffer with the right size is already allocated for us */ + *pdata_len = (size_t)buf->length; + } + + if (ret) { + if (pdata != NULL) { + if (*pdata != NULL) { + memcpy(*pdata, buf->data, buf->length); + *pdata += buf->length; + } else { + /* In this case, we steal the data from BIO_s_mem() */ + *pdata = (unsigned char *)buf->data; + buf->data = NULL; + } + } + } + } + BIO_free(out); + return ret; +} + int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx, const char *output_type) { diff --git a/crypto/store/store_result.c b/crypto/store/store_result.c index 8ba4f8880c..200544d72d 100644 --- a/crypto/store/store_result.c +++ b/crypto/store/store_result.c @@ -251,21 +251,17 @@ static EVP_PKEY *try_key_value(struct extracted_param_data_st *data, { EVP_PKEY *pk = NULL; OSSL_DECODER_CTX *decoderctx = NULL; - BIO *membio = - BIO_new_mem_buf(data->octet_data, (int)data->octet_data_size); - - if (membio == NULL) - return 0; + const unsigned char *pdata = data->octet_data; + size_t pdatalen = data->octet_data_size; decoderctx = OSSL_DECODER_CTX_new_by_EVP_PKEY(&pk, "DER", NULL, libctx, propq); (void)OSSL_DECODER_CTX_set_passphrase_cb(decoderctx, cb, cbarg); /* No error if this couldn't be decoded */ - (void)OSSL_DECODER_from_bio(decoderctx, membio); + (void)OSSL_DECODER_from_data(decoderctx, &pdata, &pdatalen); OSSL_DECODER_CTX_free(decoderctx); - BIO_free(membio); return pk; } diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c index d63a33e301..bd6a65e1c5 100644 --- a/crypto/x509/x_pubkey.c +++ b/crypto/x509/x_pubkey.c @@ -98,25 +98,25 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) X509err(X509_F_X509_PUBKEY_SET, X509_R_METHOD_NOT_SUPPORTED); goto error; } - } else if (pkey->keymgmt != NULL) { + } else if (evp_pkey_is_provided(pkey)) { const OSSL_PROVIDER *pkprov = EVP_KEYMGMT_provider(pkey->keymgmt); OPENSSL_CTX *libctx = ossl_provider_library_context(pkprov); - BIO *bmem = BIO_new(BIO_s_mem()); + unsigned char *der = NULL; + size_t derlen = 0; int selection = (OSSL_KEYMGMT_SELECT_PUBLIC_KEY | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS); OSSL_ENCODER_CTX *ectx = OSSL_ENCODER_CTX_new_by_EVP_PKEY(pkey, "DER", selection, libctx, NULL); - if (OSSL_ENCODER_to_bio(ectx, bmem)) { - const unsigned char *der = NULL; - long derlen = BIO_get_mem_data(bmem, (char **)&der); + if (OSSL_ENCODER_to_data(ectx, &der, &derlen)) { + const unsigned char *pder = der; - pk = d2i_X509_PUBKEY(NULL, &der, derlen); + pk = d2i_X509_PUBKEY(NULL, &pder, (long)derlen); } OSSL_ENCODER_CTX_free(ectx); - BIO_free(bmem); + OPENSSL_free(der); } if (pk == NULL) diff --git a/doc/man3/OSSL_DECODER_from_bio.pod b/doc/man3/OSSL_DECODER_from_bio.pod index 7de550746e..3bd43200d3 100644 --- a/doc/man3/OSSL_DECODER_from_bio.pod +++ b/doc/man3/OSSL_DECODER_from_bio.pod @@ -2,6 +2,7 @@ =head1 NAME +OSSL_DECODER_from_data, OSSL_DECODER_from_bio, OSSL_DECODER_from_fp - Routines to perform a decoding @@ -12,6 +13,8 @@ OSSL_DECODER_from_fp int OSSL_DECODER_from_bio(OSSL_DECODER_CTX *ctx, BIO *in); int OSSL_DECODER_from_fp(OSSL_DECODER_CTX *ctx, FILE *fp); + int OSSL_DECODER_from_data(OSSL_DECODER_CTX *ctx, const unsigned char **pdata, + size_t *pdata_len); Feature availability macros: @@ -24,6 +27,12 @@ is undefined. =head1 DESCRIPTION +OSSL_DECODER_from_data() runs the decoding process for the context I<ctx>, +with input coming from I<*pdata>, I<*pdata_len> bytes long. Both I<*pdata> +and I<*pdata_len> must be non-NULL. When OSSL_DECODER_from_data() returns, +I<*pdata> is updated to point at the location after what has been decoded, +and I<*pdata_len> to have the number of remaining bytes. + OSSL_DECODER_from_bio() runs the decoding process for the context I<ctx>, with the input coming from the B<BIO> I<in>. Should it make a difference, it's recommended to have the BIO set in binary mode rather than text mode. diff --git a/doc/man3/OSSL_ENCODER_to_bio.pod b/doc/man3/OSSL_ENCODER_to_bio.pod index 6f75f592e4..f28228bf10 100644 --- a/doc/man3/OSSL_ENCODER_to_bio.pod +++ b/doc/man3/OSSL_ENCODER_to_bio.pod @@ -2,6 +2,7 @@ =head1 NAME +OSSL_ENCODER_to_data, OSSL_ENCODER_to_bio, OSSL_ENCODER_to_fp - Routines to perform an encoding @@ -10,6 +11,8 @@ OSSL_ENCODER_to_fp #include <openssl/encoder.h> + int OSSL_ENCODER_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata, + size_t *pdata_len); int OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out); int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp); @@ -24,20 +27,33 @@ is undefined. =head1 DESCRIPTION +OSSL_ENCODER_to_data() runs the encoding process for the context I<ctx>, +with the output going to the I<*pdata> and I<*pdata_len>. +If I<*pdata> is NULL when OSSL_ENCODER_to_data() is called, a buffer will be +allocated using L<OPENSSL_zalloc(3)>, and I<*pdata> will be set to point at +the start of that buffer, and I<*pdata_len> will be assigned its length when +OSSL_ENCODER_to_data() returns. +If I<*pdata> is non-NULL when OSSL_ENCODER_to_data() is called, I<*pdata_len> +is assumed to have its size. In this case, I<*pdata> will be set to point +after the encoded bytes, and I<*pdata_len> will be assigned the number of +remaining bytes. + OSSL_ENCODER_to_bio() runs the encoding process for the context I<ctx>, with -the output going to the B<BIO> I<out>. The application is required to set -up the B<BIO> properly, for example to have it in text or binary mode if -that's appropriate. +the output going to the B<BIO> I<out>. + +OSSL_ENCODER_to_fp() does the same thing as OSSL_ENCODER_to_bio(), except +that the output is going to the B<FILE> I<fp>. =for comment Know your encoder! -OSSL_ENCODER_to_fp() does the same thing as OSSL_ENCODER_to_bio(), -except that the output is going to the B<FILE> I<fp>. +For OSSL_ENCODER_to_bio() and OSSL_ENCODER_to_fp(), the application is +required to set up the B<BIO> or B<FILE> properly, for example to have +it in text or binary mode as is appropriate for the encoder output type. =head1 RETURN VALUES -OSSL_ENCODER_to_bio() and OSSL_ENCODER_to_fp() return 1 on success, or 0 on -failure. +OSSL_ENCODER_to_bio(), OSSL_ENCODER_to_fp() and OSSL_ENCODER_to_data() +return 1 on success, or 0 on failure. =begin comment TODO(3.0) Add examples! diff --git a/include/openssl/decoder.h b/include/openssl/decoder.h index 66790f43c8..1eb1cbe543 100644 --- a/include/openssl/decoder.h +++ b/include/openssl/decoder.h @@ -106,6 +106,8 @@ int OSSL_DECODER_from_bio(OSSL_DECODER_CTX *ctx, BIO *in); #ifndef OPENSSL_NO_STDIO int OSSL_DECODER_from_fp(OSSL_DECODER_CTX *ctx, FILE *in); #endif +int OSSL_DECODER_from_data(OSSL_DECODER_CTX *ctx, const unsigned char **pdata, + size_t *pdata_len); /* * Create the OSSL_DECODER_CTX with an associated type. This will perform diff --git a/include/openssl/encoder.h b/include/openssl/encoder.h index 6698769e24..2d8871df12 100644 --- a/include/openssl/encoder.h +++ b/include/openssl/encoder.h @@ -101,6 +101,8 @@ int OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out); #ifndef OPENSSL_NO_STDIO int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp); #endif +int OSSL_ENCODER_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata, + size_t *pdata_len); /* * Create the OSSL_ENCODER_CTX with an associated type. This will perform diff --git a/util/libcrypto.num b/util/libcrypto.num index 05e006eb72..fb0069c9e8 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5286,3 +5286,5 @@ EVP_KEM_gettable_ctx_params ? 3_0_0 EXIST::FUNCTION: EVP_KEM_settable_ctx_params ? 3_0_0 EXIST::FUNCTION: PKCS7_type_is_other ? 3_0_0 EXIST::FUNCTION: PKCS7_get_octet_string ? 3_0_0 EXIST::FUNCTION: +OSSL_DECODER_from_data ? 3_0_0 EXIST::FUNCTION: +OSSL_ENCODER_to_data ? 3_0_0 EXIST::FUNCTION: