From: Richard Levitte Date: Thu, 25 Jul 2024 10:34:06 +0000 (+0200) Subject: feat: Implement EVP_CIPHER_CTX_{set,get}_algor_params() and EVP_CIPHER_CTX_get_algor() X-Git-Tag: openssl-3.4.0-alpha1~45 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=258aaa97b86aab7fef3c6170d59053842ce2e253;p=thirdparty%2Fopenssl.git feat: Implement EVP_CIPHER_CTX_{set,get}_algor_params() and EVP_CIPHER_CTX_get_algor() EVP_CIPHER_CTX_set_algor_params() and EVP_CIPHER_CTX_set_algor_params() can be used instead of EVP_CIPHER_asn1_to_param() and EVP_CIPHER_param_to_asn1(). Reviewed-by: Matt Caswell Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/25000) --- diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 88830a3cd2b..007db19b768 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -739,6 +739,8 @@ EVP_R_EXPECTING_A_POLY1305_KEY:164:expecting a poly1305 key EVP_R_EXPECTING_A_SIPHASH_KEY:175:expecting a siphash key EVP_R_FINAL_ERROR:188:final error EVP_R_GENERATE_ERROR:214:generate error +EVP_R_GETTING_ALGORITHMIDENTIFIER_NOT_SUPPORTED:229:\ + getting AlgorithmIdentifier not supported EVP_R_GET_RAW_KEY_FAILED:182:get raw key failed EVP_R_ILLEGAL_SCRYPT_PARAMETERS:171:illegal scrypt parameters EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS:204:inaccessible domain parameters diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index ffac813db25..48ec7ae15e0 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -71,6 +71,8 @@ static const ERR_STRING_DATA EVP_str_reasons[] = { "expecting a siphash key"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_FINAL_ERROR), "final error"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_GENERATE_ERROR), "generate error"}, + {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_GETTING_ALGORITHMIDENTIFIER_NOT_SUPPORTED), + "getting AlgorithmIdentifier not supported"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_GET_RAW_KEY_FAILED), "get raw key failed"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_ILLEGAL_SCRYPT_PARAMETERS), "illegal scrypt parameters"}, diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c index e80c2ba6812..9ae4afd42a0 100644 --- a/crypto/evp/evp_lib.c +++ b/crypto/evp/evp_lib.c @@ -17,6 +17,7 @@ #include #include "internal/cryptlib.h" #include +#include #include #include #include @@ -127,37 +128,13 @@ int evp_cipher_param_to_asn1_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type, ret = EVP_CIPHER_set_asn1_iv(c, type); } } else if (cipher->prov != NULL) { - OSSL_PARAM params[3], *p = params; - unsigned char *der = NULL, *derp; + /* We cheat, there's no need for an object ID for this use */ + X509_ALGOR alg; - /* - * We make two passes, the first to get the appropriate buffer size, - * and the second to get the actual value. - */ - *p++ = OSSL_PARAM_construct_octet_string( - OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS, - NULL, 0); - *p = OSSL_PARAM_construct_end(); - - if (!EVP_CIPHER_CTX_get_params(c, params)) - goto err; - - /* ... but, we should get a return size too! */ - if (OSSL_PARAM_modified(params) - && params[0].return_size != 0 - && (der = OPENSSL_malloc(params[0].return_size)) != NULL) { - params[0].data = der; - params[0].data_size = params[0].return_size; - OSSL_PARAM_set_all_unmodified(params); - derp = der; - if (EVP_CIPHER_CTX_get_params(c, params) - && OSSL_PARAM_modified(params) - && d2i_ASN1_TYPE(&type, (const unsigned char **)&derp, - params[0].return_size) != NULL) { - ret = 1; - } - OPENSSL_free(der); - } + alg.algorithm = NULL; + alg.parameter = type; + + ret = EVP_CIPHER_CTX_get_algor_params(c, &alg); } else { ret = -2; } @@ -220,20 +197,13 @@ int evp_cipher_asn1_to_param_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type, ret = EVP_CIPHER_get_asn1_iv(c, type) >= 0 ? 1 : -1; } } else if (cipher->prov != NULL) { - OSSL_PARAM params[3], *p = params; - unsigned char *der = NULL; - int derl = -1; - - if ((derl = i2d_ASN1_TYPE(type, &der)) >= 0) { - *p++ = - OSSL_PARAM_construct_octet_string( - OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS, - der, (size_t)derl); - *p = OSSL_PARAM_construct_end(); - if (EVP_CIPHER_CTX_set_params(c, params)) - ret = 1; - OPENSSL_free(der); - } + /* We cheat, there's no need for an object ID for this use */ + X509_ALGOR alg; + + alg.algorithm = NULL; + alg.parameter = type; + + ret = EVP_CIPHER_CTX_set_algor_params(c, &alg); } else { ret = -2; } @@ -1248,4 +1218,130 @@ EVP_PKEY *EVP_PKEY_Q_keygen(OSSL_LIB_CTX *libctx, const char *propq, return ret; } +int EVP_CIPHER_CTX_set_algor_params(EVP_CIPHER_CTX *ctx, const X509_ALGOR *alg) +{ + int ret = -1; /* Assume the worst */ + unsigned char *der = NULL; + int derl = -1; + + if ((derl = i2d_ASN1_TYPE(alg->parameter, &der)) >= 0) { + const char *k_old = OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS_OLD; + const char *k_new = OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS; + OSSL_PARAM params[3]; + + /* + * Passing the same data with both the old (deprecated) and the + * new AlgID parameters OSSL_PARAM key. + */ + params[0] = OSSL_PARAM_construct_octet_string(k_old, der, (size_t)derl); + params[1] = OSSL_PARAM_construct_octet_string(k_new, der, (size_t)derl); + params[2] = OSSL_PARAM_construct_end(); + ret = EVP_CIPHER_CTX_set_params(ctx, params); + } + OPENSSL_free(der); + return ret; +} + +int EVP_CIPHER_CTX_get_algor_params(EVP_CIPHER_CTX *ctx, X509_ALGOR *alg) +{ + int ret = -1; /* Assume the worst */ + unsigned char *der = NULL; + size_t derl; + ASN1_TYPE *type = NULL; + int i = -1; + const char *k_old = OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS_OLD; + const char *k_new = OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS; + const char *derk; + OSSL_PARAM params[3]; + + /* + * We make two passes, the first to get the appropriate buffer size, + * and the second to get the actual value. + * Also, using both the old (deprecated) and the new AlgID parameters + * OSSL_PARAM key, and using whichever the provider responds to. + * Should the provider respond on both, the new key takes priority. + */ + params[0] = OSSL_PARAM_construct_octet_string(k_old, NULL, 0); + params[1] = OSSL_PARAM_construct_octet_string(k_new, NULL, 0); + params[2] = OSSL_PARAM_construct_end(); + + if (!EVP_CIPHER_CTX_get_params(ctx, params)) + goto err; + + /* ... but, we should get a return size too! */ + if (OSSL_PARAM_modified(¶ms[0]) && params[0].return_size != 0) + i = 0; + if (OSSL_PARAM_modified(¶ms[1]) && params[1].return_size != 0) + i = 1; + + /* + * If alg->parameter is non-NULL, it will be changed by d2i_ASN1_TYPE() + * below. If it is NULL, the d2i_ASN1_TYPE() call will allocate new + * space for it. Either way, alg->parameter can be safely assigned + * with type after the d2i_ASN1_TYPE() call, with the safety that it + * will be ok. + */ + type = alg->parameter; + + derk = params[i].key; + derl = params[i].return_size; + if (i >= 0 && (der = OPENSSL_malloc(derl)) != NULL) { + unsigned char *derp = der; + + params[i] = OSSL_PARAM_construct_octet_string(derk, der, derl); + if (EVP_CIPHER_CTX_get_params(ctx, params) + && OSSL_PARAM_modified(¶ms[i]) + && d2i_ASN1_TYPE(&type, (const unsigned char **)&derp, + (int)derl) != NULL) { + /* + * Don't free alg->parameter, see comment further up. + * Worst case, alg->parameter gets assigned its own value. + */ + alg->parameter = type; + ret = 1; + } + } + err: + OPENSSL_free(der); + return ret; +} + +int EVP_CIPHER_CTX_get_algor(EVP_CIPHER_CTX *ctx, X509_ALGOR **alg) +{ + int ret = -1; /* Assume the worst */ + OSSL_PARAM params[2]; + size_t aid_len = 0; + const char *k_aid = OSSL_SIGNATURE_PARAM_ALGORITHM_ID; + + params[0] = OSSL_PARAM_construct_octet_string(k_aid, NULL, 0); + params[1] = OSSL_PARAM_construct_end(); + + if (EVP_CIPHER_CTX_get_params(ctx, params) <= 0) + goto err; + + if (OSSL_PARAM_modified(¶ms[0])) + aid_len = params[0].return_size; + if (aid_len == 0) { + ERR_raise(ERR_LIB_EVP, EVP_R_GETTING_ALGORITHMIDENTIFIER_NOT_SUPPORTED); + ret = -2; + goto err; + } + if (alg != NULL) { + unsigned char *aid = NULL; + const unsigned char *pp = NULL; + + if ((aid = OPENSSL_malloc(aid_len)) != NULL) { + params[0] = OSSL_PARAM_construct_octet_string(k_aid, aid, aid_len); + pp = aid; + if (EVP_CIPHER_CTX_get_params(ctx, params) + && OSSL_PARAM_modified(¶ms[0]) + && d2i_X509_ALGOR(alg, &pp, aid_len) != NULL) + ret = 1; + } + OPENSSL_free(aid); + } + err: + return ret; +} + #endif /* !defined(FIPS_MODULE) */ diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 97ca2a08319..5ca10346b24 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -895,6 +895,10 @@ const OSSL_PARAM *EVP_CIPHER_gettable_ctx_params(const EVP_CIPHER *cipher); const OSSL_PARAM *EVP_CIPHER_CTX_settable_params(EVP_CIPHER_CTX *ctx); const OSSL_PARAM *EVP_CIPHER_CTX_gettable_params(EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_set_algor_params(EVP_CIPHER_CTX *ctx, const X509_ALGOR *alg); +int EVP_CIPHER_CTX_get_algor_params(EVP_CIPHER_CTX *ctx, X509_ALGOR *alg); +int EVP_CIPHER_CTX_get_algor(EVP_CIPHER_CTX *ctx, X509_ALGOR **alg); + const BIO_METHOD *BIO_f_md(void); const BIO_METHOD *BIO_f_base64(void); const BIO_METHOD *BIO_f_cipher(void); diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h index 2d879342242..0a991f735a0 100644 --- a/include/openssl/evperr.h +++ b/include/openssl/evperr.h @@ -54,6 +54,7 @@ # define EVP_R_EXPECTING_A_SIPHASH_KEY 175 # define EVP_R_FINAL_ERROR 188 # define EVP_R_GENERATE_ERROR 214 +# define EVP_R_GETTING_ALGORITHMIDENTIFIER_NOT_SUPPORTED 229 # define EVP_R_GET_RAW_KEY_FAILED 182 # define EVP_R_ILLEGAL_SCRYPT_PARAMETERS 171 # define EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS 204 diff --git a/util/libcrypto.num b/util/libcrypto.num index 57c1e4686cd..351df4de982 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5726,3 +5726,6 @@ EVP_PKEY_verify_message_init ? 3_4_0 EXIST::FUNCTION: EVP_PKEY_verify_message_update ? 3_4_0 EXIST::FUNCTION: EVP_PKEY_verify_message_final ? 3_4_0 EXIST::FUNCTION: EVP_PKEY_verify_recover_init_ex2 ? 3_4_0 EXIST::FUNCTION: +EVP_CIPHER_CTX_set_algor_params ? 3_4_0 EXIST::FUNCTION: +EVP_CIPHER_CTX_get_algor_params ? 3_4_0 EXIST::FUNCTION: +EVP_CIPHER_CTX_get_algor ? 3_4_0 EXIST::FUNCTION: