diff options
| author | Enji Cooper <ngie@FreeBSD.org> | 2023-03-01 04:21:31 +0000 |
|---|---|---|
| committer | Enji Cooper <ngie@FreeBSD.org> | 2023-03-06 20:41:29 +0000 |
| commit | e4520c8bd1d300a7a338d0ed4af171a2d0e583ef (patch) | |
| tree | 26fed32699a59a50cfbc90a2eb4dac39b498d9ae /providers/implementations | |
| parent | 3c320f4e5ee3d575d48eee7edddbafa059bce3c9 (diff) | |
Diffstat (limited to 'providers/implementations')
223 files changed, 49133 insertions, 0 deletions
diff --git a/providers/implementations/asymciphers/build.info b/providers/implementations/asymciphers/build.info new file mode 100644 index 000000000000..dbca47368488 --- /dev/null +++ b/providers/implementations/asymciphers/build.info @@ -0,0 +1,11 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$RSA_GOAL=../../libdefault.a ../../libfips.a +$SM2_GOAL=../../libdefault.a + +SOURCE[$RSA_GOAL]=rsa_enc.c + +IF[{- !$disabled{"sm2"} -}] + SOURCE[$SM2_GOAL]=sm2_enc.c +ENDIF diff --git a/providers/implementations/asymciphers/rsa_enc.c b/providers/implementations/asymciphers/rsa_enc.c new file mode 100644 index 000000000000..568452ec56a2 --- /dev/null +++ b/providers/implementations/asymciphers/rsa_enc.c @@ -0,0 +1,588 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * RSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/crypto.h> +#include <openssl/evp.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/rsa.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +/* Just for SSL_MAX_MASTER_KEY_LENGTH */ +#include <openssl/prov_ssl.h> +#include "internal/constant_time.h" +#include "internal/sizes.h" +#include "crypto/rsa.h" +#include "prov/provider_ctx.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/securitycheck.h" + +#include <stdlib.h> + +static OSSL_FUNC_asym_cipher_newctx_fn rsa_newctx; +static OSSL_FUNC_asym_cipher_encrypt_init_fn rsa_encrypt_init; +static OSSL_FUNC_asym_cipher_encrypt_fn rsa_encrypt; +static OSSL_FUNC_asym_cipher_decrypt_init_fn rsa_decrypt_init; +static OSSL_FUNC_asym_cipher_decrypt_fn rsa_decrypt; +static OSSL_FUNC_asym_cipher_freectx_fn rsa_freectx; +static OSSL_FUNC_asym_cipher_dupctx_fn rsa_dupctx; +static OSSL_FUNC_asym_cipher_get_ctx_params_fn rsa_get_ctx_params; +static OSSL_FUNC_asym_cipher_gettable_ctx_params_fn rsa_gettable_ctx_params; +static OSSL_FUNC_asym_cipher_set_ctx_params_fn rsa_set_ctx_params; +static OSSL_FUNC_asym_cipher_settable_ctx_params_fn rsa_settable_ctx_params; + +static OSSL_ITEM padding_item[] = { + { RSA_PKCS1_PADDING, OSSL_PKEY_RSA_PAD_MODE_PKCSV15 }, + { RSA_NO_PADDING, OSSL_PKEY_RSA_PAD_MODE_NONE }, + { RSA_PKCS1_OAEP_PADDING, OSSL_PKEY_RSA_PAD_MODE_OAEP }, /* Correct spelling first */ + { RSA_PKCS1_OAEP_PADDING, "oeap" }, + { RSA_X931_PADDING, OSSL_PKEY_RSA_PAD_MODE_X931 }, + { 0, NULL } +}; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes RSA structures, so + * we use that here too. + */ + +typedef struct { + OSSL_LIB_CTX *libctx; + RSA *rsa; + int pad_mode; + int operation; + /* OAEP message digest */ + EVP_MD *oaep_md; + /* message digest for MGF1 */ + EVP_MD *mgf1_md; + /* OAEP label */ + unsigned char *oaep_label; + size_t oaep_labellen; + /* TLS padding */ + unsigned int client_version; + unsigned int alt_version; +} PROV_RSA_CTX; + +static void *rsa_newctx(void *provctx) +{ + PROV_RSA_CTX *prsactx; + + if (!ossl_prov_is_running()) + return NULL; + prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX)); + if (prsactx == NULL) + return NULL; + prsactx->libctx = PROV_LIBCTX_OF(provctx); + + return prsactx; +} + +static int rsa_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[], + int operation) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (!ossl_prov_is_running() || prsactx == NULL || vrsa == NULL) + return 0; + + if (!ossl_rsa_check_key(prsactx->libctx, vrsa, operation)) + return 0; + + if (!RSA_up_ref(vrsa)) + return 0; + RSA_free(prsactx->rsa); + prsactx->rsa = vrsa; + prsactx->operation = operation; + + switch (RSA_test_flags(prsactx->rsa, RSA_FLAG_TYPE_MASK)) { + case RSA_FLAG_TYPE_RSA: + prsactx->pad_mode = RSA_PKCS1_PADDING; + break; + default: + /* This should not happen due to the check above */ + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return 0; + } + return rsa_set_ctx_params(prsactx, params); +} + +static int rsa_encrypt_init(void *vprsactx, void *vrsa, + const OSSL_PARAM params[]) +{ + return rsa_init(vprsactx, vrsa, params, EVP_PKEY_OP_ENCRYPT); +} + +static int rsa_decrypt_init(void *vprsactx, void *vrsa, + const OSSL_PARAM params[]) +{ + return rsa_init(vprsactx, vrsa, params, EVP_PKEY_OP_DECRYPT); +} + +static int rsa_encrypt(void *vprsactx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, size_t inlen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + int ret; + + if (!ossl_prov_is_running()) + return 0; + + if (out == NULL) { + size_t len = RSA_size(prsactx->rsa); + + if (len == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + *outlen = len; + return 1; + } + + if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING) { + int rsasize = RSA_size(prsactx->rsa); + unsigned char *tbuf; + + if ((tbuf = OPENSSL_malloc(rsasize)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + if (prsactx->oaep_md == NULL) { + OPENSSL_free(tbuf); + prsactx->oaep_md = EVP_MD_fetch(prsactx->libctx, "SHA-1", NULL); + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return 0; + } + ret = + ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex(prsactx->libctx, tbuf, + rsasize, in, inlen, + prsactx->oaep_label, + prsactx->oaep_labellen, + prsactx->oaep_md, + prsactx->mgf1_md); + + if (!ret) { + OPENSSL_free(tbuf); + return 0; + } + ret = RSA_public_encrypt(rsasize, tbuf, out, prsactx->rsa, + RSA_NO_PADDING); + OPENSSL_free(tbuf); + } else { + ret = RSA_public_encrypt(inlen, in, out, prsactx->rsa, + prsactx->pad_mode); + } + /* A ret value of 0 is not an error */ + if (ret < 0) + return ret; + *outlen = ret; + return 1; +} + +static int rsa_decrypt(void *vprsactx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, size_t inlen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + int ret; + size_t len = RSA_size(prsactx->rsa); + + if (!ossl_prov_is_running()) + return 0; + + if (prsactx->pad_mode == RSA_PKCS1_WITH_TLS_PADDING) { + if (out == NULL) { + *outlen = SSL_MAX_MASTER_KEY_LENGTH; + return 1; + } + if (outsize < SSL_MAX_MASTER_KEY_LENGTH) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); + return 0; + } + } else { + if (out == NULL) { + if (len == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + *outlen = len; + return 1; + } + + if (outsize < len) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); + return 0; + } + } + + if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING + || prsactx->pad_mode == RSA_PKCS1_WITH_TLS_PADDING) { + unsigned char *tbuf; + + if ((tbuf = OPENSSL_malloc(len)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + ret = RSA_private_decrypt(inlen, in, tbuf, prsactx->rsa, + RSA_NO_PADDING); + /* + * With no padding then, on success ret should be len, otherwise an + * error occurred (non-constant time) + */ + if (ret != (int)len) { + OPENSSL_free(tbuf); + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_DECRYPT); + return 0; + } + if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING) { + if (prsactx->oaep_md == NULL) { + prsactx->oaep_md = EVP_MD_fetch(prsactx->libctx, "SHA-1", NULL); + if (prsactx->oaep_md == NULL) { + OPENSSL_free(tbuf); + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return 0; + } + } + ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, outsize, tbuf, + len, len, + prsactx->oaep_label, + prsactx->oaep_labellen, + prsactx->oaep_md, + prsactx->mgf1_md); + } else { + /* RSA_PKCS1_WITH_TLS_PADDING */ + if (prsactx->client_version <= 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_TLS_CLIENT_VERSION); + OPENSSL_free(tbuf); + return 0; + } + ret = ossl_rsa_padding_check_PKCS1_type_2_TLS( + prsactx->libctx, out, outsize, tbuf, len, + prsactx->client_version, prsactx->alt_version); + } + OPENSSL_free(tbuf); + } else { + ret = RSA_private_decrypt(inlen, in, out, prsactx->rsa, + prsactx->pad_mode); + } + *outlen = constant_time_select_s(constant_time_msb_s(ret), *outlen, ret); + ret = constant_time_select_int(constant_time_msb(ret), 0, 1); + return ret; +} + +static void rsa_freectx(void *vprsactx) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + RSA_free(prsactx->rsa); + + EVP_MD_free(prsactx->oaep_md); + EVP_MD_free(prsactx->mgf1_md); + OPENSSL_free(prsactx->oaep_label); + + OPENSSL_free(prsactx); +} + +static void *rsa_dupctx(void *vprsactx) +{ + PROV_RSA_CTX *srcctx = (PROV_RSA_CTX *)vprsactx; + PROV_RSA_CTX *dstctx; + + if (!ossl_prov_is_running()) + return NULL; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + if (dstctx->rsa != NULL && !RSA_up_ref(dstctx->rsa)) { + OPENSSL_free(dstctx); + return NULL; + } + + if (dstctx->oaep_md != NULL && !EVP_MD_up_ref(dstctx->oaep_md)) { + RSA_free(dstctx->rsa); + OPENSSL_free(dstctx); + return NULL; + } + + if (dstctx->mgf1_md != NULL && !EVP_MD_up_ref(dstctx->mgf1_md)) { + RSA_free(dstctx->rsa); + EVP_MD_free(dstctx->oaep_md); + OPENSSL_free(dstctx); + return NULL; + } + + return dstctx; +} + +static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + OSSL_PARAM *p; + + if (prsactx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE); + if (p != NULL) + switch (p->data_type) { + case OSSL_PARAM_INTEGER: /* Support for legacy pad mode number */ + if (!OSSL_PARAM_set_int(p, prsactx->pad_mode)) + return 0; + break; + case OSSL_PARAM_UTF8_STRING: + { + int i; + const char *word = NULL; + + for (i = 0; padding_item[i].id != 0; i++) { + if (prsactx->pad_mode == (int)padding_item[i].id) { + word = padding_item[i].ptr; + break; + } + } + + if (word != NULL) { + if (!OSSL_PARAM_set_utf8_string(p, word)) + return 0; + } else { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + } + } + break; + default: + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->oaep_md == NULL + ? "" + : EVP_MD_get0_name(prsactx->oaep_md))) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST); + if (p != NULL) { + EVP_MD *mgf1_md = prsactx->mgf1_md == NULL ? prsactx->oaep_md + : prsactx->mgf1_md; + + if (!OSSL_PARAM_set_utf8_string(p, mgf1_md == NULL + ? "" + : EVP_MD_get0_name(mgf1_md))) + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL); + if (p != NULL && + !OSSL_PARAM_set_octet_ptr(p, prsactx->oaep_label, + prsactx->oaep_labellen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION); + if (p != NULL && !OSSL_PARAM_set_uint(p, prsactx->client_version)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION); + if (p != NULL && !OSSL_PARAM_set_uint(p, prsactx->alt_version)) + return 0; + + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0), + OSSL_PARAM_DEFN(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, OSSL_PARAM_OCTET_PTR, + NULL, 0), + OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL), + OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *rsa_gettable_ctx_params(ossl_unused void *vprsactx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + const OSSL_PARAM *p; + char mdname[OSSL_MAX_NAME_SIZE]; + char mdprops[OSSL_MAX_PROPQUERY_SIZE] = { '\0' }; + char *str = NULL; + + if (prsactx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST); + if (p != NULL) { + str = mdname; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdname))) + return 0; + + p = OSSL_PARAM_locate_const(params, + OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS); + if (p != NULL) { + str = mdprops; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) + return 0; + } + + EVP_MD_free(prsactx->oaep_md); + prsactx->oaep_md = EVP_MD_fetch(prsactx->libctx, mdname, mdprops); + + if (prsactx->oaep_md == NULL) + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE); + if (p != NULL) { + int pad_mode = 0; + + switch (p->data_type) { + case OSSL_PARAM_INTEGER: /* Support for legacy pad mode number */ + if (!OSSL_PARAM_get_int(p, &pad_mode)) + return 0; + break; + case OSSL_PARAM_UTF8_STRING: + { + int i; + + if (p->data == NULL) + return 0; + + for (i = 0; padding_item[i].id != 0; i++) { + if (strcmp(p->data, padding_item[i].ptr) == 0) { + pad_mode = padding_item[i].id; + break; + } + } + } + break; + default: + return 0; + } + + /* + * PSS padding is for signatures only so is not compatible with + * asymmetric cipher use. + */ + if (pad_mode == RSA_PKCS1_PSS_PADDING) + return 0; + if (pad_mode == RSA_PKCS1_OAEP_PADDING && prsactx->oaep_md == NULL) { + prsactx->oaep_md = EVP_MD_fetch(prsactx->libctx, "SHA1", mdprops); + if (prsactx->oaep_md == NULL) + return 0; + } + prsactx->pad_mode = pad_mode; + } + + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST); + if (p != NULL) { + str = mdname; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdname))) + return 0; + + p = OSSL_PARAM_locate_const(params, + OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS); + if (p != NULL) { + str = mdprops; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) + return 0; + } else { + str = NULL; + } + + EVP_MD_free(prsactx->mgf1_md); + prsactx->mgf1_md = EVP_MD_fetch(prsactx->libctx, mdname, str); + + if (prsactx->mgf1_md == NULL) + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL); + if (p != NULL) { + void *tmp_label = NULL; + size_t tmp_labellen; + + if (!OSSL_PARAM_get_octet_string(p, &tmp_label, 0, &tmp_labellen)) + return 0; + OPENSSL_free(prsactx->oaep_label); + prsactx->oaep_label = (unsigned char *)tmp_label; + prsactx->oaep_labellen = tmp_labellen; + } + + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION); + if (p != NULL) { + unsigned int client_version; + + if (!OSSL_PARAM_get_uint(p, &client_version)) + return 0; + prsactx->client_version = client_version; + } + + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION); + if (p != NULL) { + unsigned int alt_version; + + if (!OSSL_PARAM_get_uint(p, &alt_version)) + return 0; + prsactx->alt_version = alt_version; + } + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS, NULL, 0), + OSSL_PARAM_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, NULL, 0), + OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL), + OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *rsa_settable_ctx_params(ossl_unused void *vprsactx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +const OSSL_DISPATCH ossl_rsa_asym_cipher_functions[] = { + { OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))rsa_newctx }, + { OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT, (void (*)(void))rsa_encrypt_init }, + { OSSL_FUNC_ASYM_CIPHER_ENCRYPT, (void (*)(void))rsa_encrypt }, + { OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, (void (*)(void))rsa_decrypt_init }, + { OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))rsa_decrypt }, + { OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))rsa_freectx }, + { OSSL_FUNC_ASYM_CIPHER_DUPCTX, (void (*)(void))rsa_dupctx }, + { OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS, + (void (*)(void))rsa_get_ctx_params }, + { OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS, + (void (*)(void))rsa_gettable_ctx_params }, + { OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS, + (void (*)(void))rsa_set_ctx_params }, + { OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS, + (void (*)(void))rsa_settable_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/asymciphers/sm2_enc.c b/providers/implementations/asymciphers/sm2_enc.c new file mode 100644 index 000000000000..a7c9156087cf --- /dev/null +++ b/providers/implementations/asymciphers/sm2_enc.c @@ -0,0 +1,233 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "internal/deprecated.h" + +#include <openssl/crypto.h> +#include <openssl/evp.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include "crypto/sm2.h" +#include "prov/provider_ctx.h" +#include "prov/implementations.h" +#include "prov/provider_util.h" + +static OSSL_FUNC_asym_cipher_newctx_fn sm2_newctx; +static OSSL_FUNC_asym_cipher_encrypt_init_fn sm2_init; +static OSSL_FUNC_asym_cipher_encrypt_fn sm2_asym_encrypt; +static OSSL_FUNC_asym_cipher_decrypt_init_fn sm2_init; +static OSSL_FUNC_asym_cipher_decrypt_fn sm2_asym_decrypt; +static OSSL_FUNC_asym_cipher_freectx_fn sm2_freectx; +static OSSL_FUNC_asym_cipher_dupctx_fn sm2_dupctx; +static OSSL_FUNC_asym_cipher_get_ctx_params_fn sm2_get_ctx_params; +static OSSL_FUNC_asym_cipher_gettable_ctx_params_fn sm2_gettable_ctx_params; +static OSSL_FUNC_asym_cipher_set_ctx_params_fn sm2_set_ctx_params; +static OSSL_FUNC_asym_cipher_settable_ctx_params_fn sm2_settable_ctx_params; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes EC_KEY structures, so + * we use that here too. + */ + +typedef struct { + OSSL_LIB_CTX *libctx; + EC_KEY *key; + PROV_DIGEST md; +} PROV_SM2_CTX; + +static void *sm2_newctx(void *provctx) +{ + PROV_SM2_CTX *psm2ctx = OPENSSL_zalloc(sizeof(PROV_SM2_CTX)); + + if (psm2ctx == NULL) + return NULL; + psm2ctx->libctx = PROV_LIBCTX_OF(provctx); + + return psm2ctx; +} + +static int sm2_init(void *vpsm2ctx, void *vkey, const OSSL_PARAM params[]) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + + if (psm2ctx == NULL || vkey == NULL || !EC_KEY_up_ref(vkey)) + return 0; + EC_KEY_free(psm2ctx->key); + psm2ctx->key = vkey; + + return sm2_set_ctx_params(psm2ctx, params); +} + +static const EVP_MD *sm2_get_md(PROV_SM2_CTX *psm2ctx) +{ + const EVP_MD *md = ossl_prov_digest_md(&psm2ctx->md); + + if (md == NULL) + md = ossl_prov_digest_fetch(&psm2ctx->md, psm2ctx->libctx, "SM3", NULL); + + return md; +} + +static int sm2_asym_encrypt(void *vpsm2ctx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, + size_t inlen) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + const EVP_MD *md = sm2_get_md(psm2ctx); + + if (md == NULL) + return 0; + + if (out == NULL) { + if (!ossl_sm2_ciphertext_size(psm2ctx->key, md, inlen, outlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + return 1; + } + + return ossl_sm2_encrypt(psm2ctx->key, md, in, inlen, out, outlen); +} + +static int sm2_asym_decrypt(void *vpsm2ctx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, + size_t inlen) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + const EVP_MD *md = sm2_get_md(psm2ctx); + + if (md == NULL) + return 0; + + if (out == NULL) { + if (!ossl_sm2_plaintext_size(in, inlen, outlen)) + return 0; + return 1; + } + + return ossl_sm2_decrypt(psm2ctx->key, md, in, inlen, out, outlen); +} + +static void sm2_freectx(void *vpsm2ctx) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + + EC_KEY_free(psm2ctx->key); + ossl_prov_digest_reset(&psm2ctx->md); + + OPENSSL_free(psm2ctx); +} + +static void *sm2_dupctx(void *vpsm2ctx) +{ + PROV_SM2_CTX *srcctx = (PROV_SM2_CTX *)vpsm2ctx; + PROV_SM2_CTX *dstctx; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + memset(&dstctx->md, 0, sizeof(dstctx->md)); + + if (dstctx->key != NULL && !EC_KEY_up_ref(dstctx->key)) { + OPENSSL_free(dstctx); + return NULL; + } + + if (!ossl_prov_digest_copy(&dstctx->md, &srcctx->md)) { + sm2_freectx(dstctx); + return NULL; + } + + return dstctx; +} + +static int sm2_get_ctx_params(void *vpsm2ctx, OSSL_PARAM *params) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + OSSL_PARAM *p; + + if (vpsm2ctx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_DIGEST); + if (p != NULL) { + const EVP_MD *md = ossl_prov_digest_md(&psm2ctx->md); + + if (!OSSL_PARAM_set_utf8_string(p, md == NULL ? "" + : EVP_MD_get0_name(md))) + return 0; + } + + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *sm2_gettable_ctx_params(ossl_unused void *vpsm2ctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int sm2_set_ctx_params(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + + if (psm2ctx == NULL) + return 0; + if (params == NULL) + return 1; + + if (!ossl_prov_digest_load_from_params(&psm2ctx->md, params, + psm2ctx->libctx)) + return 0; + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_ENGINE, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *sm2_settable_ctx_params(ossl_unused void *vpsm2ctx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +const OSSL_DISPATCH ossl_sm2_asym_cipher_functions[] = { + { OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))sm2_newctx }, + { OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT, (void (*)(void))sm2_init }, + { OSSL_FUNC_ASYM_CIPHER_ENCRYPT, (void (*)(void))sm2_asym_encrypt }, + { OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, (void (*)(void))sm2_init }, + { OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))sm2_asym_decrypt }, + { OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))sm2_freectx }, + { OSSL_FUNC_ASYM_CIPHER_DUPCTX, (void (*)(void))sm2_dupctx }, + { OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS, + (void (*)(void))sm2_get_ctx_params }, + { OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS, + (void (*)(void))sm2_gettable_ctx_params }, + { OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS, + (void (*)(void))sm2_set_ctx_params }, + { OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS, + (void (*)(void))sm2_settable_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/build.info b/providers/implementations/build.info new file mode 100644 index 000000000000..a2f60653e2c2 --- /dev/null +++ b/providers/implementations/build.info @@ -0,0 +1,2 @@ +SUBDIRS=digests ciphers rands macs kdfs exchange keymgmt signature asymciphers \ + encode_decode storemgmt kem diff --git a/providers/implementations/ciphers/build.info b/providers/implementations/ciphers/build.info new file mode 100644 index 000000000000..e4c5f4f051b6 --- /dev/null +++ b/providers/implementations/ciphers/build.info @@ -0,0 +1,142 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. +# +# $TDES_1_GOAL and $TDES_2_GOAL separate FIPSable and non-FIPSable TDES. +# The latter may become legacy sooner, so it's comfortable to have two +# variables already now, to switch the non-FIPSable TDES to legacy if needed. + +$COMMON_GOAL=../../libcommon.a + +$NULL_GOAL=../../libdefault.a +$AES_GOAL=../../libdefault.a ../../libfips.a +$TDES_1_GOAL=../../libdefault.a ../../libfips.a +$TDES_2_GOAL=../../libdefault.a +$ARIA_GOAL=../../libdefault.a +$CAMELLIA_GOAL=../../libdefault.a +$DES_GOAL=../../liblegacy.a +$BLOWFISH_GOAL=../../liblegacy.a +$IDEA_GOAL=../../liblegacy.a +$CAST5_GOAL=../../liblegacy.a +$RC2_GOAL=../../liblegacy.a +$RC4_GOAL=../../liblegacy.a +$RC5_GOAL=../../liblegacy.a +$SEED_GOAL=../../liblegacy.a +$SM4_GOAL=../../libdefault.a +$CHACHA_GOAL=../../libdefault.a +$CHACHAPOLY_GOAL=../../libdefault.a +$SIV_GOAL=../../libdefault.a + +# This source is common building blocks for all ciphers in all our providers. +SOURCE[$COMMON_GOAL]=\ + ciphercommon.c ciphercommon_hw.c ciphercommon_block.c \ + ciphercommon_gcm.c ciphercommon_gcm_hw.c \ + ciphercommon_ccm.c ciphercommon_ccm_hw.c + +IF[{- !$disabled{des} -}] + SOURCE[$TDES_1_GOAL]=cipher_tdes.c cipher_tdes_common.c cipher_tdes_hw.c +ENDIF + +SOURCE[$NULL_GOAL]=\ + cipher_null.c + +SOURCE[$AES_GOAL]=\ + cipher_aes.c cipher_aes_hw.c \ + cipher_aes_xts.c cipher_aes_xts_hw.c \ + cipher_aes_gcm.c cipher_aes_gcm_hw.c \ + cipher_aes_ccm.c cipher_aes_ccm_hw.c \ + cipher_aes_wrp.c \ + cipher_aes_cbc_hmac_sha.c \ + cipher_aes_cbc_hmac_sha256_hw.c cipher_aes_cbc_hmac_sha1_hw.c \ + cipher_cts.c + +# Extra code to satisfy the FIPS and non-FIPS separation. +# When the AES-xxx-XTS moves to legacy, cipher_aes_xts_fips.c can be removed. +SOURCE[$AES_GOAL]=cipher_aes_xts_fips.c + +IF[{- !$disabled{siv} -}] + SOURCE[$SIV_GOAL]=\ + cipher_aes_siv.c cipher_aes_siv_hw.c +ENDIF + +IF[{- !$disabled{des} -}] + SOURCE[$TDES_2_GOAL]=\ + cipher_tdes_default.c cipher_tdes_default_hw.c \ + cipher_tdes_wrap.c cipher_tdes_wrap_hw.c + SOURCE[$DES_GOAL]=\ + cipher_desx.c cipher_desx_hw.c \ + cipher_des.c cipher_des_hw.c + IF[{- !$disabled{module} -}] + SOURCE[$DES_GOAL]=\ + cipher_tdes_common.c + ENDIF +ENDIF + +IF[{- !$disabled{aria} -}] + SOURCE[$ARIA_GOAL]=\ + cipher_aria.c cipher_aria_hw.c \ + cipher_aria_gcm.c cipher_aria_gcm_hw.c \ + cipher_aria_ccm.c cipher_aria_ccm_hw.c +ENDIF + +IF[{- !$disabled{camellia} -}] + SOURCE[$CAMELLIA_GOAL]=\ + cipher_camellia.c cipher_camellia_hw.c +ENDIF + +IF[{- !$disabled{bf} -}] + SOURCE[$BLOWFISH_GOAL]=\ + cipher_blowfish.c cipher_blowfish_hw.c +ENDIF + +IF[{- !$disabled{idea} -}] + SOURCE[$IDEA_GOAL]=\ + cipher_idea.c cipher_idea_hw.c +ENDIF + +IF[{- !$disabled{cast} -}] + SOURCE[$CAST5_GOAL]=\ + cipher_cast5.c cipher_cast5_hw.c +ENDIF + +IF[{- !$disabled{seed} -}] + SOURCE[$SEED_GOAL]=\ + cipher_seed.c cipher_seed_hw.c +ENDIF + +IF[{- !$disabled{sm4} -}] + SOURCE[$SM4_GOAL]=\ + cipher_sm4.c cipher_sm4_hw.c +ENDIF + +IF[{- !$disabled{ocb} -}] + SOURCE[$AES_GOAL]=\ + cipher_aes_ocb.c cipher_aes_ocb_hw.c +ENDIF + +IF[{- !$disabled{rc4} -}] + SOURCE[$RC4_GOAL]=\ + cipher_rc4.c cipher_rc4_hw.c + IF[{- !$disabled{md5} -}] + SOURCE[$RC4_GOAL]=\ + cipher_rc4_hmac_md5.c cipher_rc4_hmac_md5_hw.c + ENDIF +ENDIF + +IF[{- !$disabled{rc5} -}] + SOURCE[$RC5_GOAL]=\ + cipher_rc5.c cipher_rc5_hw.c +ENDIF + +IF[{- !$disabled{rc2} -}] + SOURCE[$RC2_GOAL]=\ + cipher_rc2.c cipher_rc2_hw.c +ENDIF + +IF[{- !$disabled{chacha} -}] + SOURCE[$CHACHA_GOAL]=\ + cipher_chacha20.c cipher_chacha20_hw.c + IF[{- !$disabled{poly1305} -}] + SOURCE[$CHACHAPOLY_GOAL]=\ + cipher_chacha20_poly1305.c cipher_chacha20_poly1305_hw.c + ENDIF +ENDIF diff --git a/providers/implementations/ciphers/cipher_aes.c b/providers/implementations/ciphers/cipher_aes.c new file mode 100644 index 000000000000..2f469c131a7e --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes.c @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * AES low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +/* Dispatch functions for AES cipher modes ecb, cbc, ofb, cfb, ctr */ + +#include "cipher_aes.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +static OSSL_FUNC_cipher_freectx_fn aes_freectx; +static OSSL_FUNC_cipher_dupctx_fn aes_dupctx; + +static void aes_freectx(void *vctx) +{ + PROV_AES_CTX *ctx = (PROV_AES_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *aes_dupctx(void *ctx) +{ + PROV_AES_CTX *in = (PROV_AES_CTX *)ctx; + PROV_AES_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + in->base.hw->copyctx(&ret->base, &in->base); + + return ret; +} + +/* ossl_aes256ecb_functions */ +IMPLEMENT_generic_cipher(aes, AES, ecb, ECB, 0, 256, 128, 0, block) +/* ossl_aes192ecb_functions */ +IMPLEMENT_generic_cipher(aes, AES, ecb, ECB, 0, 192, 128, 0, block) +/* ossl_aes128ecb_functions */ +IMPLEMENT_generic_cipher(aes, AES, ecb, ECB, 0, 128, 128, 0, block) +/* ossl_aes256cbc_functions */ +IMPLEMENT_generic_cipher(aes, AES, cbc, CBC, 0, 256, 128, 128, block) +/* ossl_aes192cbc_functions */ +IMPLEMENT_generic_cipher(aes, AES, cbc, CBC, 0, 192, 128, 128, block) +/* ossl_aes128cbc_functions */ +IMPLEMENT_generic_cipher(aes, AES, cbc, CBC, 0, 128, 128, 128, block) +/* ossl_aes256ofb_functions */ +IMPLEMENT_generic_cipher(aes, AES, ofb, OFB, 0, 256, 8, 128, stream) +/* ossl_aes192ofb_functions */ +IMPLEMENT_generic_cipher(aes, AES, ofb, OFB, 0, 192, 8, 128, stream) +/* ossl_aes128ofb_functions */ +IMPLEMENT_generic_cipher(aes, AES, ofb, OFB, 0, 128, 8, 128, stream) +/* ossl_aes256cfb_functions */ +IMPLEMENT_generic_cipher(aes, AES, cfb, CFB, 0, 256, 8, 128, stream) +/* ossl_aes192cfb_functions */ +IMPLEMENT_generic_cipher(aes, AES, cfb, CFB, 0, 192, 8, 128, stream) +/* ossl_aes128cfb_functions */ +IMPLEMENT_generic_cipher(aes, AES, cfb, CFB, 0, 128, 8, 128, stream) +/* ossl_aes256cfb1_functions */ +IMPLEMENT_generic_cipher(aes, AES, cfb1, CFB, 0, 256, 8, 128, stream) +/* ossl_aes192cfb1_functions */ +IMPLEMENT_generic_cipher(aes, AES, cfb1, CFB, 0, 192, 8, 128, stream) +/* ossl_aes128cfb1_functions */ +IMPLEMENT_generic_cipher(aes, AES, cfb1, CFB, 0, 128, 8, 128, stream) +/* ossl_aes256cfb8_functions */ +IMPLEMENT_generic_cipher(aes, AES, cfb8, CFB, 0, 256, 8, 128, stream) +/* ossl_aes192cfb8_functions */ +IMPLEMENT_generic_cipher(aes, AES, cfb8, CFB, 0, 192, 8, 128, stream) +/* ossl_aes128cfb8_functions */ +IMPLEMENT_generic_cipher(aes, AES, cfb8, CFB, 0, 128, 8, 128, stream) +/* ossl_aes256ctr_functions */ +IMPLEMENT_generic_cipher(aes, AES, ctr, CTR, 0, 256, 8, 128, stream) +/* ossl_aes192ctr_functions */ +IMPLEMENT_generic_cipher(aes, AES, ctr, CTR, 0, 192, 8, 128, stream) +/* ossl_aes128ctr_functions */ +IMPLEMENT_generic_cipher(aes, AES, ctr, CTR, 0, 128, 8, 128, stream) + +#include "cipher_aes_cts.inc" diff --git a/providers/implementations/ciphers/cipher_aes.h b/providers/implementations/ciphers/cipher_aes.h new file mode 100644 index 000000000000..7eaf76c8c47d --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes.h @@ -0,0 +1,62 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/aes.h> +#include "prov/ciphercommon.h" +#include "crypto/aes_platform.h" + +typedef struct prov_aes_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + AES_KEY ks; + } ks; + + /* Platform specific data */ + union { + int dummy; +#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__) + struct { + union { + OSSL_UNION_ALIGN; + /*- + * KM-AES parameter block - begin + * (see z/Architecture Principles of Operation >= SA22-7832-06) + */ + struct { + unsigned char k[32]; + } km; + /* KM-AES parameter block - end */ + /*- + * KMO-AES/KMF-AES parameter block - begin + * (see z/Architecture Principles of Operation >= SA22-7832-08) + */ + struct { + unsigned char cv[16]; + unsigned char k[32]; + } kmo_kmf; + /* KMO-AES/KMF-AES parameter block - end */ + } param; + unsigned int fc; + int res; + } s390x; +#endif /* defined(OPENSSL_CPUID_OBJ) && defined(__s390__) */ + } plat; + +} PROV_AES_CTX; + +#define ossl_prov_cipher_hw_aes_ofb ossl_prov_cipher_hw_aes_ofb128 +#define ossl_prov_cipher_hw_aes_cfb ossl_prov_cipher_hw_aes_cfb128 +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_ecb(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_cbc(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_ofb128(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_cfb128(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_cfb1(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_cfb8(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_ctr(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.c b/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.c new file mode 100644 index 000000000000..f9a8a5804149 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.c @@ -0,0 +1,418 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * AES low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +/* Dispatch functions for AES_CBC_HMAC_SHA ciphers */ + +/* For SSL3_VERSION and TLS1_VERSION */ +#include <openssl/prov_ssl.h> +#include <openssl/proverr.h> +#include "cipher_aes_cbc_hmac_sha.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#ifndef AES_CBC_HMAC_SHA_CAPABLE +# define IMPLEMENT_CIPHER(nm, sub, kbits, blkbits, ivbits, flags) \ +const OSSL_DISPATCH ossl_##nm##kbits##sub##_functions[] = { \ + { 0, NULL } \ +}; +#else + +# define AES_CBC_HMAC_SHA_FLAGS (PROV_CIPHER_FLAG_AEAD \ + | PROV_CIPHER_FLAG_TLS1_MULTIBLOCK) + +static OSSL_FUNC_cipher_encrypt_init_fn aes_einit; +static OSSL_FUNC_cipher_decrypt_init_fn aes_dinit; +static OSSL_FUNC_cipher_freectx_fn aes_cbc_hmac_sha1_freectx; +static OSSL_FUNC_cipher_freectx_fn aes_cbc_hmac_sha256_freectx; +static OSSL_FUNC_cipher_get_ctx_params_fn aes_get_ctx_params; +static OSSL_FUNC_cipher_gettable_ctx_params_fn aes_gettable_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn aes_set_ctx_params; +static OSSL_FUNC_cipher_settable_ctx_params_fn aes_settable_ctx_params; +# define aes_gettable_params ossl_cipher_generic_gettable_params +# define aes_update ossl_cipher_generic_stream_update +# define aes_final ossl_cipher_generic_stream_final +# define aes_cipher ossl_cipher_generic_cipher + +static int aes_einit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_einit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return aes_set_ctx_params(ctx, params); +} + +static int aes_dinit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_dinit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return aes_set_ctx_params(ctx, params); +} + +static const OSSL_PARAM cipher_aes_known_settable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_MAC_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD, NULL, 0), +# if !defined(OPENSSL_NO_MULTIBLOCK) + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_SEND_FRAGMENT, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_AAD, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_IN, NULL, 0), +# endif /* !defined(OPENSSL_NO_MULTIBLOCK) */ + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_END +}; +const OSSL_PARAM *aes_settable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return cipher_aes_known_settable_ctx_params; +} + +static int aes_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_CIPHER_HW_AES_HMAC_SHA *hw = + (PROV_CIPHER_HW_AES_HMAC_SHA *)ctx->hw; + const OSSL_PARAM *p; + int ret = 1; +# if !defined(OPENSSL_NO_MULTIBLOCK) + EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param; +# endif + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_MAC_KEY); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + hw->init_mac_key(ctx, p->data, p->data_size); + } + +# if !defined(OPENSSL_NO_MULTIBLOCK) + p = OSSL_PARAM_locate_const(params, + OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_SEND_FRAGMENT); + if (p != NULL + && !OSSL_PARAM_get_size_t(p, &ctx->multiblock_max_send_fragment)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + /* + * The inputs to tls1_multiblock_aad are: + * mb_param->inp + * mb_param->len + * mb_param->interleave + * The outputs of tls1_multiblock_aad are written to: + * ctx->multiblock_interleave + * ctx->multiblock_aad_packlen + */ + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_AAD); + if (p != NULL) { + const OSSL_PARAM *p1 = OSSL_PARAM_locate_const(params, + OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE); + if (p->data_type != OSSL_PARAM_OCTET_STRING + || p1 == NULL + || !OSSL_PARAM_get_uint(p1, &mb_param.interleave)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + mb_param.inp = p->data; + mb_param.len = p->data_size; + if (hw->tls1_multiblock_aad(vctx, &mb_param) <= 0) + return 0; + } + + /* + * The inputs to tls1_multiblock_encrypt are: + * mb_param->inp + * mb_param->len + * mb_param->interleave + * mb_param->out + * The outputs of tls1_multiblock_encrypt are: + * ctx->multiblock_encrypt_len + */ + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC); + if (p != NULL) { + const OSSL_PARAM *p1 = OSSL_PARAM_locate_const(params, + OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE); + const OSSL_PARAM *pin = OSSL_PARAM_locate_const(params, + OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_IN); + + if (p->data_type != OSSL_PARAM_OCTET_STRING + || pin == NULL + || pin->data_type != OSSL_PARAM_OCTET_STRING + || p1 == NULL + || !OSSL_PARAM_get_uint(p1, &mb_param.interleave)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + mb_param.out = p->data; + mb_param.inp = pin->data; + mb_param.len = pin->data_size; + if (hw->tls1_multiblock_encrypt(vctx, &mb_param) <= 0) + return 0; + } +# endif /* !defined(OPENSSL_NO_MULTIBLOCK) */ + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (hw->set_tls1_aad(ctx, p->data, p->data_size) <= 0) + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + size_t keylen; + + if (!OSSL_PARAM_get_size_t(p, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ctx->base.keylen != keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS_VERSION); + if (p != NULL) { + if (!OSSL_PARAM_get_uint(p, &ctx->base.tlsversion)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ctx->base.tlsversion == SSL3_VERSION + || ctx->base.tlsversion == TLS1_VERSION) { + if (!ossl_assert(ctx->base.removetlsfixed >= AES_BLOCK_SIZE)) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return 0; + } + /* + * There is no explicit IV with these TLS versions, so don't attempt + * to remove it. + */ + ctx->base.removetlsfixed -= AES_BLOCK_SIZE; + } + } + return ret; +} + +static int aes_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + OSSL_PARAM *p; + +# if !defined(OPENSSL_NO_MULTIBLOCK) + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_BUFSIZE); + if (p != NULL) { + PROV_CIPHER_HW_AES_HMAC_SHA *hw = + (PROV_CIPHER_HW_AES_HMAC_SHA *)ctx->hw; + size_t len = hw->tls1_multiblock_max_bufsize(ctx); + + if (!OSSL_PARAM_set_size_t(p, len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE); + if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->multiblock_interleave)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_AAD_PACKLEN); + if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->multiblock_aad_packlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_LEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->multiblock_encrypt_len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } +# endif /* !defined(OPENSSL_NO_MULTIBLOCK) */ + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); + if (p != NULL + && !OSSL_PARAM_set_octet_string(p, ctx->base.oiv, ctx->base.ivlen) + && !OSSL_PARAM_set_octet_ptr(p, &ctx->base.oiv, ctx->base.ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV); + if (p != NULL + && !OSSL_PARAM_set_octet_string(p, ctx->base.iv, ctx->base.ivlen) + && !OSSL_PARAM_set_octet_ptr(p, &ctx->base.iv, ctx->base.ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + return 1; +} + +static const OSSL_PARAM cipher_aes_known_gettable_ctx_params[] = { +# if !defined(OPENSSL_NO_MULTIBLOCK) + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_BUFSIZE, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_AAD_PACKLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_LEN, NULL), +# endif /* !defined(OPENSSL_NO_MULTIBLOCK) */ + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_UPDATED_IV, NULL, 0), + OSSL_PARAM_END +}; +const OSSL_PARAM *aes_gettable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return cipher_aes_known_gettable_ctx_params; +} + +static void base_init(void *provctx, PROV_AES_HMAC_SHA_CTX *ctx, + const PROV_CIPHER_HW_AES_HMAC_SHA *meths, + size_t kbits, size_t blkbits, size_t ivbits, + uint64_t flags) +{ + ossl_cipher_generic_initkey(&ctx->base, kbits, blkbits, ivbits, + EVP_CIPH_CBC_MODE, flags, + &meths->base, provctx); + ctx->hw = (PROV_CIPHER_HW_AES_HMAC_SHA *)ctx->base.hw; +} + +static void *aes_cbc_hmac_sha1_newctx(void *provctx, size_t kbits, + size_t blkbits, size_t ivbits, + uint64_t flags) +{ + PROV_AES_HMAC_SHA1_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + base_init(provctx, &ctx->base_ctx, + ossl_prov_cipher_hw_aes_cbc_hmac_sha1(), kbits, blkbits, + ivbits, flags); + return ctx; +} + +static void aes_cbc_hmac_sha1_freectx(void *vctx) +{ + PROV_AES_HMAC_SHA1_CTX *ctx = (PROV_AES_HMAC_SHA1_CTX *)vctx; + + if (ctx != NULL) { + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); + } +} + +static void *aes_cbc_hmac_sha256_newctx(void *provctx, size_t kbits, + size_t blkbits, size_t ivbits, + uint64_t flags) +{ + PROV_AES_HMAC_SHA256_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + base_init(provctx, &ctx->base_ctx, + ossl_prov_cipher_hw_aes_cbc_hmac_sha256(), kbits, blkbits, + ivbits, flags); + return ctx; +} + +static void aes_cbc_hmac_sha256_freectx(void *vctx) +{ + PROV_AES_HMAC_SHA256_CTX *ctx = (PROV_AES_HMAC_SHA256_CTX *)vctx; + + if (ctx != NULL) { + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); + } +} + +# define IMPLEMENT_CIPHER(nm, sub, kbits, blkbits, ivbits, flags) \ +static OSSL_FUNC_cipher_newctx_fn nm##_##kbits##_##sub##_newctx; \ +static void *nm##_##kbits##_##sub##_newctx(void *provctx) \ +{ \ + return nm##_##sub##_newctx(provctx, kbits, blkbits, ivbits, flags); \ +} \ +static OSSL_FUNC_cipher_get_params_fn nm##_##kbits##_##sub##_get_params; \ +static int nm##_##kbits##_##sub##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_CBC_MODE, \ + flags, kbits, blkbits, ivbits); \ +} \ +const OSSL_DISPATCH ossl_##nm##kbits##sub##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))nm##_##kbits##_##sub##_newctx },\ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))nm##_##sub##_freectx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))nm##_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))nm##_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))nm##_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))nm##_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))nm##_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void))nm##_##kbits##_##sub##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))nm##_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))nm##_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))nm##_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))nm##_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))nm##_settable_ctx_params }, \ + { 0, NULL } \ +}; + +#endif /* AES_CBC_HMAC_SHA_CAPABLE */ + +/* ossl_aes128cbc_hmac_sha1_functions */ +IMPLEMENT_CIPHER(aes, cbc_hmac_sha1, 128, 128, 128, AES_CBC_HMAC_SHA_FLAGS) +/* ossl_aes256cbc_hmac_sha1_functions */ +IMPLEMENT_CIPHER(aes, cbc_hmac_sha1, 256, 128, 128, AES_CBC_HMAC_SHA_FLAGS) +/* ossl_aes128cbc_hmac_sha256_functions */ +IMPLEMENT_CIPHER(aes, cbc_hmac_sha256, 128, 128, 128, AES_CBC_HMAC_SHA_FLAGS) +/* ossl_aes256cbc_hmac_sha256_functions */ +IMPLEMENT_CIPHER(aes, cbc_hmac_sha256, 256, 128, 128, AES_CBC_HMAC_SHA_FLAGS) diff --git a/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.h b/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.h new file mode 100644 index 000000000000..6aaf3f06fb49 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.h @@ -0,0 +1,65 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/ciphercommon.h" +#include "crypto/aes_platform.h" + +int ossl_cipher_capable_aes_cbc_hmac_sha1(void); +int ossl_cipher_capable_aes_cbc_hmac_sha256(void); + +typedef struct prov_cipher_hw_aes_hmac_sha_ctx_st { + PROV_CIPHER_HW base; /* must be first */ + void (*init_mac_key)(void *ctx, const unsigned char *inkey, size_t inlen); + int (*set_tls1_aad)(void *ctx, unsigned char *aad_rec, int aad_len); +# if !defined(OPENSSL_NO_MULTIBLOCK) + int (*tls1_multiblock_max_bufsize)(void *ctx); + int (*tls1_multiblock_aad)( + void *vctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param); + int (*tls1_multiblock_encrypt)( + void *ctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param); +# endif /* OPENSSL_NO_MULTIBLOCK) */ +} PROV_CIPHER_HW_AES_HMAC_SHA; + +const PROV_CIPHER_HW_AES_HMAC_SHA *ossl_prov_cipher_hw_aes_cbc_hmac_sha1(void); +const PROV_CIPHER_HW_AES_HMAC_SHA *ossl_prov_cipher_hw_aes_cbc_hmac_sha256(void); + +#ifdef AES_CBC_HMAC_SHA_CAPABLE +# include <openssl/aes.h> +# include <openssl/sha.h> + +typedef struct prov_aes_hmac_sha_ctx_st { + PROV_CIPHER_CTX base; + AES_KEY ks; + size_t payload_length; /* AAD length in decrypt case */ + union { + unsigned int tls_ver; + unsigned char tls_aad[16]; /* 13 used */ + } aux; + const PROV_CIPHER_HW_AES_HMAC_SHA *hw; + /* some value that are setup by set methods - that can be retrieved */ + unsigned int multiblock_interleave; + unsigned int multiblock_aad_packlen; + size_t multiblock_max_send_fragment; + size_t multiblock_encrypt_len; + size_t tls_aad_pad; +} PROV_AES_HMAC_SHA_CTX; + +typedef struct prov_aes_hmac_sha1_ctx_st { + PROV_AES_HMAC_SHA_CTX base_ctx; + SHA_CTX head, tail, md; +} PROV_AES_HMAC_SHA1_CTX; + +typedef struct prov_aes_hmac_sha256_ctx_st { + PROV_AES_HMAC_SHA_CTX base_ctx; + SHA256_CTX head, tail, md; +} PROV_AES_HMAC_SHA256_CTX; + +# define NO_PAYLOAD_LENGTH ((size_t)-1) + +#endif /* AES_CBC_HMAC_SHA_CAPABLE */ diff --git a/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha1_hw.c b/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha1_hw.c new file mode 100644 index 000000000000..76674d530434 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha1_hw.c @@ -0,0 +1,795 @@ +/* + * Copyright 2011-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * All low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +#include "cipher_aes_cbc_hmac_sha.h" + +#if !defined(AES_CBC_HMAC_SHA_CAPABLE) || !defined(AESNI_CAPABLE) +int ossl_cipher_capable_aes_cbc_hmac_sha1(void) +{ + return 0; +} + +const PROV_CIPHER_HW_AES_HMAC_SHA *ossl_prov_cipher_hw_aes_cbc_hmac_sha1(void) +{ + return NULL; +} +#else + +# include <openssl/rand.h> +# include "crypto/evp.h" +# include "internal/constant_time.h" + +void sha1_block_data_order(void *c, const void *p, size_t len); +void aesni_cbc_sha1_enc(const void *inp, void *out, size_t blocks, + const AES_KEY *key, unsigned char iv[16], + SHA_CTX *ctx, const void *in0); + +int ossl_cipher_capable_aes_cbc_hmac_sha1(void) +{ + return AESNI_CBC_HMAC_SHA_CAPABLE; +} + +static int aesni_cbc_hmac_sha1_init_key(PROV_CIPHER_CTX *vctx, + const unsigned char *key, size_t keylen) +{ + int ret; + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_AES_HMAC_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx; + + if (ctx->base.enc) + ret = aesni_set_encrypt_key(key, keylen * 8, &ctx->ks); + else + ret = aesni_set_decrypt_key(key, keylen * 8, &ctx->ks); + + SHA1_Init(&sctx->head); /* handy when benchmarking */ + sctx->tail = sctx->head; + sctx->md = sctx->head; + + ctx->payload_length = NO_PAYLOAD_LENGTH; + + vctx->removetlspad = 1; + vctx->removetlsfixed = SHA_DIGEST_LENGTH + AES_BLOCK_SIZE; + + return ret < 0 ? 0 : 1; +} + +static void sha1_update(SHA_CTX *c, const void *data, size_t len) +{ + const unsigned char *ptr = data; + size_t res; + + if ((res = c->num)) { + res = SHA_CBLOCK - res; + if (len < res) + res = len; + SHA1_Update(c, ptr, res); + ptr += res; + len -= res; + } + + res = len % SHA_CBLOCK; + len -= res; + + if (len) { + sha1_block_data_order(c, ptr, len / SHA_CBLOCK); + + ptr += len; + c->Nh += len >> 29; + c->Nl += len <<= 3; + if (c->Nl < (unsigned int)len) + c->Nh++; + } + + if (res) + SHA1_Update(c, ptr, res); +} + +# if !defined(OPENSSL_NO_MULTIBLOCK) + +typedef struct { + unsigned int A[8], B[8], C[8], D[8], E[8]; +} SHA1_MB_CTX; + +typedef struct { + const unsigned char *ptr; + int blocks; +} HASH_DESC; + +typedef struct { + const unsigned char *inp; + unsigned char *out; + int blocks; + u64 iv[2]; +} CIPH_DESC; + +void sha1_multi_block(SHA1_MB_CTX *, const HASH_DESC *, int); +void aesni_multi_cbc_encrypt(CIPH_DESC *, void *, int); + +static size_t tls1_multi_block_encrypt(void *vctx, + unsigned char *out, + const unsigned char *inp, + size_t inp_len, int n4x) +{ /* n4x is 1 or 2 */ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_AES_HMAC_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx; + HASH_DESC hash_d[8], edges[8]; + CIPH_DESC ciph_d[8]; + unsigned char storage[sizeof(SHA1_MB_CTX) + 32]; + union { + u64 q[16]; + u32 d[32]; + u8 c[128]; + } blocks[8]; + SHA1_MB_CTX *mctx; + unsigned int frag, last, packlen, i; + unsigned int x4 = 4 * n4x, minblocks, processed = 0; + size_t ret = 0; + u8 *IVs; +# if defined(BSWAP8) + u64 seqnum; +# endif + + /* ask for IVs in bulk */ + if (RAND_bytes_ex(ctx->base.libctx, (IVs = blocks[0].c), 16 * x4, 0) <= 0) + return 0; + + mctx = (SHA1_MB_CTX *) (storage + 32 - ((size_t)storage % 32)); /* align */ + + frag = (unsigned int)inp_len >> (1 + n4x); + last = (unsigned int)inp_len + frag - (frag << (1 + n4x)); + if (last > frag && ((last + 13 + 9) % 64) < (x4 - 1)) { + frag++; + last -= x4 - 1; + } + + packlen = 5 + 16 + ((frag + 20 + 16) & -16); + + /* populate descriptors with pointers and IVs */ + hash_d[0].ptr = inp; + ciph_d[0].inp = inp; + /* 5+16 is place for header and explicit IV */ + ciph_d[0].out = out + 5 + 16; + memcpy(ciph_d[0].out - 16, IVs, 16); + memcpy(ciph_d[0].iv, IVs, 16); + IVs += 16; + + for (i = 1; i < x4; i++) { + ciph_d[i].inp = hash_d[i].ptr = hash_d[i - 1].ptr + frag; + ciph_d[i].out = ciph_d[i - 1].out + packlen; + memcpy(ciph_d[i].out - 16, IVs, 16); + memcpy(ciph_d[i].iv, IVs, 16); + IVs += 16; + } + +# if defined(BSWAP8) + memcpy(blocks[0].c, sctx->md.data, 8); + seqnum = BSWAP8(blocks[0].q[0]); +# endif + for (i = 0; i < x4; i++) { + unsigned int len = (i == (x4 - 1) ? last : frag); +# if !defined(BSWAP8) + unsigned int carry, j; +# endif + + mctx->A[i] = sctx->md.h0; + mctx->B[i] = sctx->md.h1; + mctx->C[i] = sctx->md.h2; + mctx->D[i] = sctx->md.h3; + mctx->E[i] = sctx->md.h4; + + /* fix seqnum */ +# if defined(BSWAP8) + blocks[i].q[0] = BSWAP8(seqnum + i); +# else + for (carry = i, j = 8; j--;) { + blocks[i].c[j] = ((u8 *)sctx->md.data)[j] + carry; + carry = (blocks[i].c[j] - carry) >> (sizeof(carry) * 8 - 1); + } +# endif + blocks[i].c[8] = ((u8 *)sctx->md.data)[8]; + blocks[i].c[9] = ((u8 *)sctx->md.data)[9]; + blocks[i].c[10] = ((u8 *)sctx->md.data)[10]; + /* fix length */ + blocks[i].c[11] = (u8)(len >> 8); + blocks[i].c[12] = (u8)(len); + + memcpy(blocks[i].c + 13, hash_d[i].ptr, 64 - 13); + hash_d[i].ptr += 64 - 13; + hash_d[i].blocks = (len - (64 - 13)) / 64; + + edges[i].ptr = blocks[i].c; + edges[i].blocks = 1; + } + + /* hash 13-byte headers and first 64-13 bytes of inputs */ + sha1_multi_block(mctx, edges, n4x); + /* hash bulk inputs */ +# define MAXCHUNKSIZE 2048 +# if MAXCHUNKSIZE%64 +# error "MAXCHUNKSIZE is not divisible by 64" +# elif MAXCHUNKSIZE + /* + * goal is to minimize pressure on L1 cache by moving in shorter steps, + * so that hashed data is still in the cache by the time we encrypt it + */ + minblocks = ((frag <= last ? frag : last) - (64 - 13)) / 64; + if (minblocks > MAXCHUNKSIZE / 64) { + for (i = 0; i < x4; i++) { + edges[i].ptr = hash_d[i].ptr; + edges[i].blocks = MAXCHUNKSIZE / 64; + ciph_d[i].blocks = MAXCHUNKSIZE / 16; + } + do { + sha1_multi_block(mctx, edges, n4x); + aesni_multi_cbc_encrypt(ciph_d, &ctx->ks, n4x); + + for (i = 0; i < x4; i++) { + edges[i].ptr = hash_d[i].ptr += MAXCHUNKSIZE; + hash_d[i].blocks -= MAXCHUNKSIZE / 64; + edges[i].blocks = MAXCHUNKSIZE / 64; + ciph_d[i].inp += MAXCHUNKSIZE; + ciph_d[i].out += MAXCHUNKSIZE; + ciph_d[i].blocks = MAXCHUNKSIZE / 16; + memcpy(ciph_d[i].iv, ciph_d[i].out - 16, 16); + } + processed += MAXCHUNKSIZE; + minblocks -= MAXCHUNKSIZE / 64; + } while (minblocks > MAXCHUNKSIZE / 64); + } +# endif +# undef MAXCHUNKSIZE + sha1_multi_block(mctx, hash_d, n4x); + + memset(blocks, 0, sizeof(blocks)); + for (i = 0; i < x4; i++) { + unsigned int len = (i == (x4 - 1) ? last : frag), + off = hash_d[i].blocks * 64; + const unsigned char *ptr = hash_d[i].ptr + off; + + off = (len - processed) - (64 - 13) - off; /* remainder actually */ + memcpy(blocks[i].c, ptr, off); + blocks[i].c[off] = 0x80; + len += 64 + 13; /* 64 is HMAC header */ + len *= 8; /* convert to bits */ + if (off < (64 - 8)) { +# ifdef BSWAP4 + blocks[i].d[15] = BSWAP4(len); +# else + PUTU32(blocks[i].c + 60, len); +# endif + edges[i].blocks = 1; + } else { +# ifdef BSWAP4 + blocks[i].d[31] = BSWAP4(len); +# else + PUTU32(blocks[i].c + 124, len); +# endif + edges[i].blocks = 2; + } + edges[i].ptr = blocks[i].c; + } + + /* hash input tails and finalize */ + sha1_multi_block(mctx, edges, n4x); + + memset(blocks, 0, sizeof(blocks)); + for (i = 0; i < x4; i++) { +# ifdef BSWAP4 + blocks[i].d[0] = BSWAP4(mctx->A[i]); + mctx->A[i] = sctx->tail.h0; + blocks[i].d[1] = BSWAP4(mctx->B[i]); + mctx->B[i] = sctx->tail.h1; + blocks[i].d[2] = BSWAP4(mctx->C[i]); + mctx->C[i] = sctx->tail.h2; + blocks[i].d[3] = BSWAP4(mctx->D[i]); + mctx->D[i] = sctx->tail.h3; + blocks[i].d[4] = BSWAP4(mctx->E[i]); + mctx->E[i] = sctx->tail.h4; + blocks[i].c[20] = 0x80; + blocks[i].d[15] = BSWAP4((64 + 20) * 8); +# else + PUTU32(blocks[i].c + 0, mctx->A[i]); + mctx->A[i] = sctx->tail.h0; + PUTU32(blocks[i].c + 4, mctx->B[i]); + mctx->B[i] = sctx->tail.h1; + PUTU32(blocks[i].c + 8, mctx->C[i]); + mctx->C[i] = sctx->tail.h2; + PUTU32(blocks[i].c + 12, mctx->D[i]); + mctx->D[i] = sctx->tail.h3; + PUTU32(blocks[i].c + 16, mctx->E[i]); + mctx->E[i] = sctx->tail.h4; + blocks[i].c[20] = 0x80; + PUTU32(blocks[i].c + 60, (64 + 20) * 8); +# endif /* BSWAP */ + edges[i].ptr = blocks[i].c; + edges[i].blocks = 1; + } + + /* finalize MACs */ + sha1_multi_block(mctx, edges, n4x); + + for (i = 0; i < x4; i++) { + unsigned int len = (i == (x4 - 1) ? last : frag), pad, j; + unsigned char *out0 = out; + + memcpy(ciph_d[i].out, ciph_d[i].inp, len - processed); + ciph_d[i].inp = ciph_d[i].out; + + out += 5 + 16 + len; + + /* write MAC */ + PUTU32(out + 0, mctx->A[i]); + PUTU32(out + 4, mctx->B[i]); + PUTU32(out + 8, mctx->C[i]); + PUTU32(out + 12, mctx->D[i]); + PUTU32(out + 16, mctx->E[i]); + out += 20; + len += 20; + + /* pad */ + pad = 15 - len % 16; + for (j = 0; j <= pad; j++) + *(out++) = pad; + len += pad + 1; + + ciph_d[i].blocks = (len - processed) / 16; + len += 16; /* account for explicit iv */ + + /* arrange header */ + out0[0] = ((u8 *)sctx->md.data)[8]; + out0[1] = ((u8 *)sctx->md.data)[9]; + out0[2] = ((u8 *)sctx->md.data)[10]; + out0[3] = (u8)(len >> 8); + out0[4] = (u8)(len); + + ret += len + 5; + inp += frag; + } + + aesni_multi_cbc_encrypt(ciph_d, &ctx->ks, n4x); + + OPENSSL_cleanse(blocks, sizeof(blocks)); + OPENSSL_cleanse(mctx, sizeof(*mctx)); + + ctx->multiblock_encrypt_len = ret; + return ret; +} +# endif /* OPENSSL_NO_MULTIBLOCK */ + +static int aesni_cbc_hmac_sha1_cipher(PROV_CIPHER_CTX *vctx, + unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_AES_HMAC_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx; + unsigned int l; + size_t plen = ctx->payload_length; + size_t iv = 0; /* explicit IV in TLS 1.1 and later */ + size_t aes_off = 0, blocks; + size_t sha_off = SHA_CBLOCK - sctx->md.num; + + ctx->payload_length = NO_PAYLOAD_LENGTH; + + if (len % AES_BLOCK_SIZE) + return 0; + + if (ctx->base.enc) { + if (plen == NO_PAYLOAD_LENGTH) + plen = len; + else if (len != + ((plen + SHA_DIGEST_LENGTH + + AES_BLOCK_SIZE) & -AES_BLOCK_SIZE)) + return 0; + else if (ctx->aux.tls_ver >= TLS1_1_VERSION) + iv = AES_BLOCK_SIZE; + + if (plen > (sha_off + iv) + && (blocks = (plen - (sha_off + iv)) / SHA_CBLOCK)) { + sha1_update(&sctx->md, in + iv, sha_off); + + aesni_cbc_sha1_enc(in, out, blocks, &ctx->ks, ctx->base.iv, + &sctx->md, in + iv + sha_off); + blocks *= SHA_CBLOCK; + aes_off += blocks; + sha_off += blocks; + sctx->md.Nh += blocks >> 29; + sctx->md.Nl += blocks <<= 3; + if (sctx->md.Nl < (unsigned int)blocks) + sctx->md.Nh++; + } else { + sha_off = 0; + } + sha_off += iv; + sha1_update(&sctx->md, in + sha_off, plen - sha_off); + + if (plen != len) { /* "TLS" mode of operation */ + if (in != out) + memcpy(out + aes_off, in + aes_off, plen - aes_off); + + /* calculate HMAC and append it to payload */ + SHA1_Final(out + plen, &sctx->md); + sctx->md = sctx->tail; + sha1_update(&sctx->md, out + plen, SHA_DIGEST_LENGTH); + SHA1_Final(out + plen, &sctx->md); + + /* pad the payload|hmac */ + plen += SHA_DIGEST_LENGTH; + for (l = len - plen - 1; plen < len; plen++) + out[plen] = l; + /* encrypt HMAC|padding at once */ + aesni_cbc_encrypt(out + aes_off, out + aes_off, len - aes_off, + &ctx->ks, ctx->base.iv, 1); + } else { + aesni_cbc_encrypt(in + aes_off, out + aes_off, len - aes_off, + &ctx->ks, ctx->base.iv, 1); + } + } else { + union { + unsigned int u[SHA_DIGEST_LENGTH / sizeof(unsigned int)]; + unsigned char c[32 + SHA_DIGEST_LENGTH]; + } mac, *pmac; + + /* arrange cache line alignment */ + pmac = (void *)(((size_t)mac.c + 31) & ((size_t)0 - 32)); + + if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */ + size_t inp_len, mask, j, i; + unsigned int res, maxpad, pad, bitlen; + int ret = 1; + union { + unsigned int u[SHA_LBLOCK]; + unsigned char c[SHA_CBLOCK]; + } *data = (void *)sctx->md.data; + + if ((ctx->aux.tls_aad[plen - 4] << 8 | ctx->aux.tls_aad[plen - 3]) + >= TLS1_1_VERSION) { + if (len < (AES_BLOCK_SIZE + SHA_DIGEST_LENGTH + 1)) + return 0; + + /* omit explicit iv */ + memcpy(ctx->base.iv, in, AES_BLOCK_SIZE); + + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + len -= AES_BLOCK_SIZE; + } else if (len < (SHA_DIGEST_LENGTH + 1)) + return 0; + + /* decrypt HMAC|padding at once */ + aesni_cbc_encrypt(in, out, len, &ctx->ks, ctx->base.iv, 0); + + /* figure out payload length */ + pad = out[len - 1]; + maxpad = len - (SHA_DIGEST_LENGTH + 1); + maxpad |= (255 - maxpad) >> (sizeof(maxpad) * 8 - 8); + maxpad &= 255; + + mask = constant_time_ge(maxpad, pad); + ret &= mask; + /* + * If pad is invalid then we will fail the above test but we must + * continue anyway because we are in constant time code. However, + * we'll use the maxpad value instead of the supplied pad to make + * sure we perform well defined pointer arithmetic. + */ + pad = constant_time_select(mask, pad, maxpad); + + inp_len = len - (SHA_DIGEST_LENGTH + pad + 1); + + ctx->aux.tls_aad[plen - 2] = inp_len >> 8; + ctx->aux.tls_aad[plen - 1] = inp_len; + + /* calculate HMAC */ + sctx->md = sctx->head; + sha1_update(&sctx->md, ctx->aux.tls_aad, plen); + + /* code containing lucky-13 fix */ + len -= SHA_DIGEST_LENGTH; /* amend mac */ + if (len >= (256 + SHA_CBLOCK)) { + j = (len - (256 + SHA_CBLOCK)) & (0 - SHA_CBLOCK); + j += SHA_CBLOCK - sctx->md.num; + sha1_update(&sctx->md, out, j); + out += j; + len -= j; + inp_len -= j; + } + + /* but pretend as if we hashed padded payload */ + bitlen = sctx->md.Nl + (inp_len << 3); /* at most 18 bits */ +# ifdef BSWAP4 + bitlen = BSWAP4(bitlen); +# else + mac.c[0] = 0; + mac.c[1] = (unsigned char)(bitlen >> 16); + mac.c[2] = (unsigned char)(bitlen >> 8); + mac.c[3] = (unsigned char)bitlen; + bitlen = mac.u[0]; +# endif /* BSWAP */ + + pmac->u[0] = 0; + pmac->u[1] = 0; + pmac->u[2] = 0; + pmac->u[3] = 0; + pmac->u[4] = 0; + + for (res = sctx->md.num, j = 0; j < len; j++) { + size_t c = out[j]; + mask = (j - inp_len) >> (sizeof(j) * 8 - 8); + c &= mask; + c |= 0x80 & ~mask & ~((inp_len - j) >> (sizeof(j) * 8 - 8)); + data->c[res++] = (unsigned char)c; + + if (res != SHA_CBLOCK) + continue; + + /* j is not incremented yet */ + mask = 0 - ((inp_len + 7 - j) >> (sizeof(j) * 8 - 1)); + data->u[SHA_LBLOCK - 1] |= bitlen & mask; + sha1_block_data_order(&sctx->md, data, 1); + mask &= 0 - ((j - inp_len - 72) >> (sizeof(j) * 8 - 1)); + pmac->u[0] |= sctx->md.h0 & mask; + pmac->u[1] |= sctx->md.h1 & mask; + pmac->u[2] |= sctx->md.h2 & mask; + pmac->u[3] |= sctx->md.h3 & mask; + pmac->u[4] |= sctx->md.h4 & mask; + res = 0; + } + + for (i = res; i < SHA_CBLOCK; i++, j++) + data->c[i] = 0; + + if (res > SHA_CBLOCK - 8) { + mask = 0 - ((inp_len + 8 - j) >> (sizeof(j) * 8 - 1)); + data->u[SHA_LBLOCK - 1] |= bitlen & mask; + sha1_block_data_order(&sctx->md, data, 1); + mask &= 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1)); + pmac->u[0] |= sctx->md.h0 & mask; + pmac->u[1] |= sctx->md.h1 & mask; + pmac->u[2] |= sctx->md.h2 & mask; + pmac->u[3] |= sctx->md.h3 & mask; + pmac->u[4] |= sctx->md.h4 & mask; + + memset(data, 0, SHA_CBLOCK); + j += 64; + } + data->u[SHA_LBLOCK - 1] = bitlen; + sha1_block_data_order(&sctx->md, data, 1); + mask = 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1)); + pmac->u[0] |= sctx->md.h0 & mask; + pmac->u[1] |= sctx->md.h1 & mask; + pmac->u[2] |= sctx->md.h2 & mask; + pmac->u[3] |= sctx->md.h3 & mask; + pmac->u[4] |= sctx->md.h4 & mask; + +# ifdef BSWAP4 + pmac->u[0] = BSWAP4(pmac->u[0]); + pmac->u[1] = BSWAP4(pmac->u[1]); + pmac->u[2] = BSWAP4(pmac->u[2]); + pmac->u[3] = BSWAP4(pmac->u[3]); + pmac->u[4] = BSWAP4(pmac->u[4]); +# else + for (i = 0; i < 5; i++) { + res = pmac->u[i]; + pmac->c[4 * i + 0] = (unsigned char)(res >> 24); + pmac->c[4 * i + 1] = (unsigned char)(res >> 16); + pmac->c[4 * i + 2] = (unsigned char)(res >> 8); + pmac->c[4 * i + 3] = (unsigned char)res; + } +# endif /* BSWAP4 */ + len += SHA_DIGEST_LENGTH; + sctx->md = sctx->tail; + sha1_update(&sctx->md, pmac->c, SHA_DIGEST_LENGTH); + SHA1_Final(pmac->c, &sctx->md); + + /* verify HMAC */ + out += inp_len; + len -= inp_len; + /* version of code with lucky-13 fix */ + { + unsigned char *p = out + len - 1 - maxpad - SHA_DIGEST_LENGTH; + size_t off = out - p; + unsigned int c, cmask; + + for (res = 0, i = 0, j = 0; j < maxpad + SHA_DIGEST_LENGTH; j++) { + c = p[j]; + cmask = + ((int)(j - off - SHA_DIGEST_LENGTH)) >> (sizeof(int) * + 8 - 1); + res |= (c ^ pad) & ~cmask; /* ... and padding */ + cmask &= ((int)(off - 1 - j)) >> (sizeof(int) * 8 - 1); + res |= (c ^ pmac->c[i]) & cmask; + i += 1 & cmask; + } + + res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1)); + ret &= (int)~res; + } + return ret; + } else { + /* decrypt HMAC|padding at once */ + aesni_cbc_encrypt(in, out, len, &ctx->ks, ctx->base.iv, 0); + sha1_update(&sctx->md, out, len); + } + } + + return 1; +} + +/* EVP_CTRL_AEAD_SET_MAC_KEY */ +static void aesni_cbc_hmac_sha1_set_mac_key(void *vctx, + const unsigned char *mac, size_t len) +{ + PROV_AES_HMAC_SHA1_CTX *ctx = (PROV_AES_HMAC_SHA1_CTX *)vctx; + unsigned int i; + unsigned char hmac_key[64]; + + memset(hmac_key, 0, sizeof(hmac_key)); + + if (len > (int)sizeof(hmac_key)) { + SHA1_Init(&ctx->head); + sha1_update(&ctx->head, mac, len); + SHA1_Final(hmac_key, &ctx->head); + } else { + memcpy(hmac_key, mac, len); + } + + for (i = 0; i < sizeof(hmac_key); i++) + hmac_key[i] ^= 0x36; /* ipad */ + SHA1_Init(&ctx->head); + sha1_update(&ctx->head, hmac_key, sizeof(hmac_key)); + + for (i = 0; i < sizeof(hmac_key); i++) + hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */ + SHA1_Init(&ctx->tail); + sha1_update(&ctx->tail, hmac_key, sizeof(hmac_key)); + + OPENSSL_cleanse(hmac_key, sizeof(hmac_key)); +} + +/* EVP_CTRL_AEAD_TLS1_AAD */ +static int aesni_cbc_hmac_sha1_set_tls1_aad(void *vctx, + unsigned char *aad_rec, int aad_len) +{ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_AES_HMAC_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx; + unsigned char *p = aad_rec; + unsigned int len; + + if (aad_len != EVP_AEAD_TLS1_AAD_LEN) + return -1; + + len = p[aad_len - 2] << 8 | p[aad_len - 1]; + + if (ctx->base.enc) { + ctx->payload_length = len; + if ((ctx->aux.tls_ver = + p[aad_len - 4] << 8 | p[aad_len - 3]) >= TLS1_1_VERSION) { + if (len < AES_BLOCK_SIZE) + return 0; + len -= AES_BLOCK_SIZE; + p[aad_len - 2] = len >> 8; + p[aad_len - 1] = len; + } + sctx->md = sctx->head; + sha1_update(&sctx->md, p, aad_len); + ctx->tls_aad_pad = (int)(((len + SHA_DIGEST_LENGTH + + AES_BLOCK_SIZE) & -AES_BLOCK_SIZE) + - len); + return 1; + } else { + memcpy(ctx->aux.tls_aad, aad_rec, aad_len); + ctx->payload_length = aad_len; + ctx->tls_aad_pad = SHA_DIGEST_LENGTH; + return 1; + } +} + +# if !defined(OPENSSL_NO_MULTIBLOCK) + +/* EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE */ +static int aesni_cbc_hmac_sha1_tls1_multiblock_max_bufsize(void *vctx) +{ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + + OPENSSL_assert(ctx->multiblock_max_send_fragment != 0); + return (int)(5 + 16 + + (((int)ctx->multiblock_max_send_fragment + 20 + 16) & -16)); +} + +/* EVP_CTRL_TLS1_1_MULTIBLOCK_AAD */ +static int aesni_cbc_hmac_sha1_tls1_multiblock_aad( + void *vctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param) +{ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_AES_HMAC_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx; + unsigned int n4x = 1, x4; + unsigned int frag, last, packlen, inp_len; + + inp_len = param->inp[11] << 8 | param->inp[12]; + ctx->multiblock_interleave = param->interleave; + + if (ctx->base.enc) { + if ((param->inp[9] << 8 | param->inp[10]) < TLS1_1_VERSION) + return -1; + + if (inp_len) { + if (inp_len < 4096) + return 0; /* too short */ + + if (inp_len >= 8192 && OPENSSL_ia32cap_P[2] & (1 << 5)) + n4x = 2; /* AVX2 */ + } else if ((n4x = param->interleave / 4) && n4x <= 2) + inp_len = param->len; + else + return -1; + + sctx->md = sctx->head; + sha1_update(&sctx->md, param->inp, 13); + + x4 = 4 * n4x; + n4x += 1; + + frag = inp_len >> n4x; + last = inp_len + frag - (frag << n4x); + if (last > frag && ((last + 13 + 9) % 64 < (x4 - 1))) { + frag++; + last -= x4 - 1; + } + + packlen = 5 + 16 + ((frag + 20 + 16) & -16); + packlen = (packlen << n4x) - packlen; + packlen += 5 + 16 + ((last + 20 + 16) & -16); + + param->interleave = x4; + /* The returned values used by get need to be stored */ + ctx->multiblock_interleave = x4; + ctx->multiblock_aad_packlen = packlen; + return 1; + } + return -1; /* not yet */ +} + +/* EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT */ +static int aesni_cbc_hmac_sha1_tls1_multiblock_encrypt( + void *ctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param) +{ + return (int)tls1_multi_block_encrypt(ctx, param->out, + param->inp, param->len, + param->interleave / 4); +} + +# endif /* OPENSSL_NO_MULTIBLOCK */ + +static const PROV_CIPHER_HW_AES_HMAC_SHA cipher_hw_aes_hmac_sha1 = { + { + aesni_cbc_hmac_sha1_init_key, + aesni_cbc_hmac_sha1_cipher + }, + aesni_cbc_hmac_sha1_set_mac_key, + aesni_cbc_hmac_sha1_set_tls1_aad, +# if !defined(OPENSSL_NO_MULTIBLOCK) + aesni_cbc_hmac_sha1_tls1_multiblock_max_bufsize, + aesni_cbc_hmac_sha1_tls1_multiblock_aad, + aesni_cbc_hmac_sha1_tls1_multiblock_encrypt +# endif +}; + +const PROV_CIPHER_HW_AES_HMAC_SHA *ossl_prov_cipher_hw_aes_cbc_hmac_sha1(void) +{ + return &cipher_hw_aes_hmac_sha1; +} + +#endif /* !defined(AES_CBC_HMAC_SHA_CAPABLE) || !defined(AESNI_CAPABLE) */ diff --git a/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha256_hw.c b/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha256_hw.c new file mode 100644 index 000000000000..f5b2f8b6da32 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha256_hw.c @@ -0,0 +1,846 @@ +/* + * Copyright 2011-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * All low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +#include "cipher_aes_cbc_hmac_sha.h" + +#if !defined(AES_CBC_HMAC_SHA_CAPABLE) || !defined(AESNI_CAPABLE) +int ossl_cipher_capable_aes_cbc_hmac_sha256(void) +{ + return 0; +} + +const PROV_CIPHER_HW_AES_HMAC_SHA *ossl_prov_cipher_hw_aes_cbc_hmac_sha256(void) +{ + return NULL; +} +#else + +# include <openssl/rand.h> +# include "crypto/evp.h" +# include "internal/constant_time.h" + +void sha256_block_data_order(void *c, const void *p, size_t len); +int aesni_cbc_sha256_enc(const void *inp, void *out, size_t blocks, + const AES_KEY *key, unsigned char iv[16], + SHA256_CTX *ctx, const void *in0); + +int ossl_cipher_capable_aes_cbc_hmac_sha256(void) +{ + return AESNI_CBC_HMAC_SHA_CAPABLE + && aesni_cbc_sha256_enc(NULL, NULL, 0, NULL, NULL, NULL, NULL); +} + +static int aesni_cbc_hmac_sha256_init_key(PROV_CIPHER_CTX *vctx, + const unsigned char *key, + size_t keylen) +{ + int ret; + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx; + + if (ctx->base.enc) + ret = aesni_set_encrypt_key(key, ctx->base.keylen * 8, &ctx->ks); + else + ret = aesni_set_decrypt_key(key, ctx->base.keylen * 8, &ctx->ks); + + SHA256_Init(&sctx->head); /* handy when benchmarking */ + sctx->tail = sctx->head; + sctx->md = sctx->head; + + ctx->payload_length = NO_PAYLOAD_LENGTH; + + vctx->removetlspad = 1; + vctx->removetlsfixed = SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE; + + return ret < 0 ? 0 : 1; +} + +void sha256_block_data_order(void *c, const void *p, size_t len); + +static void sha256_update(SHA256_CTX *c, const void *data, size_t len) +{ + const unsigned char *ptr = data; + size_t res; + + if ((res = c->num)) { + res = SHA256_CBLOCK - res; + if (len < res) + res = len; + SHA256_Update(c, ptr, res); + ptr += res; + len -= res; + } + + res = len % SHA256_CBLOCK; + len -= res; + + if (len) { + sha256_block_data_order(c, ptr, len / SHA256_CBLOCK); + + ptr += len; + c->Nh += len >> 29; + c->Nl += len <<= 3; + if (c->Nl < (unsigned int)len) + c->Nh++; + } + + if (res) + SHA256_Update(c, ptr, res); +} + +# if !defined(OPENSSL_NO_MULTIBLOCK) + +typedef struct { + unsigned int A[8], B[8], C[8], D[8], E[8], F[8], G[8], H[8]; +} SHA256_MB_CTX; + +typedef struct { + const unsigned char *ptr; + int blocks; +} HASH_DESC; + +typedef struct { + const unsigned char *inp; + unsigned char *out; + int blocks; + u64 iv[2]; +} CIPH_DESC; + +void sha256_multi_block(SHA256_MB_CTX *, const HASH_DESC *, int); +void aesni_multi_cbc_encrypt(CIPH_DESC *, void *, int); + +static size_t tls1_multi_block_encrypt(void *vctx, + unsigned char *out, + const unsigned char *inp, + size_t inp_len, int n4x) +{ /* n4x is 1 or 2 */ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx; + HASH_DESC hash_d[8], edges[8]; + CIPH_DESC ciph_d[8]; + unsigned char storage[sizeof(SHA256_MB_CTX) + 32]; + union { + u64 q[16]; + u32 d[32]; + u8 c[128]; + } blocks[8]; + SHA256_MB_CTX *mctx; + unsigned int frag, last, packlen, i; + unsigned int x4 = 4 * n4x, minblocks, processed = 0; + size_t ret = 0; + u8 *IVs; +# if defined(BSWAP8) + u64 seqnum; +# endif + + /* ask for IVs in bulk */ + if (RAND_bytes_ex(ctx->base.libctx, (IVs = blocks[0].c), 16 * x4, 0) <= 0) + return 0; + + mctx = (SHA256_MB_CTX *) (storage + 32 - ((size_t)storage % 32)); /* align */ + + frag = (unsigned int)inp_len >> (1 + n4x); + last = (unsigned int)inp_len + frag - (frag << (1 + n4x)); + if (last > frag && ((last + 13 + 9) % 64) < (x4 - 1)) { + frag++; + last -= x4 - 1; + } + + packlen = 5 + 16 + ((frag + 32 + 16) & -16); + + /* populate descriptors with pointers and IVs */ + hash_d[0].ptr = inp; + ciph_d[0].inp = inp; + /* 5+16 is place for header and explicit IV */ + ciph_d[0].out = out + 5 + 16; + memcpy(ciph_d[0].out - 16, IVs, 16); + memcpy(ciph_d[0].iv, IVs, 16); + IVs += 16; + + for (i = 1; i < x4; i++) { + ciph_d[i].inp = hash_d[i].ptr = hash_d[i - 1].ptr + frag; + ciph_d[i].out = ciph_d[i - 1].out + packlen; + memcpy(ciph_d[i].out - 16, IVs, 16); + memcpy(ciph_d[i].iv, IVs, 16); + IVs += 16; + } + +# if defined(BSWAP8) + memcpy(blocks[0].c, sctx->md.data, 8); + seqnum = BSWAP8(blocks[0].q[0]); +# endif + + for (i = 0; i < x4; i++) { + unsigned int len = (i == (x4 - 1) ? last : frag); +# if !defined(BSWAP8) + unsigned int carry, j; +# endif + + mctx->A[i] = sctx->md.h[0]; + mctx->B[i] = sctx->md.h[1]; + mctx->C[i] = sctx->md.h[2]; + mctx->D[i] = sctx->md.h[3]; + mctx->E[i] = sctx->md.h[4]; + mctx->F[i] = sctx->md.h[5]; + mctx->G[i] = sctx->md.h[6]; + mctx->H[i] = sctx->md.h[7]; + + /* fix seqnum */ +# if defined(BSWAP8) + blocks[i].q[0] = BSWAP8(seqnum + i); +# else + for (carry = i, j = 8; j--;) { + blocks[i].c[j] = ((u8 *)sctx->md.data)[j] + carry; + carry = (blocks[i].c[j] - carry) >> (sizeof(carry) * 8 - 1); + } +# endif + blocks[i].c[8] = ((u8 *)sctx->md.data)[8]; + blocks[i].c[9] = ((u8 *)sctx->md.data)[9]; + blocks[i].c[10] = ((u8 *)sctx->md.data)[10]; + /* fix length */ + blocks[i].c[11] = (u8)(len >> 8); + blocks[i].c[12] = (u8)(len); + + memcpy(blocks[i].c + 13, hash_d[i].ptr, 64 - 13); + hash_d[i].ptr += 64 - 13; + hash_d[i].blocks = (len - (64 - 13)) / 64; + + edges[i].ptr = blocks[i].c; + edges[i].blocks = 1; + } + + /* hash 13-byte headers and first 64-13 bytes of inputs */ + sha256_multi_block(mctx, edges, n4x); + /* hash bulk inputs */ +# define MAXCHUNKSIZE 2048 +# if MAXCHUNKSIZE%64 +# error "MAXCHUNKSIZE is not divisible by 64" +# elif MAXCHUNKSIZE + /* + * goal is to minimize pressure on L1 cache by moving in shorter steps, + * so that hashed data is still in the cache by the time we encrypt it + */ + minblocks = ((frag <= last ? frag : last) - (64 - 13)) / 64; + if (minblocks > MAXCHUNKSIZE / 64) { + for (i = 0; i < x4; i++) { + edges[i].ptr = hash_d[i].ptr; + edges[i].blocks = MAXCHUNKSIZE / 64; + ciph_d[i].blocks = MAXCHUNKSIZE / 16; + } + do { + sha256_multi_block(mctx, edges, n4x); + aesni_multi_cbc_encrypt(ciph_d, &ctx->ks, n4x); + + for (i = 0; i < x4; i++) { + edges[i].ptr = hash_d[i].ptr += MAXCHUNKSIZE; + hash_d[i].blocks -= MAXCHUNKSIZE / 64; + edges[i].blocks = MAXCHUNKSIZE / 64; + ciph_d[i].inp += MAXCHUNKSIZE; + ciph_d[i].out += MAXCHUNKSIZE; + ciph_d[i].blocks = MAXCHUNKSIZE / 16; + memcpy(ciph_d[i].iv, ciph_d[i].out - 16, 16); + } + processed += MAXCHUNKSIZE; + minblocks -= MAXCHUNKSIZE / 64; + } while (minblocks > MAXCHUNKSIZE / 64); + } +# endif +# undef MAXCHUNKSIZE + sha256_multi_block(mctx, hash_d, n4x); + + memset(blocks, 0, sizeof(blocks)); + for (i = 0; i < x4; i++) { + unsigned int len = (i == (x4 - 1) ? last : frag), + off = hash_d[i].blocks * 64; + const unsigned char *ptr = hash_d[i].ptr + off; + + off = (len - processed) - (64 - 13) - off; /* remainder actually */ + memcpy(blocks[i].c, ptr, off); + blocks[i].c[off] = 0x80; + len += 64 + 13; /* 64 is HMAC header */ + len *= 8; /* convert to bits */ + if (off < (64 - 8)) { +# ifdef BSWAP4 + blocks[i].d[15] = BSWAP4(len); +# else + PUTU32(blocks[i].c + 60, len); +# endif + edges[i].blocks = 1; + } else { +# ifdef BSWAP4 + blocks[i].d[31] = BSWAP4(len); +# else + PUTU32(blocks[i].c + 124, len); +# endif + edges[i].blocks = 2; + } + edges[i].ptr = blocks[i].c; + } + + /* hash input tails and finalize */ + sha256_multi_block(mctx, edges, n4x); + + memset(blocks, 0, sizeof(blocks)); + for (i = 0; i < x4; i++) { +# ifdef BSWAP4 + blocks[i].d[0] = BSWAP4(mctx->A[i]); + mctx->A[i] = sctx->tail.h[0]; + blocks[i].d[1] = BSWAP4(mctx->B[i]); + mctx->B[i] = sctx->tail.h[1]; + blocks[i].d[2] = BSWAP4(mctx->C[i]); + mctx->C[i] = sctx->tail.h[2]; + blocks[i].d[3] = BSWAP4(mctx->D[i]); + mctx->D[i] = sctx->tail.h[3]; + blocks[i].d[4] = BSWAP4(mctx->E[i]); + mctx->E[i] = sctx->tail.h[4]; + blocks[i].d[5] = BSWAP4(mctx->F[i]); + mctx->F[i] = sctx->tail.h[5]; + blocks[i].d[6] = BSWAP4(mctx->G[i]); + mctx->G[i] = sctx->tail.h[6]; + blocks[i].d[7] = BSWAP4(mctx->H[i]); + mctx->H[i] = sctx->tail.h[7]; + blocks[i].c[32] = 0x80; + blocks[i].d[15] = BSWAP4((64 + 32) * 8); +# else + PUTU32(blocks[i].c + 0, mctx->A[i]); + mctx->A[i] = sctx->tail.h[0]; + PUTU32(blocks[i].c + 4, mctx->B[i]); + mctx->B[i] = sctx->tail.h[1]; + PUTU32(blocks[i].c + 8, mctx->C[i]); + mctx->C[i] = sctx->tail.h[2]; + PUTU32(blocks[i].c + 12, mctx->D[i]); + mctx->D[i] = sctx->tail.h[3]; + PUTU32(blocks[i].c + 16, mctx->E[i]); + mctx->E[i] = sctx->tail.h[4]; + PUTU32(blocks[i].c + 20, mctx->F[i]); + mctx->F[i] = sctx->tail.h[5]; + PUTU32(blocks[i].c + 24, mctx->G[i]); + mctx->G[i] = sctx->tail.h[6]; + PUTU32(blocks[i].c + 28, mctx->H[i]); + mctx->H[i] = sctx->tail.h[7]; + blocks[i].c[32] = 0x80; + PUTU32(blocks[i].c + 60, (64 + 32) * 8); +# endif /* BSWAP */ + edges[i].ptr = blocks[i].c; + edges[i].blocks = 1; + } + + /* finalize MACs */ + sha256_multi_block(mctx, edges, n4x); + + for (i = 0; i < x4; i++) { + unsigned int len = (i == (x4 - 1) ? last : frag), pad, j; + unsigned char *out0 = out; + + memcpy(ciph_d[i].out, ciph_d[i].inp, len - processed); + ciph_d[i].inp = ciph_d[i].out; + + out += 5 + 16 + len; + + /* write MAC */ + PUTU32(out + 0, mctx->A[i]); + PUTU32(out + 4, mctx->B[i]); + PUTU32(out + 8, mctx->C[i]); + PUTU32(out + 12, mctx->D[i]); + PUTU32(out + 16, mctx->E[i]); + PUTU32(out + 20, mctx->F[i]); + PUTU32(out + 24, mctx->G[i]); + PUTU32(out + 28, mctx->H[i]); + out += 32; + len += 32; + + /* pad */ + pad = 15 - len % 16; + for (j = 0; j <= pad; j++) + *(out++) = pad; + len += pad + 1; + + ciph_d[i].blocks = (len - processed) / 16; + len += 16; /* account for explicit iv */ + + /* arrange header */ + out0[0] = ((u8 *)sctx->md.data)[8]; + out0[1] = ((u8 *)sctx->md.data)[9]; + out0[2] = ((u8 *)sctx->md.data)[10]; + out0[3] = (u8)(len >> 8); + out0[4] = (u8)(len); + + ret += len + 5; + inp += frag; + } + + aesni_multi_cbc_encrypt(ciph_d, &ctx->ks, n4x); + + OPENSSL_cleanse(blocks, sizeof(blocks)); + OPENSSL_cleanse(mctx, sizeof(*mctx)); + + ctx->multiblock_encrypt_len = ret; + return ret; +} +# endif /* !OPENSSL_NO_MULTIBLOCK */ + +static int aesni_cbc_hmac_sha256_cipher(PROV_CIPHER_CTX *vctx, + unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx; + unsigned int l; + size_t plen = ctx->payload_length; + size_t iv = 0; /* explicit IV in TLS 1.1 and * later */ + size_t aes_off = 0, blocks; + size_t sha_off = SHA256_CBLOCK - sctx->md.num; + + ctx->payload_length = NO_PAYLOAD_LENGTH; + + if (len % AES_BLOCK_SIZE) + return 0; + + if (ctx->base.enc) { + if (plen == NO_PAYLOAD_LENGTH) + plen = len; + else if (len != + ((plen + SHA256_DIGEST_LENGTH + + AES_BLOCK_SIZE) & -AES_BLOCK_SIZE)) + return 0; + else if (ctx->aux.tls_ver >= TLS1_1_VERSION) + iv = AES_BLOCK_SIZE; + + /* + * Assembly stitch handles AVX-capable processors, but its + * performance is not optimal on AMD Jaguar, ~40% worse, for + * unknown reasons. Incidentally processor in question supports + * AVX, but not AMD-specific XOP extension, which can be used + * to identify it and avoid stitch invocation. So that after we + * establish that current CPU supports AVX, we even see if it's + * either even XOP-capable Bulldozer-based or GenuineIntel one. + * But SHAEXT-capable go ahead... + */ + if (((OPENSSL_ia32cap_P[2] & (1 << 29)) || /* SHAEXT? */ + ((OPENSSL_ia32cap_P[1] & (1 << (60 - 32))) && /* AVX? */ + ((OPENSSL_ia32cap_P[1] & (1 << (43 - 32))) /* XOP? */ + | (OPENSSL_ia32cap_P[0] & (1 << 30))))) && /* "Intel CPU"? */ + plen > (sha_off + iv) && + (blocks = (plen - (sha_off + iv)) / SHA256_CBLOCK)) { + sha256_update(&sctx->md, in + iv, sha_off); + + (void)aesni_cbc_sha256_enc(in, out, blocks, &ctx->ks, + ctx->base.iv, + &sctx->md, in + iv + sha_off); + blocks *= SHA256_CBLOCK; + aes_off += blocks; + sha_off += blocks; + sctx->md.Nh += blocks >> 29; + sctx->md.Nl += blocks <<= 3; + if (sctx->md.Nl < (unsigned int)blocks) + sctx->md.Nh++; + } else { + sha_off = 0; + } + sha_off += iv; + sha256_update(&sctx->md, in + sha_off, plen - sha_off); + + if (plen != len) { /* "TLS" mode of operation */ + if (in != out) + memcpy(out + aes_off, in + aes_off, plen - aes_off); + + /* calculate HMAC and append it to payload */ + SHA256_Final(out + plen, &sctx->md); + sctx->md = sctx->tail; + sha256_update(&sctx->md, out + plen, SHA256_DIGEST_LENGTH); + SHA256_Final(out + plen, &sctx->md); + + /* pad the payload|hmac */ + plen += SHA256_DIGEST_LENGTH; + for (l = len - plen - 1; plen < len; plen++) + out[plen] = l; + /* encrypt HMAC|padding at once */ + aesni_cbc_encrypt(out + aes_off, out + aes_off, len - aes_off, + &ctx->ks, ctx->base.iv, 1); + } else { + aesni_cbc_encrypt(in + aes_off, out + aes_off, len - aes_off, + &ctx->ks, ctx->base.iv, 1); + } + } else { + union { + unsigned int u[SHA256_DIGEST_LENGTH / sizeof(unsigned int)]; + unsigned char c[64 + SHA256_DIGEST_LENGTH]; + } mac, *pmac; + + /* arrange cache line alignment */ + pmac = (void *)(((size_t)mac.c + 63) & ((size_t)0 - 64)); + + /* decrypt HMAC|padding at once */ + aesni_cbc_encrypt(in, out, len, &ctx->ks, + ctx->base.iv, 0); + + if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */ + size_t inp_len, mask, j, i; + unsigned int res, maxpad, pad, bitlen; + int ret = 1; + union { + unsigned int u[SHA_LBLOCK]; + unsigned char c[SHA256_CBLOCK]; + } *data = (void *)sctx->md.data; + + if ((ctx->aux.tls_aad[plen - 4] << 8 | ctx->aux.tls_aad[plen - 3]) + >= TLS1_1_VERSION) + iv = AES_BLOCK_SIZE; + + if (len < (iv + SHA256_DIGEST_LENGTH + 1)) + return 0; + + /* omit explicit iv */ + out += iv; + len -= iv; + + /* figure out payload length */ + pad = out[len - 1]; + maxpad = len - (SHA256_DIGEST_LENGTH + 1); + maxpad |= (255 - maxpad) >> (sizeof(maxpad) * 8 - 8); + maxpad &= 255; + + mask = constant_time_ge(maxpad, pad); + ret &= mask; + /* + * If pad is invalid then we will fail the above test but we must + * continue anyway because we are in constant time code. However, + * we'll use the maxpad value instead of the supplied pad to make + * sure we perform well defined pointer arithmetic. + */ + pad = constant_time_select(mask, pad, maxpad); + + inp_len = len - (SHA256_DIGEST_LENGTH + pad + 1); + + ctx->aux.tls_aad[plen - 2] = inp_len >> 8; + ctx->aux.tls_aad[plen - 1] = inp_len; + + /* calculate HMAC */ + sctx->md = sctx->head; + sha256_update(&sctx->md, ctx->aux.tls_aad, plen); + + /* code with lucky-13 fix */ + len -= SHA256_DIGEST_LENGTH; /* amend mac */ + if (len >= (256 + SHA256_CBLOCK)) { + j = (len - (256 + SHA256_CBLOCK)) & (0 - SHA256_CBLOCK); + j += SHA256_CBLOCK - sctx->md.num; + sha256_update(&sctx->md, out, j); + out += j; + len -= j; + inp_len -= j; + } + + /* but pretend as if we hashed padded payload */ + bitlen = sctx->md.Nl + (inp_len << 3); /* at most 18 bits */ +# ifdef BSWAP4 + bitlen = BSWAP4(bitlen); +# else + mac.c[0] = 0; + mac.c[1] = (unsigned char)(bitlen >> 16); + mac.c[2] = (unsigned char)(bitlen >> 8); + mac.c[3] = (unsigned char)bitlen; + bitlen = mac.u[0]; +# endif /* BSWAP */ + + pmac->u[0] = 0; + pmac->u[1] = 0; + pmac->u[2] = 0; + pmac->u[3] = 0; + pmac->u[4] = 0; + pmac->u[5] = 0; + pmac->u[6] = 0; + pmac->u[7] = 0; + + for (res = sctx->md.num, j = 0; j < len; j++) { + size_t c = out[j]; + mask = (j - inp_len) >> (sizeof(j) * 8 - 8); + c &= mask; + c |= 0x80 & ~mask & ~((inp_len - j) >> (sizeof(j) * 8 - 8)); + data->c[res++] = (unsigned char)c; + + if (res != SHA256_CBLOCK) + continue; + + /* j is not incremented yet */ + mask = 0 - ((inp_len + 7 - j) >> (sizeof(j) * 8 - 1)); + data->u[SHA_LBLOCK - 1] |= bitlen & mask; + sha256_block_data_order(&sctx->md, data, 1); + mask &= 0 - ((j - inp_len - 72) >> (sizeof(j) * 8 - 1)); + pmac->u[0] |= sctx->md.h[0] & mask; + pmac->u[1] |= sctx->md.h[1] & mask; + pmac->u[2] |= sctx->md.h[2] & mask; + pmac->u[3] |= sctx->md.h[3] & mask; + pmac->u[4] |= sctx->md.h[4] & mask; + pmac->u[5] |= sctx->md.h[5] & mask; + pmac->u[6] |= sctx->md.h[6] & mask; + pmac->u[7] |= sctx->md.h[7] & mask; + res = 0; + } + + for (i = res; i < SHA256_CBLOCK; i++, j++) + data->c[i] = 0; + + if (res > SHA256_CBLOCK - 8) { + mask = 0 - ((inp_len + 8 - j) >> (sizeof(j) * 8 - 1)); + data->u[SHA_LBLOCK - 1] |= bitlen & mask; + sha256_block_data_order(&sctx->md, data, 1); + mask &= 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1)); + pmac->u[0] |= sctx->md.h[0] & mask; + pmac->u[1] |= sctx->md.h[1] & mask; + pmac->u[2] |= sctx->md.h[2] & mask; + pmac->u[3] |= sctx->md.h[3] & mask; + pmac->u[4] |= sctx->md.h[4] & mask; + pmac->u[5] |= sctx->md.h[5] & mask; + pmac->u[6] |= sctx->md.h[6] & mask; + pmac->u[7] |= sctx->md.h[7] & mask; + + memset(data, 0, SHA256_CBLOCK); + j += 64; + } + data->u[SHA_LBLOCK - 1] = bitlen; + sha256_block_data_order(&sctx->md, data, 1); + mask = 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1)); + pmac->u[0] |= sctx->md.h[0] & mask; + pmac->u[1] |= sctx->md.h[1] & mask; + pmac->u[2] |= sctx->md.h[2] & mask; + pmac->u[3] |= sctx->md.h[3] & mask; + pmac->u[4] |= sctx->md.h[4] & mask; + pmac->u[5] |= sctx->md.h[5] & mask; + pmac->u[6] |= sctx->md.h[6] & mask; + pmac->u[7] |= sctx->md.h[7] & mask; + +# ifdef BSWAP4 + pmac->u[0] = BSWAP4(pmac->u[0]); + pmac->u[1] = BSWAP4(pmac->u[1]); + pmac->u[2] = BSWAP4(pmac->u[2]); + pmac->u[3] = BSWAP4(pmac->u[3]); + pmac->u[4] = BSWAP4(pmac->u[4]); + pmac->u[5] = BSWAP4(pmac->u[5]); + pmac->u[6] = BSWAP4(pmac->u[6]); + pmac->u[7] = BSWAP4(pmac->u[7]); +# else + for (i = 0; i < 8; i++) { + res = pmac->u[i]; + pmac->c[4 * i + 0] = (unsigned char)(res >> 24); + pmac->c[4 * i + 1] = (unsigned char)(res >> 16); + pmac->c[4 * i + 2] = (unsigned char)(res >> 8); + pmac->c[4 * i + 3] = (unsigned char)res; + } +# endif /* BSWAP */ + len += SHA256_DIGEST_LENGTH; + sctx->md = sctx->tail; + sha256_update(&sctx->md, pmac->c, SHA256_DIGEST_LENGTH); + SHA256_Final(pmac->c, &sctx->md); + + /* verify HMAC */ + out += inp_len; + len -= inp_len; + /* code containing lucky-13 fix */ + { + unsigned char *p = + out + len - 1 - maxpad - SHA256_DIGEST_LENGTH; + size_t off = out - p; + unsigned int c, cmask; + + for (res = 0, i = 0, j = 0; + j < maxpad + SHA256_DIGEST_LENGTH; + j++) { + c = p[j]; + cmask = + ((int)(j - off - SHA256_DIGEST_LENGTH)) >> + (sizeof(int) * 8 - 1); + res |= (c ^ pad) & ~cmask; /* ... and padding */ + cmask &= ((int)(off - 1 - j)) >> (sizeof(int) * 8 - 1); + res |= (c ^ pmac->c[i]) & cmask; + i += 1 & cmask; + } + + res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1)); + ret &= (int)~res; + } + return ret; + } else { + sha256_update(&sctx->md, out, len); + } + } + + return 1; +} + +/* EVP_CTRL_AEAD_SET_MAC_KEY */ +static void aesni_cbc_hmac_sha256_set_mac_key(void *vctx, + const unsigned char *mackey, + size_t len) +{ + PROV_AES_HMAC_SHA256_CTX *ctx = (PROV_AES_HMAC_SHA256_CTX *)vctx; + unsigned int i; + unsigned char hmac_key[64]; + + memset(hmac_key, 0, sizeof(hmac_key)); + + if (len > sizeof(hmac_key)) { + SHA256_Init(&ctx->head); + sha256_update(&ctx->head, mackey, len); + SHA256_Final(hmac_key, &ctx->head); + } else { + memcpy(hmac_key, mackey, len); + } + + for (i = 0; i < sizeof(hmac_key); i++) + hmac_key[i] ^= 0x36; /* ipad */ + SHA256_Init(&ctx->head); + sha256_update(&ctx->head, hmac_key, sizeof(hmac_key)); + + for (i = 0; i < sizeof(hmac_key); i++) + hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */ + SHA256_Init(&ctx->tail); + sha256_update(&ctx->tail, hmac_key, sizeof(hmac_key)); + + OPENSSL_cleanse(hmac_key, sizeof(hmac_key)); +} + +/* EVP_CTRL_AEAD_TLS1_AAD */ +static int aesni_cbc_hmac_sha256_set_tls1_aad(void *vctx, + unsigned char *aad_rec, int aad_len) +{ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx; + unsigned char *p = aad_rec; + unsigned int len; + + if (aad_len != EVP_AEAD_TLS1_AAD_LEN) + return -1; + + len = p[aad_len - 2] << 8 | p[aad_len - 1]; + + if (ctx->base.enc) { + ctx->payload_length = len; + if ((ctx->aux.tls_ver = + p[aad_len - 4] << 8 | p[aad_len - 3]) >= TLS1_1_VERSION) { + if (len < AES_BLOCK_SIZE) + return 0; + len -= AES_BLOCK_SIZE; + p[aad_len - 2] = len >> 8; + p[aad_len - 1] = len; + } + sctx->md = sctx->head; + sha256_update(&sctx->md, p, aad_len); + ctx->tls_aad_pad = (int)(((len + SHA256_DIGEST_LENGTH + + AES_BLOCK_SIZE) & -AES_BLOCK_SIZE) + - len); + return 1; + } else { + memcpy(ctx->aux.tls_aad, p, aad_len); + ctx->payload_length = aad_len; + ctx->tls_aad_pad = SHA256_DIGEST_LENGTH; + return 1; + } +} + +# if !defined(OPENSSL_NO_MULTIBLOCK) +/* EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE */ +static int aesni_cbc_hmac_sha256_tls1_multiblock_max_bufsize( + void *vctx) +{ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + + OPENSSL_assert(ctx->multiblock_max_send_fragment != 0); + return (int)(5 + 16 + + (((int)ctx->multiblock_max_send_fragment + 32 + 16) & -16)); +} + +/* EVP_CTRL_TLS1_1_MULTIBLOCK_AAD */ +static int aesni_cbc_hmac_sha256_tls1_multiblock_aad( + void *vctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param) +{ + PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx; + PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx; + unsigned int n4x = 1, x4; + unsigned int frag, last, packlen, inp_len; + + inp_len = param->inp[11] << 8 | param->inp[12]; + + if (ctx->base.enc) { + if ((param->inp[9] << 8 | param->inp[10]) < TLS1_1_VERSION) + return -1; + + if (inp_len) { + if (inp_len < 4096) + return 0; /* too short */ + + if (inp_len >= 8192 && OPENSSL_ia32cap_P[2] & (1 << 5)) + n4x = 2; /* AVX2 */ + } else if ((n4x = param->interleave / 4) && n4x <= 2) + inp_len = param->len; + else + return -1; + + sctx->md = sctx->head; + sha256_update(&sctx->md, param->inp, 13); + + x4 = 4 * n4x; + n4x += 1; + + frag = inp_len >> n4x; + last = inp_len + frag - (frag << n4x); + if (last > frag && ((last + 13 + 9) % 64 < (x4 - 1))) { + frag++; + last -= x4 - 1; + } + + packlen = 5 + 16 + ((frag + 32 + 16) & -16); + packlen = (packlen << n4x) - packlen; + packlen += 5 + 16 + ((last + 32 + 16) & -16); + + param->interleave = x4; + /* The returned values used by get need to be stored */ + ctx->multiblock_interleave = x4; + ctx->multiblock_aad_packlen = packlen; + return 1; + } + return -1; /* not yet */ +} + +/* EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT */ +static int aesni_cbc_hmac_sha256_tls1_multiblock_encrypt( + void *ctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param) +{ + return (int)tls1_multi_block_encrypt(ctx, param->out, + param->inp, param->len, + param->interleave / 4); +} +# endif + +static const PROV_CIPHER_HW_AES_HMAC_SHA cipher_hw_aes_hmac_sha256 = { + { + aesni_cbc_hmac_sha256_init_key, + aesni_cbc_hmac_sha256_cipher + }, + aesni_cbc_hmac_sha256_set_mac_key, + aesni_cbc_hmac_sha256_set_tls1_aad, +# if !defined(OPENSSL_NO_MULTIBLOCK) + aesni_cbc_hmac_sha256_tls1_multiblock_max_bufsize, + aesni_cbc_hmac_sha256_tls1_multiblock_aad, + aesni_cbc_hmac_sha256_tls1_multiblock_encrypt +# endif +}; + +const PROV_CIPHER_HW_AES_HMAC_SHA *ossl_prov_cipher_hw_aes_cbc_hmac_sha256(void) +{ + return &cipher_hw_aes_hmac_sha256; +} + +#endif /* !defined(AES_CBC_HMAC_SHA_CAPABLE) || !defined(AESNI_CAPABLE) */ diff --git a/providers/implementations/ciphers/cipher_aes_ccm.c b/providers/implementations/ciphers/cipher_aes_ccm.c new file mode 100644 index 000000000000..bb4b1e1e6490 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_ccm.c @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * AES low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +/* Dispatch functions for AES CCM mode */ + +#include "cipher_aes_ccm.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +static void *aes_ccm_newctx(void *provctx, size_t keybits) +{ + PROV_AES_CCM_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + ossl_ccm_initctx(&ctx->base, keybits, ossl_prov_aes_hw_ccm(keybits)); + return ctx; +} + +static OSSL_FUNC_cipher_freectx_fn aes_ccm_freectx; +static void aes_ccm_freectx(void *vctx) +{ + PROV_AES_CCM_CTX *ctx = (PROV_AES_CCM_CTX *)vctx; + + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +/* ossl_aes128ccm_functions */ +IMPLEMENT_aead_cipher(aes, ccm, CCM, AEAD_FLAGS, 128, 8, 96); +/* ossl_aes192ccm_functions */ +IMPLEMENT_aead_cipher(aes, ccm, CCM, AEAD_FLAGS, 192, 8, 96); +/* ossl_aes256ccm_functions */ +IMPLEMENT_aead_cipher(aes, ccm, CCM, AEAD_FLAGS, 256, 8, 96); diff --git a/providers/implementations/ciphers/cipher_aes_ccm.h b/providers/implementations/ciphers/cipher_aes_ccm.h new file mode 100644 index 000000000000..fd35080db3dd --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_ccm.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/aes.h> +#include "prov/ciphercommon.h" +#include "prov/ciphercommon_ccm.h" +#include "crypto/aes_platform.h" + +typedef struct prov_aes_ccm_ctx_st { + PROV_CCM_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + /*- + * Padding is chosen so that s390x.kmac.k overlaps with ks.ks and + * fc with ks.ks.rounds. Remember that on s390x, an AES_KEY's + * rounds field is used to store the function code and that the key + * schedule is not stored (if aes hardware support is detected). + */ + struct { + unsigned char pad[16]; + AES_KEY ks; + } ks; +#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__) + struct { + S390X_KMAC_PARAMS kmac; + unsigned long long blocks; + union { + unsigned long long g[2]; + unsigned char b[AES_BLOCK_SIZE]; + } nonce; + union { + unsigned long long g[2]; + unsigned char b[AES_BLOCK_SIZE]; + } buf; + unsigned char dummy_pad[168]; + unsigned int fc; /* fc has same offset as ks.ks.rounds */ + } s390x; +#endif /* defined(OPENSSL_CPUID_OBJ) && defined(__s390__) */ + } ccm; +} PROV_AES_CCM_CTX; + +const PROV_CCM_HW *ossl_prov_aes_hw_ccm(size_t keylen); diff --git a/providers/implementations/ciphers/cipher_aes_ccm_hw.c b/providers/implementations/ciphers/cipher_aes_ccm_hw.c new file mode 100644 index 000000000000..263d1902817f --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_ccm_hw.c @@ -0,0 +1,69 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* AES CCM mode */ + +/* + * This file uses the low level AES functions (which are deprecated for + * non-internal use) in order to implement provider AES ciphers. + */ +#include "internal/deprecated.h" + +#include "cipher_aes_ccm.h" + +#define AES_HW_CCM_SET_KEY_FN(fn_set_enc_key, fn_blk, fn_ccm_enc, fn_ccm_dec) \ + fn_set_enc_key(key, keylen * 8, &actx->ccm.ks.ks); \ + CRYPTO_ccm128_init(&ctx->ccm_ctx, ctx->m, ctx->l, &actx->ccm.ks.ks, \ + (block128_f)fn_blk); \ + ctx->str = ctx->enc ? (ccm128_f)fn_ccm_enc : (ccm128_f)fn_ccm_dec; \ + ctx->key_set = 1; + +static int ccm_generic_aes_initkey(PROV_CCM_CTX *ctx, const unsigned char *key, + size_t keylen) +{ + PROV_AES_CCM_CTX *actx = (PROV_AES_CCM_CTX *)ctx; + +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) { + AES_HW_CCM_SET_KEY_FN(HWAES_set_encrypt_key, HWAES_encrypt, NULL, NULL); + } else +#endif /* HWAES_CAPABLE */ + +#ifdef VPAES_CAPABLE + if (VPAES_CAPABLE) { + AES_HW_CCM_SET_KEY_FN(vpaes_set_encrypt_key, vpaes_encrypt, NULL, NULL); + } else +#endif + { + AES_HW_CCM_SET_KEY_FN(AES_set_encrypt_key, AES_encrypt, NULL, NULL) + } + return 1; +} + +static const PROV_CCM_HW aes_ccm = { + ccm_generic_aes_initkey, + ossl_ccm_generic_setiv, + ossl_ccm_generic_setaad, + ossl_ccm_generic_auth_encrypt, + ossl_ccm_generic_auth_decrypt, + ossl_ccm_generic_gettag +}; + +#if defined(S390X_aes_128_CAPABLE) +# include "cipher_aes_ccm_hw_s390x.inc" +#elif defined(AESNI_CAPABLE) +# include "cipher_aes_ccm_hw_aesni.inc" +#elif defined(SPARC_AES_CAPABLE) +# include "cipher_aes_ccm_hw_t4.inc" +#else +const PROV_CCM_HW *ossl_prov_aes_hw_ccm(size_t keybits) +{ + return &aes_ccm; +} +#endif diff --git a/providers/implementations/ciphers/cipher_aes_ccm_hw_aesni.inc b/providers/implementations/ciphers/cipher_aes_ccm_hw_aesni.inc new file mode 100644 index 000000000000..579e5a3d4f13 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_ccm_hw_aesni.inc @@ -0,0 +1,38 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * AES-NI support for AES CCM. + * This file is included by cipher_aes_ccm_hw.c + */ + +static int ccm_aesni_initkey(PROV_CCM_CTX *ctx, const unsigned char *key, + size_t keylen) +{ + PROV_AES_CCM_CTX *actx = (PROV_AES_CCM_CTX *)ctx; + + AES_HW_CCM_SET_KEY_FN(aesni_set_encrypt_key, aesni_encrypt, + aesni_ccm64_encrypt_blocks, + aesni_ccm64_decrypt_blocks); + return 1; +} + +static const PROV_CCM_HW aesni_ccm = { + ccm_aesni_initkey, + ossl_ccm_generic_setiv, + ossl_ccm_generic_setaad, + ossl_ccm_generic_auth_encrypt, + ossl_ccm_generic_auth_decrypt, + ossl_ccm_generic_gettag +}; + +const PROV_CCM_HW *ossl_prov_aes_hw_ccm(size_t keybits) +{ + return AESNI_CAPABLE ? &aesni_ccm : &aes_ccm; +} diff --git a/providers/implementations/ciphers/cipher_aes_ccm_hw_s390x.inc b/providers/implementations/ciphers/cipher_aes_ccm_hw_s390x.inc new file mode 100644 index 000000000000..7253f03a7ef1 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_ccm_hw_s390x.inc @@ -0,0 +1,268 @@ +/* + * Copyright 2001-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * S390X support for AES CCM. + * This file is included by cipher_aes_ccm_hw.c + */ + +#define S390X_CCM_AAD_FLAG 0x40 + +static int s390x_aes_ccm_initkey(PROV_CCM_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; + + sctx->ccm.s390x.fc = S390X_AES_FC(keylen); + memcpy(&sctx->ccm.s390x.kmac.k, key, keylen); + /* Store encoded m and l. */ + sctx->ccm.s390x.nonce.b[0] = ((ctx->l - 1) & 0x7) + | (((ctx->m - 2) >> 1) & 0x7) << 3; + memset(sctx->ccm.s390x.nonce.b + 1, 0, sizeof(sctx->ccm.s390x.nonce.b)); + sctx->ccm.s390x.blocks = 0; + ctx->key_set = 1; + return 1; +} + +static int s390x_aes_ccm_setiv(PROV_CCM_CTX *ctx, + const unsigned char *nonce, size_t noncelen, + size_t mlen) +{ + PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; + + sctx->ccm.s390x.nonce.b[0] &= ~S390X_CCM_AAD_FLAG; + sctx->ccm.s390x.nonce.g[1] = mlen; + memcpy(sctx->ccm.s390x.nonce.b + 1, nonce, 15 - ctx->l); + return 1; +} + +/*- + * Process additional authenticated data. Code is big-endian. + */ +static int s390x_aes_ccm_setaad(PROV_CCM_CTX *ctx, + const unsigned char *aad, size_t alen) +{ + PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; + unsigned char *ptr; + int i, rem; + + if (!alen) + return 1; + + sctx->ccm.s390x.nonce.b[0] |= S390X_CCM_AAD_FLAG; + + /* Suppress 'type-punned pointer dereference' warning. */ + ptr = sctx->ccm.s390x.buf.b; + + if (alen < ((1 << 16) - (1 << 8))) { + *(uint16_t *)ptr = alen; + i = 2; + } else if (sizeof(alen) == 8 + && alen >= (size_t)1 << (32 % (sizeof(alen) * 8))) { + *(uint16_t *)ptr = 0xffff; + *(uint64_t *)(ptr + 2) = alen; + i = 10; + } else { + *(uint16_t *)ptr = 0xfffe; + *(uint32_t *)(ptr + 2) = alen; + i = 6; + } + + while (i < 16 && alen) { + sctx->ccm.s390x.buf.b[i] = *aad; + ++aad; + --alen; + ++i; + } + while (i < 16) { + sctx->ccm.s390x.buf.b[i] = 0; + ++i; + } + + sctx->ccm.s390x.kmac.icv.g[0] = 0; + sctx->ccm.s390x.kmac.icv.g[1] = 0; + s390x_kmac(sctx->ccm.s390x.nonce.b, 32, sctx->ccm.s390x.fc, + &sctx->ccm.s390x.kmac); + sctx->ccm.s390x.blocks += 2; + + rem = alen & 0xf; + alen &= ~(size_t)0xf; + if (alen) { + s390x_kmac(aad, alen, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); + sctx->ccm.s390x.blocks += alen >> 4; + aad += alen; + } + if (rem) { + for (i = 0; i < rem; i++) + sctx->ccm.s390x.kmac.icv.b[i] ^= aad[i]; + + s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, + sctx->ccm.s390x.kmac.icv.b, sctx->ccm.s390x.fc, + sctx->ccm.s390x.kmac.k); + sctx->ccm.s390x.blocks++; + } + return 1; +} + +/*- + * En/de-crypt plain/cipher-text. Compute tag from plaintext. Returns 1 for + * success. + */ +static int s390x_aes_ccm_auth_encdec(PROV_CCM_CTX *ctx, + const unsigned char *in, + unsigned char *out, size_t len, int enc) +{ + PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; + size_t n, rem; + unsigned int i, l, num; + unsigned char flags; + + flags = sctx->ccm.s390x.nonce.b[0]; + if (!(flags & S390X_CCM_AAD_FLAG)) { + s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.kmac.icv.b, + sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); + sctx->ccm.s390x.blocks++; + } + l = flags & 0x7; + sctx->ccm.s390x.nonce.b[0] = l; + + /*- + * Reconstruct length from encoded length field + * and initialize it with counter value. + */ + n = 0; + for (i = 15 - l; i < 15; i++) { + n |= sctx->ccm.s390x.nonce.b[i]; + sctx->ccm.s390x.nonce.b[i] = 0; + n <<= 8; + } + n |= sctx->ccm.s390x.nonce.b[15]; + sctx->ccm.s390x.nonce.b[15] = 1; + + if (n != len) + return 0; /* length mismatch */ + + if (enc) { + /* Two operations per block plus one for tag encryption */ + sctx->ccm.s390x.blocks += (((len + 15) >> 4) << 1) + 1; + if (sctx->ccm.s390x.blocks > (1ULL << 61)) + return 0; /* too much data */ + } + + num = 0; + rem = len & 0xf; + len &= ~(size_t)0xf; + + if (enc) { + /* mac-then-encrypt */ + if (len) + s390x_kmac(in, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); + if (rem) { + for (i = 0; i < rem; i++) + sctx->ccm.s390x.kmac.icv.b[i] ^= in[len + i]; + + s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, + sctx->ccm.s390x.kmac.icv.b, + sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); + } + + CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks, + sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b, + &num, (ctr128_f)AES_ctr32_encrypt); + } else { + /* decrypt-then-mac */ + CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks, + sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b, + &num, (ctr128_f)AES_ctr32_encrypt); + + if (len) + s390x_kmac(out, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); + if (rem) { + for (i = 0; i < rem; i++) + sctx->ccm.s390x.kmac.icv.b[i] ^= out[len + i]; + + s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, + sctx->ccm.s390x.kmac.icv.b, + sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); + } + } + /* encrypt tag */ + for (i = 15 - l; i < 16; i++) + sctx->ccm.s390x.nonce.b[i] = 0; + + s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.buf.b, + sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); + sctx->ccm.s390x.kmac.icv.g[0] ^= sctx->ccm.s390x.buf.g[0]; + sctx->ccm.s390x.kmac.icv.g[1] ^= sctx->ccm.s390x.buf.g[1]; + + sctx->ccm.s390x.nonce.b[0] = flags; /* restore flags field */ + return 1; +} + + +static int s390x_aes_ccm_gettag(PROV_CCM_CTX *ctx, + unsigned char *tag, size_t tlen) +{ + PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; + + if (tlen > ctx->m) + return 0; + memcpy(tag, sctx->ccm.s390x.kmac.icv.b, tlen); + return 1; +} + +static int s390x_aes_ccm_auth_encrypt(PROV_CCM_CTX *ctx, + const unsigned char *in, + unsigned char *out, size_t len, + unsigned char *tag, size_t taglen) +{ + int rv; + + rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 1); + if (rv && tag != NULL) + rv = s390x_aes_ccm_gettag(ctx, tag, taglen); + return rv; +} + +static int s390x_aes_ccm_auth_decrypt(PROV_CCM_CTX *ctx, + const unsigned char *in, + unsigned char *out, size_t len, + unsigned char *expected_tag, + size_t taglen) +{ + int rv = 0; + PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; + + rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 0); + if (rv) { + if (CRYPTO_memcmp(sctx->ccm.s390x.kmac.icv.b, expected_tag, ctx->m) != 0) + rv = 0; + } + if (rv == 0) + OPENSSL_cleanse(out, len); + return rv; +} + +static const PROV_CCM_HW s390x_aes_ccm = { + s390x_aes_ccm_initkey, + s390x_aes_ccm_setiv, + s390x_aes_ccm_setaad, + s390x_aes_ccm_auth_encrypt, + s390x_aes_ccm_auth_decrypt, + s390x_aes_ccm_gettag +}; + +const PROV_CCM_HW *ossl_prov_aes_hw_ccm(size_t keybits) +{ + if ((keybits == 128 && S390X_aes_128_ccm_CAPABLE) + || (keybits == 192 && S390X_aes_192_ccm_CAPABLE) + || (keybits == 256 && S390X_aes_256_ccm_CAPABLE)) + return &s390x_aes_ccm; + return &aes_ccm; +} diff --git a/providers/implementations/ciphers/cipher_aes_ccm_hw_t4.inc b/providers/implementations/ciphers/cipher_aes_ccm_hw_t4.inc new file mode 100644 index 000000000000..a676d411b598 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_ccm_hw_t4.inc @@ -0,0 +1,36 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * Fujitsu SPARC64 X support for AES CCM. + * This file is included by cipher_aes_ccm_hw.c + */ + +static int ccm_t4_aes_initkey(PROV_CCM_CTX *ctx, const unsigned char *key, + size_t keylen) +{ + PROV_AES_CCM_CTX *actx = (PROV_AES_CCM_CTX *)ctx; + + AES_HW_CCM_SET_KEY_FN(aes_t4_set_encrypt_key, aes_t4_encrypt, NULL, NULL); + return 1; +} + +static const PROV_CCM_HW t4_aes_ccm = { + ccm_t4_aes_initkey, + ossl_ccm_generic_setiv, + ossl_ccm_generic_setaad, + ossl_ccm_generic_auth_encrypt, + ossl_ccm_generic_auth_decrypt, + ossl_ccm_generic_gettag +}; + +const PROV_CCM_HW *ossl_prov_aes_hw_ccm(size_t keybits) +{ + return SPARC_AES_CAPABLE ? &t4_aes_ccm : &aes_ccm; +} diff --git a/providers/implementations/ciphers/cipher_aes_cts.inc b/providers/implementations/ciphers/cipher_aes_cts.inc new file mode 100644 index 000000000000..1fb5ec3553f9 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_cts.inc @@ -0,0 +1,94 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for AES CBC CTS ciphers */ + +#include <openssl/proverr.h> +#include "cipher_cts.h" + +#define CTS_FLAGS PROV_CIPHER_FLAG_CTS + +static OSSL_FUNC_cipher_encrypt_init_fn aes_cbc_cts_einit; +static OSSL_FUNC_cipher_decrypt_init_fn aes_cbc_cts_dinit; +static OSSL_FUNC_cipher_get_ctx_params_fn aes_cbc_cts_get_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn aes_cbc_cts_set_ctx_params; +static OSSL_FUNC_cipher_gettable_ctx_params_fn aes_cbc_cts_gettable_ctx_params; +static OSSL_FUNC_cipher_settable_ctx_params_fn aes_cbc_cts_settable_ctx_params; + +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(aes_cbc_cts) +OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, NULL, 0), +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(aes_cbc_cts) + +static int aes_cbc_cts_einit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_einit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return aes_cbc_cts_set_ctx_params(ctx, params); +} + +static int aes_cbc_cts_dinit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_dinit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return aes_cbc_cts_set_ctx_params(ctx, params); +} + +static int aes_cbc_cts_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_CTS_MODE); + if (p != NULL) { + const char *name = ossl_cipher_cbc_cts_mode_id2name(ctx->cts_mode); + + if (name == NULL || !OSSL_PARAM_set_utf8_string(p, name)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + return ossl_cipher_generic_get_ctx_params(vctx, params); +} + +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(aes_cbc_cts) +OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, NULL, 0), +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(aes_cbc_cts) + +static int aes_cbc_cts_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + const OSSL_PARAM *p; + int id; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_CTS_MODE); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + goto err; + id = ossl_cipher_cbc_cts_mode_name2id(p->data); + if (id < 0) + goto err; + + ctx->cts_mode = (unsigned int)id; + } + return ossl_cipher_generic_set_ctx_params(vctx, params); +err: + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; +} + +/* ossl_aes256cbc_cts_functions */ +IMPLEMENT_cts_cipher(aes, AES, cbc, CBC, CTS_FLAGS, 256, 128, 128, block) +/* ossl_aes192cbc_cts_functions */ +IMPLEMENT_cts_cipher(aes, AES, cbc, CBC, CTS_FLAGS, 192, 128, 128, block) +/* ossl_aes128cbc_cts_functions */ +IMPLEMENT_cts_cipher(aes, AES, cbc, CBC, CTS_FLAGS, 128, 128, 128, block) diff --git a/providers/implementations/ciphers/cipher_aes_gcm.c b/providers/implementations/ciphers/cipher_aes_gcm.c new file mode 100644 index 000000000000..0081ca6cd776 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm.c @@ -0,0 +1,50 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * AES low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +/* Dispatch functions for AES GCM mode */ + +#include "cipher_aes_gcm.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +static void *aes_gcm_newctx(void *provctx, size_t keybits) +{ + PROV_AES_GCM_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + ossl_gcm_initctx(provctx, &ctx->base, keybits, + ossl_prov_aes_hw_gcm(keybits)); + return ctx; +} + +static OSSL_FUNC_cipher_freectx_fn aes_gcm_freectx; +static void aes_gcm_freectx(void *vctx) +{ + PROV_AES_GCM_CTX *ctx = (PROV_AES_GCM_CTX *)vctx; + + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +/* ossl_aes128gcm_functions */ +IMPLEMENT_aead_cipher(aes, gcm, GCM, AEAD_FLAGS, 128, 8, 96); +/* ossl_aes192gcm_functions */ +IMPLEMENT_aead_cipher(aes, gcm, GCM, AEAD_FLAGS, 192, 8, 96); +/* ossl_aes256gcm_functions */ +IMPLEMENT_aead_cipher(aes, gcm, GCM, AEAD_FLAGS, 256, 8, 96); diff --git a/providers/implementations/ciphers/cipher_aes_gcm.h b/providers/implementations/ciphers/cipher_aes_gcm.h new file mode 100644 index 000000000000..5e88ccca7b4d --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm.h @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/aes.h> +#include "prov/ciphercommon.h" +#include "prov/ciphercommon_gcm.h" +#include "crypto/aes_platform.h" + +typedef struct prov_aes_gcm_ctx_st { + PROV_GCM_CTX base; /* must be first entry in struct */ + union { + OSSL_UNION_ALIGN; + AES_KEY ks; + } ks; /* AES key schedule to use */ + + /* Platform specific data */ + union { + int dummy; +#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__) + struct { + union { + OSSL_UNION_ALIGN; + S390X_KMA_PARAMS kma; + } param; + unsigned int fc; + unsigned int hsflag; /* hash subkey set flag */ + unsigned char ares[16]; + unsigned char mres[16]; + unsigned char kres[16]; + int areslen; + int mreslen; + int kreslen; + int res; + } s390x; +#endif /* defined(OPENSSL_CPUID_OBJ) && defined(__s390__) */ + } plat; +} PROV_AES_GCM_CTX; + +const PROV_GCM_HW *ossl_prov_aes_hw_gcm(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw.c b/providers/implementations/ciphers/cipher_aes_gcm_hw.c new file mode 100644 index 000000000000..44fa9d4d72ea --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm_hw.c @@ -0,0 +1,150 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for AES GCM mode */ + +/* + * This file uses the low level AES functions (which are deprecated for + * non-internal use) in order to implement provider AES ciphers. + */ +#include "internal/deprecated.h" + +#include "cipher_aes_gcm.h" + +static int aes_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key, + size_t keylen) +{ + PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; + AES_KEY *ks = &actx->ks.ks; + +# ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) { +# ifdef HWAES_ctr32_encrypt_blocks + GCM_HW_SET_KEY_CTR_FN(ks, HWAES_set_encrypt_key, HWAES_encrypt, + HWAES_ctr32_encrypt_blocks); +# else + GCM_HW_SET_KEY_CTR_FN(ks, HWAES_set_encrypt_key, HWAES_encrypt, NULL); +# endif /* HWAES_ctr32_encrypt_blocks */ + } else +# endif /* HWAES_CAPABLE */ + +# ifdef BSAES_CAPABLE + if (BSAES_CAPABLE) { + GCM_HW_SET_KEY_CTR_FN(ks, AES_set_encrypt_key, AES_encrypt, + ossl_bsaes_ctr32_encrypt_blocks); + } else +# endif /* BSAES_CAPABLE */ + +# ifdef VPAES_CAPABLE + if (VPAES_CAPABLE) { + GCM_HW_SET_KEY_CTR_FN(ks, vpaes_set_encrypt_key, vpaes_encrypt, NULL); + } else +# endif /* VPAES_CAPABLE */ + + { +# ifdef AES_CTR_ASM + GCM_HW_SET_KEY_CTR_FN(ks, AES_set_encrypt_key, AES_encrypt, + AES_ctr32_encrypt); +# else + GCM_HW_SET_KEY_CTR_FN(ks, AES_set_encrypt_key, AES_encrypt, NULL); +# endif /* AES_CTR_ASM */ + } + ctx->key_set = 1; + return 1; +} + +static int generic_aes_gcm_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in, + size_t len, unsigned char *out) +{ + if (ctx->enc) { + if (ctx->ctr != NULL) { +#if defined(AES_GCM_ASM) + size_t bulk = 0; + + if (len >= AES_GCM_ENC_BYTES && AES_GCM_ASM(ctx)) { + size_t res = (16 - ctx->gcm.mres) % 16; + + if (CRYPTO_gcm128_encrypt(&ctx->gcm, in, out, res)) + return 0; + + bulk = AES_gcm_encrypt(in + res, out + res, len - res, + ctx->gcm.key, + ctx->gcm.Yi.c, ctx->gcm.Xi.u); + + ctx->gcm.len.u[1] += bulk; + bulk += res; + } + if (CRYPTO_gcm128_encrypt_ctr32(&ctx->gcm, in + bulk, out + bulk, + len - bulk, ctx->ctr)) + return 0; +#else + if (CRYPTO_gcm128_encrypt_ctr32(&ctx->gcm, in, out, len, ctx->ctr)) + return 0; +#endif /* AES_GCM_ASM */ + } else { + if (CRYPTO_gcm128_encrypt(&ctx->gcm, in, out, len)) + return 0; + } + } else { + if (ctx->ctr != NULL) { +#if defined(AES_GCM_ASM) + size_t bulk = 0; + + if (len >= AES_GCM_DEC_BYTES && AES_GCM_ASM(ctx)) { + size_t res = (16 - ctx->gcm.mres) % 16; + + if (CRYPTO_gcm128_decrypt(&ctx->gcm, in, out, res)) + return -1; + + bulk = AES_gcm_decrypt(in + res, out + res, len - res, + ctx->gcm.key, + ctx->gcm.Yi.c, ctx->gcm.Xi.u); + + ctx->gcm.len.u[1] += bulk; + bulk += res; + } + if (CRYPTO_gcm128_decrypt_ctr32(&ctx->gcm, in + bulk, out + bulk, + len - bulk, ctx->ctr)) + return 0; +#else + if (CRYPTO_gcm128_decrypt_ctr32(&ctx->gcm, in, out, len, ctx->ctr)) + return 0; +#endif /* AES_GCM_ASM */ + } else { + if (CRYPTO_gcm128_decrypt(&ctx->gcm, in, out, len)) + return 0; + } + } + return 1; +} + +static const PROV_GCM_HW aes_gcm = { + aes_gcm_initkey, + ossl_gcm_setiv, + ossl_gcm_aad_update, + generic_aes_gcm_cipher_update, + ossl_gcm_cipher_final, + ossl_gcm_one_shot +}; + +#if defined(S390X_aes_128_CAPABLE) +# include "cipher_aes_gcm_hw_s390x.inc" +#elif defined(AESNI_CAPABLE) +# include "cipher_aes_gcm_hw_aesni.inc" +#elif defined(SPARC_AES_CAPABLE) +# include "cipher_aes_gcm_hw_t4.inc" +#elif defined(AES_PMULL_CAPABLE) && defined(AES_GCM_ASM) +# include "cipher_aes_gcm_hw_armv8.inc" +#else +const PROV_GCM_HW *ossl_prov_aes_hw_gcm(size_t keybits) +{ + return &aes_gcm; +} +#endif + diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw_aesni.inc b/providers/implementations/ciphers/cipher_aes_gcm_hw_aesni.inc new file mode 100644 index 000000000000..e6aa0479dd87 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm_hw_aesni.inc @@ -0,0 +1,38 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * AES-NI support for AES GCM. + * This file is included by cipher_aes_gcm_hw.c + */ + +static int aesni_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key, + size_t keylen) +{ + PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; + AES_KEY *ks = &actx->ks.ks; + GCM_HW_SET_KEY_CTR_FN(ks, aesni_set_encrypt_key, aesni_encrypt, + aesni_ctr32_encrypt_blocks); + return 1; +} + +static const PROV_GCM_HW aesni_gcm = { + aesni_gcm_initkey, + ossl_gcm_setiv, + ossl_gcm_aad_update, + generic_aes_gcm_cipher_update, + ossl_gcm_cipher_final, + ossl_gcm_one_shot +}; + +const PROV_GCM_HW *ossl_prov_aes_hw_gcm(size_t keybits) +{ + return AESNI_CAPABLE ? &aesni_gcm : &aes_gcm; +} + diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw_armv8.inc b/providers/implementations/ciphers/cipher_aes_gcm_hw_armv8.inc new file mode 100644 index 000000000000..310f4470d6d4 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm_hw_armv8.inc @@ -0,0 +1,83 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Crypto extention support for AES GCM. + * This file is included by cipher_aes_gcm_hw.c + */ + +size_t armv8_aes_gcm_encrypt(const unsigned char *in, unsigned char *out, size_t len, + const void *key, unsigned char ivec[16], u64 *Xi) +{ + size_t align_bytes = 0; + align_bytes = len - len % 16; + + AES_KEY *aes_key = (AES_KEY *)key; + + switch(aes_key->rounds) { + case 10: + aes_gcm_enc_128_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key); + break; + case 12: + aes_gcm_enc_192_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key); + break; + case 14: + aes_gcm_enc_256_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key); + break; + } + return align_bytes; +} + +size_t armv8_aes_gcm_decrypt(const unsigned char *in, unsigned char *out, size_t len, + const void *key, unsigned char ivec[16], u64 *Xi) +{ + size_t align_bytes = 0; + align_bytes = len - len % 16; + + AES_KEY *aes_key = (AES_KEY *)key; + + switch(aes_key->rounds) { + case 10: + aes_gcm_dec_128_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key); + break; + case 12: + aes_gcm_dec_192_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key); + break; + case 14: + aes_gcm_dec_256_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key); + break; + } + return align_bytes; +} + +static int armv8_aes_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key, + size_t keylen) +{ + PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; + AES_KEY *ks = &actx->ks.ks; + + GCM_HW_SET_KEY_CTR_FN(ks, aes_v8_set_encrypt_key, aes_v8_encrypt, + aes_v8_ctr32_encrypt_blocks); + return 1; +} + + +static const PROV_GCM_HW armv8_aes_gcm = { + armv8_aes_gcm_initkey, + ossl_gcm_setiv, + ossl_gcm_aad_update, + generic_aes_gcm_cipher_update, + ossl_gcm_cipher_final, + ossl_gcm_one_shot +}; + +const PROV_GCM_HW *ossl_prov_aes_hw_gcm(size_t keybits) +{ + return AES_PMULL_CAPABLE ? &armv8_aes_gcm : &aes_gcm; +} diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc b/providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc new file mode 100644 index 000000000000..a36c48e3ec49 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc @@ -0,0 +1,312 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * IBM S390X support for AES GCM. + * This file is included by cipher_aes_gcm_hw.c + */ + +/* iv + padding length for iv lengths != 12 */ +#define S390X_gcm_ivpadlen(i) ((((i) + 15) >> 4 << 4) + 16) + +/* Additional flag or'ed to fc for decryption */ +#define S390X_gcm_decrypt_flag(ctx) (((ctx)->enc) ? 0 : S390X_DECRYPT) + +#define S390X_gcm_fc(A,C) ((A)->plat.s390x.fc | (A)->plat.s390x.hsflag |\ + S390X_gcm_decrypt_flag((C))) + +static int s390x_aes_gcm_initkey(PROV_GCM_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; + + ctx->key_set = 1; + memcpy(&actx->plat.s390x.param.kma.k, key, keylen); + actx->plat.s390x.fc = S390X_AES_FC(keylen); + return 1; +} + +static int s390x_aes_gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv, + size_t ivlen) +{ + PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; + S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma; + + kma->t.g[0] = 0; + kma->t.g[1] = 0; + kma->tpcl = 0; + kma->taadl = 0; + actx->plat.s390x.mreslen = 0; + actx->plat.s390x.areslen = 0; + actx->plat.s390x.kreslen = 0; + + if (ivlen == GCM_IV_DEFAULT_SIZE) { + memcpy(&kma->j0, iv, ivlen); + kma->j0.w[3] = 1; + kma->cv.w = 1; + actx->plat.s390x.hsflag = 0; + } else { + unsigned long long ivbits = ivlen << 3; + size_t len = S390X_gcm_ivpadlen(ivlen); + unsigned char iv_zero_pad[S390X_gcm_ivpadlen(GCM_IV_MAX_SIZE)]; + /* + * The IV length needs to be zero padded to be a multiple of 16 bytes + * followed by 8 bytes of zeros and 8 bytes for the IV length. + * The GHASH of this value can then be calculated. + */ + memcpy(iv_zero_pad, iv, ivlen); + memset(iv_zero_pad + ivlen, 0, len - ivlen); + memcpy(iv_zero_pad + len - sizeof(ivbits), &ivbits, sizeof(ivbits)); + /* + * Calculate the ghash of the iv - the result is stored into the tag + * param. + */ + s390x_kma(iv_zero_pad, len, NULL, 0, NULL, actx->plat.s390x.fc, kma); + actx->plat.s390x.hsflag = S390X_KMA_HS; /* The hash subkey is set */ + + /* Copy the 128 bit GHASH result into J0 and clear the tag */ + kma->j0.g[0] = kma->t.g[0]; + kma->j0.g[1] = kma->t.g[1]; + kma->t.g[0] = 0; + kma->t.g[1] = 0; + /* Set the 32 bit counter */ + kma->cv.w = kma->j0.w[3]; + } + return 1; +} + +static int s390x_aes_gcm_cipher_final(PROV_GCM_CTX *ctx, unsigned char *tag) +{ + PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; + S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma; + unsigned char out[AES_BLOCK_SIZE]; + unsigned int fc; + int rc; + + kma->taadl <<= 3; + kma->tpcl <<= 3; + fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD | S390X_KMA_LPC; + s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen, + actx->plat.s390x.mres, actx->plat.s390x.mreslen, out, + fc, kma); + + /* gctx->mres already returned to the caller */ + OPENSSL_cleanse(out, actx->plat.s390x.mreslen); + + if (ctx->enc) { + ctx->taglen = GCM_TAG_MAX_SIZE; + memcpy(tag, kma->t.b, ctx->taglen); + rc = 1; + } else { + rc = (CRYPTO_memcmp(tag, kma->t.b, ctx->taglen) == 0); + } + return rc; +} + +static int s390x_aes_gcm_one_shot(PROV_GCM_CTX *ctx, + unsigned char *aad, size_t aad_len, + const unsigned char *in, size_t in_len, + unsigned char *out, + unsigned char *tag, size_t taglen) +{ + PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; + S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma; + unsigned int fc; + int rc; + + kma->taadl = aad_len << 3; + kma->tpcl = in_len << 3; + fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD | S390X_KMA_LPC; + s390x_kma(aad, aad_len, in, in_len, out, fc, kma); + + if (ctx->enc) { + memcpy(tag, kma->t.b, taglen); + rc = 1; + } else { + rc = (CRYPTO_memcmp(tag, kma->t.b, taglen) == 0); + } + return rc; +} + +/* + * Process additional authenticated data. Returns 1 on success. Code is + * big-endian. + */ +static int s390x_aes_gcm_aad_update(PROV_GCM_CTX *ctx, + const unsigned char *aad, size_t len) +{ + PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; + S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma; + unsigned long long alen; + unsigned int fc; + int n, rem; + + /* If already processed pt/ct then error */ + if (kma->tpcl != 0) + return 0; + + /* update the total aad length */ + alen = kma->taadl + len; + if (alen > (U64(1) << 61) || (sizeof(len) == 8 && alen < len)) + return 0; + kma->taadl = alen; + + /* check if there is any existing aad data from a previous add */ + n = actx->plat.s390x.areslen; + if (n) { + /* add additional data to a buffer until it has 16 bytes */ + while (n && len) { + actx->plat.s390x.ares[n] = *aad; + ++aad; + --len; + n = (n + 1) & 0xf; + } + /* ctx->ares contains a complete block if offset has wrapped around */ + if (!n) { + fc = S390X_gcm_fc(actx, ctx); + s390x_kma(actx->plat.s390x.ares, 16, NULL, 0, NULL, fc, kma); + actx->plat.s390x.hsflag = S390X_KMA_HS; + } + actx->plat.s390x.areslen = n; + } + + /* If there are leftover bytes (< 128 bits) save them for next time */ + rem = len & 0xf; + /* Add any remaining 16 byte blocks (128 bit each) */ + len &= ~(size_t)0xf; + if (len) { + fc = S390X_gcm_fc(actx, ctx); + s390x_kma(aad, len, NULL, 0, NULL, fc, kma); + actx->plat.s390x.hsflag = S390X_KMA_HS; + aad += len; + } + + if (rem) { + actx->plat.s390x.areslen = rem; + + do { + --rem; + actx->plat.s390x.ares[rem] = aad[rem]; + } while (rem); + } + return 1; +} + +/*- + * En/de-crypt plain/cipher-text and authenticate ciphertext. Returns 1 for + * success. Code is big-endian. + */ +static int s390x_aes_gcm_cipher_update(PROV_GCM_CTX *ctx, + const unsigned char *in, size_t len, + unsigned char *out) +{ + PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; + S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma; + const unsigned char *inptr; + unsigned long long mlen; + unsigned int fc; + union { + unsigned int w[4]; + unsigned char b[16]; + } buf; + size_t inlen; + int n, rem, i; + + mlen = kma->tpcl + len; + if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len)) + return 0; + kma->tpcl = mlen; + + fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD; + n = actx->plat.s390x.mreslen; + if (n) { + inptr = in; + inlen = len; + while (n && inlen) { + actx->plat.s390x.mres[n] = *inptr; + n = (n + 1) & 0xf; + ++inptr; + --inlen; + } + /* ctx->mres contains a complete block if offset has wrapped around */ + if (!n) { + s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen, + actx->plat.s390x.mres, 16, buf.b, fc, kma); + actx->plat.s390x.hsflag = S390X_KMA_HS; + fc |= S390X_KMA_HS; + actx->plat.s390x.areslen = 0; + + /* previous call already encrypted/decrypted its remainder, + * see comment below */ + n = actx->plat.s390x.mreslen; + while (n) { + *out = buf.b[n]; + n = (n + 1) & 0xf; + ++out; + ++in; + --len; + } + actx->plat.s390x.mreslen = 0; + } + } + + rem = len & 0xf; + + len &= ~(size_t)0xf; + if (len) { + s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen, in, len, out, + fc, kma); + in += len; + out += len; + actx->plat.s390x.hsflag = S390X_KMA_HS; + actx->plat.s390x.areslen = 0; + } + + /*- + * If there is a remainder, it has to be saved such that it can be + * processed by kma later. However, we also have to do the for-now + * unauthenticated encryption/decryption part here and now... + */ + if (rem) { + if (!actx->plat.s390x.mreslen) { + buf.w[0] = kma->j0.w[0]; + buf.w[1] = kma->j0.w[1]; + buf.w[2] = kma->j0.w[2]; + buf.w[3] = kma->cv.w + 1; + s390x_km(buf.b, 16, actx->plat.s390x.kres, + fc & 0x1f, &kma->k); + } + + n = actx->plat.s390x.mreslen; + for (i = 0; i < rem; i++) { + actx->plat.s390x.mres[n + i] = in[i]; + out[i] = in[i] ^ actx->plat.s390x.kres[n + i]; + } + actx->plat.s390x.mreslen += rem; + } + return 1; +} + +static const PROV_GCM_HW s390x_aes_gcm = { + s390x_aes_gcm_initkey, + s390x_aes_gcm_setiv, + s390x_aes_gcm_aad_update, + s390x_aes_gcm_cipher_update, + s390x_aes_gcm_cipher_final, + s390x_aes_gcm_one_shot +}; + +const PROV_GCM_HW *ossl_prov_aes_hw_gcm(size_t keybits) +{ + if ((keybits == 128 && S390X_aes_128_gcm_CAPABLE) + || (keybits == 192 && S390X_aes_192_gcm_CAPABLE) + || (keybits == 256 && S390X_aes_256_gcm_CAPABLE)) + return &s390x_aes_gcm; + return &aes_gcm; +} diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw_t4.inc b/providers/implementations/ciphers/cipher_aes_gcm_hw_t4.inc new file mode 100644 index 000000000000..2b3a6d1d5ea2 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm_hw_t4.inc @@ -0,0 +1,52 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * Fujitsu SPARC64 X support for AES GCM. + * This file is included by cipher_aes_gcm_hw.c + */ + +static int t4_aes_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key, + size_t keylen) +{ + ctr128_f ctr; + PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; + AES_KEY *ks = &actx->ks.ks; + + + switch (keylen) { + case 16: + ctr = (ctr128_f)aes128_t4_ctr32_encrypt; + break; + case 24: + ctr = (ctr128_f)aes192_t4_ctr32_encrypt; + break; + case 32: + ctr = (ctr128_f)aes256_t4_ctr32_encrypt; + break; + default: + return 0; + } + + GCM_HW_SET_KEY_CTR_FN(ks, aes_t4_set_encrypt_key, aes_t4_encrypt, ctr); + return 1; +} + +static const PROV_GCM_HW t4_aes_gcm = { + t4_aes_gcm_initkey, + ossl_gcm_setiv, + ossl_gcm_aad_update, + generic_aes_gcm_cipher_update, + ossl_gcm_cipher_final, + ossl_gcm_one_shot +}; +const PROV_GCM_HW *ossl_prov_aes_hw_gcm(size_t keybits) +{ + return SPARC_AES_CAPABLE ? &t4_aes_gcm : &aes_gcm; +} diff --git a/providers/implementations/ciphers/cipher_aes_hw.c b/providers/implementations/ciphers/cipher_aes_hw.c new file mode 100644 index 000000000000..596cdba8d307 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_hw.c @@ -0,0 +1,157 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This file uses the low level AES functions (which are deprecated for + * non-internal use) in order to implement provider AES ciphers. + */ +#include "internal/deprecated.h" + +#include <openssl/proverr.h> +#include "cipher_aes.h" + +static int cipher_hw_aes_initkey(PROV_CIPHER_CTX *dat, + const unsigned char *key, size_t keylen) +{ + int ret; + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + AES_KEY *ks = &adat->ks.ks; + + dat->ks = ks; + + if ((dat->mode == EVP_CIPH_ECB_MODE || dat->mode == EVP_CIPH_CBC_MODE) + && !dat->enc) { +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) { + ret = HWAES_set_decrypt_key(key, keylen * 8, ks); + dat->block = (block128_f)HWAES_decrypt; + dat->stream.cbc = NULL; +# ifdef HWAES_cbc_encrypt + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)HWAES_cbc_encrypt; +# endif +# ifdef HWAES_ecb_encrypt + if (dat->mode == EVP_CIPH_ECB_MODE) + dat->stream.ecb = (ecb128_f)HWAES_ecb_encrypt; +# endif + } else +#endif +#ifdef BSAES_CAPABLE + if (BSAES_CAPABLE && dat->mode == EVP_CIPH_CBC_MODE) { + ret = AES_set_decrypt_key(key, keylen * 8, ks); + dat->block = (block128_f)AES_decrypt; + dat->stream.cbc = (cbc128_f)ossl_bsaes_cbc_encrypt; + } else +#endif +#ifdef VPAES_CAPABLE + if (VPAES_CAPABLE) { + ret = vpaes_set_decrypt_key(key, keylen * 8, ks); + dat->block = (block128_f)vpaes_decrypt; + dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE) + ?(cbc128_f)vpaes_cbc_encrypt : NULL; + } else +#endif + { + ret = AES_set_decrypt_key(key, keylen * 8, ks); + dat->block = (block128_f)AES_decrypt; + dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE) + ? (cbc128_f)AES_cbc_encrypt : NULL; + } + } else +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) { + ret = HWAES_set_encrypt_key(key, keylen * 8, ks); + dat->block = (block128_f)HWAES_encrypt; + dat->stream.cbc = NULL; +# ifdef HWAES_cbc_encrypt + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)HWAES_cbc_encrypt; + else +# endif +# ifdef HWAES_ecb_encrypt + if (dat->mode == EVP_CIPH_ECB_MODE) + dat->stream.ecb = (ecb128_f)HWAES_ecb_encrypt; + else +# endif +# ifdef HWAES_ctr32_encrypt_blocks + if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)HWAES_ctr32_encrypt_blocks; + else +# endif + (void)0; /* terminate potentially open 'else' */ + } else +#endif +#ifdef BSAES_CAPABLE + if (BSAES_CAPABLE && dat->mode == EVP_CIPH_CTR_MODE) { + ret = AES_set_encrypt_key(key, keylen * 8, ks); + dat->block = (block128_f)AES_encrypt; + dat->stream.ctr = (ctr128_f)ossl_bsaes_ctr32_encrypt_blocks; + } else +#endif +#ifdef VPAES_CAPABLE + if (VPAES_CAPABLE) { + ret = vpaes_set_encrypt_key(key, keylen * 8, ks); + dat->block = (block128_f)vpaes_encrypt; + dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE) + ? (cbc128_f)vpaes_cbc_encrypt : NULL; + } else +#endif + { + ret = AES_set_encrypt_key(key, keylen * 8, ks); + dat->block = (block128_f)AES_encrypt; + dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE) + ? (cbc128_f)AES_cbc_encrypt : NULL; +#ifdef AES_CTR_ASM + if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)AES_ctr32_encrypt; +#endif + } + + if (ret < 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SETUP_FAILED); + return 0; + } + + return 1; +} + +IMPLEMENT_CIPHER_HW_COPYCTX(cipher_hw_aes_copyctx, PROV_AES_CTX) + +#define PROV_CIPHER_HW_aes_mode(mode) \ +static const PROV_CIPHER_HW aes_##mode = { \ + cipher_hw_aes_initkey, \ + ossl_cipher_hw_generic_##mode, \ + cipher_hw_aes_copyctx \ +}; \ +PROV_CIPHER_HW_declare(mode) \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_##mode(size_t keybits) \ +{ \ + PROV_CIPHER_HW_select(mode) \ + return &aes_##mode; \ +} + +#if defined(AESNI_CAPABLE) +# include "cipher_aes_hw_aesni.inc" +#elif defined(SPARC_AES_CAPABLE) +# include "cipher_aes_hw_t4.inc" +#elif defined(S390X_aes_128_CAPABLE) +# include "cipher_aes_hw_s390x.inc" +#else +/* The generic case */ +# define PROV_CIPHER_HW_declare(mode) +# define PROV_CIPHER_HW_select(mode) +#endif + +PROV_CIPHER_HW_aes_mode(cbc) +PROV_CIPHER_HW_aes_mode(ecb) +PROV_CIPHER_HW_aes_mode(ofb128) +PROV_CIPHER_HW_aes_mode(cfb128) +PROV_CIPHER_HW_aes_mode(cfb1) +PROV_CIPHER_HW_aes_mode(cfb8) +PROV_CIPHER_HW_aes_mode(ctr) diff --git a/providers/implementations/ciphers/cipher_aes_hw_aesni.inc b/providers/implementations/ciphers/cipher_aes_hw_aesni.inc new file mode 100644 index 000000000000..33b9046054e9 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_hw_aesni.inc @@ -0,0 +1,84 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * AES-NI support for AES modes ecb, cbc, ofb, cfb, ctr. + * This file is included by cipher_aes_hw.c + */ + +#define cipher_hw_aesni_ofb128 ossl_cipher_hw_generic_ofb128 +#define cipher_hw_aesni_cfb128 ossl_cipher_hw_generic_cfb128 +#define cipher_hw_aesni_cfb8 ossl_cipher_hw_generic_cfb8 +#define cipher_hw_aesni_cfb1 ossl_cipher_hw_generic_cfb1 +#define cipher_hw_aesni_ctr ossl_cipher_hw_generic_ctr + +static int cipher_hw_aesni_initkey(PROV_CIPHER_CTX *dat, + const unsigned char *key, size_t keylen) +{ + int ret; + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + AES_KEY *ks = &adat->ks.ks; + + dat->ks = ks; + + if ((dat->mode == EVP_CIPH_ECB_MODE || dat->mode == EVP_CIPH_CBC_MODE) + && !dat->enc) { + ret = aesni_set_decrypt_key(key, keylen * 8, ks); + dat->block = (block128_f) aesni_decrypt; + dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ? + (cbc128_f) aesni_cbc_encrypt : NULL; + } else { + ret = aesni_set_encrypt_key(key, keylen * 8, ks); + dat->block = (block128_f) aesni_encrypt; + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f) aesni_cbc_encrypt; + else if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f) aesni_ctr32_encrypt_blocks; + else + dat->stream.cbc = NULL; + } + + if (ret < 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SETUP_FAILED); + return 0; + } + + return 1; +} + +static int cipher_hw_aesni_cbc(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + const AES_KEY *ks = ctx->ks; + + aesni_cbc_encrypt(in, out, len, ks, ctx->iv, ctx->enc); + + return 1; +} + +static int cipher_hw_aesni_ecb(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + if (len < ctx->blocksize) + return 1; + + aesni_ecb_encrypt(in, out, len, ctx->ks, ctx->enc); + + return 1; +} + +#define PROV_CIPHER_HW_declare(mode) \ +static const PROV_CIPHER_HW aesni_##mode = { \ + cipher_hw_aesni_initkey, \ + cipher_hw_aesni_##mode, \ + cipher_hw_aes_copyctx \ +}; +#define PROV_CIPHER_HW_select(mode) \ +if (AESNI_CAPABLE) \ + return &aesni_##mode; diff --git a/providers/implementations/ciphers/cipher_aes_hw_s390x.inc b/providers/implementations/ciphers/cipher_aes_hw_s390x.inc new file mode 100644 index 000000000000..c8282dbd08a9 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_hw_s390x.inc @@ -0,0 +1,206 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * IBM S390X support for AES modes ecb, cbc, ofb, cfb, ctr. + * This file is included by cipher_aes_hw.c + */ + +#include "s390x_arch.h" + +#include <stdio.h> + +#define s390x_aes_cbc_initkey cipher_hw_aes_initkey +#define s390x_aes_cfb1_initkey cipher_hw_aes_initkey +#define s390x_aes_ctr_initkey cipher_hw_aes_initkey +#define s390x_aes_cbc_cipher_hw ossl_cipher_hw_generic_cbc +#define s390x_aes_cfb1_cipher_hw ossl_cipher_hw_generic_cfb1 +#define s390x_aes_ctr_cipher_hw ossl_cipher_hw_generic_ctr + +#define S390X_aes_128_ofb128_CAPABLE S390X_aes_128_ofb_CAPABLE +#define S390X_aes_192_ofb128_CAPABLE S390X_aes_192_ofb_CAPABLE +#define S390X_aes_256_ofb128_CAPABLE S390X_aes_256_ofb_CAPABLE +#define S390X_aes_128_cfb128_CAPABLE S390X_aes_128_cfb_CAPABLE +#define S390X_aes_192_cfb128_CAPABLE S390X_aes_192_cfb_CAPABLE +#define S390X_aes_256_cfb128_CAPABLE S390X_aes_256_cfb_CAPABLE + +static int s390x_aes_ecb_initkey(PROV_CIPHER_CTX *dat, + const unsigned char *key, size_t keylen) +{ + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + + adat->plat.s390x.fc = S390X_AES_FC(keylen); + memcpy(adat->plat.s390x.param.km.k, key, keylen); + return 1; +} + +static int s390x_aes_ecb_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT; + + s390x_km(in, len, out, adat->plat.s390x.fc | modifier, + &adat->plat.s390x.param.km); + return 1; +} + +static int s390x_aes_ofb128_initkey(PROV_CIPHER_CTX *dat, + const unsigned char *key, size_t keylen) +{ + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + + memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen); + adat->plat.s390x.fc = S390X_AES_FC(keylen); + adat->plat.s390x.res = 0; + return 1; +} + +static int s390x_aes_ofb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + int n = adat->plat.s390x.res; + int rem; + + memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen); + while (n && len) { + *out = *in ^ adat->plat.s390x.param.kmo_kmf.cv[n]; + n = (n + 1) & 0xf; + --len; + ++in; + ++out; + } + + rem = len & 0xf; + + len &= ~(size_t)0xf; + if (len) { + s390x_kmo(in, len, out, adat->plat.s390x.fc, + &adat->plat.s390x.param.kmo_kmf); + + out += len; + in += len; + } + + if (rem) { + s390x_km(adat->plat.s390x.param.kmo_kmf.cv, 16, + adat->plat.s390x.param.kmo_kmf.cv, + adat->plat.s390x.fc, + adat->plat.s390x.param.kmo_kmf.k); + + while (rem--) { + out[n] = in[n] ^ adat->plat.s390x.param.kmo_kmf.cv[n]; + ++n; + } + } + + memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen); + adat->plat.s390x.res = n; + return 1; +} + +static int s390x_aes_cfb128_initkey(PROV_CIPHER_CTX *dat, + const unsigned char *key, size_t keylen) +{ + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + + adat->plat.s390x.fc = S390X_AES_FC(keylen); + adat->plat.s390x.fc |= 16 << 24; /* 16 bytes cipher feedback */ + adat->plat.s390x.res = 0; + memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen); + return 1; +} + +static int s390x_aes_cfb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT; + int n = adat->plat.s390x.res; + int rem; + unsigned char tmp; + + memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen); + while (n && len) { + tmp = *in; + *out = adat->plat.s390x.param.kmo_kmf.cv[n] ^ tmp; + adat->plat.s390x.param.kmo_kmf.cv[n] = dat->enc ? *out : tmp; + n = (n + 1) & 0xf; + --len; + ++in; + ++out; + } + + rem = len & 0xf; + + len &= ~(size_t)0xf; + if (len) { + s390x_kmf(in, len, out, adat->plat.s390x.fc | modifier, + &adat->plat.s390x.param.kmo_kmf); + + out += len; + in += len; + } + + if (rem) { + s390x_km(adat->plat.s390x.param.kmo_kmf.cv, 16, + adat->plat.s390x.param.kmo_kmf.cv, + S390X_AES_FC(dat->keylen), + adat->plat.s390x.param.kmo_kmf.k); + + while (rem--) { + tmp = in[n]; + out[n] = adat->plat.s390x.param.kmo_kmf.cv[n] ^ tmp; + adat->plat.s390x.param.kmo_kmf.cv[n] = dat->enc ? out[n] : tmp; + ++n; + } + } + + memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen); + adat->plat.s390x.res = n; + return 1; +} + +static int s390x_aes_cfb8_initkey(PROV_CIPHER_CTX *dat, + const unsigned char *key, size_t keylen) +{ + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + + adat->plat.s390x.fc = S390X_AES_FC(keylen); + adat->plat.s390x.fc |= 1 << 24; /* 1 byte cipher feedback */ + memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen); + return 1; +} + +static int s390x_aes_cfb8_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT; + + memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen); + s390x_kmf(in, len, out, adat->plat.s390x.fc | modifier, + &adat->plat.s390x.param.kmo_kmf); + memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen); + return 1; +} + +#define PROV_CIPHER_HW_declare(mode) \ +static const PROV_CIPHER_HW s390x_aes_##mode = { \ + s390x_aes_##mode##_initkey, \ + s390x_aes_##mode##_cipher_hw, \ + cipher_hw_aes_copyctx \ +}; +#define PROV_CIPHER_HW_select(mode) \ +if ((keybits == 128 && S390X_aes_128_##mode##_CAPABLE) \ + || (keybits == 192 && S390X_aes_192_##mode##_CAPABLE) \ + || (keybits == 256 && S390X_aes_256_##mode##_CAPABLE)) \ + return &s390x_aes_##mode; + diff --git a/providers/implementations/ciphers/cipher_aes_hw_t4.inc b/providers/implementations/ciphers/cipher_aes_hw_t4.inc new file mode 100644 index 000000000000..28454fc5089b --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_hw_t4.inc @@ -0,0 +1,96 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * Sparc t4 support for AES modes ecb, cbc, ofb, cfb, ctr. + * This file is included by cipher_aes_hw.c + */ + +static int cipher_hw_aes_t4_initkey(PROV_CIPHER_CTX *dat, + const unsigned char *key, size_t keylen) +{ + int ret, bits; + PROV_AES_CTX *adat = (PROV_AES_CTX *)dat; + AES_KEY *ks = &adat->ks.ks; + + dat->ks = (const void *)ks; /* used by cipher_hw_generic_XXX */ + + bits = keylen * 8; + if ((dat->mode == EVP_CIPH_ECB_MODE || dat->mode == EVP_CIPH_CBC_MODE) + && !dat->enc) { + ret = 0; + aes_t4_set_decrypt_key(key, bits, ks); + dat->block = (block128_f)aes_t4_decrypt; + switch (bits) { + case 128: + dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ? + (cbc128_f)aes128_t4_cbc_decrypt : NULL; + break; + case 192: + dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ? + (cbc128_f)aes192_t4_cbc_decrypt : NULL; + break; + case 256: + dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ? + (cbc128_f)aes256_t4_cbc_decrypt : NULL; + break; + default: + ret = -1; + } + } else { + ret = 0; + aes_t4_set_encrypt_key(key, bits, ks); + dat->block = (block128_f)aes_t4_encrypt; + switch (bits) { + case 128: + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)aes128_t4_cbc_encrypt; + else if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)aes128_t4_ctr32_encrypt; + else + dat->stream.cbc = NULL; + break; + case 192: + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)aes192_t4_cbc_encrypt; + else if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)aes192_t4_ctr32_encrypt; + else + dat->stream.cbc = NULL; + break; + case 256: + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)aes256_t4_cbc_encrypt; + else if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)aes256_t4_ctr32_encrypt; + else + dat->stream.cbc = NULL; + break; + default: + ret = -1; + } + } + + if (ret < 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SETUP_FAILED); + return 0; + } + + return 1; +} + +#define PROV_CIPHER_HW_declare(mode) \ +static const PROV_CIPHER_HW aes_t4_##mode = { \ + cipher_hw_aes_t4_initkey, \ + ossl_cipher_hw_generic_##mode, \ + cipher_hw_aes_copyctx \ +}; +#define PROV_CIPHER_HW_select(mode) \ + if (SPARC_AES_CAPABLE) \ + return &aes_t4_##mode; diff --git a/providers/implementations/ciphers/cipher_aes_ocb.c b/providers/implementations/ciphers/cipher_aes_ocb.c new file mode 100644 index 000000000000..ce377ad57409 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_ocb.c @@ -0,0 +1,559 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * AES low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +#include <openssl/proverr.h> +#include "cipher_aes_ocb.h" +#include "prov/providercommon.h" +#include "prov/ciphercommon_aead.h" +#include "prov/implementations.h" + +#define AES_OCB_FLAGS AEAD_FLAGS + +#define OCB_DEFAULT_TAG_LEN 16 +#define OCB_DEFAULT_IV_LEN 12 +#define OCB_MIN_IV_LEN 1 +#define OCB_MAX_IV_LEN 15 + +PROV_CIPHER_FUNC(int, ocb_cipher, (PROV_AES_OCB_CTX *ctx, + const unsigned char *in, unsigned char *out, + size_t nextblock)); +/* forward declarations */ +static OSSL_FUNC_cipher_encrypt_init_fn aes_ocb_einit; +static OSSL_FUNC_cipher_decrypt_init_fn aes_ocb_dinit; +static OSSL_FUNC_cipher_update_fn aes_ocb_block_update; +static OSSL_FUNC_cipher_final_fn aes_ocb_block_final; +static OSSL_FUNC_cipher_cipher_fn aes_ocb_cipher; +static OSSL_FUNC_cipher_freectx_fn aes_ocb_freectx; +static OSSL_FUNC_cipher_dupctx_fn aes_ocb_dupctx; +static OSSL_FUNC_cipher_get_ctx_params_fn aes_ocb_get_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn aes_ocb_set_ctx_params; +static OSSL_FUNC_cipher_gettable_ctx_params_fn cipher_ocb_gettable_ctx_params; +static OSSL_FUNC_cipher_settable_ctx_params_fn cipher_ocb_settable_ctx_params; + +/* + * The following methods could be moved into PROV_AES_OCB_HW if + * multiple hardware implementations are ever needed. + */ +static ossl_inline int aes_generic_ocb_setiv(PROV_AES_OCB_CTX *ctx, + const unsigned char *iv, + size_t ivlen, size_t taglen) +{ + return (CRYPTO_ocb128_setiv(&ctx->ocb, iv, ivlen, taglen) == 1); +} + +static ossl_inline int aes_generic_ocb_setaad(PROV_AES_OCB_CTX *ctx, + const unsigned char *aad, + size_t alen) +{ + return CRYPTO_ocb128_aad(&ctx->ocb, aad, alen) == 1; +} + +static ossl_inline int aes_generic_ocb_gettag(PROV_AES_OCB_CTX *ctx, + unsigned char *tag, size_t tlen) +{ + return CRYPTO_ocb128_tag(&ctx->ocb, tag, tlen) > 0; +} + +static ossl_inline int aes_generic_ocb_final(PROV_AES_OCB_CTX *ctx) +{ + return (CRYPTO_ocb128_finish(&ctx->ocb, ctx->tag, ctx->taglen) == 0); +} + +static ossl_inline void aes_generic_ocb_cleanup(PROV_AES_OCB_CTX *ctx) +{ + CRYPTO_ocb128_cleanup(&ctx->ocb); +} + +static ossl_inline int aes_generic_ocb_cipher(PROV_AES_OCB_CTX *ctx, + const unsigned char *in, + unsigned char *out, size_t len) +{ + if (ctx->base.enc) { + if (!CRYPTO_ocb128_encrypt(&ctx->ocb, in, out, len)) + return 0; + } else { + if (!CRYPTO_ocb128_decrypt(&ctx->ocb, in, out, len)) + return 0; + } + return 1; +} + +static ossl_inline int aes_generic_ocb_copy_ctx(PROV_AES_OCB_CTX *dst, + PROV_AES_OCB_CTX *src) +{ + return CRYPTO_ocb128_copy_ctx(&dst->ocb, &src->ocb, + &dst->ksenc.ks, &dst->ksdec.ks); +} + +/*- + * Provider dispatch functions + */ +static int aes_ocb_init(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[], int enc) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + ctx->aad_buf_len = 0; + ctx->data_buf_len = 0; + ctx->base.enc = enc; + + if (iv != NULL) { + if (ivlen != ctx->base.ivlen) { + /* IV len must be 1 to 15 */ + if (ivlen < OCB_MIN_IV_LEN || ivlen > OCB_MAX_IV_LEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + ctx->base.ivlen = ivlen; + } + if (!ossl_cipher_generic_initiv(&ctx->base, iv, ivlen)) + return 0; + ctx->iv_state = IV_STATE_BUFFERED; + } + if (key != NULL) { + if (keylen != ctx->base.keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + if (!ctx->base.hw->init(&ctx->base, key, keylen)) + return 0; + } + return aes_ocb_set_ctx_params(ctx, params); +} + +static int aes_ocb_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return aes_ocb_init(vctx, key, keylen, iv, ivlen, params, 1); +} + +static int aes_ocb_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return aes_ocb_init(vctx, key, keylen, iv, ivlen, params, 0); +} + +/* + * Because of the way OCB works, both the AAD and data are buffered in the + * same way. Only the last block can be a partial block. + */ +static int aes_ocb_block_update_internal(PROV_AES_OCB_CTX *ctx, + unsigned char *buf, size_t *bufsz, + unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, + size_t inl, OSSL_ocb_cipher_fn ciph) +{ + size_t nextblocks; + size_t outlint = 0; + + if (*bufsz != 0) + nextblocks = ossl_cipher_fillblock(buf, bufsz, AES_BLOCK_SIZE, &in, &inl); + else + nextblocks = inl & ~(AES_BLOCK_SIZE-1); + + if (*bufsz == AES_BLOCK_SIZE) { + if (outsize < AES_BLOCK_SIZE) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (!ciph(ctx, buf, out, AES_BLOCK_SIZE)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + *bufsz = 0; + outlint = AES_BLOCK_SIZE; + if (out != NULL) + out += AES_BLOCK_SIZE; + } + if (nextblocks > 0) { + outlint += nextblocks; + if (outsize < outlint) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (!ciph(ctx, in, out, nextblocks)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + in += nextblocks; + inl -= nextblocks; + } + if (inl != 0 + && !ossl_cipher_trailingdata(buf, bufsz, AES_BLOCK_SIZE, &in, &inl)) { + /* PROVerr already called */ + return 0; + } + + *outl = outlint; + return inl == 0; +} + +/* A wrapper function that has the same signature as cipher */ +static int cipher_updateaad(PROV_AES_OCB_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len) +{ + return aes_generic_ocb_setaad(ctx, in, len); +} + +static int update_iv(PROV_AES_OCB_CTX *ctx) +{ + if (ctx->iv_state == IV_STATE_FINISHED + || ctx->iv_state == IV_STATE_UNINITIALISED) + return 0; + if (ctx->iv_state == IV_STATE_BUFFERED) { + if (!aes_generic_ocb_setiv(ctx, ctx->base.iv, ctx->base.ivlen, + ctx->taglen)) + return 0; + ctx->iv_state = IV_STATE_COPIED; + } + return 1; +} + +static int aes_ocb_block_update(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, + size_t inl) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + unsigned char *buf; + size_t *buflen; + OSSL_ocb_cipher_fn fn; + + if (!ctx->key_set || !update_iv(ctx)) + return 0; + + if (inl == 0) { + *outl = 0; + return 1; + } + + /* Are we dealing with AAD or normal data here? */ + if (out == NULL) { + buf = ctx->aad_buf; + buflen = &ctx->aad_buf_len; + fn = cipher_updateaad; + } else { + buf = ctx->data_buf; + buflen = &ctx->data_buf_len; + fn = aes_generic_ocb_cipher; + } + return aes_ocb_block_update_internal(ctx, buf, buflen, out, outl, outsize, + in, inl, fn); +} + +static int aes_ocb_block_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + /* If no block_update has run then the iv still needs to be set */ + if (!ctx->key_set || !update_iv(ctx)) + return 0; + + /* + * Empty the buffer of any partial block that we might have been provided, + * both for data and AAD + */ + *outl = 0; + if (ctx->data_buf_len > 0) { + if (!aes_generic_ocb_cipher(ctx, ctx->data_buf, out, ctx->data_buf_len)) + return 0; + *outl = ctx->data_buf_len; + ctx->data_buf_len = 0; + } + if (ctx->aad_buf_len > 0) { + if (!aes_generic_ocb_setaad(ctx, ctx->aad_buf, ctx->aad_buf_len)) + return 0; + ctx->aad_buf_len = 0; + } + if (ctx->base.enc) { + /* If encrypting then just get the tag */ + if (!aes_generic_ocb_gettag(ctx, ctx->tag, ctx->taglen)) + return 0; + } else { + /* If decrypting then verify */ + if (ctx->taglen == 0) + return 0; + if (!aes_generic_ocb_final(ctx)) + return 0; + } + /* Don't reuse the IV */ + ctx->iv_state = IV_STATE_FINISHED; + return 1; +} + +static void *aes_ocb_newctx(void *provctx, size_t kbits, size_t blkbits, + size_t ivbits, unsigned int mode, uint64_t flags) +{ + PROV_AES_OCB_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) { + ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits, mode, flags, + ossl_prov_cipher_hw_aes_ocb(kbits), NULL); + ctx->taglen = OCB_DEFAULT_TAG_LEN; + } + return ctx; +} + +static void aes_ocb_freectx(void *vctx) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + + if (ctx != NULL) { + aes_generic_ocb_cleanup(ctx); + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); + } +} + +static void *aes_ocb_dupctx(void *vctx) +{ + PROV_AES_OCB_CTX *in = (PROV_AES_OCB_CTX *)vctx; + PROV_AES_OCB_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + *ret = *in; + if (!aes_generic_ocb_copy_ctx(ret, in)) { + OPENSSL_free(ret); + ret = NULL; + } + return ret; +} + +static int aes_ocb_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + const OSSL_PARAM *p; + size_t sz; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (p->data == NULL) { + /* Tag len must be 0 to 16 */ + if (p->data_size > OCB_MAX_TAG_LEN) + return 0; + ctx->taglen = p->data_size; + } else { + if (p->data_size != ctx->taglen || ctx->base.enc) + return 0; + memcpy(ctx->tag, p->data, p->data_size); + } + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_IVLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + /* IV len must be 1 to 15 */ + if (sz < OCB_MIN_IV_LEN || sz > OCB_MAX_IV_LEN) + return 0; + ctx->base.ivlen = sz; + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + size_t keylen; + + if (!OSSL_PARAM_get_size_t(p, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ctx->base.keylen != keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + return 1; +} + +static int aes_ocb_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN); + if (p != NULL) { + if (!OSSL_PARAM_set_size_t(p, ctx->taglen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); + if (p != NULL) { + if (ctx->base.ivlen > p->data_size) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + if (!OSSL_PARAM_set_octet_string(p, ctx->base.oiv, ctx->base.ivlen) + && !OSSL_PARAM_set_octet_ptr(p, &ctx->base.oiv, ctx->base.ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV); + if (p != NULL) { + if (ctx->base.ivlen > p->data_size) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + if (!OSSL_PARAM_set_octet_string(p, ctx->base.iv, ctx->base.ivlen) + && !OSSL_PARAM_set_octet_ptr(p, &ctx->base.iv, ctx->base.ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (!ctx->base.enc || p->data_size != ctx->taglen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH); + return 0; + } + memcpy(p->data, ctx->tag, ctx->taglen); + } + return 1; +} + +static const OSSL_PARAM cipher_ocb_known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_UPDATED_IV, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *cipher_ocb_gettable_ctx_params(ossl_unused void *cctx, + ossl_unused void *p_ctx) +{ + return cipher_ocb_known_gettable_ctx_params; +} + +static const OSSL_PARAM cipher_ocb_known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *cipher_ocb_settable_ctx_params(ossl_unused void *cctx, + ossl_unused void *p_ctx) +{ + return cipher_ocb_known_settable_ctx_params; +} + +static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!aes_generic_ocb_cipher(ctx, in, out, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + *outl = inl; + return 1; +} + +#define IMPLEMENT_cipher(mode, UCMODE, flags, kbits, blkbits, ivbits) \ +static OSSL_FUNC_cipher_get_params_fn aes_##kbits##_##mode##_get_params; \ +static int aes_##kbits##_##mode##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, kbits, blkbits, ivbits); \ +} \ +static OSSL_FUNC_cipher_newctx_fn aes_##kbits##_##mode##_newctx; \ +static void *aes_##kbits##_##mode##_newctx(void *provctx) \ +{ \ + return aes_##mode##_newctx(provctx, kbits, blkbits, ivbits, \ + EVP_CIPH_##UCMODE##_MODE, flags); \ +} \ +const OSSL_DISPATCH ossl_##aes##kbits##mode##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (void (*)(void))aes_##kbits##_##mode##_newctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))aes_##mode##_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))aes_##mode##_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))aes_##mode##_block_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))aes_##mode##_block_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))aes_ocb_cipher }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))aes_##mode##_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))aes_##mode##_dupctx }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void))aes_##kbits##_##mode##_get_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))aes_##mode##_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))aes_##mode##_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))cipher_ocb_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))cipher_ocb_settable_ctx_params }, \ + { 0, NULL } \ +} + +IMPLEMENT_cipher(ocb, OCB, AES_OCB_FLAGS, 256, 128, OCB_DEFAULT_IV_LEN * 8); +IMPLEMENT_cipher(ocb, OCB, AES_OCB_FLAGS, 192, 128, OCB_DEFAULT_IV_LEN * 8); +IMPLEMENT_cipher(ocb, OCB, AES_OCB_FLAGS, 128, 128, OCB_DEFAULT_IV_LEN * 8); diff --git a/providers/implementations/ciphers/cipher_aes_ocb.h b/providers/implementations/ciphers/cipher_aes_ocb.h new file mode 100644 index 000000000000..370717b43614 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_ocb.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/aes.h> +#include "prov/ciphercommon.h" +#include "crypto/aes_platform.h" + +#define OCB_MAX_TAG_LEN AES_BLOCK_SIZE +#define OCB_MAX_DATA_LEN AES_BLOCK_SIZE +#define OCB_MAX_AAD_LEN AES_BLOCK_SIZE + +typedef struct prov_aes_ocb_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + AES_KEY ks; + } ksenc; /* AES key schedule to use for encryption/aad */ + union { + OSSL_UNION_ALIGN; + AES_KEY ks; + } ksdec; /* AES key schedule to use for decryption */ + OCB128_CONTEXT ocb; + unsigned int iv_state; /* set to one of IV_STATE_XXX */ + unsigned int key_set : 1; + size_t taglen; + size_t data_buf_len; + size_t aad_buf_len; + unsigned char tag[OCB_MAX_TAG_LEN]; + unsigned char data_buf[OCB_MAX_DATA_LEN]; /* Store partial data blocks */ + unsigned char aad_buf[OCB_MAX_AAD_LEN]; /* Store partial AAD blocks */ +} PROV_AES_OCB_CTX; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_ocb(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_aes_ocb_hw.c b/providers/implementations/ciphers/cipher_aes_ocb_hw.c new file mode 100644 index 000000000000..7aa97dc77e39 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_ocb_hw.c @@ -0,0 +1,122 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This file uses the low level AES functions (which are deprecated for + * non-internal use) in order to implement provider AES ciphers. + */ +#include "internal/deprecated.h" + +#include "cipher_aes_ocb.h" + +#define OCB_SET_KEY_FN(fn_set_enc_key, fn_set_dec_key, \ + fn_block_enc, fn_block_dec, \ + fn_stream_enc, fn_stream_dec) \ +CRYPTO_ocb128_cleanup(&ctx->ocb); \ +fn_set_enc_key(key, keylen * 8, &ctx->ksenc.ks); \ +fn_set_dec_key(key, keylen * 8, &ctx->ksdec.ks); \ +if (!CRYPTO_ocb128_init(&ctx->ocb, &ctx->ksenc.ks, &ctx->ksdec.ks, \ + (block128_f)fn_block_enc, (block128_f)fn_block_dec, \ + ctx->base.enc ? (ocb128_f)fn_stream_enc : \ + (ocb128_f)fn_stream_dec)) \ + return 0; \ +ctx->key_set = 1 + + +static int cipher_hw_aes_ocb_generic_initkey(PROV_CIPHER_CTX *vctx, + const unsigned char *key, + size_t keylen) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + +/* + * We set both the encrypt and decrypt key here because decrypt + * needs both. (i.e- AAD uses encrypt). + */ +# ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) { + OCB_SET_KEY_FN(HWAES_set_encrypt_key, HWAES_set_decrypt_key, + HWAES_encrypt, HWAES_decrypt, + HWAES_ocb_encrypt, HWAES_ocb_decrypt); + } else +# endif +# ifdef VPAES_CAPABLE + if (VPAES_CAPABLE) { + OCB_SET_KEY_FN(vpaes_set_encrypt_key, vpaes_set_decrypt_key, + vpaes_encrypt, vpaes_decrypt, NULL, NULL); + } else +# endif + { + OCB_SET_KEY_FN(AES_set_encrypt_key, AES_set_decrypt_key, + AES_encrypt, AES_decrypt, NULL, NULL); + } + return 1; +} + +# if defined(AESNI_CAPABLE) + +static int cipher_hw_aes_ocb_aesni_initkey(PROV_CIPHER_CTX *vctx, + const unsigned char *key, + size_t keylen) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + + OCB_SET_KEY_FN(aesni_set_encrypt_key, aesni_set_decrypt_key, + aesni_encrypt, aesni_decrypt, + aesni_ocb_encrypt, aesni_ocb_decrypt); + return 1; +} + +# define PROV_CIPHER_HW_declare() \ +static const PROV_CIPHER_HW aesni_ocb = { \ + cipher_hw_aes_ocb_aesni_initkey, \ + NULL \ +}; +# define PROV_CIPHER_HW_select() \ + if (AESNI_CAPABLE) \ + return &aesni_ocb; + +#elif defined(SPARC_AES_CAPABLE) + +static int cipher_hw_aes_ocb_t4_initkey(PROV_CIPHER_CTX *vctx, + const unsigned char *key, + size_t keylen) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + + OCB_SET_KEY_FN(aes_t4_set_encrypt_key, aes_t4_set_decrypt_key, + aes_t4_encrypt, aes_t4_decrypt, NULL, NULL); + return 1; +} + +# define PROV_CIPHER_HW_declare() \ +static const PROV_CIPHER_HW aes_t4_ocb = { \ + cipher_hw_aes_ocb_t4_initkey, \ + NULL \ +}; +# define PROV_CIPHER_HW_select() \ + if (SPARC_AES_CAPABLE) \ + return &aes_t4_ocb; +#else +# define PROV_CIPHER_HW_declare() +# define PROV_CIPHER_HW_select() +# endif + +static const PROV_CIPHER_HW aes_generic_ocb = { + cipher_hw_aes_ocb_generic_initkey, + NULL +}; +PROV_CIPHER_HW_declare() +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_ocb(size_t keybits) +{ + PROV_CIPHER_HW_select() + return &aes_generic_ocb; +} + + diff --git a/providers/implementations/ciphers/cipher_aes_siv.c b/providers/implementations/ciphers/cipher_aes_siv.c new file mode 100644 index 000000000000..45010b90db2a --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_siv.c @@ -0,0 +1,303 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for AES SIV mode */ + +/* + * This file uses the low level AES functions (which are deprecated for + * non-internal use) in order to implement provider AES ciphers. + */ +#include "internal/deprecated.h" + +#include <openssl/proverr.h> +#include "cipher_aes_siv.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/ciphercommon_aead.h" +#include "prov/provider_ctx.h" + +#define siv_stream_update siv_cipher +#define SIV_FLAGS AEAD_FLAGS + +static OSSL_FUNC_cipher_set_ctx_params_fn aes_siv_set_ctx_params; + +static void *aes_siv_newctx(void *provctx, size_t keybits, unsigned int mode, + uint64_t flags) +{ + PROV_AES_SIV_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) { + ctx->taglen = SIV_LEN; + ctx->mode = mode; + ctx->keylen = keybits / 8; + ctx->hw = ossl_prov_cipher_hw_aes_siv(keybits); + ctx->libctx = PROV_LIBCTX_OF(provctx); + } + return ctx; +} + +static void aes_siv_freectx(void *vctx) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + + if (ctx != NULL) { + ctx->hw->cleanup(ctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); + } +} + +static void *siv_dupctx(void *vctx) +{ + PROV_AES_SIV_CTX *in = (PROV_AES_SIV_CTX *)vctx; + PROV_AES_SIV_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + if (!in->hw->dupctx(in, ret)) { + OPENSSL_free(ret); + ret = NULL; + } + return ret; +} + +static int siv_init(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[], int enc) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + ctx->enc = enc; + + if (key != NULL) { + if (keylen != ctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + if (!ctx->hw->initkey(ctx, key, ctx->keylen)) + return 0; + } + return aes_siv_set_ctx_params(ctx, params); +} + +static int siv_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return siv_init(vctx, key, keylen, iv, ivlen, params, 1); +} + +static int siv_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return siv_init(vctx, key, keylen, iv, ivlen, params, 0); +} + +static int siv_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (inl == 0) { + *outl = 0; + return 1; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (ctx->hw->cipher(ctx, out, in, inl) <= 0) + return 0; + + if (outl != NULL) + *outl = inl; + return 1; +} + +static int siv_stream_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (!ctx->hw->cipher(vctx, out, NULL, 0)) + return 0; + + if (outl != NULL) + *outl = 0; + return 1; +} + +static int aes_siv_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL && p->data_type == OSSL_PARAM_OCTET_STRING) { + if (!ctx->enc + || p->data_size != ctx->taglen + || !OSSL_PARAM_set_octet_string(p, &sctx->tag.byte, ctx->taglen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->taglen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + return 1; +} + +static const OSSL_PARAM aes_siv_known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *aes_siv_gettable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return aes_siv_known_gettable_ctx_params; +} + +static int aes_siv_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + const OSSL_PARAM *p; + unsigned int speed = 0; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL) { + if (ctx->enc) + return 1; + if (p->data_type != OSSL_PARAM_OCTET_STRING + || !ctx->hw->settag(ctx, p->data, p->data_size)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_SPEED); + if (p != NULL) { + if (!OSSL_PARAM_get_uint(p, &speed)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + ctx->hw->setspeed(ctx, (int)speed); + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + size_t keylen; + + if (!OSSL_PARAM_get_size_t(p, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + /* The key length can not be modified */ + if (keylen != ctx->keylen) + return 0; + } + return 1; +} + +static const OSSL_PARAM aes_siv_known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_SPEED, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *aes_siv_settable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return aes_siv_known_settable_ctx_params; +} + +#define IMPLEMENT_cipher(alg, lc, UCMODE, flags, kbits, blkbits, ivbits) \ +static OSSL_FUNC_cipher_newctx_fn alg##kbits##lc##_newctx; \ +static OSSL_FUNC_cipher_freectx_fn alg##_##lc##_freectx; \ +static OSSL_FUNC_cipher_dupctx_fn lc##_dupctx; \ +static OSSL_FUNC_cipher_encrypt_init_fn lc##_einit; \ +static OSSL_FUNC_cipher_decrypt_init_fn lc##_dinit; \ +static OSSL_FUNC_cipher_update_fn lc##_stream_update; \ +static OSSL_FUNC_cipher_final_fn lc##_stream_final; \ +static OSSL_FUNC_cipher_cipher_fn lc##_cipher; \ +static OSSL_FUNC_cipher_get_params_fn alg##_##kbits##_##lc##_get_params; \ +static OSSL_FUNC_cipher_get_ctx_params_fn alg##_##lc##_get_ctx_params; \ +static OSSL_FUNC_cipher_gettable_ctx_params_fn \ + alg##_##lc##_gettable_ctx_params; \ +static OSSL_FUNC_cipher_set_ctx_params_fn alg##_##lc##_set_ctx_params; \ +static OSSL_FUNC_cipher_settable_ctx_params_fn \ + alg##_##lc##_settable_ctx_params; \ +static int alg##_##kbits##_##lc##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, 2*kbits, blkbits, ivbits); \ +} \ +static void * alg##kbits##lc##_newctx(void *provctx) \ +{ \ + return alg##_##lc##_newctx(provctx, 2*kbits, EVP_CIPH_##UCMODE##_MODE, \ + flags); \ +} \ +const OSSL_DISPATCH ossl_##alg##kbits##lc##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))alg##kbits##lc##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))alg##_##lc##_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) lc##_dupctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void)) lc##_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void)) lc##_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void)) lc##_stream_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void)) lc##_stream_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void)) lc##_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void)) alg##_##kbits##_##lc##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void)) alg##_##lc##_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void)) alg##_##lc##_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void)) alg##_##lc##_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void)) alg##_##lc##_settable_ctx_params }, \ + { 0, NULL } \ +}; + +IMPLEMENT_cipher(aes, siv, SIV, SIV_FLAGS, 128, 8, 0) +IMPLEMENT_cipher(aes, siv, SIV, SIV_FLAGS, 192, 8, 0) +IMPLEMENT_cipher(aes, siv, SIV, SIV_FLAGS, 256, 8, 0) diff --git a/providers/implementations/ciphers/cipher_aes_siv.h b/providers/implementations/ciphers/cipher_aes_siv.h new file mode 100644 index 000000000000..4a682b77c440 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_siv.h @@ -0,0 +1,36 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/ciphercommon.h" +#include "crypto/aes_platform.h" +#include "crypto/siv.h" + +typedef struct prov_cipher_hw_aes_siv_st { + int (*initkey)(void *ctx, const uint8_t *key, size_t keylen); + int (*cipher)(void *ctx, unsigned char *out, const unsigned char *in, + size_t len); + void (*setspeed)(void *ctx, int speed); + int (*settag)(void *ctx, const unsigned char *tag, size_t tagl); + void (*cleanup)(void *ctx); + int (*dupctx)(void *src, void *dst); +} PROV_CIPHER_HW_AES_SIV; + +typedef struct prov_siv_ctx_st { + unsigned int mode; /* The mode that we are using */ + unsigned int enc : 1; /* Set to 1 if we are encrypting or 0 otherwise */ + size_t keylen; /* The input keylength (twice the alg key length) */ + size_t taglen; /* the taglen is the same as the sivlen */ + SIV128_CONTEXT siv; + EVP_CIPHER *ctr; /* These are fetched - so we need to free them */ + EVP_CIPHER *cbc; + const PROV_CIPHER_HW_AES_SIV *hw; + OSSL_LIB_CTX *libctx; +} PROV_AES_SIV_CTX; + +const PROV_CIPHER_HW_AES_SIV *ossl_prov_cipher_hw_aes_siv(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_aes_siv_hw.c b/providers/implementations/ciphers/cipher_aes_siv_hw.c new file mode 100644 index 000000000000..1e6b3d56e4bd --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_siv_hw.c @@ -0,0 +1,136 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This file uses the low level AES functions (which are deprecated for + * non-internal use) in order to implement provider AES ciphers. + */ +#include "internal/deprecated.h" + +#include "cipher_aes_siv.h" + +static void aes_siv_cleanup(void *vctx); + +static int aes_siv_initkey(void *vctx, const unsigned char *key, size_t keylen) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + size_t klen = keylen / 2; + OSSL_LIB_CTX *libctx = ctx->libctx; + const char *propq = NULL; + + EVP_CIPHER_free(ctx->cbc); + EVP_CIPHER_free(ctx->ctr); + ctx->cbc = NULL; + ctx->ctr = NULL; + + switch (klen) { + case 16: + ctx->cbc = EVP_CIPHER_fetch(libctx, "AES-128-CBC", propq); + ctx->ctr = EVP_CIPHER_fetch(libctx, "AES-128-CTR", propq); + break; + case 24: + ctx->cbc = EVP_CIPHER_fetch(libctx, "AES-192-CBC", propq); + ctx->ctr = EVP_CIPHER_fetch(libctx, "AES-192-CTR", propq); + break; + case 32: + ctx->cbc = EVP_CIPHER_fetch(libctx, "AES-256-CBC", propq); + ctx->ctr = EVP_CIPHER_fetch(libctx, "AES-256-CTR", propq); + break; + default: + break; + } + if (ctx->cbc == NULL || ctx->ctr == NULL) + return 0; + /* + * klen is the length of the underlying cipher, not the input key, + * which should be twice as long + */ + return ossl_siv128_init(sctx, key, klen, ctx->cbc, ctx->ctr, libctx, + propq); +} + +static int aes_siv_dupctx(void *in_vctx, void *out_vctx) +{ + PROV_AES_SIV_CTX *in = (PROV_AES_SIV_CTX *)in_vctx; + PROV_AES_SIV_CTX *out = (PROV_AES_SIV_CTX *)out_vctx; + + *out = *in; + out->siv.cipher_ctx = NULL; + out->siv.mac_ctx_init = NULL; + out->siv.mac = NULL; + if (!ossl_siv128_copy_ctx(&out->siv, &in->siv)) + return 0; + if (out->cbc != NULL) + EVP_CIPHER_up_ref(out->cbc); + if (out->ctr != NULL) + EVP_CIPHER_up_ref(out->ctr); + return 1; +} + +static int aes_siv_settag(void *vctx, const unsigned char *tag, size_t tagl) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + + return ossl_siv128_set_tag(sctx, tag, tagl); +} + +static void aes_siv_setspeed(void *vctx, int speed) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + + ossl_siv128_speed(sctx, (int)speed); +} + +static void aes_siv_cleanup(void *vctx) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + + ossl_siv128_cleanup(sctx); + EVP_CIPHER_free(ctx->cbc); + EVP_CIPHER_free(ctx->ctr); +} + +static int aes_siv_cipher(void *vctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + + /* EncryptFinal or DecryptFinal */ + if (in == NULL) + return ossl_siv128_finish(sctx) == 0; + + /* Deal with associated data */ + if (out == NULL) + return (ossl_siv128_aad(sctx, in, len) == 1); + + if (ctx->enc) + return ossl_siv128_encrypt(sctx, in, out, len) > 0; + + return ossl_siv128_decrypt(sctx, in, out, len) > 0; +} + +static const PROV_CIPHER_HW_AES_SIV aes_siv_hw = +{ + aes_siv_initkey, + aes_siv_cipher, + aes_siv_setspeed, + aes_siv_settag, + aes_siv_cleanup, + aes_siv_dupctx, +}; + +const PROV_CIPHER_HW_AES_SIV *ossl_prov_cipher_hw_aes_siv(size_t keybits) +{ + return &aes_siv_hw; +} diff --git a/providers/implementations/ciphers/cipher_aes_wrp.c b/providers/implementations/ciphers/cipher_aes_wrp.c new file mode 100644 index 000000000000..8bddf475e24d --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_wrp.c @@ -0,0 +1,311 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This file uses the low level AES functions (which are deprecated for + * non-internal use) in order to implement provider AES ciphers. + */ +#include "internal/deprecated.h" + +#include <openssl/proverr.h> +#include "cipher_aes.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" + +/* AES wrap with padding has IV length of 4, without padding 8 */ +#define AES_WRAP_PAD_IVLEN 4 +#define AES_WRAP_NOPAD_IVLEN 8 + +#define WRAP_FLAGS (PROV_CIPHER_FLAG_CUSTOM_IV) +#define WRAP_FLAGS_INV (WRAP_FLAGS | PROV_CIPHER_FLAG_INVERSE_CIPHER) + +typedef size_t (*aeswrap_fn)(void *key, const unsigned char *iv, + unsigned char *out, const unsigned char *in, + size_t inlen, block128_f block); + +static OSSL_FUNC_cipher_encrypt_init_fn aes_wrap_einit; +static OSSL_FUNC_cipher_decrypt_init_fn aes_wrap_dinit; +static OSSL_FUNC_cipher_update_fn aes_wrap_cipher; +static OSSL_FUNC_cipher_final_fn aes_wrap_final; +static OSSL_FUNC_cipher_freectx_fn aes_wrap_freectx; +static OSSL_FUNC_cipher_set_ctx_params_fn aes_wrap_set_ctx_params; + +typedef struct prov_aes_wrap_ctx_st { + PROV_CIPHER_CTX base; + union { + OSSL_UNION_ALIGN; + AES_KEY ks; + } ks; + aeswrap_fn wrapfn; + +} PROV_AES_WRAP_CTX; + + +static void *aes_wrap_newctx(size_t kbits, size_t blkbits, + size_t ivbits, unsigned int mode, uint64_t flags) +{ + PROV_AES_WRAP_CTX *wctx; + PROV_CIPHER_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + wctx = OPENSSL_zalloc(sizeof(*wctx)); + ctx = (PROV_CIPHER_CTX *)wctx; + if (ctx != NULL) { + ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits, mode, flags, + NULL, NULL); + ctx->pad = (ctx->ivlen == AES_WRAP_PAD_IVLEN); + } + return wctx; +} + +static void aes_wrap_freectx(void *vctx) +{ + PROV_AES_WRAP_CTX *wctx = (PROV_AES_WRAP_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(wctx, sizeof(*wctx)); +} + +static int aes_wrap_init(void *vctx, const unsigned char *key, + size_t keylen, const unsigned char *iv, + size_t ivlen, const OSSL_PARAM params[], int enc) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_AES_WRAP_CTX *wctx = (PROV_AES_WRAP_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + ctx->enc = enc; + if (ctx->pad) + wctx->wrapfn = enc ? CRYPTO_128_wrap_pad : CRYPTO_128_unwrap_pad; + else + wctx->wrapfn = enc ? CRYPTO_128_wrap : CRYPTO_128_unwrap; + + if (iv != NULL) { + if (!ossl_cipher_generic_initiv(ctx, iv, ivlen)) + return 0; + } + if (key != NULL) { + int use_forward_transform; + + if (keylen != ctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + /* + * See SP800-38F : Section 5.1 + * The forward and inverse transformations for the AES block + * cipher—called “cipher” and “inverse cipher” are informally known as + * the AES encryption and AES decryption functions, respectively. + * If the designated cipher function for a key-wrap algorithm is chosen + * to be the AES decryption function, then CIPH-1K will be the AES + * encryption function. + */ + if (ctx->inverse_cipher == 0) + use_forward_transform = ctx->enc; + else + use_forward_transform = !ctx->enc; + if (use_forward_transform) { + AES_set_encrypt_key(key, keylen * 8, &wctx->ks.ks); + ctx->block = (block128_f)AES_encrypt; + } else { + AES_set_decrypt_key(key, keylen * 8, &wctx->ks.ks); + ctx->block = (block128_f)AES_decrypt; + } + } + return aes_wrap_set_ctx_params(ctx, params); +} + +static int aes_wrap_einit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return aes_wrap_init(ctx, key, keylen, iv, ivlen, params, 1); +} + +static int aes_wrap_dinit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return aes_wrap_init(ctx, key, keylen, iv, ivlen, params, 0); +} + +static int aes_wrap_cipher_internal(void *vctx, unsigned char *out, + const unsigned char *in, size_t inlen) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_AES_WRAP_CTX *wctx = (PROV_AES_WRAP_CTX *)vctx; + size_t rv; + int pad = ctx->pad; + + /* No final operation so always return zero length */ + if (in == NULL) + return 0; + + /* Input length must always be non-zero */ + if (inlen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH); + return -1; + } + + /* If decrypting need at least 16 bytes and multiple of 8 */ + if (!ctx->enc && (inlen < 16 || inlen & 0x7)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH); + return -1; + } + + /* If not padding input must be multiple of 8 */ + if (!pad && inlen & 0x7) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH); + return -1; + } + + if (out == NULL) { + if (ctx->enc) { + /* If padding round up to multiple of 8 */ + if (pad) + inlen = (inlen + 7) / 8 * 8; + /* 8 byte prefix */ + return inlen + 8; + } else { + /* + * If not padding output will be exactly 8 bytes smaller than + * input. If padding it will be at least 8 bytes smaller but we + * don't know how much. + */ + return inlen - 8; + } + } + + rv = wctx->wrapfn(&wctx->ks.ks, ctx->iv_set ? ctx->iv : NULL, out, in, + inlen, ctx->block); + if (!rv) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return -1; + } + if (rv > INT_MAX) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_OUTPUT_LENGTH); + return -1; + } + return (int)rv; +} + +static int aes_wrap_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + if (!ossl_prov_is_running()) + return 0; + + *outl = 0; + return 1; +} + +static int aes_wrap_cipher(void *vctx, + unsigned char *out, size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + PROV_AES_WRAP_CTX *ctx = (PROV_AES_WRAP_CTX *)vctx; + size_t len; + + if (!ossl_prov_is_running()) + return 0; + + if (inl == 0) { + *outl = 0; + return 1; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + len = aes_wrap_cipher_internal(ctx, out, in, inl); + if (len <= 0) + return 0; + + *outl = len; + return 1; +} + +static int aes_wrap_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + const OSSL_PARAM *p; + size_t keylen = 0; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ctx->keylen != keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + return 1; +} + +#define IMPLEMENT_cipher(mode, fname, UCMODE, flags, kbits, blkbits, ivbits) \ + static OSSL_FUNC_cipher_get_params_fn aes_##kbits##_##fname##_get_params; \ + static int aes_##kbits##_##fname##_get_params(OSSL_PARAM params[]) \ + { \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE,\ + flags, kbits, blkbits, ivbits); \ + } \ + static OSSL_FUNC_cipher_newctx_fn aes_##kbits##fname##_newctx; \ + static void *aes_##kbits##fname##_newctx(void *provctx) \ + { \ + return aes_##mode##_newctx(kbits, blkbits, ivbits, \ + EVP_CIPH_##UCMODE##_MODE, flags); \ + } \ + const OSSL_DISPATCH ossl_##aes##kbits##fname##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (void (*)(void))aes_##kbits##fname##_newctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))aes_##mode##_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))aes_##mode##_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))aes_##mode##_cipher }, \ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))aes_##mode##_final }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))aes_##mode##_freectx }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void))aes_##kbits##_##fname##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))aes_wrap_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_settable_ctx_params }, \ + { 0, NULL } \ + } + +IMPLEMENT_cipher(wrap, wrap, WRAP, WRAP_FLAGS, 256, 64, AES_WRAP_NOPAD_IVLEN * 8); +IMPLEMENT_cipher(wrap, wrap, WRAP, WRAP_FLAGS, 192, 64, AES_WRAP_NOPAD_IVLEN * 8); +IMPLEMENT_cipher(wrap, wrap, WRAP, WRAP_FLAGS, 128, 64, AES_WRAP_NOPAD_IVLEN * 8); +IMPLEMENT_cipher(wrap, wrappad, WRAP, WRAP_FLAGS, 256, 64, AES_WRAP_PAD_IVLEN * 8); +IMPLEMENT_cipher(wrap, wrappad, WRAP, WRAP_FLAGS, 192, 64, AES_WRAP_PAD_IVLEN * 8); +IMPLEMENT_cipher(wrap, wrappad, WRAP, WRAP_FLAGS, 128, 64, AES_WRAP_PAD_IVLEN * 8); + +IMPLEMENT_cipher(wrap, wrapinv, WRAP, WRAP_FLAGS_INV, 256, 64, AES_WRAP_NOPAD_IVLEN * 8); +IMPLEMENT_cipher(wrap, wrapinv, WRAP, WRAP_FLAGS_INV, 192, 64, AES_WRAP_NOPAD_IVLEN * 8); +IMPLEMENT_cipher(wrap, wrapinv, WRAP, WRAP_FLAGS_INV, 128, 64, AES_WRAP_NOPAD_IVLEN * 8); +IMPLEMENT_cipher(wrap, wrappadinv, WRAP, WRAP_FLAGS_INV, 256, 64, AES_WRAP_PAD_IVLEN * 8); +IMPLEMENT_cipher(wrap, wrappadinv, WRAP, WRAP_FLAGS_INV, 192, 64, AES_WRAP_PAD_IVLEN * 8); +IMPLEMENT_cipher(wrap, wrappadinv, WRAP, WRAP_FLAGS_INV, 128, 64, AES_WRAP_PAD_IVLEN * 8); diff --git a/providers/implementations/ciphers/cipher_aes_xts.c b/providers/implementations/ciphers/cipher_aes_xts.c new file mode 100644 index 000000000000..dce2032986b1 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_xts.c @@ -0,0 +1,294 @@ + +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * AES low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +#include <openssl/proverr.h> +#include "cipher_aes_xts.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define AES_XTS_FLAGS PROV_CIPHER_FLAG_CUSTOM_IV +#define AES_XTS_IV_BITS 128 +#define AES_XTS_BLOCK_BITS 8 + +/* forward declarations */ +static OSSL_FUNC_cipher_encrypt_init_fn aes_xts_einit; +static OSSL_FUNC_cipher_decrypt_init_fn aes_xts_dinit; +static OSSL_FUNC_cipher_update_fn aes_xts_stream_update; +static OSSL_FUNC_cipher_final_fn aes_xts_stream_final; +static OSSL_FUNC_cipher_cipher_fn aes_xts_cipher; +static OSSL_FUNC_cipher_freectx_fn aes_xts_freectx; +static OSSL_FUNC_cipher_dupctx_fn aes_xts_dupctx; +static OSSL_FUNC_cipher_set_ctx_params_fn aes_xts_set_ctx_params; +static OSSL_FUNC_cipher_settable_ctx_params_fn aes_xts_settable_ctx_params; + +/* + * Verify that the two keys are different. + * + * This addresses the vulnerability described in Rogaway's + * September 2004 paper: + * + * "Efficient Instantiations of Tweakable Blockciphers and + * Refinements to Modes OCB and PMAC". + * (http://web.cs.ucdavis.edu/~rogaway/papers/offsets.pdf) + * + * FIPS 140-2 IG A.9 XTS-AES Key Generation Requirements states + * that: + * "The check for Key_1 != Key_2 shall be done at any place + * BEFORE using the keys in the XTS-AES algorithm to process + * data with them." + */ +static int aes_xts_check_keys_differ(const unsigned char *key, size_t bytes, + int enc) +{ + if ((!ossl_aes_xts_allow_insecure_decrypt || enc) + && CRYPTO_memcmp(key, key + bytes, bytes) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_XTS_DUPLICATED_KEYS); + return 0; + } + return 1; +} + +/*- + * Provider dispatch functions + */ +static int aes_xts_init(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[], int enc) +{ + PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)vctx; + PROV_CIPHER_CTX *ctx = &xctx->base; + + if (!ossl_prov_is_running()) + return 0; + + ctx->enc = enc; + + if (iv != NULL) { + if (!ossl_cipher_generic_initiv(vctx, iv, ivlen)) + return 0; + } + if (key != NULL) { + if (keylen != ctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + if (!aes_xts_check_keys_differ(key, keylen / 2, enc)) + return 0; + if (!ctx->hw->init(ctx, key, keylen)) + return 0; + } + return aes_xts_set_ctx_params(ctx, params); +} + +static int aes_xts_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return aes_xts_init(vctx, key, keylen, iv, ivlen, params, 1); +} + +static int aes_xts_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return aes_xts_init(vctx, key, keylen, iv, ivlen, params, 0); +} + +static void *aes_xts_newctx(void *provctx, unsigned int mode, uint64_t flags, + size_t kbits, size_t blkbits, size_t ivbits) +{ + PROV_AES_XTS_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ossl_cipher_generic_initkey(&ctx->base, kbits, blkbits, ivbits, mode, + flags, ossl_prov_cipher_hw_aes_xts(kbits), + NULL); + } + return ctx; +} + +static void aes_xts_freectx(void *vctx) +{ + PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *aes_xts_dupctx(void *vctx) +{ + PROV_AES_XTS_CTX *in = (PROV_AES_XTS_CTX *)vctx; + PROV_AES_XTS_CTX *ret = NULL; + + if (!ossl_prov_is_running()) + return NULL; + + if (in->xts.key1 != NULL) { + if (in->xts.key1 != &in->ks1) + return NULL; + } + if (in->xts.key2 != NULL) { + if (in->xts.key2 != &in->ks2) + return NULL; + } + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + in->base.hw->copyctx(&ret->base, &in->base); + return ret; +} + +static int aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx; + + if (!ossl_prov_is_running() + || ctx->xts.key1 == NULL + || ctx->xts.key2 == NULL + || !ctx->base.iv_set + || out == NULL + || in == NULL + || inl < AES_BLOCK_SIZE) + return 0; + + /* + * Impose a limit of 2^20 blocks per data unit as specified by + * IEEE Std 1619-2018. The earlier and obsolete IEEE Std 1619-2007 + * indicated that this was a SHOULD NOT rather than a MUST NOT. + * NIST SP 800-38E mandates the same limit. + */ + if (inl > XTS_MAX_BLOCKS_PER_DATA_UNIT * AES_BLOCK_SIZE) { + ERR_raise(ERR_LIB_PROV, PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE); + return 0; + } + + if (ctx->stream != NULL) + (*ctx->stream)(in, out, inl, ctx->xts.key1, ctx->xts.key2, ctx->base.iv); + else if (CRYPTO_xts128_encrypt(&ctx->xts, ctx->base.iv, in, out, inl, + ctx->base.enc)) + return 0; + + *outl = inl; + return 1; +} + +static int aes_xts_stream_update(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, + size_t inl) +{ + PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!aes_xts_cipher(ctx, out, outl, outsize, in, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + return 1; +} + +static int aes_xts_stream_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + if (!ossl_prov_is_running()) + return 0; + *outl = 0; + return 1; +} + +static const OSSL_PARAM aes_xts_known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *aes_xts_settable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return aes_xts_known_settable_ctx_params; +} + +static int aes_xts_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + size_t keylen; + + if (!OSSL_PARAM_get_size_t(p, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + /* The key length can not be modified for xts mode */ + if (keylen != ctx->keylen) + return 0; + } + + return 1; +} + +#define IMPLEMENT_cipher(lcmode, UCMODE, kbits, flags) \ +static OSSL_FUNC_cipher_get_params_fn aes_##kbits##_##lcmode##_get_params; \ +static int aes_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, 2 * kbits, AES_XTS_BLOCK_BITS, \ + AES_XTS_IV_BITS); \ +} \ +static OSSL_FUNC_cipher_newctx_fn aes_##kbits##_xts_newctx; \ +static void *aes_##kbits##_xts_newctx(void *provctx) \ +{ \ + return aes_xts_newctx(provctx, EVP_CIPH_##UCMODE##_MODE, flags, 2 * kbits, \ + AES_XTS_BLOCK_BITS, AES_XTS_IV_BITS); \ +} \ +const OSSL_DISPATCH ossl_aes##kbits##xts_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))aes_##kbits##_xts_newctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))aes_xts_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))aes_xts_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))aes_xts_stream_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))aes_xts_stream_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))aes_xts_cipher }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))aes_xts_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))aes_xts_dupctx }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void))aes_##kbits##_##lcmode##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))aes_xts_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))aes_xts_settable_ctx_params }, \ + { 0, NULL } \ +} + +IMPLEMENT_cipher(xts, XTS, 256, AES_XTS_FLAGS); +IMPLEMENT_cipher(xts, XTS, 128, AES_XTS_FLAGS); diff --git a/providers/implementations/ciphers/cipher_aes_xts.h b/providers/implementations/ciphers/cipher_aes_xts.h new file mode 100644 index 000000000000..afc42ef444b3 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_xts.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/aes.h> +#include "prov/ciphercommon.h" +#include "crypto/aes_platform.h" + +/* + * Available in cipher_fips.c, and compiled with different values depending + * on we're in the FIPS module or not. + */ +extern const int ossl_aes_xts_allow_insecure_decrypt; + +PROV_CIPHER_FUNC(void, xts_stream, + (const unsigned char *in, unsigned char *out, size_t len, + const AES_KEY *key1, const AES_KEY *key2, + const unsigned char iv[16])); + +typedef struct prov_aes_xts_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + AES_KEY ks; + } ks1, ks2; /* AES key schedules to use */ + XTS128_CONTEXT xts; + OSSL_xts_stream_fn stream; +} PROV_AES_XTS_CTX; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_xts(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_aes_xts_fips.c b/providers/implementations/ciphers/cipher_aes_xts_fips.c new file mode 100644 index 000000000000..777d928bf96f --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_xts_fips.c @@ -0,0 +1,23 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * AES low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +#include "cipher_aes_xts.h" + +#ifdef FIPS_MODULE +const int ossl_aes_xts_allow_insecure_decrypt = 0; +#else +const int ossl_aes_xts_allow_insecure_decrypt = 1; +#endif /* FIPS_MODULE */ diff --git a/providers/implementations/ciphers/cipher_aes_xts_hw.c b/providers/implementations/ciphers/cipher_aes_xts_hw.c new file mode 100644 index 000000000000..c71492f51f5e --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_xts_hw.c @@ -0,0 +1,177 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This file uses the low level AES functions (which are deprecated for + * non-internal use) in order to implement provider AES ciphers. + */ +#include "internal/deprecated.h" + +#include "cipher_aes_xts.h" + +#define XTS_SET_KEY_FN(fn_set_enc_key, fn_set_dec_key, \ + fn_block_enc, fn_block_dec, \ + fn_stream_enc, fn_stream_dec) { \ + size_t bytes = keylen / 2; \ + size_t bits = bytes * 8; \ + \ + if (ctx->enc) { \ + fn_set_enc_key(key, bits, &xctx->ks1.ks); \ + xctx->xts.block1 = (block128_f)fn_block_enc; \ + } else { \ + fn_set_dec_key(key, bits, &xctx->ks1.ks); \ + xctx->xts.block1 = (block128_f)fn_block_dec; \ + } \ + fn_set_enc_key(key + bytes, bits, &xctx->ks2.ks); \ + xctx->xts.block2 = (block128_f)fn_block_enc; \ + xctx->xts.key1 = &xctx->ks1; \ + xctx->xts.key2 = &xctx->ks2; \ + xctx->stream = ctx->enc ? fn_stream_enc : fn_stream_dec; \ +} + +static int cipher_hw_aes_xts_generic_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, + size_t keylen) +{ + PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)ctx; + OSSL_xts_stream_fn stream_enc = NULL; + OSSL_xts_stream_fn stream_dec = NULL; + +#ifdef AES_XTS_ASM + stream_enc = AES_xts_encrypt; + stream_dec = AES_xts_decrypt; +#endif /* AES_XTS_ASM */ + +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) { +# ifdef HWAES_xts_encrypt + stream_enc = HWAES_xts_encrypt; +# endif /* HWAES_xts_encrypt */ +# ifdef HWAES_xts_decrypt + stream_dec = HWAES_xts_decrypt; +# endif /* HWAES_xts_decrypt */ + XTS_SET_KEY_FN(HWAES_set_encrypt_key, HWAES_set_decrypt_key, + HWAES_encrypt, HWAES_decrypt, + stream_enc, stream_dec); + return 1; + } else +#endif /* HWAES_CAPABLE */ + +#ifdef BSAES_CAPABLE + if (BSAES_CAPABLE) { + stream_enc = ossl_bsaes_xts_encrypt; + stream_dec = ossl_bsaes_xts_decrypt; + } else +#endif /* BSAES_CAPABLE */ +#ifdef VPAES_CAPABLE + if (VPAES_CAPABLE) { + XTS_SET_KEY_FN(vpaes_set_encrypt_key, vpaes_set_decrypt_key, + vpaes_encrypt, vpaes_decrypt, stream_enc, stream_dec); + return 1; + } else +#endif /* VPAES_CAPABLE */ + { + (void)0; + } + { + XTS_SET_KEY_FN(AES_set_encrypt_key, AES_set_decrypt_key, + AES_encrypt, AES_decrypt, stream_enc, stream_dec); + } + return 1; +} + +static void cipher_hw_aes_xts_copyctx(PROV_CIPHER_CTX *dst, + const PROV_CIPHER_CTX *src) +{ + PROV_AES_XTS_CTX *sctx = (PROV_AES_XTS_CTX *)src; + PROV_AES_XTS_CTX *dctx = (PROV_AES_XTS_CTX *)dst; + + *dctx = *sctx; + dctx->xts.key1 = &dctx->ks1.ks; + dctx->xts.key2 = &dctx->ks2.ks; +} + +#if defined(AESNI_CAPABLE) + +static int cipher_hw_aesni_xts_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)ctx; + + XTS_SET_KEY_FN(aesni_set_encrypt_key, aesni_set_decrypt_key, + aesni_encrypt, aesni_decrypt, + aesni_xts_encrypt, aesni_xts_decrypt); + return 1; +} + +# define PROV_CIPHER_HW_declare_xts() \ +static const PROV_CIPHER_HW aesni_xts = { \ + cipher_hw_aesni_xts_initkey, \ + NULL, \ + cipher_hw_aes_xts_copyctx \ +}; +# define PROV_CIPHER_HW_select_xts() \ +if (AESNI_CAPABLE) \ + return &aesni_xts; + +# elif defined(SPARC_AES_CAPABLE) + +static int cipher_hw_aes_xts_t4_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)ctx; + OSSL_xts_stream_fn stream_enc = NULL; + OSSL_xts_stream_fn stream_dec = NULL; + + /* Note: keylen is the size of 2 keys */ + switch (keylen) { + case 32: + stream_enc = aes128_t4_xts_encrypt; + stream_dec = aes128_t4_xts_decrypt; + break; + case 64: + stream_enc = aes256_t4_xts_encrypt; + stream_dec = aes256_t4_xts_decrypt; + break; + default: + return 0; + } + + XTS_SET_KEY_FN(aes_t4_set_encrypt_key, aes_t4_set_decrypt_key, + aes_t4_encrypt, aes_t4_decrypt, + stream_enc, stream_dec); + return 1; +} + +# define PROV_CIPHER_HW_declare_xts() \ +static const PROV_CIPHER_HW aes_xts_t4 = { \ + cipher_hw_aes_xts_t4_initkey, \ + NULL, \ + cipher_hw_aes_xts_copyctx \ +}; +# define PROV_CIPHER_HW_select_xts() \ +if (SPARC_AES_CAPABLE) \ + return &aes_xts_t4; +# else +/* The generic case */ +# define PROV_CIPHER_HW_declare_xts() +# define PROV_CIPHER_HW_select_xts() +#endif + +static const PROV_CIPHER_HW aes_generic_xts = { + cipher_hw_aes_xts_generic_initkey, + NULL, + cipher_hw_aes_xts_copyctx +}; +PROV_CIPHER_HW_declare_xts() +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_xts(size_t keybits) +{ + PROV_CIPHER_HW_select_xts() + return &aes_generic_xts; +} diff --git a/providers/implementations/ciphers/cipher_aria.c b/providers/implementations/ciphers/cipher_aria.c new file mode 100644 index 000000000000..be69c39baba3 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aria.c @@ -0,0 +1,86 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for ARIA cipher modes ecb, cbc, ofb, cfb, ctr */ + +#include "cipher_aria.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +static OSSL_FUNC_cipher_freectx_fn aria_freectx; +static OSSL_FUNC_cipher_dupctx_fn aria_dupctx; + +static void aria_freectx(void *vctx) +{ + PROV_ARIA_CTX *ctx = (PROV_ARIA_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *aria_dupctx(void *ctx) +{ + PROV_ARIA_CTX *in = (PROV_ARIA_CTX *)ctx; + PROV_ARIA_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + in->base.hw->copyctx(&ret->base, &in->base); + + return ret; +} + +/* ossl_aria256ecb_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, ecb, ECB, 0, 256, 128, 0, block) +/* ossl_aria192ecb_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, ecb, ECB, 0, 192, 128, 0, block) +/* ossl_aria128ecb_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, ecb, ECB, 0, 128, 128, 0, block) +/* ossl_aria256cbc_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cbc, CBC, 0, 256, 128, 128, block) +/* ossl_aria192cbc_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cbc, CBC, 0, 192, 128, 128, block) +/* ossl_aria128cbc_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cbc, CBC, 0, 128, 128, 128, block) +/* ossl_aria256ofb_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, ofb, OFB, 0, 256, 8, 128, stream) +/* ossl_aria192ofb_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, ofb, OFB, 0, 192, 8, 128, stream) +/* ossl_aria128ofb_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, ofb, OFB, 0, 128, 8, 128, stream) +/* ossl_aria256cfb_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cfb, CFB, 0, 256, 8, 128, stream) +/* ossl_aria192cfb_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cfb, CFB, 0, 192, 8, 128, stream) +/* ossl_aria128cfb_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cfb, CFB, 0, 128, 8, 128, stream) +/* ossl_aria256cfb1_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cfb1, CFB, 0, 256, 8, 128, stream) +/* ossl_aria192cfb1_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cfb1, CFB, 0, 192, 8, 128, stream) +/* ossl_aria128cfb1_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cfb1, CFB, 0, 128, 8, 128, stream) +/* ossl_aria256cfb8_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cfb8, CFB, 0, 256, 8, 128, stream) +/* ossl_aria192cfb8_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cfb8, CFB, 0, 192, 8, 128, stream) +/* ossl_aria128cfb8_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, cfb8, CFB, 0, 128, 8, 128, stream) +/* ossl_aria256ctr_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, ctr, CTR, 0, 256, 8, 128, stream) +/* ossl_aria192ctr_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, ctr, CTR, 0, 192, 8, 128, stream) +/* ossl_aria128ctr_functions */ +IMPLEMENT_generic_cipher(aria, ARIA, ctr, CTR, 0, 128, 8, 128, stream) diff --git a/providers/implementations/ciphers/cipher_aria.h b/providers/implementations/ciphers/cipher_aria.h new file mode 100644 index 000000000000..39f84d3b4321 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aria.h @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "crypto/aria.h" +#include "prov/ciphercommon.h" + +typedef struct prov_aria_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + ARIA_KEY ks; + } ks; +} PROV_ARIA_CTX; + + +#define ossl_prov_cipher_hw_aria_ofb ossl_prov_cipher_hw_aria_ofb128 +#define ossl_prov_cipher_hw_aria_cfb ossl_prov_cipher_hw_aria_cfb128 +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aria_ecb(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aria_cbc(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aria_ofb128(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aria_cfb128(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aria_cfb1(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aria_cfb8(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aria_ctr(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_aria_ccm.c b/providers/implementations/ciphers/cipher_aria_ccm.c new file mode 100644 index 000000000000..d6b5517ee096 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aria_ccm.c @@ -0,0 +1,44 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for ARIA CCM mode */ + +#include "cipher_aria_ccm.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +static OSSL_FUNC_cipher_freectx_fn aria_ccm_freectx; + +static void *aria_ccm_newctx(void *provctx, size_t keybits) +{ + PROV_ARIA_CCM_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + ossl_ccm_initctx(&ctx->base, keybits, ossl_prov_aria_hw_ccm(keybits)); + return ctx; +} + +static void aria_ccm_freectx(void *vctx) +{ + PROV_ARIA_CCM_CTX *ctx = (PROV_ARIA_CCM_CTX *)vctx; + + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +/* aria128ccm functions */ +IMPLEMENT_aead_cipher(aria, ccm, CCM, AEAD_FLAGS, 128, 8, 96); +/* aria192ccm functions */ +IMPLEMENT_aead_cipher(aria, ccm, CCM, AEAD_FLAGS, 192, 8, 96); +/* aria256ccm functions */ +IMPLEMENT_aead_cipher(aria, ccm, CCM, AEAD_FLAGS, 256, 8, 96); + diff --git a/providers/implementations/ciphers/cipher_aria_ccm.h b/providers/implementations/ciphers/cipher_aria_ccm.h new file mode 100644 index 000000000000..558da4973fa2 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aria_ccm.h @@ -0,0 +1,22 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "crypto/aria.h" +#include "prov/ciphercommon.h" +#include "prov/ciphercommon_ccm.h" + +typedef struct prov_aria_ccm_ctx_st { + PROV_CCM_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + ARIA_KEY ks; + } ks; /* ARIA key schedule to use */ +} PROV_ARIA_CCM_CTX; + +const PROV_CCM_HW *ossl_prov_aria_hw_ccm(size_t keylen); diff --git a/providers/implementations/ciphers/cipher_aria_ccm_hw.c b/providers/implementations/ciphers/cipher_aria_ccm_hw.c new file mode 100644 index 000000000000..e56ec8fb0865 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aria_ccm_hw.c @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * Generic support for ARIA CCM. + */ + +#include "cipher_aria_ccm.h" + +static int ccm_aria_initkey(PROV_CCM_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_ARIA_CCM_CTX *actx = (PROV_ARIA_CCM_CTX *)ctx; + + ossl_aria_set_encrypt_key(key, keylen * 8, &actx->ks.ks); + CRYPTO_ccm128_init(&ctx->ccm_ctx, ctx->m, ctx->l, &actx->ks.ks, + (block128_f)ossl_aria_encrypt); + ctx->str = NULL; + ctx->key_set = 1; + return 1; +} + +static const PROV_CCM_HW ccm_aria = { + ccm_aria_initkey, + ossl_ccm_generic_setiv, + ossl_ccm_generic_setaad, + ossl_ccm_generic_auth_encrypt, + ossl_ccm_generic_auth_decrypt, + ossl_ccm_generic_gettag +}; +const PROV_CCM_HW *ossl_prov_aria_hw_ccm(size_t keybits) +{ + return &ccm_aria; +} diff --git a/providers/implementations/ciphers/cipher_aria_gcm.c b/providers/implementations/ciphers/cipher_aria_gcm.c new file mode 100644 index 000000000000..b412bd3202f8 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aria_gcm.c @@ -0,0 +1,44 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for ARIA GCM mode */ + +#include "cipher_aria_gcm.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +static void *aria_gcm_newctx(void *provctx, size_t keybits) +{ + PROV_ARIA_GCM_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + ossl_gcm_initctx(provctx, &ctx->base, keybits, + ossl_prov_aria_hw_gcm(keybits)); + return ctx; +} + +static OSSL_FUNC_cipher_freectx_fn aria_gcm_freectx; +static void aria_gcm_freectx(void *vctx) +{ + PROV_ARIA_GCM_CTX *ctx = (PROV_ARIA_GCM_CTX *)vctx; + + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +/* ossl_aria128gcm_functions */ +IMPLEMENT_aead_cipher(aria, gcm, GCM, AEAD_FLAGS, 128, 8, 96); +/* ossl_aria192gcm_functions */ +IMPLEMENT_aead_cipher(aria, gcm, GCM, AEAD_FLAGS, 192, 8, 96); +/* ossl_aria256gcm_functions */ +IMPLEMENT_aead_cipher(aria, gcm, GCM, AEAD_FLAGS, 256, 8, 96); + diff --git a/providers/implementations/ciphers/cipher_aria_gcm.h b/providers/implementations/ciphers/cipher_aria_gcm.h new file mode 100644 index 000000000000..6251e8322f36 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aria_gcm.h @@ -0,0 +1,22 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "crypto/aria.h" +#include "prov/ciphercommon.h" +#include "prov/ciphercommon_gcm.h" + +typedef struct prov_aria_gcm_ctx_st { + PROV_GCM_CTX base; /* must be first entry in struct */ + union { + OSSL_UNION_ALIGN; + ARIA_KEY ks; + } ks; +} PROV_ARIA_GCM_CTX; + +const PROV_GCM_HW *ossl_prov_aria_hw_gcm(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_aria_gcm_hw.c b/providers/implementations/ciphers/cipher_aria_gcm_hw.c new file mode 100644 index 000000000000..927327c29c77 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aria_gcm_hw.c @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * Generic support for ARIA GCM. + */ + +#include "cipher_aria_gcm.h" + +static int aria_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key, + size_t keylen) +{ + PROV_ARIA_GCM_CTX *actx = (PROV_ARIA_GCM_CTX *)ctx; + ARIA_KEY *ks = &actx->ks.ks; + + GCM_HW_SET_KEY_CTR_FN(ks, ossl_aria_set_encrypt_key, ossl_aria_encrypt, NULL); + return 1; +} + +static const PROV_GCM_HW aria_gcm = { + aria_gcm_initkey, + ossl_gcm_setiv, + ossl_gcm_aad_update, + ossl_gcm_cipher_update, + ossl_gcm_cipher_final, + ossl_gcm_one_shot +}; +const PROV_GCM_HW *ossl_prov_aria_hw_gcm(size_t keybits) +{ + return &aria_gcm; +} diff --git a/providers/implementations/ciphers/cipher_aria_hw.c b/providers/implementations/ciphers/cipher_aria_hw.c new file mode 100644 index 000000000000..425d87a65eca --- /dev/null +++ b/providers/implementations/ciphers/cipher_aria_hw.c @@ -0,0 +1,52 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/proverr.h> +#include "cipher_aria.h" + +static int cipher_hw_aria_initkey(PROV_CIPHER_CTX *dat, + const unsigned char *key, size_t keylen) +{ + int ret, mode = dat->mode; + PROV_ARIA_CTX *adat = (PROV_ARIA_CTX *)dat; + ARIA_KEY *ks = &adat->ks.ks; + + if (dat->enc || (mode != EVP_CIPH_ECB_MODE && mode != EVP_CIPH_CBC_MODE)) + ret = ossl_aria_set_encrypt_key(key, keylen * 8, ks); + else + ret = ossl_aria_set_decrypt_key(key, keylen * 8, ks); + if (ret < 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SETUP_FAILED); + return 0; + } + dat->ks = ks; + dat->block = (block128_f)ossl_aria_encrypt; + return 1; +} + +IMPLEMENT_CIPHER_HW_COPYCTX(cipher_hw_aria_copyctx, PROV_ARIA_CTX) + +# define PROV_CIPHER_HW_aria_mode(mode) \ +static const PROV_CIPHER_HW aria_##mode = { \ + cipher_hw_aria_initkey, \ + ossl_cipher_hw_chunked_##mode, \ + cipher_hw_aria_copyctx \ +}; \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_aria_##mode(size_t keybits) \ +{ \ + return &aria_##mode; \ +} + +PROV_CIPHER_HW_aria_mode(cbc) +PROV_CIPHER_HW_aria_mode(ecb) +PROV_CIPHER_HW_aria_mode(ofb128) +PROV_CIPHER_HW_aria_mode(cfb128) +PROV_CIPHER_HW_aria_mode(cfb1) +PROV_CIPHER_HW_aria_mode(cfb8) +PROV_CIPHER_HW_aria_mode(ctr) diff --git a/providers/implementations/ciphers/cipher_blowfish.c b/providers/implementations/ciphers/cipher_blowfish.c new file mode 100644 index 000000000000..748028d3f32b --- /dev/null +++ b/providers/implementations/ciphers/cipher_blowfish.c @@ -0,0 +1,60 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for Blowfish cipher modes ecb, cbc, ofb, cfb */ + +/* + * BF low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "cipher_blowfish.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define BF_FLAGS PROV_CIPHER_FLAG_VARIABLE_LENGTH + +static OSSL_FUNC_cipher_freectx_fn blowfish_freectx; +static OSSL_FUNC_cipher_dupctx_fn blowfish_dupctx; + +static void blowfish_freectx(void *vctx) +{ + PROV_BLOWFISH_CTX *ctx = (PROV_BLOWFISH_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *blowfish_dupctx(void *ctx) +{ + PROV_BLOWFISH_CTX *in = (PROV_BLOWFISH_CTX *)ctx; + PROV_BLOWFISH_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + *ret = *in; + + return ret; +} + +/* bf_ecb_functions */ +IMPLEMENT_var_keylen_cipher(blowfish, BLOWFISH, ecb, ECB, BF_FLAGS, 128, 64, 0, block) +/* bf_cbc_functions */ +IMPLEMENT_var_keylen_cipher(blowfish, BLOWFISH, cbc, CBC, BF_FLAGS, 128, 64, 64, block) +/* bf_ofb_functions */ +IMPLEMENT_var_keylen_cipher(blowfish, BLOWFISH, ofb64, OFB, BF_FLAGS, 128, 8, 64, stream) +/* bf_cfb_functions */ +IMPLEMENT_var_keylen_cipher(blowfish, BLOWFISH, cfb64, CFB, BF_FLAGS, 128, 8, 64, stream) diff --git a/providers/implementations/ciphers/cipher_blowfish.h b/providers/implementations/ciphers/cipher_blowfish.h new file mode 100644 index 000000000000..bbdc9da3789d --- /dev/null +++ b/providers/implementations/ciphers/cipher_blowfish.h @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/blowfish.h> +#include "prov/ciphercommon.h" + +typedef struct prov_blowfish_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + BF_KEY ks; + } ks; +} PROV_BLOWFISH_CTX; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_blowfish_cbc(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_blowfish_ecb(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_blowfish_ofb64(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_blowfish_cfb64(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_blowfish_hw.c b/providers/implementations/ciphers/cipher_blowfish_hw.c new file mode 100644 index 000000000000..4855a71f6871 --- /dev/null +++ b/providers/implementations/ciphers/cipher_blowfish_hw.c @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * BF low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "cipher_blowfish.h" + +static int cipher_hw_blowfish_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_BLOWFISH_CTX *bctx = (PROV_BLOWFISH_CTX *)ctx; + + BF_set_key(&bctx->ks.ks, keylen, key); + return 1; +} + +# define PROV_CIPHER_HW_blowfish_mode(mode, UCMODE) \ +IMPLEMENT_CIPHER_HW_##UCMODE(mode, blowfish, PROV_BLOWFISH_CTX, BF_KEY, \ + BF_##mode) \ +static const PROV_CIPHER_HW bf_##mode = { \ + cipher_hw_blowfish_initkey, \ + cipher_hw_blowfish_##mode##_cipher \ +}; \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_blowfish_##mode(size_t keybits) \ +{ \ + return &bf_##mode; \ +} + +PROV_CIPHER_HW_blowfish_mode(cbc, CBC) +PROV_CIPHER_HW_blowfish_mode(ecb, ECB) +PROV_CIPHER_HW_blowfish_mode(ofb64, OFB) +PROV_CIPHER_HW_blowfish_mode(cfb64, CFB) diff --git a/providers/implementations/ciphers/cipher_camellia.c b/providers/implementations/ciphers/cipher_camellia.c new file mode 100644 index 000000000000..b119666aa8b0 --- /dev/null +++ b/providers/implementations/ciphers/cipher_camellia.c @@ -0,0 +1,94 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Camellia low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +/* Dispatch functions for CAMELLIA cipher modes ecb, cbc, ofb, cfb, ctr */ + +#include "cipher_camellia.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +static OSSL_FUNC_cipher_freectx_fn camellia_freectx; +static OSSL_FUNC_cipher_dupctx_fn camellia_dupctx; + +static void camellia_freectx(void *vctx) +{ + PROV_CAMELLIA_CTX *ctx = (PROV_CAMELLIA_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *camellia_dupctx(void *ctx) +{ + PROV_CAMELLIA_CTX *in = (PROV_CAMELLIA_CTX *)ctx; + PROV_CAMELLIA_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + in->base.hw->copyctx(&ret->base, &in->base); + + return ret; +} + +/* ossl_camellia256ecb_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, ecb, ECB, 0, 256, 128, 0, block) +/* ossl_camellia192ecb_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, ecb, ECB, 0, 192, 128, 0, block) +/* ossl_camellia128ecb_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, ecb, ECB, 0, 128, 128, 0, block) +/* ossl_camellia256cbc_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cbc, CBC, 0, 256, 128, 128, block) +/* ossl_camellia192cbc_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cbc, CBC, 0, 192, 128, 128, block) +/* ossl_camellia128cbc_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cbc, CBC, 0, 128, 128, 128, block) +/* ossl_camellia256ofb_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, ofb, OFB, 0, 256, 8, 128, stream) +/* ossl_camellia192ofb_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, ofb, OFB, 0, 192, 8, 128, stream) +/* ossl_camellia128ofb_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, ofb, OFB, 0, 128, 8, 128, stream) +/* ossl_camellia256cfb_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb, CFB, 0, 256, 8, 128, stream) +/* ossl_camellia192cfb_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb, CFB, 0, 192, 8, 128, stream) +/* ossl_camellia128cfb_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb, CFB, 0, 128, 8, 128, stream) +/* ossl_camellia256cfb1_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb1, CFB, 0, 256, 8, 128, stream) +/* ossl_camellia192cfb1_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb1, CFB, 0, 192, 8, 128, stream) +/* ossl_camellia128cfb1_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb1, CFB, 0, 128, 8, 128, stream) +/* ossl_camellia256cfb8_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb8, CFB, 0, 256, 8, 128, stream) +/* ossl_camellia192cfb8_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb8, CFB, 0, 192, 8, 128, stream) +/* ossl_camellia128cfb8_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb8, CFB, 0, 128, 8, 128, stream) +/* ossl_camellia256ctr_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, ctr, CTR, 0, 256, 8, 128, stream) +/* ossl_camellia192ctr_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, ctr, CTR, 0, 192, 8, 128, stream) +/* ossl_camellia128ctr_functions */ +IMPLEMENT_generic_cipher(camellia, CAMELLIA, ctr, CTR, 0, 128, 8, 128, stream) + +#include "cipher_camellia_cts.inc" diff --git a/providers/implementations/ciphers/cipher_camellia.h b/providers/implementations/ciphers/cipher_camellia.h new file mode 100644 index 000000000000..953ea74c0b5d --- /dev/null +++ b/providers/implementations/ciphers/cipher_camellia.h @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/camellia.h> +#include "prov/ciphercommon.h" +#include "crypto/cmll_platform.h" + +typedef struct prov_camellia_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + CAMELLIA_KEY ks; + } ks; +} PROV_CAMELLIA_CTX; + +#define ossl_prov_cipher_hw_camellia_ofb ossl_prov_cipher_hw_camellia_ofb128 +#define ossl_prov_cipher_hw_camellia_cfb ossl_prov_cipher_hw_camellia_cfb128 +const PROV_CIPHER_HW *ossl_prov_cipher_hw_camellia_ecb(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_camellia_cbc(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_camellia_ofb128(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_camellia_cfb128(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_camellia_cfb1(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_camellia_cfb8(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_camellia_ctr(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_camellia_cts.inc b/providers/implementations/ciphers/cipher_camellia_cts.inc new file mode 100644 index 000000000000..84ea992b8da9 --- /dev/null +++ b/providers/implementations/ciphers/cipher_camellia_cts.inc @@ -0,0 +1,94 @@ +/* + * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for CAMELLIA CBC CTS ciphers */ + +#include <openssl/proverr.h> +#include "cipher_cts.h" + +#define CTS_FLAGS PROV_CIPHER_FLAG_CTS + +static OSSL_FUNC_cipher_encrypt_init_fn camellia_cbc_cts_einit; +static OSSL_FUNC_cipher_decrypt_init_fn camellia_cbc_cts_dinit; +static OSSL_FUNC_cipher_get_ctx_params_fn camellia_cbc_cts_get_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn camellia_cbc_cts_set_ctx_params; +static OSSL_FUNC_cipher_gettable_ctx_params_fn camellia_cbc_cts_gettable_ctx_params; +static OSSL_FUNC_cipher_settable_ctx_params_fn camellia_cbc_cts_settable_ctx_params; + +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(camellia_cbc_cts) +OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, NULL, 0), +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(camellia_cbc_cts) + +static int camellia_cbc_cts_einit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_einit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return camellia_cbc_cts_set_ctx_params(ctx, params); +} + +static int camellia_cbc_cts_dinit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_dinit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return camellia_cbc_cts_set_ctx_params(ctx, params); +} + +static int camellia_cbc_cts_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_CTS_MODE); + if (p != NULL) { + const char *name = ossl_cipher_cbc_cts_mode_id2name(ctx->cts_mode); + + if (name == NULL || !OSSL_PARAM_set_utf8_string(p, name)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + return ossl_cipher_generic_get_ctx_params(vctx, params); +} + +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(camellia_cbc_cts) +OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, NULL, 0), +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(camellia_cbc_cts) + +static int camellia_cbc_cts_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + const OSSL_PARAM *p; + int id; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_CTS_MODE); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + goto err; + id = ossl_cipher_cbc_cts_mode_name2id(p->data); + if (id < 0) + goto err; + + ctx->cts_mode = (unsigned int)id; + } + return ossl_cipher_generic_set_ctx_params(vctx, params); +err: + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; +} + +/* ossl_camellia256cbc_cts_functions */ +IMPLEMENT_cts_cipher(camellia, CAMELLIA, cbc, CBC, CTS_FLAGS, 256, 128, 128, block) +/* ossl_camellia192cbc_cts_functions */ +IMPLEMENT_cts_cipher(camellia, CAMELLIA, cbc, CBC, CTS_FLAGS, 192, 128, 128, block) +/* ossl_camellia128cbc_cts_functions */ +IMPLEMENT_cts_cipher(camellia, CAMELLIA, cbc, CBC, CTS_FLAGS, 128, 128, 128, block) diff --git a/providers/implementations/ciphers/cipher_camellia_hw.c b/providers/implementations/ciphers/cipher_camellia_hw.c new file mode 100644 index 000000000000..3ebf5b8d4612 --- /dev/null +++ b/providers/implementations/ciphers/cipher_camellia_hw.c @@ -0,0 +1,74 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Camellia low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/camellia.h> +#include <openssl/proverr.h> +#include "cipher_camellia.h" + +static int cipher_hw_camellia_initkey(PROV_CIPHER_CTX *dat, + const unsigned char *key, size_t keylen) +{ + int ret, mode = dat->mode; + PROV_CAMELLIA_CTX *adat = (PROV_CAMELLIA_CTX *)dat; + CAMELLIA_KEY *ks = &adat->ks.ks; + + dat->ks = ks; + ret = Camellia_set_key(key, keylen * 8, ks); + if (ret < 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SETUP_FAILED); + return 0; + } + if (dat->enc || (mode != EVP_CIPH_ECB_MODE && mode != EVP_CIPH_CBC_MODE)) { + dat->block = (block128_f) Camellia_encrypt; + dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ? + (cbc128_f) Camellia_cbc_encrypt : NULL; + } else { + dat->block = (block128_f) Camellia_decrypt; + dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ? + (cbc128_f) Camellia_cbc_encrypt : NULL; + } + return 1; +} + +IMPLEMENT_CIPHER_HW_COPYCTX(cipher_hw_camellia_copyctx, PROV_CAMELLIA_CTX) + +# if defined(SPARC_CMLL_CAPABLE) +# include "cipher_camellia_hw_t4.inc" +# else +/* The generic case */ +# define PROV_CIPHER_HW_declare(mode) +# define PROV_CIPHER_HW_select(mode) +# endif /* SPARC_CMLL_CAPABLE */ + +#define PROV_CIPHER_HW_camellia_mode(mode) \ +static const PROV_CIPHER_HW camellia_##mode = { \ + cipher_hw_camellia_initkey, \ + ossl_cipher_hw_generic_##mode, \ + cipher_hw_camellia_copyctx \ +}; \ +PROV_CIPHER_HW_declare(mode) \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_camellia_##mode(size_t keybits) \ +{ \ + PROV_CIPHER_HW_select(mode) \ + return &camellia_##mode; \ +} + +PROV_CIPHER_HW_camellia_mode(cbc) +PROV_CIPHER_HW_camellia_mode(ecb) +PROV_CIPHER_HW_camellia_mode(ofb128) +PROV_CIPHER_HW_camellia_mode(cfb128) +PROV_CIPHER_HW_camellia_mode(cfb1) +PROV_CIPHER_HW_camellia_mode(cfb8) +PROV_CIPHER_HW_camellia_mode(ctr) diff --git a/providers/implementations/ciphers/cipher_camellia_hw_t4.inc b/providers/implementations/ciphers/cipher_camellia_hw_t4.inc new file mode 100644 index 000000000000..2dcf3fa18eb5 --- /dev/null +++ b/providers/implementations/ciphers/cipher_camellia_hw_t4.inc @@ -0,0 +1,84 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/*- + * Fujitsu SPARC64 X support for camellia modes. + * This file is included by cipher_camellia_hw.c + */ + +static int cipher_hw_camellia_t4_initkey(PROV_CIPHER_CTX *dat, + const unsigned char *key, + size_t keylen) +{ + int ret = 0, bits, mode = dat->mode; + PROV_CAMELLIA_CTX *adat = (PROV_CAMELLIA_CTX *)dat; + CAMELLIA_KEY *ks = &adat->ks.ks; + + dat->ks = ks; + bits = keylen * 8; + + cmll_t4_set_key(key, bits, ks); + + if (dat->enc || (mode != EVP_CIPH_ECB_MODE && mode != EVP_CIPH_CBC_MODE)) { + dat->block = (block128_f) cmll_t4_encrypt; + switch (bits) { + case 128: + if (mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f) cmll128_t4_cbc_encrypt; + else if (mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f) cmll128_t4_ctr32_encrypt; + else + dat->stream.cbc = NULL; + break; + case 192: + case 256: + if (mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f) cmll256_t4_cbc_encrypt; + else if (mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f) cmll256_t4_ctr32_encrypt; + else + dat->stream.cbc = NULL; + break; + default: + ret = -1; + break; + } + } else { + dat->block = (block128_f) cmll_t4_decrypt; + switch (bits) { + case 128: + dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ? + (cbc128_f) cmll128_t4_cbc_decrypt : NULL; + break; + case 192: + case 256: + dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ? + (cbc128_f) cmll256_t4_cbc_decrypt : NULL; + break; + default: + ret = -1; + break; + } + } + if (ret < 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SETUP_FAILED); + return 0; + } + return 1; +} + +#define PROV_CIPHER_HW_declare(mode) \ +static const PROV_CIPHER_HW t4_camellia_##mode = { \ + cipher_hw_camellia_t4_initkey, \ + ossl_cipher_hw_generic_##mode, \ + cipher_hw_camellia_copyctx \ +}; +#define PROV_CIPHER_HW_select(mode) \ +if (SPARC_CMLL_CAPABLE) \ + return &t4_camellia_##mode; diff --git a/providers/implementations/ciphers/cipher_cast.h b/providers/implementations/ciphers/cipher_cast.h new file mode 100644 index 000000000000..84b58621c1bc --- /dev/null +++ b/providers/implementations/ciphers/cipher_cast.h @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/cast.h> +#include "prov/ciphercommon.h" + +typedef struct prov_cast_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + CAST_KEY ks; + } ks; +} PROV_CAST_CTX; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_cast5_cbc(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_cast5_ecb(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_cast5_ofb64(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_cast5_cfb64(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_cast5.c b/providers/implementations/ciphers/cipher_cast5.c new file mode 100644 index 000000000000..55081ccbe958 --- /dev/null +++ b/providers/implementations/ciphers/cipher_cast5.c @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * CAST low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +/* Dispatch functions for cast cipher modes ecb, cbc, ofb, cfb */ + +#include <openssl/proverr.h> +#include "cipher_cast.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define CAST5_FLAGS PROV_CIPHER_FLAG_VARIABLE_LENGTH + +static OSSL_FUNC_cipher_freectx_fn cast5_freectx; +static OSSL_FUNC_cipher_dupctx_fn cast5_dupctx; + +static void cast5_freectx(void *vctx) +{ + PROV_CAST_CTX *ctx = (PROV_CAST_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *cast5_dupctx(void *ctx) +{ + PROV_CAST_CTX *in = (PROV_CAST_CTX *)ctx; + PROV_CAST_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + *ret = *in; + + return ret; +} + +/* ossl_cast5128ecb_functions */ +IMPLEMENT_var_keylen_cipher(cast5, CAST, ecb, ECB, CAST5_FLAGS, 128, 64, 0, block) +/* ossl_cast5128cbc_functions */ +IMPLEMENT_var_keylen_cipher(cast5, CAST, cbc, CBC, CAST5_FLAGS, 128, 64, 64, block) +/* ossl_cast5128ofb64_functions */ +IMPLEMENT_var_keylen_cipher(cast5, CAST, ofb64, OFB, CAST5_FLAGS, 128, 8, 64, stream) +/* ossl_cast5128cfb64_functions */ +IMPLEMENT_var_keylen_cipher(cast5, CAST, cfb64, CFB, CAST5_FLAGS, 128, 8, 64, stream) diff --git a/providers/implementations/ciphers/cipher_cast5_hw.c b/providers/implementations/ciphers/cipher_cast5_hw.c new file mode 100644 index 000000000000..73f0628e578b --- /dev/null +++ b/providers/implementations/ciphers/cipher_cast5_hw.c @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * CAST low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include "cipher_cast.h" + +static int cipher_hw_cast5_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_CAST_CTX *bctx = (PROV_CAST_CTX *)ctx; + + CAST_set_key(&(bctx->ks.ks), keylen, key); + return 1; +} + +# define PROV_CIPHER_HW_cast_mode(mode, UCMODE) \ +IMPLEMENT_CIPHER_HW_##UCMODE(mode, cast5, PROV_CAST_CTX, CAST_KEY, \ + CAST_##mode) \ +static const PROV_CIPHER_HW cast5_##mode = { \ + cipher_hw_cast5_initkey, \ + cipher_hw_cast5_##mode##_cipher \ +}; \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_cast5_##mode(size_t keybits) \ +{ \ + return &cast5_##mode; \ +} + +PROV_CIPHER_HW_cast_mode(cbc, CBC) +PROV_CIPHER_HW_cast_mode(ecb, ECB) +PROV_CIPHER_HW_cast_mode(ofb64, OFB) +PROV_CIPHER_HW_cast_mode(cfb64, CFB) diff --git a/providers/implementations/ciphers/cipher_chacha20.c b/providers/implementations/ciphers/cipher_chacha20.c new file mode 100644 index 000000000000..386c865d832e --- /dev/null +++ b/providers/implementations/ciphers/cipher_chacha20.c @@ -0,0 +1,205 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for chacha20 cipher */ + +#include <openssl/proverr.h> +#include "cipher_chacha20.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define CHACHA20_KEYLEN (CHACHA_KEY_SIZE) +#define CHACHA20_BLKLEN (1) +#define CHACHA20_IVLEN (CHACHA_CTR_SIZE) +#define CHACHA20_FLAGS (PROV_CIPHER_FLAG_CUSTOM_IV) + +static OSSL_FUNC_cipher_newctx_fn chacha20_newctx; +static OSSL_FUNC_cipher_freectx_fn chacha20_freectx; +static OSSL_FUNC_cipher_get_params_fn chacha20_get_params; +static OSSL_FUNC_cipher_get_ctx_params_fn chacha20_get_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn chacha20_set_ctx_params; +static OSSL_FUNC_cipher_gettable_ctx_params_fn chacha20_gettable_ctx_params; +static OSSL_FUNC_cipher_settable_ctx_params_fn chacha20_settable_ctx_params; +#define chacha20_cipher ossl_cipher_generic_cipher +#define chacha20_update ossl_cipher_generic_stream_update +#define chacha20_final ossl_cipher_generic_stream_final +#define chacha20_gettable_params ossl_cipher_generic_gettable_params + +void ossl_chacha20_initctx(PROV_CHACHA20_CTX *ctx) +{ + ossl_cipher_generic_initkey(ctx, CHACHA20_KEYLEN * 8, + CHACHA20_BLKLEN * 8, + CHACHA20_IVLEN * 8, + 0, CHACHA20_FLAGS, + ossl_prov_cipher_hw_chacha20(CHACHA20_KEYLEN * 8), + NULL); +} + +static void *chacha20_newctx(void *provctx) +{ + PROV_CHACHA20_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + ossl_chacha20_initctx(ctx); + return ctx; +} + +static void chacha20_freectx(void *vctx) +{ + PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)vctx; + + if (ctx != NULL) { + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); + } +} + +static int chacha20_get_params(OSSL_PARAM params[]) +{ + return ossl_cipher_generic_get_params(params, 0, CHACHA20_FLAGS, + CHACHA20_KEYLEN * 8, + CHACHA20_BLKLEN * 8, + CHACHA20_IVLEN * 8); +} + +static int chacha20_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, CHACHA20_IVLEN)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, CHACHA20_KEYLEN)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + + return 1; +} + +static const OSSL_PARAM chacha20_known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_END +}; +const OSSL_PARAM *chacha20_gettable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return chacha20_known_gettable_ctx_params; +} + +static int chacha20_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + size_t len; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (len != CHACHA20_KEYLEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (len != CHACHA20_IVLEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + } + return 1; +} + +static const OSSL_PARAM chacha20_known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_END +}; +const OSSL_PARAM *chacha20_settable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return chacha20_known_settable_ctx_params; +} + +int ossl_chacha20_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + int ret; + + /* The generic function checks for ossl_prov_is_running() */ + ret = ossl_cipher_generic_einit(vctx, key, keylen, iv, ivlen, NULL); + if (ret && iv != NULL) { + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CIPHER_HW_CHACHA20 *hw = (PROV_CIPHER_HW_CHACHA20 *)ctx->hw; + + hw->initiv(ctx); + } + if (ret && !chacha20_set_ctx_params(vctx, params)) + ret = 0; + return ret; +} + +int ossl_chacha20_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + int ret; + + /* The generic function checks for ossl_prov_is_running() */ + ret = ossl_cipher_generic_dinit(vctx, key, keylen, iv, ivlen, NULL); + if (ret && iv != NULL) { + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CIPHER_HW_CHACHA20 *hw = (PROV_CIPHER_HW_CHACHA20 *)ctx->hw; + + hw->initiv(ctx); + } + if (ret && !chacha20_set_ctx_params(vctx, params)) + ret = 0; + return ret; +} + +/* ossl_chacha20_functions */ +const OSSL_DISPATCH ossl_chacha20_functions[] = { + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))chacha20_newctx }, + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))chacha20_freectx }, + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))ossl_chacha20_einit }, + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))ossl_chacha20_dinit }, + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))chacha20_update }, + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))chacha20_final }, + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))chacha20_cipher}, + { OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))chacha20_get_params }, + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS,(void (*)(void))chacha20_gettable_params }, + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (void (*)(void))chacha20_get_ctx_params }, + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, + (void (*)(void))chacha20_gettable_ctx_params }, + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, (void (*)(void))chacha20_set_ctx_params }, + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, + (void (*)(void))chacha20_settable_ctx_params }, + { 0, NULL } +}; + diff --git a/providers/implementations/ciphers/cipher_chacha20.h b/providers/implementations/ciphers/cipher_chacha20.h new file mode 100644 index 000000000000..9db8ed9cb424 --- /dev/null +++ b/providers/implementations/ciphers/cipher_chacha20.h @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "include/crypto/chacha.h" +#include "prov/ciphercommon.h" + +typedef struct { + PROV_CIPHER_CTX base; /* must be first */ + union { + OSSL_UNION_ALIGN; + unsigned int d[CHACHA_KEY_SIZE / 4]; + } key; + unsigned int counter[CHACHA_CTR_SIZE / 4]; + unsigned char buf[CHACHA_BLK_SIZE]; + unsigned int partial_len; +} PROV_CHACHA20_CTX; + +typedef struct prov_cipher_hw_chacha20_st { + PROV_CIPHER_HW base; /* must be first */ + int (*initiv)(PROV_CIPHER_CTX *ctx); + +} PROV_CIPHER_HW_CHACHA20; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_chacha20(size_t keybits); + +OSSL_FUNC_cipher_encrypt_init_fn ossl_chacha20_einit; +OSSL_FUNC_cipher_decrypt_init_fn ossl_chacha20_dinit; +void ossl_chacha20_initctx(PROV_CHACHA20_CTX *ctx); diff --git a/providers/implementations/ciphers/cipher_chacha20_hw.c b/providers/implementations/ciphers/cipher_chacha20_hw.c new file mode 100644 index 000000000000..3b03bc81ed5a --- /dev/null +++ b/providers/implementations/ciphers/cipher_chacha20_hw.c @@ -0,0 +1,122 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* chacha20 cipher implementation */ + +#include "cipher_chacha20.h" + +static int chacha20_initkey(PROV_CIPHER_CTX *bctx, const uint8_t *key, + size_t keylen) +{ + PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)bctx; + unsigned int i; + + if (key != NULL) { + for (i = 0; i < CHACHA_KEY_SIZE; i += 4) + ctx->key.d[i / 4] = CHACHA_U8TOU32(key + i); + } + ctx->partial_len = 0; + return 1; +} + +static int chacha20_initiv(PROV_CIPHER_CTX *bctx) +{ + PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)bctx; + unsigned int i; + + if (bctx->iv_set) { + for (i = 0; i < CHACHA_CTR_SIZE; i += 4) + ctx->counter[i / 4] = CHACHA_U8TOU32(bctx->oiv + i); + } + ctx->partial_len = 0; + return 1; +} + +static int chacha20_cipher(PROV_CIPHER_CTX *bctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)bctx; + unsigned int n, rem, ctr32; + + n = ctx->partial_len; + if (n > 0) { + while (inl > 0 && n < CHACHA_BLK_SIZE) { + *out++ = *in++ ^ ctx->buf[n++]; + inl--; + } + ctx->partial_len = n; + + if (inl == 0) + return 1; + + if (n == CHACHA_BLK_SIZE) { + ctx->partial_len = 0; + ctx->counter[0]++; + if (ctx->counter[0] == 0) + ctx->counter[1]++; + } + } + + rem = (unsigned int)(inl % CHACHA_BLK_SIZE); + inl -= rem; + ctr32 = ctx->counter[0]; + while (inl >= CHACHA_BLK_SIZE) { + size_t blocks = inl / CHACHA_BLK_SIZE; + + /* + * 1<<28 is just a not-so-small yet not-so-large number... + * Below condition is practically never met, but it has to + * be checked for code correctness. + */ + if (sizeof(size_t) > sizeof(unsigned int) && blocks > (1U << 28)) + blocks = (1U << 28); + + /* + * As ChaCha20_ctr32 operates on 32-bit counter, caller + * has to handle overflow. 'if' below detects the + * overflow, which is then handled by limiting the + * amount of blocks to the exact overflow point... + */ + ctr32 += (unsigned int)blocks; + if (ctr32 < blocks) { + blocks -= ctr32; + ctr32 = 0; + } + blocks *= CHACHA_BLK_SIZE; + ChaCha20_ctr32(out, in, blocks, ctx->key.d, ctx->counter); + inl -= blocks; + in += blocks; + out += blocks; + + ctx->counter[0] = ctr32; + if (ctr32 == 0) ctx->counter[1]++; + } + + if (rem > 0) { + memset(ctx->buf, 0, sizeof(ctx->buf)); + ChaCha20_ctr32(ctx->buf, ctx->buf, CHACHA_BLK_SIZE, + ctx->key.d, ctx->counter); + for (n = 0; n < rem; n++) + out[n] = in[n] ^ ctx->buf[n]; + ctx->partial_len = rem; + } + + return 1; +} + +static const PROV_CIPHER_HW_CHACHA20 chacha20_hw = { + { chacha20_initkey, chacha20_cipher }, + chacha20_initiv +}; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_chacha20(size_t keybits) +{ + return (PROV_CIPHER_HW *)&chacha20_hw; +} + diff --git a/providers/implementations/ciphers/cipher_chacha20_poly1305.c b/providers/implementations/ciphers/cipher_chacha20_poly1305.c new file mode 100644 index 000000000000..abe670add7a8 --- /dev/null +++ b/providers/implementations/ciphers/cipher_chacha20_poly1305.c @@ -0,0 +1,332 @@ +/* + * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for chacha20_poly1305 cipher */ + +#include <openssl/proverr.h> +#include "cipher_chacha20_poly1305.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define CHACHA20_POLY1305_KEYLEN CHACHA_KEY_SIZE +#define CHACHA20_POLY1305_BLKLEN 1 +#define CHACHA20_POLY1305_MAX_IVLEN 12 +#define CHACHA20_POLY1305_MODE 0 +#define CHACHA20_POLY1305_FLAGS (PROV_CIPHER_FLAG_AEAD \ + | PROV_CIPHER_FLAG_CUSTOM_IV) + +static OSSL_FUNC_cipher_newctx_fn chacha20_poly1305_newctx; +static OSSL_FUNC_cipher_freectx_fn chacha20_poly1305_freectx; +static OSSL_FUNC_cipher_encrypt_init_fn chacha20_poly1305_einit; +static OSSL_FUNC_cipher_decrypt_init_fn chacha20_poly1305_dinit; +static OSSL_FUNC_cipher_get_params_fn chacha20_poly1305_get_params; +static OSSL_FUNC_cipher_get_ctx_params_fn chacha20_poly1305_get_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn chacha20_poly1305_set_ctx_params; +static OSSL_FUNC_cipher_cipher_fn chacha20_poly1305_cipher; +static OSSL_FUNC_cipher_final_fn chacha20_poly1305_final; +static OSSL_FUNC_cipher_gettable_ctx_params_fn chacha20_poly1305_gettable_ctx_params; +#define chacha20_poly1305_settable_ctx_params ossl_cipher_aead_settable_ctx_params +#define chacha20_poly1305_gettable_params ossl_cipher_generic_gettable_params +#define chacha20_poly1305_update chacha20_poly1305_cipher + +static void *chacha20_poly1305_newctx(void *provctx) +{ + PROV_CHACHA20_POLY1305_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) { + ossl_cipher_generic_initkey(&ctx->base, CHACHA20_POLY1305_KEYLEN * 8, + CHACHA20_POLY1305_BLKLEN * 8, + CHACHA20_POLY1305_IVLEN * 8, + CHACHA20_POLY1305_MODE, + CHACHA20_POLY1305_FLAGS, + ossl_prov_cipher_hw_chacha20_poly1305( + CHACHA20_POLY1305_KEYLEN * 8), + NULL); + ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH; + ossl_chacha20_initctx(&ctx->chacha); + } + return ctx; +} + +static void chacha20_poly1305_freectx(void *vctx) +{ + PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx; + + if (ctx != NULL) { + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); + } +} + +static int chacha20_poly1305_get_params(OSSL_PARAM params[]) +{ + return ossl_cipher_generic_get_params(params, 0, CHACHA20_POLY1305_FLAGS, + CHACHA20_POLY1305_KEYLEN * 8, + CHACHA20_POLY1305_BLKLEN * 8, + CHACHA20_POLY1305_IVLEN * 8); +} + +static int chacha20_poly1305_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL) { + if (!OSSL_PARAM_set_size_t(p, CHACHA20_POLY1305_IVLEN)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, CHACHA20_POLY1305_KEYLEN)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tag_len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + if (!ctx->base.enc) { + ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_SET); + return 0; + } + if (p->data_size == 0 || p->data_size > POLY1305_BLOCK_SIZE) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH); + return 0; + } + memcpy(p->data, ctx->tag, p->data_size); + } + + return 1; +} + +static const OSSL_PARAM chacha20_poly1305_known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL), + OSSL_PARAM_END +}; +static const OSSL_PARAM *chacha20_poly1305_gettable_ctx_params + (ossl_unused void *cctx, ossl_unused void *provctx) +{ + return chacha20_poly1305_known_gettable_ctx_params; +} + +static int chacha20_poly1305_set_ctx_params(void *vctx, + const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + size_t len; + PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx; + PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = + (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->base.hw; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (len != CHACHA20_POLY1305_KEYLEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (len != CHACHA20_POLY1305_MAX_IVLEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (p->data_size == 0 || p->data_size > POLY1305_BLOCK_SIZE) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH); + return 0; + } + if (p->data != NULL) { + if (ctx->base.enc) { + ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED); + return 0; + } + memcpy(ctx->tag, p->data, p->data_size); + } + ctx->tag_len = p->data_size; + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + len = hw->tls_init(&ctx->base, p->data, p->data_size); + if (len == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA); + return 0; + } + ctx->tls_aad_pad_sz = len; + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (hw->tls_iv_set_fixed(&ctx->base, p->data, p->data_size) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + } + /* ignore OSSL_CIPHER_PARAM_AEAD_MAC_KEY */ + return 1; +} + +static int chacha20_poly1305_einit(void *vctx, const unsigned char *key, + size_t keylen, const unsigned char *iv, + size_t ivlen, const OSSL_PARAM params[]) +{ + int ret; + + /* The generic function checks for ossl_prov_is_running() */ + ret = ossl_cipher_generic_einit(vctx, key, keylen, iv, ivlen, NULL); + if (ret && iv != NULL) { + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = + (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; + + hw->initiv(ctx); + } + if (ret && !chacha20_poly1305_set_ctx_params(vctx, params)) + ret = 0; + return ret; +} + +static int chacha20_poly1305_dinit(void *vctx, const unsigned char *key, + size_t keylen, const unsigned char *iv, + size_t ivlen, const OSSL_PARAM params[]) +{ + int ret; + + /* The generic function checks for ossl_prov_is_running() */ + ret = ossl_cipher_generic_dinit(vctx, key, keylen, iv, ivlen, NULL); + if (ret && iv != NULL) { + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = + (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; + + hw->initiv(ctx); + } + if (ret && !chacha20_poly1305_set_ctx_params(vctx, params)) + ret = 0; + return ret; +} + +static int chacha20_poly1305_cipher(void *vctx, unsigned char *out, + size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = + (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; + + if (!ossl_prov_is_running()) + return 0; + + if (inl == 0) { + *outl = 0; + return 1; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!hw->aead_cipher(ctx, out, outl, in, inl)) + return 0; + + return 1; +} + +static int chacha20_poly1305_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = + (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; + + if (!ossl_prov_is_running()) + return 0; + + if (hw->aead_cipher(ctx, out, outl, NULL, 0) <= 0) + return 0; + + *outl = 0; + return 1; +} + +/* ossl_chacha20_ossl_poly1305_functions */ +const OSSL_DISPATCH ossl_chacha20_ossl_poly1305_functions[] = { + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))chacha20_poly1305_newctx }, + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))chacha20_poly1305_freectx }, + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))chacha20_poly1305_einit }, + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))chacha20_poly1305_dinit }, + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))chacha20_poly1305_update }, + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))chacha20_poly1305_final }, + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))chacha20_poly1305_cipher }, + { OSSL_FUNC_CIPHER_GET_PARAMS, + (void (*)(void))chacha20_poly1305_get_params }, + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, + (void (*)(void))chacha20_poly1305_gettable_params }, + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, + (void (*)(void))chacha20_poly1305_get_ctx_params }, + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, + (void (*)(void))chacha20_poly1305_gettable_ctx_params }, + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, + (void (*)(void))chacha20_poly1305_set_ctx_params }, + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, + (void (*)(void))chacha20_poly1305_settable_ctx_params }, + { 0, NULL } +}; + diff --git a/providers/implementations/ciphers/cipher_chacha20_poly1305.h b/providers/implementations/ciphers/cipher_chacha20_poly1305.h new file mode 100644 index 000000000000..f2ea26a77f3a --- /dev/null +++ b/providers/implementations/ciphers/cipher_chacha20_poly1305.h @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for chacha20_poly1305 cipher */ + +#include "include/crypto/poly1305.h" +#include "cipher_chacha20.h" + +#define NO_TLS_PAYLOAD_LENGTH ((size_t)-1) +#define CHACHA20_POLY1305_IVLEN 12 + +typedef struct { + PROV_CIPHER_CTX base; /* must be first */ + PROV_CHACHA20_CTX chacha; + POLY1305 poly1305; + unsigned int nonce[12 / 4]; + unsigned char tag[POLY1305_BLOCK_SIZE]; + unsigned char tls_aad[POLY1305_BLOCK_SIZE]; + struct { uint64_t aad, text; } len; + unsigned int aad : 1; + unsigned int mac_inited : 1; + size_t tag_len; + size_t tls_payload_length; + size_t tls_aad_pad_sz; +} PROV_CHACHA20_POLY1305_CTX; + +typedef struct prov_cipher_hw_chacha_aead_st { + PROV_CIPHER_HW base; /* must be first */ + int (*aead_cipher)(PROV_CIPHER_CTX *dat, unsigned char *out, size_t *outl, + const unsigned char *in, size_t len); + int (*initiv)(PROV_CIPHER_CTX *ctx); + int (*tls_init)(PROV_CIPHER_CTX *ctx, unsigned char *aad, size_t alen); + int (*tls_iv_set_fixed)(PROV_CIPHER_CTX *ctx, unsigned char *fixed, + size_t flen); +} PROV_CIPHER_HW_CHACHA20_POLY1305; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_chacha20_poly1305(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c b/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c new file mode 100644 index 000000000000..8173663e5e7e --- /dev/null +++ b/providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c @@ -0,0 +1,413 @@ +/* + * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* chacha20_poly1305 cipher implementation */ + +#include "internal/endian.h" +#include "cipher_chacha20_poly1305.h" + +static int chacha_poly1305_tls_init(PROV_CIPHER_CTX *bctx, + unsigned char *aad, size_t alen) +{ + unsigned int len; + PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx; + + if (alen != EVP_AEAD_TLS1_AAD_LEN) + return 0; + + memcpy(ctx->tls_aad, aad, EVP_AEAD_TLS1_AAD_LEN); + len = aad[EVP_AEAD_TLS1_AAD_LEN - 2] << 8 | aad[EVP_AEAD_TLS1_AAD_LEN - 1]; + aad = ctx->tls_aad; + if (!bctx->enc) { + if (len < POLY1305_BLOCK_SIZE) + return 0; + len -= POLY1305_BLOCK_SIZE; /* discount attached tag */ + aad[EVP_AEAD_TLS1_AAD_LEN - 2] = (unsigned char)(len >> 8); + aad[EVP_AEAD_TLS1_AAD_LEN - 1] = (unsigned char)len; + } + ctx->tls_payload_length = len; + + /* merge record sequence number as per RFC7905 */ + ctx->chacha.counter[1] = ctx->nonce[0]; + ctx->chacha.counter[2] = ctx->nonce[1] ^ CHACHA_U8TOU32(aad); + ctx->chacha.counter[3] = ctx->nonce[2] ^ CHACHA_U8TOU32(aad+4); + ctx->mac_inited = 0; + + return POLY1305_BLOCK_SIZE; /* tag length */ +} + +static int chacha_poly1305_tls_iv_set_fixed(PROV_CIPHER_CTX *bctx, + unsigned char *fixed, size_t flen) +{ + PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx; + + if (flen != CHACHA20_POLY1305_IVLEN) + return 0; + ctx->nonce[0] = ctx->chacha.counter[1] = CHACHA_U8TOU32(fixed); + ctx->nonce[1] = ctx->chacha.counter[2] = CHACHA_U8TOU32(fixed + 4); + ctx->nonce[2] = ctx->chacha.counter[3] = CHACHA_U8TOU32(fixed + 8); + return 1; +} + +static int chacha20_poly1305_initkey(PROV_CIPHER_CTX *bctx, + const unsigned char *key, size_t keylen) +{ + PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx; + + ctx->len.aad = 0; + ctx->len.text = 0; + ctx->aad = 0; + ctx->mac_inited = 0; + ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH; + + if (bctx->enc) + return ossl_chacha20_einit(&ctx->chacha, key, keylen, NULL, 0, NULL); + else + return ossl_chacha20_dinit(&ctx->chacha, key, keylen, NULL, 0, NULL); +} + +static int chacha20_poly1305_initiv(PROV_CIPHER_CTX *bctx) +{ + PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx; + unsigned char tempiv[CHACHA_CTR_SIZE] = { 0 }; + int ret = 1; + size_t noncelen = CHACHA20_POLY1305_IVLEN; + + ctx->len.aad = 0; + ctx->len.text = 0; + ctx->aad = 0; + ctx->mac_inited = 0; + ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH; + + /* pad on the left */ + memcpy(tempiv + CHACHA_CTR_SIZE - noncelen, bctx->oiv, + noncelen); + + if (bctx->enc) + ret = ossl_chacha20_einit(&ctx->chacha, NULL, 0, + tempiv, sizeof(tempiv), NULL); + else + ret = ossl_chacha20_dinit(&ctx->chacha, NULL, 0, + tempiv, sizeof(tempiv), NULL); + ctx->nonce[0] = ctx->chacha.counter[1]; + ctx->nonce[1] = ctx->chacha.counter[2]; + ctx->nonce[2] = ctx->chacha.counter[3]; + bctx->iv_set = 1; + return ret; +} + +#if !defined(OPENSSL_SMALL_FOOTPRINT) + +# if defined(POLY1305_ASM) && (defined(__x86_64) || defined(__x86_64__) \ + || defined(_M_AMD64) || defined(_M_X64)) +# define XOR128_HELPERS +void *xor128_encrypt_n_pad(void *out, const void *inp, void *otp, size_t len); +void *xor128_decrypt_n_pad(void *out, const void *inp, void *otp, size_t len); +static const unsigned char zero[4 * CHACHA_BLK_SIZE] = { 0 }; +# else +static const unsigned char zero[2 * CHACHA_BLK_SIZE] = { 0 }; +# endif + +static int chacha20_poly1305_tls_cipher(PROV_CIPHER_CTX *bctx, + unsigned char *out, + size_t *out_padlen, + const unsigned char *in, size_t len) +{ + PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx; + POLY1305 *poly = &ctx->poly1305; + size_t tail, tohash_len, buf_len, plen = ctx->tls_payload_length; + unsigned char *buf, *tohash, *ctr, storage[sizeof(zero) + 32]; + + DECLARE_IS_ENDIAN; + + buf = storage + ((0 - (size_t)storage) & 15); /* align */ + ctr = buf + CHACHA_BLK_SIZE; + tohash = buf + CHACHA_BLK_SIZE - POLY1305_BLOCK_SIZE; + +# ifdef XOR128_HELPERS + if (plen <= 3 * CHACHA_BLK_SIZE) { + ctx->chacha.counter[0] = 0; + buf_len = (plen + 2 * CHACHA_BLK_SIZE - 1) & (0 - CHACHA_BLK_SIZE); + ChaCha20_ctr32(buf, zero, buf_len, ctx->chacha.key.d, ctx->chacha.counter); + Poly1305_Init(poly, buf); + ctx->chacha.partial_len = 0; + memcpy(tohash, ctx->tls_aad, POLY1305_BLOCK_SIZE); + tohash_len = POLY1305_BLOCK_SIZE; + ctx->len.aad = EVP_AEAD_TLS1_AAD_LEN; + ctx->len.text = plen; + + if (plen) { + if (bctx->enc) + ctr = xor128_encrypt_n_pad(out, in, ctr, plen); + else + ctr = xor128_decrypt_n_pad(out, in, ctr, plen); + + in += plen; + out += plen; + tohash_len = (size_t)(ctr - tohash); + } + } +# else + if (plen <= CHACHA_BLK_SIZE) { + size_t i; + + ctx->chacha.counter[0] = 0; + ChaCha20_ctr32(buf, zero, (buf_len = 2 * CHACHA_BLK_SIZE), + ctx->chacha.key.d, ctx->chacha.counter); + Poly1305_Init(poly, buf); + ctx->chacha.partial_len = 0; + memcpy(tohash, ctx->tls_aad, POLY1305_BLOCK_SIZE); + tohash_len = POLY1305_BLOCK_SIZE; + ctx->len.aad = EVP_AEAD_TLS1_AAD_LEN; + ctx->len.text = plen; + + if (bctx->enc) { + for (i = 0; i < plen; i++) + out[i] = ctr[i] ^= in[i]; + } else { + for (i = 0; i < plen; i++) { + unsigned char c = in[i]; + + out[i] = ctr[i] ^ c; + ctr[i] = c; + } + } + + in += i; + out += i; + + tail = (0 - i) & (POLY1305_BLOCK_SIZE - 1); + memset(ctr + i, 0, tail); + ctr += i + tail; + tohash_len += i + tail; + } +# endif + else { + ctx->chacha.counter[0] = 0; + ChaCha20_ctr32(buf, zero, (buf_len = CHACHA_BLK_SIZE), + ctx->chacha.key.d, ctx->chacha.counter); + Poly1305_Init(poly, buf); + ctx->chacha.counter[0] = 1; + ctx->chacha.partial_len = 0; + Poly1305_Update(poly, ctx->tls_aad, POLY1305_BLOCK_SIZE); + tohash = ctr; + tohash_len = 0; + ctx->len.aad = EVP_AEAD_TLS1_AAD_LEN; + ctx->len.text = plen; + + if (bctx->enc) { + ChaCha20_ctr32(out, in, plen, ctx->chacha.key.d, ctx->chacha.counter); + Poly1305_Update(poly, out, plen); + } else { + Poly1305_Update(poly, in, plen); + ChaCha20_ctr32(out, in, plen, ctx->chacha.key.d, ctx->chacha.counter); + } + + in += plen; + out += plen; + tail = (0 - plen) & (POLY1305_BLOCK_SIZE - 1); + Poly1305_Update(poly, zero, tail); + } + + if (IS_LITTLE_ENDIAN) { + memcpy(ctr, (unsigned char *)&ctx->len, POLY1305_BLOCK_SIZE); + } else { + ctr[0] = (unsigned char)(ctx->len.aad); + ctr[1] = (unsigned char)(ctx->len.aad>>8); + ctr[2] = (unsigned char)(ctx->len.aad>>16); + ctr[3] = (unsigned char)(ctx->len.aad>>24); + ctr[4] = (unsigned char)(ctx->len.aad>>32); + ctr[5] = (unsigned char)(ctx->len.aad>>40); + ctr[6] = (unsigned char)(ctx->len.aad>>48); + ctr[7] = (unsigned char)(ctx->len.aad>>56); + + ctr[8] = (unsigned char)(ctx->len.text); + ctr[9] = (unsigned char)(ctx->len.text>>8); + ctr[10] = (unsigned char)(ctx->len.text>>16); + ctr[11] = (unsigned char)(ctx->len.text>>24); + ctr[12] = (unsigned char)(ctx->len.text>>32); + ctr[13] = (unsigned char)(ctx->len.text>>40); + ctr[14] = (unsigned char)(ctx->len.text>>48); + ctr[15] = (unsigned char)(ctx->len.text>>56); + } + tohash_len += POLY1305_BLOCK_SIZE; + + Poly1305_Update(poly, tohash, tohash_len); + OPENSSL_cleanse(buf, buf_len); + Poly1305_Final(poly, bctx->enc ? ctx->tag : tohash); + + ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH; + + if (bctx->enc) { + memcpy(out, ctx->tag, POLY1305_BLOCK_SIZE); + } else { + if (CRYPTO_memcmp(tohash, in, POLY1305_BLOCK_SIZE)) { + if (len > POLY1305_BLOCK_SIZE) + memset(out - (len - POLY1305_BLOCK_SIZE), 0, + len - POLY1305_BLOCK_SIZE); + return 0; + } + /* Strip the tag */ + len -= POLY1305_BLOCK_SIZE; + } + + *out_padlen = len; + return 1; +} +#else +static const unsigned char zero[CHACHA_BLK_SIZE] = { 0 }; +#endif /* OPENSSL_SMALL_FOOTPRINT */ + +static int chacha20_poly1305_aead_cipher(PROV_CIPHER_CTX *bctx, + unsigned char *out, size_t *outl, + const unsigned char *in, size_t inl) +{ + PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx; + POLY1305 *poly = &ctx->poly1305; + size_t rem, plen = ctx->tls_payload_length; + size_t olen = 0; + int rv = 0; + + DECLARE_IS_ENDIAN; + + if (!ctx->mac_inited) { + if (plen != NO_TLS_PAYLOAD_LENGTH && out != NULL) { + if (inl != plen + POLY1305_BLOCK_SIZE) + return 0; +#if !defined(OPENSSL_SMALL_FOOTPRINT) + return chacha20_poly1305_tls_cipher(bctx, out, outl, in, inl); +#endif + } + + ctx->chacha.counter[0] = 0; + ChaCha20_ctr32(ctx->chacha.buf, zero, CHACHA_BLK_SIZE, + ctx->chacha.key.d, ctx->chacha.counter); + Poly1305_Init(poly, ctx->chacha.buf); + ctx->chacha.counter[0] = 1; + ctx->chacha.partial_len = 0; + ctx->len.aad = ctx->len.text = 0; + ctx->mac_inited = 1; + if (plen != NO_TLS_PAYLOAD_LENGTH) { + Poly1305_Update(poly, ctx->tls_aad, EVP_AEAD_TLS1_AAD_LEN); + ctx->len.aad = EVP_AEAD_TLS1_AAD_LEN; + ctx->aad = 1; + } + } + + if (in != NULL) { /* aad or text */ + if (out == NULL) { /* aad */ + Poly1305_Update(poly, in, inl); + ctx->len.aad += inl; + ctx->aad = 1; + goto finish; + } else { /* plain- or ciphertext */ + if (ctx->aad) { /* wrap up aad */ + if ((rem = (size_t)ctx->len.aad % POLY1305_BLOCK_SIZE)) + Poly1305_Update(poly, zero, POLY1305_BLOCK_SIZE - rem); + ctx->aad = 0; + } + + ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH; + if (plen == NO_TLS_PAYLOAD_LENGTH) + plen = inl; + else if (inl != plen + POLY1305_BLOCK_SIZE) + goto err; + + if (bctx->enc) { /* plaintext */ + ctx->chacha.base.hw->cipher(&ctx->chacha.base, out, in, plen); + Poly1305_Update(poly, out, plen); + in += plen; + out += plen; + ctx->len.text += plen; + } else { /* ciphertext */ + Poly1305_Update(poly, in, plen); + ctx->chacha.base.hw->cipher(&ctx->chacha.base, out, in, plen); + in += plen; + out += plen; + ctx->len.text += plen; + } + } + } + /* explicit final, or tls mode */ + if (in == NULL || inl != plen) { + + unsigned char temp[POLY1305_BLOCK_SIZE]; + + if (ctx->aad) { /* wrap up aad */ + if ((rem = (size_t)ctx->len.aad % POLY1305_BLOCK_SIZE)) + Poly1305_Update(poly, zero, POLY1305_BLOCK_SIZE - rem); + ctx->aad = 0; + } + + if ((rem = (size_t)ctx->len.text % POLY1305_BLOCK_SIZE)) + Poly1305_Update(poly, zero, POLY1305_BLOCK_SIZE - rem); + + if (IS_LITTLE_ENDIAN) { + Poly1305_Update(poly, (unsigned char *)&ctx->len, + POLY1305_BLOCK_SIZE); + } else { + temp[0] = (unsigned char)(ctx->len.aad); + temp[1] = (unsigned char)(ctx->len.aad>>8); + temp[2] = (unsigned char)(ctx->len.aad>>16); + temp[3] = (unsigned char)(ctx->len.aad>>24); + temp[4] = (unsigned char)(ctx->len.aad>>32); + temp[5] = (unsigned char)(ctx->len.aad>>40); + temp[6] = (unsigned char)(ctx->len.aad>>48); + temp[7] = (unsigned char)(ctx->len.aad>>56); + temp[8] = (unsigned char)(ctx->len.text); + temp[9] = (unsigned char)(ctx->len.text>>8); + temp[10] = (unsigned char)(ctx->len.text>>16); + temp[11] = (unsigned char)(ctx->len.text>>24); + temp[12] = (unsigned char)(ctx->len.text>>32); + temp[13] = (unsigned char)(ctx->len.text>>40); + temp[14] = (unsigned char)(ctx->len.text>>48); + temp[15] = (unsigned char)(ctx->len.text>>56); + Poly1305_Update(poly, temp, POLY1305_BLOCK_SIZE); + } + Poly1305_Final(poly, bctx->enc ? ctx->tag : temp); + ctx->mac_inited = 0; + + if (in != NULL && inl != plen) { + if (bctx->enc) { + memcpy(out, ctx->tag, POLY1305_BLOCK_SIZE); + } else { + if (CRYPTO_memcmp(temp, in, POLY1305_BLOCK_SIZE)) { + memset(out - plen, 0, plen); + goto err; + } + /* Strip the tag */ + inl -= POLY1305_BLOCK_SIZE; + } + } + else if (!bctx->enc) { + if (CRYPTO_memcmp(temp, ctx->tag, ctx->tag_len)) + goto err; + } + } +finish: + olen = inl; + rv = 1; +err: + *outl = olen; + return rv; +} + +static const PROV_CIPHER_HW_CHACHA20_POLY1305 chacha20poly1305_hw = +{ + { chacha20_poly1305_initkey, NULL }, + chacha20_poly1305_aead_cipher, + chacha20_poly1305_initiv, + chacha_poly1305_tls_init, + chacha_poly1305_tls_iv_set_fixed +}; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_chacha20_poly1305(size_t keybits) +{ + return (PROV_CIPHER_HW *)&chacha20poly1305_hw; +} diff --git a/providers/implementations/ciphers/cipher_cts.c b/providers/implementations/ciphers/cipher_cts.c new file mode 100644 index 000000000000..6a596508da69 --- /dev/null +++ b/providers/implementations/ciphers/cipher_cts.c @@ -0,0 +1,378 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Helper functions for 128 bit CBC CTS ciphers (Currently AES and Camellia). + * + * The function dispatch tables are embedded into cipher_aes.c + * and cipher_camellia.c using cipher_aes_cts.inc and cipher_camellia_cts.inc + */ + +/* + * Refer to SP800-38A-Addendum + * + * Ciphertext stealing encrypts plaintext using a block cipher, without padding + * the message to a multiple of the block size, so the ciphertext is the same + * size as the plaintext. + * It does this by altering processing of the last two blocks of the message. + * The processing of all but the last two blocks is unchanged, but a portion of + * the second-last block's ciphertext is "stolen" to pad the last plaintext + * block. The padded final block is then encrypted as usual. + * The final ciphertext for the last two blocks, consists of the partial block + * (with the "stolen" portion omitted) plus the full final block, + * which are the same size as the original plaintext. + * Decryption requires decrypting the final block first, then restoring the + * stolen ciphertext to the partial block, which can then be decrypted as usual. + + * AES_CBC_CTS has 3 variants: + * (1) CS1 The NIST variant. + * If the length is a multiple of the blocksize it is the same as CBC mode. + * otherwise it produces C1||C2||(C(n-1))*||Cn. + * Where C(n-1)* is a partial block. + * (2) CS2 + * If the length is a multiple of the blocksize it is the same as CBC mode. + * otherwise it produces C1||C2||Cn||(C(n-1))*. + * Where C(n-1)* is a partial block. + * (3) CS3 The Kerberos5 variant. + * Produces C1||C2||Cn||(C(n-1))* regardless of the length. + * If the length is a multiple of the blocksize it looks similar to CBC mode + * with the last 2 blocks swapped. + * Otherwise it is the same as CS2. + */ + +#include <openssl/core_names.h> +#include "prov/ciphercommon.h" +#include "internal/nelem.h" +#include "cipher_cts.h" + +/* The value assigned to 0 is the default */ +#define CTS_CS1 0 +#define CTS_CS2 1 +#define CTS_CS3 2 + +#define CTS_BLOCK_SIZE 16 + +typedef union { + size_t align; + unsigned char c[CTS_BLOCK_SIZE]; +} aligned_16bytes; + +typedef struct cts_mode_name2id_st { + unsigned int id; + const char *name; +} CTS_MODE_NAME2ID; + +static CTS_MODE_NAME2ID cts_modes[] = +{ + { CTS_CS1, OSSL_CIPHER_CTS_MODE_CS1 }, + { CTS_CS2, OSSL_CIPHER_CTS_MODE_CS2 }, + { CTS_CS3, OSSL_CIPHER_CTS_MODE_CS3 }, +}; + +const char *ossl_cipher_cbc_cts_mode_id2name(unsigned int id) +{ + size_t i; + + for (i = 0; i < OSSL_NELEM(cts_modes); ++i) { + if (cts_modes[i].id == id) + return cts_modes[i].name; + } + return NULL; +} + +int ossl_cipher_cbc_cts_mode_name2id(const char *name) +{ + size_t i; + + for (i = 0; i < OSSL_NELEM(cts_modes); ++i) { + if (OPENSSL_strcasecmp(name, cts_modes[i].name) == 0) + return (int)cts_modes[i].id; + } + return -1; +} + +static size_t cts128_cs1_encrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len) +{ + aligned_16bytes tmp_in; + size_t residue; + + residue = len % CTS_BLOCK_SIZE; + len -= residue; + if (!ctx->hw->cipher(ctx, out, in, len)) + return 0; + + if (residue == 0) + return len; + + in += len; + out += len; + + memset(tmp_in.c, 0, sizeof(tmp_in)); + memcpy(tmp_in.c, in, residue); + if (!ctx->hw->cipher(ctx, out - CTS_BLOCK_SIZE + residue, tmp_in.c, + CTS_BLOCK_SIZE)) + return 0; + return len + residue; +} + +static void do_xor(const unsigned char *in1, const unsigned char *in2, + size_t len, unsigned char *out) +{ + size_t i; + + for (i = 0; i < len; ++i) + out[i] = in1[i] ^ in2[i]; +} + +static size_t cts128_cs1_decrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len) +{ + aligned_16bytes mid_iv, ct_mid, cn, pt_last; + size_t residue; + + residue = len % CTS_BLOCK_SIZE; + if (residue == 0) { + /* If there are no partial blocks then it is the same as CBC mode */ + if (!ctx->hw->cipher(ctx, out, in, len)) + return 0; + return len; + } + /* Process blocks at the start - but leave the last 2 blocks */ + len -= CTS_BLOCK_SIZE + residue; + if (len > 0) { + if (!ctx->hw->cipher(ctx, out, in, len)) + return 0; + in += len; + out += len; + } + /* Save the iv that will be used by the second last block */ + memcpy(mid_iv.c, ctx->iv, CTS_BLOCK_SIZE); + /* Save the C(n) block */ + memcpy(cn.c, in + residue, CTS_BLOCK_SIZE); + + /* Decrypt the last block first using an iv of zero */ + memset(ctx->iv, 0, CTS_BLOCK_SIZE); + if (!ctx->hw->cipher(ctx, pt_last.c, in + residue, CTS_BLOCK_SIZE)) + return 0; + + /* + * Rebuild the ciphertext of the second last block as a combination of + * the decrypted last block + replace the start with the ciphertext bytes + * of the partial second last block. + */ + memcpy(ct_mid.c, in, residue); + memcpy(ct_mid.c + residue, pt_last.c + residue, CTS_BLOCK_SIZE - residue); + /* + * Restore the last partial ciphertext block. + * Now that we have the cipher text of the second last block, apply + * that to the partial plaintext end block. We have already decrypted the + * block using an IV of zero. For decryption the IV is just XORed after + * doing an Cipher CBC block - so just XOR in the cipher text. + */ + do_xor(ct_mid.c, pt_last.c, residue, out + CTS_BLOCK_SIZE); + + /* Restore the iv needed by the second last block */ + memcpy(ctx->iv, mid_iv.c, CTS_BLOCK_SIZE); + + /* + * Decrypt the second last plaintext block now that we have rebuilt the + * ciphertext. + */ + if (!ctx->hw->cipher(ctx, out, ct_mid.c, CTS_BLOCK_SIZE)) + return 0; + + /* The returned iv is the C(n) block */ + memcpy(ctx->iv, cn.c, CTS_BLOCK_SIZE); + return len + CTS_BLOCK_SIZE + residue; +} + +static size_t cts128_cs3_encrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len) +{ + aligned_16bytes tmp_in; + size_t residue; + + if (len < CTS_BLOCK_SIZE) /* CS3 requires at least one block */ + return 0; + + /* If we only have one block then just process the aligned block */ + if (len == CTS_BLOCK_SIZE) + return ctx->hw->cipher(ctx, out, in, len) ? len : 0; + + residue = len % CTS_BLOCK_SIZE; + if (residue == 0) + residue = CTS_BLOCK_SIZE; + len -= residue; + + if (!ctx->hw->cipher(ctx, out, in, len)) + return 0; + + in += len; + out += len; + + memset(tmp_in.c, 0, sizeof(tmp_in)); + memcpy(tmp_in.c, in, residue); + memcpy(out, out - CTS_BLOCK_SIZE, residue); + if (!ctx->hw->cipher(ctx, out - CTS_BLOCK_SIZE, tmp_in.c, CTS_BLOCK_SIZE)) + return 0; + return len + residue; +} + +/* + * Note: + * The cipher text (in) is of the form C(0), C(1), ., C(n), C(n-1)* where + * C(n) is a full block and C(n-1)* can be a partial block + * (but could be a full block). + * This means that the output plaintext (out) needs to swap the plaintext of + * the last two decoded ciphertext blocks. + */ +static size_t cts128_cs3_decrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len) +{ + aligned_16bytes mid_iv, ct_mid, cn, pt_last; + size_t residue; + + if (len < CTS_BLOCK_SIZE) /* CS3 requires at least one block */ + return 0; + + /* If we only have one block then just process the aligned block */ + if (len == CTS_BLOCK_SIZE) + return ctx->hw->cipher(ctx, out, in, len) ? len : 0; + + /* Process blocks at the start - but leave the last 2 blocks */ + residue = len % CTS_BLOCK_SIZE; + if (residue == 0) + residue = CTS_BLOCK_SIZE; + len -= CTS_BLOCK_SIZE + residue; + + if (len > 0) { + if (!ctx->hw->cipher(ctx, out, in, len)) + return 0; + in += len; + out += len; + } + /* Save the iv that will be used by the second last block */ + memcpy(mid_iv.c, ctx->iv, CTS_BLOCK_SIZE); + /* Save the C(n) block : For CS3 it is C(1)||...||C(n-2)||C(n)||C(n-1)* */ + memcpy(cn.c, in, CTS_BLOCK_SIZE); + + /* Decrypt the C(n) block first using an iv of zero */ + memset(ctx->iv, 0, CTS_BLOCK_SIZE); + if (!ctx->hw->cipher(ctx, pt_last.c, in, CTS_BLOCK_SIZE)) + return 0; + + /* + * Rebuild the ciphertext of C(n-1) as a combination of + * the decrypted C(n) block + replace the start with the ciphertext bytes + * of the partial last block. + */ + memcpy(ct_mid.c, in + CTS_BLOCK_SIZE, residue); + if (residue != CTS_BLOCK_SIZE) + memcpy(ct_mid.c + residue, pt_last.c + residue, CTS_BLOCK_SIZE - residue); + /* + * Restore the last partial ciphertext block. + * Now that we have the cipher text of the second last block, apply + * that to the partial plaintext end block. We have already decrypted the + * block using an IV of zero. For decryption the IV is just XORed after + * doing an AES block - so just XOR in the ciphertext. + */ + do_xor(ct_mid.c, pt_last.c, residue, out + CTS_BLOCK_SIZE); + + /* Restore the iv needed by the second last block */ + memcpy(ctx->iv, mid_iv.c, CTS_BLOCK_SIZE); + /* + * Decrypt the second last plaintext block now that we have rebuilt the + * ciphertext. + */ + if (!ctx->hw->cipher(ctx, out, ct_mid.c, CTS_BLOCK_SIZE)) + return 0; + + /* The returned iv is the C(n) block */ + memcpy(ctx->iv, cn.c, CTS_BLOCK_SIZE); + return len + CTS_BLOCK_SIZE + residue; +} + +static size_t cts128_cs2_encrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len) +{ + if (len % CTS_BLOCK_SIZE == 0) { + /* If there are no partial blocks then it is the same as CBC mode */ + if (!ctx->hw->cipher(ctx, out, in, len)) + return 0; + return len; + } + /* For partial blocks CS2 is equivalent to CS3 */ + return cts128_cs3_encrypt(ctx, in, out, len); +} + +static size_t cts128_cs2_decrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len) +{ + if (len % CTS_BLOCK_SIZE == 0) { + /* If there are no partial blocks then it is the same as CBC mode */ + if (!ctx->hw->cipher(ctx, out, in, len)) + return 0; + return len; + } + /* For partial blocks CS2 is equivalent to CS3 */ + return cts128_cs3_decrypt(ctx, in, out, len); +} + +int ossl_cipher_cbc_cts_block_update(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, + size_t inl) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + size_t sz = 0; + + if (inl < CTS_BLOCK_SIZE) /* There must be at least one block for CTS mode */ + return 0; + if (outsize < inl) + return 0; + if (out == NULL) { + *outl = inl; + return 1; + } + + /* + * Return an error if the update is called multiple times, only one shot + * is supported. + */ + if (ctx->updated == 1) + return 0; + + if (ctx->enc) { + if (ctx->cts_mode == CTS_CS1) + sz = cts128_cs1_encrypt(ctx, in, out, inl); + else if (ctx->cts_mode == CTS_CS2) + sz = cts128_cs2_encrypt(ctx, in, out, inl); + else if (ctx->cts_mode == CTS_CS3) + sz = cts128_cs3_encrypt(ctx, in, out, inl); + } else { + if (ctx->cts_mode == CTS_CS1) + sz = cts128_cs1_decrypt(ctx, in, out, inl); + else if (ctx->cts_mode == CTS_CS2) + sz = cts128_cs2_decrypt(ctx, in, out, inl); + else if (ctx->cts_mode == CTS_CS3) + sz = cts128_cs3_decrypt(ctx, in, out, inl); + } + if (sz == 0) + return 0; + ctx->updated = 1; /* Stop multiple updates being allowed */ + *outl = sz; + return 1; +} + +int ossl_cipher_cbc_cts_block_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + *outl = 0; + return 1; +} diff --git a/providers/implementations/ciphers/cipher_cts.h b/providers/implementations/ciphers/cipher_cts.h new file mode 100644 index 000000000000..9473fbde886c --- /dev/null +++ b/providers/implementations/ciphers/cipher_cts.h @@ -0,0 +1,52 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "crypto/evp.h" + +/* NOTE: The underlying block cipher is CBC so we reuse most of the code */ +#define IMPLEMENT_cts_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits, \ + blkbits, ivbits, typ) \ +static OSSL_FUNC_cipher_get_params_fn alg##_##kbits##_##lcmode##_get_params; \ +static int alg##_cts_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, kbits, blkbits, ivbits); \ +} \ +const OSSL_DISPATCH ossl_##alg##kbits##lcmode##_cts_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (void (*)(void)) alg##_##kbits##_##lcmode##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void)) alg##_cbc_cts_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void)) alg##_cbc_cts_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, \ + (void (*)(void)) ossl_cipher_cbc_cts_block_update }, \ + { OSSL_FUNC_CIPHER_FINAL, \ + (void (*)(void)) ossl_cipher_cbc_cts_block_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_cipher_generic_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void)) alg##_cts_##kbits##_##lcmode##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void)) alg##_cbc_cts_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void)) alg##_cbc_cts_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void)) alg##_cbc_cts_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void)) alg##_cbc_cts_settable_ctx_params }, \ + { 0, NULL } \ +}; + +OSSL_FUNC_cipher_update_fn ossl_cipher_cbc_cts_block_update; +OSSL_FUNC_cipher_final_fn ossl_cipher_cbc_cts_block_final; + +const char *ossl_cipher_cbc_cts_mode_id2name(unsigned int id); +int ossl_cipher_cbc_cts_mode_name2id(const char *name); diff --git a/providers/implementations/ciphers/cipher_des.c b/providers/implementations/ciphers/cipher_des.c new file mode 100644 index 000000000000..c6d13466f79d --- /dev/null +++ b/providers/implementations/ciphers/cipher_des.c @@ -0,0 +1,202 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include <openssl/rand.h> +#include <openssl/proverr.h> +#include "prov/ciphercommon.h" +#include "cipher_des.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define DES_FLAGS PROV_CIPHER_FLAG_RAND_KEY + +static OSSL_FUNC_cipher_freectx_fn des_freectx; +static OSSL_FUNC_cipher_encrypt_init_fn des_einit; +static OSSL_FUNC_cipher_decrypt_init_fn des_dinit; +static OSSL_FUNC_cipher_get_ctx_params_fn des_get_ctx_params; +static OSSL_FUNC_cipher_gettable_ctx_params_fn des_gettable_ctx_params; + +static void *des_newctx(void *provctx, size_t kbits, size_t blkbits, + size_t ivbits, unsigned int mode, uint64_t flags, + const PROV_CIPHER_HW *hw) +{ + PROV_DES_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits, mode, flags, + hw, provctx); + return ctx; +} + +static void *des_dupctx(void *ctx) +{ + PROV_DES_CTX *in = (PROV_DES_CTX *)ctx; + PROV_DES_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + in->base.hw->copyctx(&ret->base, &in->base); + + return ret; +} + +static void des_freectx(void *vctx) +{ + PROV_DES_CTX *ctx = (PROV_DES_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static int des_init(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[], int enc) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + ctx->num = 0; + ctx->bufsz = 0; + ctx->enc = enc; + + if (iv != NULL) { + if (!ossl_cipher_generic_initiv(ctx, iv, ivlen)) + return 0; + } else if (ctx->iv_set) { + /* reset IV to keep compatibility with 1.1.1 */ + memcpy(ctx->iv, ctx->oiv, ctx->ivlen); + } + + if (key != NULL) { + if (keylen != ctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + if (!ctx->hw->init(ctx, key, keylen)) + return 0; + } + return ossl_cipher_generic_set_ctx_params(ctx, params); +} + +static int des_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return des_init(vctx, key, keylen, iv, ivlen, params, 1); +} + +static int des_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return des_init(vctx, key, keylen, iv, ivlen, params, 0); +} + +static int des_generatekey(PROV_CIPHER_CTX *ctx, void *ptr) +{ + + DES_cblock *deskey = ptr; + size_t kl = ctx->keylen; + + if (kl == 0 || RAND_priv_bytes_ex(ctx->libctx, ptr, kl, 0) <= 0) + return 0; + DES_set_odd_parity(deskey); + return 1; +} + +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(des) + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_RANDOM_KEY, NULL, 0), +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(des) + +static int des_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + OSSL_PARAM *p; + + if (!ossl_cipher_generic_get_ctx_params(vctx, params)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_RANDOM_KEY); + if (p != NULL && !des_generatekey(ctx, p->data)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY); + return 0; + } + return 1; +} + +#define IMPLEMENT_des_cipher(type, lcmode, UCMODE, flags, \ + kbits, blkbits, ivbits, block) \ +static OSSL_FUNC_cipher_newctx_fn type##_##lcmode##_newctx; \ +static void *des_##lcmode##_newctx(void *provctx) \ +{ \ + return des_newctx(provctx, kbits, blkbits, ivbits, \ + EVP_CIPH_##UCMODE##_MODE, flags, \ + ossl_prov_cipher_hw_des_##lcmode()); \ +} \ +static OSSL_FUNC_cipher_get_params_fn des_##lcmode##_get_params; \ +static int des_##lcmode##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, kbits, blkbits, ivbits); \ +} \ +const OSSL_DISPATCH ossl_##des_##lcmode##_functions[] = { \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))des_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))des_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, \ + (void (*)(void))ossl_cipher_generic_##block##_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))ossl_cipher_generic_##block##_final },\ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_cipher_generic_cipher }, \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (void (*)(void))des_##lcmode##_newctx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))des_dupctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))des_freectx }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void))des_##lcmode##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (void (*)(void))des_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))des_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_settable_ctx_params }, \ + { 0, NULL } \ +} + +/* ossl_des_ecb_functions */ +IMPLEMENT_des_cipher(des, ecb, ECB, DES_FLAGS, 64, 64, 0, block); +/* ossl_des_cbc_functions */ +IMPLEMENT_des_cipher(des, cbc, CBC, DES_FLAGS, 64, 64, 64, block); +/* ossl_des_ofb64_functions */ +IMPLEMENT_des_cipher(des, ofb64, OFB, DES_FLAGS, 64, 8, 64, stream); +/* ossl_des_cfb64_functions */ +IMPLEMENT_des_cipher(des, cfb64, CFB, DES_FLAGS, 64, 8, 64, stream); +/* ossl_des_cfb1_functions */ +IMPLEMENT_des_cipher(des, cfb1, CFB, DES_FLAGS, 64, 8, 64, stream); +/* ossl_des_cfb8_functions */ +IMPLEMENT_des_cipher(des, cfb8, CFB, DES_FLAGS, 64, 8, 64, stream); diff --git a/providers/implementations/ciphers/cipher_des.h b/providers/implementations/ciphers/cipher_des.h new file mode 100644 index 000000000000..ad10f63d8b16 --- /dev/null +++ b/providers/implementations/ciphers/cipher_des.h @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/des.h> +#include "crypto/des_platform.h" + +#define TDES_FLAGS 0 + +typedef struct prov_des_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + DES_key_schedule ks; + } dks; + union { + void (*cbc) (const void *, void *, size_t, + const DES_key_schedule *, unsigned char *); + } dstream; + +} PROV_DES_CTX; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_des_cbc(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_des_ecb(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_des_ofb64(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_des_cfb64(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_des_cfb1(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_des_cfb8(void); diff --git a/providers/implementations/ciphers/cipher_des_hw.c b/providers/implementations/ciphers/cipher_des_hw.c new file mode 100644 index 000000000000..a77fcc681a4a --- /dev/null +++ b/providers/implementations/ciphers/cipher_des_hw.c @@ -0,0 +1,196 @@ +/* + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "prov/ciphercommon.h" +#include "cipher_des.h" + +static int cipher_hw_des_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_DES_CTX *dctx = (PROV_DES_CTX *)ctx; + DES_cblock *deskey = (DES_cblock *)key; + DES_key_schedule *ks = &dctx->dks.ks; + + dctx->dstream.cbc = NULL; +#if defined(SPARC_DES_CAPABLE) + if (SPARC_DES_CAPABLE) { + if (ctx->mode == EVP_CIPH_CBC_MODE) { + des_t4_key_expand(&deskey[0], ks); + dctx->dstream.cbc = ctx->enc ? des_t4_cbc_encrypt : + des_t4_cbc_decrypt; + return 1; + } + } +#endif + DES_set_key_unchecked(deskey, ks); + return 1; +} + +static void cipher_hw_des_copyctx(PROV_CIPHER_CTX *dst, + const PROV_CIPHER_CTX *src) +{ + PROV_DES_CTX *sctx = (PROV_DES_CTX *)src; + PROV_DES_CTX *dctx = (PROV_DES_CTX *)dst; + + *dctx = *sctx; + dst->ks = &dctx->dks.ks; +} + +static int cipher_hw_des_ecb_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + size_t i, bl = ctx->blocksize; + DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks); + + if (len < bl) + return 1; + for (i = 0, len -= bl; i <= len; i += bl) + DES_ecb_encrypt((const_DES_cblock *)(in + i), + (const_DES_cblock *)(out + i), key, ctx->enc); + return 1; +} + +static int cipher_hw_des_cbc_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_DES_CTX *dctx = (PROV_DES_CTX *)ctx; + DES_key_schedule *key = &(dctx->dks.ks); + + if (dctx->dstream.cbc != NULL) { + (*dctx->dstream.cbc) (in, out, len, key, ctx->iv); + return 1; + } + + while (len >= MAXCHUNK) { + DES_ncbc_encrypt(in, out, MAXCHUNK, key, (DES_cblock *)ctx->iv, + ctx->enc); + len -= MAXCHUNK; + in += MAXCHUNK; + out += MAXCHUNK; + } + if (len > 0) + DES_ncbc_encrypt(in, out, (long)len, key, (DES_cblock *)ctx->iv, + ctx->enc); + return 1; +} + +static int cipher_hw_des_ofb64_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + int num = ctx->num; + DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks); + + while (len >= MAXCHUNK) { + DES_ofb64_encrypt(in, out, MAXCHUNK, key, (DES_cblock *)ctx->iv, &num); + len -= MAXCHUNK; + in += MAXCHUNK; + out += MAXCHUNK; + } + if (len > 0) { + DES_ofb64_encrypt(in, out, (long)len, key, (DES_cblock *)ctx->iv, &num); + } + ctx->num = num; + return 1; +} + +static int cipher_hw_des_cfb64_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + size_t chunk = MAXCHUNK; + DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks); + int num = ctx->num; + + if (len < chunk) + chunk = len; + while (len > 0 && len >= chunk) { + DES_cfb64_encrypt(in, out, (long)chunk, key, (DES_cblock *)ctx->iv, + &num, ctx->enc); + len -= chunk; + in += chunk; + out += chunk; + if (len < chunk) + chunk = len; + } + ctx->num = num; + return 1; +} + +/* + * Although we have a CFB-r implementation for DES, it doesn't pack the right + * way, so wrap it here + */ +static int cipher_hw_des_cfb1_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + size_t n, chunk = MAXCHUNK / 8; + DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks); + unsigned char c[1], d[1]; + + if (inl < chunk) + chunk = inl; + + while (inl && inl >= chunk) { + for (n = 0; n < chunk * 8; ++n) { + c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0; + DES_cfb_encrypt(c, d, 1, 1, key, (DES_cblock *)ctx->iv, ctx->enc); + out[n / 8] = + (out[n / 8] & ~(0x80 >> (unsigned int)(n % 8))) | + ((d[0] & 0x80) >> (unsigned int)(n % 8)); + } + inl -= chunk; + in += chunk; + out += chunk; + if (inl < chunk) + chunk = inl; + } + + return 1; +} + +static int cipher_hw_des_cfb8_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks); + + while (inl >= MAXCHUNK) { + DES_cfb_encrypt(in, out, 8, (long)MAXCHUNK, key, + (DES_cblock *)ctx->iv, ctx->enc); + inl -= MAXCHUNK; + in += MAXCHUNK; + out += MAXCHUNK; + } + if (inl > 0) + DES_cfb_encrypt(in, out, 8, (long)inl, key, + (DES_cblock *)ctx->iv, ctx->enc); + return 1; +} + +#define PROV_CIPHER_HW_des_mode(mode) \ +static const PROV_CIPHER_HW des_##mode = { \ + cipher_hw_des_initkey, \ + cipher_hw_des_##mode##_cipher, \ + cipher_hw_des_copyctx \ +}; \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_des_##mode(void) \ +{ \ + return &des_##mode; \ +} + +PROV_CIPHER_HW_des_mode(ecb) +PROV_CIPHER_HW_des_mode(cbc) +PROV_CIPHER_HW_des_mode(ofb64) +PROV_CIPHER_HW_des_mode(cfb64) +PROV_CIPHER_HW_des_mode(cfb1) +PROV_CIPHER_HW_des_mode(cfb8) diff --git a/providers/implementations/ciphers/cipher_desx.c b/providers/implementations/ciphers/cipher_desx.c new file mode 100644 index 000000000000..41596554435e --- /dev/null +++ b/providers/implementations/ciphers/cipher_desx.c @@ -0,0 +1,21 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "cipher_tdes_default.h" +#include "prov/implementations.h" + +/* desx_cbc_functions */ +IMPLEMENT_tdes_cipher(desx, DESX, cbc, CBC, TDES_FLAGS, 64*3, 64, 64, block); + diff --git a/providers/implementations/ciphers/cipher_desx_hw.c b/providers/implementations/ciphers/cipher_desx_hw.c new file mode 100644 index 000000000000..7dc4c50ef55a --- /dev/null +++ b/providers/implementations/ciphers/cipher_desx_hw.c @@ -0,0 +1,80 @@ +/* + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include <openssl/des.h> +#include "cipher_tdes_default.h" + +/* + * Note the PROV_TDES_CTX has been used for the DESX cipher, just to reduce + * code size. + */ +#define ks1 tks.ks[0] +#define ks2 tks.ks[1].ks[0].cblock +#define ks3 tks.ks[2].ks[0].cblock + +static int cipher_hw_desx_cbc_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx; + DES_cblock *deskey = (DES_cblock *)key; + + DES_set_key_unchecked(deskey, &tctx->ks1); + memcpy(&tctx->ks2, &key[8], 8); + memcpy(&tctx->ks3, &key[16], 8); + + return 1; +} + +static void cipher_hw_desx_copyctx(PROV_CIPHER_CTX *dst, + const PROV_CIPHER_CTX *src) +{ + PROV_TDES_CTX *sctx = (PROV_TDES_CTX *)src; + PROV_TDES_CTX *dctx = (PROV_TDES_CTX *)dst; + + *dctx = *sctx; + dst->ks = &dctx->tks.ks; +} + +static int cipher_hw_desx_cbc(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx; + + while (inl >= MAXCHUNK) { + DES_xcbc_encrypt(in, out, (long)MAXCHUNK, &tctx->ks1, + (DES_cblock *)ctx->iv, &tctx->ks2, &tctx->ks3, + ctx->enc); + inl -= MAXCHUNK; + in += MAXCHUNK; + out += MAXCHUNK; + } + if (inl > 0) + DES_xcbc_encrypt(in, out, (long)inl, &tctx->ks1, + (DES_cblock *)ctx->iv, &tctx->ks2, &tctx->ks3, + ctx->enc); + return 1; +} + +static const PROV_CIPHER_HW desx_cbc = +{ + cipher_hw_desx_cbc_initkey, + cipher_hw_desx_cbc, + cipher_hw_desx_copyctx +}; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_desx_cbc(void) +{ + return &desx_cbc; +} diff --git a/providers/implementations/ciphers/cipher_idea.c b/providers/implementations/ciphers/cipher_idea.c new file mode 100644 index 000000000000..bc716290a48a --- /dev/null +++ b/providers/implementations/ciphers/cipher_idea.c @@ -0,0 +1,59 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * IDEA low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +/* Dispatch functions for Idea cipher modes ecb, cbc, ofb, cfb */ + +#include "cipher_idea.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +static OSSL_FUNC_cipher_freectx_fn idea_freectx; +static OSSL_FUNC_cipher_dupctx_fn idea_dupctx; + +static void idea_freectx(void *vctx) +{ + PROV_IDEA_CTX *ctx = (PROV_IDEA_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *idea_dupctx(void *ctx) +{ + PROV_IDEA_CTX *in = (PROV_IDEA_CTX *)ctx; + PROV_IDEA_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + *ret = *in; + + return ret; +} + +/* ossl_idea128ecb_functions */ +IMPLEMENT_generic_cipher(idea, IDEA, ecb, ECB, 0, 128, 64, 0, block) +/* ossl_idea128cbc_functions */ +IMPLEMENT_generic_cipher(idea, IDEA, cbc, CBC, 0, 128, 64, 64, block) +/* ossl_idea128ofb64_functions */ +IMPLEMENT_generic_cipher(idea, IDEA, ofb64, OFB, 0, 128, 8, 64, stream) +/* ossl_idea128cfb64_functions */ +IMPLEMENT_generic_cipher(idea, IDEA, cfb64, CFB, 0, 128, 8, 64, stream) diff --git a/providers/implementations/ciphers/cipher_idea.h b/providers/implementations/ciphers/cipher_idea.h new file mode 100644 index 000000000000..212efa8af575 --- /dev/null +++ b/providers/implementations/ciphers/cipher_idea.h @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/idea.h> +#include "prov/ciphercommon.h" + +typedef struct prov_idea_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + IDEA_KEY_SCHEDULE ks; + } ks; +} PROV_IDEA_CTX; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_idea_cbc(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_idea_ecb(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_idea_ofb64(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_idea_cfb64(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_idea_hw.c b/providers/implementations/ciphers/cipher_idea_hw.c new file mode 100644 index 000000000000..1c451b77edc4 --- /dev/null +++ b/providers/implementations/ciphers/cipher_idea_hw.c @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * IDEA low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +#include "cipher_idea.h" + +static int cipher_hw_idea_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_IDEA_CTX *ictx = (PROV_IDEA_CTX *)ctx; + IDEA_KEY_SCHEDULE *ks = &(ictx->ks.ks); + + if (ctx->enc + || ctx->mode == EVP_CIPH_OFB_MODE + || ctx->mode == EVP_CIPH_CFB_MODE) { + IDEA_set_encrypt_key(key, ks); + } else { + IDEA_KEY_SCHEDULE tmp; + + IDEA_set_encrypt_key(key, &tmp); + IDEA_set_decrypt_key(&tmp, ks); + OPENSSL_cleanse((unsigned char *)&tmp, sizeof(IDEA_KEY_SCHEDULE)); + } + return 1; +} + +# define PROV_CIPHER_HW_idea_mode_ex(mode, UCMODE, fname) \ +IMPLEMENT_CIPHER_HW_##UCMODE(mode, idea, PROV_IDEA_CTX, IDEA_KEY_SCHEDULE, \ + fname) \ +static const PROV_CIPHER_HW idea_##mode = { \ + cipher_hw_idea_initkey, \ + cipher_hw_idea_##mode##_cipher \ +}; \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_idea_##mode(size_t keybits) \ +{ \ + return &idea_##mode; \ +} + +# define PROV_CIPHER_HW_idea_mode(mode, UCMODE) \ + PROV_CIPHER_HW_idea_mode_ex(mode, UCMODE, IDEA_##mode) + +PROV_CIPHER_HW_idea_mode(cbc, CBC) +PROV_CIPHER_HW_idea_mode(ofb64, OFB) +PROV_CIPHER_HW_idea_mode(cfb64, CFB) +/* + * IDEA_ecb_encrypt() does not have a enc parameter - so we create a macro + * that ignores this parameter when IMPLEMENT_CIPHER_HW_ecb() is called. + */ +#define IDEA2_ecb_encrypt(in, out, ks, enc) IDEA_ecb_encrypt(in, out, ks) + +PROV_CIPHER_HW_idea_mode_ex(ecb, ECB, IDEA2_ecb) diff --git a/providers/implementations/ciphers/cipher_null.c b/providers/implementations/ciphers/cipher_null.c new file mode 100644 index 000000000000..0df97a7f8bc3 --- /dev/null +++ b/providers/implementations/ciphers/cipher_null.c @@ -0,0 +1,197 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/core_dispatch.h> +#include <openssl/proverr.h> +#include "prov/implementations.h" +#include "prov/ciphercommon.h" +#include "prov/providercommon.h" + +typedef struct prov_cipher_null_ctx_st { + int enc; + size_t tlsmacsize; + const unsigned char *tlsmac; +} PROV_CIPHER_NULL_CTX; + +static OSSL_FUNC_cipher_newctx_fn null_newctx; +static void *null_newctx(void *provctx) +{ + if (!ossl_prov_is_running()) + return NULL; + + return OPENSSL_zalloc(sizeof(PROV_CIPHER_NULL_CTX)); +} + +static OSSL_FUNC_cipher_freectx_fn null_freectx; +static void null_freectx(void *vctx) +{ + OPENSSL_free(vctx); +} + +static OSSL_FUNC_cipher_encrypt_init_fn null_einit; +static int null_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + PROV_CIPHER_NULL_CTX *ctx = (PROV_CIPHER_NULL_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + ctx->enc = 1; + return 1; +} + +static OSSL_FUNC_cipher_decrypt_init_fn null_dinit; +static int null_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_prov_is_running()) + return 0; + + return 1; +} + +static OSSL_FUNC_cipher_cipher_fn null_cipher; +static int null_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_CIPHER_NULL_CTX *ctx = (PROV_CIPHER_NULL_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (!ctx->enc && ctx->tlsmacsize > 0) { + /* + * TLS NULL cipher as per: + * https://tools.ietf.org/html/rfc5246#section-6.2.3.1 + */ + if (inl < ctx->tlsmacsize) + return 0; + ctx->tlsmac = in + inl - ctx->tlsmacsize; + inl -= ctx->tlsmacsize; + } + if (outsize < inl) + return 0; + if (in != out) + memcpy(out, in, inl); + *outl = inl; + return 1; +} + +static OSSL_FUNC_cipher_final_fn null_final; +static int null_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + if (!ossl_prov_is_running()) + return 0; + + *outl = 0; + return 1; +} + +static OSSL_FUNC_cipher_get_params_fn null_get_params; +static int null_get_params(OSSL_PARAM params[]) +{ + return ossl_cipher_generic_get_params(params, 0, 0, 0, 8, 0); +} + +static const OSSL_PARAM null_known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + { OSSL_CIPHER_PARAM_TLS_MAC, OSSL_PARAM_OCTET_PTR, NULL, 0, OSSL_PARAM_UNMODIFIED }, + OSSL_PARAM_END +}; + +static OSSL_FUNC_cipher_gettable_ctx_params_fn null_gettable_ctx_params; +static const OSSL_PARAM *null_gettable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return null_known_gettable_ctx_params; +} + +static OSSL_FUNC_cipher_get_ctx_params_fn null_get_ctx_params; +static int null_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_CIPHER_NULL_CTX *ctx = (PROV_CIPHER_NULL_CTX *)vctx; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS_MAC); + if (p != NULL + && !OSSL_PARAM_set_octet_ptr(p, ctx->tlsmac, ctx->tlsmacsize)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + return 1; +} + +static const OSSL_PARAM null_known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS_MAC_SIZE, NULL), + OSSL_PARAM_END +}; + +static OSSL_FUNC_cipher_settable_ctx_params_fn null_settable_ctx_params; +static const OSSL_PARAM *null_settable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return null_known_settable_ctx_params; +} + + +static OSSL_FUNC_cipher_set_ctx_params_fn null_set_ctx_params; +static int null_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_CIPHER_NULL_CTX *ctx = (PROV_CIPHER_NULL_CTX *)vctx; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS_MAC_SIZE); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &ctx->tlsmacsize)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + + return 1; +} + +const OSSL_DISPATCH ossl_null_functions[] = { + { OSSL_FUNC_CIPHER_NEWCTX, + (void (*)(void)) null_newctx }, + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) null_freectx }, + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) null_newctx }, + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))null_einit }, + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))null_dinit }, + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))null_cipher }, + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))null_final }, + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))null_cipher }, + { OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void)) null_get_params }, + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, + (void (*)(void))ossl_cipher_generic_gettable_params }, + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (void (*)(void))null_get_ctx_params }, + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, + (void (*)(void))null_gettable_ctx_params }, + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, (void (*)(void))null_set_ctx_params }, + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, + (void (*)(void))null_settable_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/ciphers/cipher_rc2.c b/providers/implementations/ciphers/cipher_rc2.c new file mode 100644 index 000000000000..106f47e8667a --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc2.c @@ -0,0 +1,283 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for RC2 cipher modes ecb, cbc, ofb, cfb */ + +/* + * RC2 low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include <openssl/proverr.h> +#include "cipher_rc2.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define RC2_40_MAGIC 0xa0 +#define RC2_64_MAGIC 0x78 +#define RC2_128_MAGIC 0x3a +#define RC2_FLAGS PROV_CIPHER_FLAG_VARIABLE_LENGTH + +static OSSL_FUNC_cipher_encrypt_init_fn rc2_einit; +static OSSL_FUNC_cipher_decrypt_init_fn rc2_dinit; +static OSSL_FUNC_cipher_freectx_fn rc2_freectx; +static OSSL_FUNC_cipher_dupctx_fn rc2_dupctx; +static OSSL_FUNC_cipher_gettable_ctx_params_fn rc2_gettable_ctx_params; +static OSSL_FUNC_cipher_settable_ctx_params_fn rc2_settable_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn rc2_set_ctx_params; + +static void rc2_freectx(void *vctx) +{ + PROV_RC2_CTX *ctx = (PROV_RC2_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *rc2_dupctx(void *ctx) +{ + PROV_RC2_CTX *in = (PROV_RC2_CTX *)ctx; + PROV_RC2_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + *ret = *in; + + return ret; +} + +static int rc2_keybits_to_magic(int keybits) +{ + switch (keybits) { + case 128: + return RC2_128_MAGIC; + case 64: + return RC2_64_MAGIC; + case 40: + return RC2_40_MAGIC; + } + ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_KEY_SIZE); + return 0; +} + +static int rc2_magic_to_keybits(int magic) +{ + switch (magic) { + case RC2_128_MAGIC: + return 128; + case RC2_64_MAGIC: + return 64; + case RC2_40_MAGIC: + return 40; + } + ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_KEY_SIZE); + return 0; +} + +static int rc2_einit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_einit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return rc2_set_ctx_params(ctx, params); +} + +static int rc2_dinit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_dinit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return rc2_set_ctx_params(ctx, params); +} + +static int rc2_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_RC2_CTX *ctx = (PROV_RC2_CTX *)vctx; + OSSL_PARAM *p; + + if (!ossl_cipher_generic_get_ctx_params(vctx, params)) + return 0; + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_RC2_KEYBITS); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->key_bits)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS); + if (p != NULL) { + long num; + int i; + ASN1_TYPE *type; + unsigned char *d = p->data; + unsigned char **dd = d == NULL ? NULL : &d; + + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + if ((type = ASN1_TYPE_new()) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + /* Is this the original IV or the running IV? */ + num = rc2_keybits_to_magic(ctx->key_bits); + if (!ASN1_TYPE_set_int_octetstring(type, num, + ctx->base.iv, ctx->base.ivlen)) { + ASN1_TYPE_free(type); + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + /* + * IF the caller has a buffer, we pray to the gods they got the + * size right. There's no way to tell the i2d functions... + */ + i = i2d_ASN1_TYPE(type, dd); + if (i >= 0) + p->return_size = (size_t)i; + + ASN1_TYPE_free(type); + if (i < 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + return 1; +} + +static int rc2_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_RC2_CTX *ctx = (PROV_RC2_CTX *)vctx; + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + if (!ossl_cipher_var_keylen_set_ctx_params(vctx, params)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_RC2_KEYBITS); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &ctx->key_bits)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS); + if (p != NULL) { + ASN1_TYPE *type = NULL; + long num = 0; + const unsigned char *d = p->data; + int ret = 1; + unsigned char iv[16]; + + if (p->data_type != OSSL_PARAM_OCTET_STRING + || ctx->base.ivlen > sizeof(iv) + || (type = d2i_ASN1_TYPE(NULL, &d, p->data_size)) == NULL + || ((size_t)ASN1_TYPE_get_int_octetstring(type, &num, iv, + ctx->base.ivlen) + != ctx->base.ivlen) + || !ossl_cipher_generic_initiv(&ctx->base, iv, ctx->base.ivlen) + || (ctx->key_bits = rc2_magic_to_keybits(num)) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + ret = 0; + } + ASN1_TYPE_free(type); + if (ret == 0) + return 0; + /* + * This code assumes that the caller will call + * EVP_CipherInit_ex() with a non NULL key in order to setup a key that + * uses the keylen and keybits that were set here. + */ + ctx->base.keylen = ctx->key_bits / 8; + } + return 1; +} + +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(rc2) +OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_RC2_KEYBITS, NULL), +OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS, NULL, 0), +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(rc2) + +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(rc2) +OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), +OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_RC2_KEYBITS, NULL), +OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_ALGORITHM_ID_PARAMS, NULL, 0), +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(rc2) + +#define IMPLEMENT_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits, blkbits, \ + ivbits, typ) \ +static OSSL_FUNC_cipher_get_params_fn alg##_##kbits##_##lcmode##_get_params; \ +static int alg##_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, kbits, blkbits, ivbits); \ +} \ +static OSSL_FUNC_cipher_newctx_fn alg##_##kbits##_##lcmode##_newctx; \ +static void * alg##_##kbits##_##lcmode##_newctx(void *provctx) \ +{ \ + PROV_##UCALG##_CTX *ctx; \ + if (!ossl_prov_is_running()) \ + return NULL; \ + ctx = OPENSSL_zalloc(sizeof(*ctx)); \ + if (ctx != NULL) { \ + ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits, \ + EVP_CIPH_##UCMODE##_MODE, flags, \ + ossl_prov_cipher_hw_##alg##_##lcmode(kbits), \ + NULL); \ + ctx->key_bits = kbits; \ + } \ + return ctx; \ +} \ +const OSSL_DISPATCH ossl_##alg##kbits##lcmode##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (void (*)(void)) alg##_##kbits##_##lcmode##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))rc2_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))rc2_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))ossl_cipher_generic_##typ##_update },\ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))ossl_cipher_generic_##typ##_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_cipher_generic_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void)) alg##_##kbits##_##lcmode##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))rc2_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))rc2_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))rc2_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))rc2_settable_ctx_params }, \ + { 0, NULL } \ +}; + +/* ossl_rc2128ecb_functions */ +IMPLEMENT_cipher(rc2, RC2, ecb, ECB, RC2_FLAGS, 128, 64, 0, block) +/* ossl_rc2128cbc_functions */ +IMPLEMENT_cipher(rc2, RC2, cbc, CBC, RC2_FLAGS, 128, 64, 64, block) +/* ossl_rc240cbc_functions */ +IMPLEMENT_cipher(rc2, RC2, cbc, CBC, RC2_FLAGS, 40, 64, 64, block) +/* ossl_rc264cbc_functions */ +IMPLEMENT_cipher(rc2, RC2, cbc, CBC, RC2_FLAGS, 64, 64, 64, block) + +/* ossl_rc2128ofb128_functions */ +IMPLEMENT_cipher(rc2, RC2, ofb128, OFB, RC2_FLAGS, 128, 8, 64, stream) +/* ossl_rc2128cfb128_functions */ +IMPLEMENT_cipher(rc2, RC2, cfb128, CFB, RC2_FLAGS, 128, 8, 64, stream) diff --git a/providers/implementations/ciphers/cipher_rc2.h b/providers/implementations/ciphers/cipher_rc2.h new file mode 100644 index 000000000000..7a4bea5ac404 --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc2.h @@ -0,0 +1,28 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/rc2.h> +#include "prov/ciphercommon.h" + +typedef struct prov_rc2_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + RC2_KEY ks; + } ks; + size_t key_bits; +} PROV_RC2_CTX; + +#define ossl_prov_cipher_hw_rc2_ofb128 ossl_prov_cipher_hw_rc2_ofb64 +#define ossl_prov_cipher_hw_rc2_cfb128 ossl_prov_cipher_hw_rc2_cfb64 + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc2_cbc(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc2_ecb(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc2_ofb64(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc2_cfb64(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_rc2_hw.c b/providers/implementations/ciphers/cipher_rc2_hw.c new file mode 100644 index 000000000000..da9ff729cda0 --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc2_hw.c @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * RC2 low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "cipher_rc2.h" + +static int cipher_hw_rc2_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_RC2_CTX *rctx = (PROV_RC2_CTX *)ctx; + RC2_KEY *ks = &(rctx->ks.ks); + + RC2_set_key(ks, (int)ctx->keylen, key, (int)rctx->key_bits); + return 1; +} + +# define PROV_CIPHER_HW_rc2_mode(mode, UCMODE) \ +IMPLEMENT_CIPHER_HW_##UCMODE(mode, rc2, PROV_RC2_CTX, RC2_KEY, \ + RC2_##mode) \ +static const PROV_CIPHER_HW rc2_##mode = { \ + cipher_hw_rc2_initkey, \ + cipher_hw_rc2_##mode##_cipher \ +}; \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc2_##mode(size_t keybits) \ +{ \ + return &rc2_##mode; \ +} + +PROV_CIPHER_HW_rc2_mode(cbc, CBC) +PROV_CIPHER_HW_rc2_mode(ecb, ECB) +PROV_CIPHER_HW_rc2_mode(ofb64, OFB) +PROV_CIPHER_HW_rc2_mode(cfb64, CFB) diff --git a/providers/implementations/ciphers/cipher_rc4.c b/providers/implementations/ciphers/cipher_rc4.c new file mode 100644 index 000000000000..a548beafaf5f --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc4.c @@ -0,0 +1,121 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for RC4 ciphers */ + +/* + * RC4 low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "cipher_rc4.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define RC4_FLAGS PROV_CIPHER_FLAG_VARIABLE_LENGTH + +static OSSL_FUNC_cipher_encrypt_init_fn rc4_einit; +static OSSL_FUNC_cipher_decrypt_init_fn rc4_dinit; +static OSSL_FUNC_cipher_freectx_fn rc4_freectx; +static OSSL_FUNC_cipher_dupctx_fn rc4_dupctx; + +static void rc4_freectx(void *vctx) +{ + PROV_RC4_CTX *ctx = (PROV_RC4_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *rc4_dupctx(void *ctx) +{ + PROV_RC4_CTX *in = (PROV_RC4_CTX *)ctx; + PROV_RC4_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + *ret = *in; + + return ret; +} + +static int rc4_einit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_einit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return ossl_cipher_var_keylen_set_ctx_params(ctx, params); +} + +static int rc4_dinit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_dinit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return ossl_cipher_var_keylen_set_ctx_params(ctx, params); +} + +#define IMPLEMENT_cipher(alg, UCALG, flags, kbits, blkbits, ivbits, typ) \ +static OSSL_FUNC_cipher_get_params_fn alg##_##kbits##_get_params; \ +static int alg##_##kbits##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, 0, flags, \ + kbits, blkbits, ivbits); \ +} \ +static OSSL_FUNC_cipher_newctx_fn alg##_##kbits##_newctx; \ +static void * alg##_##kbits##_newctx(void *provctx) \ +{ \ + PROV_##UCALG##_CTX *ctx; \ + if (!ossl_prov_is_running()) \ + return NULL; \ + ctx = OPENSSL_zalloc(sizeof(*ctx)); \ + if (ctx != NULL) { \ + ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits, 0, flags, \ + ossl_prov_cipher_hw_##alg(kbits), NULL); \ + } \ + return ctx; \ +} \ +const OSSL_DISPATCH ossl_##alg##kbits##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (void (*)(void)) alg##_##kbits##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))rc4_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))rc4_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))ossl_cipher_generic_##typ##_update },\ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))ossl_cipher_generic_##typ##_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_cipher_generic_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void)) alg##_##kbits##_get_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_var_keylen_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_var_keylen_settable_ctx_params }, \ + { 0, NULL } \ +}; + +/* ossl_rc440_functions */ +IMPLEMENT_cipher(rc4, RC4, RC4_FLAGS, 40, 8, 0, stream) +/* ossl_rc4128_functions */ +IMPLEMENT_cipher(rc4, RC4, RC4_FLAGS, 128, 8, 0, stream) diff --git a/providers/implementations/ciphers/cipher_rc4.h b/providers/implementations/ciphers/cipher_rc4.h new file mode 100644 index 000000000000..40d822ceb2ef --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc4.h @@ -0,0 +1,21 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/rc4.h> +#include "prov/ciphercommon.h" + +typedef struct prov_rc4_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + RC4_KEY ks; + } ks; +} PROV_RC4_CTX; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc4(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_rc4_hmac_md5.c b/providers/implementations/ciphers/cipher_rc4_hmac_md5.c new file mode 100644 index 000000000000..c46c6eab63e0 --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc4_hmac_md5.c @@ -0,0 +1,234 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for RC4_HMAC_MD5 cipher */ + +/* + * MD5 and RC4 low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/proverr.h> +#include "cipher_rc4_hmac_md5.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define RC4_HMAC_MD5_FLAGS (PROV_CIPHER_FLAG_VARIABLE_LENGTH \ + | PROV_CIPHER_FLAG_AEAD) + +#define RC4_HMAC_MD5_KEY_BITS (16 * 8) +#define RC4_HMAC_MD5_BLOCK_BITS (1 * 8) +#define RC4_HMAC_MD5_IV_BITS 0 +#define RC4_HMAC_MD5_MODE 0 + +#define GET_HW(ctx) ((PROV_CIPHER_HW_RC4_HMAC_MD5 *)ctx->base.hw) + +static OSSL_FUNC_cipher_encrypt_init_fn rc4_hmac_md5_einit; +static OSSL_FUNC_cipher_decrypt_init_fn rc4_hmac_md5_dinit; +static OSSL_FUNC_cipher_newctx_fn rc4_hmac_md5_newctx; +static OSSL_FUNC_cipher_freectx_fn rc4_hmac_md5_freectx; +static OSSL_FUNC_cipher_get_ctx_params_fn rc4_hmac_md5_get_ctx_params; +static OSSL_FUNC_cipher_gettable_ctx_params_fn rc4_hmac_md5_gettable_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn rc4_hmac_md5_set_ctx_params; +static OSSL_FUNC_cipher_settable_ctx_params_fn rc4_hmac_md5_settable_ctx_params; +static OSSL_FUNC_cipher_get_params_fn rc4_hmac_md5_get_params; +#define rc4_hmac_md5_gettable_params ossl_cipher_generic_gettable_params +#define rc4_hmac_md5_update ossl_cipher_generic_stream_update +#define rc4_hmac_md5_final ossl_cipher_generic_stream_final +#define rc4_hmac_md5_cipher ossl_cipher_generic_cipher + +static void *rc4_hmac_md5_newctx(void *provctx) +{ + PROV_RC4_HMAC_MD5_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + ossl_cipher_generic_initkey(ctx, RC4_HMAC_MD5_KEY_BITS, + RC4_HMAC_MD5_BLOCK_BITS, + RC4_HMAC_MD5_IV_BITS, + RC4_HMAC_MD5_MODE, RC4_HMAC_MD5_FLAGS, + ossl_prov_cipher_hw_rc4_hmac_md5( + RC4_HMAC_MD5_KEY_BITS + ), NULL); + return ctx; +} + +static void rc4_hmac_md5_freectx(void *vctx) +{ + PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static int rc4_hmac_md5_einit(void *ctx, const unsigned char *key, + size_t keylen, const unsigned char *iv, + size_t ivlen, const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_einit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return rc4_hmac_md5_set_ctx_params(ctx, params); +} + +static int rc4_hmac_md5_dinit(void *ctx, const unsigned char *key, + size_t keylen, const unsigned char *iv, + size_t ivlen, const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_dinit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return rc4_hmac_md5_set_ctx_params(ctx, params); +} + +static const OSSL_PARAM rc4_hmac_md5_known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL), + OSSL_PARAM_END +}; +const OSSL_PARAM *rc4_hmac_md5_gettable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return rc4_hmac_md5_known_gettable_ctx_params; +} + +static int rc4_hmac_md5_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)vctx; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + return 1; +} + +static const OSSL_PARAM rc4_hmac_md5_known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD, NULL, 0), + OSSL_PARAM_END +}; +const OSSL_PARAM *rc4_hmac_md5_settable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return rc4_hmac_md5_known_settable_ctx_params; +} + +static int rc4_hmac_md5_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)vctx; + const OSSL_PARAM *p; + size_t sz; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ctx->base.keylen != sz) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ctx->base.ivlen != sz) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + sz = GET_HW(ctx)->tls_init(&ctx->base, p->data, p->data_size); + if (sz == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA); + return 0; + } + ctx->tls_aad_pad_sz = sz; + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_MAC_KEY); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + GET_HW(ctx)->init_mackey(&ctx->base, p->data, p->data_size); + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS_VERSION); + if (p != NULL) { + if (!OSSL_PARAM_get_uint(p, &ctx->base.tlsversion)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + + return 1; +} + +static int rc4_hmac_md5_get_params(OSSL_PARAM params[]) +{ + return ossl_cipher_generic_get_params(params, RC4_HMAC_MD5_MODE, + RC4_HMAC_MD5_FLAGS, + RC4_HMAC_MD5_KEY_BITS, + RC4_HMAC_MD5_BLOCK_BITS, + RC4_HMAC_MD5_IV_BITS); +} + +const OSSL_DISPATCH ossl_rc4_hmac_ossl_md5_functions[] = { + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))rc4_hmac_md5_newctx }, + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))rc4_hmac_md5_freectx }, + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))rc4_hmac_md5_einit }, + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))rc4_hmac_md5_dinit }, + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))rc4_hmac_md5_update }, + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))rc4_hmac_md5_final }, + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))rc4_hmac_md5_cipher }, + { OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))rc4_hmac_md5_get_params }, + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, + (void (*)(void))rc4_hmac_md5_gettable_params }, + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, + (void (*)(void))rc4_hmac_md5_get_ctx_params }, + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, + (void (*)(void))rc4_hmac_md5_gettable_ctx_params }, + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, + (void (*)(void))rc4_hmac_md5_set_ctx_params }, + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, + (void (*)(void))rc4_hmac_md5_settable_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/ciphers/cipher_rc4_hmac_md5.h b/providers/implementations/ciphers/cipher_rc4_hmac_md5.h new file mode 100644 index 000000000000..1697aabbf39b --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc4_hmac_md5.h @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/rc4.h> +#include <openssl/md5.h> +#include "prov/ciphercommon.h" + +typedef struct prov_rc4_hmac_md5_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + RC4_KEY ks; + } ks; + MD5_CTX head, tail, md; + size_t payload_length; + size_t tls_aad_pad_sz; +} PROV_RC4_HMAC_MD5_CTX; + +typedef struct prov_cipher_hw_rc4_hmac_md5_st { + PROV_CIPHER_HW base; /* Must be first */ + int (*tls_init)(PROV_CIPHER_CTX *ctx, unsigned char *aad, size_t aad_len); + void (*init_mackey)(PROV_CIPHER_CTX *ctx, const unsigned char *key, + size_t len); + +} PROV_CIPHER_HW_RC4_HMAC_MD5; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc4_hmac_md5(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_rc4_hmac_md5_hw.c b/providers/implementations/ciphers/cipher_rc4_hmac_md5_hw.c new file mode 100644 index 000000000000..8cce02b1c5af --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc4_hmac_md5_hw.c @@ -0,0 +1,233 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* RC4_HMAC_MD5 cipher implementation */ + +/* + * MD5 and RC4 low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include "cipher_rc4_hmac_md5.h" + +#define NO_PAYLOAD_LENGTH ((size_t)-1) + +#if defined(RC4_ASM) \ + && defined(MD5_ASM) \ + && (defined(__x86_64) \ + || defined(__x86_64__) \ + || defined(_M_AMD64) \ + || defined(_M_X64)) +# define STITCHED_CALL +# define MOD 32 /* 32 is $MOD from rc4_md5-x86_64.pl */ +#else +# define rc4_off 0 +# define md5_off 0 +#endif + +static int cipher_hw_rc4_hmac_md5_initkey(PROV_CIPHER_CTX *bctx, + const uint8_t *key, size_t keylen) +{ + PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)bctx; + + RC4_set_key(&ctx->ks.ks, keylen, key); + MD5_Init(&ctx->head); /* handy when benchmarking */ + ctx->tail = ctx->head; + ctx->md = ctx->head; + ctx->payload_length = NO_PAYLOAD_LENGTH; + bctx->removetlsfixed = MD5_DIGEST_LENGTH; + return 1; +} + +static int cipher_hw_rc4_hmac_md5_cipher(PROV_CIPHER_CTX *bctx, + unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)bctx; + RC4_KEY *ks = &ctx->ks.ks; + +#if defined(STITCHED_CALL) + size_t rc4_off = MOD - 1 - (ks->x & (MOD - 1)); + size_t md5_off = MD5_CBLOCK - ctx->md.num, blocks; + unsigned int l; +#endif + size_t plen = ctx->payload_length; + + if (plen != NO_PAYLOAD_LENGTH && len != (plen + MD5_DIGEST_LENGTH)) + return 0; + + if (ctx->base.enc) { + if (plen == NO_PAYLOAD_LENGTH) + plen = len; +#if defined(STITCHED_CALL) + /* cipher has to "fall behind" */ + if (rc4_off > md5_off) + md5_off += MD5_CBLOCK; + + if (plen > md5_off + && (blocks = (plen - md5_off) / MD5_CBLOCK) + && (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { + MD5_Update(&ctx->md, in, md5_off); + RC4(ks, rc4_off, in, out); + + rc4_md5_enc(ks, in + rc4_off, out + rc4_off, + &ctx->md, in + md5_off, blocks); + blocks *= MD5_CBLOCK; + rc4_off += blocks; + md5_off += blocks; + ctx->md.Nh += blocks >> 29; + ctx->md.Nl += blocks <<= 3; + if (ctx->md.Nl < (unsigned int)blocks) + ctx->md.Nh++; + } else { + rc4_off = 0; + md5_off = 0; + } +#endif + MD5_Update(&ctx->md, in + md5_off, plen - md5_off); + + if (plen != len) { /* "TLS" mode of operation */ + if (in != out) + memcpy(out + rc4_off, in + rc4_off, plen - rc4_off); + + /* calculate HMAC and append it to payload */ + MD5_Final(out + plen, &ctx->md); + ctx->md = ctx->tail; + MD5_Update(&ctx->md, out + plen, MD5_DIGEST_LENGTH); + MD5_Final(out + plen, &ctx->md); + /* encrypt HMAC at once */ + RC4(ks, len - rc4_off, out + rc4_off, out + rc4_off); + } else { + RC4(ks, len - rc4_off, in + rc4_off, out + rc4_off); + } + } else { + unsigned char mac[MD5_DIGEST_LENGTH]; + +#if defined(STITCHED_CALL) + /* digest has to "fall behind" */ + if (md5_off > rc4_off) + rc4_off += 2 * MD5_CBLOCK; + else + rc4_off += MD5_CBLOCK; + + if (len > rc4_off + && (blocks = (len - rc4_off) / MD5_CBLOCK) + && (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { + RC4(ks, rc4_off, in, out); + MD5_Update(&ctx->md, out, md5_off); + + rc4_md5_enc(ks, in + rc4_off, out + rc4_off, + &ctx->md, out + md5_off, blocks); + blocks *= MD5_CBLOCK; + rc4_off += blocks; + md5_off += blocks; + l = (ctx->md.Nl + (blocks << 3)) & 0xffffffffU; + if (l < ctx->md.Nl) + ctx->md.Nh++; + ctx->md.Nl = l; + ctx->md.Nh += blocks >> 29; + } else { + md5_off = 0; + rc4_off = 0; + } +#endif + /* decrypt HMAC at once */ + RC4(ks, len - rc4_off, in + rc4_off, out + rc4_off); + if (plen != NO_PAYLOAD_LENGTH) { + /* "TLS" mode of operation */ + MD5_Update(&ctx->md, out + md5_off, plen - md5_off); + + /* calculate HMAC and verify it */ + MD5_Final(mac, &ctx->md); + ctx->md = ctx->tail; + MD5_Update(&ctx->md, mac, MD5_DIGEST_LENGTH); + MD5_Final(mac, &ctx->md); + + if (CRYPTO_memcmp(out + plen, mac, MD5_DIGEST_LENGTH)) + return 0; + } else { + MD5_Update(&ctx->md, out + md5_off, len - md5_off); + } + } + + ctx->payload_length = NO_PAYLOAD_LENGTH; + + return 1; +} + +static int cipher_hw_rc4_hmac_md5_tls_init(PROV_CIPHER_CTX *bctx, + unsigned char *aad, size_t aad_len) +{ + PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)bctx; + unsigned int len; + + if (aad_len != EVP_AEAD_TLS1_AAD_LEN) + return 0; + + len = aad[aad_len - 2] << 8 | aad[aad_len - 1]; + + if (!bctx->enc) { + if (len < MD5_DIGEST_LENGTH) + return 0; + len -= MD5_DIGEST_LENGTH; + aad[aad_len - 2] = len >> 8; + aad[aad_len - 1] = len; + } + ctx->payload_length = len; + ctx->md = ctx->head; + MD5_Update(&ctx->md, aad, aad_len); + + return MD5_DIGEST_LENGTH; +} + +static void cipher_hw_rc4_hmac_md5_init_mackey(PROV_CIPHER_CTX *bctx, + const unsigned char *key, + size_t len) +{ + PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)bctx; + unsigned int i; + unsigned char hmac_key[64]; + + memset(hmac_key, 0, sizeof(hmac_key)); + + if (len > (int)sizeof(hmac_key)) { + MD5_Init(&ctx->head); + MD5_Update(&ctx->head, key, len); + MD5_Final(hmac_key, &ctx->head); + } else { + memcpy(hmac_key, key, len); + } + + for (i = 0; i < sizeof(hmac_key); i++) + hmac_key[i] ^= 0x36; /* ipad */ + MD5_Init(&ctx->head); + MD5_Update(&ctx->head, hmac_key, sizeof(hmac_key)); + + for (i = 0; i < sizeof(hmac_key); i++) + hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */ + MD5_Init(&ctx->tail); + MD5_Update(&ctx->tail, hmac_key, sizeof(hmac_key)); + + OPENSSL_cleanse(hmac_key, sizeof(hmac_key)); +} + +static const PROV_CIPHER_HW_RC4_HMAC_MD5 rc4_hmac_md5_hw = { + { + cipher_hw_rc4_hmac_md5_initkey, + cipher_hw_rc4_hmac_md5_cipher + }, + cipher_hw_rc4_hmac_md5_tls_init, + cipher_hw_rc4_hmac_md5_init_mackey +}; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc4_hmac_md5(size_t keybits) +{ + return (PROV_CIPHER_HW *)&rc4_hmac_md5_hw; +} diff --git a/providers/implementations/ciphers/cipher_rc4_hw.c b/providers/implementations/ciphers/cipher_rc4_hw.c new file mode 100644 index 000000000000..09192b5d5e14 --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc4_hw.c @@ -0,0 +1,44 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * RC4 low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "cipher_rc4.h" + +static int cipher_hw_rc4_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_RC4_CTX *rctx = (PROV_RC4_CTX *)ctx; + + RC4_set_key(&rctx->ks.ks, keylen, key); + return 1; +} + +static int cipher_hw_rc4_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_RC4_CTX *rctx = (PROV_RC4_CTX *)ctx; + + RC4(&rctx->ks.ks, len, in, out); + return 1; +} + +static const PROV_CIPHER_HW rc4_hw = { + cipher_hw_rc4_initkey, + cipher_hw_rc4_cipher +}; +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc4(size_t keybits) +{ + return &rc4_hw; +} + diff --git a/providers/implementations/ciphers/cipher_rc5.c b/providers/implementations/ciphers/cipher_rc5.c new file mode 100644 index 000000000000..5c7d2b1721c0 --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc5.c @@ -0,0 +1,188 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for RC5 cipher modes ecb, cbc, ofb, cfb */ + +/* + * RC5 low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include <openssl/proverr.h> +#include "cipher_rc5.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define RC5_FLAGS PROV_CIPHER_FLAG_VARIABLE_LENGTH + +static OSSL_FUNC_cipher_encrypt_init_fn rc5_einit; +static OSSL_FUNC_cipher_decrypt_init_fn rc5_dinit; +static OSSL_FUNC_cipher_freectx_fn rc5_freectx; +static OSSL_FUNC_cipher_dupctx_fn rc5_dupctx; +OSSL_FUNC_cipher_gettable_ctx_params_fn rc5_gettable_ctx_params; +OSSL_FUNC_cipher_settable_ctx_params_fn rc5_settable_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn rc5_set_ctx_params; + +static void rc5_freectx(void *vctx) +{ + PROV_RC5_CTX *ctx = (PROV_RC5_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *rc5_dupctx(void *ctx) +{ + PROV_RC5_CTX *in = (PROV_RC5_CTX *)ctx; + PROV_RC5_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + *ret = *in; + + return ret; +} + +static int rc5_einit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_einit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return rc5_set_ctx_params(ctx, params); +} + +static int rc5_dinit(void *ctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + if (!ossl_cipher_generic_dinit(ctx, key, keylen, iv, ivlen, NULL)) + return 0; + return rc5_set_ctx_params(ctx, params); +} + +static int rc5_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_RC5_CTX *ctx = (PROV_RC5_CTX *)vctx; + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + if (!ossl_cipher_var_keylen_set_ctx_params(vctx, params)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_ROUNDS); + if (p != NULL) { + unsigned int rounds; + + if (!OSSL_PARAM_get_uint(p, &rounds)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (rounds != RC5_8_ROUNDS + && rounds != RC5_12_ROUNDS + && rounds != RC5_16_ROUNDS) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS); + return 0; + } + ctx->rounds = rounds; + } + return 1; +} + +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(rc5) + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_ROUNDS, NULL), +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(rc5) + +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(rc5) + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_ROUNDS, NULL), +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(rc5) + + +static int rc5_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_RC5_CTX *ctx = (PROV_RC5_CTX *)vctx; + OSSL_PARAM *p; + + if (!ossl_cipher_generic_get_ctx_params(vctx, params)) + return 0; + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_ROUNDS); + if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->rounds)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + return 1; +} + +#define IMPLEMENT_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits, \ + blkbits, ivbits, typ) \ +static OSSL_FUNC_cipher_get_params_fn alg##_##kbits##_##lcmode##_get_params; \ +static int alg##_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, kbits, blkbits, ivbits); \ +} \ +static OSSL_FUNC_cipher_newctx_fn alg##_##kbits##_##lcmode##_newctx; \ +static void * alg##_##kbits##_##lcmode##_newctx(void *provctx) \ +{ \ + PROV_##UCALG##_CTX *ctx; \ + if (!ossl_prov_is_running()) \ + return NULL; \ + ctx = OPENSSL_zalloc(sizeof(*ctx)); \ + if (ctx != NULL) { \ + ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits, \ + EVP_CIPH_##UCMODE##_MODE, flags, \ + ossl_prov_cipher_hw_##alg##_##lcmode(kbits),\ + NULL); \ + ctx->rounds = RC5_12_ROUNDS; \ + } \ + return ctx; \ +} \ +const OSSL_DISPATCH ossl_##alg##kbits##lcmode##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (void (*)(void)) alg##_##kbits##_##lcmode##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))rc5_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))rc5_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))ossl_cipher_generic_##typ##_update },\ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))ossl_cipher_generic_##typ##_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_cipher_generic_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void)) alg##_##kbits##_##lcmode##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))rc5_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))rc5_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))rc5_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))rc5_settable_ctx_params }, \ + { 0, NULL } \ +}; + +/* ossl_rc5128ecb_functions */ +IMPLEMENT_cipher(rc5, RC5, ecb, ECB, RC5_FLAGS, 128, 64, 0, block) +/* ossl_rc5128cbc_functions */ +IMPLEMENT_cipher(rc5, RC5, cbc, CBC, RC5_FLAGS, 128, 64, 64, block) +/* ossl_rc5128ofb64_functions */ +IMPLEMENT_cipher(rc5, RC5, ofb64, OFB, RC5_FLAGS, 128, 8, 64, stream) +/* ossl_rc5128cfb64_functions */ +IMPLEMENT_cipher(rc5, RC5, cfb64, CFB, RC5_FLAGS, 128, 8, 64, stream) diff --git a/providers/implementations/ciphers/cipher_rc5.h b/providers/implementations/ciphers/cipher_rc5.h new file mode 100644 index 000000000000..c630e7c87bf9 --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc5.h @@ -0,0 +1,25 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/rc5.h> +#include "prov/ciphercommon.h" + +typedef struct prov_blowfish_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + RC5_32_KEY ks; /* key schedule */ + } ks; + unsigned int rounds; /* number of rounds */ +} PROV_RC5_CTX; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc5_cbc(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc5_ecb(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc5_ofb64(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc5_cfb64(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_rc5_hw.c b/providers/implementations/ciphers/cipher_rc5_hw.c new file mode 100644 index 000000000000..898bd383f95a --- /dev/null +++ b/providers/implementations/ciphers/cipher_rc5_hw.c @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * RC5 low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "cipher_rc5.h" + +static int cipher_hw_rc5_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_RC5_CTX *rctx = (PROV_RC5_CTX *)ctx; + + return RC5_32_set_key(&rctx->ks.ks, keylen, key, rctx->rounds); +} + +# define PROV_CIPHER_HW_rc5_mode(mode, UCMODE) \ +IMPLEMENT_CIPHER_HW_##UCMODE(mode, rc5, PROV_RC5_CTX, RC5_32_KEY, \ + RC5_32_##mode) \ +static const PROV_CIPHER_HW rc5_##mode = { \ + cipher_hw_rc5_initkey, \ + cipher_hw_rc5_##mode##_cipher \ +}; \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_rc5_##mode(size_t keybits) \ +{ \ + return &rc5_##mode; \ +} + +PROV_CIPHER_HW_rc5_mode(cbc, CBC) +PROV_CIPHER_HW_rc5_mode(ecb, ECB) +PROV_CIPHER_HW_rc5_mode(ofb64, OFB) +PROV_CIPHER_HW_rc5_mode(cfb64, CFB) diff --git a/providers/implementations/ciphers/cipher_seed.c b/providers/implementations/ciphers/cipher_seed.c new file mode 100644 index 000000000000..bae6a8e530ba --- /dev/null +++ b/providers/implementations/ciphers/cipher_seed.c @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for Seed cipher modes ecb, cbc, ofb, cfb */ + +/* + * SEED low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include "cipher_seed.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +static OSSL_FUNC_cipher_freectx_fn seed_freectx; +static OSSL_FUNC_cipher_dupctx_fn seed_dupctx; + +static void seed_freectx(void *vctx) +{ + PROV_SEED_CTX *ctx = (PROV_SEED_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *seed_dupctx(void *ctx) +{ + PROV_SEED_CTX *in = (PROV_SEED_CTX *)ctx; + PROV_SEED_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + *ret = *in; + + return ret; +} + +/* ossl_seed128ecb_functions */ +IMPLEMENT_generic_cipher(seed, SEED, ecb, ECB, 0, 128, 128, 0, block) +/* ossl_seed128cbc_functions */ +IMPLEMENT_generic_cipher(seed, SEED, cbc, CBC, 0, 128, 128, 128, block) +/* ossl_seed128ofb128_functions */ +IMPLEMENT_generic_cipher(seed, SEED, ofb128, OFB, 0, 128, 8, 128, stream) +/* ossl_seed128cfb128_functions */ +IMPLEMENT_generic_cipher(seed, SEED, cfb128, CFB, 0, 128, 8, 128, stream) diff --git a/providers/implementations/ciphers/cipher_seed.h b/providers/implementations/ciphers/cipher_seed.h new file mode 100644 index 000000000000..9006a9183b55 --- /dev/null +++ b/providers/implementations/ciphers/cipher_seed.h @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/seed.h> +#include "prov/ciphercommon.h" + +typedef struct prov_seed_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + SEED_KEY_SCHEDULE ks; + } ks; +} PROV_SEED_CTX; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_seed_cbc(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_seed_ecb(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_seed_ofb128(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_seed_cfb128(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_seed_hw.c b/providers/implementations/ciphers/cipher_seed_hw.c new file mode 100644 index 000000000000..2d1dba92bc73 --- /dev/null +++ b/providers/implementations/ciphers/cipher_seed_hw.c @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * SEED low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include "cipher_seed.h" + +static int cipher_hw_seed_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_SEED_CTX *sctx = (PROV_SEED_CTX *)ctx; + + SEED_set_key(key, &(sctx->ks.ks)); + return 1; +} + +# define PROV_CIPHER_HW_seed_mode(mode, UCMODE) \ +IMPLEMENT_CIPHER_HW_##UCMODE(mode, seed, PROV_SEED_CTX, SEED_KEY_SCHEDULE, \ + SEED_##mode) \ +static const PROV_CIPHER_HW seed_##mode = { \ + cipher_hw_seed_initkey, \ + cipher_hw_seed_##mode##_cipher \ +}; \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_seed_##mode(size_t keybits) \ +{ \ + return &seed_##mode; \ +} + +PROV_CIPHER_HW_seed_mode(cbc, CBC) +PROV_CIPHER_HW_seed_mode(ecb, ECB) +PROV_CIPHER_HW_seed_mode(ofb128, OFB) +PROV_CIPHER_HW_seed_mode(cfb128, CFB) diff --git a/providers/implementations/ciphers/cipher_sm4.c b/providers/implementations/ciphers/cipher_sm4.c new file mode 100644 index 000000000000..6cf2731c6d5d --- /dev/null +++ b/providers/implementations/ciphers/cipher_sm4.c @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for cast cipher modes ecb, cbc, ofb, cfb */ + +#include "cipher_sm4.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +static OSSL_FUNC_cipher_freectx_fn sm4_freectx; +static OSSL_FUNC_cipher_dupctx_fn sm4_dupctx; + +static void sm4_freectx(void *vctx) +{ + PROV_SM4_CTX *ctx = (PROV_SM4_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *sm4_dupctx(void *ctx) +{ + PROV_SM4_CTX *in = (PROV_SM4_CTX *)ctx; + PROV_SM4_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + in->base.hw->copyctx(&ret->base, &in->base); + + return ret; +} + +/* ossl_sm4128ecb_functions */ +IMPLEMENT_generic_cipher(sm4, SM4, ecb, ECB, 0, 128, 128, 0, block) +/* ossl_sm4128cbc_functions */ +IMPLEMENT_generic_cipher(sm4, SM4, cbc, CBC, 0, 128, 128, 128, block) +/* ossl_sm4128ctr_functions */ +IMPLEMENT_generic_cipher(sm4, SM4, ctr, CTR, 0, 128, 8, 128, stream) +/* ossl_sm4128ofb128_functions */ +IMPLEMENT_generic_cipher(sm4, SM4, ofb128, OFB, 0, 128, 8, 128, stream) +/* ossl_sm4128cfb128_functions */ +IMPLEMENT_generic_cipher(sm4, SM4, cfb128, CFB, 0, 128, 8, 128, stream) diff --git a/providers/implementations/ciphers/cipher_sm4.h b/providers/implementations/ciphers/cipher_sm4.h new file mode 100644 index 000000000000..f7f833fcb4cf --- /dev/null +++ b/providers/implementations/ciphers/cipher_sm4.h @@ -0,0 +1,25 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/ciphercommon.h" +#include "crypto/sm4.h" + +typedef struct prov_cast_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + SM4_KEY ks; + } ks; +} PROV_SM4_CTX; + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_sm4_cbc(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_sm4_ecb(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_sm4_ctr(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_sm4_ofb128(size_t keybits); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_sm4_cfb128(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_sm4_hw.c b/providers/implementations/ciphers/cipher_sm4_hw.c new file mode 100644 index 000000000000..0db04b1a743b --- /dev/null +++ b/providers/implementations/ciphers/cipher_sm4_hw.c @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "cipher_sm4.h" + +static int cipher_hw_sm4_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_SM4_CTX *sctx = (PROV_SM4_CTX *)ctx; + SM4_KEY *ks = &sctx->ks.ks; + + ossl_sm4_set_key(key, ks); + ctx->ks = ks; + if (ctx->enc + || (ctx->mode != EVP_CIPH_ECB_MODE + && ctx->mode != EVP_CIPH_CBC_MODE)) + ctx->block = (block128_f)ossl_sm4_encrypt; + else + ctx->block = (block128_f)ossl_sm4_decrypt; + return 1; +} + +IMPLEMENT_CIPHER_HW_COPYCTX(cipher_hw_sm4_copyctx, PROV_SM4_CTX) + +# define PROV_CIPHER_HW_sm4_mode(mode) \ +static const PROV_CIPHER_HW sm4_##mode = { \ + cipher_hw_sm4_initkey, \ + ossl_cipher_hw_chunked_##mode, \ + cipher_hw_sm4_copyctx \ +}; \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_sm4_##mode(size_t keybits) \ +{ \ + return &sm4_##mode; \ +} + +PROV_CIPHER_HW_sm4_mode(cbc) +PROV_CIPHER_HW_sm4_mode(ecb) +PROV_CIPHER_HW_sm4_mode(ofb128) +PROV_CIPHER_HW_sm4_mode(cfb128) +PROV_CIPHER_HW_sm4_mode(ctr) diff --git a/providers/implementations/ciphers/cipher_tdes.c b/providers/implementations/ciphers/cipher_tdes.c new file mode 100644 index 000000000000..2e5f8c3f05bb --- /dev/null +++ b/providers/implementations/ciphers/cipher_tdes.c @@ -0,0 +1,25 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include <openssl/rand.h> +#include <openssl/proverr.h> +#include "prov/ciphercommon.h" +#include "cipher_tdes.h" +#include "prov/implementations.h" + +/* ossl_tdes_ede3_ecb_functions */ +IMPLEMENT_tdes_cipher(ede3, EDE3, ecb, ECB, TDES_FLAGS, 64*3, 64, 0, block); +/* ossl_tdes_ede3_cbc_functions */ +IMPLEMENT_tdes_cipher(ede3, EDE3, cbc, CBC, TDES_FLAGS, 64*3, 64, 64, block); diff --git a/providers/implementations/ciphers/cipher_tdes.h b/providers/implementations/ciphers/cipher_tdes.h new file mode 100644 index 000000000000..93f9d1744dc9 --- /dev/null +++ b/providers/implementations/ciphers/cipher_tdes.h @@ -0,0 +1,103 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/des.h> +#include <openssl/core_dispatch.h> +#include "crypto/des_platform.h" + +#define DES_BLOCK_SIZE 8 +#define TDES_IVLEN 8 +#define TDES_FLAGS PROV_CIPHER_FLAG_RAND_KEY + +typedef struct prov_tdes_ctx_st { + PROV_CIPHER_CTX base; /* Must be first */ + union { + OSSL_UNION_ALIGN; + DES_key_schedule ks[3]; + } tks; + union { + void (*cbc) (const void *, void *, size_t, + const DES_key_schedule *, unsigned char *); + } tstream; + +} PROV_TDES_CTX; + +#define IMPLEMENT_tdes_cipher(type, UCTYPE, lcmode, UCMODE, flags, \ + kbits, blkbits, ivbits, block) \ +static OSSL_FUNC_cipher_newctx_fn tdes_##type##_##lcmode##_newctx; \ +static void *tdes_##type##_##lcmode##_newctx(void *provctx) \ +{ \ + return ossl_tdes_newctx(provctx, EVP_CIPH_##UCMODE##_MODE, kbits, blkbits, \ + ivbits, flags, \ + ossl_prov_cipher_hw_tdes_##type##_##lcmode()); \ +} \ +static OSSL_FUNC_cipher_get_params_fn tdes_##type##_##lcmode##_get_params; \ +static int tdes_##type##_##lcmode##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, kbits, blkbits, ivbits); \ +} \ +const OSSL_DISPATCH ossl_tdes_##type##_##lcmode##_functions[] = { \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))ossl_tdes_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))ossl_tdes_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, \ + (void (*)(void))ossl_cipher_generic_##block##_update }, \ + { OSSL_FUNC_CIPHER_FINAL, \ + (void (*)(void))ossl_cipher_generic_##block##_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_cipher_generic_cipher }, \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (void (*)(void))tdes_##type##_##lcmode##_newctx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))ossl_tdes_dupctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))ossl_tdes_freectx }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void))tdes_##type##_##lcmode##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))ossl_tdes_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_tdes_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_settable_ctx_params }, \ + { 0, NULL } \ +} + +void *ossl_tdes_newctx(void *provctx, int mode, size_t kbits, size_t blkbits, + size_t ivbits, uint64_t flags, const PROV_CIPHER_HW *hw); +OSSL_FUNC_cipher_dupctx_fn ossl_tdes_dupctx; +OSSL_FUNC_cipher_freectx_fn ossl_tdes_freectx; +OSSL_FUNC_cipher_encrypt_init_fn ossl_tdes_einit; +OSSL_FUNC_cipher_decrypt_init_fn ossl_tdes_dinit; +OSSL_FUNC_cipher_get_ctx_params_fn ossl_tdes_get_ctx_params; +OSSL_FUNC_cipher_gettable_ctx_params_fn ossl_tdes_gettable_ctx_params; + +#define PROV_CIPHER_HW_tdes_mode(type, mode) \ +static const PROV_CIPHER_HW type##_##mode = { \ + ossl_cipher_hw_tdes_##type##_initkey, \ + ossl_cipher_hw_tdes_##mode, \ + ossl_cipher_hw_tdes_copyctx \ +}; \ +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_##type##_##mode(void) \ +{ \ + return &type##_##mode; \ +} + +int ossl_cipher_hw_tdes_ede3_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen); +void ossl_cipher_hw_tdes_copyctx(PROV_CIPHER_CTX *dst, + const PROV_CIPHER_CTX *src); +int ossl_cipher_hw_tdes_cbc(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl); +int ossl_cipher_hw_tdes_ecb(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_ede3_cbc(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_ede3_ecb(void); diff --git a/providers/implementations/ciphers/cipher_tdes_common.c b/providers/implementations/ciphers/cipher_tdes_common.c new file mode 100644 index 000000000000..346aec05a1cc --- /dev/null +++ b/providers/implementations/ciphers/cipher_tdes_common.c @@ -0,0 +1,149 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include <openssl/rand.h> +#include <openssl/proverr.h> +#include "prov/ciphercommon.h" +#include "cipher_tdes.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +void *ossl_tdes_newctx(void *provctx, int mode, size_t kbits, size_t blkbits, + size_t ivbits, uint64_t flags, const PROV_CIPHER_HW *hw) +{ + PROV_TDES_CTX *tctx; + + if (!ossl_prov_is_running()) + return NULL; + + tctx = OPENSSL_zalloc(sizeof(*tctx)); + if (tctx != NULL) + ossl_cipher_generic_initkey(tctx, kbits, blkbits, ivbits, mode, flags, + hw, provctx); + return tctx; +} + +void *ossl_tdes_dupctx(void *ctx) +{ + PROV_TDES_CTX *in = (PROV_TDES_CTX *)ctx; + PROV_TDES_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + ret = OPENSSL_malloc(sizeof(*ret)); + if (ret == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + in->base.hw->copyctx(&ret->base, &in->base); + + return ret; +} + +void ossl_tdes_freectx(void *vctx) +{ + PROV_TDES_CTX *ctx = (PROV_TDES_CTX *)vctx; + + ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static int tdes_init(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[], int enc) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + ctx->num = 0; + ctx->bufsz = 0; + ctx->enc = enc; + + if (iv != NULL) { + if (!ossl_cipher_generic_initiv(ctx, iv, ivlen)) + return 0; + } else if (ctx->iv_set + && (ctx->mode == EVP_CIPH_CBC_MODE + || ctx->mode == EVP_CIPH_CFB_MODE + || ctx->mode == EVP_CIPH_OFB_MODE)) { + /* reset IV to keep compatibility with 1.1.1 */ + memcpy(ctx->iv, ctx->oiv, ctx->ivlen); + } + + if (key != NULL) { + if (keylen != ctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + if (!ctx->hw->init(ctx, key, ctx->keylen)) + return 0; + } + return ossl_cipher_generic_set_ctx_params(ctx, params); +} + +int ossl_tdes_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return tdes_init(vctx, key, keylen, iv, ivlen, params, 1); +} + +int ossl_tdes_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return tdes_init(vctx, key, keylen, iv, ivlen, params, 0); +} + +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(ossl_tdes) + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_RANDOM_KEY, NULL, 0), +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(ossl_tdes) + +static int tdes_generatekey(PROV_CIPHER_CTX *ctx, void *ptr) +{ + + DES_cblock *deskey = ptr; + size_t kl = ctx->keylen; + + if (kl == 0 || RAND_priv_bytes_ex(ctx->libctx, ptr, kl, 0) <= 0) + return 0; + DES_set_odd_parity(deskey); + if (kl >= 16) + DES_set_odd_parity(deskey + 1); + if (kl >= 24) { + DES_set_odd_parity(deskey + 2); + return 1; + } + return 0; +} + +int ossl_tdes_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + OSSL_PARAM *p; + + if (!ossl_cipher_generic_get_ctx_params(vctx, params)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_RANDOM_KEY); + if (p != NULL && !tdes_generatekey(ctx, p->data)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY); + return 0; + } + return 1; +} diff --git a/providers/implementations/ciphers/cipher_tdes_default.c b/providers/implementations/ciphers/cipher_tdes_default.c new file mode 100644 index 000000000000..3b8908ff3988 --- /dev/null +++ b/providers/implementations/ciphers/cipher_tdes_default.c @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "cipher_tdes_default.h" +#include "prov/implementations.h" + +/* ossl_tdes_ede3_ofb_functions */ +IMPLEMENT_tdes_cipher(ede3, EDE3, ofb, OFB, TDES_FLAGS, 64*3, 8, 64, stream); +/* ossl_tdes_ede3_cfb_functions */ +IMPLEMENT_tdes_cipher(ede3, EDE3, cfb, CFB, TDES_FLAGS, 64*3, 8, 64, stream); +/* ossl_tdes_ede3_cfb1_functions */ +IMPLEMENT_tdes_cipher(ede3, EDE3, cfb1, CFB, TDES_FLAGS, 64*3, 8, 64, stream); +/* ossl_tdes_ede3_cfb8_functions */ +IMPLEMENT_tdes_cipher(ede3, EDE3, cfb8, CFB, TDES_FLAGS, 64*3, 8, 64, stream); + +/* ossl_tdes_ede2_ecb_functions */ +IMPLEMENT_tdes_cipher(ede2, EDE2, ecb, ECB, TDES_FLAGS, 64*2, 64, 0, block); +/* ossl_tdes_ede2_cbc_functions */ +IMPLEMENT_tdes_cipher(ede2, EDE2, cbc, CBC, TDES_FLAGS, 64*2, 64, 64, block); +/* ossl_tdes_ede2_ofb_functions */ +IMPLEMENT_tdes_cipher(ede2, EDE2, ofb, OFB, TDES_FLAGS, 64*2, 8, 64, stream); +/* ossl_tdes_ede2_cfb_functions */ +IMPLEMENT_tdes_cipher(ede2, EDE2, cfb, CFB, TDES_FLAGS, 64*2, 8, 64, stream); diff --git a/providers/implementations/ciphers/cipher_tdes_default.h b/providers/implementations/ciphers/cipher_tdes_default.h new file mode 100644 index 000000000000..dc8458b5dafa --- /dev/null +++ b/providers/implementations/ciphers/cipher_tdes_default.h @@ -0,0 +1,25 @@ +/* + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/ciphercommon.h" +#include "cipher_tdes.h" + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_ede3_ofb(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_ede3_cfb(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_ede3_cfb1(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_ede3_cfb8(void); + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_ede2_cbc(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_ede2_ecb(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_ede2_ofb(void); +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_ede2_cfb(void); + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_desx_cbc(void); + +const PROV_CIPHER_HW *ossl_prov_cipher_hw_tdes_wrap_cbc(void); diff --git a/providers/implementations/ciphers/cipher_tdes_default_hw.c b/providers/implementations/ciphers/cipher_tdes_default_hw.c new file mode 100644 index 000000000000..53cbbad57191 --- /dev/null +++ b/providers/implementations/ciphers/cipher_tdes_default_hw.c @@ -0,0 +1,147 @@ +/* + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "cipher_tdes_default.h" + +#define ks1 tks.ks[0] +#define ks2 tks.ks[1] +#define ks3 tks.ks[2] + +static int ossl_cipher_hw_tdes_ede2_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, + size_t keylen) +{ + PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx; + DES_cblock *deskey = (DES_cblock *)key; + + tctx->tstream.cbc = NULL; +# if defined(SPARC_DES_CAPABLE) + if (SPARC_DES_CAPABLE) { + if (ctx->mode == EVP_CIPH_CBC_MODE) { + des_t4_key_expand(&deskey[0], &tctx->ks1); + des_t4_key_expand(&deskey[1], &tctx->ks2); + memcpy(&tctx->ks3, &tctx->ks1, sizeof(tctx->ks1)); + tctx->tstream.cbc = ctx->enc ? des_t4_ede3_cbc_encrypt : + des_t4_ede3_cbc_decrypt; + return 1; + } + } +# endif + DES_set_key_unchecked(&deskey[0], &tctx->ks1); + DES_set_key_unchecked(&deskey[1], &tctx->ks2); + memcpy(&tctx->ks3, &tctx->ks1, sizeof(tctx->ks1)); + return 1; +} + +static int ossl_cipher_hw_tdes_ofb(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx; + int num = ctx->num; + + while (inl >= MAXCHUNK) { + DES_ede3_ofb64_encrypt(in, out, (long)MAXCHUNK, &tctx->ks1, &tctx->ks2, + &tctx->ks3, (DES_cblock *)ctx->iv, &num); + inl -= MAXCHUNK; + in += MAXCHUNK; + out += MAXCHUNK; + } + if (inl > 0) { + DES_ede3_ofb64_encrypt(in, out, (long)inl, &tctx->ks1, &tctx->ks2, + &tctx->ks3, (DES_cblock *)ctx->iv, &num); + } + ctx->num = num; + return 1; +} + +static int ossl_cipher_hw_tdes_cfb(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx; + int num = ctx->num; + + while (inl >= MAXCHUNK) { + + DES_ede3_cfb64_encrypt(in, out, (long)MAXCHUNK, + &tctx->ks1, &tctx->ks2, &tctx->ks3, + (DES_cblock *)ctx->iv, &num, ctx->enc); + inl -= MAXCHUNK; + in += MAXCHUNK; + out += MAXCHUNK; + } + if (inl > 0) { + DES_ede3_cfb64_encrypt(in, out, (long)inl, + &tctx->ks1, &tctx->ks2, &tctx->ks3, + (DES_cblock *)ctx->iv, &num, ctx->enc); + } + ctx->num = num; + return 1; +} + +/* + * Although we have a CFB-r implementation for 3-DES, it doesn't pack the + * right way, so wrap it here + */ +static int ossl_cipher_hw_tdes_cfb1(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx; + size_t n; + unsigned char c[1], d[1]; + + if (ctx->use_bits == 0) + inl *= 8; + for (n = 0; n < inl; ++n) { + c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0; + DES_ede3_cfb_encrypt(c, d, 1, 1, + &tctx->ks1, &tctx->ks2, &tctx->ks3, + (DES_cblock *)ctx->iv, ctx->enc); + out[n / 8] = (out[n / 8] & ~(0x80 >> (unsigned int)(n % 8))) + | ((d[0] & 0x80) >> (unsigned int)(n % 8)); + } + + return 1; +} + +static int ossl_cipher_hw_tdes_cfb8(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx; + + while (inl >= MAXCHUNK) { + DES_ede3_cfb_encrypt(in, out, 8, (long)MAXCHUNK, + &tctx->ks1, &tctx->ks2, &tctx->ks3, + (DES_cblock *)ctx->iv, ctx->enc); + inl -= MAXCHUNK; + in += MAXCHUNK; + out += MAXCHUNK; + } + if (inl > 0) + DES_ede3_cfb_encrypt(in, out, 8, (long)inl, + &tctx->ks1, &tctx->ks2, &tctx->ks3, + (DES_cblock *)ctx->iv, ctx->enc); + return 1; +} + +PROV_CIPHER_HW_tdes_mode(ede3, ofb) +PROV_CIPHER_HW_tdes_mode(ede3, cfb) +PROV_CIPHER_HW_tdes_mode(ede3, cfb1) +PROV_CIPHER_HW_tdes_mode(ede3, cfb8) + +PROV_CIPHER_HW_tdes_mode(ede2, ecb) +PROV_CIPHER_HW_tdes_mode(ede2, cbc) +PROV_CIPHER_HW_tdes_mode(ede2, ofb) +PROV_CIPHER_HW_tdes_mode(ede2, cfb) + diff --git a/providers/implementations/ciphers/cipher_tdes_hw.c b/providers/implementations/ciphers/cipher_tdes_hw.c new file mode 100644 index 000000000000..4382969f44bb --- /dev/null +++ b/providers/implementations/ciphers/cipher_tdes_hw.c @@ -0,0 +1,98 @@ +/* + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "prov/ciphercommon.h" +#include "cipher_tdes.h" + +#define ks1 tks.ks[0] +#define ks2 tks.ks[1] +#define ks3 tks.ks[2] + +int ossl_cipher_hw_tdes_ede3_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx; + DES_cblock *deskey = (DES_cblock *)key; + + tctx->tstream.cbc = NULL; +# if defined(SPARC_DES_CAPABLE) + if (SPARC_DES_CAPABLE) { + if (ctx->mode == EVP_CIPH_CBC_MODE) { + des_t4_key_expand(&deskey[0], &tctx->ks1); + des_t4_key_expand(&deskey[1], &tctx->ks2); + des_t4_key_expand(&deskey[2], &tctx->ks3); + tctx->tstream.cbc = ctx->enc ? des_t4_ede3_cbc_encrypt : + des_t4_ede3_cbc_decrypt; + return 1; + } + } +# endif + DES_set_key_unchecked(&deskey[0], &tctx->ks1); + DES_set_key_unchecked(&deskey[1], &tctx->ks2); + DES_set_key_unchecked(&deskey[2], &tctx->ks3); + return 1; +} + +void ossl_cipher_hw_tdes_copyctx(PROV_CIPHER_CTX *dst, + const PROV_CIPHER_CTX *src) +{ + PROV_TDES_CTX *sctx = (PROV_TDES_CTX *)src; + PROV_TDES_CTX *dctx = (PROV_TDES_CTX *)dst; + + *dctx = *sctx; + dst->ks = &dctx->tks.ks; +} + +int ossl_cipher_hw_tdes_cbc(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx; + + if (tctx->tstream.cbc != NULL) { + (*tctx->tstream.cbc) (in, out, inl, tctx->tks.ks, ctx->iv); + return 1; + } + + while (inl >= MAXCHUNK) { + DES_ede3_cbc_encrypt(in, out, (long)MAXCHUNK, &tctx->ks1, &tctx->ks2, + &tctx->ks3, (DES_cblock *)ctx->iv, ctx->enc); + inl -= MAXCHUNK; + in += MAXCHUNK; + out += MAXCHUNK; + } + if (inl > 0) + DES_ede3_cbc_encrypt(in, out, (long)inl, &tctx->ks1, &tctx->ks2, + &tctx->ks3, (DES_cblock *)ctx->iv, ctx->enc); + return 1; +} + +int ossl_cipher_hw_tdes_ecb(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + size_t i; + PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx; + + if (len < DES_BLOCK_SIZE) + return 1; + + for (i = 0, len -= DES_BLOCK_SIZE; i <= len; i += DES_BLOCK_SIZE) { + DES_ecb3_encrypt((const_DES_cblock *)(in + i), (DES_cblock *)(out + i), + &tctx->ks1, &tctx->ks2, &tctx->ks3, ctx->enc); + } + return 1; +} + +PROV_CIPHER_HW_tdes_mode(ede3, ecb) +PROV_CIPHER_HW_tdes_mode(ede3, cbc) diff --git a/providers/implementations/ciphers/cipher_tdes_wrap.c b/providers/implementations/ciphers/cipher_tdes_wrap.c new file mode 100644 index 000000000000..1b4539a64ce3 --- /dev/null +++ b/providers/implementations/ciphers/cipher_tdes_wrap.c @@ -0,0 +1,210 @@ +/* + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES and SHA-1 low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/sha.h> +#include <openssl/rand.h> +#include <openssl/proverr.h> +#include "cipher_tdes_default.h" +#include "crypto/evp.h" +#include "crypto/sha.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +#define TDES_WRAP_FLAGS PROV_CIPHER_FLAG_CUSTOM_IV | PROV_CIPHER_FLAG_RAND_KEY + +static OSSL_FUNC_cipher_update_fn tdes_wrap_update; +static OSSL_FUNC_cipher_cipher_fn tdes_wrap_cipher; + +static const unsigned char wrap_iv[8] = +{ + 0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05 +}; + +static int des_ede3_unwrap(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + unsigned char icv[8], iv[TDES_IVLEN], sha1tmp[SHA_DIGEST_LENGTH]; + int rv = -1; + + if (inl < 24) + return -1; + if (out == NULL) + return inl - 16; + + memcpy(ctx->iv, wrap_iv, 8); + /* Decrypt first block which will end up as icv */ + ctx->hw->cipher(ctx, icv, in, 8); + /* Decrypt central blocks */ + /* + * If decrypting in place move whole output along a block so the next + * des_ede_cbc_cipher is in place. + */ + if (out == in) { + memmove(out, out + 8, inl - 8); + in -= 8; + } + ctx->hw->cipher(ctx, out, in + 8, inl - 16); + /* Decrypt final block which will be IV */ + ctx->hw->cipher(ctx, iv, in + inl - 8, 8); + /* Reverse order of everything */ + BUF_reverse(icv, NULL, 8); + BUF_reverse(out, NULL, inl - 16); + BUF_reverse(ctx->iv, iv, 8); + /* Decrypt again using new IV */ + ctx->hw->cipher(ctx, out, out, inl - 16); + ctx->hw->cipher(ctx, icv, icv, 8); + if (ossl_sha1(out, inl - 16, sha1tmp) /* Work out hash of first portion */ + && CRYPTO_memcmp(sha1tmp, icv, 8) == 0) + rv = inl - 16; + OPENSSL_cleanse(icv, 8); + OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH); + OPENSSL_cleanse(iv, 8); + OPENSSL_cleanse(ctx->iv, sizeof(ctx->iv)); + if (rv == -1) + OPENSSL_cleanse(out, inl - 16); + + return rv; +} + +static int des_ede3_wrap(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + unsigned char sha1tmp[SHA_DIGEST_LENGTH]; + size_t ivlen = TDES_IVLEN; + size_t icvlen = TDES_IVLEN; + size_t len = inl + ivlen + icvlen; + + if (out == NULL) + return len; + + /* Copy input to output buffer + 8 so we have space for IV */ + memmove(out + ivlen, in, inl); + /* Work out ICV */ + if (!ossl_sha1(in, inl, sha1tmp)) + return 0; + memcpy(out + inl + ivlen, sha1tmp, icvlen); + OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH); + /* Generate random IV */ + if (RAND_bytes_ex(ctx->libctx, ctx->iv, ivlen, 0) <= 0) + return 0; + memcpy(out, ctx->iv, ivlen); + /* Encrypt everything after IV in place */ + ctx->hw->cipher(ctx, out + ivlen, out + ivlen, inl + ivlen); + BUF_reverse(out, NULL, len); + memcpy(ctx->iv, wrap_iv, ivlen); + ctx->hw->cipher(ctx, out, out, len); + return len; +} + +static int tdes_wrap_cipher_internal(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + /* + * Sanity check input length: we typically only wrap keys so EVP_MAXCHUNK + * is more than will ever be needed. Also input length must be a multiple + * of 8 bits. + */ + if (inl >= EVP_MAXCHUNK || inl % 8) + return -1; + if (ctx->enc) + return des_ede3_wrap(ctx, out, in, inl); + else + return des_ede3_unwrap(ctx, out, in, inl); +} + +static int tdes_wrap_cipher(void *vctx, + unsigned char *out, size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + int ret; + + *outl = 0; + if (!ossl_prov_is_running()) + return 0; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + ret = tdes_wrap_cipher_internal(ctx, out, in, inl); + if (ret <= 0) + return 0; + + *outl = ret; + return 1; +} + +static int tdes_wrap_update(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, + size_t inl) +{ + *outl = 0; + if (inl == 0) + return 1; + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!tdes_wrap_cipher(vctx, out, outl, outsize, in, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + return 1; +} + + +# define IMPLEMENT_WRAP_CIPHER(flags, kbits, blkbits, ivbits) \ +static OSSL_FUNC_cipher_newctx_fn tdes_wrap_newctx; \ +static void *tdes_wrap_newctx(void *provctx) \ +{ \ + return ossl_tdes_newctx(provctx, EVP_CIPH_WRAP_MODE, kbits, blkbits, \ + ivbits, flags, \ + ossl_prov_cipher_hw_tdes_wrap_cbc()); \ +} \ +static OSSL_FUNC_cipher_get_params_fn tdes_wrap_get_params; \ +static int tdes_wrap_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_WRAP_MODE, flags, \ + kbits, blkbits, ivbits); \ +} \ +const OSSL_DISPATCH ossl_tdes_wrap_cbc_functions[] = \ +{ \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void)) ossl_tdes_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void)) ossl_tdes_dinit }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))tdes_wrap_cipher }, \ + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))tdes_wrap_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))ossl_tdes_freectx }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))tdes_wrap_update }, \ + { OSSL_FUNC_CIPHER_FINAL, \ + (void (*)(void))ossl_cipher_generic_stream_final }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))tdes_wrap_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))ossl_tdes_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_tdes_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_settable_ctx_params }, \ + { 0, NULL } \ +} + +/* ossl_tdes_wrap_cbc_functions */ +IMPLEMENT_WRAP_CIPHER(TDES_WRAP_FLAGS, 64*3, 64, 0); diff --git a/providers/implementations/ciphers/cipher_tdes_wrap_hw.c b/providers/implementations/ciphers/cipher_tdes_wrap_hw.c new file mode 100644 index 000000000000..3c8c83332070 --- /dev/null +++ b/providers/implementations/ciphers/cipher_tdes_wrap_hw.c @@ -0,0 +1,20 @@ +/* + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include "cipher_tdes_default.h" + +#define ossl_cipher_hw_tdes_wrap_initkey ossl_cipher_hw_tdes_ede3_initkey + +PROV_CIPHER_HW_tdes_mode(wrap, cbc) diff --git a/providers/implementations/ciphers/ciphercommon.c b/providers/implementations/ciphers/ciphercommon.c new file mode 100644 index 000000000000..fa383165d83c --- /dev/null +++ b/providers/implementations/ciphers/ciphercommon.c @@ -0,0 +1,680 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Generic dispatch table functions for ciphers. + */ + +/* For SSL3_VERSION */ +#include <openssl/prov_ssl.h> +#include <openssl/proverr.h> +#include "ciphercommon_local.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" + +/*- + * Generic cipher functions for OSSL_PARAM gettables and settables + */ +static const OSSL_PARAM cipher_known_gettable_params[] = { + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_MODE, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_AEAD, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_CUSTOM_IV, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_CTS, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_HAS_RAND_KEY, NULL), + OSSL_PARAM_END +}; +const OSSL_PARAM *ossl_cipher_generic_gettable_params(ossl_unused void *provctx) +{ + return cipher_known_gettable_params; +} + +int ossl_cipher_generic_get_params(OSSL_PARAM params[], unsigned int md, + uint64_t flags, + size_t kbits, size_t blkbits, size_t ivbits) +{ + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_MODE); + if (p != NULL && !OSSL_PARAM_set_uint(p, md)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD); + if (p != NULL + && !OSSL_PARAM_set_int(p, (flags & PROV_CIPHER_FLAG_AEAD) != 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_CUSTOM_IV); + if (p != NULL + && !OSSL_PARAM_set_int(p, (flags & PROV_CIPHER_FLAG_CUSTOM_IV) != 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_CTS); + if (p != NULL + && !OSSL_PARAM_set_int(p, (flags & PROV_CIPHER_FLAG_CTS) != 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK); + if (p != NULL + && !OSSL_PARAM_set_int(p, (flags & PROV_CIPHER_FLAG_TLS1_MULTIBLOCK) != 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_HAS_RAND_KEY); + if (p != NULL + && !OSSL_PARAM_set_int(p, (flags & PROV_CIPHER_FLAG_RAND_KEY) != 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, kbits / 8)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_BLOCK_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, blkbits / 8)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ivbits / 8)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + return 1; +} + +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(ossl_cipher_generic) +{ OSSL_CIPHER_PARAM_TLS_MAC, OSSL_PARAM_OCTET_PTR, NULL, 0, OSSL_PARAM_UNMODIFIED }, +CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(ossl_cipher_generic) + +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(ossl_cipher_generic) +OSSL_PARAM_uint(OSSL_CIPHER_PARAM_USE_BITS, NULL), +OSSL_PARAM_uint(OSSL_CIPHER_PARAM_TLS_VERSION, NULL), +OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS_MAC_SIZE, NULL), +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(ossl_cipher_generic) + +/* + * Variable key length cipher functions for OSSL_PARAM settables + */ +int ossl_cipher_var_keylen_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + if (!ossl_cipher_generic_set_ctx_params(vctx, params)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + size_t keylen; + + if (!OSSL_PARAM_get_size_t(p, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + ctx->keylen = keylen; + } + return 1; +} + +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(ossl_cipher_var_keylen) +OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(ossl_cipher_var_keylen) + +/*- + * AEAD cipher functions for OSSL_PARAM gettables and settables + */ +static const OSSL_PARAM cipher_aead_known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_UPDATED_IV, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN, NULL, 0), + OSSL_PARAM_END +}; +const OSSL_PARAM *ossl_cipher_aead_gettable_ctx_params( + ossl_unused void *cctx, ossl_unused void *provctx + ) +{ + return cipher_aead_known_gettable_ctx_params; +} + +static const OSSL_PARAM cipher_aead_known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV, NULL, 0), + OSSL_PARAM_END +}; +const OSSL_PARAM *ossl_cipher_aead_settable_ctx_params( + ossl_unused void *cctx, ossl_unused void *provctx + ) +{ + return cipher_aead_known_settable_ctx_params; +} + +void ossl_cipher_generic_reset_ctx(PROV_CIPHER_CTX *ctx) +{ + if (ctx != NULL && ctx->alloced) { + OPENSSL_free(ctx->tlsmac); + ctx->alloced = 0; + ctx->tlsmac = NULL; + } +} + +static int cipher_generic_init_internal(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[], int enc) +{ + ctx->num = 0; + ctx->bufsz = 0; + ctx->updated = 0; + ctx->enc = enc ? 1 : 0; + + if (!ossl_prov_is_running()) + return 0; + + if (iv != NULL && ctx->mode != EVP_CIPH_ECB_MODE) { + if (!ossl_cipher_generic_initiv(ctx, iv, ivlen)) + return 0; + } + if (iv == NULL && ctx->iv_set + && (ctx->mode == EVP_CIPH_CBC_MODE + || ctx->mode == EVP_CIPH_CFB_MODE + || ctx->mode == EVP_CIPH_OFB_MODE)) + /* reset IV for these modes to keep compatibility with 1.1.1 */ + memcpy(ctx->iv, ctx->oiv, ctx->ivlen); + + if (key != NULL) { + if (ctx->variable_keylength == 0) { + if (keylen != ctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } else { + ctx->keylen = keylen; + } + if (!ctx->hw->init(ctx, key, ctx->keylen)) + return 0; + } + return ossl_cipher_generic_set_ctx_params(ctx, params); +} + +int ossl_cipher_generic_einit(void *vctx, const unsigned char *key, + size_t keylen, const unsigned char *iv, + size_t ivlen, const OSSL_PARAM params[]) +{ + return cipher_generic_init_internal((PROV_CIPHER_CTX *)vctx, key, keylen, + iv, ivlen, params, 1); +} + +int ossl_cipher_generic_dinit(void *vctx, const unsigned char *key, + size_t keylen, const unsigned char *iv, + size_t ivlen, const OSSL_PARAM params[]) +{ + return cipher_generic_init_internal((PROV_CIPHER_CTX *)vctx, key, keylen, + iv, ivlen, params, 0); +} + +/* Max padding including padding length byte */ +#define MAX_PADDING 256 + +int ossl_cipher_generic_block_update(void *vctx, unsigned char *out, + size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + size_t outlint = 0; + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + size_t blksz = ctx->blocksize; + size_t nextblocks; + + if (ctx->tlsversion > 0) { + /* + * Each update call corresponds to a TLS record and is individually + * padded + */ + + /* Sanity check inputs */ + if (in == NULL + || in != out + || outsize < inl + || !ctx->pad) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + if (ctx->enc) { + unsigned char padval; + size_t padnum, loop; + + /* Add padding */ + + padnum = blksz - (inl % blksz); + + if (outsize < inl + padnum) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + if (padnum > MAX_PADDING) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + padval = (unsigned char)(padnum - 1); + if (ctx->tlsversion == SSL3_VERSION) { + if (padnum > 1) + memset(out + inl, 0, padnum - 1); + *(out + inl + padnum - 1) = padval; + } else { + /* we need to add 'padnum' padding bytes of value padval */ + for (loop = inl; loop < inl + padnum; loop++) + out[loop] = padval; + } + inl += padnum; + } + + if ((inl % blksz) != 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + + /* Shouldn't normally fail */ + if (!ctx->hw->cipher(ctx, out, in, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + if (ctx->alloced) { + OPENSSL_free(ctx->tlsmac); + ctx->alloced = 0; + ctx->tlsmac = NULL; + } + + /* This only fails if padding is publicly invalid */ + *outl = inl; + if (!ctx->enc + && !ossl_cipher_tlsunpadblock(ctx->libctx, ctx->tlsversion, + out, outl, + blksz, &ctx->tlsmac, &ctx->alloced, + ctx->tlsmacsize, 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + return 1; + } + + if (ctx->bufsz != 0) + nextblocks = ossl_cipher_fillblock(ctx->buf, &ctx->bufsz, blksz, + &in, &inl); + else + nextblocks = inl & ~(blksz-1); + + /* + * If we're decrypting and we end an update on a block boundary we hold + * the last block back in case this is the last update call and the last + * block is padded. + */ + if (ctx->bufsz == blksz && (ctx->enc || inl > 0 || !ctx->pad)) { + if (outsize < blksz) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (!ctx->hw->cipher(ctx, out, ctx->buf, blksz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + ctx->bufsz = 0; + outlint = blksz; + out += blksz; + } + if (nextblocks > 0) { + if (!ctx->enc && ctx->pad && nextblocks == inl) { + if (!ossl_assert(inl >= blksz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + nextblocks -= blksz; + } + outlint += nextblocks; + if (outsize < outlint) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + } + if (nextblocks > 0) { + if (!ctx->hw->cipher(ctx, out, in, nextblocks)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + in += nextblocks; + inl -= nextblocks; + } + if (inl != 0 + && !ossl_cipher_trailingdata(ctx->buf, &ctx->bufsz, blksz, &in, &inl)) { + /* ERR_raise already called */ + return 0; + } + + *outl = outlint; + return inl == 0; +} + +int ossl_cipher_generic_block_final(void *vctx, unsigned char *out, + size_t *outl, size_t outsize) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + size_t blksz = ctx->blocksize; + + if (!ossl_prov_is_running()) + return 0; + + if (ctx->tlsversion > 0) { + /* We never finalize TLS, so this is an error */ + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + if (ctx->enc) { + if (ctx->pad) { + ossl_cipher_padblock(ctx->buf, &ctx->bufsz, blksz); + } else if (ctx->bufsz == 0) { + *outl = 0; + return 1; + } else if (ctx->bufsz != blksz) { + ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH); + return 0; + } + + if (outsize < blksz) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (!ctx->hw->cipher(ctx, out, ctx->buf, blksz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + ctx->bufsz = 0; + *outl = blksz; + return 1; + } + + /* Decrypting */ + if (ctx->bufsz != blksz) { + if (ctx->bufsz == 0 && !ctx->pad) { + *outl = 0; + return 1; + } + ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH); + return 0; + } + + if (!ctx->hw->cipher(ctx, ctx->buf, ctx->buf, blksz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + if (ctx->pad && !ossl_cipher_unpadblock(ctx->buf, &ctx->bufsz, blksz)) { + /* ERR_raise already called */ + return 0; + } + + if (outsize < ctx->bufsz) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + memcpy(out, ctx->buf, ctx->bufsz); + *outl = ctx->bufsz; + ctx->bufsz = 0; + return 1; +} + +int ossl_cipher_generic_stream_update(void *vctx, unsigned char *out, + size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + + if (inl == 0) { + *outl = 0; + return 1; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!ctx->hw->cipher(ctx, out, in, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + *outl = inl; + if (!ctx->enc && ctx->tlsversion > 0) { + /* + * Remove any TLS padding. Only used by cipher_aes_cbc_hmac_sha1_hw.c and + * cipher_aes_cbc_hmac_sha256_hw.c + */ + if (ctx->removetlspad) { + /* + * We should have already failed in the cipher() call above if this + * isn't true. + */ + if (!ossl_assert(*outl >= (size_t)(out[inl - 1] + 1))) + return 0; + /* The actual padding length */ + *outl -= out[inl - 1] + 1; + } + + /* TLS MAC and explicit IV if relevant. We should have already failed + * in the cipher() call above if *outl is too short. + */ + if (!ossl_assert(*outl >= ctx->removetlsfixed)) + return 0; + *outl -= ctx->removetlsfixed; + + /* Extract the MAC if there is one */ + if (ctx->tlsmacsize > 0) { + if (*outl < ctx->tlsmacsize) + return 0; + + ctx->tlsmac = out + *outl - ctx->tlsmacsize; + *outl -= ctx->tlsmacsize; + } + } + + return 1; +} +int ossl_cipher_generic_stream_final(void *vctx, unsigned char *out, + size_t *outl, size_t outsize) +{ + if (!ossl_prov_is_running()) + return 0; + + *outl = 0; + return 1; +} + +int ossl_cipher_generic_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, + size_t inl) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!ctx->hw->cipher(ctx, out, in, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + *outl = inl; + return 1; +} + +int ossl_cipher_generic_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_PADDING); + if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->pad)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); + if (p != NULL + && !OSSL_PARAM_set_octet_ptr(p, &ctx->oiv, ctx->ivlen) + && !OSSL_PARAM_set_octet_string(p, &ctx->oiv, ctx->ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV); + if (p != NULL + && !OSSL_PARAM_set_octet_ptr(p, &ctx->iv, ctx->ivlen) + && !OSSL_PARAM_set_octet_string(p, &ctx->iv, ctx->ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_NUM); + if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->num)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS_MAC); + if (p != NULL + && !OSSL_PARAM_set_octet_ptr(p, ctx->tlsmac, ctx->tlsmacsize)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + return 1; +} + +int ossl_cipher_generic_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_PADDING); + if (p != NULL) { + unsigned int pad; + + if (!OSSL_PARAM_get_uint(p, &pad)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + ctx->pad = pad ? 1 : 0; + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_USE_BITS); + if (p != NULL) { + unsigned int bits; + + if (!OSSL_PARAM_get_uint(p, &bits)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + ctx->use_bits = bits ? 1 : 0; + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS_VERSION); + if (p != NULL) { + if (!OSSL_PARAM_get_uint(p, &ctx->tlsversion)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS_MAC_SIZE); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &ctx->tlsmacsize)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_NUM); + if (p != NULL) { + unsigned int num; + + if (!OSSL_PARAM_get_uint(p, &num)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + ctx->num = num; + } + return 1; +} + +int ossl_cipher_generic_initiv(PROV_CIPHER_CTX *ctx, const unsigned char *iv, + size_t ivlen) +{ + if (ivlen != ctx->ivlen + || ivlen > sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + ctx->iv_set = 1; + memcpy(ctx->iv, iv, ivlen); + memcpy(ctx->oiv, iv, ivlen); + return 1; +} + +void ossl_cipher_generic_initkey(void *vctx, size_t kbits, size_t blkbits, + size_t ivbits, unsigned int mode, + uint64_t flags, const PROV_CIPHER_HW *hw, + void *provctx) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + + if ((flags & PROV_CIPHER_FLAG_INVERSE_CIPHER) != 0) + ctx->inverse_cipher = 1; + if ((flags & PROV_CIPHER_FLAG_VARIABLE_LENGTH) != 0) + ctx->variable_keylength = 1; + + ctx->pad = 1; + ctx->keylen = ((kbits) / 8); + ctx->ivlen = ((ivbits) / 8); + ctx->hw = hw; + ctx->mode = mode; + ctx->blocksize = blkbits / 8; + if (provctx != NULL) + ctx->libctx = PROV_LIBCTX_OF(provctx); /* used for rand */ +} diff --git a/providers/implementations/ciphers/ciphercommon_block.c b/providers/implementations/ciphers/ciphercommon_block.c new file mode 100644 index 000000000000..6e6bb091e76b --- /dev/null +++ b/providers/implementations/ciphers/ciphercommon_block.c @@ -0,0 +1,190 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <assert.h> +/* For SSL3_VERSION, TLS1_VERSION etc */ +#include <openssl/prov_ssl.h> +#include <openssl/rand.h> +#include <openssl/proverr.h> +#include "internal/constant_time.h" +#include "ciphercommon_local.h" + +/* Functions defined in ssl/tls_pad.c */ +int ssl3_cbc_remove_padding_and_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, + unsigned char **mac, + int *alloced, + size_t block_size, size_t mac_size, + OSSL_LIB_CTX *libctx); + +int tls1_cbc_remove_padding_and_mac(size_t *reclen, + size_t origreclen, + unsigned char *recdata, + unsigned char **mac, + int *alloced, + size_t block_size, size_t mac_size, + int aead, + OSSL_LIB_CTX *libctx); + +/* + * Fills a single block of buffered data from the input, and returns the amount + * of data remaining in the input that is a multiple of the blocksize. The buffer + * is only filled if it already has some data in it, isn't full already or we + * don't have at least one block in the input. + * + * buf: a buffer of blocksize bytes + * buflen: contains the amount of data already in buf on entry. Updated with the + * amount of data in buf at the end. On entry *buflen must always be + * less than the blocksize + * blocksize: size of a block. Must be greater than 0 and a power of 2 + * in: pointer to a pointer containing the input data + * inlen: amount of input data available + * + * On return buf is filled with as much data as possible up to a full block, + * *buflen is updated containing the amount of data in buf. *in is updated to + * the new location where input data should be read from, *inlen is updated with + * the remaining amount of data in *in. Returns the largest value <= *inlen + * which is a multiple of the blocksize. + */ +size_t ossl_cipher_fillblock(unsigned char *buf, size_t *buflen, + size_t blocksize, + const unsigned char **in, size_t *inlen) +{ + size_t blockmask = ~(blocksize - 1); + size_t bufremain = blocksize - *buflen; + + assert(*buflen <= blocksize); + assert(blocksize > 0 && (blocksize & (blocksize - 1)) == 0); + + if (*inlen < bufremain) + bufremain = *inlen; + memcpy(buf + *buflen, *in, bufremain); + *in += bufremain; + *inlen -= bufremain; + *buflen += bufremain; + + return *inlen & blockmask; +} + +/* + * Fills the buffer with trailing data from an encryption/decryption that didn't + * fit into a full block. + */ +int ossl_cipher_trailingdata(unsigned char *buf, size_t *buflen, size_t blocksize, + const unsigned char **in, size_t *inlen) +{ + if (*inlen == 0) + return 1; + + if (*buflen + *inlen > blocksize) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return 0; + } + + memcpy(buf + *buflen, *in, *inlen); + *buflen += *inlen; + *inlen = 0; + + return 1; +} + +/* Pad the final block for encryption */ +void ossl_cipher_padblock(unsigned char *buf, size_t *buflen, size_t blocksize) +{ + size_t i; + unsigned char pad = (unsigned char)(blocksize - *buflen); + + for (i = *buflen; i < blocksize; i++) + buf[i] = pad; +} + +int ossl_cipher_unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize) +{ + size_t pad, i; + size_t len = *buflen; + + if(len != blocksize) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return 0; + } + + /* + * The following assumes that the ciphertext has been authenticated. + * Otherwise it provides a padding oracle. + */ + pad = buf[blocksize - 1]; + if (pad == 0 || pad > blocksize) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT); + return 0; + } + for (i = 0; i < pad; i++) { + if (buf[--len] != pad) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT); + return 0; + } + } + *buflen = len; + return 1; +} + +/*- + * ossl_cipher_tlsunpadblock removes the CBC padding from the decrypted, TLS, CBC + * record in constant time. Also removes the MAC from the record in constant + * time. + * + * libctx: Our library context + * tlsversion: The TLS version in use, e.g. SSL3_VERSION, TLS1_VERSION, etc + * buf: The decrypted TLS record data + * buflen: The length of the decrypted TLS record data. Updated with the new + * length after the padding is removed + * block_size: the block size of the cipher used to encrypt the record. + * mac: Location to store the pointer to the MAC + * alloced: Whether the MAC is stored in a newly allocated buffer, or whether + * *mac points into *buf + * macsize: the size of the MAC inside the record (or 0 if there isn't one) + * aead: whether this is an aead cipher + * returns: + * 0: (in non-constant time) if the record is publicly invalid. + * 1: (in constant time) Record is publicly valid. If padding is invalid then + * the mac is random + */ +int ossl_cipher_tlsunpadblock(OSSL_LIB_CTX *libctx, unsigned int tlsversion, + unsigned char *buf, size_t *buflen, + size_t blocksize, + unsigned char **mac, int *alloced, size_t macsize, + int aead) +{ + int ret; + + switch (tlsversion) { + case SSL3_VERSION: + return ssl3_cbc_remove_padding_and_mac(buflen, *buflen, buf, mac, + alloced, blocksize, macsize, + libctx); + + case TLS1_2_VERSION: + case DTLS1_2_VERSION: + case TLS1_1_VERSION: + case DTLS1_VERSION: + case DTLS1_BAD_VER: + /* Remove the explicit IV */ + buf += blocksize; + *buflen -= blocksize; + /* Fall through */ + case TLS1_VERSION: + ret = tls1_cbc_remove_padding_and_mac(buflen, *buflen, buf, mac, + alloced, blocksize, macsize, + aead, libctx); + return ret; + + default: + return 0; + } +} diff --git a/providers/implementations/ciphers/ciphercommon_ccm.c b/providers/implementations/ciphers/ciphercommon_ccm.c new file mode 100644 index 000000000000..ce3f7527f31e --- /dev/null +++ b/providers/implementations/ciphers/ciphercommon_ccm.c @@ -0,0 +1,453 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for ccm mode */ + +#include <openssl/proverr.h> +#include "prov/ciphercommon.h" +#include "prov/ciphercommon_ccm.h" +#include "prov/providercommon.h" + +static int ccm_cipher_internal(PROV_CCM_CTX *ctx, unsigned char *out, + size_t *padlen, const unsigned char *in, + size_t len); + +static int ccm_tls_init(PROV_CCM_CTX *ctx, unsigned char *aad, size_t alen) +{ + size_t len; + + if (!ossl_prov_is_running() || alen != EVP_AEAD_TLS1_AAD_LEN) + return 0; + + /* Save the aad for later use. */ + memcpy(ctx->buf, aad, alen); + ctx->tls_aad_len = alen; + + len = ctx->buf[alen - 2] << 8 | ctx->buf[alen - 1]; + if (len < EVP_CCM_TLS_EXPLICIT_IV_LEN) + return 0; + + /* Correct length for explicit iv. */ + len -= EVP_CCM_TLS_EXPLICIT_IV_LEN; + + if (!ctx->enc) { + if (len < ctx->m) + return 0; + /* Correct length for tag. */ + len -= ctx->m; + } + ctx->buf[alen - 2] = (unsigned char)(len >> 8); + ctx->buf[alen - 1] = (unsigned char)(len & 0xff); + + /* Extra padding: tag appended to record. */ + return ctx->m; +} + +static int ccm_tls_iv_set_fixed(PROV_CCM_CTX *ctx, unsigned char *fixed, + size_t flen) +{ + if (flen != EVP_CCM_TLS_FIXED_IV_LEN) + return 0; + + /* Copy to first part of the iv. */ + memcpy(ctx->iv, fixed, flen); + return 1; +} + +static size_t ccm_get_ivlen(PROV_CCM_CTX *ctx) +{ + return 15 - ctx->l; +} + +int ossl_ccm_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; + const OSSL_PARAM *p; + size_t sz; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if ((p->data_size & 1) || (p->data_size < 4) || p->data_size > 16) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH); + return 0; + } + + if (p->data != NULL) { + if (ctx->enc) { + ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED); + return 0; + } + memcpy(ctx->buf, p->data, p->data_size); + ctx->tag_set = 1; + } + ctx->m = p->data_size; + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_IVLEN); + if (p != NULL) { + size_t ivlen; + + if (!OSSL_PARAM_get_size_t(p, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + ivlen = 15 - sz; + if (ivlen < 2 || ivlen > 8) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + ctx->l = ivlen; + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + sz = ccm_tls_init(ctx, p->data, p->data_size); + if (sz == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA); + return 0; + } + ctx->tls_aad_pad_sz = sz; + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ccm_tls_iv_set_fixed(ctx, p->data, p->data_size) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + } + + return 1; +} + +int ossl_ccm_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ccm_get_ivlen(ctx))) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN); + if (p != NULL) { + size_t m = ctx->m; + + if (!OSSL_PARAM_set_size_t(p, m)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); + if (p != NULL) { + if (ccm_get_ivlen(ctx) > p->data_size) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + if (!OSSL_PARAM_set_octet_string(p, ctx->iv, p->data_size) + && !OSSL_PARAM_set_octet_ptr(p, &ctx->iv, p->data_size)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV); + if (p != NULL) { + if (ccm_get_ivlen(ctx) > p->data_size) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + if (!OSSL_PARAM_set_octet_string(p, ctx->iv, p->data_size) + && !OSSL_PARAM_set_octet_ptr(p, &ctx->iv, p->data_size)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL) { + if (!ctx->enc || !ctx->tag_set) { + ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_SET); + return 0; + } + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + if (!ctx->hw->gettag(ctx, p->data, p->data_size)) + return 0; + ctx->tag_set = 0; + ctx->iv_set = 0; + ctx->len_set = 0; + } + return 1; +} + +static int ccm_init(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[], int enc) +{ + PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + ctx->enc = enc; + + if (iv != NULL) { + if (ivlen != ccm_get_ivlen(ctx)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + memcpy(ctx->iv, iv, ivlen); + ctx->iv_set = 1; + } + if (key != NULL) { + if (keylen != ctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + if (!ctx->hw->setkey(ctx, key, keylen)) + return 0; + } + return ossl_ccm_set_ctx_params(ctx, params); +} + +int ossl_ccm_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return ccm_init(vctx, key, keylen, iv, ivlen, params, 1); +} + +int ossl_ccm_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return ccm_init(vctx, key, keylen, iv, ivlen, params, 0); +} + +int ossl_ccm_stream_update(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, + size_t inl) +{ + PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!ccm_cipher_internal(ctx, out, outl, in, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + return 1; +} + +int ossl_ccm_stream_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; + int i; + + if (!ossl_prov_is_running()) + return 0; + + i = ccm_cipher_internal(ctx, out, outl, NULL, 0); + if (i <= 0) + return 0; + + *outl = 0; + return 1; +} + +int ossl_ccm_cipher(void *vctx, unsigned char *out, size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (ccm_cipher_internal(ctx, out, outl, in, inl) <= 0) + return 0; + + *outl = inl; + return 1; +} + +/* Copy the buffered iv */ +static int ccm_set_iv(PROV_CCM_CTX *ctx, size_t mlen) +{ + const PROV_CCM_HW *hw = ctx->hw; + + if (!hw->setiv(ctx, ctx->iv, ccm_get_ivlen(ctx), mlen)) + return 0; + ctx->len_set = 1; + return 1; +} + +static int ccm_tls_cipher(PROV_CCM_CTX *ctx, + unsigned char *out, size_t *padlen, + const unsigned char *in, size_t len) +{ + int rv = 0; + size_t olen = 0; + + if (!ossl_prov_is_running()) + goto err; + + /* Encrypt/decrypt must be performed in place */ + if (in == NULL || out != in || len < EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m) + goto err; + + /* If encrypting set explicit IV from sequence number (start of AAD) */ + if (ctx->enc) + memcpy(out, ctx->buf, EVP_CCM_TLS_EXPLICIT_IV_LEN); + /* Get rest of IV from explicit IV */ + memcpy(ctx->iv + EVP_CCM_TLS_FIXED_IV_LEN, in, EVP_CCM_TLS_EXPLICIT_IV_LEN); + /* Correct length value */ + len -= EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m; + if (!ccm_set_iv(ctx, len)) + goto err; + + /* Use saved AAD */ + if (!ctx->hw->setaad(ctx, ctx->buf, ctx->tls_aad_len)) + goto err; + + /* Fix buffer to point to payload */ + in += EVP_CCM_TLS_EXPLICIT_IV_LEN; + out += EVP_CCM_TLS_EXPLICIT_IV_LEN; + if (ctx->enc) { + if (!ctx->hw->auth_encrypt(ctx, in, out, len, out + len, ctx->m)) + goto err; + olen = len + EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m; + } else { + if (!ctx->hw->auth_decrypt(ctx, in, out, len, + (unsigned char *)in + len, ctx->m)) + goto err; + olen = len; + } + rv = 1; +err: + *padlen = olen; + return rv; +} + +static int ccm_cipher_internal(PROV_CCM_CTX *ctx, unsigned char *out, + size_t *padlen, const unsigned char *in, + size_t len) +{ + int rv = 0; + size_t olen = 0; + const PROV_CCM_HW *hw = ctx->hw; + + /* If no key set, return error */ + if (!ctx->key_set) + return 0; + + if (ctx->tls_aad_len != UNINITIALISED_SIZET) + return ccm_tls_cipher(ctx, out, padlen, in, len); + + /* EVP_*Final() doesn't return any data */ + if (in == NULL && out != NULL) + goto finish; + + if (!ctx->iv_set) + goto err; + + if (out == NULL) { + if (in == NULL) { + if (!ccm_set_iv(ctx, len)) + goto err; + } else { + /* If we have AAD, we need a message length */ + if (!ctx->len_set && len) + goto err; + if (!hw->setaad(ctx, in, len)) + goto err; + } + } else { + /* If not set length yet do it */ + if (!ctx->len_set && !ccm_set_iv(ctx, len)) + goto err; + + if (ctx->enc) { + if (!hw->auth_encrypt(ctx, in, out, len, NULL, 0)) + goto err; + ctx->tag_set = 1; + } else { + /* The tag must be set before actually decrypting data */ + if (!ctx->tag_set) + goto err; + + if (!hw->auth_decrypt(ctx, in, out, len, ctx->buf, ctx->m)) + goto err; + /* Finished - reset flags so calling this method again will fail */ + ctx->iv_set = 0; + ctx->tag_set = 0; + ctx->len_set = 0; + } + } + olen = len; +finish: + rv = 1; +err: + *padlen = olen; + return rv; +} + +void ossl_ccm_initctx(PROV_CCM_CTX *ctx, size_t keybits, const PROV_CCM_HW *hw) +{ + ctx->keylen = keybits / 8; + ctx->key_set = 0; + ctx->iv_set = 0; + ctx->tag_set = 0; + ctx->len_set = 0; + ctx->l = 8; + ctx->m = 12; + ctx->tls_aad_len = UNINITIALISED_SIZET; + ctx->hw = hw; +} diff --git a/providers/implementations/ciphers/ciphercommon_ccm_hw.c b/providers/implementations/ciphers/ciphercommon_ccm_hw.c new file mode 100644 index 000000000000..ad3fbc59e4fc --- /dev/null +++ b/providers/implementations/ciphers/ciphercommon_ccm_hw.c @@ -0,0 +1,69 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/ciphercommon.h" +#include "prov/ciphercommon_ccm.h" + +int ossl_ccm_generic_setiv(PROV_CCM_CTX *ctx, const unsigned char *nonce, + size_t nlen, size_t mlen) +{ + return CRYPTO_ccm128_setiv(&ctx->ccm_ctx, nonce, nlen, mlen) == 0; +} + +int ossl_ccm_generic_setaad(PROV_CCM_CTX *ctx, const unsigned char *aad, + size_t alen) +{ + CRYPTO_ccm128_aad(&ctx->ccm_ctx, aad, alen); + return 1; +} + +int ossl_ccm_generic_gettag(PROV_CCM_CTX *ctx, unsigned char *tag, size_t tlen) +{ + return CRYPTO_ccm128_tag(&ctx->ccm_ctx, tag, tlen) > 0; +} + +int ossl_ccm_generic_auth_encrypt(PROV_CCM_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len, + unsigned char *tag, size_t taglen) +{ + int rv; + + if (ctx->str != NULL) + rv = CRYPTO_ccm128_encrypt_ccm64(&ctx->ccm_ctx, in, + out, len, ctx->str) == 0; + else + rv = CRYPTO_ccm128_encrypt(&ctx->ccm_ctx, in, out, len) == 0; + + if (rv == 1 && tag != NULL) + rv = (CRYPTO_ccm128_tag(&ctx->ccm_ctx, tag, taglen) > 0); + return rv; +} + +int ossl_ccm_generic_auth_decrypt(PROV_CCM_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len, + unsigned char *expected_tag, size_t taglen) +{ + int rv = 0; + + if (ctx->str != NULL) + rv = CRYPTO_ccm128_decrypt_ccm64(&ctx->ccm_ctx, in, out, len, + ctx->str) == 0; + else + rv = CRYPTO_ccm128_decrypt(&ctx->ccm_ctx, in, out, len) == 0; + if (rv) { + unsigned char tag[16]; + + if (!CRYPTO_ccm128_tag(&ctx->ccm_ctx, tag, taglen) + || CRYPTO_memcmp(tag, expected_tag, taglen) != 0) + rv = 0; + } + if (rv == 0) + OPENSSL_cleanse(out, len); + return rv; +} diff --git a/providers/implementations/ciphers/ciphercommon_gcm.c b/providers/implementations/ciphers/ciphercommon_gcm.c new file mode 100644 index 000000000000..ed95c97ff473 --- /dev/null +++ b/providers/implementations/ciphers/ciphercommon_gcm.c @@ -0,0 +1,568 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Dispatch functions for gcm mode */ + +#include <openssl/rand.h> +#include <openssl/proverr.h> +#include "prov/ciphercommon.h" +#include "prov/ciphercommon_gcm.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" + +static int gcm_tls_init(PROV_GCM_CTX *dat, unsigned char *aad, size_t aad_len); +static int gcm_tls_iv_set_fixed(PROV_GCM_CTX *ctx, unsigned char *iv, + size_t len); +static int gcm_tls_cipher(PROV_GCM_CTX *ctx, unsigned char *out, size_t *padlen, + const unsigned char *in, size_t len); +static int gcm_cipher_internal(PROV_GCM_CTX *ctx, unsigned char *out, + size_t *padlen, const unsigned char *in, + size_t len); + +/* + * Called from EVP_CipherInit when there is currently no context via + * the new_ctx() function + */ +void ossl_gcm_initctx(void *provctx, PROV_GCM_CTX *ctx, size_t keybits, + const PROV_GCM_HW *hw) +{ + ctx->pad = 1; + ctx->mode = EVP_CIPH_GCM_MODE; + ctx->taglen = UNINITIALISED_SIZET; + ctx->tls_aad_len = UNINITIALISED_SIZET; + ctx->ivlen = (EVP_GCM_TLS_FIXED_IV_LEN + EVP_GCM_TLS_EXPLICIT_IV_LEN); + ctx->keylen = keybits / 8; + ctx->hw = hw; + ctx->libctx = PROV_LIBCTX_OF(provctx); +} + +/* + * Called by EVP_CipherInit via the _einit and _dinit functions + */ +static int gcm_init(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[], int enc) +{ + PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + ctx->enc = enc; + + if (iv != NULL) { + if (ivlen == 0 || ivlen > sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + ctx->ivlen = ivlen; + memcpy(ctx->iv, iv, ivlen); + ctx->iv_state = IV_STATE_BUFFERED; + } + + if (key != NULL) { + if (keylen != ctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + if (!ctx->hw->setkey(ctx, key, ctx->keylen)) + return 0; + ctx->tls_enc_records = 0; + } + return ossl_gcm_set_ctx_params(ctx, params); +} + +int ossl_gcm_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return gcm_init(vctx, key, keylen, iv, ivlen, params, 1); +} + +int ossl_gcm_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + return gcm_init(vctx, key, keylen, iv, ivlen, params, 0); +} + +/* increment counter (64-bit int) by 1 */ +static void ctr64_inc(unsigned char *counter) +{ + int n = 8; + unsigned char c; + + do { + --n; + c = counter[n]; + ++c; + counter[n] = c; + if (c > 0) + return; + } while (n > 0); +} + +static int getivgen(PROV_GCM_CTX *ctx, unsigned char *out, size_t olen) +{ + if (!ctx->iv_gen + || !ctx->key_set + || !ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen)) + return 0; + if (olen == 0 || olen > ctx->ivlen) + olen = ctx->ivlen; + memcpy(out, ctx->iv + ctx->ivlen - olen, olen); + /* + * Invocation field will be at least 8 bytes in size and so no need + * to check wrap around or increment more than last 8 bytes. + */ + ctr64_inc(ctx->iv + ctx->ivlen - 8); + ctx->iv_state = IV_STATE_COPIED; + return 1; +} + +static int setivinv(PROV_GCM_CTX *ctx, unsigned char *in, size_t inl) +{ + if (!ctx->iv_gen + || !ctx->key_set + || ctx->enc) + return 0; + + memcpy(ctx->iv + ctx->ivlen - inl, in, inl); + if (!ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen)) + return 0; + ctx->iv_state = IV_STATE_COPIED; + return 1; +} + +int ossl_gcm_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; + OSSL_PARAM *p; + size_t sz; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN); + if (p != NULL) { + size_t taglen = (ctx->taglen != UNINITIALISED_SIZET) ? ctx->taglen : + GCM_TAG_MAX_SIZE; + + if (!OSSL_PARAM_set_size_t(p, taglen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); + if (p != NULL) { + if (ctx->iv_state == IV_STATE_UNINITIALISED) + return 0; + if (ctx->ivlen > p->data_size) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + if (!OSSL_PARAM_set_octet_string(p, ctx->iv, ctx->ivlen) + && !OSSL_PARAM_set_octet_ptr(p, &ctx->iv, ctx->ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV); + if (p != NULL) { + if (ctx->iv_state == IV_STATE_UNINITIALISED) + return 0; + if (ctx->ivlen > p->data_size) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + if (!OSSL_PARAM_set_octet_string(p, ctx->iv, ctx->ivlen) + && !OSSL_PARAM_set_octet_ptr(p, &ctx->iv, ctx->ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL) { + sz = p->data_size; + if (sz == 0 + || sz > EVP_GCM_TLS_TAG_LEN + || !ctx->enc + || ctx->taglen == UNINITIALISED_SIZET) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG); + return 0; + } + if (!OSSL_PARAM_set_octet_string(p, ctx->buf, sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN); + if (p != NULL) { + if (p->data == NULL + || p->data_type != OSSL_PARAM_OCTET_STRING + || !getivgen(ctx, p->data, p->data_size)) + return 0; + } + return 1; +} + +int ossl_gcm_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; + const OSSL_PARAM *p; + size_t sz; + void *vp; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL) { + vp = ctx->buf; + if (!OSSL_PARAM_get_octet_string(p, &vp, EVP_GCM_TLS_TAG_LEN, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (sz == 0 || ctx->enc) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG); + return 0; + } + ctx->taglen = sz; + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_IVLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (sz == 0 || sz > sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + ctx->ivlen = sz; + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + sz = gcm_tls_init(ctx, p->data, p->data_size); + if (sz == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_AAD); + return 0; + } + ctx->tls_aad_pad_sz = sz; + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (gcm_tls_iv_set_fixed(ctx, p->data, p->data_size) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV); + if (p != NULL) { + if (p->data == NULL + || p->data_type != OSSL_PARAM_OCTET_STRING + || !setivinv(ctx, p->data, p->data_size)) + return 0; + } + + + return 1; +} + +int ossl_gcm_stream_update(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; + + if (inl == 0) { + *outl = 0; + return 1; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (gcm_cipher_internal(ctx, out, outl, in, inl) <= 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + return 1; +} + +int ossl_gcm_stream_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; + int i; + + if (!ossl_prov_is_running()) + return 0; + + i = gcm_cipher_internal(ctx, out, outl, NULL, 0); + if (i <= 0) + return 0; + + *outl = 0; + return 1; +} + +int ossl_gcm_cipher(void *vctx, + unsigned char *out, size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (gcm_cipher_internal(ctx, out, outl, in, inl) <= 0) + return 0; + + *outl = inl; + return 1; +} + +/* + * See SP800-38D (GCM) Section 8 "Uniqueness requirement on IVS and keys" + * + * See also 8.2.2 RBG-based construction. + * Random construction consists of a free field (which can be NULL) and a + * random field which will use a DRBG that can return at least 96 bits of + * entropy strength. (The DRBG must be seeded by the FIPS module). + */ +static int gcm_iv_generate(PROV_GCM_CTX *ctx, int offset) +{ + int sz = ctx->ivlen - offset; + + /* Must be at least 96 bits */ + if (sz <= 0 || ctx->ivlen < GCM_IV_DEFAULT_SIZE) + return 0; + + /* Use DRBG to generate random iv */ + if (RAND_bytes_ex(ctx->libctx, ctx->iv + offset, sz, 0) <= 0) + return 0; + ctx->iv_state = IV_STATE_BUFFERED; + ctx->iv_gen_rand = 1; + return 1; +} + +static int gcm_cipher_internal(PROV_GCM_CTX *ctx, unsigned char *out, + size_t *padlen, const unsigned char *in, + size_t len) +{ + size_t olen = 0; + int rv = 0; + const PROV_GCM_HW *hw = ctx->hw; + + if (ctx->tls_aad_len != UNINITIALISED_SIZET) + return gcm_tls_cipher(ctx, out, padlen, in, len); + + if (!ctx->key_set || ctx->iv_state == IV_STATE_FINISHED) + goto err; + + /* + * FIPS requires generation of AES-GCM IV's inside the FIPS module. + * The IV can still be set externally (the security policy will state that + * this is not FIPS compliant). There are some applications + * where setting the IV externally is the only option available. + */ + if (ctx->iv_state == IV_STATE_UNINITIALISED) { + if (!ctx->enc || !gcm_iv_generate(ctx, 0)) + goto err; + } + + if (ctx->iv_state == IV_STATE_BUFFERED) { + if (!hw->setiv(ctx, ctx->iv, ctx->ivlen)) + goto err; + ctx->iv_state = IV_STATE_COPIED; + } + + if (in != NULL) { + /* The input is AAD if out is NULL */ + if (out == NULL) { + if (!hw->aadupdate(ctx, in, len)) + goto err; + } else { + /* The input is ciphertext OR plaintext */ + if (!hw->cipherupdate(ctx, in, len, out)) + goto err; + } + } else { + /* The tag must be set before actually decrypting data */ + if (!ctx->enc && ctx->taglen == UNINITIALISED_SIZET) + goto err; + if (!hw->cipherfinal(ctx, ctx->buf)) + goto err; + ctx->iv_state = IV_STATE_FINISHED; /* Don't reuse the IV */ + goto finish; + } + olen = len; +finish: + rv = 1; +err: + *padlen = olen; + return rv; +} + +static int gcm_tls_init(PROV_GCM_CTX *dat, unsigned char *aad, size_t aad_len) +{ + unsigned char *buf; + size_t len; + + if (!ossl_prov_is_running() || aad_len != EVP_AEAD_TLS1_AAD_LEN) + return 0; + + /* Save the aad for later use. */ + buf = dat->buf; + memcpy(buf, aad, aad_len); + dat->tls_aad_len = aad_len; + + len = buf[aad_len - 2] << 8 | buf[aad_len - 1]; + /* Correct length for explicit iv. */ + if (len < EVP_GCM_TLS_EXPLICIT_IV_LEN) + return 0; + len -= EVP_GCM_TLS_EXPLICIT_IV_LEN; + + /* If decrypting correct for tag too. */ + if (!dat->enc) { + if (len < EVP_GCM_TLS_TAG_LEN) + return 0; + len -= EVP_GCM_TLS_TAG_LEN; + } + buf[aad_len - 2] = (unsigned char)(len >> 8); + buf[aad_len - 1] = (unsigned char)(len & 0xff); + /* Extra padding: tag appended to record. */ + return EVP_GCM_TLS_TAG_LEN; +} + +static int gcm_tls_iv_set_fixed(PROV_GCM_CTX *ctx, unsigned char *iv, + size_t len) +{ + /* Special case: -1 length restores whole IV */ + if (len == (size_t)-1) { + memcpy(ctx->iv, iv, ctx->ivlen); + ctx->iv_gen = 1; + ctx->iv_state = IV_STATE_BUFFERED; + return 1; + } + /* Fixed field must be at least 4 bytes and invocation field at least 8 */ + if ((len < EVP_GCM_TLS_FIXED_IV_LEN) + || (ctx->ivlen - (int)len) < EVP_GCM_TLS_EXPLICIT_IV_LEN) + return 0; + if (len > 0) + memcpy(ctx->iv, iv, len); + if (ctx->enc + && RAND_bytes_ex(ctx->libctx, ctx->iv + len, ctx->ivlen - len, 0) <= 0) + return 0; + ctx->iv_gen = 1; + ctx->iv_state = IV_STATE_BUFFERED; + return 1; +} + +/* + * Handle TLS GCM packet format. This consists of the last portion of the IV + * followed by the payload and finally the tag. On encrypt generate IV, + * encrypt payload and write the tag. On verify retrieve IV, decrypt payload + * and verify tag. + */ +static int gcm_tls_cipher(PROV_GCM_CTX *ctx, unsigned char *out, size_t *padlen, + const unsigned char *in, size_t len) +{ + int rv = 0; + size_t arg = EVP_GCM_TLS_EXPLICIT_IV_LEN; + size_t plen = 0; + unsigned char *tag = NULL; + + if (!ossl_prov_is_running() || !ctx->key_set) + goto err; + + /* Encrypt/decrypt must be performed in place */ + if (out != in || len < (EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN)) + goto err; + + /* + * Check for too many keys as per FIPS 140-2 IG A.5 "Key/IV Pair Uniqueness + * Requirements from SP 800-38D". The requirements is for one party to the + * communication to fail after 2^64 - 1 keys. We do this on the encrypting + * side only. + */ + if (ctx->enc && ++ctx->tls_enc_records == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_TOO_MANY_RECORDS); + goto err; + } + + /* + * Set IV from start of buffer or generate IV and write to start of + * buffer. + */ + if (ctx->enc) { + if (!getivgen(ctx, out, arg)) + goto err; + } else { + if (!setivinv(ctx, out, arg)) + goto err; + } + + /* Fix buffer and length to point to payload */ + in += EVP_GCM_TLS_EXPLICIT_IV_LEN; + out += EVP_GCM_TLS_EXPLICIT_IV_LEN; + len -= EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN; + + tag = ctx->enc ? out + len : (unsigned char *)in + len; + if (!ctx->hw->oneshot(ctx, ctx->buf, ctx->tls_aad_len, in, len, out, tag, + EVP_GCM_TLS_TAG_LEN)) { + if (!ctx->enc) + OPENSSL_cleanse(out, len); + goto err; + } + if (ctx->enc) + plen = len + EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN; + else + plen = len; + + rv = 1; +err: + ctx->iv_state = IV_STATE_FINISHED; + ctx->tls_aad_len = UNINITIALISED_SIZET; + *padlen = plen; + return rv; +} diff --git a/providers/implementations/ciphers/ciphercommon_gcm_hw.c b/providers/implementations/ciphers/ciphercommon_gcm_hw.c new file mode 100644 index 000000000000..c0a7399640fd --- /dev/null +++ b/providers/implementations/ciphers/ciphercommon_gcm_hw.c @@ -0,0 +1,69 @@ +/* + * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/ciphercommon.h" +#include "prov/ciphercommon_gcm.h" + + +int ossl_gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv, size_t ivlen) +{ + CRYPTO_gcm128_setiv(&ctx->gcm, iv, ivlen); + return 1; +} + +int ossl_gcm_aad_update(PROV_GCM_CTX *ctx, const unsigned char *aad, + size_t aad_len) +{ + return CRYPTO_gcm128_aad(&ctx->gcm, aad, aad_len) == 0; +} + +int ossl_gcm_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in, + size_t len, unsigned char *out) +{ + if (ctx->enc) { + if (CRYPTO_gcm128_encrypt(&ctx->gcm, in, out, len)) + return 0; + } else { + if (CRYPTO_gcm128_decrypt(&ctx->gcm, in, out, len)) + return 0; + } + return 1; +} + +int ossl_gcm_cipher_final(PROV_GCM_CTX *ctx, unsigned char *tag) +{ + if (ctx->enc) { + CRYPTO_gcm128_tag(&ctx->gcm, tag, GCM_TAG_MAX_SIZE); + ctx->taglen = GCM_TAG_MAX_SIZE; + } else { + if (CRYPTO_gcm128_finish(&ctx->gcm, tag, ctx->taglen) != 0) + return 0; + } + return 1; +} + +int ossl_gcm_one_shot(PROV_GCM_CTX *ctx, unsigned char *aad, size_t aad_len, + const unsigned char *in, size_t in_len, + unsigned char *out, unsigned char *tag, size_t tag_len) +{ + int ret = 0; + + /* Use saved AAD */ + if (!ctx->hw->aadupdate(ctx, aad, aad_len)) + goto err; + if (!ctx->hw->cipherupdate(ctx, in, in_len, out)) + goto err; + ctx->taglen = GCM_TAG_MAX_SIZE; + if (!ctx->hw->cipherfinal(ctx, tag)) + goto err; + ret = 1; + +err: + return ret; +} diff --git a/providers/implementations/ciphers/ciphercommon_hw.c b/providers/implementations/ciphers/ciphercommon_hw.c new file mode 100644 index 000000000000..e73416a1c5c8 --- /dev/null +++ b/providers/implementations/ciphers/ciphercommon_hw.c @@ -0,0 +1,194 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/ciphercommon.h" + +/*- + * The generic cipher functions for cipher modes cbc, ecb, ofb, cfb and ctr. + * Used if there is no special hardware implementations. + */ +int ossl_cipher_hw_generic_cbc(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + if (dat->stream.cbc) + (*dat->stream.cbc) (in, out, len, dat->ks, dat->iv, dat->enc); + else if (dat->enc) + CRYPTO_cbc128_encrypt(in, out, len, dat->ks, dat->iv, dat->block); + else + CRYPTO_cbc128_decrypt(in, out, len, dat->ks, dat->iv, dat->block); + + return 1; +} + +int ossl_cipher_hw_generic_ecb(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + size_t i, bl = dat->blocksize; + + if (len < bl) + return 1; + + if (dat->stream.ecb) { + (*dat->stream.ecb) (in, out, len, dat->ks, dat->enc); + } + else { + for (i = 0, len -= bl; i <= len; i += bl) + (*dat->block) (in + i, out + i, dat->ks); + } + + return 1; +} + +int ossl_cipher_hw_generic_ofb128(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + int num = dat->num; + + CRYPTO_ofb128_encrypt(in, out, len, dat->ks, dat->iv, &num, dat->block); + dat->num = num; + + return 1; +} + +int ossl_cipher_hw_generic_cfb128(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + int num = dat->num; + + CRYPTO_cfb128_encrypt(in, out, len, dat->ks, dat->iv, &num, dat->enc, + dat->block); + dat->num = num; + + return 1; +} + +int ossl_cipher_hw_generic_cfb8(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + int num = dat->num; + + CRYPTO_cfb128_8_encrypt(in, out, len, dat->ks, dat->iv, &num, dat->enc, + dat->block); + dat->num = num; + + return 1; +} + +int ossl_cipher_hw_generic_cfb1(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + int num = dat->num; + + if (dat->use_bits) { + CRYPTO_cfb128_1_encrypt(in, out, len, dat->ks, dat->iv, &num, + dat->enc, dat->block); + dat->num = num; + return 1; + } + + while (len >= MAXBITCHUNK) { + CRYPTO_cfb128_1_encrypt(in, out, MAXBITCHUNK * 8, dat->ks, + dat->iv, &num, dat->enc, dat->block); + len -= MAXBITCHUNK; + out += MAXBITCHUNK; + in += MAXBITCHUNK; + } + if (len) + CRYPTO_cfb128_1_encrypt(in, out, len * 8, dat->ks, dat->iv, &num, + dat->enc, dat->block); + + dat->num = num; + + return 1; +} + +int ossl_cipher_hw_generic_ctr(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + unsigned int num = dat->num; + + if (dat->stream.ctr) + CRYPTO_ctr128_encrypt_ctr32(in, out, len, dat->ks, dat->iv, dat->buf, + &num, dat->stream.ctr); + else + CRYPTO_ctr128_encrypt(in, out, len, dat->ks, dat->iv, dat->buf, + &num, dat->block); + dat->num = num; + + return 1; +} + +/*- + * The chunked cipher functions for cipher modes cbc, ecb, ofb, cfb and ctr. + * Used if there is no special hardware implementations. + */ + +int ossl_cipher_hw_chunked_cbc(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + while (inl >= MAXCHUNK) { + ossl_cipher_hw_generic_cbc(ctx, out, in, MAXCHUNK); + inl -= MAXCHUNK; + in += MAXCHUNK; + out += MAXCHUNK; + } + if (inl > 0) + ossl_cipher_hw_generic_cbc(ctx, out, in, inl); + return 1; +} + +int ossl_cipher_hw_chunked_cfb8(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + size_t chunk = MAXCHUNK; + + if (inl < chunk) + chunk = inl; + while (inl > 0 && inl >= chunk) { + ossl_cipher_hw_generic_cfb8(ctx, out, in, inl); + inl -= chunk; + in += chunk; + out += chunk; + if (inl < chunk) + chunk = inl; + } + return 1; +} + +int ossl_cipher_hw_chunked_cfb128(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + size_t chunk = MAXCHUNK; + + if (inl < chunk) + chunk = inl; + while (inl > 0 && inl >= chunk) { + ossl_cipher_hw_generic_cfb128(ctx, out, in, inl); + inl -= chunk; + in += chunk; + out += chunk; + if (inl < chunk) + chunk = inl; + } + return 1; +} + +int ossl_cipher_hw_chunked_ofb128(PROV_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + while (inl >= MAXCHUNK) { + ossl_cipher_hw_generic_ofb128(ctx, out, in, MAXCHUNK); + inl -= MAXCHUNK; + in += MAXCHUNK; + out += MAXCHUNK; + } + if (inl > 0) + ossl_cipher_hw_generic_ofb128(ctx, out, in, inl); + return 1; +} diff --git a/providers/implementations/ciphers/ciphercommon_local.h b/providers/implementations/ciphers/ciphercommon_local.h new file mode 100644 index 000000000000..11cb6116a815 --- /dev/null +++ b/providers/implementations/ciphers/ciphercommon_local.h @@ -0,0 +1,16 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/ciphercommon.h" + +void ossl_cipher_padblock(unsigned char *buf, size_t *buflen, size_t blocksize); +int ossl_cipher_unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize); +int ossl_cipher_tlsunpadblock(OSSL_LIB_CTX *libctx, unsigned int tlsversion, + unsigned char *buf, size_t *buflen, size_t blocksize, + unsigned char **mac, int *alloced, size_t macsize, int aead); diff --git a/providers/implementations/digests/blake2_impl.h b/providers/implementations/digests/blake2_impl.h new file mode 100644 index 000000000000..e7c31474a364 --- /dev/null +++ b/providers/implementations/digests/blake2_impl.h @@ -0,0 +1,118 @@ +/* + * Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Derived from the BLAKE2 reference implementation written by Samuel Neves. + * Copyright 2012, Samuel Neves <sneves@dei.uc.pt> + * More information about the BLAKE2 hash function and its implementations + * can be found at https://blake2.net. + */ + +#include <string.h> +#include "internal/endian.h" + +static ossl_inline uint32_t load32(const uint8_t *src) +{ + DECLARE_IS_ENDIAN; + + if (IS_LITTLE_ENDIAN) { + uint32_t w; + memcpy(&w, src, sizeof(w)); + return w; + } else { + uint32_t w = ((uint32_t)src[0]) + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); + return w; + } +} + +static ossl_inline uint64_t load64(const uint8_t *src) +{ + DECLARE_IS_ENDIAN; + + if (IS_LITTLE_ENDIAN) { + uint64_t w; + memcpy(&w, src, sizeof(w)); + return w; + } else { + uint64_t w = ((uint64_t)src[0]) + | ((uint64_t)src[1] << 8) + | ((uint64_t)src[2] << 16) + | ((uint64_t)src[3] << 24) + | ((uint64_t)src[4] << 32) + | ((uint64_t)src[5] << 40) + | ((uint64_t)src[6] << 48) + | ((uint64_t)src[7] << 56); + return w; + } +} + +static ossl_inline void store32(uint8_t *dst, uint32_t w) +{ + DECLARE_IS_ENDIAN; + + if (IS_LITTLE_ENDIAN) { + memcpy(dst, &w, sizeof(w)); + } else { + uint8_t *p = (uint8_t *)dst; + int i; + + for (i = 0; i < 4; i++) + p[i] = (uint8_t)(w >> (8 * i)); + } +} + +static ossl_inline void store64(uint8_t *dst, uint64_t w) +{ + DECLARE_IS_ENDIAN; + + if (IS_LITTLE_ENDIAN) { + memcpy(dst, &w, sizeof(w)); + } else { + uint8_t *p = (uint8_t *)dst; + int i; + + for (i = 0; i < 8; i++) + p[i] = (uint8_t)(w >> (8 * i)); + } +} + +static ossl_inline uint64_t load48(const uint8_t *src) +{ + uint64_t w = ((uint64_t)src[0]) + | ((uint64_t)src[1] << 8) + | ((uint64_t)src[2] << 16) + | ((uint64_t)src[3] << 24) + | ((uint64_t)src[4] << 32) + | ((uint64_t)src[5] << 40); + return w; +} + +static ossl_inline void store48(uint8_t *dst, uint64_t w) +{ + uint8_t *p = (uint8_t *)dst; + p[0] = (uint8_t)w; + p[1] = (uint8_t)(w>>8); + p[2] = (uint8_t)(w>>16); + p[3] = (uint8_t)(w>>24); + p[4] = (uint8_t)(w>>32); + p[5] = (uint8_t)(w>>40); +} + +static ossl_inline uint32_t rotr32(const uint32_t w, const unsigned int c) +{ + return (w >> c) | (w << (32 - c)); +} + +static ossl_inline uint64_t rotr64(const uint64_t w, const unsigned int c) +{ + return (w >> c) | (w << (64 - c)); +} diff --git a/providers/implementations/digests/blake2_prov.c b/providers/implementations/digests/blake2_prov.c new file mode 100644 index 000000000000..25342eedb832 --- /dev/null +++ b/providers/implementations/digests/blake2_prov.c @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/crypto.h> +#include "prov/blake2.h" +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +int ossl_blake2s256_init(void *ctx) +{ + BLAKE2S_PARAM P; + + ossl_blake2s_param_init(&P); + return ossl_blake2s_init((BLAKE2S_CTX *)ctx, &P); +} + +int ossl_blake2b512_init(void *ctx) +{ + BLAKE2B_PARAM P; + + ossl_blake2b_param_init(&P); + return ossl_blake2b_init((BLAKE2B_CTX *)ctx, &P); +} + +/* ossl_blake2s256_functions */ +IMPLEMENT_digest_functions(blake2s256, BLAKE2S_CTX, + BLAKE2S_BLOCKBYTES, BLAKE2S_DIGEST_LENGTH, 0, + ossl_blake2s256_init, ossl_blake2s_update, + ossl_blake2s_final) + +/* ossl_blake2b512_functions */ +IMPLEMENT_digest_functions(blake2b512, BLAKE2B_CTX, + BLAKE2B_BLOCKBYTES, BLAKE2B_DIGEST_LENGTH, 0, + ossl_blake2b512_init, ossl_blake2b_update, + ossl_blake2b_final) diff --git a/providers/implementations/digests/blake2b_prov.c b/providers/implementations/digests/blake2b_prov.c new file mode 100644 index 000000000000..11271e1b59d3 --- /dev/null +++ b/providers/implementations/digests/blake2b_prov.c @@ -0,0 +1,331 @@ +/* + * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Derived from the BLAKE2 reference implementation written by Samuel Neves. + * Copyright 2012, Samuel Neves <sneves@dei.uc.pt> + * More information about the BLAKE2 hash function and its implementations + * can be found at https://blake2.net. + */ + +#include <assert.h> +#include <string.h> +#include <openssl/crypto.h> +#include "blake2_impl.h" +#include "prov/blake2.h" + +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const uint8_t blake2b_sigma[12][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + +/* Set that it's the last block we'll compress */ +static ossl_inline void blake2b_set_lastblock(BLAKE2B_CTX *S) +{ + S->f[0] = -1; +} + +/* Initialize the hashing state. */ +static ossl_inline void blake2b_init0(BLAKE2B_CTX *S) +{ + int i; + + memset(S, 0, sizeof(BLAKE2B_CTX)); + for (i = 0; i < 8; ++i) { + S->h[i] = blake2b_IV[i]; + } +} + +/* init xors IV with input parameter block and sets the output length */ +static void blake2b_init_param(BLAKE2B_CTX *S, const BLAKE2B_PARAM *P) +{ + size_t i; + const uint8_t *p = (const uint8_t *)(P); + + blake2b_init0(S); + S->outlen = P->digest_length; + + /* The param struct is carefully hand packed, and should be 64 bytes on + * every platform. */ + assert(sizeof(BLAKE2B_PARAM) == 64); + /* IV XOR ParamBlock */ + for (i = 0; i < 8; ++i) { + S->h[i] ^= load64(p + sizeof(S->h[i]) * i); + } +} + +/* Initialize the parameter block with default values */ +void ossl_blake2b_param_init(BLAKE2B_PARAM *P) +{ + P->digest_length = BLAKE2B_DIGEST_LENGTH; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32(P->leaf_length, 0); + store64(P->node_offset, 0); + P->node_depth = 0; + P->inner_length = 0; + memset(P->reserved, 0, sizeof(P->reserved)); + memset(P->salt, 0, sizeof(P->salt)); + memset(P->personal, 0, sizeof(P->personal)); +} + +void ossl_blake2b_param_set_digest_length(BLAKE2B_PARAM *P, uint8_t outlen) +{ + P->digest_length = outlen; +} + +void ossl_blake2b_param_set_key_length(BLAKE2B_PARAM *P, uint8_t keylen) +{ + P->key_length = keylen; +} + +void ossl_blake2b_param_set_personal(BLAKE2B_PARAM *P, const uint8_t *personal, + size_t len) +{ + memcpy(P->personal, personal, len); + memset(P->personal + len, 0, BLAKE2B_PERSONALBYTES - len); +} + +void ossl_blake2b_param_set_salt(BLAKE2B_PARAM *P, const uint8_t *salt, + size_t len) +{ + memcpy(P->salt, salt, len); + memset(P->salt + len, 0, BLAKE2B_SALTBYTES - len); +} + +/* + * Initialize the hashing context with the given parameter block. + * Always returns 1. + */ +int ossl_blake2b_init(BLAKE2B_CTX *c, const BLAKE2B_PARAM *P) +{ + blake2b_init_param(c, P); + return 1; +} + +/* + * Initialize the hashing context with the given parameter block and key. + * Always returns 1. + */ +int ossl_blake2b_init_key(BLAKE2B_CTX *c, const BLAKE2B_PARAM *P, + const void *key) +{ + blake2b_init_param(c, P); + + /* Pad the key to form first data block */ + { + uint8_t block[BLAKE2B_BLOCKBYTES] = {0}; + + memcpy(block, key, P->key_length); + ossl_blake2b_update(c, block, BLAKE2B_BLOCKBYTES); + OPENSSL_cleanse(block, BLAKE2B_BLOCKBYTES); + } + + return 1; +} + +/* Permute the state while xoring in the block of data. */ +static void blake2b_compress(BLAKE2B_CTX *S, + const uint8_t *blocks, + size_t len) +{ + uint64_t m[16]; + uint64_t v[16]; + int i; + size_t increment; + + /* + * There are two distinct usage vectors for this function: + * + * a) BLAKE2b_Update uses it to process complete blocks, + * possibly more than one at a time; + * + * b) BLAK2b_Final uses it to process last block, always + * single but possibly incomplete, in which case caller + * pads input with zeros. + */ + assert(len < BLAKE2B_BLOCKBYTES || len % BLAKE2B_BLOCKBYTES == 0); + + /* + * Since last block is always processed with separate call, + * |len| not being multiple of complete blocks can be observed + * only with |len| being less than BLAKE2B_BLOCKBYTES ("less" + * including even zero), which is why following assignment doesn't + * have to reside inside the main loop below. + */ + increment = len < BLAKE2B_BLOCKBYTES ? len : BLAKE2B_BLOCKBYTES; + + for (i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + do { + for (i = 0; i < 16; ++i) { + m[i] = load64(blocks + i * sizeof(m[i])); + } + + /* blake2b_increment_counter */ + S->t[0] += increment; + S->t[1] += (S->t[0] < increment); + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = S->t[0] ^ blake2b_IV[4]; + v[13] = S->t[1] ^ blake2b_IV[5]; + v[14] = S->f[0] ^ blake2b_IV[6]; + v[15] = S->f[1] ^ blake2b_IV[7]; +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2*i+0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2*i+1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while (0) +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while (0) +#if defined(OPENSSL_SMALL_FOOTPRINT) + /* 3x size reduction on x86_64, almost 7x on ARMv8, 9x on ARMv4 */ + for (i = 0; i < 12; i++) { + ROUND(i); + } +#else + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + ROUND(10); + ROUND(11); +#endif + + for (i = 0; i < 8; ++i) { + S->h[i] = v[i] ^= v[i + 8] ^ S->h[i]; + } +#undef G +#undef ROUND + blocks += increment; + len -= increment; + } while (len); +} + +/* Absorb the input data into the hash state. Always returns 1. */ +int ossl_blake2b_update(BLAKE2B_CTX *c, const void *data, size_t datalen) +{ + const uint8_t *in = data; + size_t fill; + + /* + * Intuitively one would expect intermediate buffer, c->buf, to + * store incomplete blocks. But in this case we are interested to + * temporarily stash even complete blocks, because last one in the + * stream has to be treated in special way, and at this point we + * don't know if last block in *this* call is last one "ever". This + * is the reason for why |datalen| is compared as >, and not >=. + */ + fill = sizeof(c->buf) - c->buflen; + if (datalen > fill) { + if (c->buflen) { + memcpy(c->buf + c->buflen, in, fill); /* Fill buffer */ + blake2b_compress(c, c->buf, BLAKE2B_BLOCKBYTES); + c->buflen = 0; + in += fill; + datalen -= fill; + } + if (datalen > BLAKE2B_BLOCKBYTES) { + size_t stashlen = datalen % BLAKE2B_BLOCKBYTES; + /* + * If |datalen| is a multiple of the blocksize, stash + * last complete block, it can be final one... + */ + stashlen = stashlen ? stashlen : BLAKE2B_BLOCKBYTES; + datalen -= stashlen; + blake2b_compress(c, in, datalen); + in += datalen; + datalen = stashlen; + } + } + + assert(datalen <= BLAKE2B_BLOCKBYTES); + + memcpy(c->buf + c->buflen, in, datalen); + c->buflen += datalen; /* Be lazy, do not compress */ + + return 1; +} + +/* + * Calculate the final hash and save it in md. + * Always returns 1. + */ +int ossl_blake2b_final(unsigned char *md, BLAKE2B_CTX *c) +{ + uint8_t outbuffer[BLAKE2B_OUTBYTES] = {0}; + uint8_t *target = outbuffer; + int iter = (c->outlen + 7) / 8; + int i; + + /* Avoid writing to the temporary buffer if possible */ + if ((c->outlen % sizeof(c->h[0])) == 0) + target = md; + + blake2b_set_lastblock(c); + /* Padding */ + memset(c->buf + c->buflen, 0, sizeof(c->buf) - c->buflen); + blake2b_compress(c, c->buf, c->buflen); + + /* Output full hash to buffer */ + for (i = 0; i < iter; ++i) + store64(target + sizeof(c->h[i]) * i, c->h[i]); + + if (target != md) + memcpy(md, target, c->outlen); + + OPENSSL_cleanse(c, sizeof(BLAKE2B_CTX)); + return 1; +} diff --git a/providers/implementations/digests/blake2s_prov.c b/providers/implementations/digests/blake2s_prov.c new file mode 100644 index 000000000000..a9a8f9d048a2 --- /dev/null +++ b/providers/implementations/digests/blake2s_prov.c @@ -0,0 +1,322 @@ +/* + * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Derived from the BLAKE2 reference implementation written by Samuel Neves. + * Copyright 2012, Samuel Neves <sneves@dei.uc.pt> + * More information about the BLAKE2 hash function and its implementations + * can be found at https://blake2.net. + */ + +#include <assert.h> +#include <string.h> +#include <openssl/crypto.h> +#include "blake2_impl.h" +#include "prov/blake2.h" + +static const uint32_t blake2s_IV[8] = +{ + 0x6A09E667U, 0xBB67AE85U, 0x3C6EF372U, 0xA54FF53AU, + 0x510E527FU, 0x9B05688CU, 0x1F83D9ABU, 0x5BE0CD19U +}; + +static const uint8_t blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +/* Set that it's the last block we'll compress */ +static ossl_inline void blake2s_set_lastblock(BLAKE2S_CTX *S) +{ + S->f[0] = -1; +} + +/* Initialize the hashing state. */ +static ossl_inline void blake2s_init0(BLAKE2S_CTX *S) +{ + int i; + + memset(S, 0, sizeof(BLAKE2S_CTX)); + for (i = 0; i < 8; ++i) { + S->h[i] = blake2s_IV[i]; + } +} + +/* init xors IV with input parameter block and sets the output length */ +static void blake2s_init_param(BLAKE2S_CTX *S, const BLAKE2S_PARAM *P) +{ + size_t i; + const uint8_t *p = (const uint8_t *)(P); + + blake2s_init0(S); + S->outlen = P->digest_length; + + /* The param struct is carefully hand packed, and should be 32 bytes on + * every platform. */ + assert(sizeof(BLAKE2S_PARAM) == 32); + /* IV XOR ParamBlock */ + for (i = 0; i < 8; ++i) { + S->h[i] ^= load32(&p[i*4]); + } +} + +void ossl_blake2s_param_init(BLAKE2S_PARAM *P) +{ + P->digest_length = BLAKE2S_DIGEST_LENGTH; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32(P->leaf_length, 0); + store48(P->node_offset, 0); + P->node_depth = 0; + P->inner_length = 0; + memset(P->salt, 0, sizeof(P->salt)); + memset(P->personal, 0, sizeof(P->personal)); +} + +void ossl_blake2s_param_set_digest_length(BLAKE2S_PARAM *P, uint8_t outlen) +{ + P->digest_length = outlen; +} + +void ossl_blake2s_param_set_key_length(BLAKE2S_PARAM *P, uint8_t keylen) +{ + P->key_length = keylen; +} + +void ossl_blake2s_param_set_personal(BLAKE2S_PARAM *P, const uint8_t *personal, + size_t len) +{ + memcpy(P->personal, personal, len); + memset(P->personal + len, 0, BLAKE2S_PERSONALBYTES - len); +} + +void ossl_blake2s_param_set_salt(BLAKE2S_PARAM *P, const uint8_t *salt, + size_t len) +{ + memcpy(P->salt, salt, len); + memset(P->salt + len, 0, BLAKE2S_SALTBYTES - len);} + +/* + * Initialize the hashing context with the given parameter block. + * Always returns 1. + */ +int ossl_blake2s_init(BLAKE2S_CTX *c, const BLAKE2S_PARAM *P) +{ + blake2s_init_param(c, P); + return 1; +} + +/* + * Initialize the hashing context with the given parameter block and key. + * Always returns 1. + */ +int ossl_blake2s_init_key(BLAKE2S_CTX *c, const BLAKE2S_PARAM *P, + const void *key) +{ + blake2s_init_param(c, P); + + /* Pad the key to form first data block */ + { + uint8_t block[BLAKE2S_BLOCKBYTES] = {0}; + + memcpy(block, key, P->key_length); + ossl_blake2s_update(c, block, BLAKE2S_BLOCKBYTES); + OPENSSL_cleanse(block, BLAKE2S_BLOCKBYTES); + } + + return 1; +} + +/* Permute the state while xoring in the block of data. */ +static void blake2s_compress(BLAKE2S_CTX *S, + const uint8_t *blocks, + size_t len) +{ + uint32_t m[16]; + uint32_t v[16]; + size_t i; + size_t increment; + + /* + * There are two distinct usage vectors for this function: + * + * a) BLAKE2s_Update uses it to process complete blocks, + * possibly more than one at a time; + * + * b) BLAK2s_Final uses it to process last block, always + * single but possibly incomplete, in which case caller + * pads input with zeros. + */ + assert(len < BLAKE2S_BLOCKBYTES || len % BLAKE2S_BLOCKBYTES == 0); + + /* + * Since last block is always processed with separate call, + * |len| not being multiple of complete blocks can be observed + * only with |len| being less than BLAKE2S_BLOCKBYTES ("less" + * including even zero), which is why following assignment doesn't + * have to reside inside the main loop below. + */ + increment = len < BLAKE2S_BLOCKBYTES ? len : BLAKE2S_BLOCKBYTES; + + for (i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + do { + for (i = 0; i < 16; ++i) { + m[i] = load32(blocks + i * sizeof(m[i])); + } + + /* blake2s_increment_counter */ + S->t[0] += increment; + S->t[1] += (S->t[0] < increment); + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); \ + } while (0) +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while (0) +#if defined(OPENSSL_SMALL_FOOTPRINT) + /* almost 3x reduction on x86_64, 4.5x on ARMv8, 4x on ARMv4 */ + for (i = 0; i < 10; i++) { + ROUND(i); + } +#else + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); +#endif + + for (i = 0; i < 8; ++i) { + S->h[i] = v[i] ^= v[i + 8] ^ S->h[i]; + } +#undef G +#undef ROUND + blocks += increment; + len -= increment; + } while (len); +} + +/* Absorb the input data into the hash state. Always returns 1. */ +int ossl_blake2s_update(BLAKE2S_CTX *c, const void *data, size_t datalen) +{ + const uint8_t *in = data; + size_t fill; + + /* + * Intuitively one would expect intermediate buffer, c->buf, to + * store incomplete blocks. But in this case we are interested to + * temporarily stash even complete blocks, because last one in the + * stream has to be treated in special way, and at this point we + * don't know if last block in *this* call is last one "ever". This + * is the reason for why |datalen| is compared as >, and not >=. + */ + fill = sizeof(c->buf) - c->buflen; + if (datalen > fill) { + if (c->buflen) { + memcpy(c->buf + c->buflen, in, fill); /* Fill buffer */ + blake2s_compress(c, c->buf, BLAKE2S_BLOCKBYTES); + c->buflen = 0; + in += fill; + datalen -= fill; + } + if (datalen > BLAKE2S_BLOCKBYTES) { + size_t stashlen = datalen % BLAKE2S_BLOCKBYTES; + /* + * If |datalen| is a multiple of the blocksize, stash + * last complete block, it can be final one... + */ + stashlen = stashlen ? stashlen : BLAKE2S_BLOCKBYTES; + datalen -= stashlen; + blake2s_compress(c, in, datalen); + in += datalen; + datalen = stashlen; + } + } + + assert(datalen <= BLAKE2S_BLOCKBYTES); + + memcpy(c->buf + c->buflen, in, datalen); + c->buflen += datalen; /* Be lazy, do not compress */ + + return 1; +} + +/* + * Calculate the final hash and save it in md. + * Always returns 1. + */ +int ossl_blake2s_final(unsigned char *md, BLAKE2S_CTX *c) +{ + uint8_t outbuffer[BLAKE2S_OUTBYTES] = {0}; + uint8_t *target = outbuffer; + int iter = (c->outlen + 3) / 4; + int i; + + /* Avoid writing to the temporary buffer if possible */ + if ((c->outlen % sizeof(c->h[0])) == 0) + target = md; + + blake2s_set_lastblock(c); + /* Padding */ + memset(c->buf + c->buflen, 0, sizeof(c->buf) - c->buflen); + blake2s_compress(c, c->buf, c->buflen); + + /* Output full hash to buffer */ + for (i = 0; i < iter; ++i) + store32(target + sizeof(c->h[i]) * i, c->h[i]); + + if (target != md) + memcpy(md, target, c->outlen); + + OPENSSL_cleanse(c, sizeof(BLAKE2S_CTX)); + return 1; +} diff --git a/providers/implementations/digests/build.info b/providers/implementations/digests/build.info new file mode 100644 index 000000000000..d30975028e9f --- /dev/null +++ b/providers/implementations/digests/build.info @@ -0,0 +1,62 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$COMMON_GOAL=../../libcommon.a + +$SHA1_GOAL=../../libdefault.a ../../libfips.a +$SHA2_GOAL=../../libdefault.a ../../libfips.a +$SHA3_GOAL=../../libdefault.a ../../libfips.a +$BLAKE2_GOAL=../../libdefault.a +$SM3_GOAL=../../libdefault.a +$MD5_GOAL=../../libdefault.a +$NULL_GOAL=../../libdefault.a + +$MD2_GOAL=../../liblegacy.a +$MD4_GOAL=../../liblegacy.a +$MDC2_GOAL=../../liblegacy.a +$WHIRLPOOL_GOAL=../../liblegacy.a +IF[{- !$disabled{module} -}] + $RIPEMD_GOAL=../../libdefault.a ../../liblegacy.a +ELSE + $RIPEMD_GOAL=../../libdefault.a +ENDIF + +# This source is common for all digests in all our providers. +SOURCE[$COMMON_GOAL]=digestcommon.c + +SOURCE[$SHA2_GOAL]=sha2_prov.c +SOURCE[$SHA3_GOAL]=sha3_prov.c + +SOURCE[$NULL_GOAL]=null_prov.c + +IF[{- !$disabled{blake2} -}] + SOURCE[$BLAKE2_GOAL]=blake2_prov.c blake2b_prov.c blake2s_prov.c +ENDIF + +IF[{- !$disabled{sm3} -}] + SOURCE[$SM3_GOAL]=sm3_prov.c +ENDIF + +IF[{- !$disabled{md5} -}] + SOURCE[$MD5_GOAL]=md5_prov.c md5_sha1_prov.c +ENDIF + +IF[{- !$disabled{md2} -}] + SOURCE[$MD2_GOAL]=md2_prov.c +ENDIF + +IF[{- !$disabled{md4} -}] + SOURCE[$MD4_GOAL]=md4_prov.c +ENDIF + +IF[{- !$disabled{mdc2} -}] + SOURCE[$MDC2_GOAL]=mdc2_prov.c +ENDIF + +IF[{- !$disabled{whirlpool} -}] + SOURCE[$WHIRLPOOL_GOAL]=wp_prov.c +ENDIF + +IF[{- !$disabled{rmd160} -}] + SOURCE[$RIPEMD_GOAL]=ripemd_prov.c +ENDIF diff --git a/providers/implementations/digests/digestcommon.c b/providers/implementations/digests/digestcommon.c new file mode 100644 index 000000000000..5cd1d1620062 --- /dev/null +++ b/providers/implementations/digests/digestcommon.c @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/err.h> +#include <openssl/proverr.h> +#include "prov/digestcommon.h" + +int ossl_digest_default_get_params(OSSL_PARAM params[], size_t blksz, + size_t paramsz, unsigned long flags) +{ + OSSL_PARAM *p = NULL; + + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_BLOCK_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, blksz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, paramsz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_XOF); + if (p != NULL + && !OSSL_PARAM_set_int(p, (flags & PROV_DIGEST_FLAG_XOF) != 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_ALGID_ABSENT); + if (p != NULL + && !OSSL_PARAM_set_int(p, (flags & PROV_DIGEST_FLAG_ALGID_ABSENT) != 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + return 1; +} + +static const OSSL_PARAM digest_default_known_gettable_params[] = { + OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_SIZE, NULL), + OSSL_PARAM_int(OSSL_DIGEST_PARAM_XOF, NULL), + OSSL_PARAM_int(OSSL_DIGEST_PARAM_ALGID_ABSENT, NULL), + OSSL_PARAM_END +}; +const OSSL_PARAM *ossl_digest_default_gettable_params(void *provctx) +{ + return digest_default_known_gettable_params; +} diff --git a/providers/implementations/digests/md2_prov.c b/providers/implementations/digests/md2_prov.c new file mode 100644 index 000000000000..a41a02c19890 --- /dev/null +++ b/providers/implementations/digests/md2_prov.c @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * MD2 low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/crypto.h> +#include <openssl/md2.h> +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +/* ossl_md2_functions */ +IMPLEMENT_digest_functions(md2, MD2_CTX, + MD2_BLOCK, MD2_DIGEST_LENGTH, 0, + MD2_Init, MD2_Update, MD2_Final) diff --git a/providers/implementations/digests/md4_prov.c b/providers/implementations/digests/md4_prov.c new file mode 100644 index 000000000000..97f73018c275 --- /dev/null +++ b/providers/implementations/digests/md4_prov.c @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * MD4 low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/crypto.h> +#include <openssl/md4.h> +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +/* ossl_md4_functions */ +IMPLEMENT_digest_functions(md4, MD4_CTX, + MD4_CBLOCK, MD4_DIGEST_LENGTH, 0, + MD4_Init, MD4_Update, MD4_Final) diff --git a/providers/implementations/digests/md5_prov.c b/providers/implementations/digests/md5_prov.c new file mode 100644 index 000000000000..a330e057f547 --- /dev/null +++ b/providers/implementations/digests/md5_prov.c @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * MD5 low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/crypto.h> +#include <openssl/md5.h> +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +/* ossl_md5_functions */ +IMPLEMENT_digest_functions(md5, MD5_CTX, + MD5_CBLOCK, MD5_DIGEST_LENGTH, 0, + MD5_Init, MD5_Update, MD5_Final) diff --git a/providers/implementations/digests/md5_sha1_prov.c b/providers/implementations/digests/md5_sha1_prov.c new file mode 100644 index 000000000000..e7b8389b2b5c --- /dev/null +++ b/providers/implementations/digests/md5_sha1_prov.c @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * MD5 and SHA-1 low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/evp.h> +#include <openssl/params.h> +#include <openssl/core_names.h> +#include "prov/md5_sha1.h" +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +static OSSL_FUNC_digest_set_ctx_params_fn md5_sha1_set_ctx_params; +static OSSL_FUNC_digest_settable_ctx_params_fn md5_sha1_settable_ctx_params; + +static const OSSL_PARAM known_md5_sha1_settable_ctx_params[] = { + {OSSL_DIGEST_PARAM_SSL3_MS, OSSL_PARAM_OCTET_STRING, NULL, 0, 0}, + OSSL_PARAM_END +}; + +static const OSSL_PARAM *md5_sha1_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_md5_sha1_settable_ctx_params; +} + +/* Special set_params method for SSL3 */ +static int md5_sha1_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + MD5_SHA1_CTX *ctx = (MD5_SHA1_CTX *)vctx; + + if (ctx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_DIGEST_PARAM_SSL3_MS); + if (p != NULL && p->data_type == OSSL_PARAM_OCTET_STRING) + return ossl_md5_sha1_ctrl(ctx, EVP_CTRL_SSL3_MASTER_SECRET, + p->data_size, p->data); + return 1; +} + +/* ossl_md5_sha1_functions */ +IMPLEMENT_digest_functions_with_settable_ctx( + md5_sha1, MD5_SHA1_CTX, MD5_SHA1_CBLOCK, MD5_SHA1_DIGEST_LENGTH, 0, + ossl_md5_sha1_init, ossl_md5_sha1_update, ossl_md5_sha1_final, + md5_sha1_settable_ctx_params, md5_sha1_set_ctx_params) diff --git a/providers/implementations/digests/mdc2_prov.c b/providers/implementations/digests/mdc2_prov.c new file mode 100644 index 000000000000..de39f8a10482 --- /dev/null +++ b/providers/implementations/digests/mdc2_prov.c @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * MDC2 low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/crypto.h> +#include <openssl/params.h> +#include <openssl/mdc2.h> +#include <openssl/core_names.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +static OSSL_FUNC_digest_set_ctx_params_fn mdc2_set_ctx_params; +static OSSL_FUNC_digest_settable_ctx_params_fn mdc2_settable_ctx_params; + +static const OSSL_PARAM known_mdc2_settable_ctx_params[] = { + OSSL_PARAM_uint(OSSL_DIGEST_PARAM_PAD_TYPE, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *mdc2_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_mdc2_settable_ctx_params; +} + +static int mdc2_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + MDC2_CTX *ctx = (MDC2_CTX *)vctx; + + if (ctx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_DIGEST_PARAM_PAD_TYPE); + if (p != NULL && !OSSL_PARAM_get_uint(p, &ctx->pad_type)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + return 1; +} + +/* ossl_mdc2_functions */ +IMPLEMENT_digest_functions_with_settable_ctx( + mdc2, MDC2_CTX, MDC2_BLOCK, MDC2_DIGEST_LENGTH, 0, + MDC2_Init, MDC2_Update, MDC2_Final, + mdc2_settable_ctx_params, mdc2_set_ctx_params) diff --git a/providers/implementations/digests/null_prov.c b/providers/implementations/digests/null_prov.c new file mode 100644 index 000000000000..b220a1966ff7 --- /dev/null +++ b/providers/implementations/digests/null_prov.c @@ -0,0 +1,52 @@ +/* + * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/crypto.h> +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +typedef struct { + unsigned char nothing; +} NULLMD_CTX; + +static int null_init(NULLMD_CTX *ctx) +{ + return 1; +} + +static int null_update(NULLMD_CTX *ctx, const void *data, size_t datalen) +{ + return 1; +} + +static int null_final(unsigned char *md, NULLMD_CTX *ctx) +{ + return 1; +} + +/* + * We must override the PROV_FUNC_DIGEST_FINAL as dgstsize == 0 + * and that would cause compilation warnings with the default implementation. + */ +#undef PROV_FUNC_DIGEST_FINAL +#define PROV_FUNC_DIGEST_FINAL(name, dgstsize, fin) \ +static OSSL_FUNC_digest_final_fn name##_internal_final; \ +static int name##_internal_final(void *ctx, unsigned char *out, size_t *outl, \ + size_t outsz) \ +{ \ + if (ossl_prov_is_running() && fin(out, ctx)) { \ + *outl = dgstsize; \ + return 1; \ + } \ + return 0; \ +} + +IMPLEMENT_digest_functions(nullmd, NULLMD_CTX, + 0, 0, 0, + null_init, null_update, null_final) diff --git a/providers/implementations/digests/ripemd_prov.c b/providers/implementations/digests/ripemd_prov.c new file mode 100644 index 000000000000..526706c06dcc --- /dev/null +++ b/providers/implementations/digests/ripemd_prov.c @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * RIPEMD160 low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/crypto.h> +#include <openssl/ripemd.h> +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +/* ossl_ripemd160_functions */ +IMPLEMENT_digest_functions(ripemd160, RIPEMD160_CTX, + RIPEMD160_CBLOCK, RIPEMD160_DIGEST_LENGTH, 0, + RIPEMD160_Init, RIPEMD160_Update, RIPEMD160_Final) diff --git a/providers/implementations/digests/sha2_prov.c b/providers/implementations/digests/sha2_prov.c new file mode 100644 index 000000000000..3b731796bdc4 --- /dev/null +++ b/providers/implementations/digests/sha2_prov.c @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * SHA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/crypto.h> +#include <openssl/core_dispatch.h> +#include <openssl/evp.h> +#include <openssl/sha.h> +#include <openssl/evp.h> +#include <openssl/params.h> +#include <openssl/core_names.h> +#include "prov/digestcommon.h" +#include "prov/implementations.h" +#include "crypto/sha.h" + +#define SHA2_FLAGS PROV_DIGEST_FLAG_ALGID_ABSENT + +static OSSL_FUNC_digest_set_ctx_params_fn sha1_set_ctx_params; +static OSSL_FUNC_digest_settable_ctx_params_fn sha1_settable_ctx_params; + +static const OSSL_PARAM known_sha1_settable_ctx_params[] = { + {OSSL_DIGEST_PARAM_SSL3_MS, OSSL_PARAM_OCTET_STRING, NULL, 0, 0}, + OSSL_PARAM_END +}; +static const OSSL_PARAM *sha1_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_sha1_settable_ctx_params; +} + +/* Special set_params method for SSL3 */ +static int sha1_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + SHA_CTX *ctx = (SHA_CTX *)vctx; + + if (ctx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_DIGEST_PARAM_SSL3_MS); + if (p != NULL && p->data_type == OSSL_PARAM_OCTET_STRING) + return ossl_sha1_ctrl(ctx, EVP_CTRL_SSL3_MASTER_SECRET, + p->data_size, p->data); + return 1; +} + +/* ossl_sha1_functions */ +IMPLEMENT_digest_functions_with_settable_ctx( + sha1, SHA_CTX, SHA_CBLOCK, SHA_DIGEST_LENGTH, SHA2_FLAGS, + SHA1_Init, SHA1_Update, SHA1_Final, + sha1_settable_ctx_params, sha1_set_ctx_params) + +/* ossl_sha224_functions */ +IMPLEMENT_digest_functions(sha224, SHA256_CTX, + SHA256_CBLOCK, SHA224_DIGEST_LENGTH, SHA2_FLAGS, + SHA224_Init, SHA224_Update, SHA224_Final) + +/* ossl_sha256_functions */ +IMPLEMENT_digest_functions(sha256, SHA256_CTX, + SHA256_CBLOCK, SHA256_DIGEST_LENGTH, SHA2_FLAGS, + SHA256_Init, SHA256_Update, SHA256_Final) + +/* ossl_sha384_functions */ +IMPLEMENT_digest_functions(sha384, SHA512_CTX, + SHA512_CBLOCK, SHA384_DIGEST_LENGTH, SHA2_FLAGS, + SHA384_Init, SHA384_Update, SHA384_Final) + +/* ossl_sha512_functions */ +IMPLEMENT_digest_functions(sha512, SHA512_CTX, + SHA512_CBLOCK, SHA512_DIGEST_LENGTH, SHA2_FLAGS, + SHA512_Init, SHA512_Update, SHA512_Final) + +/* ossl_sha512_224_functions */ +IMPLEMENT_digest_functions(sha512_224, SHA512_CTX, + SHA512_CBLOCK, SHA224_DIGEST_LENGTH, SHA2_FLAGS, + sha512_224_init, SHA512_Update, SHA512_Final) + +/* ossl_sha512_256_functions */ +IMPLEMENT_digest_functions(sha512_256, SHA512_CTX, + SHA512_CBLOCK, SHA256_DIGEST_LENGTH, SHA2_FLAGS, + sha512_256_init, SHA512_Update, SHA512_Final) + diff --git a/providers/implementations/digests/sha3_prov.c b/providers/implementations/digests/sha3_prov.c new file mode 100644 index 000000000000..168825d47564 --- /dev/null +++ b/providers/implementations/digests/sha3_prov.c @@ -0,0 +1,332 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> +#include <openssl/core_names.h> +#include <openssl/crypto.h> +#include <openssl/evp.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include "internal/sha3.h" +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +#define SHA3_FLAGS PROV_DIGEST_FLAG_ALGID_ABSENT +#define SHAKE_FLAGS PROV_DIGEST_FLAG_XOF +#define KMAC_FLAGS PROV_DIGEST_FLAG_XOF + +/* + * Forward declaration of any unique methods implemented here. This is not strictly + * necessary for the compiler, but provides an assurance that the signatures + * of the functions in the dispatch table are correct. + */ +static OSSL_FUNC_digest_init_fn keccak_init; +static OSSL_FUNC_digest_init_fn keccak_init_params; +static OSSL_FUNC_digest_update_fn keccak_update; +static OSSL_FUNC_digest_final_fn keccak_final; +static OSSL_FUNC_digest_freectx_fn keccak_freectx; +static OSSL_FUNC_digest_dupctx_fn keccak_dupctx; +static OSSL_FUNC_digest_set_ctx_params_fn shake_set_ctx_params; +static OSSL_FUNC_digest_settable_ctx_params_fn shake_settable_ctx_params; +static sha3_absorb_fn generic_sha3_absorb; +static sha3_final_fn generic_sha3_final; + +#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__) && defined(KECCAK1600_ASM) +/* + * IBM S390X support + */ +# include "s390x_arch.h" +# define S390_SHA3 1 +# define S390_SHA3_CAPABLE(name) \ + ((OPENSSL_s390xcap_P.kimd[0] & S390X_CAPBIT(S390X_##name)) && \ + (OPENSSL_s390xcap_P.klmd[0] & S390X_CAPBIT(S390X_##name))) + +#endif + +static int keccak_init(void *vctx, ossl_unused const OSSL_PARAM params[]) +{ + if (!ossl_prov_is_running()) + return 0; + /* The newctx() handles most of the ctx fixed setup. */ + ossl_sha3_reset((KECCAK1600_CTX *)vctx); + return 1; +} + +static int keccak_init_params(void *vctx, const OSSL_PARAM params[]) +{ + return keccak_init(vctx, NULL) + && shake_set_ctx_params(vctx, params); +} + +static int keccak_update(void *vctx, const unsigned char *inp, size_t len) +{ + KECCAK1600_CTX *ctx = vctx; + const size_t bsz = ctx->block_size; + size_t num, rem; + + if (len == 0) + return 1; + + /* Is there anything in the buffer already ? */ + if ((num = ctx->bufsz) != 0) { + /* Calculate how much space is left in the buffer */ + rem = bsz - num; + /* If the new input does not fill the buffer then just add it */ + if (len < rem) { + memcpy(ctx->buf + num, inp, len); + ctx->bufsz += len; + return 1; + } + /* otherwise fill up the buffer and absorb the buffer */ + memcpy(ctx->buf + num, inp, rem); + /* Update the input pointer */ + inp += rem; + len -= rem; + ctx->meth.absorb(ctx, ctx->buf, bsz); + ctx->bufsz = 0; + } + /* Absorb the input - rem = leftover part of the input < blocksize) */ + rem = ctx->meth.absorb(ctx, inp, len); + /* Copy the leftover bit of the input into the buffer */ + if (rem) { + memcpy(ctx->buf, inp + len - rem, rem); + ctx->bufsz = rem; + } + return 1; +} + +static int keccak_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsz) +{ + int ret = 1; + KECCAK1600_CTX *ctx = vctx; + + if (!ossl_prov_is_running()) + return 0; + if (outsz > 0) + ret = ctx->meth.final(out, ctx); + + *outl = ctx->md_size; + return ret; +} + +/*- + * Generic software version of the absorb() and final(). + */ +static size_t generic_sha3_absorb(void *vctx, const void *inp, size_t len) +{ + KECCAK1600_CTX *ctx = vctx; + + return SHA3_absorb(ctx->A, inp, len, ctx->block_size); +} + +static int generic_sha3_final(unsigned char *md, void *vctx) +{ + return ossl_sha3_final(md, (KECCAK1600_CTX *)vctx); +} + +static PROV_SHA3_METHOD sha3_generic_md = +{ + generic_sha3_absorb, + generic_sha3_final +}; + +#if defined(S390_SHA3) + +static sha3_absorb_fn s390x_sha3_absorb; +static sha3_final_fn s390x_sha3_final; +static sha3_final_fn s390x_shake_final; + +/*- + * The platform specific parts of the absorb() and final() for S390X. + */ +static size_t s390x_sha3_absorb(void *vctx, const void *inp, size_t len) +{ + KECCAK1600_CTX *ctx = vctx; + size_t rem = len % ctx->block_size; + + s390x_kimd(inp, len - rem, ctx->pad, ctx->A); + return rem; +} + +static int s390x_sha3_final(unsigned char *md, void *vctx) +{ + KECCAK1600_CTX *ctx = vctx; + + if (!ossl_prov_is_running()) + return 0; + s390x_klmd(ctx->buf, ctx->bufsz, NULL, 0, ctx->pad, ctx->A); + memcpy(md, ctx->A, ctx->md_size); + return 1; +} + +static int s390x_shake_final(unsigned char *md, void *vctx) +{ + KECCAK1600_CTX *ctx = vctx; + + if (!ossl_prov_is_running()) + return 0; + s390x_klmd(ctx->buf, ctx->bufsz, md, ctx->md_size, ctx->pad, ctx->A); + return 1; +} + +static PROV_SHA3_METHOD sha3_s390x_md = +{ + s390x_sha3_absorb, + s390x_sha3_final +}; + +static PROV_SHA3_METHOD shake_s390x_md = +{ + s390x_sha3_absorb, + s390x_shake_final +}; + +# define SHA3_SET_MD(uname, typ) \ + if (S390_SHA3_CAPABLE(uname)) { \ + ctx->pad = S390X_##uname; \ + ctx->meth = typ##_s390x_md; \ + } else { \ + ctx->meth = sha3_generic_md; \ + } +#else +# define SHA3_SET_MD(uname, typ) ctx->meth = sha3_generic_md; +#endif /* S390_SHA3 */ + +#define SHA3_newctx(typ, uname, name, bitlen, pad) \ +static OSSL_FUNC_digest_newctx_fn name##_newctx; \ +static void *name##_newctx(void *provctx) \ +{ \ + KECCAK1600_CTX *ctx = ossl_prov_is_running() ? OPENSSL_zalloc(sizeof(*ctx)) \ + : NULL; \ + \ + if (ctx == NULL) \ + return NULL; \ + ossl_sha3_init(ctx, pad, bitlen); \ + SHA3_SET_MD(uname, typ) \ + return ctx; \ +} + +#define KMAC_newctx(uname, bitlen, pad) \ +static OSSL_FUNC_digest_newctx_fn uname##_newctx; \ +static void *uname##_newctx(void *provctx) \ +{ \ + KECCAK1600_CTX *ctx = ossl_prov_is_running() ? OPENSSL_zalloc(sizeof(*ctx)) \ + : NULL; \ + \ + if (ctx == NULL) \ + return NULL; \ + ossl_keccak_kmac_init(ctx, pad, bitlen); \ + ctx->meth = sha3_generic_md; \ + return ctx; \ +} + +#define PROV_FUNC_SHA3_DIGEST_COMMON(name, bitlen, blksize, dgstsize, flags) \ +PROV_FUNC_DIGEST_GET_PARAM(name, blksize, dgstsize, flags) \ +const OSSL_DISPATCH ossl_##name##_functions[] = { \ + { OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))name##_newctx }, \ + { OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))keccak_update }, \ + { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))keccak_final }, \ + { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))keccak_freectx }, \ + { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))keccak_dupctx }, \ + PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(name) + +#define PROV_FUNC_SHA3_DIGEST(name, bitlen, blksize, dgstsize, flags) \ + PROV_FUNC_SHA3_DIGEST_COMMON(name, bitlen, blksize, dgstsize, flags), \ + { OSSL_FUNC_DIGEST_INIT, (void (*)(void))keccak_init }, \ + PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END + +#define PROV_FUNC_SHAKE_DIGEST(name, bitlen, blksize, dgstsize, flags) \ + PROV_FUNC_SHA3_DIGEST_COMMON(name, bitlen, blksize, dgstsize, flags), \ + { OSSL_FUNC_DIGEST_INIT, (void (*)(void))keccak_init_params }, \ + { OSSL_FUNC_DIGEST_SET_CTX_PARAMS, (void (*)(void))shake_set_ctx_params }, \ + { OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS, \ + (void (*)(void))shake_settable_ctx_params }, \ + PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END + +static void keccak_freectx(void *vctx) +{ + KECCAK1600_CTX *ctx = (KECCAK1600_CTX *)vctx; + + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *keccak_dupctx(void *ctx) +{ + KECCAK1600_CTX *in = (KECCAK1600_CTX *)ctx; + KECCAK1600_CTX *ret = ossl_prov_is_running() ? OPENSSL_malloc(sizeof(*ret)) + : NULL; + + if (ret != NULL) + *ret = *in; + return ret; +} + +static const OSSL_PARAM known_shake_settable_ctx_params[] = { + {OSSL_DIGEST_PARAM_XOFLEN, OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0}, + OSSL_PARAM_END +}; +static const OSSL_PARAM *shake_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_shake_settable_ctx_params; +} + +static int shake_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KECCAK1600_CTX *ctx = (KECCAK1600_CTX *)vctx; + + if (ctx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_DIGEST_PARAM_XOFLEN); + if (p != NULL && !OSSL_PARAM_get_size_t(p, &ctx->md_size)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + return 1; +} + +#define IMPLEMENT_SHA3_functions(bitlen) \ + SHA3_newctx(sha3, SHA3_##bitlen, sha3_##bitlen, bitlen, '\x06') \ + PROV_FUNC_SHA3_DIGEST(sha3_##bitlen, bitlen, \ + SHA3_BLOCKSIZE(bitlen), SHA3_MDSIZE(bitlen), \ + SHA3_FLAGS) + +#define IMPLEMENT_SHAKE_functions(bitlen) \ + SHA3_newctx(shake, SHAKE_##bitlen, shake_##bitlen, bitlen, '\x1f') \ + PROV_FUNC_SHAKE_DIGEST(shake_##bitlen, bitlen, \ + SHA3_BLOCKSIZE(bitlen), SHA3_MDSIZE(bitlen), \ + SHAKE_FLAGS) +#define IMPLEMENT_KMAC_functions(bitlen) \ + KMAC_newctx(keccak_kmac_##bitlen, bitlen, '\x04') \ + PROV_FUNC_SHAKE_DIGEST(keccak_kmac_##bitlen, bitlen, \ + SHA3_BLOCKSIZE(bitlen), KMAC_MDSIZE(bitlen), \ + KMAC_FLAGS) + +/* ossl_sha3_224_functions */ +IMPLEMENT_SHA3_functions(224) +/* ossl_sha3_256_functions */ +IMPLEMENT_SHA3_functions(256) +/* ossl_sha3_384_functions */ +IMPLEMENT_SHA3_functions(384) +/* ossl_sha3_512_functions */ +IMPLEMENT_SHA3_functions(512) +/* ossl_shake_128_functions */ +IMPLEMENT_SHAKE_functions(128) +/* ossl_shake_256_functions */ +IMPLEMENT_SHAKE_functions(256) +/* ossl_keccak_kmac_128_functions */ +IMPLEMENT_KMAC_functions(128) +/* ossl_keccak_kmac_256_functions */ +IMPLEMENT_KMAC_functions(256) diff --git a/providers/implementations/digests/sm3_prov.c b/providers/implementations/digests/sm3_prov.c new file mode 100644 index 000000000000..9d6de5b6ac19 --- /dev/null +++ b/providers/implementations/digests/sm3_prov.c @@ -0,0 +1,18 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/crypto.h> +#include "internal/sm3.h" +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +/* ossl_sm3_functions */ +IMPLEMENT_digest_functions(sm3, SM3_CTX, + SM3_CBLOCK, SM3_DIGEST_LENGTH, 0, + ossl_sm3_init, ossl_sm3_update, ossl_sm3_final) diff --git a/providers/implementations/digests/wp_prov.c b/providers/implementations/digests/wp_prov.c new file mode 100644 index 000000000000..2af70b337281 --- /dev/null +++ b/providers/implementations/digests/wp_prov.c @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Whirlpool low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/crypto.h> +#include <openssl/whrlpool.h> +#include "prov/digestcommon.h" +#include "prov/implementations.h" + +/* ossl_wp_functions */ +IMPLEMENT_digest_functions(wp, WHIRLPOOL_CTX, + WHIRLPOOL_BBLOCK / 8, WHIRLPOOL_DIGEST_LENGTH, 0, + WHIRLPOOL_Init, WHIRLPOOL_Update, WHIRLPOOL_Final) diff --git a/providers/implementations/encode_decode/build.info b/providers/implementations/encode_decode/build.info new file mode 100644 index 000000000000..d3f6ca4abdef --- /dev/null +++ b/providers/implementations/encode_decode/build.info @@ -0,0 +1,20 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$ENCODER_GOAL=../../libdefault.a +$DECODER_GOAL=../../libdefault.a + +SOURCE[$ENCODER_GOAL]=endecoder_common.c + +SOURCE[$DECODER_GOAL]=decode_der2key.c decode_epki2pki.c decode_pem2der.c \ + decode_msblob2key.c decode_pvk2key.c \ + decode_spki2typespki.c + +SOURCE[$ENCODER_GOAL]=encode_key2any.c encode_key2text.c encode_key2ms.c +# encode_key2blob.c is only being included when EC is enabled, because we +# currently only define a "blob" output type for EC public keys. This may +# change in the future. +IF[{- !$disabled{ec} -}] + SOURCE[$ENCODER_GOAL]=encode_key2blob.c +ENDIF +DEPEND[encode_key2any.o]=../../common/include/prov/der_rsa.h diff --git a/providers/implementations/encode_decode/decode_der2key.c b/providers/implementations/encode_decode/decode_der2key.c new file mode 100644 index 000000000000..b9cee2571bf3 --- /dev/null +++ b/providers/implementations/encode_decode/decode_der2key.c @@ -0,0 +1,793 @@ +/* + * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/params.h> +#include <openssl/pem.h> /* PEM_BUFSIZE and public PEM functions */ +#include <openssl/pkcs12.h> +#include <openssl/x509.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" /* ossl_assert() */ +#include "internal/asn1.h" +#include "crypto/dh.h" +#include "crypto/dsa.h" +#include "crypto/ec.h" +#include "crypto/evp.h" +#include "crypto/ecx.h" +#include "crypto/rsa.h" +#include "crypto/x509.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +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); +typedef void free_key_fn(void *); +typedef void *d2i_PKCS8_fn(void **, const unsigned char **, long, + struct der2key_ctx_st *); +struct keytype_desc_st { + const char *keytype_name; + const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */ + + /* The input structure name */ + const char *structure_name; + + /* + * The EVP_PKEY_xxx type macro. Should be zero for type specific + * structures, non-zero when the outermost structure is PKCS#8 or + * SubjectPublicKeyInfo. This determines which of the function + * pointers below will be used. + */ + int evp_type; + + /* The selection mask for OSSL_FUNC_decoder_does_selection() */ + int selection_mask; + + /* For type specific decoders, we use the corresponding d2i */ + d2i_of_void *d2i_private_key; /* From type-specific DER */ + d2i_of_void *d2i_public_key; /* From type-specific DER */ + d2i_of_void *d2i_key_params; /* From type-specific DER */ + d2i_PKCS8_fn *d2i_PKCS8; /* Wrapped in a PrivateKeyInfo */ + d2i_of_void *d2i_PUBKEY; /* Wrapped in a SubjectPublicKeyInfo */ + + /* + * For any key, we may need to check that the key meets expectations. + * This is useful when the same functions can decode several variants + * of a key. + */ + check_key_fn *check_key; + + /* + * For any key, we may need to make provider specific adjustments, such + * as ensure the key carries the correct library context. + */ + adjust_key_fn *adjust_key; + /* {type}_free() */ + free_key_fn *free_key; +}; + +/* + * Context used for DER to key decoding. + */ +struct der2key_ctx_st { + PROV_CTX *provctx; + const struct keytype_desc_st *desc; + /* The selection that is passed to der2key_decode() */ + int selection; + /* Flag used to signal that a failure is fatal */ + unsigned int flag_fatal : 1; +}; + +typedef void *key_from_pkcs8_t(const PKCS8_PRIV_KEY_INFO *p8inf, + OSSL_LIB_CTX *libctx, const char *propq); +static void *der2key_decode_p8(const unsigned char **input_der, + long input_der_len, struct der2key_ctx_st *ctx, + key_from_pkcs8_t *key_from_pkcs8) +{ + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + const X509_ALGOR *alg = NULL; + void *key = NULL; + + if ((p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, input_der, input_der_len)) != NULL + && PKCS8_pkey_get0(NULL, NULL, NULL, &alg, p8inf) + && 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; +} + +/* ---------------------------------------------------------------------- */ + +static OSSL_FUNC_decoder_freectx_fn der2key_freectx; +static OSSL_FUNC_decoder_decode_fn der2key_decode; +static OSSL_FUNC_decoder_export_object_fn der2key_export_object; + +static struct der2key_ctx_st * +der2key_newctx(void *provctx, const struct keytype_desc_st *desc) +{ + struct der2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + ctx->desc = desc; + } + return ctx; +} + +static void der2key_freectx(void *vctx) +{ + struct der2key_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static int der2key_check_selection(int selection, + const struct keytype_desc_st *desc) +{ + /* + * The selections are kinda sorta "levels", i.e. each selection given + * here is assumed to include those following. + */ + int checks[] = { + OSSL_KEYMGMT_SELECT_PRIVATE_KEY, + OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + OSSL_KEYMGMT_SELECT_ALL_PARAMETERS + }; + size_t i; + + /* The decoder implementations made here support guessing */ + if (selection == 0) + return 1; + + for (i = 0; i < OSSL_NELEM(checks); i++) { + int check1 = (selection & checks[i]) != 0; + int check2 = (desc->selection_mask & checks[i]) != 0; + + /* + * If the caller asked for the currently checked bit(s), return + * whether the decoder description says it's supported. + */ + if (check1) + return check2; + } + + /* This should be dead code, but just to be safe... */ + return 0; +} + +static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct der2key_ctx_st *ctx = vctx; + unsigned char *der = NULL; + const unsigned char *derp; + long der_len = 0; + void *key = NULL; + int ok = 0; + + ctx->selection = selection; + /* + * The caller is allowed to specify 0 as a selection mark, to have the + * structure and key type guessed. For type-specific structures, this + * is not recommended, as some structures are very similar. + * Note that 0 isn't the same as OSSL_KEYMGMT_SELECT_ALL, as the latter + * signifies a private key structure, where everything else is assumed + * to be present as well. + */ + if (selection == 0) + selection = ctx->desc->selection_mask; + if ((selection & ctx->desc->selection_mask) == 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + ok = ossl_read_der(ctx->provctx, cin, &der, &der_len); + if (!ok) + goto next; + + ok = 0; /* Assume that we fail */ + + ERR_set_mark(); + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + derp = der; + if (ctx->desc->d2i_PKCS8 != NULL) { + key = ctx->desc->d2i_PKCS8(NULL, &derp, der_len, ctx); + if (ctx->flag_fatal) { + ERR_clear_last_mark(); + goto end; + } + } else if (ctx->desc->d2i_private_key != NULL) { + key = ctx->desc->d2i_private_key(NULL, &derp, der_len); + } + if (key == NULL && ctx->selection != 0) { + ERR_clear_last_mark(); + goto next; + } + } + if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + derp = der; + if (ctx->desc->d2i_PUBKEY != NULL) + key = ctx->desc->d2i_PUBKEY(NULL, &derp, der_len); + else if (ctx->desc->d2i_public_key != NULL) + key = ctx->desc->d2i_public_key(NULL, &derp, der_len); + if (key == NULL && ctx->selection != 0) { + ERR_clear_last_mark(); + goto next; + } + } + if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) { + derp = der; + if (ctx->desc->d2i_key_params != NULL) + key = ctx->desc->d2i_key_params(NULL, &derp, der_len); + if (key == NULL && ctx->selection != 0) { + ERR_clear_last_mark(); + goto next; + } + } + if (key == NULL) + ERR_clear_last_mark(); + else + ERR_pop_to_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)) { + ctx->desc->free_key(key); + key = NULL; + } + + if (key != NULL && ctx->desc->adjust_key != NULL) + 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 memory here so it's not held up during the callback, because + * we know the process is recursive and the allocated chunks of memory + * add up. + */ + OPENSSL_free(der); + der = NULL; + + if (key != NULL) { + OSSL_PARAM params[4]; + int object_type = OSSL_OBJECT_PKEY; + + params[0] = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type); + params[1] = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + (char *)ctx->desc->keytype_name, + 0); + /* The address of the key becomes the octet string */ + params[2] = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE, + &key, sizeof(key)); + params[3] = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + + end: + ctx->desc->free_key(key); + OPENSSL_free(der); + + return ok; +} + +static int der2key_export_object(void *vctx, + const void *reference, size_t reference_sz, + OSSL_CALLBACK *export_cb, void *export_cbarg) +{ + struct der2key_ctx_st *ctx = vctx; + OSSL_FUNC_keymgmt_export_fn *export = + ossl_prov_get_keymgmt_export(ctx->desc->fns); + void *keydata; + + if (reference_sz == sizeof(keydata) && export != NULL) { + /* The contents of the reference is the address to our object */ + keydata = *(void **)reference; + + return export(keydata, ctx->selection, export_cb, export_cbarg); + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DH +# define dh_evp_type EVP_PKEY_DH +# define dh_d2i_private_key NULL +# define dh_d2i_public_key NULL +# define dh_d2i_key_params (d2i_of_void *)d2i_DHparams + +static void *dh_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_dh_key_from_pkcs8); +} + +# define dh_d2i_PUBKEY (d2i_of_void *)ossl_d2i_DH_PUBKEY +# define dh_free (free_key_fn *)DH_free +# define dh_check NULL + +static void dh_adjust(void *key, struct der2key_ctx_st *ctx) +{ + ossl_dh_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +# define dhx_evp_type EVP_PKEY_DHX +# define dhx_d2i_private_key NULL +# define dhx_d2i_public_key NULL +# define dhx_d2i_key_params (d2i_of_void *)d2i_DHxparams +# define dhx_d2i_PKCS8 dh_d2i_PKCS8 +# define dhx_d2i_PUBKEY (d2i_of_void *)ossl_d2i_DHx_PUBKEY +# define dhx_free (free_key_fn *)DH_free +# define dhx_check NULL +# define dhx_adjust dh_adjust +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DSA +# define dsa_evp_type EVP_PKEY_DSA +# define dsa_d2i_private_key (d2i_of_void *)d2i_DSAPrivateKey +# define dsa_d2i_public_key (d2i_of_void *)d2i_DSAPublicKey +# define dsa_d2i_key_params (d2i_of_void *)d2i_DSAparams + +static void *dsa_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_dsa_key_from_pkcs8); +} + +# define dsa_d2i_PUBKEY (d2i_of_void *)ossl_d2i_DSA_PUBKEY +# define dsa_free (free_key_fn *)DSA_free +# define dsa_check NULL + +static void dsa_adjust(void *key, struct der2key_ctx_st *ctx) +{ + ossl_dsa_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_EC +# define ec_evp_type EVP_PKEY_EC +# define ec_d2i_private_key (d2i_of_void *)d2i_ECPrivateKey +# define ec_d2i_public_key NULL +# define ec_d2i_key_params (d2i_of_void *)d2i_ECParameters + +static void *ec_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_ec_key_from_pkcs8); +} + +# define ec_d2i_PUBKEY (d2i_of_void *)d2i_EC_PUBKEY +# define ec_free (free_key_fn *)EC_KEY_free + +static int ec_check(void *key, struct der2key_ctx_st *ctx) +{ + /* We're trying to be clever by comparing two truths */ + + int sm2 = (EC_KEY_get_flags(key) & EC_FLAG_SM2_RANGE) != 0; + + return sm2 == (ctx->desc->evp_type == EVP_PKEY_SM2); +} + +static void ec_adjust(void *key, struct der2key_ctx_st *ctx) +{ + ossl_ec_key_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +/* + * ED25519, ED448, X25519, X448 only implement PKCS#8 and SubjectPublicKeyInfo, + * so no d2i functions to be had. + */ + +static void *ecx_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_ecx_key_from_pkcs8); +} + +static void ecx_key_adjust(void *key, struct der2key_ctx_st *ctx) +{ + ossl_ecx_key_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +# define ed25519_evp_type EVP_PKEY_ED25519 +# define ed25519_d2i_private_key NULL +# define ed25519_d2i_public_key NULL +# define ed25519_d2i_key_params NULL +# define ed25519_d2i_PKCS8 ecx_d2i_PKCS8 +# define ed25519_d2i_PUBKEY (d2i_of_void *)ossl_d2i_ED25519_PUBKEY +# define ed25519_free (free_key_fn *)ossl_ecx_key_free +# define ed25519_check NULL +# define ed25519_adjust ecx_key_adjust + +# define ed448_evp_type EVP_PKEY_ED448 +# define ed448_d2i_private_key NULL +# define ed448_d2i_public_key NULL +# define ed448_d2i_key_params NULL +# define ed448_d2i_PKCS8 ecx_d2i_PKCS8 +# define ed448_d2i_PUBKEY (d2i_of_void *)ossl_d2i_ED448_PUBKEY +# define ed448_free (free_key_fn *)ossl_ecx_key_free +# define ed448_check NULL +# define ed448_adjust ecx_key_adjust + +# define x25519_evp_type EVP_PKEY_X25519 +# define x25519_d2i_private_key NULL +# define x25519_d2i_public_key NULL +# define x25519_d2i_key_params NULL +# define x25519_d2i_PKCS8 ecx_d2i_PKCS8 +# define x25519_d2i_PUBKEY (d2i_of_void *)ossl_d2i_X25519_PUBKEY +# define x25519_free (free_key_fn *)ossl_ecx_key_free +# define x25519_check NULL +# define x25519_adjust ecx_key_adjust + +# define x448_evp_type EVP_PKEY_X448 +# define x448_d2i_private_key NULL +# define x448_d2i_public_key NULL +# define x448_d2i_key_params NULL +# define x448_d2i_PKCS8 ecx_d2i_PKCS8 +# define x448_d2i_PUBKEY (d2i_of_void *)ossl_d2i_X448_PUBKEY +# define x448_free (free_key_fn *)ossl_ecx_key_free +# define x448_check NULL +# define x448_adjust ecx_key_adjust + +# ifndef OPENSSL_NO_SM2 +# define sm2_evp_type EVP_PKEY_SM2 +# define sm2_d2i_private_key (d2i_of_void *)d2i_ECPrivateKey +# define sm2_d2i_public_key NULL +# define sm2_d2i_key_params (d2i_of_void *)d2i_ECParameters + +static void *sm2_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_ec_key_from_pkcs8); +} + +# define sm2_d2i_PUBKEY (d2i_of_void *)d2i_EC_PUBKEY +# define sm2_free (free_key_fn *)EC_KEY_free +# define sm2_check ec_check +# define sm2_adjust ec_adjust +# endif +#endif + +/* ---------------------------------------------------------------------- */ + +#define rsa_evp_type EVP_PKEY_RSA +#define rsa_d2i_private_key (d2i_of_void *)d2i_RSAPrivateKey +#define rsa_d2i_public_key (d2i_of_void *)d2i_RSAPublicKey +#define rsa_d2i_key_params NULL + +static void *rsa_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + return der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)ossl_rsa_key_from_pkcs8); +} + +#define rsa_d2i_PUBKEY (d2i_of_void *)d2i_RSA_PUBKEY +#define rsa_free (free_key_fn *)RSA_free + +static int rsa_check(void *key, struct der2key_ctx_st *ctx) +{ + switch (RSA_test_flags(key, RSA_FLAG_TYPE_MASK)) { + case RSA_FLAG_TYPE_RSA: + return ctx->desc->evp_type == EVP_PKEY_RSA; + case RSA_FLAG_TYPE_RSASSAPSS: + return ctx->desc->evp_type == EVP_PKEY_RSA_PSS; + } + + /* Currently unsupported RSA key type */ + return 0; +} + +static void rsa_adjust(void *key, struct der2key_ctx_st *ctx) +{ + ossl_rsa_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +#define rsapss_evp_type EVP_PKEY_RSA_PSS +#define rsapss_d2i_private_key (d2i_of_void *)d2i_RSAPrivateKey +#define rsapss_d2i_public_key (d2i_of_void *)d2i_RSAPublicKey +#define rsapss_d2i_key_params NULL +#define rsapss_d2i_PKCS8 rsa_d2i_PKCS8 +#define rsapss_d2i_PUBKEY (d2i_of_void *)d2i_RSA_PUBKEY +#define rsapss_free (free_key_fn *)RSA_free +#define rsapss_check rsa_check +#define rsapss_adjust rsa_adjust + +/* ---------------------------------------------------------------------- */ + +/* + * The DO_ macros help define the selection mask and the method functions + * for each kind of object we want to decode. + */ +#define DO_type_specific_keypair(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_KEYPAIR ), \ + keytype##_d2i_private_key, \ + keytype##_d2i_public_key, \ + NULL, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_type_specific_pub(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PUBLIC_KEY ), \ + NULL, \ + keytype##_d2i_public_key, \ + NULL, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_type_specific_priv(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY ), \ + keytype##_d2i_private_key, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_type_specific_params(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + NULL, \ + NULL, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_type_specific(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_ALL ), \ + keytype##_d2i_private_key, \ + keytype##_d2i_public_key, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_type_specific_no_pub(keytype) \ + "type-specific", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY \ + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + keytype##_d2i_private_key, \ + NULL, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_PrivateKeyInfo(keytype) \ + "PrivateKeyInfo", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY ), \ + NULL, \ + NULL, \ + NULL, \ + keytype##_d2i_PKCS8, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_SubjectPublicKeyInfo(keytype) \ + "SubjectPublicKeyInfo", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PUBLIC_KEY ), \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + keytype##_d2i_PUBKEY, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_DH(keytype) \ + "DH", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + NULL, \ + NULL, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_DHX(keytype) \ + "DHX", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + NULL, \ + NULL, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_DSA(keytype) \ + "DSA", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_ALL ), \ + keytype##_d2i_private_key, \ + keytype##_d2i_public_key, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_EC(keytype) \ + "EC", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY \ + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + keytype##_d2i_private_key, \ + NULL, \ + keytype##_d2i_key_params, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +#define DO_RSA(keytype) \ + "RSA", keytype##_evp_type, \ + ( OSSL_KEYMGMT_SELECT_KEYPAIR ), \ + keytype##_d2i_private_key, \ + keytype##_d2i_public_key, \ + NULL, \ + NULL, \ + NULL, \ + keytype##_check, \ + keytype##_adjust, \ + keytype##_free + +/* + * MAKE_DECODER is the single driver for creating OSSL_DISPATCH tables. + * It takes the following arguments: + * + * keytype_name The implementation key type as a string. + * keytype The implementation key type. This must correspond exactly + * to our existing keymgmt keytype names... in other words, + * there must exist an ossl_##keytype##_keymgmt_functions. + * type The type name for the set of functions that implement the + * decoder for the key type. This isn't necessarily the same + * as keytype. For example, the key types ed25519, ed448, + * x25519 and x448 are all handled by the same functions with + * the common type name ecx. + * kind The kind of support to implement. This translates into + * the DO_##kind macros above, to populate the keytype_desc_st + * structure. + */ +#define MAKE_DECODER(keytype_name, keytype, type, kind) \ + static const struct keytype_desc_st kind##_##keytype##_desc = \ + { keytype_name, ossl_##keytype##_keymgmt_functions, \ + DO_##kind(keytype) }; \ + \ + static OSSL_FUNC_decoder_newctx_fn kind##_der2##keytype##_newctx; \ + \ + static void *kind##_der2##keytype##_newctx(void *provctx) \ + { \ + return der2key_newctx(provctx, &kind##_##keytype##_desc); \ + } \ + static int kind##_der2##keytype##_does_selection(void *provctx, \ + int selection) \ + { \ + return der2key_check_selection(selection, \ + &kind##_##keytype##_desc); \ + } \ + const OSSL_DISPATCH \ + ossl_##kind##_der_to_##keytype##_decoder_functions[] = { \ + { OSSL_FUNC_DECODER_NEWCTX, \ + (void (*)(void))kind##_der2##keytype##_newctx }, \ + { OSSL_FUNC_DECODER_FREECTX, \ + (void (*)(void))der2key_freectx }, \ + { OSSL_FUNC_DECODER_DOES_SELECTION, \ + (void (*)(void))kind##_der2##keytype##_does_selection }, \ + { OSSL_FUNC_DECODER_DECODE, \ + (void (*)(void))der2key_decode }, \ + { OSSL_FUNC_DECODER_EXPORT_OBJECT, \ + (void (*)(void))der2key_export_object }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_DH +MAKE_DECODER("DH", dh, dh, PrivateKeyInfo); +MAKE_DECODER("DH", dh, dh, SubjectPublicKeyInfo); +MAKE_DECODER("DH", dh, dh, type_specific_params); +MAKE_DECODER("DH", dh, dh, DH); +MAKE_DECODER("DHX", dhx, dhx, PrivateKeyInfo); +MAKE_DECODER("DHX", dhx, dhx, SubjectPublicKeyInfo); +MAKE_DECODER("DHX", dhx, dhx, type_specific_params); +MAKE_DECODER("DHX", dhx, dhx, DHX); +#endif +#ifndef OPENSSL_NO_DSA +MAKE_DECODER("DSA", dsa, dsa, PrivateKeyInfo); +MAKE_DECODER("DSA", dsa, dsa, SubjectPublicKeyInfo); +MAKE_DECODER("DSA", dsa, dsa, type_specific); +MAKE_DECODER("DSA", dsa, dsa, DSA); +#endif +#ifndef OPENSSL_NO_EC +MAKE_DECODER("EC", ec, ec, PrivateKeyInfo); +MAKE_DECODER("EC", ec, ec, SubjectPublicKeyInfo); +MAKE_DECODER("EC", ec, ec, type_specific_no_pub); +MAKE_DECODER("EC", ec, ec, EC); +MAKE_DECODER("X25519", x25519, ecx, PrivateKeyInfo); +MAKE_DECODER("X25519", x25519, ecx, SubjectPublicKeyInfo); +MAKE_DECODER("X448", x448, ecx, PrivateKeyInfo); +MAKE_DECODER("X448", x448, ecx, SubjectPublicKeyInfo); +MAKE_DECODER("ED25519", ed25519, ecx, PrivateKeyInfo); +MAKE_DECODER("ED25519", ed25519, ecx, SubjectPublicKeyInfo); +MAKE_DECODER("ED448", ed448, ecx, PrivateKeyInfo); +MAKE_DECODER("ED448", ed448, ecx, SubjectPublicKeyInfo); +# ifndef OPENSSL_NO_SM2 +MAKE_DECODER("SM2", sm2, ec, PrivateKeyInfo); +MAKE_DECODER("SM2", sm2, ec, SubjectPublicKeyInfo); +# endif +#endif +MAKE_DECODER("RSA", rsa, rsa, PrivateKeyInfo); +MAKE_DECODER("RSA", rsa, rsa, SubjectPublicKeyInfo); +MAKE_DECODER("RSA", rsa, rsa, type_specific_keypair); +MAKE_DECODER("RSA", rsa, rsa, RSA); +MAKE_DECODER("RSA-PSS", rsapss, rsapss, PrivateKeyInfo); +MAKE_DECODER("RSA-PSS", rsapss, rsapss, SubjectPublicKeyInfo); diff --git a/providers/implementations/encode_decode/decode_epki2pki.c b/providers/implementations/encode_decode/decode_epki2pki.c new file mode 100644 index 000000000000..9cea80b616d6 --- /dev/null +++ b/providers/implementations/encode_decode/decode_epki2pki.c @@ -0,0 +1,158 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/core.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/asn1.h> +#include <openssl/err.h> +#include <openssl/objects.h> +#include <openssl/pkcs12.h> +#include <openssl/x509.h> +#include <openssl/proverr.h> +#include "internal/asn1.h" +#include "internal/sizes.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +static OSSL_FUNC_decoder_newctx_fn epki2pki_newctx; +static OSSL_FUNC_decoder_freectx_fn epki2pki_freectx; +static OSSL_FUNC_decoder_decode_fn epki2pki_decode; + +/* + * Context used for EncryptedPrivateKeyInfo to PrivateKeyInfo decoding. + */ +struct epki2pki_ctx_st { + PROV_CTX *provctx; +}; + +static void *epki2pki_newctx(void *provctx) +{ + struct epki2pki_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) + ctx->provctx = provctx; + return ctx; +} + +static void epki2pki_freectx(void *vctx) +{ + struct epki2pki_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +/* + * The selection parameter in epki2pki_decode() is not used by this function + * because it's not relevant just to decode EncryptedPrivateKeyInfo to + * PrivateKeyInfo. + */ +static int epki2pki_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct epki2pki_ctx_st *ctx = vctx; + BUF_MEM *mem = NULL; + unsigned char *der = NULL; + const unsigned char *pder = NULL; + long der_len = 0; + X509_SIG *p8 = NULL; + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + const X509_ALGOR *alg = NULL; + BIO *in = ossl_bio_new_from_core_bio(ctx->provctx, cin); + int ok = 0; + + if (in == NULL) + return 0; + + ok = (asn1_d2i_read_bio(in, &mem) >= 0); + BIO_free(in); + + /* We return "empty handed". This is not an error. */ + if (!ok) + return 1; + + pder = der = (unsigned char *)mem->data; + der_len = (long)mem->length; + OPENSSL_free(mem); + + ok = 1; /* Assume good */ + ERR_set_mark(); + if ((p8 = d2i_X509_SIG(NULL, &pder, der_len)) != NULL) { + char pbuf[1024]; + size_t plen = 0; + + ERR_clear_last_mark(); + + if (!pw_cb(pbuf, sizeof(pbuf), &plen, NULL, pw_cbarg)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PASSPHRASE); + ok = 0; + } else { + const ASN1_OCTET_STRING *oct; + unsigned char *new_der = NULL; + int new_der_len = 0; + + X509_SIG_get0(p8, &alg, &oct); + if (!PKCS12_pbe_crypt_ex(alg, pbuf, plen, + oct->data, oct->length, + &new_der, &new_der_len, 0, + PROV_LIBCTX_OF(ctx->provctx), NULL)) { + ok = 0; + } else { + OPENSSL_free(der); + der = new_der; + der_len = new_der_len; + } + alg = NULL; + } + X509_SIG_free(p8); + } else { + ERR_pop_to_mark(); + } + + ERR_set_mark(); + pder = der; + p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &pder, der_len); + ERR_pop_to_mark(); + + if (p8inf != NULL && PKCS8_pkey_get0(NULL, NULL, NULL, &alg, p8inf)) { + /* + * We have something and recognised it as PrivateKeyInfo, so let's + * pass all the applicable data to the callback. + */ + char keytype[OSSL_MAX_NAME_SIZE]; + OSSL_PARAM params[5], *p = params; + int objtype = OSSL_OBJECT_PKEY; + + OBJ_obj2txt(keytype, sizeof(keytype), alg->algorithm, 0); + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + keytype, 0); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, + "PrivateKeyInfo", 0); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, + der, der_len); + *p++ = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); + *p = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + PKCS8_PRIV_KEY_INFO_free(p8inf); + OPENSSL_free(der); + return ok; +} + +const OSSL_DISPATCH ossl_EncryptedPrivateKeyInfo_der_to_der_decoder_functions[] = { + { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))epki2pki_newctx }, + { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))epki2pki_freectx }, + { OSSL_FUNC_DECODER_DECODE, (void (*)(void))epki2pki_decode }, + { 0, NULL } +}; diff --git a/providers/implementations/encode_decode/decode_msblob2key.c b/providers/implementations/encode_decode/decode_msblob2key.c new file mode 100644 index 000000000000..501957faba01 --- /dev/null +++ b/providers/implementations/encode_decode/decode_msblob2key.c @@ -0,0 +1,273 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/crypto.h> +#include <openssl/params.h> +#include <openssl/pem.h> /* For public PVK functions */ +#include <openssl/x509.h> +#include <openssl/err.h> +#include "internal/passphrase.h" +#include "crypto/pem.h" /* For internal PVK and "blob" headers */ +#include "crypto/rsa.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +struct msblob2key_ctx_st; /* Forward declaration */ +typedef void *b2i_of_void_fn(const unsigned char **in, unsigned int bitlen, + int ispub); +typedef void adjust_key_fn(void *, struct msblob2key_ctx_st *ctx); +typedef void free_key_fn(void *); +struct keytype_desc_st { + int type; /* EVP key type */ + const char *name; /* Keytype */ + const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */ + + b2i_of_void_fn *read_private_key; + b2i_of_void_fn *read_public_key; + adjust_key_fn *adjust_key; + free_key_fn *free_key; +}; + +static OSSL_FUNC_decoder_freectx_fn msblob2key_freectx; +static OSSL_FUNC_decoder_decode_fn msblob2key_decode; +static OSSL_FUNC_decoder_export_object_fn msblob2key_export_object; + +/* + * Context used for DER to key decoding. + */ +struct msblob2key_ctx_st { + PROV_CTX *provctx; + const struct keytype_desc_st *desc; + /* The selection that is passed to msblob2key_decode() */ + int selection; +}; + +static struct msblob2key_ctx_st * +msblob2key_newctx(void *provctx, const struct keytype_desc_st *desc) +{ + struct msblob2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + ctx->desc = desc; + } + return ctx; +} + +static void msblob2key_freectx(void *vctx) +{ + struct msblob2key_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static int msblob2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct msblob2key_ctx_st *ctx = vctx; + BIO *in = ossl_bio_new_from_core_bio(ctx->provctx, cin); + const unsigned char *p; + unsigned char hdr_buf[16], *buf = NULL; + unsigned int bitlen, magic, length; + int isdss = -1; + int ispub = -1; + void *key = NULL; + int ok = 0; + + if (in == NULL) + return 0; + + if (BIO_read(in, hdr_buf, 16) != 16) { + ERR_raise(ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT); + goto next; + } + ERR_set_mark(); + p = hdr_buf; + ok = ossl_do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) > 0; + ERR_pop_to_mark(); + if (!ok) + goto next; + + ctx->selection = selection; + ok = 0; /* Assume that we fail */ + + if ((isdss && ctx->desc->type != EVP_PKEY_DSA) + || (!isdss && ctx->desc->type != EVP_PKEY_RSA)) + 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 next; + } + buf = OPENSSL_malloc(length); + if (buf == NULL) { + ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE); + goto end; + } + p = buf; + if (BIO_read(in, buf, length) != (int)length) { + ERR_raise(ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT); + goto next; + } + + if ((selection == 0 + || (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + && !ispub + && ctx->desc->read_private_key != NULL) { + struct ossl_passphrase_data_st pwdata; + + memset(&pwdata, 0, sizeof(pwdata)); + if (!ossl_pw_set_ossl_passphrase_cb(&pwdata, pw_cb, pw_cbarg)) + goto end; + p = buf; + key = ctx->desc->read_private_key(&p, bitlen, ispub); + if (selection != 0 && key == NULL) + goto next; + } + if (key == NULL && (selection == 0 + || (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + && ispub + && ctx->desc->read_public_key != NULL) { + p = buf; + key = ctx->desc->read_public_key(&p, bitlen, ispub); + if (selection != 0 && key == NULL) + goto next; + } + + if (key != NULL && ctx->desc->adjust_key != NULL) + 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 + * add up. + */ + OPENSSL_free(buf); + BIO_free(in); + buf = NULL; + in = NULL; + + if (key != NULL) { + OSSL_PARAM params[4]; + int object_type = OSSL_OBJECT_PKEY; + + params[0] = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type); + params[1] = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + (char *)ctx->desc->name, 0); + /* The address of the key becomes the octet string */ + params[2] = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE, + &key, sizeof(key)); + params[3] = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + + end: + BIO_free(in); + OPENSSL_free(buf); + ctx->desc->free_key(key); + + return ok; +} + +static int +msblob2key_export_object(void *vctx, + const void *reference, size_t reference_sz, + OSSL_CALLBACK *export_cb, void *export_cbarg) +{ + struct msblob2key_ctx_st *ctx = vctx; + OSSL_FUNC_keymgmt_export_fn *export = + ossl_prov_get_keymgmt_export(ctx->desc->fns); + void *keydata; + + if (reference_sz == sizeof(keydata) && export != NULL) { + /* The contents of the reference is the address to our object */ + keydata = *(void **)reference; + + return export(keydata, ctx->selection, export_cb, export_cbarg); + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +#define dsa_decode_private_key (b2i_of_void_fn *)ossl_b2i_DSA_after_header +#define dsa_decode_public_key (b2i_of_void_fn *)ossl_b2i_DSA_after_header +#define dsa_adjust NULL +#define dsa_free (void (*)(void *))DSA_free + +/* ---------------------------------------------------------------------- */ + +#define rsa_decode_private_key (b2i_of_void_fn *)ossl_b2i_RSA_after_header +#define rsa_decode_public_key (b2i_of_void_fn *)ossl_b2i_RSA_after_header + +static void rsa_adjust(void *key, struct msblob2key_ctx_st *ctx) +{ + ossl_rsa_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +#define rsa_free (void (*)(void *))RSA_free + +/* ---------------------------------------------------------------------- */ + +#define IMPLEMENT_MSBLOB(KEYTYPE, keytype) \ + static const struct keytype_desc_st mstype##2##keytype##_desc = { \ + EVP_PKEY_##KEYTYPE, #KEYTYPE, \ + ossl_##keytype##_keymgmt_functions, \ + keytype##_decode_private_key, \ + keytype##_decode_public_key, \ + keytype##_adjust, \ + keytype##_free \ + }; \ + static OSSL_FUNC_decoder_newctx_fn msblob2##keytype##_newctx; \ + static void *msblob2##keytype##_newctx(void *provctx) \ + { \ + return msblob2key_newctx(provctx, &mstype##2##keytype##_desc); \ + } \ + const OSSL_DISPATCH \ + ossl_msblob_to_##keytype##_decoder_functions[] = { \ + { OSSL_FUNC_DECODER_NEWCTX, \ + (void (*)(void))msblob2##keytype##_newctx }, \ + { OSSL_FUNC_DECODER_FREECTX, \ + (void (*)(void))msblob2key_freectx }, \ + { OSSL_FUNC_DECODER_DECODE, \ + (void (*)(void))msblob2key_decode }, \ + { OSSL_FUNC_DECODER_EXPORT_OBJECT, \ + (void (*)(void))msblob2key_export_object }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_DSA +IMPLEMENT_MSBLOB(DSA, dsa); +#endif +IMPLEMENT_MSBLOB(RSA, rsa); diff --git a/providers/implementations/encode_decode/decode_pem2der.c b/providers/implementations/encode_decode/decode_pem2der.c new file mode 100644 index 000000000000..bc937ffb9d27 --- /dev/null +++ b/providers/implementations/encode_decode/decode_pem2der.c @@ -0,0 +1,219 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * RSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/params.h> +#include <openssl/pem.h> +#include <openssl/proverr.h> +#include "internal/nelem.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +static int read_pem(PROV_CTX *provctx, OSSL_CORE_BIO *cin, + char **pem_name, char **pem_header, + unsigned char **data, long *len) +{ + BIO *in = ossl_bio_new_from_core_bio(provctx, cin); + int ok; + + if (in == NULL) + return 0; + ok = (PEM_read_bio(in, pem_name, pem_header, data, len) > 0); + + BIO_free(in); + return ok; +} + +static OSSL_FUNC_decoder_newctx_fn pem2der_newctx; +static OSSL_FUNC_decoder_freectx_fn pem2der_freectx; +static OSSL_FUNC_decoder_decode_fn pem2der_decode; + +/* + * Context used for PEM to DER decoding. + */ +struct pem2der_ctx_st { + PROV_CTX *provctx; +}; + +static void *pem2der_newctx(void *provctx) +{ + struct pem2der_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) + ctx->provctx = provctx; + return ctx; +} + +static void pem2der_freectx(void *vctx) +{ + struct pem2der_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +/* pem_password_cb compatible function */ +struct pem2der_pass_data_st { + OSSL_PASSPHRASE_CALLBACK *cb; + void *cbarg; +}; + +static int pem2der_pass_helper(char *buf, int num, int w, void *data) +{ + struct pem2der_pass_data_st *pass_data = data; + size_t plen; + + if (pass_data == NULL + || pass_data->cb == NULL + || !pass_data->cb(buf, num, &plen, NULL, pass_data->cbarg)) + return -1; + return (int)plen; +} + +/* + * The selection parameter in pem2der_decode() is not used by this function + * because it's not relevant just to decode PEM to DER. + */ +static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + /* + * PEM names we recognise. Other PEM names should be recognised by + * other decoder implementations. + */ + static struct pem_name_map_st { + const char *pem_name; + int object_type; + const char *data_type; + const char *data_structure; + } pem_name_map[] = { + /* PKCS#8 and SubjectPublicKeyInfo */ + { PEM_STRING_PKCS8, OSSL_OBJECT_PKEY, NULL, "EncryptedPrivateKeyInfo" }, + { PEM_STRING_PKCS8INF, OSSL_OBJECT_PKEY, NULL, "PrivateKeyInfo" }, + { PEM_STRING_PUBLIC, OSSL_OBJECT_PKEY, NULL, "SubjectPublicKeyInfo" }, + + /* Our set of type specific PEM types */ + { PEM_STRING_DHPARAMS, OSSL_OBJECT_PKEY, "DH", "type-specific" }, + { PEM_STRING_DHXPARAMS, OSSL_OBJECT_PKEY, "X9.42 DH", "type-specific" }, + { PEM_STRING_DSA, OSSL_OBJECT_PKEY, "DSA", "type-specific" }, + { PEM_STRING_DSA_PUBLIC, OSSL_OBJECT_PKEY, "DSA", "type-specific" }, + { PEM_STRING_DSAPARAMS, OSSL_OBJECT_PKEY, "DSA", "type-specific" }, + { PEM_STRING_ECPRIVATEKEY, OSSL_OBJECT_PKEY, "EC", "type-specific" }, + { PEM_STRING_ECPARAMETERS, OSSL_OBJECT_PKEY, "EC", "type-specific" }, + { PEM_STRING_RSA, OSSL_OBJECT_PKEY, "RSA", "type-specific" }, + { PEM_STRING_RSA_PUBLIC, OSSL_OBJECT_PKEY, "RSA", "type-specific" }, + + /* + * A few others that there is at least have an object type for, even + * though there is no provider interface to handle such objects, yet. + * However, this is beneficial for the OSSL_STORE result handler. + */ + { PEM_STRING_X509, OSSL_OBJECT_CERT, NULL, "Certificate" }, + { PEM_STRING_X509_TRUSTED, OSSL_OBJECT_CERT, NULL, "Certificate" }, + { PEM_STRING_X509_OLD, OSSL_OBJECT_CERT, NULL, "Certificate" }, + { PEM_STRING_X509_CRL, OSSL_OBJECT_CRL, NULL, "CertificateList" } + }; + struct pem2der_ctx_st *ctx = vctx; + char *pem_name = NULL, *pem_header = NULL; + size_t i; + unsigned char *der = NULL; + long der_len = 0; + int ok = 0; + int objtype = OSSL_OBJECT_UNKNOWN; + + 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 + * 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 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) + || !PEM_do_header(&cipher, der, &der_len, + pem2der_pass_helper, &pass_data)) + goto end; + } + + /* + * Indicated that we successfully decoded something, or not at all. + * Ending up "empty handed" is not an error. + */ + ok = 1; + + /* Have a look to see if we recognise anything */ + for (i = 0; i < OSSL_NELEM(pem_name_map); i++) + if (strcmp(pem_name, pem_name_map[i].pem_name) == 0) + break; + + if (i < OSSL_NELEM(pem_name_map)) { + OSSL_PARAM params[5], *p = params; + /* We expect these to be read only so casting away the const is ok */ + char *data_type = (char *)pem_name_map[i].data_type; + char *data_structure = (char *)pem_name_map[i].data_structure; + + objtype = pem_name_map[i].object_type; + if (data_type != NULL) + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + data_type, 0); + + /* We expect this to be read only so casting away the const is ok */ + if (data_structure != NULL) + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, + data_structure, 0); + *p++ = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, + der, der_len); + *p++ = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); + + *p = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + + end: + OPENSSL_free(pem_name); + OPENSSL_free(pem_header); + OPENSSL_free(der); + return ok; +} + +const OSSL_DISPATCH ossl_pem_to_der_decoder_functions[] = { + { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))pem2der_newctx }, + { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))pem2der_freectx }, + { OSSL_FUNC_DECODER_DECODE, (void (*)(void))pem2der_decode }, + { 0, NULL } +}; diff --git a/providers/implementations/encode_decode/decode_pvk2key.c b/providers/implementations/encode_decode/decode_pvk2key.c new file mode 100644 index 000000000000..c6424165b03b --- /dev/null +++ b/providers/implementations/encode_decode/decode_pvk2key.c @@ -0,0 +1,239 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#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" +#include "crypto/pem.h" /* For internal PVK and "blob" headers */ +#include "crypto/rsa.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +struct pvk2key_ctx_st; /* Forward declaration */ +typedef int check_key_fn(void *, struct pvk2key_ctx_st *ctx); +typedef void adjust_key_fn(void *, struct pvk2key_ctx_st *ctx); +typedef void *b2i_PVK_of_bio_pw_fn(BIO *in, pem_password_cb *cb, void *u, + OSSL_LIB_CTX *libctx, const char *propq); +typedef void free_key_fn(void *); +struct keytype_desc_st { + int type; /* EVP key type */ + const char *name; /* Keytype */ + const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */ + + b2i_PVK_of_bio_pw_fn *read_private_key; + adjust_key_fn *adjust_key; + free_key_fn *free_key; +}; + +static OSSL_FUNC_decoder_freectx_fn pvk2key_freectx; +static OSSL_FUNC_decoder_decode_fn pvk2key_decode; +static OSSL_FUNC_decoder_export_object_fn pvk2key_export_object; + +/* + * Context used for DER to key decoding. + */ +struct pvk2key_ctx_st { + PROV_CTX *provctx; + const struct keytype_desc_st *desc; + /* The selection that is passed to der2key_decode() */ + int selection; +}; + +static struct pvk2key_ctx_st * +pvk2key_newctx(void *provctx, const struct keytype_desc_st *desc) +{ + struct pvk2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + ctx->desc = desc; + } + return ctx; +} + +static void pvk2key_freectx(void *vctx) +{ + struct pvk2key_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static int pvk2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct pvk2key_ctx_st *ctx = vctx; + BIO *in = ossl_bio_new_from_core_bio(ctx->provctx, cin); + void *key = NULL; + int ok = 0; + + if (in == NULL) + return 0; + + ctx->selection = selection; + + if ((selection == 0 + || (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_pvk_password, &pwdata, + PROV_LIBCTX_OF(ctx->provctx), NULL); + + /* + * 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; + } + + if (key != NULL && ctx->desc->adjust_key != NULL) + 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 + * add up. + */ + BIO_free(in); + in = NULL; + + if (key != NULL) { + OSSL_PARAM params[4]; + int object_type = OSSL_OBJECT_PKEY; + + params[0] = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type); + params[1] = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + (char *)ctx->desc->name, 0); + /* The address of the key becomes the octet string */ + params[2] = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE, + &key, sizeof(key)); + params[3] = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + + end: + BIO_free(in); + ctx->desc->free_key(key); + + return ok; +} + +static int pvk2key_export_object(void *vctx, + const void *reference, size_t reference_sz, + OSSL_CALLBACK *export_cb, void *export_cbarg) +{ + struct pvk2key_ctx_st *ctx = vctx; + OSSL_FUNC_keymgmt_export_fn *export = + ossl_prov_get_keymgmt_export(ctx->desc->fns); + void *keydata; + + if (reference_sz == sizeof(keydata) && export != NULL) { + /* The contents of the reference is the address to our object */ + keydata = *(void **)reference; + + return export(keydata, ctx->selection, export_cb, export_cbarg); + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +#define dsa_private_key_bio (b2i_PVK_of_bio_pw_fn *)b2i_DSA_PVK_bio_ex +#define dsa_adjust NULL +#define dsa_free (void (*)(void *))DSA_free + +/* ---------------------------------------------------------------------- */ + +#define rsa_private_key_bio (b2i_PVK_of_bio_pw_fn *)b2i_RSA_PVK_bio_ex + +static void rsa_adjust(void *key, struct pvk2key_ctx_st *ctx) +{ + ossl_rsa_set0_libctx(key, PROV_LIBCTX_OF(ctx->provctx)); +} + +#define rsa_free (void (*)(void *))RSA_free + +/* ---------------------------------------------------------------------- */ + +#define IMPLEMENT_MS(KEYTYPE, keytype) \ + static const struct keytype_desc_st \ + pvk2##keytype##_desc = { \ + EVP_PKEY_##KEYTYPE, #KEYTYPE, \ + ossl_##keytype##_keymgmt_functions, \ + keytype##_private_key_bio, \ + keytype##_adjust, \ + keytype##_free \ + }; \ + static OSSL_FUNC_decoder_newctx_fn pvk2##keytype##_newctx; \ + static void *pvk2##keytype##_newctx(void *provctx) \ + { \ + return pvk2key_newctx(provctx, &pvk2##keytype##_desc); \ + } \ + const OSSL_DISPATCH \ + ossl_##pvk_to_##keytype##_decoder_functions[] = { \ + { OSSL_FUNC_DECODER_NEWCTX, \ + (void (*)(void))pvk2##keytype##_newctx }, \ + { OSSL_FUNC_DECODER_FREECTX, \ + (void (*)(void))pvk2key_freectx }, \ + { OSSL_FUNC_DECODER_DECODE, \ + (void (*)(void))pvk2key_decode }, \ + { OSSL_FUNC_DECODER_EXPORT_OBJECT, \ + (void (*)(void))pvk2key_export_object }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_DSA +IMPLEMENT_MS(DSA, dsa); +#endif +IMPLEMENT_MS(RSA, rsa); diff --git a/providers/implementations/encode_decode/decode_spki2typespki.c b/providers/implementations/encode_decode/decode_spki2typespki.c new file mode 100644 index 000000000000..a5dbbb31adf8 --- /dev/null +++ b/providers/implementations/encode_decode/decode_spki2typespki.c @@ -0,0 +1,124 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> +#include <openssl/asn1t.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/params.h> +#include <openssl/x509.h> +#include "internal/sizes.h" +#include "crypto/x509.h" +#include "crypto/ec.h" +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +static OSSL_FUNC_decoder_newctx_fn spki2typespki_newctx; +static OSSL_FUNC_decoder_freectx_fn spki2typespki_freectx; +static OSSL_FUNC_decoder_decode_fn spki2typespki_decode; + +/* + * Context used for SubjectPublicKeyInfo to Type specific SubjectPublicKeyInfo + * decoding. + */ +struct spki2typespki_ctx_st { + PROV_CTX *provctx; +}; + +static void *spki2typespki_newctx(void *provctx) +{ + struct spki2typespki_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) + ctx->provctx = provctx; + return ctx; +} + +static void spki2typespki_freectx(void *vctx) +{ + struct spki2typespki_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static int spki2typespki_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct spki2typespki_ctx_st *ctx = vctx; + unsigned char *der, *derp; + long len; + int ok = 0; + int objtype = OSSL_OBJECT_PKEY; + X509_PUBKEY *xpub = NULL; + X509_ALGOR *algor = NULL; + const ASN1_OBJECT *oid = NULL; + char dataname[OSSL_MAX_NAME_SIZE]; + OSSL_PARAM params[5], *p = params; + + if (!ossl_read_der(ctx->provctx, cin, &der, &len)) + return 1; + derp = der; + xpub = ossl_d2i_X509_PUBKEY_INTERNAL((const unsigned char **)&derp, len, + PROV_LIBCTX_OF(ctx->provctx)); + + + if (xpub == NULL) { + /* We return "empty handed". This is not an error. */ + ok = 1; + goto end; + } + + if (!X509_PUBKEY_get0_param(NULL, NULL, NULL, &algor, xpub)) + goto end; + X509_ALGOR_get0(&oid, NULL, NULL, algor); + +#ifndef OPENSSL_NO_EC + /* SM2 abuses the EC oid, so this could actually be SM2 */ + if (OBJ_obj2nid(oid) == NID_X9_62_id_ecPublicKey + && ossl_x509_algor_is_sm2(algor)) + strcpy(dataname, "SM2"); + else +#endif + if (OBJ_obj2txt(dataname, sizeof(dataname), oid, 0) <= 0) + goto end; + + ossl_X509_PUBKEY_INTERNAL_free(xpub); + xpub = NULL; + + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + dataname, 0); + + *p++ = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, + "SubjectPublicKeyInfo", + 0); + *p++ = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, der, len); + *p++ = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); + + *p = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + + end: + ossl_X509_PUBKEY_INTERNAL_free(xpub); + OPENSSL_free(der); + return ok; +} + +const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_der_decoder_functions[] = { + { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))spki2typespki_newctx }, + { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))spki2typespki_freectx }, + { OSSL_FUNC_DECODER_DECODE, (void (*)(void))spki2typespki_decode }, + { 0, NULL } +}; diff --git a/providers/implementations/encode_decode/encode_key2any.c b/providers/implementations/encode_decode/encode_key2any.c new file mode 100644 index 000000000000..c7b01cb2b3e5 --- /dev/null +++ b/providers/implementations/encode_decode/encode_key2any.c @@ -0,0 +1,1465 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Low level APIs are deprecated for public use, but still ok for internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/core.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/crypto.h> +#include <openssl/params.h> +#include <openssl/asn1.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/x509.h> +#include <openssl/pkcs12.h> /* PKCS8_encrypt() */ +#include <openssl/dh.h> +#include <openssl/dsa.h> +#include <openssl/ec.h> +#include <openssl/proverr.h> +#include "internal/passphrase.h" +#include "internal/cryptlib.h" +#include "crypto/ecx.h" +#include "crypto/rsa.h" +#include "prov/implementations.h" +#include "prov/bio.h" +#include "prov/provider_ctx.h" +#include "prov/der_rsa.h" +#include "endecoder_local.h" + +#if defined(OPENSSL_NO_DH) && defined(OPENSSL_NO_DSA) && defined(OPENSSL_NO_EC) +# define OPENSSL_NO_KEYPARAMS +#endif + +struct key2any_ctx_st { + PROV_CTX *provctx; + + /* Set to 0 if parameters should not be saved (dsa only) */ + int save_parameters; + + /* Set to 1 if intending to encrypt/decrypt, otherwise 0 */ + int cipher_intent; + + EVP_CIPHER *cipher; + + struct ossl_passphrase_data_st pwdata; +}; + +typedef int check_key_type_fn(const void *key, int nid); +typedef int key_to_paramstring_fn(const void *key, int nid, int save, + void **str, int *strtype); +typedef int key_to_der_fn(BIO *out, const void *key, + int key_nid, const char *pemname, + key_to_paramstring_fn *p2s, i2d_of_void *k2d, + struct key2any_ctx_st *ctx); +typedef int write_bio_of_void_fn(BIO *bp, const void *x); + + +/* Free the blob allocated during key_to_paramstring_fn */ +static void free_asn1_data(int type, void *data) +{ + switch(type) { + case V_ASN1_OBJECT: + ASN1_OBJECT_free(data); + break; + case V_ASN1_SEQUENCE: + ASN1_STRING_free(data); + break; + } +} + +static PKCS8_PRIV_KEY_INFO *key_to_p8info(const void *key, int key_nid, + void *params, int params_type, + i2d_of_void *k2d) +{ + /* der, derlen store the key DER output and its length */ + unsigned char *der = NULL; + int derlen; + /* The final PKCS#8 info */ + PKCS8_PRIV_KEY_INFO *p8info = NULL; + + if ((p8info = PKCS8_PRIV_KEY_INFO_new()) == NULL + || (derlen = k2d(key, &der)) <= 0 + || !PKCS8_pkey_set0(p8info, OBJ_nid2obj(key_nid), 0, + params_type, params, der, derlen)) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + PKCS8_PRIV_KEY_INFO_free(p8info); + OPENSSL_free(der); + p8info = NULL; + } + + return p8info; +} + +static X509_SIG *p8info_to_encp8(PKCS8_PRIV_KEY_INFO *p8info, + struct key2any_ctx_st *ctx) +{ + X509_SIG *p8 = NULL; + char kstr[PEM_BUFSIZE]; + size_t klen = 0; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + + if (ctx->cipher == NULL) + return NULL; + + if (!ossl_pw_get_passphrase(kstr, sizeof(kstr), &klen, NULL, 1, + &ctx->pwdata)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PASSPHRASE); + return NULL; + } + /* First argument == -1 means "standard" */ + p8 = PKCS8_encrypt_ex(-1, ctx->cipher, kstr, klen, NULL, 0, 0, p8info, libctx, NULL); + OPENSSL_cleanse(kstr, klen); + return p8; +} + +static X509_SIG *key_to_encp8(const void *key, int key_nid, + void *params, int params_type, + i2d_of_void *k2d, struct key2any_ctx_st *ctx) +{ + PKCS8_PRIV_KEY_INFO *p8info = + key_to_p8info(key, key_nid, params, params_type, k2d); + X509_SIG *p8 = NULL; + + if (p8info == NULL) { + free_asn1_data(params_type, params); + } else { + p8 = p8info_to_encp8(p8info, ctx); + PKCS8_PRIV_KEY_INFO_free(p8info); + } + return p8; +} + +static X509_PUBKEY *key_to_pubkey(const void *key, int key_nid, + void *params, int params_type, + i2d_of_void k2d) +{ + /* der, derlen store the key DER output and its length */ + unsigned char *der = NULL; + int derlen; + /* The final X509_PUBKEY */ + X509_PUBKEY *xpk = NULL; + + + if ((xpk = X509_PUBKEY_new()) == NULL + || (derlen = k2d(key, &der)) <= 0 + || !X509_PUBKEY_set0_param(xpk, OBJ_nid2obj(key_nid), + params_type, params, der, derlen)) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + X509_PUBKEY_free(xpk); + OPENSSL_free(der); + xpk = NULL; + } + + return xpk; +} + +/* + * key_to_epki_* produce encoded output with the private key data in a + * EncryptedPrivateKeyInfo structure (defined by PKCS#8). They require + * that there's an intent to encrypt, anything else is an error. + * + * key_to_pki_* primarly produce encoded output with the private key data + * in a PrivateKeyInfo structure (also defined by PKCS#8). However, if + * there is an intent to encrypt the data, the corresponding key_to_epki_* + * function is used instead. + * + * key_to_spki_* produce encoded output with the public key data in an + * X.509 SubjectPublicKeyInfo. + * + * Key parameters don't have any defined envelopment of this kind, but are + * included in some manner in the output from the functions described above, + * either in the AlgorithmIdentifier's parameter field, or as part of the + * key data itself. + */ + +static int key_to_epki_der_priv_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + X509_SIG *p8; + + if (!ctx->cipher_intent) + return 0; + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx); + if (p8 != NULL) + ret = i2d_PKCS8_bio(out, p8); + + X509_SIG_free(p8); + + return ret; +} + +static int key_to_epki_pem_priv_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + X509_SIG *p8; + + if (!ctx->cipher_intent) + return 0; + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx); + if (p8 != NULL) + ret = PEM_write_bio_PKCS8(out, p8); + + X509_SIG_free(p8); + + return ret; +} + +static int key_to_pki_der_priv_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + PKCS8_PRIV_KEY_INFO *p8info; + + if (ctx->cipher_intent) + return key_to_epki_der_priv_bio(out, key, key_nid, pemname, + p2s, k2d, ctx); + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8info = key_to_p8info(key, key_nid, str, strtype, k2d); + + if (p8info != NULL) + ret = i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8info); + else + free_asn1_data(strtype, str); + + PKCS8_PRIV_KEY_INFO_free(p8info); + + return ret; +} + +static int key_to_pki_pem_priv_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + PKCS8_PRIV_KEY_INFO *p8info; + + if (ctx->cipher_intent) + return key_to_epki_pem_priv_bio(out, key, key_nid, pemname, + p2s, k2d, ctx); + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8info = key_to_p8info(key, key_nid, str, strtype, k2d); + + if (p8info != NULL) + ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8info); + else + free_asn1_data(strtype, str); + + PKCS8_PRIV_KEY_INFO_free(p8info); + + return ret; +} + +static int key_to_spki_der_pub_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + X509_PUBKEY *xpk = NULL; + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + xpk = key_to_pubkey(key, key_nid, str, strtype, k2d); + + if (xpk != NULL) + ret = i2d_X509_PUBKEY_bio(out, xpk); + + /* Also frees |str| */ + X509_PUBKEY_free(xpk); + return ret; +} + +static int key_to_spki_pem_pub_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + X509_PUBKEY *xpk = NULL; + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + xpk = key_to_pubkey(key, key_nid, str, strtype, k2d); + + if (xpk != NULL) + ret = PEM_write_bio_X509_PUBKEY(out, xpk); + else + free_asn1_data(strtype, str); + + /* Also frees |str| */ + X509_PUBKEY_free(xpk); + return ret; +} + +/* + * key_to_type_specific_* produce encoded output with type specific key data, + * no envelopment; the same kind of output as the type specific i2d_ and + * PEM_write_ functions, which is often a simple SEQUENCE of INTEGER. + * + * OpenSSL tries to discourage production of new keys in this form, because + * of the ambiguity when trying to recognise them, but can't deny that PKCS#1 + * et al still are live standards. + * + * Note that these functions completely ignore p2s, and rather rely entirely + * on k2d to do the complete work. + */ +static int key_to_type_specific_der_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + unsigned char *der = NULL; + int derlen; + int ret; + + if ((derlen = k2d(key, &der)) <= 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + ret = BIO_write(out, der, derlen); + OPENSSL_free(der); + return ret > 0; +} +#define key_to_type_specific_der_priv_bio key_to_type_specific_der_bio +#define key_to_type_specific_der_pub_bio key_to_type_specific_der_bio +#define key_to_type_specific_der_param_bio key_to_type_specific_der_bio + +static int key_to_type_specific_pem_bio_cb(BIO *out, const void *key, + int key_nid, const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx, + pem_password_cb *cb, void *cbarg) +{ + return + PEM_ASN1_write_bio(k2d, pemname, out, key, ctx->cipher, + NULL, 0, cb, cbarg) > 0; +} + +static int key_to_type_specific_pem_priv_bio(BIO *out, const void *key, + int key_nid, const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname, + p2s, k2d, ctx, + ossl_pw_pem_password, &ctx->pwdata); +} + +static int key_to_type_specific_pem_pub_bio(BIO *out, const void *key, + int key_nid, const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname, + p2s, k2d, ctx, NULL, NULL); +} + +#ifndef OPENSSL_NO_KEYPARAMS +static int key_to_type_specific_pem_param_bio(BIO *out, const void *key, + int key_nid, const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname, + p2s, k2d, ctx, NULL, NULL); +} +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DH +static int prepare_dh_params(const void *dh, int nid, int save, + void **pstr, int *pstrtype) +{ + ASN1_STRING *params = ASN1_STRING_new(); + + if (params == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (nid == EVP_PKEY_DHX) + params->length = i2d_DHxparams(dh, ¶ms->data); + else + params->length = i2d_DHparams(dh, ¶ms->data); + + if (params->length <= 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ASN1_STRING_free(params); + return 0; + } + params->type = V_ASN1_SEQUENCE; + + *pstr = params; + *pstrtype = V_ASN1_SEQUENCE; + return 1; +} + +static int dh_spki_pub_to_der(const void *dh, unsigned char **pder) +{ + const BIGNUM *bn = NULL; + ASN1_INTEGER *pub_key = NULL; + int ret; + + if ((bn = DH_get0_pub_key(dh)) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + if ((pub_key = BN_to_ASN1_INTEGER(bn, NULL)) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_BN_ERROR); + return 0; + } + + ret = i2d_ASN1_INTEGER(pub_key, pder); + + ASN1_STRING_clear_free(pub_key); + return ret; +} + +static int dh_pki_priv_to_der(const void *dh, unsigned char **pder) +{ + const BIGNUM *bn = NULL; + ASN1_INTEGER *priv_key = NULL; + int ret; + + if ((bn = DH_get0_priv_key(dh)) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } + if ((priv_key = BN_to_ASN1_INTEGER(bn, NULL)) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_BN_ERROR); + return 0; + } + + ret = i2d_ASN1_INTEGER(priv_key, pder); + + ASN1_STRING_clear_free(priv_key); + return ret; +} + +# define dh_epki_priv_to_der dh_pki_priv_to_der + +static int dh_type_specific_params_to_der(const void *dh, unsigned char **pder) +{ + if (DH_test_flags(dh, DH_FLAG_TYPE_DHX)) + return i2d_DHxparams(dh, pder); + return i2d_DHparams(dh, pder); +} + +/* + * DH doesn't have i2d_DHPrivateKey or i2d_DHPublicKey, so we can't make + * corresponding functions here. + */ +# define dh_type_specific_priv_to_der NULL +# define dh_type_specific_pub_to_der NULL + +static int dh_check_key_type(const void *dh, int expected_type) +{ + int type = + DH_test_flags(dh, DH_FLAG_TYPE_DHX) ? EVP_PKEY_DHX : EVP_PKEY_DH; + + return type == expected_type; +} + +# define dh_evp_type EVP_PKEY_DH +# define dhx_evp_type EVP_PKEY_DHX +# define dh_input_type "DH" +# define dhx_input_type "DHX" +# define dh_pem_type "DH" +# define dhx_pem_type "X9.42 DH" +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DSA +static int encode_dsa_params(const void *dsa, int nid, + void **pstr, int *pstrtype) +{ + ASN1_STRING *params = ASN1_STRING_new(); + + if (params == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + params->length = i2d_DSAparams(dsa, ¶ms->data); + + if (params->length <= 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ASN1_STRING_free(params); + return 0; + } + + *pstrtype = V_ASN1_SEQUENCE; + *pstr = params; + return 1; +} + +static int prepare_dsa_params(const void *dsa, int nid, int save, + void **pstr, int *pstrtype) +{ + const BIGNUM *p = DSA_get0_p(dsa); + const BIGNUM *q = DSA_get0_q(dsa); + const BIGNUM *g = DSA_get0_g(dsa); + + if (save && p != NULL && q != NULL && g != NULL) + return encode_dsa_params(dsa, nid, pstr, pstrtype); + + *pstr = NULL; + *pstrtype = V_ASN1_UNDEF; + return 1; +} + +static int dsa_spki_pub_to_der(const void *dsa, unsigned char **pder) +{ + const BIGNUM *bn = NULL; + ASN1_INTEGER *pub_key = NULL; + int ret; + + if ((bn = DSA_get0_pub_key(dsa)) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + if ((pub_key = BN_to_ASN1_INTEGER(bn, NULL)) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_BN_ERROR); + return 0; + } + + ret = i2d_ASN1_INTEGER(pub_key, pder); + + ASN1_STRING_clear_free(pub_key); + return ret; +} + +static int dsa_pki_priv_to_der(const void *dsa, unsigned char **pder) +{ + const BIGNUM *bn = NULL; + ASN1_INTEGER *priv_key = NULL; + int ret; + + if ((bn = DSA_get0_priv_key(dsa)) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } + if ((priv_key = BN_to_ASN1_INTEGER(bn, NULL)) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_BN_ERROR); + return 0; + } + + ret = i2d_ASN1_INTEGER(priv_key, pder); + + ASN1_STRING_clear_free(priv_key); + return ret; +} + +# define dsa_epki_priv_to_der dsa_pki_priv_to_der + +# define dsa_type_specific_priv_to_der (i2d_of_void *)i2d_DSAPrivateKey +# define dsa_type_specific_pub_to_der (i2d_of_void *)i2d_DSAPublicKey +# define dsa_type_specific_params_to_der (i2d_of_void *)i2d_DSAparams + +# define dsa_check_key_type NULL +# define dsa_evp_type EVP_PKEY_DSA +# define dsa_input_type "DSA" +# define dsa_pem_type "DSA" +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_EC +static int prepare_ec_explicit_params(const void *eckey, + void **pstr, int *pstrtype) +{ + ASN1_STRING *params = ASN1_STRING_new(); + + if (params == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + params->length = i2d_ECParameters(eckey, ¶ms->data); + if (params->length <= 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ASN1_STRING_free(params); + return 0; + } + + *pstrtype = V_ASN1_SEQUENCE; + *pstr = params; + return 1; +} + +/* + * This implements EcpkParameters, where the CHOICE is based on whether there + * is a curve name (curve nid) to be found or not. See RFC 3279 for details. + */ +static int prepare_ec_params(const void *eckey, int nid, int save, + void **pstr, int *pstrtype) +{ + int curve_nid; + const EC_GROUP *group = EC_KEY_get0_group(eckey); + ASN1_OBJECT *params = NULL; + + if (group == NULL) + return 0; + curve_nid = EC_GROUP_get_curve_name(group); + if (curve_nid != NID_undef) { + params = OBJ_nid2obj(curve_nid); + if (params == NULL) + return 0; + } + + if (curve_nid != NID_undef + && (EC_GROUP_get_asn1_flag(group) & OPENSSL_EC_NAMED_CURVE)) { + /* The CHOICE came to namedCurve */ + if (OBJ_length(params) == 0) { + /* Some curves might not have an associated OID */ + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_OID); + ASN1_OBJECT_free(params); + return 0; + } + *pstr = params; + *pstrtype = V_ASN1_OBJECT; + return 1; + } else { + /* The CHOICE came to ecParameters */ + return prepare_ec_explicit_params(eckey, pstr, pstrtype); + } +} + +static int ec_spki_pub_to_der(const void *eckey, unsigned char **pder) +{ + if (EC_KEY_get0_public_key(eckey) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + return i2o_ECPublicKey(eckey, pder); +} + +static int ec_pki_priv_to_der(const void *veckey, unsigned char **pder) +{ + EC_KEY *eckey = (EC_KEY *)veckey; + unsigned int old_flags; + int ret = 0; + + /* + * For PKCS8 the curve name appears in the PKCS8_PRIV_KEY_INFO object + * as the pkeyalg->parameter field. (For a named curve this is an OID) + * The pkey field is an octet string that holds the encoded + * ECPrivateKey SEQUENCE with the optional parameters field omitted. + * We omit this by setting the EC_PKEY_NO_PARAMETERS flag. + */ + old_flags = EC_KEY_get_enc_flags(eckey); /* save old flags */ + EC_KEY_set_enc_flags(eckey, old_flags | EC_PKEY_NO_PARAMETERS); + ret = i2d_ECPrivateKey(eckey, pder); + EC_KEY_set_enc_flags(eckey, old_flags); /* restore old flags */ + return ret; /* return the length of the der encoded data */ +} + +# define ec_epki_priv_to_der ec_pki_priv_to_der + +# define ec_type_specific_params_to_der (i2d_of_void *)i2d_ECParameters +/* No ec_type_specific_pub_to_der, there simply is no such thing */ +# define ec_type_specific_priv_to_der (i2d_of_void *)i2d_ECPrivateKey + +# define ec_check_key_type NULL +# define ec_evp_type EVP_PKEY_EC +# define ec_input_type "EC" +# define ec_pem_type "EC" + +# ifndef OPENSSL_NO_SM2 +# define sm2_evp_type EVP_PKEY_SM2 +# define sm2_input_type "SM2" +# define sm2_pem_type "SM2" +# endif +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_EC +# define prepare_ecx_params NULL + +static int ecx_spki_pub_to_der(const void *vecxkey, unsigned char **pder) +{ + const ECX_KEY *ecxkey = vecxkey; + unsigned char *keyblob; + + if (ecxkey == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + keyblob = OPENSSL_memdup(ecxkey->pubkey, ecxkey->keylen); + if (keyblob == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + *pder = keyblob; + return ecxkey->keylen; +} + +static int ecx_pki_priv_to_der(const void *vecxkey, unsigned char **pder) +{ + const ECX_KEY *ecxkey = vecxkey; + ASN1_OCTET_STRING oct; + int keybloblen; + + if (ecxkey == NULL || ecxkey->privkey == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + oct.data = ecxkey->privkey; + oct.length = ecxkey->keylen; + oct.flags = 0; + + keybloblen = i2d_ASN1_OCTET_STRING(&oct, pder); + if (keybloblen < 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + return keybloblen; +} + +# define ecx_epki_priv_to_der ecx_pki_priv_to_der + +/* + * ED25519, ED448, X25519 and X448 only has PKCS#8 / SubjectPublicKeyInfo + * representation, so we don't define ecx_type_specific_[priv,pub,params]_to_der. + */ + +# define ecx_check_key_type NULL + +# define ed25519_evp_type EVP_PKEY_ED25519 +# define ed448_evp_type EVP_PKEY_ED448 +# define x25519_evp_type EVP_PKEY_X25519 +# define x448_evp_type EVP_PKEY_X448 +# define ed25519_input_type "ED25519" +# define ed448_input_type "ED448" +# define x25519_input_type "X25519" +# define x448_input_type "X448" +# define ed25519_pem_type "ED25519" +# define ed448_pem_type "ED448" +# define x25519_pem_type "X25519" +# define x448_pem_type "X448" +#endif + +/* ---------------------------------------------------------------------- */ + +/* + * Helper functions to prepare RSA-PSS params for encoding. We would + * have simply written the whole AlgorithmIdentifier, but existing libcrypto + * functionality doesn't allow that. + */ + +static int prepare_rsa_params(const void *rsa, int nid, int save, + void **pstr, int *pstrtype) +{ + const RSA_PSS_PARAMS_30 *pss = ossl_rsa_get0_pss_params_30((RSA *)rsa); + + *pstr = NULL; + + switch (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK)) { + case RSA_FLAG_TYPE_RSA: + /* If plain RSA, the parameters shall be NULL */ + *pstrtype = V_ASN1_NULL; + return 1; + case RSA_FLAG_TYPE_RSASSAPSS: + if (ossl_rsa_pss_params_30_is_unrestricted(pss)) { + *pstrtype = V_ASN1_UNDEF; + return 1; + } else { + ASN1_STRING *astr = NULL; + WPACKET pkt; + unsigned char *str = NULL; + size_t str_sz = 0; + int i; + + for (i = 0; i < 2; i++) { + switch (i) { + case 0: + if (!WPACKET_init_null_der(&pkt)) + goto err; + break; + case 1: + if ((str = OPENSSL_malloc(str_sz)) == NULL + || !WPACKET_init_der(&pkt, str, str_sz)) { + goto err; + } + break; + } + if (!ossl_DER_w_RSASSA_PSS_params(&pkt, -1, pss) + || !WPACKET_finish(&pkt) + || !WPACKET_get_total_written(&pkt, &str_sz)) + goto err; + WPACKET_cleanup(&pkt); + + /* + * If no PSS parameters are going to be written, there's no + * point going for another iteration. + * This saves us from getting |str| allocated just to have it + * immediately de-allocated. + */ + if (str_sz == 0) + break; + } + + if ((astr = ASN1_STRING_new()) == NULL) + goto err; + *pstrtype = V_ASN1_SEQUENCE; + ASN1_STRING_set0(astr, str, (int)str_sz); + *pstr = astr; + + return 1; + err: + OPENSSL_free(str); + return 0; + } + } + + /* Currently unsupported RSA key type */ + return 0; +} + +/* + * RSA is extremely simple, as PKCS#1 is used for the PKCS#8 |privateKey| + * field as well as the SubjectPublicKeyInfo |subjectPublicKey| field. + */ +#define rsa_pki_priv_to_der rsa_type_specific_priv_to_der +#define rsa_epki_priv_to_der rsa_type_specific_priv_to_der +#define rsa_spki_pub_to_der rsa_type_specific_pub_to_der +#define rsa_type_specific_priv_to_der (i2d_of_void *)i2d_RSAPrivateKey +#define rsa_type_specific_pub_to_der (i2d_of_void *)i2d_RSAPublicKey +#define rsa_type_specific_params_to_der NULL + +static int rsa_check_key_type(const void *rsa, int expected_type) +{ + switch (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK)) { + case RSA_FLAG_TYPE_RSA: + return expected_type == EVP_PKEY_RSA; + case RSA_FLAG_TYPE_RSASSAPSS: + return expected_type == EVP_PKEY_RSA_PSS; + } + + /* Currently unsupported RSA key type */ + return EVP_PKEY_NONE; +} + +#define rsa_evp_type EVP_PKEY_RSA +#define rsapss_evp_type EVP_PKEY_RSA_PSS +#define rsa_input_type "RSA" +#define rsapss_input_type "RSA-PSS" +#define rsa_pem_type "RSA" +#define rsapss_pem_type "RSA-PSS" + +/* ---------------------------------------------------------------------- */ + +static OSSL_FUNC_decoder_newctx_fn key2any_newctx; +static OSSL_FUNC_decoder_freectx_fn key2any_freectx; + +static void *key2any_newctx(void *provctx) +{ + struct key2any_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + ctx->save_parameters = 1; + } + + return ctx; +} + +static void key2any_freectx(void *vctx) +{ + struct key2any_ctx_st *ctx = vctx; + + ossl_pw_clear_passphrase_data(&ctx->pwdata); + EVP_CIPHER_free(ctx->cipher); + OPENSSL_free(ctx); +} + +static const OSSL_PARAM *key2any_settable_ctx_params(ossl_unused void *provctx) +{ + static const OSSL_PARAM settables[] = { + OSSL_PARAM_utf8_string(OSSL_ENCODER_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ENCODER_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_END, + }; + + return settables; +} + +static int key2any_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct key2any_ctx_st *ctx = vctx; + OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(ctx->provctx); + const OSSL_PARAM *cipherp = + OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_CIPHER); + const OSSL_PARAM *propsp = + OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_PROPERTIES); + const OSSL_PARAM *save_paramsp = + OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_SAVE_PARAMETERS); + + if (cipherp != NULL) { + const char *ciphername = NULL; + const char *props = NULL; + + if (!OSSL_PARAM_get_utf8_string_ptr(cipherp, &ciphername)) + return 0; + if (propsp != NULL && !OSSL_PARAM_get_utf8_string_ptr(propsp, &props)) + return 0; + + EVP_CIPHER_free(ctx->cipher); + ctx->cipher = NULL; + ctx->cipher_intent = ciphername != NULL; + if (ciphername != NULL + && ((ctx->cipher = + EVP_CIPHER_fetch(libctx, ciphername, props)) == NULL)) + return 0; + } + + if (save_paramsp != NULL) { + if (!OSSL_PARAM_get_int(save_paramsp, &ctx->save_parameters)) + return 0; + } + return 1; +} + +static int key2any_check_selection(int selection, int selection_mask) +{ + /* + * The selections are kinda sorta "levels", i.e. each selection given + * here is assumed to include those following. + */ + int checks[] = { + OSSL_KEYMGMT_SELECT_PRIVATE_KEY, + OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + OSSL_KEYMGMT_SELECT_ALL_PARAMETERS + }; + size_t i; + + /* The decoder implementations made here support guessing */ + if (selection == 0) + return 1; + + for (i = 0; i < OSSL_NELEM(checks); i++) { + int check1 = (selection & checks[i]) != 0; + int check2 = (selection_mask & checks[i]) != 0; + + /* + * If the caller asked for the currently checked bit(s), return + * whether the decoder description says it's supported. + */ + if (check1) + return check2; + } + + /* This should be dead code, but just to be safe... */ + return 0; +} + +static int key2any_encode(struct key2any_ctx_st *ctx, OSSL_CORE_BIO *cout, + const void *key, int type, const char *pemname, + check_key_type_fn *checker, + key_to_der_fn *writer, + OSSL_PASSPHRASE_CALLBACK *pwcb, void *pwcbarg, + key_to_paramstring_fn *key2paramstring, + i2d_of_void *key2der) +{ + int ret = 0; + + if (key == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + } else if (writer != NULL + && (checker == NULL || checker(key, type))) { + BIO *out = ossl_bio_new_from_core_bio(ctx->provctx, cout); + + if (out != NULL + && (pwcb == NULL + || ossl_pw_set_ossl_passphrase_cb(&ctx->pwdata, pwcb, pwcbarg))) + ret = + writer(out, key, type, pemname, key2paramstring, key2der, ctx); + + BIO_free(out); + } else { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + } + return ret; +} + +#define DO_PRIVATE_KEY_selection_mask OSSL_KEYMGMT_SELECT_PRIVATE_KEY +#define DO_PRIVATE_KEY(impl, type, kind, output) \ + if ((selection & DO_PRIVATE_KEY_selection_mask) != 0) \ + return key2any_encode(ctx, cout, key, impl##_evp_type, \ + impl##_pem_type " PRIVATE KEY", \ + type##_check_key_type, \ + key_to_##kind##_##output##_priv_bio, \ + cb, cbarg, prepare_##type##_params, \ + type##_##kind##_priv_to_der); + +#define DO_PUBLIC_KEY_selection_mask OSSL_KEYMGMT_SELECT_PUBLIC_KEY +#define DO_PUBLIC_KEY(impl, type, kind, output) \ + if ((selection & DO_PUBLIC_KEY_selection_mask) != 0) \ + return key2any_encode(ctx, cout, key, impl##_evp_type, \ + impl##_pem_type " PUBLIC KEY", \ + type##_check_key_type, \ + key_to_##kind##_##output##_pub_bio, \ + cb, cbarg, prepare_##type##_params, \ + type##_##kind##_pub_to_der); + +#define DO_PARAMETERS_selection_mask OSSL_KEYMGMT_SELECT_ALL_PARAMETERS +#define DO_PARAMETERS(impl, type, kind, output) \ + if ((selection & DO_PARAMETERS_selection_mask) != 0) \ + return key2any_encode(ctx, cout, key, impl##_evp_type, \ + impl##_pem_type " PARAMETERS", \ + type##_check_key_type, \ + key_to_##kind##_##output##_param_bio, \ + NULL, NULL, NULL, \ + type##_##kind##_params_to_der); + +/*- + * Implement the kinds of output structure that can be produced. They are + * referred to by name, and for each name, the following macros are defined + * (braces not included): + * + * DO_{kind}_selection_mask + * + * A mask of selection bits that must not be zero. This is used as a + * selection criterion for each implementation. + * This mask must never be zero. + * + * DO_{kind} + * + * The performing macro. It must use the DO_ macros defined above, + * always in this order: + * + * - DO_PRIVATE_KEY + * - DO_PUBLIC_KEY + * - DO_PARAMETERS + * + * Any of those may be omitted, but the relative order must still be + * the same. + */ + +/* + * PKCS#8 defines two structures for private keys only: + * - PrivateKeyInfo (raw unencrypted form) + * - EncryptedPrivateKeyInfo (encrypted wrapping) + * + * To allow a certain amount of flexibility, we allow the routines + * for PrivateKeyInfo to also produce EncryptedPrivateKeyInfo if a + * passphrase callback has been passed to them. + */ +#define DO_PrivateKeyInfo_selection_mask DO_PRIVATE_KEY_selection_mask +#define DO_PrivateKeyInfo(impl, type, output) \ + DO_PRIVATE_KEY(impl, type, pki, output) + +#define DO_EncryptedPrivateKeyInfo_selection_mask DO_PRIVATE_KEY_selection_mask +#define DO_EncryptedPrivateKeyInfo(impl, type, output) \ + DO_PRIVATE_KEY(impl, type, epki, output) + +/* SubjectPublicKeyInfo is a structure for public keys only */ +#define DO_SubjectPublicKeyInfo_selection_mask DO_PUBLIC_KEY_selection_mask +#define DO_SubjectPublicKeyInfo(impl, type, output) \ + DO_PUBLIC_KEY(impl, type, spki, output) + +/* + * "type-specific" is a uniform name for key type specific output for private + * and public keys as well as key parameters. This is used internally in + * libcrypto so it doesn't have to have special knowledge about select key + * types, but also when no better name has been found. If there are more + * expressive DO_ names above, those are preferred. + * + * Three forms exist: + * + * - type_specific_keypair Only supports private and public key + * - type_specific_params Only supports parameters + * - type_specific Supports all parts of an EVP_PKEY + * - type_specific_no_pub Supports all parts of an EVP_PKEY + * except public key + */ +#define DO_type_specific_params_selection_mask DO_PARAMETERS_selection_mask +#define DO_type_specific_params(impl, type, output) \ + DO_PARAMETERS(impl, type, type_specific, output) +#define DO_type_specific_keypair_selection_mask \ + ( DO_PRIVATE_KEY_selection_mask | DO_PUBLIC_KEY_selection_mask ) +#define DO_type_specific_keypair(impl, type, output) \ + DO_PRIVATE_KEY(impl, type, type_specific, output) \ + DO_PUBLIC_KEY(impl, type, type_specific, output) +#define DO_type_specific_selection_mask \ + ( DO_type_specific_keypair_selection_mask \ + | DO_type_specific_params_selection_mask ) +#define DO_type_specific(impl, type, output) \ + DO_type_specific_keypair(impl, type, output) \ + DO_type_specific_params(impl, type, output) +#define DO_type_specific_no_pub_selection_mask \ + ( DO_PRIVATE_KEY_selection_mask | DO_PARAMETERS_selection_mask) +#define DO_type_specific_no_pub(impl, type, output) \ + DO_PRIVATE_KEY(impl, type, type_specific, output) \ + DO_type_specific_params(impl, type, output) + +/* + * Type specific aliases for the cases where we need to refer to them by + * type name. + * This only covers key types that are represented with i2d_{TYPE}PrivateKey, + * i2d_{TYPE}PublicKey and i2d_{TYPE}params / i2d_{TYPE}Parameters. + */ +#define DO_RSA_selection_mask DO_type_specific_keypair_selection_mask +#define DO_RSA(impl, type, output) DO_type_specific_keypair(impl, type, output) + +#define DO_DH_selection_mask DO_type_specific_params_selection_mask +#define DO_DH(impl, type, output) DO_type_specific_params(impl, type, output) + +#define DO_DHX_selection_mask DO_type_specific_params_selection_mask +#define DO_DHX(impl, type, output) DO_type_specific_params(impl, type, output) + +#define DO_DSA_selection_mask DO_type_specific_selection_mask +#define DO_DSA(impl, type, output) DO_type_specific(impl, type, output) + +#define DO_EC_selection_mask DO_type_specific_no_pub_selection_mask +#define DO_EC(impl, type, output) DO_type_specific_no_pub(impl, type, output) + +#define DO_SM2_selection_mask DO_type_specific_no_pub_selection_mask +#define DO_SM2(impl, type, output) DO_type_specific_no_pub(impl, type, output) + +/* PKCS#1 defines a structure for RSA private and public keys */ +#define DO_PKCS1_selection_mask DO_RSA_selection_mask +#define DO_PKCS1(impl, type, output) DO_RSA(impl, type, output) + +/* PKCS#3 defines a structure for DH parameters */ +#define DO_PKCS3_selection_mask DO_DH_selection_mask +#define DO_PKCS3(impl, type, output) DO_DH(impl, type, output) +/* X9.42 defines a structure for DHx parameters */ +#define DO_X9_42_selection_mask DO_DHX_selection_mask +#define DO_X9_42(impl, type, output) DO_DHX(impl, type, output) + +/* X9.62 defines a structure for EC keys and parameters */ +#define DO_X9_62_selection_mask DO_EC_selection_mask +#define DO_X9_62(impl, type, output) DO_EC(impl, type, output) + +/* + * MAKE_ENCODER is the single driver for creating OSSL_DISPATCH tables. + * It takes the following arguments: + * + * impl This is the key type name that's being implemented. + * type This is the type name for the set of functions that implement + * the key type. For example, ed25519, ed448, x25519 and x448 + * are all implemented with the exact same set of functions. + * evp_type The corresponding EVP_PKEY_xxx type macro for each key. + * Necessary because we currently use EVP_PKEY with legacy + * native keys internally. This will need to be refactored + * when that legacy support goes away. + * kind What kind of support to implement. These translate into + * the DO_##kind macros above. + * output The output type to implement. may be der or pem. + * + * The resulting OSSL_DISPATCH array gets the following name (expressed in + * C preprocessor terms) from those arguments: + * + * ossl_##impl##_to_##kind##_##output##_encoder_functions + */ +#define MAKE_ENCODER(impl, type, evp_type, kind, output) \ + static OSSL_FUNC_encoder_import_object_fn \ + impl##_to_##kind##_##output##_import_object; \ + static OSSL_FUNC_encoder_free_object_fn \ + impl##_to_##kind##_##output##_free_object; \ + static OSSL_FUNC_encoder_encode_fn \ + impl##_to_##kind##_##output##_encode; \ + \ + static void * \ + impl##_to_##kind##_##output##_import_object(void *vctx, int selection, \ + const OSSL_PARAM params[]) \ + { \ + struct key2any_ctx_st *ctx = vctx; \ + \ + return ossl_prov_import_key(ossl_##impl##_keymgmt_functions, \ + ctx->provctx, selection, params); \ + } \ + static void impl##_to_##kind##_##output##_free_object(void *key) \ + { \ + ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key); \ + } \ + static int impl##_to_##kind##_##output##_does_selection(void *ctx, \ + int selection) \ + { \ + return key2any_check_selection(selection, \ + DO_##kind##_selection_mask); \ + } \ + static int \ + impl##_to_##kind##_##output##_encode(void *ctx, OSSL_CORE_BIO *cout, \ + const void *key, \ + const OSSL_PARAM key_abstract[], \ + int selection, \ + OSSL_PASSPHRASE_CALLBACK *cb, \ + void *cbarg) \ + { \ + /* We don't deal with abstract objects */ \ + if (key_abstract != NULL) { \ + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); \ + return 0; \ + } \ + DO_##kind(impl, type, output) \ + \ + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); \ + return 0; \ + } \ + const OSSL_DISPATCH \ + ossl_##impl##_to_##kind##_##output##_encoder_functions[] = { \ + { OSSL_FUNC_ENCODER_NEWCTX, \ + (void (*)(void))key2any_newctx }, \ + { OSSL_FUNC_ENCODER_FREECTX, \ + (void (*)(void))key2any_freectx }, \ + { OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))key2any_settable_ctx_params }, \ + { OSSL_FUNC_ENCODER_SET_CTX_PARAMS, \ + (void (*)(void))key2any_set_ctx_params }, \ + { OSSL_FUNC_ENCODER_DOES_SELECTION, \ + (void (*)(void))impl##_to_##kind##_##output##_does_selection }, \ + { OSSL_FUNC_ENCODER_IMPORT_OBJECT, \ + (void (*)(void))impl##_to_##kind##_##output##_import_object }, \ + { OSSL_FUNC_ENCODER_FREE_OBJECT, \ + (void (*)(void))impl##_to_##kind##_##output##_free_object }, \ + { OSSL_FUNC_ENCODER_ENCODE, \ + (void (*)(void))impl##_to_##kind##_##output##_encode }, \ + { 0, NULL } \ + } + +/* + * Replacements for i2d_{TYPE}PrivateKey, i2d_{TYPE}PublicKey, + * i2d_{TYPE}params, as they exist. + */ +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, type_specific_keypair, der); +#ifndef OPENSSL_NO_DH +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, type_specific_params, der); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, type_specific_params, der); +#endif +#ifndef OPENSSL_NO_DSA +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, type_specific, der); +#endif +#ifndef OPENSSL_NO_EC +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, type_specific_no_pub, der); +# ifndef OPENSSL_NO_SM2 +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, type_specific_no_pub, der); +# endif +#endif + +/* + * Replacements for PEM_write_bio_{TYPE}PrivateKey, + * PEM_write_bio_{TYPE}PublicKey, PEM_write_bio_{TYPE}params, as they exist. + */ +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, type_specific_keypair, pem); +#ifndef OPENSSL_NO_DH +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, type_specific_params, pem); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, type_specific_params, pem); +#endif +#ifndef OPENSSL_NO_DSA +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, type_specific, pem); +#endif +#ifndef OPENSSL_NO_EC +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, type_specific_no_pub, pem); +# ifndef OPENSSL_NO_SM2 +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, type_specific_no_pub, pem); +# endif +#endif + +/* + * PKCS#8 and SubjectPublicKeyInfo support. This may duplicate some of the + * implementations specified above, but are more specific. + * The SubjectPublicKeyInfo implementations also replace the + * PEM_write_bio_{TYPE}_PUBKEY functions. + * For PEM, these are expected to be used by PEM_write_bio_PrivateKey(), + * PEM_write_bio_PUBKEY() and PEM_write_bio_Parameters(). + */ +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PrivateKeyInfo, der); +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PrivateKeyInfo, pem); +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, SubjectPublicKeyInfo, der); +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PrivateKeyInfo, der); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PrivateKeyInfo, pem); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, SubjectPublicKeyInfo, der); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, SubjectPublicKeyInfo, pem); +#ifndef OPENSSL_NO_DH +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PrivateKeyInfo, der); +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PrivateKeyInfo, pem); +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, SubjectPublicKeyInfo, der); +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PrivateKeyInfo, der); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PrivateKeyInfo, pem); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, SubjectPublicKeyInfo, der); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, SubjectPublicKeyInfo, pem); +#endif +#ifndef OPENSSL_NO_DSA +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PrivateKeyInfo, der); +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PrivateKeyInfo, pem); +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, SubjectPublicKeyInfo, der); +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, SubjectPublicKeyInfo, pem); +#endif +#ifndef OPENSSL_NO_EC +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PrivateKeyInfo, der); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PrivateKeyInfo, pem); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, der); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, pem); +# ifndef OPENSSL_NO_SM2 +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, PrivateKeyInfo, der); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, PrivateKeyInfo, pem); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, der); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, pem); +# endif +MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PrivateKeyInfo, der); +MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PrivateKeyInfo, pem); +MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, SubjectPublicKeyInfo, der); +MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, der); +MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, pem); +MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, der); +MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PrivateKeyInfo, der); +MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PrivateKeyInfo, pem); +MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, SubjectPublicKeyInfo, der); +MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, der); +MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, pem); +MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, der); +MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, pem); +#endif + +/* + * Support for key type specific output formats. Not all key types have + * this, we only aim to duplicate what is available in 1.1.1 as + * i2d_TYPEPrivateKey(), i2d_TYPEPublicKey() and i2d_TYPEparams(). + * For example, there are no publicly available i2d_ function for + * ED25519, ED448, X25519 or X448, and they therefore only have PKCS#8 + * and SubjectPublicKeyInfo implementations as implemented above. + */ +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, RSA, der); +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, RSA, pem); +#ifndef OPENSSL_NO_DH +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, DH, der); +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, DH, pem); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, DHX, der); +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, DHX, pem); +#endif +#ifndef OPENSSL_NO_DSA +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, DSA, der); +MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, DSA, pem); +#endif +#ifndef OPENSSL_NO_EC +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, EC, der); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, EC, pem); +# ifndef OPENSSL_NO_SM2 +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, SM2, der); +MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, SM2, pem); +# endif +#endif + +/* Convenience structure names */ +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS1, der); +MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS1, pem); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS1, der); +MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS1, pem); +#ifndef OPENSSL_NO_DH +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS3, der); /* parameters only */ +MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS3, pem); /* parameters only */ +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, X9_42, der); /* parameters only */ +MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, X9_42, pem); /* parameters only */ +#endif +#ifndef OPENSSL_NO_EC +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, X9_62, der); +MAKE_ENCODER(ec, ec, EVP_PKEY_EC, X9_62, pem); +#endif diff --git a/providers/implementations/encode_decode/encode_key2blob.c b/providers/implementations/encode_decode/encode_key2blob.c new file mode 100644 index 000000000000..550bceb09f58 --- /dev/null +++ b/providers/implementations/encode_decode/encode_key2blob.c @@ -0,0 +1,179 @@ +/* + * Copyright 2021-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Low level APIs are deprecated for public use, but still ok for internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/core.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/ec.h> +#include "internal/passphrase.h" +#include "internal/nelem.h" +#include "prov/implementations.h" +#include "prov/bio.h" +#include "prov/provider_ctx.h" +#include "endecoder_local.h" + +static int write_blob(void *provctx, OSSL_CORE_BIO *cout, + void *data, int len) +{ + BIO *out = ossl_bio_new_from_core_bio(provctx, cout); + int ret; + + if (out == NULL) + return 0; + ret = BIO_write(out, data, len); + + BIO_free(out); + return ret; +} + +static OSSL_FUNC_encoder_newctx_fn key2blob_newctx; +static OSSL_FUNC_encoder_freectx_fn key2blob_freectx; + +static void *key2blob_newctx(void *provctx) +{ + return provctx; +} + +static void key2blob_freectx(void *vctx) +{ +} + +static int key2blob_check_selection(int selection, int selection_mask) +{ + /* + * The selections are kinda sorta "levels", i.e. each selection given + * here is assumed to include those following. + */ + int checks[] = { + OSSL_KEYMGMT_SELECT_PRIVATE_KEY, + OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + OSSL_KEYMGMT_SELECT_ALL_PARAMETERS + }; + size_t i; + + /* The decoder implementations made here support guessing */ + if (selection == 0) + return 1; + + for (i = 0; i < OSSL_NELEM(checks); i++) { + int check1 = (selection & checks[i]) != 0; + int check2 = (selection_mask & checks[i]) != 0; + + /* + * If the caller asked for the currently checked bit(s), return + * whether the decoder description says it's supported. + */ + if (check1) + return check2; + } + + /* This should be dead code, but just to be safe... */ + return 0; +} + +static int key2blob_encode(void *vctx, const void *key, int selection, + OSSL_CORE_BIO *cout) +{ + int pubkey_len = 0, ok = 0; + unsigned char *pubkey = NULL; + + pubkey_len = i2o_ECPublicKey(key, &pubkey); + if (pubkey_len > 0 && pubkey != NULL) + ok = write_blob(vctx, cout, pubkey, pubkey_len); + OPENSSL_free(pubkey); + return ok; +} + +/* + * MAKE_BLOB_ENCODER() Makes an OSSL_DISPATCH table for a particular key->blob + * encoder + * + * impl: The keytype to encode + * type: The C structure type holding the key data + * selection_name: The acceptable selections. This translates into + * the macro EVP_PKEY_##selection_name. + * + * The selection is understood as a "level" rather than an exact set of + * requests from the caller. The encoder has to decide what contents fit + * the encoded format. For example, the EC public key blob will only contain + * the encoded public key itself, no matter if the selection bits include + * OSSL_KEYMGMT_SELECT_PARAMETERS or not. However, if the selection includes + * OSSL_KEYMGMT_SELECT_PRIVATE_KEY, the same encoder will simply refuse to + * cooperate, because it cannot output the private key. + * + * EVP_PKEY_##selection_name are convenience macros that combine "typical" + * OSSL_KEYMGMT_SELECT_ macros for a certain type of EVP_PKEY content. + */ +#define MAKE_BLOB_ENCODER(impl, type, selection_name) \ + static OSSL_FUNC_encoder_import_object_fn \ + impl##2blob_import_object; \ + static OSSL_FUNC_encoder_free_object_fn impl##2blob_free_object; \ + static OSSL_FUNC_encoder_does_selection_fn \ + impl##2blob_does_selection; \ + static OSSL_FUNC_encoder_encode_fn impl##2blob_encode; \ + \ + static void *impl##2blob_import_object(void *ctx, int selection, \ + const OSSL_PARAM params[]) \ + { \ + return ossl_prov_import_key(ossl_##impl##_keymgmt_functions, \ + ctx, selection, params); \ + } \ + static void impl##2blob_free_object(void *key) \ + { \ + ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key); \ + } \ + static int impl##2blob_does_selection(void *ctx, int selection) \ + { \ + return key2blob_check_selection(selection, \ + EVP_PKEY_##selection_name); \ + } \ + static int impl##2blob_encode(void *vctx, OSSL_CORE_BIO *cout, \ + const void *key, \ + const OSSL_PARAM key_abstract[], \ + int selection, \ + OSSL_PASSPHRASE_CALLBACK *cb, \ + void *cbarg) \ + { \ + /* We don't deal with abstract objects */ \ + if (key_abstract != NULL) { \ + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); \ + return 0; \ + } \ + return key2blob_encode(vctx, key, selection, cout); \ + } \ + const OSSL_DISPATCH ossl_##impl##_to_blob_encoder_functions[] = { \ + { OSSL_FUNC_ENCODER_NEWCTX, \ + (void (*)(void))key2blob_newctx }, \ + { OSSL_FUNC_ENCODER_FREECTX, \ + (void (*)(void))key2blob_freectx }, \ + { OSSL_FUNC_ENCODER_DOES_SELECTION, \ + (void (*)(void))impl##2blob_does_selection }, \ + { OSSL_FUNC_ENCODER_IMPORT_OBJECT, \ + (void (*)(void))impl##2blob_import_object }, \ + { OSSL_FUNC_ENCODER_FREE_OBJECT, \ + (void (*)(void))impl##2blob_free_object }, \ + { OSSL_FUNC_ENCODER_ENCODE, \ + (void (*)(void))impl##2blob_encode }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_EC +MAKE_BLOB_ENCODER(ec, ec, PUBLIC_KEY); +# ifndef OPENSSL_NO_SM2 +MAKE_BLOB_ENCODER(sm2, ec, PUBLIC_KEY); +# endif +#endif diff --git a/providers/implementations/encode_decode/encode_key2ms.c b/providers/implementations/encode_decode/encode_key2ms.c new file mode 100644 index 000000000000..fe8c2dce4316 --- /dev/null +++ b/providers/implementations/encode_decode/encode_key2ms.c @@ -0,0 +1,234 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Low level APIs are deprecated for public use, but still ok for internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> +#include <openssl/core.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/pem.h> /* Functions for writing MSBLOB and PVK */ +#include <openssl/dsa.h> +#include "internal/passphrase.h" +#include "crypto/rsa.h" +#include "prov/implementations.h" +#include "prov/bio.h" +#include "prov/provider_ctx.h" +#include "endecoder_local.h" + +struct key2ms_ctx_st { + PROV_CTX *provctx; + + int pvk_encr_level; + + struct ossl_passphrase_data_st pwdata; +}; + +static int write_msblob(struct key2ms_ctx_st *ctx, OSSL_CORE_BIO *cout, + EVP_PKEY *pkey, int ispub) +{ + BIO *out = ossl_bio_new_from_core_bio(ctx->provctx, cout); + int ret; + + if (out == NULL) + return 0; + ret = ispub ? i2b_PublicKey_bio(out, pkey) : i2b_PrivateKey_bio(out, pkey); + + BIO_free(out); + return ret; +} + +static int write_pvk(struct key2ms_ctx_st *ctx, OSSL_CORE_BIO *cout, + EVP_PKEY *pkey) +{ + BIO *out = NULL; + int ret; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + + out = ossl_bio_new_from_core_bio(ctx->provctx, cout); + if (out == NULL) + return 0; + ret = i2b_PVK_bio_ex(out, pkey, ctx->pvk_encr_level, + ossl_pw_pvk_password, &ctx->pwdata, libctx, NULL); + BIO_free(out); + return ret; +} + +static OSSL_FUNC_encoder_freectx_fn key2ms_freectx; +static OSSL_FUNC_encoder_does_selection_fn key2ms_does_selection; + +static struct key2ms_ctx_st *key2ms_newctx(void *provctx) +{ + struct key2ms_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + /* This is the strongest encryption level */ + ctx->pvk_encr_level = 2; + } + return ctx; +} + +static void key2ms_freectx(void *vctx) +{ + struct key2ms_ctx_st *ctx = vctx; + + ossl_pw_clear_passphrase_data(&ctx->pwdata); + OPENSSL_free(ctx); +} + +static const OSSL_PARAM *key2pvk_settable_ctx_params(ossl_unused void *provctx) +{ + static const OSSL_PARAM settables[] = { + OSSL_PARAM_int(OSSL_ENCODER_PARAM_ENCRYPT_LEVEL, NULL), + OSSL_PARAM_END, + }; + + return settables; +} + +static int key2pvk_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct key2ms_ctx_st *ctx = vctx; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_ENCRYPT_LEVEL); + if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->pvk_encr_level)) + return 0; + return 1; +} + +static int key2ms_does_selection(void *vctx, int selection) +{ + return (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0; +} + +/* + * The real EVP_PKEY_set1_TYPE() functions take a non-const key, while the key + * pointer in the encode function is a const pointer. We violate the constness + * knowingly, since we know that the key comes from the same provider, is never + * actually const, and the implied reference count change is safe. + * + * EVP_PKEY_assign() can't be used, because there's no way to clear the internal + * key using that function without freeing the existing internal key. + */ +typedef int evp_pkey_set1_fn(EVP_PKEY *, const void *key); + +static int key2msblob_encode(void *vctx, const void *key, int selection, + OSSL_CORE_BIO *cout, evp_pkey_set1_fn *set1_key, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct key2ms_ctx_st *ctx = vctx; + int ispub = -1; + EVP_PKEY *pkey = NULL; + int ok = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ispub = 0; + else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ispub = 1; + else + return 0; /* Error */ + + if ((pkey = EVP_PKEY_new()) != NULL && set1_key(pkey, key)) + ok = write_msblob(ctx, cout, pkey, ispub); + EVP_PKEY_free(pkey); + return ok; +} + +static int key2pvk_encode(void *vctx, const void *key, int selection, + OSSL_CORE_BIO *cout, evp_pkey_set1_fn *set1_key, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct key2ms_ctx_st *ctx = vctx; + EVP_PKEY *pkey = NULL; + int ok = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) == 0) + return 0; /* Error */ + + if ((pkey = EVP_PKEY_new()) != NULL && set1_key(pkey, key) + && (pw_cb == NULL + || ossl_pw_set_ossl_passphrase_cb(&ctx->pwdata, pw_cb, pw_cbarg))) + ok = write_pvk(ctx, cout, pkey); + EVP_PKEY_free(pkey); + return ok; +} + +#define dsa_set1 (evp_pkey_set1_fn *)EVP_PKEY_set1_DSA +#define rsa_set1 (evp_pkey_set1_fn *)EVP_PKEY_set1_RSA + +#define msblob_set_params +#define pvk_set_params \ + { OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))key2pvk_settable_ctx_params }, \ + { OSSL_FUNC_ENCODER_SET_CTX_PARAMS, \ + (void (*)(void))key2pvk_set_ctx_params }, + +#define MAKE_MS_ENCODER(impl, output, type) \ + static OSSL_FUNC_encoder_import_object_fn \ + impl##2##output##_import_object; \ + static OSSL_FUNC_encoder_free_object_fn impl##2##output##_free_object; \ + static OSSL_FUNC_encoder_encode_fn impl##2##output##_encode; \ + \ + static void * \ + impl##2##output##_import_object(void *ctx, int selection, \ + const OSSL_PARAM params[]) \ + { \ + return ossl_prov_import_key(ossl_##impl##_keymgmt_functions, \ + ctx, selection, params); \ + } \ + static void impl##2##output##_free_object(void *key) \ + { \ + ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key); \ + } \ + static int impl##2##output##_encode(void *vctx, OSSL_CORE_BIO *cout, \ + const void *key, \ + const OSSL_PARAM key_abstract[], \ + int selection, \ + OSSL_PASSPHRASE_CALLBACK *cb, \ + void *cbarg) \ + { \ + /* We don't deal with abstract objects */ \ + if (key_abstract != NULL) { \ + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); \ + return 0; \ + } \ + return key2##output##_encode(vctx, key, selection, cout, type##_set1, \ + cb, cbarg); \ + } \ + const OSSL_DISPATCH ossl_##impl##_to_##output##_encoder_functions[] = { \ + { OSSL_FUNC_ENCODER_NEWCTX, \ + (void (*)(void))key2ms_newctx }, \ + { OSSL_FUNC_ENCODER_FREECTX, \ + (void (*)(void))key2ms_freectx }, \ + output##_set_params \ + { OSSL_FUNC_ENCODER_DOES_SELECTION, \ + (void (*)(void))key2ms_does_selection }, \ + { OSSL_FUNC_ENCODER_IMPORT_OBJECT, \ + (void (*)(void))impl##2##output##_import_object }, \ + { OSSL_FUNC_ENCODER_FREE_OBJECT, \ + (void (*)(void))impl##2##output##_free_object }, \ + { OSSL_FUNC_ENCODER_ENCODE, \ + (void (*)(void))impl##2##output##_encode }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_DSA +MAKE_MS_ENCODER(dsa, pvk, dsa); +MAKE_MS_ENCODER(dsa, msblob, dsa); +#endif + +MAKE_MS_ENCODER(rsa, pvk, rsa); +MAKE_MS_ENCODER(rsa, msblob, rsa); diff --git a/providers/implementations/encode_decode/encode_key2text.c b/providers/implementations/encode_decode/encode_key2text.c new file mode 100644 index 000000000000..7d983f5e51c6 --- /dev/null +++ b/providers/implementations/encode_decode/encode_key2text.c @@ -0,0 +1,889 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Low level APIs are deprecated for public use, but still ok for internal use. + */ +#include "internal/deprecated.h" + +#include <ctype.h> + +#include <openssl/core.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/safestack.h> +#include <openssl/proverr.h> +#include "internal/ffc.h" +#include "crypto/bn.h" /* bn_get_words() */ +#include "crypto/dh.h" /* ossl_dh_get0_params() */ +#include "crypto/dsa.h" /* ossl_dsa_get0_params() */ +#include "crypto/ec.h" /* ossl_ec_key_get_libctx */ +#include "crypto/ecx.h" /* ECX_KEY, etc... */ +#include "crypto/rsa.h" /* RSA_PSS_PARAMS_30, etc... */ +#include "prov/bio.h" +#include "prov/implementations.h" +#include "endecoder_local.h" + +DEFINE_SPECIAL_STACK_OF_CONST(BIGNUM_const, BIGNUM) + +# ifdef SIXTY_FOUR_BIT_LONG +# define BN_FMTu "%lu" +# define BN_FMTx "%lx" +# endif + +# ifdef SIXTY_FOUR_BIT +# define BN_FMTu "%llu" +# define BN_FMTx "%llx" +# endif + +# ifdef THIRTY_TWO_BIT +# define BN_FMTu "%u" +# define BN_FMTx "%x" +# endif + +static int print_labeled_bignum(BIO *out, const char *label, const BIGNUM *bn) +{ + int ret = 0, use_sep = 0; + char *hex_str = NULL, *p; + const char spaces[] = " "; + const char *post_label_spc = " "; + + const char *neg = ""; + int bytes; + + if (bn == NULL) + return 0; + if (label == NULL) { + label = ""; + post_label_spc = ""; + } + + if (BN_is_zero(bn)) + return BIO_printf(out, "%s%s0\n", label, post_label_spc); + + if (BN_num_bytes(bn) <= BN_BYTES) { + BN_ULONG *words = bn_get_words(bn); + + if (BN_is_negative(bn)) + neg = "-"; + + return BIO_printf(out, "%s%s%s" BN_FMTu " (%s0x" BN_FMTx ")\n", + label, post_label_spc, neg, words[0], neg, words[0]); + } + + hex_str = BN_bn2hex(bn); + if (hex_str == NULL) + return 0; + + p = hex_str; + if (*p == '-') { + ++p; + neg = " (Negative)"; + } + if (BIO_printf(out, "%s%s\n", label, neg) <= 0) + goto err; + + /* Keep track of how many bytes we have printed out so far */ + bytes = 0; + + if (BIO_printf(out, "%s", spaces) <= 0) + goto err; + + /* Add a leading 00 if the top bit is set */ + if (*p >= '8') { + if (BIO_printf(out, "%02x", 0) <= 0) + goto err; + ++bytes; + use_sep = 1; + } + while (*p != '\0') { + /* Do a newline after every 15 hex bytes + add the space indent */ + if ((bytes % 15) == 0 && bytes > 0) { + if (BIO_printf(out, ":\n%s", spaces) <= 0) + goto err; + use_sep = 0; /* The first byte on the next line doesnt have a : */ + } + if (BIO_printf(out, "%s%c%c", use_sep ? ":" : "", + tolower(p[0]), tolower(p[1])) <= 0) + goto err; + ++bytes; + p += 2; + use_sep = 1; + } + if (BIO_printf(out, "\n") <= 0) + goto err; + ret = 1; +err: + OPENSSL_free(hex_str); + return ret; +} + +/* Number of octets per line */ +#define LABELED_BUF_PRINT_WIDTH 15 + +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_EC) +static int print_labeled_buf(BIO *out, const char *label, + const unsigned char *buf, size_t buflen) +{ + size_t i; + + if (BIO_printf(out, "%s\n", label) <= 0) + return 0; + + for (i = 0; i < buflen; i++) { + if ((i % LABELED_BUF_PRINT_WIDTH) == 0) { + if (i > 0 && BIO_printf(out, "\n") <= 0) + return 0; + if (BIO_printf(out, " ") <= 0) + return 0; + } + + if (BIO_printf(out, "%02x%s", buf[i], + (i == buflen - 1) ? "" : ":") <= 0) + return 0; + } + if (BIO_printf(out, "\n") <= 0) + return 0; + + return 1; +} +#endif + +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_DSA) +static int ffc_params_to_text(BIO *out, const FFC_PARAMS *ffc) +{ + if (ffc->nid != NID_undef) { +#ifndef OPENSSL_NO_DH + const DH_NAMED_GROUP *group = ossl_ffc_uid_to_dh_named_group(ffc->nid); + const char *name = ossl_ffc_named_group_get_name(group); + + if (name == NULL) + goto err; + if (BIO_printf(out, "GROUP: %s\n", name) <= 0) + goto err; + return 1; +#else + /* How could this be? We should not have a nid in a no-dh build. */ + goto err; +#endif + } + + if (!print_labeled_bignum(out, "P: ", ffc->p)) + goto err; + if (ffc->q != NULL) { + if (!print_labeled_bignum(out, "Q: ", ffc->q)) + goto err; + } + if (!print_labeled_bignum(out, "G: ", ffc->g)) + goto err; + if (ffc->j != NULL) { + if (!print_labeled_bignum(out, "J: ", ffc->j)) + goto err; + } + if (ffc->seed != NULL) { + if (!print_labeled_buf(out, "SEED:", ffc->seed, ffc->seedlen)) + goto err; + } + if (ffc->gindex != -1) { + if (BIO_printf(out, "gindex: %d\n", ffc->gindex) <= 0) + goto err; + } + if (ffc->pcounter != -1) { + if (BIO_printf(out, "pcounter: %d\n", ffc->pcounter) <= 0) + goto err; + } + if (ffc->h != 0) { + if (BIO_printf(out, "h: %d\n", ffc->h) <= 0) + goto err; + } + return 1; +err: + return 0; +} +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DH +static int dh_to_text(BIO *out, const void *key, int selection) +{ + const DH *dh = key; + const char *type_label = NULL; + const BIGNUM *priv_key = NULL, *pub_key = NULL; + const FFC_PARAMS *params = NULL; + const BIGNUM *p = NULL; + long length; + + if (out == NULL || dh == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + type_label = "DH Private-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + type_label = "DH Public-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + type_label = "DH Parameters"; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + priv_key = DH_get0_priv_key(dh); + if (priv_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } + } + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + pub_key = DH_get0_pub_key(dh); + if (pub_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + } + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + params = ossl_dh_get0_params((DH *)dh); + if (params == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_PARAMETERS); + return 0; + } + } + + p = DH_get0_p(dh); + if (p == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + + if (BIO_printf(out, "%s: (%d bit)\n", type_label, BN_num_bits(p)) <= 0) + return 0; + if (priv_key != NULL + && !print_labeled_bignum(out, "private-key:", priv_key)) + return 0; + if (pub_key != NULL + && !print_labeled_bignum(out, "public-key:", pub_key)) + return 0; + if (params != NULL + && !ffc_params_to_text(out, params)) + return 0; + length = DH_get_length(dh); + if (length > 0 + && BIO_printf(out, "recommended-private-length: %ld bits\n", + length) <= 0) + return 0; + + return 1; +} + +# define dh_input_type "DH" +# define dhx_input_type "DHX" +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_DSA +static int dsa_to_text(BIO *out, const void *key, int selection) +{ + const DSA *dsa = key; + const char *type_label = NULL; + const BIGNUM *priv_key = NULL, *pub_key = NULL; + const FFC_PARAMS *params = NULL; + const BIGNUM *p = NULL; + + if (out == NULL || dsa == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + type_label = "Private-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + type_label = "Public-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + type_label = "DSA-Parameters"; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + priv_key = DSA_get0_priv_key(dsa); + if (priv_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } + } + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + pub_key = DSA_get0_pub_key(dsa); + if (pub_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + } + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + params = ossl_dsa_get0_params((DSA *)dsa); + if (params == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_PARAMETERS); + return 0; + } + } + + p = DSA_get0_p(dsa); + if (p == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + + if (BIO_printf(out, "%s: (%d bit)\n", type_label, BN_num_bits(p)) <= 0) + return 0; + if (priv_key != NULL + && !print_labeled_bignum(out, "priv:", priv_key)) + return 0; + if (pub_key != NULL + && !print_labeled_bignum(out, "pub: ", pub_key)) + return 0; + if (params != NULL + && !ffc_params_to_text(out, params)) + return 0; + + return 1; +} + +# define dsa_input_type "DSA" +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_EC +static int ec_param_explicit_curve_to_text(BIO *out, const EC_GROUP *group, + BN_CTX *ctx) +{ + const char *plabel = "Prime:"; + BIGNUM *p = NULL, *a = NULL, *b = NULL; + + p = BN_CTX_get(ctx); + a = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + if (b == NULL + || !EC_GROUP_get_curve(group, p, a, b, ctx)) + return 0; + + if (EC_GROUP_get_field_type(group) == NID_X9_62_characteristic_two_field) { + int basis_type = EC_GROUP_get_basis_type(group); + + /* print the 'short name' of the base type OID */ + if (basis_type == NID_undef + || BIO_printf(out, "Basis Type: %s\n", OBJ_nid2sn(basis_type)) <= 0) + return 0; + plabel = "Polynomial:"; + } + return print_labeled_bignum(out, plabel, p) + && print_labeled_bignum(out, "A: ", a) + && print_labeled_bignum(out, "B: ", b); +} + +static int ec_param_explicit_gen_to_text(BIO *out, const EC_GROUP *group, + BN_CTX *ctx) +{ + int ret; + size_t buflen; + point_conversion_form_t form; + const EC_POINT *point = NULL; + const char *glabel = NULL; + unsigned char *buf = NULL; + + form = EC_GROUP_get_point_conversion_form(group); + point = EC_GROUP_get0_generator(group); + + if (point == NULL) + return 0; + + switch (form) { + case POINT_CONVERSION_COMPRESSED: + glabel = "Generator (compressed):"; + break; + case POINT_CONVERSION_UNCOMPRESSED: + glabel = "Generator (uncompressed):"; + break; + case POINT_CONVERSION_HYBRID: + glabel = "Generator (hybrid):"; + break; + default: + return 0; + } + + buflen = EC_POINT_point2buf(group, point, form, &buf, ctx); + if (buflen == 0) + return 0; + + ret = print_labeled_buf(out, glabel, buf, buflen); + OPENSSL_clear_free(buf, buflen); + return ret; +} + +/* Print explicit parameters */ +static int ec_param_explicit_to_text(BIO *out, const EC_GROUP *group, + OSSL_LIB_CTX *libctx) +{ + int ret = 0, tmp_nid; + BN_CTX *ctx = NULL; + const BIGNUM *order = NULL, *cofactor = NULL; + const unsigned char *seed; + size_t seed_len = 0; + + ctx = BN_CTX_new_ex(libctx); + if (ctx == NULL) + return 0; + BN_CTX_start(ctx); + + tmp_nid = EC_GROUP_get_field_type(group); + order = EC_GROUP_get0_order(group); + if (order == NULL) + goto err; + + seed = EC_GROUP_get0_seed(group); + if (seed != NULL) + seed_len = EC_GROUP_get_seed_len(group); + cofactor = EC_GROUP_get0_cofactor(group); + + /* print the 'short name' of the field type */ + if (BIO_printf(out, "Field Type: %s\n", OBJ_nid2sn(tmp_nid)) <= 0 + || !ec_param_explicit_curve_to_text(out, group, ctx) + || !ec_param_explicit_gen_to_text(out, group, ctx) + || !print_labeled_bignum(out, "Order: ", order) + || (cofactor != NULL + && !print_labeled_bignum(out, "Cofactor: ", cofactor)) + || (seed != NULL + && !print_labeled_buf(out, "Seed:", seed, seed_len))) + goto err; + ret = 1; +err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ret; +} + +static int ec_param_to_text(BIO *out, const EC_GROUP *group, + OSSL_LIB_CTX *libctx) +{ + if (EC_GROUP_get_asn1_flag(group) & OPENSSL_EC_NAMED_CURVE) { + const char *curve_name; + int curve_nid = EC_GROUP_get_curve_name(group); + + /* Explicit parameters */ + if (curve_nid == NID_undef) + return 0; + + if (BIO_printf(out, "%s: %s\n", "ASN1 OID", OBJ_nid2sn(curve_nid)) <= 0) + return 0; + + curve_name = EC_curve_nid2nist(curve_nid); + return (curve_name == NULL + || BIO_printf(out, "%s: %s\n", "NIST CURVE", curve_name) > 0); + } else { + return ec_param_explicit_to_text(out, group, libctx); + } +} + +static int ec_to_text(BIO *out, const void *key, int selection) +{ + const EC_KEY *ec = key; + const char *type_label = NULL; + unsigned char *priv = NULL, *pub = NULL; + size_t priv_len = 0, pub_len = 0; + const EC_GROUP *group; + int ret = 0; + + if (out == NULL || ec == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((group = EC_KEY_get0_group(ec)) == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + type_label = "Private-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + type_label = "Public-Key"; + else if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + type_label = "EC-Parameters"; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + const BIGNUM *priv_key = EC_KEY_get0_private_key(ec); + + if (priv_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + goto err; + } + priv_len = EC_KEY_priv2buf(ec, &priv); + if (priv_len == 0) + goto err; + } + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + const EC_POINT *pub_pt = EC_KEY_get0_public_key(ec); + + if (pub_pt == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + goto err; + } + + pub_len = EC_KEY_key2buf(ec, EC_KEY_get_conv_form(ec), &pub, NULL); + if (pub_len == 0) + goto err; + } + + if (BIO_printf(out, "%s: (%d bit)\n", type_label, + EC_GROUP_order_bits(group)) <= 0) + goto err; + if (priv != NULL + && !print_labeled_buf(out, "priv:", priv, priv_len)) + goto err; + if (pub != NULL + && !print_labeled_buf(out, "pub:", pub, pub_len)) + goto err; + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + ret = ec_param_to_text(out, group, ossl_ec_key_get_libctx(ec)); +err: + OPENSSL_clear_free(priv, priv_len); + OPENSSL_free(pub); + return ret; +} + +# define ec_input_type "EC" + +# ifndef OPENSSL_NO_SM2 +# define sm2_input_type "SM2" +# endif +#endif + +/* ---------------------------------------------------------------------- */ + +#ifndef OPENSSL_NO_EC +static int ecx_to_text(BIO *out, const void *key, int selection) +{ + const ECX_KEY *ecx = key; + const char *type_label = NULL; + + if (out == NULL || ecx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + if (ecx->privkey == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } + + switch (ecx->type) { + case ECX_KEY_TYPE_X25519: + type_label = "X25519 Private-Key"; + break; + case ECX_KEY_TYPE_X448: + type_label = "X448 Private-Key"; + break; + case ECX_KEY_TYPE_ED25519: + type_label = "ED25519 Private-Key"; + break; + case ECX_KEY_TYPE_ED448: + type_label = "ED448 Private-Key"; + break; + } + } else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + /* ecx->pubkey is an array, not a pointer... */ + if (!ecx->haspubkey) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + + switch (ecx->type) { + case ECX_KEY_TYPE_X25519: + type_label = "X25519 Public-Key"; + break; + case ECX_KEY_TYPE_X448: + type_label = "X448 Public-Key"; + break; + case ECX_KEY_TYPE_ED25519: + type_label = "ED25519 Public-Key"; + break; + case ECX_KEY_TYPE_ED448: + type_label = "ED448 Public-Key"; + break; + } + } + + if (BIO_printf(out, "%s:\n", type_label) <= 0) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0 + && !print_labeled_buf(out, "priv:", ecx->privkey, ecx->keylen)) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0 + && !print_labeled_buf(out, "pub:", ecx->pubkey, ecx->keylen)) + return 0; + + return 1; +} + +# define ed25519_input_type "ED25519" +# define ed448_input_type "ED448" +# define x25519_input_type "X25519" +# define x448_input_type "X448" +#endif + +/* ---------------------------------------------------------------------- */ + +static int rsa_to_text(BIO *out, const void *key, int selection) +{ + const RSA *rsa = key; + const char *type_label = "RSA key"; + const char *modulus_label = NULL; + const char *exponent_label = NULL; + const BIGNUM *rsa_d = NULL, *rsa_n = NULL, *rsa_e = NULL; + STACK_OF(BIGNUM_const) *factors = NULL; + STACK_OF(BIGNUM_const) *exps = NULL; + STACK_OF(BIGNUM_const) *coeffs = NULL; + int primes; + const RSA_PSS_PARAMS_30 *pss_params = ossl_rsa_get0_pss_params_30((RSA *)rsa); + int ret = 0; + + if (out == NULL || rsa == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + + factors = sk_BIGNUM_const_new_null(); + exps = sk_BIGNUM_const_new_null(); + coeffs = sk_BIGNUM_const_new_null(); + + if (factors == NULL || exps == NULL || coeffs == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + type_label = "Private-Key"; + modulus_label = "modulus:"; + exponent_label = "publicExponent:"; + } else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + type_label = "Public-Key"; + modulus_label = "Modulus:"; + exponent_label = "Exponent:"; + } + + RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d); + ossl_rsa_get0_all_params((RSA *)rsa, factors, exps, coeffs); + primes = sk_BIGNUM_const_num(factors); + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + if (BIO_printf(out, "%s: (%d bit, %d primes)\n", + type_label, BN_num_bits(rsa_n), primes) <= 0) + goto err; + } else { + if (BIO_printf(out, "%s: (%d bit)\n", + type_label, BN_num_bits(rsa_n)) <= 0) + goto err; + } + + if (!print_labeled_bignum(out, modulus_label, rsa_n)) + goto err; + if (!print_labeled_bignum(out, exponent_label, rsa_e)) + goto err; + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + int i; + + if (!print_labeled_bignum(out, "privateExponent:", rsa_d)) + goto err; + if (!print_labeled_bignum(out, "prime1:", + sk_BIGNUM_const_value(factors, 0))) + goto err; + if (!print_labeled_bignum(out, "prime2:", + sk_BIGNUM_const_value(factors, 1))) + goto err; + if (!print_labeled_bignum(out, "exponent1:", + sk_BIGNUM_const_value(exps, 0))) + goto err; + if (!print_labeled_bignum(out, "exponent2:", + sk_BIGNUM_const_value(exps, 1))) + goto err; + if (!print_labeled_bignum(out, "coefficient:", + sk_BIGNUM_const_value(coeffs, 0))) + goto err; + for (i = 2; i < sk_BIGNUM_const_num(factors); i++) { + if (BIO_printf(out, "prime%d:", i + 1) <= 0) + goto err; + if (!print_labeled_bignum(out, NULL, + sk_BIGNUM_const_value(factors, i))) + goto err; + if (BIO_printf(out, "exponent%d:", i + 1) <= 0) + goto err; + if (!print_labeled_bignum(out, NULL, + sk_BIGNUM_const_value(exps, i))) + goto err; + if (BIO_printf(out, "coefficient%d:", i + 1) <= 0) + goto err; + if (!print_labeled_bignum(out, NULL, + sk_BIGNUM_const_value(coeffs, i - 1))) + goto err; + } + } + + if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0) { + switch (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK)) { + case RSA_FLAG_TYPE_RSA: + if (!ossl_rsa_pss_params_30_is_unrestricted(pss_params)) { + if (BIO_printf(out, "(INVALID PSS PARAMETERS)\n") <= 0) + goto err; + } + break; + case RSA_FLAG_TYPE_RSASSAPSS: + if (ossl_rsa_pss_params_30_is_unrestricted(pss_params)) { + if (BIO_printf(out, "No PSS parameter restrictions\n") <= 0) + goto err; + } else { + int hashalg_nid = ossl_rsa_pss_params_30_hashalg(pss_params); + int maskgenalg_nid = + ossl_rsa_pss_params_30_maskgenalg(pss_params); + int maskgenhashalg_nid = + ossl_rsa_pss_params_30_maskgenhashalg(pss_params); + int saltlen = ossl_rsa_pss_params_30_saltlen(pss_params); + int trailerfield = + ossl_rsa_pss_params_30_trailerfield(pss_params); + + if (BIO_printf(out, "PSS parameter restrictions:\n") <= 0) + goto err; + if (BIO_printf(out, " Hash Algorithm: %s%s\n", + ossl_rsa_oaeppss_nid2name(hashalg_nid), + (hashalg_nid == NID_sha1 + ? " (default)" : "")) <= 0) + goto err; + if (BIO_printf(out, " Mask Algorithm: %s with %s%s\n", + ossl_rsa_mgf_nid2name(maskgenalg_nid), + ossl_rsa_oaeppss_nid2name(maskgenhashalg_nid), + (maskgenalg_nid == NID_mgf1 + && maskgenhashalg_nid == NID_sha1 + ? " (default)" : "")) <= 0) + goto err; + if (BIO_printf(out, " Minimum Salt Length: %d%s\n", + saltlen, + (saltlen == 20 ? " (default)" : "")) <= 0) + goto err; + if (BIO_printf(out, " Trailer Field: 0x%x%s\n", + trailerfield, + (trailerfield == 1 ? " (default)" : "")) <= 0) + goto err; + } + break; + } + } + + ret = 1; + err: + sk_BIGNUM_const_free(factors); + sk_BIGNUM_const_free(exps); + sk_BIGNUM_const_free(coeffs); + return ret; +} + +#define rsa_input_type "RSA" +#define rsapss_input_type "RSA-PSS" + +/* ---------------------------------------------------------------------- */ + +static void *key2text_newctx(void *provctx) +{ + return provctx; +} + +static void key2text_freectx(ossl_unused void *vctx) +{ +} + +static int key2text_encode(void *vctx, const void *key, int selection, + OSSL_CORE_BIO *cout, + int (*key2text)(BIO *out, const void *key, + int selection), + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + BIO *out = ossl_bio_new_from_core_bio(vctx, cout); + int ret; + + if (out == NULL) + return 0; + + ret = key2text(out, key, selection); + BIO_free(out); + + return ret; +} + +#define MAKE_TEXT_ENCODER(impl, type) \ + static OSSL_FUNC_encoder_import_object_fn \ + impl##2text_import_object; \ + static OSSL_FUNC_encoder_free_object_fn \ + impl##2text_free_object; \ + static OSSL_FUNC_encoder_encode_fn impl##2text_encode; \ + \ + static void *impl##2text_import_object(void *ctx, int selection, \ + const OSSL_PARAM params[]) \ + { \ + return ossl_prov_import_key(ossl_##impl##_keymgmt_functions, \ + ctx, selection, params); \ + } \ + static void impl##2text_free_object(void *key) \ + { \ + ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key); \ + } \ + static int impl##2text_encode(void *vctx, OSSL_CORE_BIO *cout, \ + const void *key, \ + const OSSL_PARAM key_abstract[], \ + int selection, \ + OSSL_PASSPHRASE_CALLBACK *cb, \ + void *cbarg) \ + { \ + /* We don't deal with abstract objects */ \ + if (key_abstract != NULL) { \ + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); \ + return 0; \ + } \ + return key2text_encode(vctx, key, selection, cout, \ + type##_to_text, cb, cbarg); \ + } \ + const OSSL_DISPATCH ossl_##impl##_to_text_encoder_functions[] = { \ + { OSSL_FUNC_ENCODER_NEWCTX, \ + (void (*)(void))key2text_newctx }, \ + { OSSL_FUNC_ENCODER_FREECTX, \ + (void (*)(void))key2text_freectx }, \ + { OSSL_FUNC_ENCODER_IMPORT_OBJECT, \ + (void (*)(void))impl##2text_import_object }, \ + { OSSL_FUNC_ENCODER_FREE_OBJECT, \ + (void (*)(void))impl##2text_free_object }, \ + { OSSL_FUNC_ENCODER_ENCODE, \ + (void (*)(void))impl##2text_encode }, \ + { 0, NULL } \ + } + +#ifndef OPENSSL_NO_DH +MAKE_TEXT_ENCODER(dh, dh); +MAKE_TEXT_ENCODER(dhx, dh); +#endif +#ifndef OPENSSL_NO_DSA +MAKE_TEXT_ENCODER(dsa, dsa); +#endif +#ifndef OPENSSL_NO_EC +MAKE_TEXT_ENCODER(ec, ec); +# ifndef OPENSSL_NO_SM2 +MAKE_TEXT_ENCODER(sm2, ec); +# endif +MAKE_TEXT_ENCODER(ed25519, ecx); +MAKE_TEXT_ENCODER(ed448, ecx); +MAKE_TEXT_ENCODER(x25519, ecx); +MAKE_TEXT_ENCODER(x448, ecx); +#endif +MAKE_TEXT_ENCODER(rsa, rsa); +MAKE_TEXT_ENCODER(rsapss, rsa); diff --git a/providers/implementations/encode_decode/endecoder_common.c b/providers/implementations/encode_decode/endecoder_common.c new file mode 100644 index 000000000000..c4ea2f853cfc --- /dev/null +++ b/providers/implementations/encode_decode/endecoder_common.c @@ -0,0 +1,104 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/core.h> +#include <openssl/buffer.h> +#include "internal/asn1.h" +#include "prov/bio.h" +#include "endecoder_local.h" + +OSSL_FUNC_keymgmt_new_fn * +ossl_prov_get_keymgmt_new(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_NEW) + return OSSL_FUNC_keymgmt_new(fns); + + return NULL; +} + +OSSL_FUNC_keymgmt_free_fn * +ossl_prov_get_keymgmt_free(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_FREE) + return OSSL_FUNC_keymgmt_free(fns); + + return NULL; +} + +OSSL_FUNC_keymgmt_import_fn * +ossl_prov_get_keymgmt_import(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_IMPORT) + return OSSL_FUNC_keymgmt_import(fns); + + return NULL; +} + +OSSL_FUNC_keymgmt_export_fn * +ossl_prov_get_keymgmt_export(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_EXPORT) + return OSSL_FUNC_keymgmt_export(fns); + + return NULL; +} + +void *ossl_prov_import_key(const OSSL_DISPATCH *fns, void *provctx, + int selection, const OSSL_PARAM params[]) +{ + OSSL_FUNC_keymgmt_new_fn *kmgmt_new = ossl_prov_get_keymgmt_new(fns); + OSSL_FUNC_keymgmt_free_fn *kmgmt_free = ossl_prov_get_keymgmt_free(fns); + OSSL_FUNC_keymgmt_import_fn *kmgmt_import = + ossl_prov_get_keymgmt_import(fns); + void *key = NULL; + + if (kmgmt_new != NULL && kmgmt_import != NULL && kmgmt_free != NULL) { + if ((key = kmgmt_new(provctx)) == NULL + || !kmgmt_import(key, selection, params)) { + kmgmt_free(key); + key = NULL; + } + } + return key; +} + +void ossl_prov_free_key(const OSSL_DISPATCH *fns, void *key) +{ + OSSL_FUNC_keymgmt_free_fn *kmgmt_free = ossl_prov_get_keymgmt_free(fns); + + if (kmgmt_free != NULL) + kmgmt_free(key); +} + +int ossl_read_der(PROV_CTX *provctx, OSSL_CORE_BIO *cin, unsigned char **data, + long *len) +{ + BUF_MEM *mem = NULL; + BIO *in = ossl_bio_new_from_core_bio(provctx, cin); + int ok; + + if (in == NULL) + return 0; + ok = (asn1_d2i_read_bio(in, &mem) >= 0); + if (ok) { + *data = (unsigned char *)mem->data; + *len = (long)mem->length; + OPENSSL_free(mem); + } + BIO_free(in); + return ok; +} diff --git a/providers/implementations/encode_decode/endecoder_local.h b/providers/implementations/encode_decode/endecoder_local.h new file mode 100644 index 000000000000..a65d05ffaeac --- /dev/null +++ b/providers/implementations/encode_decode/endecoder_local.h @@ -0,0 +1,28 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/core.h> +#include <openssl/core_dispatch.h> +#include <openssl/types.h> +#include "prov/provider_ctx.h" + +OSSL_FUNC_keymgmt_new_fn *ossl_prov_get_keymgmt_new(const OSSL_DISPATCH *fns); +OSSL_FUNC_keymgmt_free_fn *ossl_prov_get_keymgmt_free(const OSSL_DISPATCH *fns); +OSSL_FUNC_keymgmt_import_fn *ossl_prov_get_keymgmt_import(const OSSL_DISPATCH *fns); +OSSL_FUNC_keymgmt_export_fn *ossl_prov_get_keymgmt_export(const OSSL_DISPATCH *fns); + +int ossl_prov_der_from_p8(unsigned char **new_der, long *new_der_len, + unsigned char *input_der, long input_der_len, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg); + +void *ossl_prov_import_key(const OSSL_DISPATCH *fns, void *provctx, + int selection, const OSSL_PARAM params[]); +void ossl_prov_free_key(const OSSL_DISPATCH *fns, void *key); +int ossl_read_der(PROV_CTX *provctx, OSSL_CORE_BIO *cin, unsigned char **data, + long *len); diff --git a/providers/implementations/exchange/build.info b/providers/implementations/exchange/build.info new file mode 100644 index 000000000000..3c1e5c58f1e3 --- /dev/null +++ b/providers/implementations/exchange/build.info @@ -0,0 +1,29 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$DH_GOAL=../../libdefault.a ../../libfips.a +$ECDH_GOAL=../../libdefault.a ../../libfips.a +$ECX_GOAL=../../libdefault.a ../../libfips.a +$KDF_GOAL=../../libdefault.a ../../libfips.a + +IF[{- !$disabled{dh} -}] + SOURCE[$DH_GOAL]=dh_exch.c +ENDIF + +IF[{- !$disabled{asm} -}] + $ECDEF_s390x=S390X_EC_ASM + + # Now that we have defined all the arch specific variables, use the + # appropriate one, and define the appropriate macros + IF[$ECASM_{- $target{asm_arch} -}] + $ECDEF=$ECDEF_{- $target{asm_arch} -} + ENDIF +ENDIF + +IF[{- !$disabled{ec} -}] + SOURCE[$ECX_GOAL]=ecx_exch.c + DEFINE[$ECX_GOAL]=$ECDEF + SOURCE[$ECDH_GOAL]=ecdh_exch.c +ENDIF + +SOURCE[$KDF_GOAL]=kdf_exch.c diff --git a/providers/implementations/exchange/dh_exch.c b/providers/implementations/exchange/dh_exch.c new file mode 100644 index 000000000000..1d8a2e27b30e --- /dev/null +++ b/providers/implementations/exchange/dh_exch.c @@ -0,0 +1,512 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/dh.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include <openssl/params.h> +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/securitycheck.h" +#include "crypto/dh.h" + +static OSSL_FUNC_keyexch_newctx_fn dh_newctx; +static OSSL_FUNC_keyexch_init_fn dh_init; +static OSSL_FUNC_keyexch_set_peer_fn dh_set_peer; +static OSSL_FUNC_keyexch_derive_fn dh_derive; +static OSSL_FUNC_keyexch_freectx_fn dh_freectx; +static OSSL_FUNC_keyexch_dupctx_fn dh_dupctx; +static OSSL_FUNC_keyexch_set_ctx_params_fn dh_set_ctx_params; +static OSSL_FUNC_keyexch_settable_ctx_params_fn dh_settable_ctx_params; +static OSSL_FUNC_keyexch_get_ctx_params_fn dh_get_ctx_params; +static OSSL_FUNC_keyexch_gettable_ctx_params_fn dh_gettable_ctx_params; + +/* + * This type is only really used to handle some legacy related functionality. + * If you need to use other KDF's (such as SSKDF) just use PROV_DH_KDF_NONE + * here and then create and run a KDF after the key is derived. + * Note that X942 has 2 variants of key derivation: + * (1) DH_KDF_X9_42_ASN1 - which contains an ANS1 encoded object that has + * the counter embedded in it. + * (2) DH_KDF_X941_CONCAT - which is the same as ECDH_X963_KDF (which can be + * done by creating a "X963KDF". + */ +enum kdf_type { + PROV_DH_KDF_NONE = 0, + PROV_DH_KDF_X9_42_ASN1 +}; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes DH structures, so + * we use that here too. + */ + +typedef struct { + OSSL_LIB_CTX *libctx; + DH *dh; + DH *dhpeer; + unsigned int pad : 1; + + /* DH KDF */ + /* KDF (if any) to use for DH */ + enum kdf_type kdf_type; + /* Message digest to use for key derivation */ + EVP_MD *kdf_md; + /* User key material */ + unsigned char *kdf_ukm; + size_t kdf_ukmlen; + /* KDF output length */ + size_t kdf_outlen; + char *kdf_cekalg; +} PROV_DH_CTX; + +static void *dh_newctx(void *provctx) +{ + PROV_DH_CTX *pdhctx; + + if (!ossl_prov_is_running()) + return NULL; + + pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_CTX)); + if (pdhctx == NULL) + return NULL; + pdhctx->libctx = PROV_LIBCTX_OF(provctx); + pdhctx->kdf_type = PROV_DH_KDF_NONE; + return pdhctx; +} + +static int dh_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[]) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + + if (!ossl_prov_is_running() + || pdhctx == NULL + || vdh == NULL + || !DH_up_ref(vdh)) + return 0; + DH_free(pdhctx->dh); + pdhctx->dh = vdh; + pdhctx->kdf_type = PROV_DH_KDF_NONE; + return dh_set_ctx_params(pdhctx, params) + && ossl_dh_check_key(pdhctx->libctx, vdh); +} + +/* The 2 parties must share the same domain parameters */ +static int dh_match_params(DH *priv, DH *peer) +{ + int ret; + FFC_PARAMS *dhparams_priv = ossl_dh_get0_params(priv); + FFC_PARAMS *dhparams_peer = ossl_dh_get0_params(peer); + + ret = dhparams_priv != NULL + && dhparams_peer != NULL + && ossl_ffc_params_cmp(dhparams_priv, dhparams_peer, 1); + if (!ret) + ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS); + return ret; +} + +static int dh_set_peer(void *vpdhctx, void *vdh) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + + if (!ossl_prov_is_running() + || pdhctx == NULL + || vdh == NULL + || !dh_match_params(vdh, pdhctx->dh) + || !DH_up_ref(vdh)) + return 0; + DH_free(pdhctx->dhpeer); + pdhctx->dhpeer = vdh; + return 1; +} + +static int dh_plain_derive(void *vpdhctx, + unsigned char *secret, size_t *secretlen, + size_t outlen, unsigned int pad) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + int ret; + size_t dhsize; + const BIGNUM *pub_key = NULL; + + if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return 0; + } + + dhsize = (size_t)DH_size(pdhctx->dh); + if (secret == NULL) { + *secretlen = dhsize; + return 1; + } + if (outlen < dhsize) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + DH_get0_key(pdhctx->dhpeer, &pub_key, NULL); + if (pad) + ret = DH_compute_key_padded(secret, pub_key, pdhctx->dh); + else + ret = DH_compute_key(secret, pub_key, pdhctx->dh); + if (ret <= 0) + return 0; + + *secretlen = ret; + return 1; +} + +static int dh_X9_42_kdf_derive(void *vpdhctx, unsigned char *secret, + size_t *secretlen, size_t outlen) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + unsigned char *stmp = NULL; + size_t stmplen; + int ret = 0; + + if (secret == NULL) { + *secretlen = pdhctx->kdf_outlen; + return 1; + } + + if (pdhctx->kdf_outlen > outlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (!dh_plain_derive(pdhctx, NULL, &stmplen, 0, 1)) + return 0; + if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + if (!dh_plain_derive(pdhctx, stmp, &stmplen, stmplen, 1)) + goto err; + + /* Do KDF stuff */ + if (pdhctx->kdf_type == PROV_DH_KDF_X9_42_ASN1) { + if (!ossl_dh_kdf_X9_42_asn1(secret, pdhctx->kdf_outlen, + stmp, stmplen, + pdhctx->kdf_cekalg, + pdhctx->kdf_ukm, + pdhctx->kdf_ukmlen, + pdhctx->kdf_md, + pdhctx->libctx, NULL)) + goto err; + } + *secretlen = pdhctx->kdf_outlen; + ret = 1; +err: + OPENSSL_secure_clear_free(stmp, stmplen); + return ret; +} + +static int dh_derive(void *vpdhctx, unsigned char *secret, + size_t *psecretlen, size_t outlen) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + + if (!ossl_prov_is_running()) + return 0; + + switch (pdhctx->kdf_type) { + case PROV_DH_KDF_NONE: + return dh_plain_derive(pdhctx, secret, psecretlen, outlen, + pdhctx->pad); + case PROV_DH_KDF_X9_42_ASN1: + return dh_X9_42_kdf_derive(pdhctx, secret, psecretlen, outlen); + default: + break; + } + return 0; +} + +static void dh_freectx(void *vpdhctx) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + + OPENSSL_free(pdhctx->kdf_cekalg); + DH_free(pdhctx->dh); + DH_free(pdhctx->dhpeer); + EVP_MD_free(pdhctx->kdf_md); + OPENSSL_clear_free(pdhctx->kdf_ukm, pdhctx->kdf_ukmlen); + + OPENSSL_free(pdhctx); +} + +static void *dh_dupctx(void *vpdhctx) +{ + PROV_DH_CTX *srcctx = (PROV_DH_CTX *)vpdhctx; + PROV_DH_CTX *dstctx; + + if (!ossl_prov_is_running()) + return NULL; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + dstctx->dh = NULL; + dstctx->dhpeer = NULL; + dstctx->kdf_md = NULL; + dstctx->kdf_ukm = NULL; + dstctx->kdf_cekalg = NULL; + + if (srcctx->dh != NULL && !DH_up_ref(srcctx->dh)) + goto err; + else + dstctx->dh = srcctx->dh; + + if (srcctx->dhpeer != NULL && !DH_up_ref(srcctx->dhpeer)) + goto err; + else + dstctx->dhpeer = srcctx->dhpeer; + + if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md)) + goto err; + else + dstctx->kdf_md = srcctx->kdf_md; + + /* Duplicate UKM data if present */ + if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) { + dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm, + srcctx->kdf_ukmlen); + if (dstctx->kdf_ukm == NULL) + goto err; + } + + if (srcctx->kdf_cekalg != NULL) { + dstctx->kdf_cekalg = OPENSSL_strdup(srcctx->kdf_cekalg); + if (dstctx->kdf_cekalg == NULL) + goto err; + } + + return dstctx; +err: + dh_freectx(dstctx); + return NULL; +} + +static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[]) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + const OSSL_PARAM *p; + unsigned int pad; + char name[80] = { '\0' }; /* should be big enough */ + char *str = NULL; + + if (pdhctx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); + if (p != NULL) { + str = name; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) + return 0; + + if (name[0] == '\0') + pdhctx->kdf_type = PROV_DH_KDF_NONE; + else if (strcmp(name, OSSL_KDF_NAME_X942KDF_ASN1) == 0) + pdhctx->kdf_type = PROV_DH_KDF_X9_42_ASN1; + else + return 0; + } + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); + if (p != NULL) { + char mdprops[80] = { '\0' }; /* should be big enough */ + + str = name; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) + return 0; + + str = mdprops; + p = OSSL_PARAM_locate_const(params, + OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS); + + if (p != NULL) { + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) + return 0; + } + + EVP_MD_free(pdhctx->kdf_md); + pdhctx->kdf_md = EVP_MD_fetch(pdhctx->libctx, name, mdprops); + if (!ossl_digest_is_allowed(pdhctx->libctx, pdhctx->kdf_md)) { + EVP_MD_free(pdhctx->kdf_md); + pdhctx->kdf_md = NULL; + } + if (pdhctx->kdf_md == NULL) + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); + if (p != NULL) { + size_t outlen; + + if (!OSSL_PARAM_get_size_t(p, &outlen)) + return 0; + pdhctx->kdf_outlen = outlen; + } + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM); + if (p != NULL) { + void *tmp_ukm = NULL; + size_t tmp_ukmlen; + + OPENSSL_free(pdhctx->kdf_ukm); + pdhctx->kdf_ukm = NULL; + pdhctx->kdf_ukmlen = 0; + /* ukm is an optional field so it can be NULL */ + if (p->data != NULL && p->data_size != 0) { + if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen)) + return 0; + pdhctx->kdf_ukm = tmp_ukm; + pdhctx->kdf_ukmlen = tmp_ukmlen; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_PAD); + if (p != NULL) { + if (!OSSL_PARAM_get_uint(p, &pad)) + return 0; + pdhctx->pad = pad ? 1 : 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CEK_ALG); + if (p != NULL) { + str = name; + + OPENSSL_free(pdhctx->kdf_cekalg); + pdhctx->kdf_cekalg = NULL; + if (p->data != NULL && p->data_size != 0) { + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) + return 0; + pdhctx->kdf_cekalg = OPENSSL_strdup(name); + if (pdhctx->kdf_cekalg == NULL) + return 0; + } + } + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD, NULL), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0), + OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), + OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dh_settable_ctx_params(ossl_unused void *vpdhctx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), + OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), + OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR, + NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dh_gettable_ctx_params(ossl_unused void *vpdhctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int dh_get_ctx_params(void *vpdhctx, OSSL_PARAM params[]) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + OSSL_PARAM *p; + + if (pdhctx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); + if (p != NULL) { + const char *kdf_type = NULL; + + switch (pdhctx->kdf_type) { + case PROV_DH_KDF_NONE: + kdf_type = ""; + break; + case PROV_DH_KDF_X9_42_ASN1: + kdf_type = OSSL_KDF_NAME_X942KDF_ASN1; + break; + default: + return 0; + } + + if (!OSSL_PARAM_set_utf8_string(p, kdf_type)) + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); + if (p != NULL + && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_md == NULL + ? "" + : EVP_MD_get0_name(pdhctx->kdf_md))){ + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, pdhctx->kdf_outlen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM); + if (p != NULL + && !OSSL_PARAM_set_octet_ptr(p, pdhctx->kdf_ukm, pdhctx->kdf_ukmlen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_CEK_ALG); + if (p != NULL + && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_cekalg == NULL + ? "" : pdhctx->kdf_cekalg)) + return 0; + + return 1; +} + +const OSSL_DISPATCH ossl_dh_keyexch_functions[] = { + { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))dh_newctx }, + { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))dh_init }, + { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))dh_derive }, + { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))dh_set_peer }, + { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))dh_freectx }, + { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))dh_dupctx }, + { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))dh_set_ctx_params }, + { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, + (void (*)(void))dh_settable_ctx_params }, + { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))dh_get_ctx_params }, + { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS, + (void (*)(void))dh_gettable_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/exchange/ecdh_exch.c b/providers/implementations/exchange/ecdh_exch.c new file mode 100644 index 000000000000..35d665fb9105 --- /dev/null +++ b/providers/implementations/exchange/ecdh_exch.c @@ -0,0 +1,580 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * ECDH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/evp.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/ec.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/securitycheck.h" +#include "crypto/ec.h" /* ossl_ecdh_kdf_X9_63() */ + +static OSSL_FUNC_keyexch_newctx_fn ecdh_newctx; +static OSSL_FUNC_keyexch_init_fn ecdh_init; +static OSSL_FUNC_keyexch_set_peer_fn ecdh_set_peer; +static OSSL_FUNC_keyexch_derive_fn ecdh_derive; +static OSSL_FUNC_keyexch_freectx_fn ecdh_freectx; +static OSSL_FUNC_keyexch_dupctx_fn ecdh_dupctx; +static OSSL_FUNC_keyexch_set_ctx_params_fn ecdh_set_ctx_params; +static OSSL_FUNC_keyexch_settable_ctx_params_fn ecdh_settable_ctx_params; +static OSSL_FUNC_keyexch_get_ctx_params_fn ecdh_get_ctx_params; +static OSSL_FUNC_keyexch_gettable_ctx_params_fn ecdh_gettable_ctx_params; + +enum kdf_type { + PROV_ECDH_KDF_NONE = 0, + PROV_ECDH_KDF_X9_63 +}; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes EC_KEY structures, so + * we use that here too. + */ + +typedef struct { + OSSL_LIB_CTX *libctx; + + EC_KEY *k; + EC_KEY *peerk; + + /* + * ECDH cofactor mode: + * + * . 0 disabled + * . 1 enabled + * . -1 use cofactor mode set for k + */ + int cofactor_mode; + + /************ + * ECDH KDF * + ************/ + /* KDF (if any) to use for ECDH */ + enum kdf_type kdf_type; + /* Message digest to use for key derivation */ + EVP_MD *kdf_md; + /* User key material */ + unsigned char *kdf_ukm; + size_t kdf_ukmlen; + /* KDF output length */ + size_t kdf_outlen; +} PROV_ECDH_CTX; + +static +void *ecdh_newctx(void *provctx) +{ + PROV_ECDH_CTX *pectx; + + if (!ossl_prov_is_running()) + return NULL; + + pectx = OPENSSL_zalloc(sizeof(*pectx)); + if (pectx == NULL) + return NULL; + + pectx->libctx = PROV_LIBCTX_OF(provctx); + pectx->cofactor_mode = -1; + pectx->kdf_type = PROV_ECDH_KDF_NONE; + + return (void *)pectx; +} + +static +int ecdh_init(void *vpecdhctx, void *vecdh, const OSSL_PARAM params[]) +{ + PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; + + if (!ossl_prov_is_running() + || pecdhctx == NULL + || vecdh == NULL + || !EC_KEY_up_ref(vecdh)) + return 0; + EC_KEY_free(pecdhctx->k); + pecdhctx->k = vecdh; + pecdhctx->cofactor_mode = -1; + pecdhctx->kdf_type = PROV_ECDH_KDF_NONE; + return ecdh_set_ctx_params(pecdhctx, params) + && ossl_ec_check_key(pecdhctx->libctx, vecdh, 1); +} + +static +int ecdh_match_params(const EC_KEY *priv, const EC_KEY *peer) +{ + int ret; + BN_CTX *ctx = NULL; + const EC_GROUP *group_priv = EC_KEY_get0_group(priv); + const EC_GROUP *group_peer = EC_KEY_get0_group(peer); + + ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(priv)); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + ret = group_priv != NULL + && group_peer != NULL + && EC_GROUP_cmp(group_priv, group_peer, ctx) == 0; + if (!ret) + ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS); + BN_CTX_free(ctx); + return ret; +} + +static +int ecdh_set_peer(void *vpecdhctx, void *vecdh) +{ + PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; + + if (!ossl_prov_is_running() + || pecdhctx == NULL + || vecdh == NULL + || !ecdh_match_params(pecdhctx->k, vecdh) + || !ossl_ec_check_key(pecdhctx->libctx, vecdh, 1) + || !EC_KEY_up_ref(vecdh)) + return 0; + + EC_KEY_free(pecdhctx->peerk); + pecdhctx->peerk = vecdh; + return 1; +} + +static +void ecdh_freectx(void *vpecdhctx) +{ + PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; + + EC_KEY_free(pecdhctx->k); + EC_KEY_free(pecdhctx->peerk); + + EVP_MD_free(pecdhctx->kdf_md); + OPENSSL_clear_free(pecdhctx->kdf_ukm, pecdhctx->kdf_ukmlen); + + OPENSSL_free(pecdhctx); +} + +static +void *ecdh_dupctx(void *vpecdhctx) +{ + PROV_ECDH_CTX *srcctx = (PROV_ECDH_CTX *)vpecdhctx; + PROV_ECDH_CTX *dstctx; + + if (!ossl_prov_is_running()) + return NULL; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + + /* clear all pointers */ + + dstctx->k= NULL; + dstctx->peerk = NULL; + dstctx->kdf_md = NULL; + dstctx->kdf_ukm = NULL; + + /* up-ref all ref-counted objects referenced in dstctx */ + + if (srcctx->k != NULL && !EC_KEY_up_ref(srcctx->k)) + goto err; + else + dstctx->k = srcctx->k; + + if (srcctx->peerk != NULL && !EC_KEY_up_ref(srcctx->peerk)) + goto err; + else + dstctx->peerk = srcctx->peerk; + + if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md)) + goto err; + else + dstctx->kdf_md = srcctx->kdf_md; + + /* Duplicate UKM data if present */ + if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) { + dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm, + srcctx->kdf_ukmlen); + if (dstctx->kdf_ukm == NULL) + goto err; + } + + return dstctx; + + err: + ecdh_freectx(dstctx); + return NULL; +} + +static +int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[]) +{ + char name[80] = { '\0' }; /* should be big enough */ + char *str = NULL; + PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx; + const OSSL_PARAM *p; + + if (pectx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE); + if (p != NULL) { + int mode; + + if (!OSSL_PARAM_get_int(p, &mode)) + return 0; + + if (mode < -1 || mode > 1) + return 0; + + pectx->cofactor_mode = mode; + } + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); + if (p != NULL) { + str = name; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) + return 0; + + if (name[0] == '\0') + pectx->kdf_type = PROV_ECDH_KDF_NONE; + else if (strcmp(name, OSSL_KDF_NAME_X963KDF) == 0) + pectx->kdf_type = PROV_ECDH_KDF_X9_63; + else + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); + if (p != NULL) { + char mdprops[80] = { '\0' }; /* should be big enough */ + + str = name; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) + return 0; + + str = mdprops; + p = OSSL_PARAM_locate_const(params, + OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS); + + if (p != NULL) { + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) + return 0; + } + + EVP_MD_free(pectx->kdf_md); + pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops); + if (!ossl_digest_is_allowed(pectx->libctx, pectx->kdf_md)) { + EVP_MD_free(pectx->kdf_md); + pectx->kdf_md = NULL; + } + if (pectx->kdf_md == NULL) + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); + if (p != NULL) { + size_t outlen; + + if (!OSSL_PARAM_get_size_t(p, &outlen)) + return 0; + pectx->kdf_outlen = outlen; + } + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM); + if (p != NULL) { + void *tmp_ukm = NULL; + size_t tmp_ukmlen; + + if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen)) + return 0; + OPENSSL_free(pectx->kdf_ukm); + pectx->kdf_ukm = tmp_ukm; + pectx->kdf_ukmlen = tmp_ukmlen; + } + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0), + OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), + OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), + OSSL_PARAM_END +}; + +static +const OSSL_PARAM *ecdh_settable_ctx_params(ossl_unused void *vpecdhctx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +static +int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[]) +{ + PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx; + OSSL_PARAM *p; + + if (pectx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE); + if (p != NULL) { + int mode = pectx->cofactor_mode; + + if (mode == -1) { + /* check what is the default for pecdhctx->k */ + mode = EC_KEY_get_flags(pectx->k) & EC_FLAG_COFACTOR_ECDH ? 1 : 0; + } + + if (!OSSL_PARAM_set_int(p, mode)) + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); + if (p != NULL) { + const char *kdf_type = NULL; + + switch (pectx->kdf_type) { + case PROV_ECDH_KDF_NONE: + kdf_type = ""; + break; + case PROV_ECDH_KDF_X9_63: + kdf_type = OSSL_KDF_NAME_X963KDF; + break; + default: + return 0; + } + + if (!OSSL_PARAM_set_utf8_string(p, kdf_type)) + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); + if (p != NULL + && !OSSL_PARAM_set_utf8_string(p, pectx->kdf_md == NULL + ? "" + : EVP_MD_get0_name(pectx->kdf_md))){ + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, pectx->kdf_outlen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM); + if (p != NULL && + !OSSL_PARAM_set_octet_ptr(p, pectx->kdf_ukm, pectx->kdf_ukmlen)) + return 0; + + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), + OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), + OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR, + NULL, 0), + OSSL_PARAM_END +}; + +static +const OSSL_PARAM *ecdh_gettable_ctx_params(ossl_unused void *vpecdhctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static ossl_inline +size_t ecdh_size(const EC_KEY *k) +{ + size_t degree = 0; + const EC_GROUP *group; + + if (k == NULL + || (group = EC_KEY_get0_group(k)) == NULL) + return 0; + + degree = EC_GROUP_get_degree(group); + + return (degree + 7) / 8; +} + +static ossl_inline +int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret, + size_t *psecretlen, size_t outlen) +{ + PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; + int retlen, ret = 0; + size_t ecdhsize, size; + const EC_POINT *ppubkey = NULL; + EC_KEY *privk = NULL; + const EC_GROUP *group; + const BIGNUM *cofactor; + int key_cofactor_mode; + + if (pecdhctx->k == NULL || pecdhctx->peerk == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return 0; + } + + ecdhsize = ecdh_size(pecdhctx->k); + if (secret == NULL) { + *psecretlen = ecdhsize; + return 1; + } + + if ((group = EC_KEY_get0_group(pecdhctx->k)) == NULL + || (cofactor = EC_GROUP_get0_cofactor(group)) == NULL ) + return 0; + + /* + * NB: unlike PKCS#3 DH, if outlen is less than maximum size this is not + * an error, the result is truncated. + */ + size = outlen < ecdhsize ? outlen : ecdhsize; + + /* + * The ctx->cofactor_mode flag has precedence over the + * cofactor_mode flag set on ctx->k. + * + * - if ctx->cofactor_mode == -1, use ctx->k directly + * - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly + * - if ctx->cofactor_mode != key_cofactor_mode: + * - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use + * ctx->k directly + * - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag + * set to ctx->cofactor_mode + */ + key_cofactor_mode = + (EC_KEY_get_flags(pecdhctx->k) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0; + if (pecdhctx->cofactor_mode != -1 + && pecdhctx->cofactor_mode != key_cofactor_mode + && !BN_is_one(cofactor)) { + if ((privk = EC_KEY_dup(pecdhctx->k)) == NULL) + return 0; + + if (pecdhctx->cofactor_mode == 1) + EC_KEY_set_flags(privk, EC_FLAG_COFACTOR_ECDH); + else + EC_KEY_clear_flags(privk, EC_FLAG_COFACTOR_ECDH); + } else { + privk = pecdhctx->k; + } + + ppubkey = EC_KEY_get0_public_key(pecdhctx->peerk); + + retlen = ECDH_compute_key(secret, size, ppubkey, privk, NULL); + + if (retlen <= 0) + goto end; + + *psecretlen = retlen; + ret = 1; + + end: + if (privk != pecdhctx->k) + EC_KEY_free(privk); + return ret; +} + +static ossl_inline +int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret, + size_t *psecretlen, size_t outlen) +{ + PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; + unsigned char *stmp = NULL; + size_t stmplen; + int ret = 0; + + if (secret == NULL) { + *psecretlen = pecdhctx->kdf_outlen; + return 1; + } + + if (pecdhctx->kdf_outlen > outlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (!ecdh_plain_derive(vpecdhctx, NULL, &stmplen, 0)) + return 0; + if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + if (!ecdh_plain_derive(vpecdhctx, stmp, &stmplen, stmplen)) + goto err; + + /* Do KDF stuff */ + if (!ossl_ecdh_kdf_X9_63(secret, pecdhctx->kdf_outlen, + stmp, stmplen, + pecdhctx->kdf_ukm, + pecdhctx->kdf_ukmlen, + pecdhctx->kdf_md, + pecdhctx->libctx, NULL)) + goto err; + *psecretlen = pecdhctx->kdf_outlen; + ret = 1; + + err: + OPENSSL_secure_clear_free(stmp, stmplen); + return ret; +} + +static +int ecdh_derive(void *vpecdhctx, unsigned char *secret, + size_t *psecretlen, size_t outlen) +{ + PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; + + switch (pecdhctx->kdf_type) { + case PROV_ECDH_KDF_NONE: + return ecdh_plain_derive(vpecdhctx, secret, psecretlen, outlen); + case PROV_ECDH_KDF_X9_63: + return ecdh_X9_63_kdf_derive(vpecdhctx, secret, psecretlen, outlen); + default: + break; + } + return 0; +} + +const OSSL_DISPATCH ossl_ecdh_keyexch_functions[] = { + { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdh_newctx }, + { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdh_init }, + { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdh_derive }, + { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecdh_set_peer }, + { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecdh_freectx }, + { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecdh_dupctx }, + { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))ecdh_set_ctx_params }, + { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, + (void (*)(void))ecdh_settable_ctx_params }, + { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))ecdh_get_ctx_params }, + { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS, + (void (*)(void))ecdh_gettable_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/exchange/ecx_exch.c b/providers/implementations/exchange/ecx_exch.c new file mode 100644 index 000000000000..2ba9090c8b5a --- /dev/null +++ b/providers/implementations/exchange/ecx_exch.c @@ -0,0 +1,243 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/crypto.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" +#include "crypto/ecx.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" +#ifdef S390X_EC_ASM +# include "s390x_arch.h" +#endif + +static OSSL_FUNC_keyexch_newctx_fn x25519_newctx; +static OSSL_FUNC_keyexch_newctx_fn x448_newctx; +static OSSL_FUNC_keyexch_init_fn ecx_init; +static OSSL_FUNC_keyexch_set_peer_fn ecx_set_peer; +static OSSL_FUNC_keyexch_derive_fn ecx_derive; +static OSSL_FUNC_keyexch_freectx_fn ecx_freectx; +static OSSL_FUNC_keyexch_dupctx_fn ecx_dupctx; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes ECX_KEY structures, so + * we use that here too. + */ + +typedef struct { + size_t keylen; + ECX_KEY *key; + ECX_KEY *peerkey; +} PROV_ECX_CTX; + +static void *ecx_newctx(void *provctx, size_t keylen) +{ + PROV_ECX_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(PROV_ECX_CTX)); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ctx->keylen = keylen; + + return ctx; +} + +static void *x25519_newctx(void *provctx) +{ + return ecx_newctx(provctx, X25519_KEYLEN); +} + +static void *x448_newctx(void *provctx) +{ + return ecx_newctx(provctx, X448_KEYLEN); +} + +static int ecx_init(void *vecxctx, void *vkey, + ossl_unused const OSSL_PARAM params[]) +{ + PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; + ECX_KEY *key = vkey; + + if (!ossl_prov_is_running()) + return 0; + + if (ecxctx == NULL + || key == NULL + || key->keylen != ecxctx->keylen + || !ossl_ecx_key_up_ref(key)) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return 0; + } + + ossl_ecx_key_free(ecxctx->key); + ecxctx->key = key; + + return 1; +} + +static int ecx_set_peer(void *vecxctx, void *vkey) +{ + PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; + ECX_KEY *key = vkey; + + if (!ossl_prov_is_running()) + return 0; + + if (ecxctx == NULL + || key == NULL + || key->keylen != ecxctx->keylen + || !ossl_ecx_key_up_ref(key)) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return 0; + } + ossl_ecx_key_free(ecxctx->peerkey); + ecxctx->peerkey = key; + + return 1; +} + +static int ecx_derive(void *vecxctx, unsigned char *secret, size_t *secretlen, + size_t outlen) +{ + PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; + + if (!ossl_prov_is_running()) + return 0; + + if (ecxctx->key == NULL + || ecxctx->key->privkey == NULL + || ecxctx->peerkey == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return 0; + } + + if (!ossl_assert(ecxctx->keylen == X25519_KEYLEN + || ecxctx->keylen == X448_KEYLEN)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + + if (secret == NULL) { + *secretlen = ecxctx->keylen; + return 1; + } + if (outlen < ecxctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (ecxctx->keylen == X25519_KEYLEN) { +#ifdef S390X_EC_ASM + if (OPENSSL_s390xcap_P.pcc[1] + & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X25519)) { + if (s390x_x25519_mul(secret, ecxctx->peerkey->pubkey, + ecxctx->key->privkey) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); + return 0; + } + } else +#endif + if (ossl_x25519(secret, ecxctx->key->privkey, + ecxctx->peerkey->pubkey) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); + return 0; + } + } else { +#ifdef S390X_EC_ASM + if (OPENSSL_s390xcap_P.pcc[1] + & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X448)) { + if (s390x_x448_mul(secret, ecxctx->peerkey->pubkey, + ecxctx->key->privkey) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); + return 0; + } + } else +#endif + if (ossl_x448(secret, ecxctx->key->privkey, + ecxctx->peerkey->pubkey) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); + return 0; + } + } + + *secretlen = ecxctx->keylen; + return 1; +} + +static void ecx_freectx(void *vecxctx) +{ + PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; + + ossl_ecx_key_free(ecxctx->key); + ossl_ecx_key_free(ecxctx->peerkey); + + OPENSSL_free(ecxctx); +} + +static void *ecx_dupctx(void *vecxctx) +{ + PROV_ECX_CTX *srcctx = (PROV_ECX_CTX *)vecxctx; + PROV_ECX_CTX *dstctx; + + if (!ossl_prov_is_running()) + return NULL; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + *dstctx = *srcctx; + if (dstctx->key != NULL && !ossl_ecx_key_up_ref(dstctx->key)) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + OPENSSL_free(dstctx); + return NULL; + } + + if (dstctx->peerkey != NULL && !ossl_ecx_key_up_ref(dstctx->peerkey)) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + ossl_ecx_key_free(dstctx->key); + OPENSSL_free(dstctx); + return NULL; + } + + return dstctx; +} + +const OSSL_DISPATCH ossl_x25519_keyexch_functions[] = { + { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))x25519_newctx }, + { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecx_init }, + { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecx_derive }, + { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecx_set_peer }, + { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecx_freectx }, + { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecx_dupctx }, + { 0, NULL } +}; + +const OSSL_DISPATCH ossl_x448_keyexch_functions[] = { + { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))x448_newctx }, + { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecx_init }, + { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecx_derive }, + { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecx_set_peer }, + { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecx_freectx }, + { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecx_dupctx }, + { 0, NULL } +}; diff --git a/providers/implementations/exchange/kdf_exch.c b/providers/implementations/exchange/kdf_exch.c new file mode 100644 index 000000000000..527a866c3d8d --- /dev/null +++ b/providers/implementations/exchange/kdf_exch.c @@ -0,0 +1,215 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/crypto.h> +#include <openssl/kdf.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include <openssl/params.h> +#include "internal/numbers.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/kdfexchange.h" +#include "prov/providercommon.h" + +static OSSL_FUNC_keyexch_newctx_fn kdf_tls1_prf_newctx; +static OSSL_FUNC_keyexch_newctx_fn kdf_hkdf_newctx; +static OSSL_FUNC_keyexch_newctx_fn kdf_scrypt_newctx; +static OSSL_FUNC_keyexch_init_fn kdf_init; +static OSSL_FUNC_keyexch_derive_fn kdf_derive; +static OSSL_FUNC_keyexch_freectx_fn kdf_freectx; +static OSSL_FUNC_keyexch_dupctx_fn kdf_dupctx; +static OSSL_FUNC_keyexch_set_ctx_params_fn kdf_set_ctx_params; +static OSSL_FUNC_keyexch_settable_ctx_params_fn kdf_tls1_prf_settable_ctx_params; +static OSSL_FUNC_keyexch_settable_ctx_params_fn kdf_hkdf_settable_ctx_params; +static OSSL_FUNC_keyexch_settable_ctx_params_fn kdf_scrypt_settable_ctx_params; + +typedef struct { + void *provctx; + EVP_KDF_CTX *kdfctx; + KDF_DATA *kdfdata; +} PROV_KDF_CTX; + +static void *kdf_newctx(const char *kdfname, void *provctx) +{ + PROV_KDF_CTX *kdfctx; + EVP_KDF *kdf = NULL; + + if (!ossl_prov_is_running()) + return NULL; + + kdfctx = OPENSSL_zalloc(sizeof(PROV_KDF_CTX)); + if (kdfctx == NULL) + return NULL; + + kdfctx->provctx = provctx; + + kdf = EVP_KDF_fetch(PROV_LIBCTX_OF(provctx), kdfname, NULL); + if (kdf == NULL) + goto err; + kdfctx->kdfctx = EVP_KDF_CTX_new(kdf); + EVP_KDF_free(kdf); + + if (kdfctx->kdfctx == NULL) + goto err; + + return kdfctx; +err: + OPENSSL_free(kdfctx); + return NULL; +} + +#define KDF_NEWCTX(funcname, kdfname) \ + static void *kdf_##funcname##_newctx(void *provctx) \ + { \ + return kdf_newctx(kdfname, provctx); \ + } + +KDF_NEWCTX(tls1_prf, "TLS1-PRF") +KDF_NEWCTX(hkdf, "HKDF") +KDF_NEWCTX(scrypt, "SCRYPT") + +static int kdf_init(void *vpkdfctx, void *vkdf, const OSSL_PARAM params[]) +{ + PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx; + + if (!ossl_prov_is_running() + || pkdfctx == NULL + || vkdf == NULL + || !ossl_kdf_data_up_ref(vkdf)) + return 0; + pkdfctx->kdfdata = vkdf; + + return kdf_set_ctx_params(pkdfctx, params); +} + +static int kdf_derive(void *vpkdfctx, unsigned char *secret, size_t *secretlen, + size_t outlen) +{ + PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx; + size_t kdfsize; + int ret; + + if (!ossl_prov_is_running()) + return 0; + + kdfsize = EVP_KDF_CTX_get_kdf_size(pkdfctx->kdfctx); + + if (secret == NULL) { + *secretlen = kdfsize; + return 1; + } + + if (kdfsize != SIZE_MAX) { + if (outlen < kdfsize) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + outlen = kdfsize; + } + + ret = EVP_KDF_derive(pkdfctx->kdfctx, secret, outlen, NULL); + if (ret <= 0) + return 0; + + *secretlen = outlen; + return 1; +} + +static void kdf_freectx(void *vpkdfctx) +{ + PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx; + + EVP_KDF_CTX_free(pkdfctx->kdfctx); + ossl_kdf_data_free(pkdfctx->kdfdata); + + OPENSSL_free(pkdfctx); +} + +static void *kdf_dupctx(void *vpkdfctx) +{ + PROV_KDF_CTX *srcctx = (PROV_KDF_CTX *)vpkdfctx; + PROV_KDF_CTX *dstctx; + + if (!ossl_prov_is_running()) + return NULL; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + + dstctx->kdfctx = EVP_KDF_CTX_dup(srcctx->kdfctx); + if (dstctx->kdfctx == NULL) { + OPENSSL_free(dstctx); + return NULL; + } + if (!ossl_kdf_data_up_ref(dstctx->kdfdata)) { + EVP_KDF_CTX_free(dstctx->kdfctx); + OPENSSL_free(dstctx); + return NULL; + } + + return dstctx; +} + +static int kdf_set_ctx_params(void *vpkdfctx, const OSSL_PARAM params[]) +{ + PROV_KDF_CTX *pkdfctx = (PROV_KDF_CTX *)vpkdfctx; + + return EVP_KDF_CTX_set_params(pkdfctx->kdfctx, params); +} + +static const OSSL_PARAM *kdf_settable_ctx_params(ossl_unused void *vpkdfctx, + void *provctx, + const char *kdfname) +{ + EVP_KDF *kdf = EVP_KDF_fetch(PROV_LIBCTX_OF(provctx), kdfname, + NULL); + const OSSL_PARAM *params; + + if (kdf == NULL) + return NULL; + + params = EVP_KDF_settable_ctx_params(kdf); + EVP_KDF_free(kdf); + + return params; +} + +#define KDF_SETTABLE_CTX_PARAMS(funcname, kdfname) \ + static const OSSL_PARAM *kdf_##funcname##_settable_ctx_params(void *vpkdfctx, \ + void *provctx) \ + { \ + return kdf_settable_ctx_params(vpkdfctx, provctx, kdfname); \ + } + +KDF_SETTABLE_CTX_PARAMS(tls1_prf, "TLS1-PRF") +KDF_SETTABLE_CTX_PARAMS(hkdf, "HKDF") +KDF_SETTABLE_CTX_PARAMS(scrypt, "SCRYPT") + +#define KDF_KEYEXCH_FUNCTIONS(funcname) \ + const OSSL_DISPATCH ossl_kdf_##funcname##_keyexch_functions[] = { \ + { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))kdf_##funcname##_newctx }, \ + { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))kdf_init }, \ + { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))kdf_derive }, \ + { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))kdf_freectx }, \ + { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))kdf_dupctx }, \ + { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))kdf_set_ctx_params }, \ + { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, \ + (void (*)(void))kdf_##funcname##_settable_ctx_params }, \ + { 0, NULL } \ + }; + +KDF_KEYEXCH_FUNCTIONS(tls1_prf) +KDF_KEYEXCH_FUNCTIONS(hkdf) +KDF_KEYEXCH_FUNCTIONS(scrypt) diff --git a/providers/implementations/include/prov/__DECC_INCLUDE_EPILOGUE.H b/providers/implementations/include/prov/__DECC_INCLUDE_EPILOGUE.H new file mode 100644 index 000000000000..2ab493330675 --- /dev/null +++ b/providers/implementations/include/prov/__DECC_INCLUDE_EPILOGUE.H @@ -0,0 +1,22 @@ +/* + * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This file is only used by HP C/C++ on VMS, and is included automatically + * after each header file from this directory + */ + +/* + * The C++ compiler doesn't understand these pragmas, even though it + * understands the corresponding command line qualifier. + */ +#ifndef __cplusplus +/* restore state. Must correspond to the save in __decc_include_prologue.h */ +# pragma names restore +#endif diff --git a/providers/implementations/include/prov/__DECC_INCLUDE_PROLOGUE.H b/providers/implementations/include/prov/__DECC_INCLUDE_PROLOGUE.H new file mode 100644 index 000000000000..8e95fa975488 --- /dev/null +++ b/providers/implementations/include/prov/__DECC_INCLUDE_PROLOGUE.H @@ -0,0 +1,26 @@ +/* + * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This file is only used by HP C/C++ on VMS, and is included automatically + * after each header file from this directory + */ + +/* + * The C++ compiler doesn't understand these pragmas, even though it + * understands the corresponding command line qualifier. + */ +#ifndef __cplusplus +/* save state */ +# pragma names save +/* have the compiler shorten symbols larger than 31 chars to 23 chars + * followed by a 8 hex char CRC + */ +# pragma names as_is,shortened +#endif diff --git a/providers/implementations/include/prov/blake2.h b/providers/implementations/include/prov/blake2.h new file mode 100644 index 000000000000..d18cbc708c4f --- /dev/null +++ b/providers/implementations/include/prov/blake2.h @@ -0,0 +1,120 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef OSSL_PROV_BLAKE2_H +# define OSSL_PROV_BLAKE2_H + +# include <openssl/opensslconf.h> + +# include <openssl/e_os2.h> +# include <stddef.h> + +# define BLAKE2S_BLOCKBYTES 64 +# define BLAKE2S_OUTBYTES 32 +# define BLAKE2S_KEYBYTES 32 +# define BLAKE2S_SALTBYTES 8 +# define BLAKE2S_PERSONALBYTES 8 + +# define BLAKE2B_BLOCKBYTES 128 +# define BLAKE2B_OUTBYTES 64 +# define BLAKE2B_KEYBYTES 64 +# define BLAKE2B_SALTBYTES 16 +# define BLAKE2B_PERSONALBYTES 16 + +struct blake2s_param_st { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint8_t leaf_length[4];/* 8 */ + uint8_t node_offset[6];/* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ +}; + +typedef struct blake2s_param_st BLAKE2S_PARAM; + +struct blake2s_ctx_st { + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; +}; + +struct blake2b_param_st { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint8_t leaf_length[4];/* 8 */ + uint8_t node_offset[8];/* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ +}; + +typedef struct blake2b_param_st BLAKE2B_PARAM; + +struct blake2b_ctx_st { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; +}; + +#define BLAKE2B_DIGEST_LENGTH 64 +#define BLAKE2S_DIGEST_LENGTH 32 + +typedef struct blake2s_ctx_st BLAKE2S_CTX; +typedef struct blake2b_ctx_st BLAKE2B_CTX; + +int ossl_blake2s256_init(void *ctx); +int ossl_blake2b512_init(void *ctx); + +int ossl_blake2b_init(BLAKE2B_CTX *c, const BLAKE2B_PARAM *P); +int ossl_blake2b_init_key(BLAKE2B_CTX *c, const BLAKE2B_PARAM *P, + const void *key); +int ossl_blake2b_update(BLAKE2B_CTX *c, const void *data, size_t datalen); +int ossl_blake2b_final(unsigned char *md, BLAKE2B_CTX *c); + +/* + * These setters are internal and do not check the validity of their parameters. + * See blake2b_mac_ctrl for validation logic. + */ + +void ossl_blake2b_param_init(BLAKE2B_PARAM *P); +void ossl_blake2b_param_set_digest_length(BLAKE2B_PARAM *P, uint8_t outlen); +void ossl_blake2b_param_set_key_length(BLAKE2B_PARAM *P, uint8_t keylen); +void ossl_blake2b_param_set_personal(BLAKE2B_PARAM *P, const uint8_t *personal, + size_t length); +void ossl_blake2b_param_set_salt(BLAKE2B_PARAM *P, const uint8_t *salt, + size_t length); +int ossl_blake2s_init(BLAKE2S_CTX *c, const BLAKE2S_PARAM *P); +int ossl_blake2s_init_key(BLAKE2S_CTX *c, const BLAKE2S_PARAM *P, + const void *key); +int ossl_blake2s_update(BLAKE2S_CTX *c, const void *data, size_t datalen); +int ossl_blake2s_final(unsigned char *md, BLAKE2S_CTX *c); + +void ossl_blake2s_param_init(BLAKE2S_PARAM *P); +void ossl_blake2s_param_set_digest_length(BLAKE2S_PARAM *P, uint8_t outlen); +void ossl_blake2s_param_set_key_length(BLAKE2S_PARAM *P, uint8_t keylen); +void ossl_blake2s_param_set_personal(BLAKE2S_PARAM *P, const uint8_t *personal, + size_t length); +void ossl_blake2s_param_set_salt(BLAKE2S_PARAM *P, const uint8_t *salt, + size_t length); + +#endif /* OSSL_PROV_BLAKE2_H */ diff --git a/providers/implementations/include/prov/ciphercommon.h b/providers/implementations/include/prov/ciphercommon.h new file mode 100644 index 000000000000..8153872cba26 --- /dev/null +++ b/providers/implementations/include/prov/ciphercommon.h @@ -0,0 +1,361 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/params.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/evp.h> +#include "internal/cryptlib.h" +#include "crypto/modes.h" + +# define MAXCHUNK ((size_t)1 << 30) +# define MAXBITCHUNK ((size_t)1 << (sizeof(size_t) * 8 - 4)) + +#define GENERIC_BLOCK_SIZE 16 +#define IV_STATE_UNINITIALISED 0 /* initial state is not initialized */ +#define IV_STATE_BUFFERED 1 /* iv has been copied to the iv buffer */ +#define IV_STATE_COPIED 2 /* iv has been copied from the iv buffer */ +#define IV_STATE_FINISHED 3 /* the iv has been used - so don't reuse it */ + +#define PROV_CIPHER_FUNC(type, name, args) typedef type (* OSSL_##name##_fn)args + +typedef struct prov_cipher_hw_st PROV_CIPHER_HW; +typedef struct prov_cipher_ctx_st PROV_CIPHER_CTX; + +typedef int (PROV_CIPHER_HW_FN)(PROV_CIPHER_CTX *dat, unsigned char *out, + const unsigned char *in, size_t len); + +/* Internal flags that can be queried */ +#define PROV_CIPHER_FLAG_AEAD 0x0001 +#define PROV_CIPHER_FLAG_CUSTOM_IV 0x0002 +#define PROV_CIPHER_FLAG_CTS 0x0004 +#define PROV_CIPHER_FLAG_TLS1_MULTIBLOCK 0x0008 +#define PROV_CIPHER_FLAG_RAND_KEY 0x0010 +/* Internal flags that are only used within the provider */ +#define PROV_CIPHER_FLAG_VARIABLE_LENGTH 0x0100 +#define PROV_CIPHER_FLAG_INVERSE_CIPHER 0x0200 + +struct prov_cipher_ctx_st { + block128_f block; + union { + cbc128_f cbc; + ctr128_f ctr; + ecb128_f ecb; + } stream; + + unsigned int mode; + size_t keylen; /* key size (in bytes) */ + size_t ivlen; + size_t blocksize; + size_t bufsz; /* Number of bytes in buf */ + unsigned int cts_mode; /* Use to set the type for CTS modes */ + unsigned int pad : 1; /* Whether padding should be used or not */ + unsigned int enc : 1; /* Set to 1 for encrypt, or 0 otherwise */ + unsigned int iv_set : 1; /* Set when the iv is copied to the iv/oiv buffers */ + unsigned int updated : 1; /* Set to 1 during update for one shot ciphers */ + unsigned int variable_keylength : 1; + unsigned int inverse_cipher : 1; /* set to 1 to use inverse cipher */ + unsigned int use_bits : 1; /* Set to 0 for cfb1 to use bits instead of bytes */ + + unsigned int tlsversion; /* If TLS padding is in use the TLS version number */ + unsigned char *tlsmac; /* tls MAC extracted from the last record */ + int alloced; /* + * Whether the tlsmac data has been allocated or + * points into the user buffer. + */ + size_t tlsmacsize; /* Size of the TLS MAC */ + int removetlspad; /* Whether TLS padding should be removed or not */ + size_t removetlsfixed; /* + * Length of the fixed size data to remove when + * processing TLS data (equals mac size plus + * IV size if applicable) + */ + + /* + * num contains the number of bytes of |iv| which are valid for modes that + * manage partial blocks themselves. + */ + unsigned int num; + + /* The original value of the iv */ + unsigned char oiv[GENERIC_BLOCK_SIZE]; + /* Buffer of partial blocks processed via update calls */ + unsigned char buf[GENERIC_BLOCK_SIZE]; + unsigned char iv[GENERIC_BLOCK_SIZE]; + const PROV_CIPHER_HW *hw; /* hardware specific functions */ + const void *ks; /* Pointer to algorithm specific key data */ + OSSL_LIB_CTX *libctx; +}; + +struct prov_cipher_hw_st { + int (*init)(PROV_CIPHER_CTX *dat, const uint8_t *key, size_t keylen); + PROV_CIPHER_HW_FN *cipher; + void (*copyctx)(PROV_CIPHER_CTX *dst, const PROV_CIPHER_CTX *src); +}; + +void ossl_cipher_generic_reset_ctx(PROV_CIPHER_CTX *ctx); +OSSL_FUNC_cipher_encrypt_init_fn ossl_cipher_generic_einit; +OSSL_FUNC_cipher_decrypt_init_fn ossl_cipher_generic_dinit; +OSSL_FUNC_cipher_update_fn ossl_cipher_generic_block_update; +OSSL_FUNC_cipher_final_fn ossl_cipher_generic_block_final; +OSSL_FUNC_cipher_update_fn ossl_cipher_generic_stream_update; +OSSL_FUNC_cipher_final_fn ossl_cipher_generic_stream_final; +OSSL_FUNC_cipher_cipher_fn ossl_cipher_generic_cipher; +OSSL_FUNC_cipher_get_ctx_params_fn ossl_cipher_generic_get_ctx_params; +OSSL_FUNC_cipher_set_ctx_params_fn ossl_cipher_generic_set_ctx_params; +OSSL_FUNC_cipher_gettable_params_fn ossl_cipher_generic_gettable_params; +OSSL_FUNC_cipher_gettable_ctx_params_fn ossl_cipher_generic_gettable_ctx_params; +OSSL_FUNC_cipher_settable_ctx_params_fn ossl_cipher_generic_settable_ctx_params; +OSSL_FUNC_cipher_set_ctx_params_fn ossl_cipher_var_keylen_set_ctx_params; +OSSL_FUNC_cipher_settable_ctx_params_fn ossl_cipher_var_keylen_settable_ctx_params; +OSSL_FUNC_cipher_gettable_ctx_params_fn ossl_cipher_aead_gettable_ctx_params; +OSSL_FUNC_cipher_settable_ctx_params_fn ossl_cipher_aead_settable_ctx_params; + +int ossl_cipher_generic_get_params(OSSL_PARAM params[], unsigned int md, + uint64_t flags, + size_t kbits, size_t blkbits, size_t ivbits); +void ossl_cipher_generic_initkey(void *vctx, size_t kbits, size_t blkbits, + size_t ivbits, unsigned int mode, + uint64_t flags, + const PROV_CIPHER_HW *hw, void *provctx); + +#define IMPLEMENT_generic_cipher_func(alg, UCALG, lcmode, UCMODE, flags, kbits,\ + blkbits, ivbits, typ) \ +const OSSL_DISPATCH ossl_##alg##kbits##lcmode##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (void (*)(void)) alg##_##kbits##_##lcmode##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))ossl_cipher_generic_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))ossl_cipher_generic_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))ossl_cipher_generic_##typ##_update },\ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))ossl_cipher_generic_##typ##_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_cipher_generic_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void)) alg##_##kbits##_##lcmode##_get_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_settable_ctx_params }, \ + { 0, NULL } \ +}; + +#define IMPLEMENT_var_keylen_cipher_func(alg, UCALG, lcmode, UCMODE, flags, \ + kbits, blkbits, ivbits, typ) \ +const OSSL_DISPATCH ossl_##alg##kbits##lcmode##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (void (*)(void)) alg##_##kbits##_##lcmode##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))ossl_cipher_generic_einit },\ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))ossl_cipher_generic_dinit },\ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))ossl_cipher_generic_##typ##_update },\ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))ossl_cipher_generic_##typ##_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_cipher_generic_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void)) alg##_##kbits##_##lcmode##_get_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_var_keylen_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_var_keylen_settable_ctx_params }, \ + { 0, NULL } \ +}; + + +#define IMPLEMENT_generic_cipher_genfn(alg, UCALG, lcmode, UCMODE, flags, \ + kbits, blkbits, ivbits, typ) \ +static OSSL_FUNC_cipher_get_params_fn alg##_##kbits##_##lcmode##_get_params; \ +static int alg##_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, kbits, blkbits, ivbits); \ +} \ +static OSSL_FUNC_cipher_newctx_fn alg##_##kbits##_##lcmode##_newctx; \ +static void * alg##_##kbits##_##lcmode##_newctx(void *provctx) \ +{ \ + PROV_##UCALG##_CTX *ctx = ossl_prov_is_running() ? OPENSSL_zalloc(sizeof(*ctx))\ + : NULL; \ + if (ctx != NULL) { \ + ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits, \ + EVP_CIPH_##UCMODE##_MODE, flags, \ + ossl_prov_cipher_hw_##alg##_##lcmode(kbits),\ + provctx); \ + } \ + return ctx; \ +} \ + +#define IMPLEMENT_generic_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits, \ + blkbits, ivbits, typ) \ +IMPLEMENT_generic_cipher_genfn(alg, UCALG, lcmode, UCMODE, flags, kbits, \ + blkbits, ivbits, typ) \ +IMPLEMENT_generic_cipher_func(alg, UCALG, lcmode, UCMODE, flags, kbits, \ + blkbits, ivbits, typ) + +#define IMPLEMENT_var_keylen_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits, \ + blkbits, ivbits, typ) \ +IMPLEMENT_generic_cipher_genfn(alg, UCALG, lcmode, UCMODE, flags, kbits, \ + blkbits, ivbits, typ) \ +IMPLEMENT_var_keylen_cipher_func(alg, UCALG, lcmode, UCMODE, flags, kbits, \ + blkbits, ivbits, typ) + +PROV_CIPHER_HW_FN ossl_cipher_hw_generic_cbc; +PROV_CIPHER_HW_FN ossl_cipher_hw_generic_ecb; +PROV_CIPHER_HW_FN ossl_cipher_hw_generic_ofb128; +PROV_CIPHER_HW_FN ossl_cipher_hw_generic_cfb128; +PROV_CIPHER_HW_FN ossl_cipher_hw_generic_cfb8; +PROV_CIPHER_HW_FN ossl_cipher_hw_generic_cfb1; +PROV_CIPHER_HW_FN ossl_cipher_hw_generic_ctr; +PROV_CIPHER_HW_FN ossl_cipher_hw_chunked_cbc; +PROV_CIPHER_HW_FN ossl_cipher_hw_chunked_cfb8; +PROV_CIPHER_HW_FN ossl_cipher_hw_chunked_cfb128; +PROV_CIPHER_HW_FN ossl_cipher_hw_chunked_ofb128; +#define ossl_cipher_hw_chunked_ecb ossl_cipher_hw_generic_ecb +#define ossl_cipher_hw_chunked_ctr ossl_cipher_hw_generic_ctr +#define ossl_cipher_hw_chunked_cfb1 ossl_cipher_hw_generic_cfb1 + +#define IMPLEMENT_CIPHER_HW_OFB(MODE, NAME, CTX_NAME, KEY_NAME, FUNC_PREFIX) \ +static int cipher_hw_##NAME##_##MODE##_cipher(PROV_CIPHER_CTX *ctx, \ + unsigned char *out, \ + const unsigned char *in, size_t len) \ +{ \ + int num = ctx->num; \ + KEY_NAME *key = &(((CTX_NAME *)ctx)->ks.ks); \ + \ + while (len >= MAXCHUNK) { \ + FUNC_PREFIX##_encrypt(in, out, MAXCHUNK, key, ctx->iv, &num); \ + len -= MAXCHUNK; \ + in += MAXCHUNK; \ + out += MAXCHUNK; \ + } \ + if (len > 0) { \ + FUNC_PREFIX##_encrypt(in, out, (long)len, key, ctx->iv, &num); \ + } \ + ctx->num = num; \ + return 1; \ +} + +#define IMPLEMENT_CIPHER_HW_ECB(MODE, NAME, CTX_NAME, KEY_NAME, FUNC_PREFIX) \ +static int cipher_hw_##NAME##_##MODE##_cipher(PROV_CIPHER_CTX *ctx, \ + unsigned char *out, \ + const unsigned char *in, size_t len) \ +{ \ + size_t i, bl = ctx->blocksize; \ + KEY_NAME *key = &(((CTX_NAME *)ctx)->ks.ks); \ + \ + if (len < bl) \ + return 1; \ + for (i = 0, len -= bl; i <= len; i += bl) \ + FUNC_PREFIX##_encrypt(in + i, out + i, key, ctx->enc); \ + return 1; \ +} + +#define IMPLEMENT_CIPHER_HW_CBC(MODE, NAME, CTX_NAME, KEY_NAME, FUNC_PREFIX) \ +static int cipher_hw_##NAME##_##MODE##_cipher(PROV_CIPHER_CTX *ctx, \ + unsigned char *out, \ + const unsigned char *in, size_t len) \ +{ \ + KEY_NAME *key = &(((CTX_NAME *)ctx)->ks.ks); \ + \ + while (len >= MAXCHUNK) { \ + FUNC_PREFIX##_encrypt(in, out, MAXCHUNK, key, ctx->iv, ctx->enc); \ + len -= MAXCHUNK; \ + in += MAXCHUNK; \ + out += MAXCHUNK; \ + } \ + if (len > 0) \ + FUNC_PREFIX##_encrypt(in, out, (long)len, key, ctx->iv, ctx->enc); \ + return 1; \ +} + +#define IMPLEMENT_CIPHER_HW_CFB(MODE, NAME, CTX_NAME, KEY_NAME, FUNC_PREFIX) \ +static int cipher_hw_##NAME##_##MODE##_cipher(PROV_CIPHER_CTX *ctx, \ + unsigned char *out, \ + const unsigned char *in, size_t len) \ +{ \ + size_t chunk = MAXCHUNK; \ + KEY_NAME *key = &(((CTX_NAME *)ctx)->ks.ks); \ + int num = ctx->num; \ + \ + if (len < chunk) \ + chunk = len; \ + while (len > 0 && len >= chunk) { \ + FUNC_PREFIX##_encrypt(in, out, (long)chunk, key, ctx->iv, &num, \ + ctx->enc); \ + len -= chunk; \ + in += chunk; \ + out += chunk; \ + if (len < chunk) \ + chunk = len; \ + } \ + ctx->num = num; \ + return 1; \ +} + +#define IMPLEMENT_CIPHER_HW_COPYCTX(name, CTX_TYPE) \ +static void name(PROV_CIPHER_CTX *dst, const PROV_CIPHER_CTX *src) \ +{ \ + CTX_TYPE *sctx = (CTX_TYPE *)src; \ + CTX_TYPE *dctx = (CTX_TYPE *)dst; \ + \ + *dctx = *sctx; \ + dst->ks = &dctx->ks.ks; \ +} + +#define CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(name) \ +static const OSSL_PARAM name##_known_gettable_ctx_params[] = { \ + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), \ + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), \ + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_PADDING, NULL), \ + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_NUM, NULL), \ + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0), \ + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_UPDATED_IV, NULL, 0), + +#define CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(name) \ + OSSL_PARAM_END \ +}; \ +const OSSL_PARAM * name##_gettable_ctx_params(ossl_unused void *cctx, \ + ossl_unused void *provctx) \ +{ \ + return name##_known_gettable_ctx_params; \ +} + +#define CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(name) \ +static const OSSL_PARAM name##_known_settable_ctx_params[] = { \ + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_PADDING, NULL), \ + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_NUM, NULL), +#define CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(name) \ + OSSL_PARAM_END \ +}; \ +const OSSL_PARAM * name##_settable_ctx_params(ossl_unused void *cctx, \ + ossl_unused void *provctx) \ +{ \ + return name##_known_settable_ctx_params; \ +} + +int ossl_cipher_generic_initiv(PROV_CIPHER_CTX *ctx, const unsigned char *iv, + size_t ivlen); + +size_t ossl_cipher_fillblock(unsigned char *buf, size_t *buflen, + size_t blocksize, + const unsigned char **in, size_t *inlen); +int ossl_cipher_trailingdata(unsigned char *buf, size_t *buflen, + size_t blocksize, + const unsigned char **in, size_t *inlen); diff --git a/providers/implementations/include/prov/ciphercommon_aead.h b/providers/implementations/include/prov/ciphercommon_aead.h new file mode 100644 index 000000000000..1d017175d320 --- /dev/null +++ b/providers/implementations/include/prov/ciphercommon_aead.h @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#define UNINITIALISED_SIZET ((size_t)-1) + +#define AEAD_FLAGS (PROV_CIPHER_FLAG_AEAD | PROV_CIPHER_FLAG_CUSTOM_IV) + +#define IMPLEMENT_aead_cipher(alg, lc, UCMODE, flags, kbits, blkbits, ivbits) \ +static OSSL_FUNC_cipher_get_params_fn alg##_##kbits##_##lc##_get_params; \ +static int alg##_##kbits##_##lc##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, kbits, blkbits, ivbits); \ +} \ +static OSSL_FUNC_cipher_newctx_fn alg##kbits##lc##_newctx; \ +static void * alg##kbits##lc##_newctx(void *provctx) \ +{ \ + return alg##_##lc##_newctx(provctx, kbits); \ +} \ +const OSSL_DISPATCH ossl_##alg##kbits##lc##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))alg##kbits##lc##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))alg##_##lc##_freectx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))ossl_##lc##_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))ossl_##lc##_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))ossl_##lc##_stream_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))ossl_##lc##_stream_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_##lc##_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void)) alg##_##kbits##_##lc##_get_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void)) ossl_##lc##_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void)) ossl_##lc##_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))ossl_cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_aead_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))ossl_cipher_aead_settable_ctx_params }, \ + { 0, NULL } \ +} diff --git a/providers/implementations/include/prov/ciphercommon_ccm.h b/providers/implementations/include/prov/ciphercommon_ccm.h new file mode 100644 index 000000000000..4c184b395f44 --- /dev/null +++ b/providers/implementations/include/prov/ciphercommon_ccm.h @@ -0,0 +1,100 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "ciphercommon_aead.h" + +typedef struct prov_ccm_hw_st PROV_CCM_HW; + +#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__) +/*- + * KMAC-AES parameter block - begin + * (see z/Architecture Principles of Operation >= SA22-7832-08) + */ +typedef struct S390X_kmac_params_st { + union { + unsigned long long g[2]; + unsigned char b[16]; + } icv; + unsigned char k[32]; +} S390X_KMAC_PARAMS; +/* KMAC-AES parameter block - end */ +#endif + +/* Base structure that is shared by AES & ARIA for CCM MODE */ +typedef struct prov_ccm_st { + unsigned int enc : 1; + unsigned int key_set : 1; /* Set if key initialised */ + unsigned int iv_set : 1; /* Set if an iv is set */ + unsigned int tag_set : 1; /* Set if tag is valid */ + unsigned int len_set : 1; /* Set if message length set */ + size_t l, m; /* L and M parameters from RFC3610 */ + size_t keylen; + size_t tls_aad_len; /* TLS AAD length */ + size_t tls_aad_pad_sz; + unsigned char iv[GENERIC_BLOCK_SIZE]; + unsigned char buf[GENERIC_BLOCK_SIZE]; + CCM128_CONTEXT ccm_ctx; + ccm128_f str; + const PROV_CCM_HW *hw; /* hardware specific methods */ +} PROV_CCM_CTX; + +PROV_CIPHER_FUNC(int, CCM_cipher, (PROV_CCM_CTX *ctx, unsigned char *out, \ + size_t *padlen, const unsigned char *in, \ + size_t len)); +PROV_CIPHER_FUNC(int, CCM_setkey, (PROV_CCM_CTX *ctx, \ + const unsigned char *key, size_t keylen)); +PROV_CIPHER_FUNC(int, CCM_setiv, (PROV_CCM_CTX *dat, \ + const unsigned char *iv, size_t ivlen, \ + size_t mlen)); +PROV_CIPHER_FUNC(int, CCM_setaad, (PROV_CCM_CTX *ctx, \ + const unsigned char *aad, size_t aadlen)); +PROV_CIPHER_FUNC(int, CCM_auth_encrypt, (PROV_CCM_CTX *ctx, \ + const unsigned char *in, \ + unsigned char *out, size_t len, \ + unsigned char *tag, size_t taglen)); +PROV_CIPHER_FUNC(int, CCM_auth_decrypt, (PROV_CCM_CTX *ctx, \ + const unsigned char *in, \ + unsigned char *out, size_t len, \ + unsigned char *tag, size_t taglen)); +PROV_CIPHER_FUNC(int, CCM_gettag, (PROV_CCM_CTX *ctx, \ + unsigned char *tag, size_t taglen)); + +/* + * CCM Mode internal method table used to handle hardware specific differences, + * (and different algorithms). + */ +struct prov_ccm_hw_st { + OSSL_CCM_setkey_fn setkey; + OSSL_CCM_setiv_fn setiv; + OSSL_CCM_setaad_fn setaad; + OSSL_CCM_auth_encrypt_fn auth_encrypt; + OSSL_CCM_auth_decrypt_fn auth_decrypt; + OSSL_CCM_gettag_fn gettag; +}; + +OSSL_FUNC_cipher_encrypt_init_fn ossl_ccm_einit; +OSSL_FUNC_cipher_decrypt_init_fn ossl_ccm_dinit; +OSSL_FUNC_cipher_get_ctx_params_fn ossl_ccm_get_ctx_params; +OSSL_FUNC_cipher_set_ctx_params_fn ossl_ccm_set_ctx_params; +OSSL_FUNC_cipher_update_fn ossl_ccm_stream_update; +OSSL_FUNC_cipher_final_fn ossl_ccm_stream_final; +OSSL_FUNC_cipher_cipher_fn ossl_ccm_cipher; +void ossl_ccm_initctx(PROV_CCM_CTX *ctx, size_t keybits, const PROV_CCM_HW *hw); + +int ossl_ccm_generic_setiv(PROV_CCM_CTX *ctx, const unsigned char *nonce, + size_t nlen, size_t mlen); +int ossl_ccm_generic_setaad(PROV_CCM_CTX *ctx, const unsigned char *aad, + size_t alen); +int ossl_ccm_generic_gettag(PROV_CCM_CTX *ctx, unsigned char *tag, size_t tlen); +int ossl_ccm_generic_auth_encrypt(PROV_CCM_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len, + unsigned char *tag, size_t taglen); +int ossl_ccm_generic_auth_decrypt(PROV_CCM_CTX *ctx, const unsigned char *in, + unsigned char *out, size_t len, + unsigned char *expected_tag, size_t taglen); diff --git a/providers/implementations/include/prov/ciphercommon_gcm.h b/providers/implementations/include/prov/ciphercommon_gcm.h new file mode 100644 index 000000000000..7c4a548f9d44 --- /dev/null +++ b/providers/implementations/include/prov/ciphercommon_gcm.h @@ -0,0 +1,129 @@ + +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/aes.h> +#include "ciphercommon_aead.h" + +typedef struct prov_gcm_hw_st PROV_GCM_HW; + +#define GCM_IV_DEFAULT_SIZE 12 /* IV's for AES_GCM should normally be 12 bytes */ +#define GCM_IV_MAX_SIZE (1024 / 8) +#define GCM_TAG_MAX_SIZE 16 + +#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__) +/*- + * KMA-GCM-AES parameter block - begin + * (see z/Architecture Principles of Operation >= SA22-7832-11) + */ +typedef struct S390X_kma_params_st { + unsigned char reserved[12]; + union { + unsigned int w; + unsigned char b[4]; + } cv; /* 32 bit counter value */ + union { + unsigned long long g[2]; + unsigned char b[16]; + } t; /* tag */ + unsigned char h[16]; /* hash subkey */ + unsigned long long taadl; /* total AAD length */ + unsigned long long tpcl; /* total plaintxt/ciphertxt len */ + union { + unsigned long long g[2]; + unsigned int w[4]; + } j0; /* initial counter value */ + unsigned char k[32]; /* key */ +} S390X_KMA_PARAMS; + +#endif + +typedef struct prov_gcm_ctx_st { + unsigned int mode; /* The mode that we are using */ + size_t keylen; + size_t ivlen; + size_t taglen; + size_t tls_aad_pad_sz; + size_t tls_aad_len; /* TLS AAD length */ + uint64_t tls_enc_records; /* Number of TLS records encrypted */ + + /* + * num contains the number of bytes of |iv| which are valid for modes that + * manage partial blocks themselves. + */ + size_t num; + size_t bufsz; /* Number of bytes in buf */ + uint64_t flags; + + unsigned int iv_state; /* set to one of IV_STATE_XXX */ + unsigned int enc:1; /* Set to 1 if we are encrypting or 0 otherwise */ + unsigned int pad:1; /* Whether padding should be used or not */ + unsigned int key_set:1; /* Set if key initialised */ + unsigned int iv_gen_rand:1; /* No IV was specified, so generate a rand IV */ + unsigned int iv_gen:1; /* It is OK to generate IVs */ + + unsigned char iv[GCM_IV_MAX_SIZE]; /* Buffer to use for IV's */ + unsigned char buf[AES_BLOCK_SIZE]; /* Buffer of partial blocks processed via update calls */ + + OSSL_LIB_CTX *libctx; /* needed for rand calls */ + const PROV_GCM_HW *hw; /* hardware specific methods */ + GCM128_CONTEXT gcm; + ctr128_f ctr; + const void *ks; +} PROV_GCM_CTX; + +PROV_CIPHER_FUNC(int, GCM_setkey, (PROV_GCM_CTX *ctx, const unsigned char *key, + size_t keylen)); +PROV_CIPHER_FUNC(int, GCM_setiv, (PROV_GCM_CTX *dat, const unsigned char *iv, + size_t ivlen)); +PROV_CIPHER_FUNC(int, GCM_aadupdate, (PROV_GCM_CTX *ctx, + const unsigned char *aad, size_t aadlen)); +PROV_CIPHER_FUNC(int, GCM_cipherupdate, (PROV_GCM_CTX *ctx, + const unsigned char *in, size_t len, + unsigned char *out)); +PROV_CIPHER_FUNC(int, GCM_cipherfinal, (PROV_GCM_CTX *ctx, unsigned char *tag)); +PROV_CIPHER_FUNC(int, GCM_oneshot, (PROV_GCM_CTX *ctx, unsigned char *aad, + size_t aad_len, const unsigned char *in, + size_t in_len, unsigned char *out, + unsigned char *tag, size_t taglen)); +struct prov_gcm_hw_st { + OSSL_GCM_setkey_fn setkey; + OSSL_GCM_setiv_fn setiv; + OSSL_GCM_aadupdate_fn aadupdate; + OSSL_GCM_cipherupdate_fn cipherupdate; + OSSL_GCM_cipherfinal_fn cipherfinal; + OSSL_GCM_oneshot_fn oneshot; +}; + +OSSL_FUNC_cipher_encrypt_init_fn ossl_gcm_einit; +OSSL_FUNC_cipher_decrypt_init_fn ossl_gcm_dinit; +OSSL_FUNC_cipher_get_ctx_params_fn ossl_gcm_get_ctx_params; +OSSL_FUNC_cipher_set_ctx_params_fn ossl_gcm_set_ctx_params; +OSSL_FUNC_cipher_cipher_fn ossl_gcm_cipher; +OSSL_FUNC_cipher_update_fn ossl_gcm_stream_update; +OSSL_FUNC_cipher_final_fn ossl_gcm_stream_final; +void ossl_gcm_initctx(void *provctx, PROV_GCM_CTX *ctx, size_t keybits, + const PROV_GCM_HW *hw); + +int ossl_gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv, size_t ivlen); +int ossl_gcm_aad_update(PROV_GCM_CTX *ctx, const unsigned char *aad, + size_t aad_len); +int ossl_gcm_cipher_final(PROV_GCM_CTX *ctx, unsigned char *tag); +int ossl_gcm_one_shot(PROV_GCM_CTX *ctx, unsigned char *aad, size_t aad_len, + const unsigned char *in, size_t in_len, + unsigned char *out, unsigned char *tag, size_t tag_len); +int ossl_gcm_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in, + size_t len, unsigned char *out); + +#define GCM_HW_SET_KEY_CTR_FN(ks, fn_set_enc_key, fn_block, fn_ctr) \ + ctx->ks = ks; \ + fn_set_enc_key(key, keylen * 8, ks); \ + CRYPTO_gcm128_init(&ctx->gcm, ks, (block128_f)fn_block); \ + ctx->ctr = (ctr128_f)fn_ctr; \ + ctx->key_set = 1; diff --git a/providers/implementations/include/prov/digestcommon.h b/providers/implementations/include/prov/digestcommon.h new file mode 100644 index 000000000000..abdb8bb2ad55 --- /dev/null +++ b/providers/implementations/include/prov/digestcommon.h @@ -0,0 +1,126 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef OSSL_PROVIDERS_DIGESTCOMMON_H +# define OSSL_PROVIDERS_DIGESTCOMMON_H + +# include <openssl/core_dispatch.h> +# include <openssl/core_names.h> +# include <openssl/params.h> +# include "prov/providercommon.h" + +/* Internal flags that can be queried */ +#define PROV_DIGEST_FLAG_XOF 0x0001 +#define PROV_DIGEST_FLAG_ALGID_ABSENT 0x0002 + +# ifdef __cplusplus +extern "C" { +# endif + +#define PROV_FUNC_DIGEST_GET_PARAM(name, blksize, dgstsize, flags) \ +static OSSL_FUNC_digest_get_params_fn name##_get_params; \ +static int name##_get_params(OSSL_PARAM params[]) \ +{ \ + return ossl_digest_default_get_params(params, blksize, dgstsize, flags); \ +} + +#define PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(name) \ +{ OSSL_FUNC_DIGEST_GET_PARAMS, (void (*)(void))name##_get_params }, \ +{ OSSL_FUNC_DIGEST_GETTABLE_PARAMS, \ + (void (*)(void))ossl_digest_default_gettable_params } + +# define PROV_FUNC_DIGEST_FINAL(name, dgstsize, fin) \ +static OSSL_FUNC_digest_final_fn name##_internal_final; \ +static int name##_internal_final(void *ctx, unsigned char *out, size_t *outl, \ + size_t outsz) \ +{ \ + if (ossl_prov_is_running() && outsz >= dgstsize && fin(out, ctx)) { \ + *outl = dgstsize; \ + return 1; \ + } \ + return 0; \ +} + +# define PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_START( \ + name, CTX, blksize, dgstsize, flags, upd, fin) \ +static OSSL_FUNC_digest_newctx_fn name##_newctx; \ +static OSSL_FUNC_digest_freectx_fn name##_freectx; \ +static OSSL_FUNC_digest_dupctx_fn name##_dupctx; \ +static void *name##_newctx(void *prov_ctx) \ +{ \ + CTX *ctx = ossl_prov_is_running() ? OPENSSL_zalloc(sizeof(*ctx)) : NULL; \ + return ctx; \ +} \ +static void name##_freectx(void *vctx) \ +{ \ + CTX *ctx = (CTX *)vctx; \ + OPENSSL_clear_free(ctx, sizeof(*ctx)); \ +} \ +static void *name##_dupctx(void *ctx) \ +{ \ + CTX *in = (CTX *)ctx; \ + CTX *ret = ossl_prov_is_running() ? OPENSSL_malloc(sizeof(*ret)) : NULL; \ + if (ret != NULL) \ + *ret = *in; \ + return ret; \ +} \ +PROV_FUNC_DIGEST_FINAL(name, dgstsize, fin) \ +PROV_FUNC_DIGEST_GET_PARAM(name, blksize, dgstsize, flags) \ +const OSSL_DISPATCH ossl_##name##_functions[] = { \ + { OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))name##_newctx }, \ + { OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))upd }, \ + { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))name##_internal_final }, \ + { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))name##_freectx }, \ + { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))name##_dupctx }, \ + PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(name) + +# define PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END \ + { 0, NULL } \ +}; + +# define IMPLEMENT_digest_functions( \ + name, CTX, blksize, dgstsize, flags, init, upd, fin) \ +static OSSL_FUNC_digest_init_fn name##_internal_init; \ +static int name##_internal_init(void *ctx, \ + ossl_unused const OSSL_PARAM params[]) \ +{ \ + return ossl_prov_is_running() && init(ctx); \ +} \ +PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_START(name, CTX, blksize, dgstsize, flags, \ + upd, fin), \ + { OSSL_FUNC_DIGEST_INIT, (void (*)(void))name##_internal_init }, \ +PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END + +# define IMPLEMENT_digest_functions_with_settable_ctx( \ + name, CTX, blksize, dgstsize, flags, init, upd, fin, \ + settable_ctx_params, set_ctx_params) \ +static OSSL_FUNC_digest_init_fn name##_internal_init; \ +static int name##_internal_init(void *ctx, const OSSL_PARAM params[]) \ +{ \ + return ossl_prov_is_running() \ + && init(ctx) \ + && set_ctx_params(ctx, params); \ +} \ +PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_START(name, CTX, blksize, dgstsize, flags, \ + upd, fin), \ + { OSSL_FUNC_DIGEST_INIT, (void (*)(void))name##_internal_init }, \ + { OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS, (void (*)(void))settable_ctx_params }, \ + { OSSL_FUNC_DIGEST_SET_CTX_PARAMS, (void (*)(void))set_ctx_params }, \ +PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END + + +const OSSL_PARAM *ossl_digest_default_gettable_params(void *provctx); +int ossl_digest_default_get_params(OSSL_PARAM params[], size_t blksz, + size_t paramsz, unsigned long flags); + +# ifdef __cplusplus +} +# endif + +#endif /* OSSL_PROVIDERS_DIGESTCOMMON_H */ diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h new file mode 100644 index 000000000000..3f6dd7ee16b6 --- /dev/null +++ b/providers/implementations/include/prov/implementations.h @@ -0,0 +1,517 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/core.h> +#include <openssl/types.h> + +/* Digests */ +extern const OSSL_DISPATCH ossl_sha1_functions[]; +extern const OSSL_DISPATCH ossl_sha224_functions[]; +extern const OSSL_DISPATCH ossl_sha256_functions[]; +extern const OSSL_DISPATCH ossl_sha384_functions[]; +extern const OSSL_DISPATCH ossl_sha512_functions[]; +extern const OSSL_DISPATCH ossl_sha512_224_functions[]; +extern const OSSL_DISPATCH ossl_sha512_256_functions[]; +extern const OSSL_DISPATCH ossl_sha3_224_functions[]; +extern const OSSL_DISPATCH ossl_sha3_256_functions[]; +extern const OSSL_DISPATCH ossl_sha3_384_functions[]; +extern const OSSL_DISPATCH ossl_sha3_512_functions[]; +extern const OSSL_DISPATCH ossl_keccak_kmac_128_functions[]; +extern const OSSL_DISPATCH ossl_keccak_kmac_256_functions[]; +extern const OSSL_DISPATCH ossl_shake_128_functions[]; +extern const OSSL_DISPATCH ossl_shake_256_functions[]; +extern const OSSL_DISPATCH ossl_blake2s256_functions[]; +extern const OSSL_DISPATCH ossl_blake2b512_functions[]; +extern const OSSL_DISPATCH ossl_md5_functions[]; +extern const OSSL_DISPATCH ossl_md5_sha1_functions[]; +extern const OSSL_DISPATCH ossl_sm3_functions[]; +extern const OSSL_DISPATCH ossl_md2_functions[]; +extern const OSSL_DISPATCH ossl_md4_functions[]; +extern const OSSL_DISPATCH ossl_mdc2_functions[]; +extern const OSSL_DISPATCH ossl_wp_functions[]; +extern const OSSL_DISPATCH ossl_ripemd160_functions[]; +extern const OSSL_DISPATCH ossl_nullmd_functions[]; + +/* Ciphers */ +extern const OSSL_DISPATCH ossl_null_functions[]; +extern const OSSL_DISPATCH ossl_aes256ecb_functions[]; +extern const OSSL_DISPATCH ossl_aes192ecb_functions[]; +extern const OSSL_DISPATCH ossl_aes128ecb_functions[]; +extern const OSSL_DISPATCH ossl_aes256cbc_functions[]; +extern const OSSL_DISPATCH ossl_aes192cbc_functions[]; +extern const OSSL_DISPATCH ossl_aes128cbc_functions[]; +extern const OSSL_DISPATCH ossl_aes256cbc_cts_functions[]; +extern const OSSL_DISPATCH ossl_aes192cbc_cts_functions[]; +extern const OSSL_DISPATCH ossl_aes128cbc_cts_functions[]; +extern const OSSL_DISPATCH ossl_aes256ofb_functions[]; +extern const OSSL_DISPATCH ossl_aes192ofb_functions[]; +extern const OSSL_DISPATCH ossl_aes128ofb_functions[]; +extern const OSSL_DISPATCH ossl_aes256cfb_functions[]; +extern const OSSL_DISPATCH ossl_aes192cfb_functions[]; +extern const OSSL_DISPATCH ossl_aes128cfb_functions[]; +extern const OSSL_DISPATCH ossl_aes256cfb1_functions[]; +extern const OSSL_DISPATCH ossl_aes192cfb1_functions[]; +extern const OSSL_DISPATCH ossl_aes128cfb1_functions[]; +extern const OSSL_DISPATCH ossl_aes256cfb8_functions[]; +extern const OSSL_DISPATCH ossl_aes192cfb8_functions[]; +extern const OSSL_DISPATCH ossl_aes128cfb8_functions[]; +extern const OSSL_DISPATCH ossl_aes256ctr_functions[]; +extern const OSSL_DISPATCH ossl_aes192ctr_functions[]; +extern const OSSL_DISPATCH ossl_aes128ctr_functions[]; +extern const OSSL_DISPATCH ossl_aes256xts_functions[]; +extern const OSSL_DISPATCH ossl_aes128xts_functions[]; +#ifndef OPENSSL_NO_OCB +extern const OSSL_DISPATCH ossl_aes256ocb_functions[]; +extern const OSSL_DISPATCH ossl_aes192ocb_functions[]; +extern const OSSL_DISPATCH ossl_aes128ocb_functions[]; +#endif /* OPENSSL_NO_OCB */ +extern const OSSL_DISPATCH ossl_aes256gcm_functions[]; +extern const OSSL_DISPATCH ossl_aes192gcm_functions[]; +extern const OSSL_DISPATCH ossl_aes128gcm_functions[]; +extern const OSSL_DISPATCH ossl_aes256ccm_functions[]; +extern const OSSL_DISPATCH ossl_aes192ccm_functions[]; +extern const OSSL_DISPATCH ossl_aes128ccm_functions[]; +extern const OSSL_DISPATCH ossl_aes256wrap_functions[]; +extern const OSSL_DISPATCH ossl_aes192wrap_functions[]; +extern const OSSL_DISPATCH ossl_aes128wrap_functions[]; +extern const OSSL_DISPATCH ossl_aes256wrappad_functions[]; +extern const OSSL_DISPATCH ossl_aes192wrappad_functions[]; +extern const OSSL_DISPATCH ossl_aes128wrappad_functions[]; +extern const OSSL_DISPATCH ossl_aes256wrapinv_functions[]; +extern const OSSL_DISPATCH ossl_aes192wrapinv_functions[]; +extern const OSSL_DISPATCH ossl_aes128wrapinv_functions[]; +extern const OSSL_DISPATCH ossl_aes256wrappadinv_functions[]; +extern const OSSL_DISPATCH ossl_aes192wrappadinv_functions[]; +extern const OSSL_DISPATCH ossl_aes128wrappadinv_functions[]; +extern const OSSL_DISPATCH ossl_aes256cbc_hmac_sha1_functions[]; +extern const OSSL_DISPATCH ossl_aes128cbc_hmac_sha1_functions[]; +extern const OSSL_DISPATCH ossl_aes256cbc_hmac_sha256_functions[]; +extern const OSSL_DISPATCH ossl_aes128cbc_hmac_sha256_functions[]; + +#ifndef OPENSSL_NO_ARIA +extern const OSSL_DISPATCH ossl_aria256gcm_functions[]; +extern const OSSL_DISPATCH ossl_aria192gcm_functions[]; +extern const OSSL_DISPATCH ossl_aria128gcm_functions[]; +extern const OSSL_DISPATCH ossl_aria256ccm_functions[]; +extern const OSSL_DISPATCH ossl_aria192ccm_functions[]; +extern const OSSL_DISPATCH ossl_aria128ccm_functions[]; +extern const OSSL_DISPATCH ossl_aria256ecb_functions[]; +extern const OSSL_DISPATCH ossl_aria192ecb_functions[]; +extern const OSSL_DISPATCH ossl_aria128ecb_functions[]; +extern const OSSL_DISPATCH ossl_aria256cbc_functions[]; +extern const OSSL_DISPATCH ossl_aria192cbc_functions[]; +extern const OSSL_DISPATCH ossl_aria128cbc_functions[]; +extern const OSSL_DISPATCH ossl_aria256ofb_functions[]; +extern const OSSL_DISPATCH ossl_aria192ofb_functions[]; +extern const OSSL_DISPATCH ossl_aria128ofb_functions[]; +extern const OSSL_DISPATCH ossl_aria256cfb_functions[]; +extern const OSSL_DISPATCH ossl_aria192cfb_functions[]; +extern const OSSL_DISPATCH ossl_aria128cfb_functions[]; +extern const OSSL_DISPATCH ossl_aria256cfb1_functions[]; +extern const OSSL_DISPATCH ossl_aria192cfb1_functions[]; +extern const OSSL_DISPATCH ossl_aria128cfb1_functions[]; +extern const OSSL_DISPATCH ossl_aria256cfb8_functions[]; +extern const OSSL_DISPATCH ossl_aria192cfb8_functions[]; +extern const OSSL_DISPATCH ossl_aria128cfb8_functions[]; +extern const OSSL_DISPATCH ossl_aria256ctr_functions[]; +extern const OSSL_DISPATCH ossl_aria192ctr_functions[]; +extern const OSSL_DISPATCH ossl_aria128ctr_functions[]; +#endif /* OPENSSL_NO_ARIA */ +#ifndef OPENSSL_NO_CAMELLIA +extern const OSSL_DISPATCH ossl_camellia256ecb_functions[]; +extern const OSSL_DISPATCH ossl_camellia192ecb_functions[]; +extern const OSSL_DISPATCH ossl_camellia128ecb_functions[]; +extern const OSSL_DISPATCH ossl_camellia256cbc_functions[]; +extern const OSSL_DISPATCH ossl_camellia192cbc_functions[]; +extern const OSSL_DISPATCH ossl_camellia128cbc_functions[]; +extern const OSSL_DISPATCH ossl_camellia256cbc_cts_functions[]; +extern const OSSL_DISPATCH ossl_camellia192cbc_cts_functions[]; +extern const OSSL_DISPATCH ossl_camellia128cbc_cts_functions[]; +extern const OSSL_DISPATCH ossl_camellia256ofb_functions[]; +extern const OSSL_DISPATCH ossl_camellia192ofb_functions[]; +extern const OSSL_DISPATCH ossl_camellia128ofb_functions[]; +extern const OSSL_DISPATCH ossl_camellia256cfb_functions[]; +extern const OSSL_DISPATCH ossl_camellia192cfb_functions[]; +extern const OSSL_DISPATCH ossl_camellia128cfb_functions[]; +extern const OSSL_DISPATCH ossl_camellia256cfb1_functions[]; +extern const OSSL_DISPATCH ossl_camellia192cfb1_functions[]; +extern const OSSL_DISPATCH ossl_camellia128cfb1_functions[]; +extern const OSSL_DISPATCH ossl_camellia256cfb8_functions[]; +extern const OSSL_DISPATCH ossl_camellia192cfb8_functions[]; +extern const OSSL_DISPATCH ossl_camellia128cfb8_functions[]; +extern const OSSL_DISPATCH ossl_camellia256ctr_functions[]; +extern const OSSL_DISPATCH ossl_camellia192ctr_functions[]; +extern const OSSL_DISPATCH ossl_camellia128ctr_functions[]; +#endif /* OPENSSL_NO_CAMELLIA */ +#ifndef OPENSSL_NO_BF +extern const OSSL_DISPATCH ossl_blowfish128ecb_functions[]; +extern const OSSL_DISPATCH ossl_blowfish128cbc_functions[]; +extern const OSSL_DISPATCH ossl_blowfish128ofb64_functions[]; +extern const OSSL_DISPATCH ossl_blowfish128cfb64_functions[]; +#endif /* OPENSSL_NO_BF */ +#ifndef OPENSSL_NO_IDEA +extern const OSSL_DISPATCH ossl_idea128ecb_functions[]; +extern const OSSL_DISPATCH ossl_idea128cbc_functions[]; +extern const OSSL_DISPATCH ossl_idea128ofb64_functions[]; +extern const OSSL_DISPATCH ossl_idea128cfb64_functions[]; +#endif /* OPENSSL_NO_IDEA */ +#ifndef OPENSSL_NO_CAST +extern const OSSL_DISPATCH ossl_cast5128ecb_functions[]; +extern const OSSL_DISPATCH ossl_cast5128cbc_functions[]; +extern const OSSL_DISPATCH ossl_cast5128ofb64_functions[]; +extern const OSSL_DISPATCH ossl_cast5128cfb64_functions[]; +#endif /* OPENSSL_NO_CAST */ +#ifndef OPENSSL_NO_SEED +extern const OSSL_DISPATCH ossl_seed128ecb_functions[]; +extern const OSSL_DISPATCH ossl_seed128cbc_functions[]; +extern const OSSL_DISPATCH ossl_seed128ofb128_functions[]; +extern const OSSL_DISPATCH ossl_seed128cfb128_functions[]; +#endif /* OPENSSL_NO_SEED */ +#ifndef OPENSSL_NO_SM4 +extern const OSSL_DISPATCH ossl_sm4128ecb_functions[]; +extern const OSSL_DISPATCH ossl_sm4128cbc_functions[]; +extern const OSSL_DISPATCH ossl_sm4128ctr_functions[]; +extern const OSSL_DISPATCH ossl_sm4128ofb128_functions[]; +extern const OSSL_DISPATCH ossl_sm4128cfb128_functions[]; +#endif /* OPENSSL_NO_SM4 */ +#ifndef OPENSSL_NO_RC5 +extern const OSSL_DISPATCH ossl_rc5128ecb_functions[]; +extern const OSSL_DISPATCH ossl_rc5128cbc_functions[]; +extern const OSSL_DISPATCH ossl_rc5128ofb64_functions[]; +extern const OSSL_DISPATCH ossl_rc5128cfb64_functions[]; +#endif /* OPENSSL_NO_RC5 */ +#ifndef OPENSSL_NO_RC2 +extern const OSSL_DISPATCH ossl_rc2128ecb_functions[]; +extern const OSSL_DISPATCH ossl_rc2128cbc_functions[]; +extern const OSSL_DISPATCH ossl_rc240cbc_functions[]; +extern const OSSL_DISPATCH ossl_rc264cbc_functions[]; +extern const OSSL_DISPATCH ossl_rc2128cfb128_functions[]; +extern const OSSL_DISPATCH ossl_rc2128ofb128_functions[]; +#endif /* OPENSSL_NO_RC2 */ +#ifndef OPENSSL_NO_DES +extern const OSSL_DISPATCH ossl_tdes_ede3_ecb_functions[]; +extern const OSSL_DISPATCH ossl_tdes_ede3_cbc_functions[]; +# ifndef FIPS_MODULE +extern const OSSL_DISPATCH ossl_tdes_ede3_ofb_functions[]; +extern const OSSL_DISPATCH ossl_tdes_ede3_cfb_functions[]; +extern const OSSL_DISPATCH ossl_tdes_ede3_cfb8_functions[]; +extern const OSSL_DISPATCH ossl_tdes_ede3_cfb1_functions[]; + +extern const OSSL_DISPATCH ossl_tdes_ede2_ecb_functions[]; +extern const OSSL_DISPATCH ossl_tdes_ede2_cbc_functions[]; +extern const OSSL_DISPATCH ossl_tdes_ede2_ofb_functions[]; +extern const OSSL_DISPATCH ossl_tdes_ede2_cfb_functions[]; + +extern const OSSL_DISPATCH ossl_tdes_desx_cbc_functions[]; +extern const OSSL_DISPATCH ossl_tdes_wrap_cbc_functions[]; + +extern const OSSL_DISPATCH ossl_des_ecb_functions[]; +extern const OSSL_DISPATCH ossl_des_cbc_functions[]; +extern const OSSL_DISPATCH ossl_des_ofb64_functions[]; +extern const OSSL_DISPATCH ossl_des_cfb64_functions[]; +extern const OSSL_DISPATCH ossl_des_cfb1_functions[]; +extern const OSSL_DISPATCH ossl_des_cfb8_functions[]; +# endif /* FIPS_MODULE */ +#endif /* OPENSSL_NO_DES */ + +#ifndef OPENSSL_NO_RC4 +extern const OSSL_DISPATCH ossl_rc440_functions[]; +extern const OSSL_DISPATCH ossl_rc4128_functions[]; +# ifndef OPENSSL_NO_MD5 +extern const OSSL_DISPATCH ossl_rc4_hmac_ossl_md5_functions[]; +# endif /* OPENSSL_NO_MD5 */ +#endif /* OPENSSL_NO_RC4 */ +#ifndef OPENSSL_NO_CHACHA +extern const OSSL_DISPATCH ossl_chacha20_functions[]; +# ifndef OPENSSL_NO_POLY1305 +extern const OSSL_DISPATCH ossl_chacha20_ossl_poly1305_functions[]; +# endif /* OPENSSL_NO_POLY1305 */ +#endif /* OPENSSL_NO_CHACHA */ + + +#ifndef OPENSSL_NO_SIV +extern const OSSL_DISPATCH ossl_aes128siv_functions[]; +extern const OSSL_DISPATCH ossl_aes192siv_functions[]; +extern const OSSL_DISPATCH ossl_aes256siv_functions[]; +#endif /* OPENSSL_NO_SIV */ + +/* MACs */ +extern const OSSL_DISPATCH ossl_blake2bmac_functions[]; +extern const OSSL_DISPATCH ossl_blake2smac_functions[]; +extern const OSSL_DISPATCH ossl_cmac_functions[]; +extern const OSSL_DISPATCH ossl_gmac_functions[]; +extern const OSSL_DISPATCH ossl_hmac_functions[]; +extern const OSSL_DISPATCH ossl_kmac128_functions[]; +extern const OSSL_DISPATCH ossl_kmac256_functions[]; +extern const OSSL_DISPATCH ossl_siphash_functions[]; +extern const OSSL_DISPATCH ossl_poly1305_functions[]; + +/* KDFs / PRFs */ +extern const OSSL_DISPATCH ossl_kdf_pbkdf1_functions[]; +extern const OSSL_DISPATCH ossl_kdf_pbkdf2_functions[]; +extern const OSSL_DISPATCH ossl_kdf_pkcs12_functions[]; +#ifndef OPENSSL_NO_SCRYPT +extern const OSSL_DISPATCH ossl_kdf_scrypt_functions[]; +#endif +extern const OSSL_DISPATCH ossl_kdf_tls1_prf_functions[]; +extern const OSSL_DISPATCH ossl_kdf_hkdf_functions[]; +extern const OSSL_DISPATCH ossl_kdf_tls1_3_kdf_functions[]; +extern const OSSL_DISPATCH ossl_kdf_sshkdf_functions[]; +extern const OSSL_DISPATCH ossl_kdf_sskdf_functions[]; +extern const OSSL_DISPATCH ossl_kdf_x963_kdf_functions[]; +extern const OSSL_DISPATCH ossl_kdf_kbkdf_functions[]; +extern const OSSL_DISPATCH ossl_kdf_x942_kdf_functions[]; +extern const OSSL_DISPATCH ossl_kdf_krb5kdf_functions[]; + +/* RNGs */ +extern const OSSL_DISPATCH ossl_test_rng_functions[]; +extern const OSSL_DISPATCH ossl_seed_src_functions[]; +extern const OSSL_DISPATCH ossl_drbg_hash_functions[]; +extern const OSSL_DISPATCH ossl_drbg_ossl_hmac_functions[]; +extern const OSSL_DISPATCH ossl_drbg_ctr_functions[]; +extern const OSSL_DISPATCH crngt_functions[]; + +/* Key management */ +extern const OSSL_DISPATCH ossl_dh_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_dhx_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_dsa_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_rsa_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_rsapss_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_x25519_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_x448_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_ed25519_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_ed448_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_ec_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_kdf_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mac_legacy_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_cmac_legacy_keymgmt_functions[]; +#ifndef OPENSSL_NO_SM2 +extern const OSSL_DISPATCH ossl_sm2_keymgmt_functions[]; +#endif + +/* Key Exchange */ +extern const OSSL_DISPATCH ossl_dh_keyexch_functions[]; +extern const OSSL_DISPATCH ossl_x25519_keyexch_functions[]; +extern const OSSL_DISPATCH ossl_x448_keyexch_functions[]; +extern const OSSL_DISPATCH ossl_ecdh_keyexch_functions[]; +extern const OSSL_DISPATCH ossl_kdf_tls1_prf_keyexch_functions[]; +extern const OSSL_DISPATCH ossl_kdf_hkdf_keyexch_functions[]; +extern const OSSL_DISPATCH ossl_kdf_scrypt_keyexch_functions[]; + +/* Signature */ +extern const OSSL_DISPATCH ossl_dsa_signature_functions[]; +extern const OSSL_DISPATCH ossl_rsa_signature_functions[]; +extern const OSSL_DISPATCH ossl_ed25519_signature_functions[]; +extern const OSSL_DISPATCH ossl_ed448_signature_functions[]; +extern const OSSL_DISPATCH ossl_ecdsa_signature_functions[]; +extern const OSSL_DISPATCH ossl_mac_legacy_hmac_signature_functions[]; +extern const OSSL_DISPATCH ossl_mac_legacy_siphash_signature_functions[]; +extern const OSSL_DISPATCH ossl_mac_legacy_poly1305_signature_functions[]; +extern const OSSL_DISPATCH ossl_mac_legacy_cmac_signature_functions[]; +extern const OSSL_DISPATCH ossl_sm2_signature_functions[]; + +/* Asym Cipher */ +extern const OSSL_DISPATCH ossl_rsa_asym_cipher_functions[]; +#ifndef OPENSSL_NO_SM2 +extern const OSSL_DISPATCH ossl_sm2_asym_cipher_functions[]; +#endif + +/* Asym Key encapsulation */ +extern const OSSL_DISPATCH ossl_rsa_asym_kem_functions[]; + +/* Encoders */ +extern const OSSL_DISPATCH ossl_rsa_to_PKCS1_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_PKCS1_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_RSA_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_RSA_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_msblob_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_pvk_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_text_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_type_specific_keypair_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsa_to_type_specific_keypair_pem_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_rsapss_to_PKCS1_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsapss_to_PKCS1_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsapss_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsapss_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsapss_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsapss_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsapss_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsapss_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_rsapss_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_dh_to_DH_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_DH_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_PKCS3_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_PKCS3_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_type_specific_params_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_type_specific_params_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dh_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_dhx_to_DHX_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_DHX_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_X9_42_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_X9_42_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_type_specific_params_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_type_specific_params_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dhx_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_dsa_to_DSA_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_DSA_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_type_specific_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_type_specific_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_msblob_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_pvk_encoder_functions[]; +extern const OSSL_DISPATCH ossl_dsa_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_ec_to_EC_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_EC_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_blob_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_X9_62_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_X9_62_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_type_specific_no_pub_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_type_specific_no_pub_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ec_to_text_encoder_functions[]; + +#ifndef OPENSSL_NO_SM2 +extern const OSSL_DISPATCH ossl_sm2_to_SM2_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_SM2_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_blob_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_type_specific_no_pub_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_type_specific_no_pub_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_sm2_to_text_encoder_functions[]; +#endif + +extern const OSSL_DISPATCH ossl_ed25519_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed25519_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed25519_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed25519_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed25519_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed25519_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed25519_to_OSSL_current_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed25519_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_ed448_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed448_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed448_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed448_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed448_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed448_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed448_to_OSSL_current_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_ed448_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_x25519_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x25519_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x25519_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x25519_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x25519_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x25519_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x25519_to_OSSL_current_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x25519_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_x448_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x448_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x448_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x448_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x448_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x448_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x448_to_OSSL_current_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_x448_to_text_encoder_functions[]; + +/* Decoders */ +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_dh_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_dh_decoder_functions[]; +extern const OSSL_DISPATCH ossl_type_specific_params_der_to_dh_decoder_functions[]; +extern const OSSL_DISPATCH ossl_DH_der_to_dh_decoder_functions[]; + +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_dhx_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_dhx_decoder_functions[]; +extern const OSSL_DISPATCH ossl_type_specific_params_der_to_dhx_decoder_functions[]; +extern const OSSL_DISPATCH ossl_DHX_der_to_dhx_decoder_functions[]; + +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_dsa_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_dsa_decoder_functions[]; +extern const OSSL_DISPATCH ossl_type_specific_der_to_dsa_decoder_functions[]; +extern const OSSL_DISPATCH ossl_DSA_der_to_dsa_decoder_functions[]; +extern const OSSL_DISPATCH ossl_msblob_to_dsa_decoder_functions[]; +extern const OSSL_DISPATCH ossl_pvk_to_dsa_decoder_functions[]; + +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_ec_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ec_decoder_functions[]; +extern const OSSL_DISPATCH ossl_type_specific_no_pub_der_to_ec_decoder_functions[]; +extern const OSSL_DISPATCH ossl_EC_der_to_ec_decoder_functions[]; + +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_x25519_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_x25519_decoder_functions[]; + +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_x448_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_x448_decoder_functions[]; + +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_ed25519_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ed25519_decoder_functions[]; + +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_ed448_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ed448_decoder_functions[]; + +#ifndef OPENSSL_NO_SM2 +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_sm2_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_sm2_decoder_functions[]; +#endif + +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_rsa_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_rsa_decoder_functions[]; +extern const OSSL_DISPATCH ossl_type_specific_keypair_der_to_rsa_decoder_functions[]; +extern const OSSL_DISPATCH ossl_RSA_der_to_rsa_decoder_functions[]; +extern const OSSL_DISPATCH ossl_msblob_to_rsa_decoder_functions[]; +extern const OSSL_DISPATCH ossl_pvk_to_rsa_decoder_functions[]; + +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_rsapss_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_rsapss_decoder_functions[]; + +extern const OSSL_DISPATCH ossl_EncryptedPrivateKeyInfo_der_to_der_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_der_decoder_functions[]; +extern const OSSL_DISPATCH ossl_pem_to_der_decoder_functions[]; + +extern const OSSL_DISPATCH ossl_file_store_functions[]; diff --git a/providers/implementations/include/prov/kdfexchange.h b/providers/implementations/include/prov/kdfexchange.h new file mode 100644 index 000000000000..bfedd3afd364 --- /dev/null +++ b/providers/implementations/include/prov/kdfexchange.h @@ -0,0 +1,24 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <openssl/crypto.h> +#include "internal/refcount.h" + +struct kdf_data_st { + OSSL_LIB_CTX *libctx; + CRYPTO_REF_COUNT refcnt; + CRYPTO_RWLOCK *lock; +}; + +typedef struct kdf_data_st KDF_DATA; + +KDF_DATA *ossl_kdf_data_new(void *provctx); +void ossl_kdf_data_free(KDF_DATA *kdfdata); +int ossl_kdf_data_up_ref(KDF_DATA *kdfdata); diff --git a/providers/implementations/include/prov/macsignature.h b/providers/implementations/include/prov/macsignature.h new file mode 100644 index 000000000000..9bfaaf9b6e63 --- /dev/null +++ b/providers/implementations/include/prov/macsignature.h @@ -0,0 +1,30 @@ +/* + * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <openssl/crypto.h> +#include "internal/refcount.h" +#include "prov/provider_util.h" + +struct mac_key_st { + CRYPTO_RWLOCK *lock; + OSSL_LIB_CTX *libctx; + CRYPTO_REF_COUNT refcnt; + unsigned char *priv_key; + size_t priv_key_len; + PROV_CIPHER cipher; + char *properties; + int cmac; +}; + +typedef struct mac_key_st MAC_KEY; + +MAC_KEY *ossl_mac_key_new(OSSL_LIB_CTX *libctx, int cmac); +void ossl_mac_key_free(MAC_KEY *mackey); +int ossl_mac_key_up_ref(MAC_KEY *mackey); diff --git a/providers/implementations/include/prov/md5_sha1.h b/providers/implementations/include/prov/md5_sha1.h new file mode 100644 index 000000000000..181267d6b19f --- /dev/null +++ b/providers/implementations/include/prov/md5_sha1.h @@ -0,0 +1,36 @@ +/* + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef OSSL_PROV_MD5_SHA1_H +# define OSSL_PROV_MD5_SHA1_H + +# include <openssl/opensslconf.h> + +# ifndef OPENSSL_NO_MD5 +# include <openssl/e_os2.h> +# include <stddef.h> +# include <openssl/md5.h> +# include <openssl/sha.h> + +# define MD5_SHA1_DIGEST_LENGTH (MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH) +# define MD5_SHA1_CBLOCK MD5_CBLOCK + +typedef struct md5_sha1_st { + MD5_CTX md5; + SHA_CTX sha1; +} MD5_SHA1_CTX; + +int ossl_md5_sha1_init(MD5_SHA1_CTX *mctx); +int ossl_md5_sha1_update(MD5_SHA1_CTX *mctx, const void *data, size_t count); +int ossl_md5_sha1_final(unsigned char *md, MD5_SHA1_CTX *mctx); +int ossl_md5_sha1_ctrl(MD5_SHA1_CTX *mctx, int cmd, int mslen, void *ms); + +# endif /* OPENSSL_NO_MD5 */ + +#endif /* OSSL_PROV_MD5_SHA1_H */ diff --git a/providers/implementations/include/prov/names.h b/providers/implementations/include/prov/names.h new file mode 100644 index 000000000000..e0dbb69a9d8c --- /dev/null +++ b/providers/implementations/include/prov/names.h @@ -0,0 +1,327 @@ +/* + * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Macros for use as names and descriptions in our providers' OSSL_ALGORITHM. + * + * All the strings are formatted the same way: + * + * Our primary name[:other names][:numeric OID] + * + * 'other names' include historical OpenSSL names, NIST names, ASN.1 OBJECT + * IDENTIFIER names, and commonly known aliases. + * + * Where it matters, our primary names follow this format: + * + * ALGNAME[VERSION?][-SUBNAME[VERSION?]?][-SIZE?][-MODE?] + * + * VERSION is only present if there are multiple versions of + * an alg (MD2, MD4, MD5). It may be omitted if there is only + * one version (if a subsequent version is released in the future, + * we can always change the canonical name, and add the old name + * as an alias). + * + * SUBNAME may be present where we are combining multiple + * algorithms together, e.g. MD5-SHA1. + * + * SIZE is only present if multiple versions of an algorithm exist + * with different sizes (e.g. AES-128-CBC, AES-256-CBC) + * + * MODE is only present where applicable. + */ + +/*- + * Symmetric ciphers + * ----------------- + */ +#define PROV_NAMES_AES_256_ECB "AES-256-ECB:2.16.840.1.101.3.4.1.41" +#define PROV_NAMES_AES_192_ECB "AES-192-ECB:2.16.840.1.101.3.4.1.21" +#define PROV_NAMES_AES_128_ECB "AES-128-ECB:2.16.840.1.101.3.4.1.1" +#define PROV_NAMES_AES_256_CBC "AES-256-CBC:AES256:2.16.840.1.101.3.4.1.42" +#define PROV_NAMES_AES_192_CBC "AES-192-CBC:AES192:2.16.840.1.101.3.4.1.22" +#define PROV_NAMES_AES_128_CBC "AES-128-CBC:AES128:2.16.840.1.101.3.4.1.2" +#define PROV_NAMES_AES_256_CBC_CTS "AES-256-CBC-CTS" +#define PROV_NAMES_AES_192_CBC_CTS "AES-192-CBC-CTS" +#define PROV_NAMES_AES_128_CBC_CTS "AES-128-CBC-CTS" +#define PROV_NAMES_AES_256_OFB "AES-256-OFB:2.16.840.1.101.3.4.1.43" +#define PROV_NAMES_AES_192_OFB "AES-192-OFB:2.16.840.1.101.3.4.1.23" +#define PROV_NAMES_AES_128_OFB "AES-128-OFB:2.16.840.1.101.3.4.1.3" +#define PROV_NAMES_AES_256_CFB "AES-256-CFB:2.16.840.1.101.3.4.1.44" +#define PROV_NAMES_AES_192_CFB "AES-192-CFB:2.16.840.1.101.3.4.1.24" +#define PROV_NAMES_AES_128_CFB "AES-128-CFB:2.16.840.1.101.3.4.1.4" +#define PROV_NAMES_AES_256_CFB1 "AES-256-CFB1" +#define PROV_NAMES_AES_192_CFB1 "AES-192-CFB1" +#define PROV_NAMES_AES_128_CFB1 "AES-128-CFB1" +#define PROV_NAMES_AES_256_CFB8 "AES-256-CFB8" +#define PROV_NAMES_AES_192_CFB8 "AES-192-CFB8" +#define PROV_NAMES_AES_128_CFB8 "AES-128-CFB8" +#define PROV_NAMES_AES_256_CTR "AES-256-CTR" +#define PROV_NAMES_AES_192_CTR "AES-192-CTR" +#define PROV_NAMES_AES_128_CTR "AES-128-CTR" +#define PROV_NAMES_AES_256_XTS "AES-256-XTS:1.3.111.2.1619.0.1.2" +#define PROV_NAMES_AES_128_XTS "AES-128-XTS:1.3.111.2.1619.0.1.1" +#define PROV_NAMES_AES_256_GCM "AES-256-GCM:id-aes256-GCM:2.16.840.1.101.3.4.1.46" +#define PROV_NAMES_AES_192_GCM "AES-192-GCM:id-aes192-GCM:2.16.840.1.101.3.4.1.26" +#define PROV_NAMES_AES_128_GCM "AES-128-GCM:id-aes128-GCM:2.16.840.1.101.3.4.1.6" +#define PROV_NAMES_AES_256_CCM "AES-256-CCM:id-aes256-CCM:2.16.840.1.101.3.4.1.47" +#define PROV_NAMES_AES_192_CCM "AES-192-CCM:id-aes192-CCM:2.16.840.1.101.3.4.1.27" +#define PROV_NAMES_AES_128_CCM "AES-128-CCM:id-aes128-CCM:2.16.840.1.101.3.4.1.7" +#define PROV_NAMES_AES_256_WRAP "AES-256-WRAP:id-aes256-wrap:AES256-WRAP:2.16.840.1.101.3.4.1.45" +#define PROV_NAMES_AES_192_WRAP "AES-192-WRAP:id-aes192-wrap:AES192-WRAP:2.16.840.1.101.3.4.1.25" +#define PROV_NAMES_AES_128_WRAP "AES-128-WRAP:id-aes128-wrap:AES128-WRAP:2.16.840.1.101.3.4.1.5" +#define PROV_NAMES_AES_256_WRAP_PAD "AES-256-WRAP-PAD:id-aes256-wrap-pad:AES256-WRAP-PAD:2.16.840.1.101.3.4.1.48" +#define PROV_NAMES_AES_192_WRAP_PAD "AES-192-WRAP-PAD:id-aes192-wrap-pad:AES192-WRAP-PAD:2.16.840.1.101.3.4.1.28" +#define PROV_NAMES_AES_128_WRAP_PAD "AES-128-WRAP-PAD:id-aes128-wrap-pad:AES128-WRAP-PAD:2.16.840.1.101.3.4.1.8" +#define PROV_NAMES_AES_256_WRAP_INV "AES-256-WRAP-INV:AES256-WRAP-INV" +#define PROV_NAMES_AES_192_WRAP_INV "AES-192-WRAP-INV:AES192-WRAP-INV" +#define PROV_NAMES_AES_128_WRAP_INV "AES-128-WRAP-INV:AES128-WRAP-INV" +#define PROV_NAMES_AES_256_WRAP_PAD_INV "AES-256-WRAP-PAD-INV:AES256-WRAP-PAD-INV" +#define PROV_NAMES_AES_192_WRAP_PAD_INV "AES-192-WRAP-PAD-INV:AES192-WRAP-PAD-INV" +#define PROV_NAMES_AES_128_WRAP_PAD_INV "AES-128-WRAP-PAD-INV:AES128-WRAP-PAD-INV" +#define PROV_NAMES_AES_128_CBC_HMAC_SHA1 "AES-128-CBC-HMAC-SHA1" +#define PROV_NAMES_AES_256_CBC_HMAC_SHA1 "AES-256-CBC-HMAC-SHA1" +#define PROV_NAMES_AES_128_CBC_HMAC_SHA256 "AES-128-CBC-HMAC-SHA256" +#define PROV_NAMES_AES_256_CBC_HMAC_SHA256 "AES-256-CBC-HMAC-SHA256" +#define PROV_NAMES_DES_EDE3_ECB "DES-EDE3-ECB:DES-EDE3" +#define PROV_NAMES_DES_EDE3_CBC "DES-EDE3-CBC:DES3:1.2.840.113549.3.7" +#define PROV_NAMES_NULL "NULL" +#define PROV_NAMES_AES_256_OCB "AES-256-OCB" +#define PROV_NAMES_AES_192_OCB "AES-192-OCB" +#define PROV_NAMES_AES_128_OCB "AES-128-OCB" +#define PROV_NAMES_AES_128_SIV "AES-128-SIV" +#define PROV_NAMES_AES_192_SIV "AES-192-SIV" +#define PROV_NAMES_AES_256_SIV "AES-256-SIV" +#define PROV_NAMES_ARIA_256_GCM "ARIA-256-GCM:1.2.410.200046.1.1.36" +#define PROV_NAMES_ARIA_192_GCM "ARIA-192-GCM:1.2.410.200046.1.1.35" +#define PROV_NAMES_ARIA_128_GCM "ARIA-128-GCM:1.2.410.200046.1.1.34" +#define PROV_NAMES_ARIA_256_CCM "ARIA-256-CCM:1.2.410.200046.1.1.39" +#define PROV_NAMES_ARIA_192_CCM "ARIA-192-CCM:1.2.410.200046.1.1.38" +#define PROV_NAMES_ARIA_128_CCM "ARIA-128-CCM:1.2.410.200046.1.1.37" +#define PROV_NAMES_ARIA_256_ECB "ARIA-256-ECB:1.2.410.200046.1.1.11" +#define PROV_NAMES_ARIA_192_ECB "ARIA-192-ECB:1.2.410.200046.1.1.6" +#define PROV_NAMES_ARIA_128_ECB "ARIA-128-ECB:1.2.410.200046.1.1.1" +#define PROV_NAMES_ARIA_256_CBC "ARIA-256-CBC:ARIA256:1.2.410.200046.1.1.12" +#define PROV_NAMES_ARIA_192_CBC "ARIA-192-CBC:ARIA192:1.2.410.200046.1.1.7" +#define PROV_NAMES_ARIA_128_CBC "ARIA-128-CBC:ARIA128:1.2.410.200046.1.1.2" +#define PROV_NAMES_ARIA_256_OFB "ARIA-256-OFB:1.2.410.200046.1.1.14" +#define PROV_NAMES_ARIA_192_OFB "ARIA-192-OFB:1.2.410.200046.1.1.9" +#define PROV_NAMES_ARIA_128_OFB "ARIA-128-OFB:1.2.410.200046.1.1.4" +#define PROV_NAMES_ARIA_256_CFB "ARIA-256-CFB:1.2.410.200046.1.1.13" +#define PROV_NAMES_ARIA_192_CFB "ARIA-192-CFB:1.2.410.200046.1.1.8" +#define PROV_NAMES_ARIA_128_CFB "ARIA-128-CFB:1.2.410.200046.1.1.3" +#define PROV_NAMES_ARIA_256_CFB1 "ARIA-256-CFB1" +#define PROV_NAMES_ARIA_192_CFB1 "ARIA-192-CFB1" +#define PROV_NAMES_ARIA_128_CFB1 "ARIA-128-CFB1" +#define PROV_NAMES_ARIA_256_CFB8 "ARIA-256-CFB8" +#define PROV_NAMES_ARIA_192_CFB8 "ARIA-192-CFB8" +#define PROV_NAMES_ARIA_128_CFB8 "ARIA-128-CFB8" +#define PROV_NAMES_ARIA_256_CTR "ARIA-256-CTR:1.2.410.200046.1.1.15" +#define PROV_NAMES_ARIA_192_CTR "ARIA-192-CTR:1.2.410.200046.1.1.10" +#define PROV_NAMES_ARIA_128_CTR "ARIA-128-CTR:1.2.410.200046.1.1.5" +#define PROV_NAMES_CAMELLIA_256_ECB "CAMELLIA-256-ECB:0.3.4401.5.3.1.9.41" +#define PROV_NAMES_CAMELLIA_192_ECB "CAMELLIA-192-ECB:0.3.4401.5.3.1.9.21" +#define PROV_NAMES_CAMELLIA_128_ECB "CAMELLIA-128-ECB:0.3.4401.5.3.1.9.1" +#define PROV_NAMES_CAMELLIA_256_CBC "CAMELLIA-256-CBC:CAMELLIA256:1.2.392.200011.61.1.1.1.4" +#define PROV_NAMES_CAMELLIA_192_CBC "CAMELLIA-192-CBC:CAMELLIA192:1.2.392.200011.61.1.1.1.3" +#define PROV_NAMES_CAMELLIA_128_CBC "CAMELLIA-128-CBC:CAMELLIA128:1.2.392.200011.61.1.1.1.2" +#define PROV_NAMES_CAMELLIA_256_CBC_CTS "CAMELLIA-256-CBC-CTS" +#define PROV_NAMES_CAMELLIA_192_CBC_CTS "CAMELLIA-192-CBC-CTS" +#define PROV_NAMES_CAMELLIA_128_CBC_CTS "CAMELLIA-128-CBC-CTS" +#define PROV_NAMES_CAMELLIA_256_OFB "CAMELLIA-256-OFB:0.3.4401.5.3.1.9.43" +#define PROV_NAMES_CAMELLIA_192_OFB "CAMELLIA-192-OFB:0.3.4401.5.3.1.9.23" +#define PROV_NAMES_CAMELLIA_128_OFB "CAMELLIA-128-OFB:0.3.4401.5.3.1.9.3" +#define PROV_NAMES_CAMELLIA_256_CFB "CAMELLIA-256-CFB:0.3.4401.5.3.1.9.44" +#define PROV_NAMES_CAMELLIA_192_CFB "CAMELLIA-192-CFB:0.3.4401.5.3.1.9.24" +#define PROV_NAMES_CAMELLIA_128_CFB "CAMELLIA-128-CFB:0.3.4401.5.3.1.9.4" +#define PROV_NAMES_CAMELLIA_256_CFB1 "CAMELLIA-256-CFB1" +#define PROV_NAMES_CAMELLIA_192_CFB1 "CAMELLIA-192-CFB1" +#define PROV_NAMES_CAMELLIA_128_CFB1 "CAMELLIA-128-CFB1" +#define PROV_NAMES_CAMELLIA_256_CFB8 "CAMELLIA-256-CFB8" +#define PROV_NAMES_CAMELLIA_192_CFB8 "CAMELLIA-192-CFB8" +#define PROV_NAMES_CAMELLIA_128_CFB8 "CAMELLIA-128-CFB8" +#define PROV_NAMES_CAMELLIA_256_CTR "CAMELLIA-256-CTR:0.3.4401.5.3.1.9.49" +#define PROV_NAMES_CAMELLIA_192_CTR "CAMELLIA-192-CTR:0.3.4401.5.3.1.9.29" +#define PROV_NAMES_CAMELLIA_128_CTR "CAMELLIA-128-CTR:0.3.4401.5.3.1.9.9" +#define PROV_NAMES_DES_EDE3_OFB "DES-EDE3-OFB" +#define PROV_NAMES_DES_EDE3_CFB "DES-EDE3-CFB" +#define PROV_NAMES_DES_EDE3_CFB8 "DES-EDE3-CFB8" +#define PROV_NAMES_DES_EDE3_CFB1 "DES-EDE3-CFB1" +#define PROV_NAMES_DES3_WRAP "DES3-WRAP:id-smime-alg-CMS3DESwrap:1.2.840.113549.1.9.16.3.6" +#define PROV_NAMES_DES_EDE_ECB "DES-EDE-ECB:DES-EDE:1.3.14.3.2.17" +#define PROV_NAMES_DES_EDE_CBC "DES-EDE-CBC" +#define PROV_NAMES_DES_EDE_OFB "DES-EDE-OFB" +#define PROV_NAMES_DES_EDE_CFB "DES-EDE-CFB" +#define PROV_NAMES_SM4_ECB "SM4-ECB:1.2.156.10197.1.104.1" +#define PROV_NAMES_SM4_CBC "SM4-CBC:SM4:1.2.156.10197.1.104.2" +#define PROV_NAMES_SM4_CTR "SM4-CTR:1.2.156.10197.1.104.7" +#define PROV_NAMES_SM4_OFB "SM4-OFB:SM4-OFB128:1.2.156.10197.1.104.3" +#define PROV_NAMES_SM4_CFB "SM4-CFB:SM4-CFB128:1.2.156.10197.1.104.4" +#define PROV_NAMES_ChaCha20 "ChaCha20" +#define PROV_NAMES_ChaCha20_Poly1305 "ChaCha20-Poly1305" +#define PROV_NAMES_CAST5_ECB "CAST5-ECB" +#define PROV_NAMES_CAST5_CBC "CAST5-CBC:CAST-CBC:CAST:1.2.840.113533.7.66.10" +#define PROV_NAMES_CAST5_OFB "CAST5-OFB" +#define PROV_NAMES_CAST5_CFB "CAST5-CFB" +#define PROV_NAMES_BF_ECB "BF-ECB" +#define PROV_NAMES_BF_CBC "BF-CBC:BF:BLOWFISH:1.3.6.1.4.1.3029.1.2" +#define PROV_NAMES_BF_OFB "BF-OFB" +#define PROV_NAMES_BF_CFB "BF-CFB" +#define PROV_NAMES_IDEA_ECB "IDEA-ECB" +#define PROV_NAMES_IDEA_CBC "IDEA-CBC:IDEA:1.3.6.1.4.1.188.7.1.1.2" +#define PROV_NAMES_IDEA_OFB "IDEA-OFB:IDEA-OFB64" +#define PROV_NAMES_IDEA_CFB "IDEA-CFB:IDEA-CFB64" +#define PROV_NAMES_SEED_ECB "SEED-ECB:1.2.410.200004.1.3" +#define PROV_NAMES_SEED_CBC "SEED-CBC:SEED:1.2.410.200004.1.4" +#define PROV_NAMES_SEED_OFB "SEED-OFB:SEED-OFB128:1.2.410.200004.1.6" +#define PROV_NAMES_SEED_CFB "SEED-CFB:SEED-CFB128:1.2.410.200004.1.5" +#define PROV_NAMES_RC2_ECB "RC2-ECB" +#define PROV_NAMES_RC2_CBC "RC2-CBC:RC2:RC2-128:1.2.840.113549.3.2" +#define PROV_NAMES_RC2_40_CBC "RC2-40-CBC:RC2-40" +#define PROV_NAMES_RC2_64_CBC "RC2-64-CBC:RC2-64" +#define PROV_NAMES_RC2_CFB "RC2-CFB" +#define PROV_NAMES_RC2_OFB "RC2-OFB" +#define PROV_NAMES_RC4 "RC4:1.2.840.113549.3.4" +#define PROV_NAMES_RC4_40 "RC4-40" +#define PROV_NAMES_RC4_HMAC_MD5 "RC4-HMAC-MD5" +#define PROV_NAMES_RC5_ECB "RC5-ECB" +#define PROV_NAMES_RC5_CBC "RC5-CBC:RC5:1.2.840.113549.3.8" +#define PROV_NAMES_RC5_OFB "RC5-OFB" +#define PROV_NAMES_RC5_CFB "RC5-CFB" +#define PROV_NAMES_DESX_CBC "DESX-CBC:DESX" +#define PROV_NAMES_DES_ECB "DES-ECB:1.3.14.3.2.6" +#define PROV_NAMES_DES_CBC "DES-CBC:DES:1.3.14.3.2.7" +#define PROV_NAMES_DES_OFB "DES-OFB:1.3.14.3.2.8" +#define PROV_NAMES_DES_CFB "DES-CFB:1.3.14.3.2.9" +#define PROV_NAMES_DES_CFB1 "DES-CFB1" +#define PROV_NAMES_DES_CFB8 "DES-CFB8" + +/*- + * Digests + * ------- + */ +#define PROV_NAMES_SHA1 "SHA1:SHA-1:SSL3-SHA1:1.3.14.3.2.26" +#define PROV_NAMES_SHA2_224 "SHA2-224:SHA-224:SHA224:2.16.840.1.101.3.4.2.4" +#define PROV_NAMES_SHA2_256 "SHA2-256:SHA-256:SHA256:2.16.840.1.101.3.4.2.1" +#define PROV_NAMES_SHA2_384 "SHA2-384:SHA-384:SHA384:2.16.840.1.101.3.4.2.2" +#define PROV_NAMES_SHA2_512 "SHA2-512:SHA-512:SHA512:2.16.840.1.101.3.4.2.3" +#define PROV_NAMES_SHA2_512_224 "SHA2-512/224:SHA-512/224:SHA512-224:2.16.840.1.101.3.4.2.5" +#define PROV_NAMES_SHA2_512_256 "SHA2-512/256:SHA-512/256:SHA512-256:2.16.840.1.101.3.4.2.6" + +/* We agree with NIST here, so one name only */ +#define PROV_NAMES_SHA3_224 "SHA3-224:2.16.840.1.101.3.4.2.7" +#define PROV_NAMES_SHA3_256 "SHA3-256:2.16.840.1.101.3.4.2.8" +#define PROV_NAMES_SHA3_384 "SHA3-384:2.16.840.1.101.3.4.2.9" +#define PROV_NAMES_SHA3_512 "SHA3-512:2.16.840.1.101.3.4.2.10" + +#define PROV_NAMES_SHAKE_128 "SHAKE-128:SHAKE128:2.16.840.1.101.3.4.2.11" +#define PROV_NAMES_SHAKE_256 "SHAKE-256:SHAKE256:2.16.840.1.101.3.4.2.12" + +/* + * KECCAK-KMAC-128 and KECCAK-KMAC-256 as hashes are mostly useful for + * KMAC128 and KMAC256. + */ +#define PROV_NAMES_KECCAK_KMAC_128 "KECCAK-KMAC-128:KECCAK-KMAC128" +#define PROV_NAMES_KECCAK_KMAC_256 "KECCAK-KMAC-256:KECCAK-KMAC256" +/* + * https://blake2.net/ doesn't specify size variants, but mentions that + * Bouncy Castle uses the names BLAKE2b-160, BLAKE2b-256, BLAKE2b-384, and + * BLAKE2b-512 + * If we assume that "2b" and "2s" are versions, that pattern fits with ours. + * We also add our historical names. + */ +#define PROV_NAMES_BLAKE2S_256 "BLAKE2S-256:BLAKE2s256:1.3.6.1.4.1.1722.12.2.2.8" +#define PROV_NAMES_BLAKE2B_512 "BLAKE2B-512:BLAKE2b512:1.3.6.1.4.1.1722.12.2.1.16" +#define PROV_NAMES_SM3 "SM3:1.2.156.10197.1.401" +#define PROV_NAMES_MD5 "MD5:SSL3-MD5:1.2.840.113549.2.5" +#define PROV_NAMES_MD5_SHA1 "MD5-SHA1" +#define PROV_NAMES_MD2 "MD2:1.2.840.113549.2.2" +#define PROV_NAMES_MD4 "MD4:1.2.840.113549.2.4" +#define PROV_NAMES_MDC2 "MDC2:2.5.8.3.101" +#define PROV_NAMES_WHIRLPOOL "WHIRLPOOL:1.0.10118.3.0.55" +#define PROV_NAMES_RIPEMD_160 "RIPEMD-160:RIPEMD160:RIPEMD:RMD160:1.3.36.3.2.1" + +/*- + * KDFs / PRFs + * ----------- + */ +#define PROV_NAMES_HKDF "HKDF" +#define PROV_DESCS_HKDF_SIGN "OpenSSL HKDF via EVP_PKEY implementation" +#define PROV_NAMES_TLS1_3_KDF "TLS13-KDF" +#define PROV_NAMES_SSKDF "SSKDF" +#define PROV_NAMES_PBKDF1 "PBKDF1" +#define PROV_NAMES_PBKDF2 "PBKDF2:1.2.840.113549.1.5.12" +#define PROV_NAMES_SSHKDF "SSHKDF" +#define PROV_NAMES_X963KDF "X963KDF:X942KDF-CONCAT" +#define PROV_NAMES_X942KDF_ASN1 "X942KDF-ASN1:X942KDF" +#define PROV_NAMES_TLS1_PRF "TLS1-PRF" +#define PROV_DESCS_TLS1_PRF_SIGN "OpenSSL TLS1_PRF via EVP_PKEY implementation" +#define PROV_NAMES_KBKDF "KBKDF" +#define PROV_NAMES_PKCS12KDF "PKCS12KDF" +#define PROV_NAMES_SCRYPT "SCRYPT:id-scrypt:1.3.6.1.4.1.11591.4.11" +#define PROV_DESCS_SCRYPT_SIGN "OpenSSL SCRYPT via EVP_PKEY implementation" +#define PROV_NAMES_KRB5KDF "KRB5KDF" + +/*- + * MACs + * ---- + */ +#define PROV_NAMES_HMAC "HMAC" +#define PROV_DESCS_HMAC_SIGN "OpenSSL HMAC via EVP_PKEY implementation" +#define PROV_NAMES_CMAC "CMAC" +#define PROV_DESCS_CMAC_SIGN "OpenSSL CMAC via EVP_PKEY implementation" +#define PROV_NAMES_SIPHASH "SIPHASH" +#define PROV_DESCS_SIPHASH_SIGN "OpenSSL SIPHASH via EVP_PKEY implementation" +#define PROV_NAMES_POLY1305 "POLY1305" +#define PROV_DESCS_POLY1305_SIGN "OpenSSL POLY1305 via EVP_PKEY implementation" +#define PROV_NAMES_GMAC "GMAC:1.0.9797.3.4" +#define PROV_NAMES_KMAC_128 "KMAC-128:KMAC128:2.16.840.1.101.3.4.2.19" +#define PROV_NAMES_KMAC_256 "KMAC-256:KMAC256:2.16.840.1.101.3.4.2.20" +#define PROV_NAMES_BLAKE2BMAC "BLAKE2BMAC:1.3.6.1.4.1.1722.12.2.1" +#define PROV_NAMES_BLAKE2SMAC "BLAKE2SMAC:1.3.6.1.4.1.1722.12.2.2" + +/*- + * RANDs + * ----- + */ +#define PROV_NAMES_CTR_DRBG "CTR-DRBG" +#define PROV_NAMES_HASH_DRBG "HASH-DRBG" +#define PROV_NAMES_HMAC_DRBG "HMAC-DRBG" +#define PROV_NAMES_TEST_RAND "TEST-RAND" +#define PROV_NAMES_SEED_SRC "SEED-SRC" + +/*- + * Asymmetric algos + * ---------------- + */ +#define PROV_NAMES_EC "EC:id-ecPublicKey:1.2.840.10045.2.1" +#define PROV_DESCS_EC "OpenSSL EC implementation" +#define PROV_NAMES_ECDH "ECDH" +#define PROV_DESCS_ECDH "OpenSSL ECDH implementation" +#define PROV_NAMES_ECDSA "ECDSA" +#define PROV_DESCS_ECDSA "OpenSSL ECDSA implementation" +#define PROV_NAMES_X25519 "X25519:1.3.101.110" +#define PROV_DESCS_X25519 "OpenSSL X25519 implementation" +#define PROV_NAMES_X448 "X448:1.3.101.111" +#define PROV_DESCS_X448 "OpenSSL X448 implementation" +#define PROV_NAMES_ED25519 "ED25519:1.3.101.112" +#define PROV_DESCS_ED25519 "OpenSSL ED25519 implementation" +#define PROV_NAMES_ED448 "ED448:1.3.101.113" +#define PROV_DESCS_ED448 "OpenSSL ED448 implementation" +#define PROV_NAMES_DH "DH:dhKeyAgreement:1.2.840.113549.1.3.1" +#define PROV_DESCS_DH "OpenSSL PKCS#3 DH implementation" +#define PROV_NAMES_DHX "DHX:X9.42 DH:dhpublicnumber:1.2.840.10046.2.1" +#define PROV_DESCS_DHX "OpenSSL X9.42 DH implementation" +#define PROV_NAMES_DSA "DSA:dsaEncryption:1.2.840.10040.4.1" +#define PROV_DESCS_DSA "OpenSSL DSA implementation" +#define PROV_NAMES_RSA "RSA:rsaEncryption:1.2.840.113549.1.1.1" +#define PROV_DESCS_RSA "OpenSSL RSA implementation" +#define PROV_NAMES_RSA_PSS "RSA-PSS:RSASSA-PSS:1.2.840.113549.1.1.10" +#define PROV_DESCS_RSA_PSS "OpenSSL RSA-PSS implementation" +#define PROV_NAMES_SM2 "SM2:1.2.156.10197.1.301" +#define PROV_DESCS_SM2 "OpenSSL SM2 implementation" diff --git a/providers/implementations/include/prov/seeding.h b/providers/implementations/include/prov/seeding.h new file mode 100644 index 000000000000..637b921b2b52 --- /dev/null +++ b/providers/implementations/include/prov/seeding.h @@ -0,0 +1,41 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/provider_ctx.h" +#include "crypto/rand_pool.h" + +/* Hardware-based seeding functions. */ +size_t ossl_prov_acquire_entropy_from_tsc(RAND_POOL *pool); +size_t ossl_prov_acquire_entropy_from_cpu(RAND_POOL *pool); + +/* + * Add some platform specific additional data + * + * This function is platform specific and adds some random noise to the + * additional data used for generating random bytes and for reseeding + * the drbg. + * + * Returns 1 on success and 0 on failure. + */ +int ossl_rand_pool_add_additional_data(RAND_POOL *pool); + +/* + * External seeding functions from the core dispatch table. + */ +int ossl_prov_seeding_from_dispatch(const OSSL_DISPATCH *fns); + +size_t ossl_prov_get_entropy(PROV_CTX *prov_ctx, unsigned char **pout, + int entropy, size_t min_len, size_t max_len); +void ossl_prov_cleanup_entropy(PROV_CTX *prov_ctx, unsigned char *buf, + size_t len); +size_t ossl_prov_get_nonce(PROV_CTX *prov_ctx, unsigned char **pout, + size_t min_len, size_t max_len, + const void *salt, size_t salt_len); +void ossl_prov_cleanup_nonce(PROV_CTX *prov_ctx, unsigned char *buf, + size_t len); diff --git a/providers/implementations/kdfs/build.info b/providers/implementations/kdfs/build.info new file mode 100644 index 000000000000..f4620adce2df --- /dev/null +++ b/providers/implementations/kdfs/build.info @@ -0,0 +1,38 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$TLS1_PRF_GOAL=../../libdefault.a ../../libfips.a +$HKDF_GOAL=../../libdefault.a ../../libfips.a +$KBKDF_GOAL=../../libdefault.a ../../libfips.a +$KRB5KDF_GOAL=../../libdefault.a +$PBKDF1_GOAL=../../liblegacy.a +$PBKDF2_GOAL=../../libdefault.a ../../libfips.a +$PKCS12KDF_GOAL=../../libdefault.a +$SSKDF_GOAL=../../libdefault.a ../../libfips.a +$SCRYPT_GOAL=../../libdefault.a +$SSHKDF_GOAL=../../libdefault.a ../../libfips.a +$X942KDF_GOAL=../../libdefault.a ../../libfips.a + +SOURCE[$TLS1_PRF_GOAL]=tls1_prf.c + +SOURCE[$HKDF_GOAL]=hkdf.c + +SOURCE[$KBKDF_GOAL]=kbkdf.c + +SOURCE[$KRB5KDF_GOAL]=krb5kdf.c + +SOURCE[$PBKDF1_GOAL]=pbkdf1.c + +SOURCE[$PBKDF2_GOAL]=pbkdf2.c +# Extra code to satisfy the FIPS and non-FIPS separation. +# When the PBKDF2 moves to legacy, this can be removed. +SOURCE[$PBKDF2_GOAL]=pbkdf2_fips.c + +SOURCE[$PKCS12KDF_GOAL]=pkcs12kdf.c + +SOURCE[$SSKDF_GOAL]=sskdf.c + +SOURCE[$SCRYPT_GOAL]=scrypt.c +SOURCE[$SSHKDF_GOAL]=sshkdf.c +SOURCE[$X942KDF_GOAL]=x942kdf.c +DEPEND[x942kdf.o]=../../common/include/prov/der_wrap.h diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c new file mode 100644 index 000000000000..dfa7786bde0c --- /dev/null +++ b/providers/implementations/kdfs/hkdf.c @@ -0,0 +1,783 @@ +/* + * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * HMAC low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <openssl/hmac.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include <openssl/core_names.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" +#include "internal/numbers.h" +#include "internal/packet.h" +#include "crypto/evp.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_util.h" +#include "e_os.h" + +#define HKDF_MAXBUF 2048 +#define HKDF_MAXINFO (32*1024) + +static OSSL_FUNC_kdf_newctx_fn kdf_hkdf_new; +static OSSL_FUNC_kdf_freectx_fn kdf_hkdf_free; +static OSSL_FUNC_kdf_reset_fn kdf_hkdf_reset; +static OSSL_FUNC_kdf_derive_fn kdf_hkdf_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_hkdf_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kdf_hkdf_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_hkdf_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn kdf_hkdf_get_ctx_params; +static OSSL_FUNC_kdf_derive_fn kdf_tls1_3_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_tls1_3_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kdf_tls1_3_set_ctx_params; + +static int HKDF(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md, + const unsigned char *salt, size_t salt_len, + const unsigned char *key, size_t key_len, + const unsigned char *info, size_t info_len, + unsigned char *okm, size_t okm_len); +static int HKDF_Extract(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md, + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + unsigned char *prk, size_t prk_len); +static int HKDF_Expand(const EVP_MD *evp_md, + const unsigned char *prk, size_t prk_len, + const unsigned char *info, size_t info_len, + unsigned char *okm, size_t okm_len); + +/* Settable context parameters that are common across HKDF and the TLS KDF */ +#define HKDF_COMMON_SETTABLES \ + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0), \ + OSSL_PARAM_int(OSSL_KDF_PARAM_MODE, NULL), \ + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), \ + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), \ + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), \ + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0) + +typedef struct { + void *provctx; + int mode; + PROV_DIGEST digest; + unsigned char *salt; + size_t salt_len; + unsigned char *key; + size_t key_len; + unsigned char *prefix; + size_t prefix_len; + unsigned char *label; + size_t label_len; + unsigned char *data; + size_t data_len; + unsigned char *info; + size_t info_len; +} KDF_HKDF; + +static void *kdf_hkdf_new(void *provctx) +{ + KDF_HKDF *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + else + ctx->provctx = provctx; + return ctx; +} + +static void kdf_hkdf_free(void *vctx) +{ + KDF_HKDF *ctx = (KDF_HKDF *)vctx; + + if (ctx != NULL) { + kdf_hkdf_reset(ctx); + OPENSSL_free(ctx); + } +} + +static void kdf_hkdf_reset(void *vctx) +{ + KDF_HKDF *ctx = (KDF_HKDF *)vctx; + void *provctx = ctx->provctx; + + ossl_prov_digest_reset(&ctx->digest); + OPENSSL_free(ctx->salt); + OPENSSL_free(ctx->prefix); + OPENSSL_free(ctx->label); + OPENSSL_clear_free(ctx->data, ctx->data_len); + OPENSSL_clear_free(ctx->key, ctx->key_len); + OPENSSL_clear_free(ctx->info, ctx->info_len); + memset(ctx, 0, sizeof(*ctx)); + ctx->provctx = provctx; +} + +static size_t kdf_hkdf_size(KDF_HKDF *ctx) +{ + int sz; + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + + if (ctx->mode != EVP_KDF_HKDF_MODE_EXTRACT_ONLY) + return SIZE_MAX; + + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + sz = EVP_MD_get_size(md); + if (sz < 0) + return 0; + + return sz; +} + +static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_HKDF *ctx = (KDF_HKDF *)vctx; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const EVP_MD *md; + + if (!ossl_prov_is_running() || !kdf_hkdf_set_ctx_params(ctx, params)) + return 0; + + md = ossl_prov_digest_md(&ctx->digest); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + if (ctx->key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return 0; + } + if (keylen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + + switch (ctx->mode) { + case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND: + default: + return HKDF(libctx, md, ctx->salt, ctx->salt_len, + ctx->key, ctx->key_len, ctx->info, ctx->info_len, key, keylen); + + case EVP_KDF_HKDF_MODE_EXTRACT_ONLY: + return HKDF_Extract(libctx, md, ctx->salt, ctx->salt_len, + ctx->key, ctx->key_len, key, keylen); + + case EVP_KDF_HKDF_MODE_EXPAND_ONLY: + return HKDF_Expand(md, ctx->key, ctx->key_len, ctx->info, + ctx->info_len, key, keylen); + } +} + +static int hkdf_common_set_ctx_params(KDF_HKDF *ctx, const OSSL_PARAM params[]) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const OSSL_PARAM *p; + int n; + + if (params == NULL) + return 1; + + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE)) != NULL) { + if (p->data_type == OSSL_PARAM_UTF8_STRING) { + if (OPENSSL_strcasecmp(p->data, "EXTRACT_AND_EXPAND") == 0) { + ctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND; + } else if (OPENSSL_strcasecmp(p->data, "EXTRACT_ONLY") == 0) { + ctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY; + } else if (OPENSSL_strcasecmp(p->data, "EXPAND_ONLY") == 0) { + ctx->mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY; + } else { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return 0; + } + } else if (OSSL_PARAM_get_int(p, &n)) { + if (n != EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND + && n != EVP_KDF_HKDF_MODE_EXTRACT_ONLY + && n != EVP_KDF_HKDF_MODE_EXPAND_ONLY) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return 0; + } + ctx->mode = n; + } else { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return 0; + } + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) { + OPENSSL_clear_free(ctx->key, ctx->key_len); + ctx->key = NULL; + if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->key, 0, + &ctx->key_len)) + return 0; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) { + if (p->data_size != 0 && p->data != NULL) { + OPENSSL_free(ctx->salt); + ctx->salt = NULL; + if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->salt, 0, + &ctx->salt_len)) + return 0; + } + } + + return 1; +} + +/* + * Use WPACKET to concat one or more OSSL_KDF_PARAM_INFO fields into a fixed + * out buffer of size *outlen. + * If out is NULL then outlen is used to return the required buffer size. + */ +static int setinfo_fromparams(const OSSL_PARAM *p, unsigned char *out, size_t *outlen) +{ + int ret = 0; + WPACKET pkt; + + if (out == NULL) { + if (!WPACKET_init_null(&pkt, 0)) + return 0; + } else { + if (!WPACKET_init_static_len(&pkt, out, *outlen, 0)) + return 0; + } + + for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1, OSSL_KDF_PARAM_INFO)) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) + goto err; + if (p->data != NULL + && p->data_size != 0 + && !WPACKET_memcpy(&pkt, p->data, p->data_size)) + goto err; + } + if (!WPACKET_get_total_written(&pkt, outlen) + || !WPACKET_finish(&pkt)) + goto err; + ret = 1; +err: + WPACKET_cleanup(&pkt); + return ret; +} + +static int kdf_hkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_HKDF *ctx = vctx; + + if (params == NULL) + return 1; + + if (!hkdf_common_set_ctx_params(ctx, params)) + return 0; + + /* The info fields concatenate, so process them all */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO)) != NULL) { + size_t sz = 0; + + /* calculate the total size */ + if (!setinfo_fromparams(p, NULL, &sz)) + return 0; + if (sz > HKDF_MAXINFO) + return 0; + + OPENSSL_clear_free(ctx->info, ctx->info_len); + ctx->info = NULL; + if (sz == 0) + return 1; + /* Alloc the buffer */ + ctx->info = OPENSSL_malloc(sz); + if (ctx->info == NULL) + return 0; + ctx->info_len = sz; + /* Concat one or more OSSL_KDF_PARAM_INFO fields */ + if (!setinfo_fromparams(p, ctx->info, &sz)) + return 0; + } + return 1; +} + +static const OSSL_PARAM *kdf_hkdf_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + HKDF_COMMON_SETTABLES, + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + KDF_HKDF *ctx = (KDF_HKDF *)vctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) { + size_t sz = kdf_hkdf_size(ctx); + + if (sz == 0) + return 0; + return OSSL_PARAM_set_size_t(p, sz); + } + return -2; +} + +static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_hkdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_hkdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_hkdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_hkdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_hkdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_hkdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_hkdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_hkdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_hkdf_get_ctx_params }, + { 0, NULL } +}; + +/* + * Refer to "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)" + * Section 2 (https://tools.ietf.org/html/rfc5869#section-2) and + * "Cryptographic Extraction and Key Derivation: The HKDF Scheme" + * Section 4.2 (https://eprint.iacr.org/2010/264.pdf). + * + * From the paper: + * The scheme HKDF is specified as: + * HKDF(XTS, SKM, CTXinfo, L) = K(1) | K(2) | ... | K(t) + * + * where: + * SKM is source key material + * XTS is extractor salt (which may be null or constant) + * CTXinfo is context information (may be null) + * L is the number of key bits to be produced by KDF + * k is the output length in bits of the hash function used with HMAC + * t = ceil(L/k) + * the value K(t) is truncated to its first d = L mod k bits. + * + * From RFC 5869: + * 2.2. Step 1: Extract + * HKDF-Extract(salt, IKM) -> PRK + * 2.3. Step 2: Expand + * HKDF-Expand(PRK, info, L) -> OKM + */ +static int HKDF(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md, + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + const unsigned char *info, size_t info_len, + unsigned char *okm, size_t okm_len) +{ + unsigned char prk[EVP_MAX_MD_SIZE]; + int ret, sz; + size_t prk_len; + + sz = EVP_MD_get_size(evp_md); + if (sz < 0) + return 0; + prk_len = (size_t)sz; + + /* Step 1: HKDF-Extract(salt, IKM) -> PRK */ + if (!HKDF_Extract(libctx, evp_md, + salt, salt_len, ikm, ikm_len, prk, prk_len)) + return 0; + + /* Step 2: HKDF-Expand(PRK, info, L) -> OKM */ + ret = HKDF_Expand(evp_md, prk, prk_len, info, info_len, okm, okm_len); + OPENSSL_cleanse(prk, sizeof(prk)); + + return ret; +} + +/* + * Refer to "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)" + * Section 2.2 (https://tools.ietf.org/html/rfc5869#section-2.2). + * + * 2.2. Step 1: Extract + * + * HKDF-Extract(salt, IKM) -> PRK + * + * Options: + * Hash a hash function; HashLen denotes the length of the + * hash function output in octets + * + * Inputs: + * salt optional salt value (a non-secret random value); + * if not provided, it is set to a string of HashLen zeros. + * IKM input keying material + * + * Output: + * PRK a pseudorandom key (of HashLen octets) + * + * The output PRK is calculated as follows: + * + * PRK = HMAC-Hash(salt, IKM) + */ +static int HKDF_Extract(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md, + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + unsigned char *prk, size_t prk_len) +{ + int sz = EVP_MD_get_size(evp_md); + + if (sz < 0) + return 0; + if (prk_len != (size_t)sz) { + ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE); + return 0; + } + /* calc: PRK = HMAC-Hash(salt, IKM) */ + return + EVP_Q_mac(libctx, "HMAC", NULL, EVP_MD_get0_name(evp_md), NULL, salt, + salt_len, ikm, ikm_len, prk, EVP_MD_get_size(evp_md), NULL) + != NULL; +} + +/* + * Refer to "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)" + * Section 2.3 (https://tools.ietf.org/html/rfc5869#section-2.3). + * + * 2.3. Step 2: Expand + * + * HKDF-Expand(PRK, info, L) -> OKM + * + * Options: + * Hash a hash function; HashLen denotes the length of the + * hash function output in octets + * + * Inputs: + * PRK a pseudorandom key of at least HashLen octets + * (usually, the output from the extract step) + * info optional context and application specific information + * (can be a zero-length string) + * L length of output keying material in octets + * (<= 255*HashLen) + * + * Output: + * OKM output keying material (of L octets) + * + * The output OKM is calculated as follows: + * + * N = ceil(L/HashLen) + * T = T(1) | T(2) | T(3) | ... | T(N) + * OKM = first L octets of T + * + * where: + * T(0) = empty string (zero length) + * T(1) = HMAC-Hash(PRK, T(0) | info | 0x01) + * T(2) = HMAC-Hash(PRK, T(1) | info | 0x02) + * T(3) = HMAC-Hash(PRK, T(2) | info | 0x03) + * ... + * + * (where the constant concatenated to the end of each T(n) is a + * single octet.) + */ +static int HKDF_Expand(const EVP_MD *evp_md, + const unsigned char *prk, size_t prk_len, + const unsigned char *info, size_t info_len, + unsigned char *okm, size_t okm_len) +{ + HMAC_CTX *hmac; + int ret = 0, sz; + unsigned int i; + unsigned char prev[EVP_MAX_MD_SIZE]; + size_t done_len = 0, dig_len, n; + + sz = EVP_MD_get_size(evp_md); + if (sz <= 0) + return 0; + dig_len = (size_t)sz; + + /* calc: N = ceil(L/HashLen) */ + n = okm_len / dig_len; + if (okm_len % dig_len) + n++; + + if (n > 255 || okm == NULL) + return 0; + + if ((hmac = HMAC_CTX_new()) == NULL) + return 0; + + if (!HMAC_Init_ex(hmac, prk, prk_len, evp_md, NULL)) + goto err; + + for (i = 1; i <= n; i++) { + size_t copy_len; + const unsigned char ctr = i; + + /* calc: T(i) = HMAC-Hash(PRK, T(i - 1) | info | i) */ + if (i > 1) { + if (!HMAC_Init_ex(hmac, NULL, 0, NULL, NULL)) + goto err; + + if (!HMAC_Update(hmac, prev, dig_len)) + goto err; + } + + if (!HMAC_Update(hmac, info, info_len)) + goto err; + + if (!HMAC_Update(hmac, &ctr, 1)) + goto err; + + if (!HMAC_Final(hmac, prev, NULL)) + goto err; + + copy_len = (done_len + dig_len > okm_len) ? + okm_len - done_len : + dig_len; + + memcpy(okm + done_len, prev, copy_len); + + done_len += copy_len; + } + ret = 1; + + err: + OPENSSL_cleanse(prev, sizeof(prev)); + HMAC_CTX_free(hmac); + return ret; +} + +/* + * TLS uses slight variations of the above and for FIPS validation purposes, + * they need to be present here. + * Refer to RFC 8446 section 7 for specific details. + */ + +/* + * Given a |secret|; a |label| of length |labellen|; and |data| of length + * |datalen| (e.g. typically a hash of the handshake messages), derive a new + * secret |outlen| bytes long and store it in the location pointed to be |out|. + * The |data| value may be zero length. Returns 1 on success and 0 on failure. + */ +static int prov_tls13_hkdf_expand(const EVP_MD *md, + const unsigned char *key, size_t keylen, + const unsigned char *prefix, size_t prefixlen, + const unsigned char *label, size_t labellen, + const unsigned char *data, size_t datalen, + unsigned char *out, size_t outlen) +{ + size_t hkdflabellen; + unsigned char hkdflabel[HKDF_MAXBUF]; + WPACKET pkt; + + /* + * 2 bytes for length of derived secret + 1 byte for length of combined + * prefix and label + bytes for the label itself + 1 byte length of hash + * + bytes for the hash itself. We've got the maximum the KDF can handle + * which should always be sufficient. + */ + if (!WPACKET_init_static_len(&pkt, hkdflabel, sizeof(hkdflabel), 0) + || !WPACKET_put_bytes_u16(&pkt, outlen) + || !WPACKET_start_sub_packet_u8(&pkt) + || !WPACKET_memcpy(&pkt, prefix, prefixlen) + || !WPACKET_memcpy(&pkt, label, labellen) + || !WPACKET_close(&pkt) + || !WPACKET_sub_memcpy_u8(&pkt, data, (data == NULL) ? 0 : datalen) + || !WPACKET_get_total_written(&pkt, &hkdflabellen) + || !WPACKET_finish(&pkt)) { + WPACKET_cleanup(&pkt); + return 0; + } + + return HKDF_Expand(md, key, keylen, hkdflabel, hkdflabellen, + out, outlen); +} + +static int prov_tls13_hkdf_generate_secret(OSSL_LIB_CTX *libctx, + const EVP_MD *md, + const unsigned char *prevsecret, + size_t prevsecretlen, + const unsigned char *insecret, + size_t insecretlen, + const unsigned char *prefix, + size_t prefixlen, + const unsigned char *label, + size_t labellen, + unsigned char *out, size_t outlen) +{ + size_t mdlen; + int ret; + unsigned char preextractsec[EVP_MAX_MD_SIZE]; + /* Always filled with zeros */ + static const unsigned char default_zeros[EVP_MAX_MD_SIZE]; + + ret = EVP_MD_get_size(md); + /* Ensure cast to size_t is safe */ + if (ret <= 0) + return 0; + mdlen = (size_t)ret; + + if (insecret == NULL) { + insecret = default_zeros; + insecretlen = mdlen; + } + if (prevsecret == NULL) { + prevsecret = default_zeros; + prevsecretlen = 0; + } else { + EVP_MD_CTX *mctx = EVP_MD_CTX_new(); + unsigned char hash[EVP_MAX_MD_SIZE]; + + /* The pre-extract derive step uses a hash of no messages */ + if (mctx == NULL + || EVP_DigestInit_ex(mctx, md, NULL) <= 0 + || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) { + EVP_MD_CTX_free(mctx); + return 0; + } + EVP_MD_CTX_free(mctx); + + /* Generate the pre-extract secret */ + if (!prov_tls13_hkdf_expand(md, prevsecret, mdlen, + prefix, prefixlen, label, labellen, + hash, mdlen, preextractsec, mdlen)) + return 0; + prevsecret = preextractsec; + prevsecretlen = mdlen; + } + + ret = HKDF_Extract(libctx, md, prevsecret, prevsecretlen, + insecret, insecretlen, out, outlen); + + if (prevsecret == preextractsec) + OPENSSL_cleanse(preextractsec, mdlen); + return ret; +} + +static int kdf_tls1_3_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_HKDF *ctx = (KDF_HKDF *)vctx; + const EVP_MD *md; + + if (!ossl_prov_is_running() || !kdf_tls1_3_set_ctx_params(ctx, params)) + return 0; + + md = ossl_prov_digest_md(&ctx->digest); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + + switch (ctx->mode) { + default: + return 0; + + case EVP_KDF_HKDF_MODE_EXTRACT_ONLY: + return prov_tls13_hkdf_generate_secret(PROV_LIBCTX_OF(ctx->provctx), + md, + ctx->salt, ctx->salt_len, + ctx->key, ctx->key_len, + ctx->prefix, ctx->prefix_len, + ctx->label, ctx->label_len, + key, keylen); + + case EVP_KDF_HKDF_MODE_EXPAND_ONLY: + return prov_tls13_hkdf_expand(md, ctx->key, ctx->key_len, + ctx->prefix, ctx->prefix_len, + ctx->label, ctx->label_len, + ctx->data, ctx->data_len, + key, keylen); + } +} + +static int kdf_tls1_3_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_HKDF *ctx = vctx; + + if (params == NULL) + return 1; + + if (!hkdf_common_set_ctx_params(ctx, params)) + return 0; + + if (ctx->mode == EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return 0; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PREFIX)) != NULL) { + OPENSSL_free(ctx->prefix); + ctx->prefix = NULL; + if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->prefix, 0, + &ctx->prefix_len)) + return 0; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_LABEL)) != NULL) { + OPENSSL_free(ctx->label); + ctx->label = NULL; + if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->label, 0, + &ctx->label_len)) + return 0; + } + + OPENSSL_clear_free(ctx->data, ctx->data_len); + ctx->data = NULL; + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DATA)) != NULL + && !OSSL_PARAM_get_octet_string(p, (void **)&ctx->data, 0, + &ctx->data_len)) + return 0; + return 1; +} + +static const OSSL_PARAM *kdf_tls1_3_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + HKDF_COMMON_SETTABLES, + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PREFIX, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_LABEL, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_DATA, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_tls1_3_kdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_hkdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_hkdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_hkdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_tls1_3_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_tls1_3_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_tls1_3_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_hkdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_hkdf_get_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/kdfs/kbkdf.c b/providers/implementations/kdfs/kbkdf.c new file mode 100644 index 000000000000..a542f84dfa5b --- /dev/null +++ b/providers/implementations/kdfs/kbkdf.c @@ -0,0 +1,395 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019 Red Hat, Inc. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This implements https://csrc.nist.gov/publications/detail/sp/800-108/final + * section 5.1 ("counter mode") and section 5.2 ("feedback mode") in both HMAC + * and CMAC. That document does not name the KDFs it defines; the name is + * derived from + * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Key-Derivation + * + * Note that section 5.3 ("double-pipeline mode") is not implemented, though + * it would be possible to do so in the future. + * + * These versions all assume the counter is used. It would be relatively + * straightforward to expose a configuration handle should the need arise. + * + * Variable names attempt to match those of SP800-108. + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <openssl/core_names.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> +#include <openssl/kdf.h> +#include <openssl/params.h> +#include <openssl/proverr.h> + +#include "internal/cryptlib.h" +#include "crypto/evp.h" +#include "internal/numbers.h" +#include "internal/endian.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/provider_util.h" +#include "prov/providercommon.h" + +#include "e_os.h" + +#define ossl_min(a, b) ((a) < (b)) ? (a) : (b) + +typedef enum { + COUNTER = 0, + FEEDBACK +} kbkdf_mode; + +/* Our context structure. */ +typedef struct { + void *provctx; + kbkdf_mode mode; + EVP_MAC_CTX *ctx_init; + + /* Names are lowercased versions of those found in SP800-108. */ + unsigned char *ki; + size_t ki_len; + unsigned char *label; + size_t label_len; + unsigned char *context; + size_t context_len; + unsigned char *iv; + size_t iv_len; + int use_l; + int use_separator; +} KBKDF; + +/* Definitions needed for typechecking. */ +static OSSL_FUNC_kdf_newctx_fn kbkdf_new; +static OSSL_FUNC_kdf_freectx_fn kbkdf_free; +static OSSL_FUNC_kdf_reset_fn kbkdf_reset; +static OSSL_FUNC_kdf_derive_fn kbkdf_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kbkdf_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kbkdf_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn kbkdf_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn kbkdf_get_ctx_params; + +/* Not all platforms have htobe32(). */ +static uint32_t be32(uint32_t host) +{ + uint32_t big = 0; + DECLARE_IS_ENDIAN; + + if (!IS_LITTLE_ENDIAN) + return host; + + big |= (host & 0xff000000) >> 24; + big |= (host & 0x00ff0000) >> 8; + big |= (host & 0x0000ff00) << 8; + big |= (host & 0x000000ff) << 24; + return big; +} + +static void init(KBKDF *ctx) +{ + ctx->use_l = 1; + ctx->use_separator = 1; +} + +static void *kbkdf_new(void *provctx) +{ + KBKDF *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ctx->provctx = provctx; + init(ctx); + return ctx; +} + +static void kbkdf_free(void *vctx) +{ + KBKDF *ctx = (KBKDF *)vctx; + + if (ctx != NULL) { + kbkdf_reset(ctx); + OPENSSL_free(ctx); + } +} + +static void kbkdf_reset(void *vctx) +{ + KBKDF *ctx = (KBKDF *)vctx; + void *provctx = ctx->provctx; + + EVP_MAC_CTX_free(ctx->ctx_init); + OPENSSL_clear_free(ctx->context, ctx->context_len); + OPENSSL_clear_free(ctx->label, ctx->label_len); + OPENSSL_clear_free(ctx->ki, ctx->ki_len); + OPENSSL_clear_free(ctx->iv, ctx->iv_len); + memset(ctx, 0, sizeof(*ctx)); + ctx->provctx = provctx; + init(ctx); +} + +/* SP800-108 section 5.1 or section 5.2 depending on mode. */ +static int derive(EVP_MAC_CTX *ctx_init, kbkdf_mode mode, unsigned char *iv, + size_t iv_len, unsigned char *label, size_t label_len, + unsigned char *context, size_t context_len, + unsigned char *k_i, size_t h, uint32_t l, int has_separator, + unsigned char *ko, size_t ko_len) +{ + int ret = 0; + EVP_MAC_CTX *ctx = NULL; + size_t written = 0, to_write, k_i_len = iv_len; + const unsigned char zero = 0; + uint32_t counter, i; + /* + * From SP800-108: + * The fixed input data is a concatenation of a Label, + * a separation indicator 0x00, the Context, and L. + * One or more of these fixed input data fields may be omitted. + * + * has_separator == 0 means that the separator is omitted. + * Passing a value of l == 0 means that L is omitted. + * The Context and L are omitted automatically if a NULL buffer is passed. + */ + int has_l = (l != 0); + + /* Setup K(0) for feedback mode. */ + if (iv_len > 0) + memcpy(k_i, iv, iv_len); + + for (counter = 1; written < ko_len; counter++) { + i = be32(counter); + + ctx = EVP_MAC_CTX_dup(ctx_init); + if (ctx == NULL) + goto done; + + /* Perform feedback, if appropriate. */ + if (mode == FEEDBACK && !EVP_MAC_update(ctx, k_i, k_i_len)) + goto done; + + if (!EVP_MAC_update(ctx, (unsigned char *)&i, 4) + || !EVP_MAC_update(ctx, label, label_len) + || (has_separator && !EVP_MAC_update(ctx, &zero, 1)) + || !EVP_MAC_update(ctx, context, context_len) + || (has_l && !EVP_MAC_update(ctx, (unsigned char *)&l, 4)) + || !EVP_MAC_final(ctx, k_i, NULL, h)) + goto done; + + to_write = ko_len - written; + memcpy(ko + written, k_i, ossl_min(to_write, h)); + written += h; + + k_i_len = h; + EVP_MAC_CTX_free(ctx); + ctx = NULL; + } + + ret = 1; +done: + EVP_MAC_CTX_free(ctx); + return ret; +} + +static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KBKDF *ctx = (KBKDF *)vctx; + int ret = 0; + unsigned char *k_i = NULL; + uint32_t l = 0; + size_t h = 0; + + if (!ossl_prov_is_running() || !kbkdf_set_ctx_params(ctx, params)) + return 0; + + /* label, context, and iv are permitted to be empty. Check everything + * else. */ + if (ctx->ctx_init == NULL) { + if (ctx->ki_len == 0 || ctx->ki == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } + /* Could either be missing MAC or missing message digest or missing + * cipher - arbitrarily, I pick this one. */ + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MAC); + return 0; + } + + /* Fail if the output length is zero */ + if (keylen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + + h = EVP_MAC_CTX_get_mac_size(ctx->ctx_init); + if (h == 0) + goto done; + if (ctx->iv_len != 0 && ctx->iv_len != h) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH); + goto done; + } + + if (ctx->use_l != 0) + l = be32(keylen * 8); + + k_i = OPENSSL_zalloc(h); + if (k_i == NULL) + goto done; + + ret = derive(ctx->ctx_init, ctx->mode, ctx->iv, ctx->iv_len, ctx->label, + ctx->label_len, ctx->context, ctx->context_len, k_i, h, l, + ctx->use_separator, key, keylen); +done: + if (ret != 1) + OPENSSL_cleanse(key, keylen); + OPENSSL_clear_free(k_i, h); + return ret; +} + +static int kbkdf_set_buffer(unsigned char **out, size_t *out_len, + const OSSL_PARAM *p) +{ + if (p->data == NULL || p->data_size == 0) + return 1; + + OPENSSL_clear_free(*out, *out_len); + *out = NULL; + return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len); +} + +static int kbkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + KBKDF *ctx = (KBKDF *)vctx; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + if (!ossl_prov_macctx_load_from_params(&ctx->ctx_init, params, NULL, + NULL, NULL, libctx)) + return 0; + else if (ctx->ctx_init != NULL + && !EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->ctx_init), + OSSL_MAC_NAME_HMAC) + && !EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->ctx_init), + OSSL_MAC_NAME_CMAC)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MAC); + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE); + if (p != NULL + && OPENSSL_strncasecmp("counter", p->data, p->data_size) == 0) { + ctx->mode = COUNTER; + } else if (p != NULL + && OPENSSL_strncasecmp("feedback", p->data, p->data_size) == 0) { + ctx->mode = FEEDBACK; + } else if (p != NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY); + if (p != NULL && !kbkdf_set_buffer(&ctx->ki, &ctx->ki_len, p)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT); + if (p != NULL && !kbkdf_set_buffer(&ctx->label, &ctx->label_len, p)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO); + if (p != NULL && !kbkdf_set_buffer(&ctx->context, &ctx->context_len, p)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SEED); + if (p != NULL && !kbkdf_set_buffer(&ctx->iv, &ctx->iv_len, p)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KBKDF_USE_L); + if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->use_l)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR); + if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->use_separator)) + return 0; + + /* Set up digest context, if we can. */ + if (ctx->ctx_init != NULL && ctx->ki_len != 0 + && !EVP_MAC_init(ctx->ctx_init, ctx->ki, ctx->ki_len, NULL)) + return 0; + return 1; +} + +static const OSSL_PARAM *kbkdf_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MAC, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_int(OSSL_KDF_PARAM_KBKDF_USE_L, NULL), + OSSL_PARAM_int(OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR, NULL), + OSSL_PARAM_END, + }; + return known_settable_ctx_params; +} + +static int kbkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE); + if (p == NULL) + return -2; + + /* KBKDF can produce results as large as you like. */ + return OSSL_PARAM_set_size_t(p, SIZE_MAX); +} + +static const OSSL_PARAM *kbkdf_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = + { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), OSSL_PARAM_END }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_kbkdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kbkdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kbkdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kbkdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kbkdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kbkdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kbkdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kbkdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kbkdf_get_ctx_params }, + { 0, NULL }, +}; diff --git a/providers/implementations/kdfs/krb5kdf.c b/providers/implementations/kdfs/krb5kdf.c new file mode 100644 index 000000000000..8516a3f824af --- /dev/null +++ b/providers/implementations/kdfs/krb5kdf.c @@ -0,0 +1,467 @@ +/* + * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DES low level APIs are deprecated for public use, but still ok for internal + * use. We access the DES_set_odd_parity(3) function here. + */ +#include "internal/deprecated.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include <openssl/core_names.h> +#include <openssl/des.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include <openssl/proverr.h> + +#include "internal/cryptlib.h" +#include "crypto/evp.h" +#include "internal/numbers.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/provider_util.h" +#include "prov/providercommon.h" + +/* KRB5 KDF defined in RFC 3961, Section 5.1 */ + +static OSSL_FUNC_kdf_newctx_fn krb5kdf_new; +static OSSL_FUNC_kdf_freectx_fn krb5kdf_free; +static OSSL_FUNC_kdf_reset_fn krb5kdf_reset; +static OSSL_FUNC_kdf_derive_fn krb5kdf_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn krb5kdf_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn krb5kdf_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn krb5kdf_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn krb5kdf_get_ctx_params; + +static int KRB5KDF(const EVP_CIPHER *cipher, ENGINE *engine, + const unsigned char *key, size_t key_len, + const unsigned char *constant, size_t constant_len, + unsigned char *okey, size_t okey_len); + +typedef struct { + void *provctx; + PROV_CIPHER cipher; + unsigned char *key; + size_t key_len; + unsigned char *constant; + size_t constant_len; +} KRB5KDF_CTX; + +static void *krb5kdf_new(void *provctx) +{ + KRB5KDF_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + ctx->provctx = provctx; + return ctx; +} + +static void krb5kdf_free(void *vctx) +{ + KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx; + + if (ctx != NULL) { + krb5kdf_reset(ctx); + OPENSSL_free(ctx); + } +} + +static void krb5kdf_reset(void *vctx) +{ + KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx; + void *provctx = ctx->provctx; + + ossl_prov_cipher_reset(&ctx->cipher); + OPENSSL_clear_free(ctx->key, ctx->key_len); + OPENSSL_clear_free(ctx->constant, ctx->constant_len); + memset(ctx, 0, sizeof(*ctx)); + ctx->provctx = provctx; +} + +static int krb5kdf_set_membuf(unsigned char **dst, size_t *dst_len, + const OSSL_PARAM *p) +{ + OPENSSL_clear_free(*dst, *dst_len); + *dst = NULL; + *dst_len = 0; + return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len); +} + +static int krb5kdf_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx; + const EVP_CIPHER *cipher; + ENGINE *engine; + + if (!ossl_prov_is_running() || !krb5kdf_set_ctx_params(ctx, params)) + return 0; + + cipher = ossl_prov_cipher_cipher(&ctx->cipher); + if (cipher == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CIPHER); + return 0; + } + if (ctx->key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return 0; + } + if (ctx->constant == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CONSTANT); + return 0; + } + engine = ossl_prov_cipher_engine(&ctx->cipher); + return KRB5KDF(cipher, engine, ctx->key, ctx->key_len, + ctx->constant, ctx->constant_len, + key, keylen); +} + +static int krb5kdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KRB5KDF_CTX *ctx = vctx; + OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx); + + if (params == NULL) + return 1; + + if (!ossl_prov_cipher_load_from_params(&ctx->cipher, params, provctx)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) + if (!krb5kdf_set_membuf(&ctx->key, &ctx->key_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CONSTANT)) + != NULL) + if (!krb5kdf_set_membuf(&ctx->constant, &ctx->constant_len, p)) + return 0; + + return 1; +} + +static const OSSL_PARAM *krb5kdf_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_CONSTANT, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int krb5kdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx; + const EVP_CIPHER *cipher; + size_t len; + OSSL_PARAM *p; + + cipher = ossl_prov_cipher_cipher(&ctx->cipher); + if (cipher) + len = EVP_CIPHER_get_key_length(cipher); + else + len = EVP_MAX_KEY_LENGTH; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, len); + return -2; +} + +static const OSSL_PARAM *krb5kdf_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_krb5kdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))krb5kdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))krb5kdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))krb5kdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))krb5kdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))krb5kdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, + (void(*)(void))krb5kdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))krb5kdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, + (void(*)(void))krb5kdf_get_ctx_params }, + { 0, NULL } +}; + +#ifndef OPENSSL_NO_DES +/* + * DES3 is a special case, it requires a random-to-key function and its + * input truncated to 21 bytes of the 24 produced by the cipher. + * See RFC3961 6.3.1 + */ +static int fixup_des3_key(unsigned char *key) +{ + unsigned char *cblock; + int i, j; + + for (i = 2; i >= 0; i--) { + cblock = &key[i * 8]; + memmove(cblock, &key[i * 7], 7); + cblock[7] = 0; + for (j = 0; j < 7; j++) + cblock[7] |= (cblock[j] & 1) << (j + 1); + DES_set_odd_parity((DES_cblock *)cblock); + } + + /* fail if keys are such that triple des degrades to single des */ + if (CRYPTO_memcmp(&key[0], &key[8], 8) == 0 || + CRYPTO_memcmp(&key[8], &key[16], 8) == 0) { + return 0; + } + + return 1; +} +#endif + +/* + * N-fold(K) where blocksize is N, and constant_len is K + * Note: Here |= denotes concatenation + * + * L = lcm(N,K) + * R = L/K + * + * for r: 1 -> R + * s |= constant rot 13*(r-1)) + * + * block = 0 + * for k: 1 -> K + * block += s[N(k-1)..(N-1)k] (one's complement addition) + * + * Optimizing for space we compute: + * for each l in L-1 -> 0: + * s[l] = (constant rot 13*(l/K))[l%k] + * block[l % N] += s[l] (with carry) + * finally add carry if any + */ +static void n_fold(unsigned char *block, unsigned int blocksize, + const unsigned char *constant, size_t constant_len) +{ + unsigned int tmp, gcd, remainder, lcm, carry; + int b, l; + + if (constant_len == blocksize) { + memcpy(block, constant, constant_len); + return; + } + + /* Least Common Multiple of lengths: LCM(a,b)*/ + gcd = blocksize; + remainder = constant_len; + /* Calculate Great Common Divisor first GCD(a,b) */ + while (remainder != 0) { + tmp = gcd % remainder; + gcd = remainder; + remainder = tmp; + } + /* resulting a is the GCD, LCM(a,b) = |a*b|/GCD(a,b) */ + lcm = blocksize * constant_len / gcd; + + /* now spread out the bits */ + memset(block, 0, blocksize); + + /* last to first to be able to bring carry forward */ + carry = 0; + for (l = lcm - 1; l >= 0; l--) { + unsigned int rotbits, rshift, rbyte; + + /* destination byte in block is l % N */ + b = l % blocksize; + /* Our virtual s buffer is R = L/K long (K = constant_len) */ + /* So we rotate backwards from R-1 to 0 (none) rotations */ + rotbits = 13 * (l / constant_len); + /* find the byte on s where rotbits falls onto */ + rbyte = l - (rotbits / 8); + /* calculate how much shift on that byte */ + rshift = rotbits & 0x07; + /* rbyte % constant_len gives us the unrotated byte in the + * constant buffer, get also the previous byte then + * appropriately shift them to get the rotated byte we need */ + tmp = (constant[(rbyte-1) % constant_len] << (8 - rshift) + | constant[rbyte % constant_len] >> rshift) + & 0xff; + /* add with carry to any value placed by previous passes */ + tmp += carry + block[b]; + block[b] = tmp & 0xff; + /* save any carry that may be left */ + carry = tmp >> 8; + } + + /* if any carry is left at the end, add it through the number */ + for (b = blocksize - 1; b >= 0 && carry != 0; b--) { + carry += block[b]; + block[b] = carry & 0xff; + carry >>= 8; + } +} + +static int cipher_init(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *engine, + const unsigned char *key, size_t key_len) +{ + int klen, ret; + + ret = EVP_EncryptInit_ex(ctx, cipher, engine, key, NULL); + if (!ret) + goto out; + /* set the key len for the odd variable key len cipher */ + klen = EVP_CIPHER_CTX_get_key_length(ctx); + if (key_len != (size_t)klen) { + ret = EVP_CIPHER_CTX_set_key_length(ctx, key_len); + if (ret <= 0) { + ret = 0; + goto out; + } + } + /* we never want padding, either the length requested is a multiple of + * the cipher block size or we are passed a cipher that can cope with + * partial blocks via techniques like cipher text stealing */ + ret = EVP_CIPHER_CTX_set_padding(ctx, 0); + if (!ret) + goto out; + +out: + return ret; +} + +static int KRB5KDF(const EVP_CIPHER *cipher, ENGINE *engine, + const unsigned char *key, size_t key_len, + const unsigned char *constant, size_t constant_len, + unsigned char *okey, size_t okey_len) +{ + EVP_CIPHER_CTX *ctx = NULL; + unsigned char block[EVP_MAX_BLOCK_LENGTH * 2]; + unsigned char *plainblock, *cipherblock; + size_t blocksize; + size_t cipherlen; + size_t osize; +#ifndef OPENSSL_NO_DES + int des3_no_fixup = 0; +#endif + int ret; + + if (key_len != okey_len) { +#ifndef OPENSSL_NO_DES + /* special case for 3des, where the caller may be requesting + * the random raw key, instead of the fixed up key */ + if (EVP_CIPHER_get_nid(cipher) == NID_des_ede3_cbc && + key_len == 24 && okey_len == 21) { + des3_no_fixup = 1; + } else { +#endif + ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE); + return 0; +#ifndef OPENSSL_NO_DES + } +#endif + } + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) + return 0; + + ret = cipher_init(ctx, cipher, engine, key, key_len); + if (!ret) + goto out; + + /* Initialize input block */ + blocksize = EVP_CIPHER_CTX_get_block_size(ctx); + + if (constant_len > blocksize) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CONSTANT_LENGTH); + ret = 0; + goto out; + } + + n_fold(block, blocksize, constant, constant_len); + plainblock = block; + cipherblock = block + EVP_MAX_BLOCK_LENGTH; + + for (osize = 0; osize < okey_len; osize += cipherlen) { + int olen; + + ret = EVP_EncryptUpdate(ctx, cipherblock, &olen, + plainblock, blocksize); + if (!ret) + goto out; + cipherlen = olen; + ret = EVP_EncryptFinal_ex(ctx, cipherblock, &olen); + if (!ret) + goto out; + if (olen != 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH); + ret = 0; + goto out; + } + + /* write cipherblock out */ + if (cipherlen > okey_len - osize) + cipherlen = okey_len - osize; + memcpy(okey + osize, cipherblock, cipherlen); + + if (okey_len > osize + cipherlen) { + /* we need to reinitialize cipher context per spec */ + ret = EVP_CIPHER_CTX_reset(ctx); + if (!ret) + goto out; + ret = cipher_init(ctx, cipher, engine, key, key_len); + if (!ret) + goto out; + + /* also swap block offsets so last ciphertext becomes new + * plaintext */ + plainblock = cipherblock; + if (cipherblock == block) { + cipherblock += EVP_MAX_BLOCK_LENGTH; + } else { + cipherblock = block; + } + } + } + +#ifndef OPENSSL_NO_DES + if (EVP_CIPHER_get_nid(cipher) == NID_des_ede3_cbc && !des3_no_fixup) { + ret = fixup_des3_key(okey); + if (!ret) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY); + goto out; + } + } +#endif + + ret = 1; + +out: + EVP_CIPHER_CTX_free(ctx); + OPENSSL_cleanse(block, EVP_MAX_BLOCK_LENGTH * 2); + return ret; +} + diff --git a/providers/implementations/kdfs/pbkdf1.c b/providers/implementations/kdfs/pbkdf1.c new file mode 100644 index 000000000000..1a042bac9f52 --- /dev/null +++ b/providers/implementations/kdfs/pbkdf1.c @@ -0,0 +1,244 @@ +/* + * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/trace.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include <openssl/core_names.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" +#include "internal/numbers.h" +#include "crypto/evp.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_util.h" + +static OSSL_FUNC_kdf_newctx_fn kdf_pbkdf1_new; +static OSSL_FUNC_kdf_freectx_fn kdf_pbkdf1_free; +static OSSL_FUNC_kdf_reset_fn kdf_pbkdf1_reset; +static OSSL_FUNC_kdf_derive_fn kdf_pbkdf1_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_pbkdf1_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pbkdf1_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pbkdf1_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pbkdf1_get_ctx_params; + +typedef struct { + void *provctx; + PROV_DIGEST digest; + unsigned char *pass; + size_t pass_len; + unsigned char *salt; + size_t salt_len; + uint64_t iter; +} KDF_PBKDF1; + +/* + * PKCS5 PBKDF1 compatible key/IV generation as specified in: + * https://tools.ietf.org/html/rfc8018#page-10 + */ + +static int kdf_pbkdf1_do_derive(const unsigned char *pass, size_t passlen, + const unsigned char *salt, size_t saltlen, + uint64_t iter, const EVP_MD *md_type, + unsigned char *out, size_t n) +{ + uint64_t i; + int mdsize, ret = 0; + unsigned char md_tmp[EVP_MAX_MD_SIZE]; + EVP_MD_CTX *ctx = NULL; + + ctx = EVP_MD_CTX_new(); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_DigestInit_ex(ctx, md_type, NULL) + || !EVP_DigestUpdate(ctx, pass, passlen) + || !EVP_DigestUpdate(ctx, salt, saltlen) + || !EVP_DigestFinal_ex(ctx, md_tmp, NULL)) + goto err; + mdsize = EVP_MD_size(md_type); + if (mdsize < 0) + goto err; + for (i = 1; i < iter; i++) { + if (!EVP_DigestInit_ex(ctx, md_type, NULL)) + goto err; + if (!EVP_DigestUpdate(ctx, md_tmp, mdsize)) + goto err; + if (!EVP_DigestFinal_ex(ctx, md_tmp, NULL)) + goto err; + } + + memcpy(out, md_tmp, n); + ret = 1; +err: + EVP_MD_CTX_free(ctx); + return ret; +} + +static void *kdf_pbkdf1_new(void *provctx) +{ + KDF_PBKDF1 *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + ctx->provctx = provctx; + return ctx; +} + +static void kdf_pbkdf1_cleanup(KDF_PBKDF1 *ctx) +{ + ossl_prov_digest_reset(&ctx->digest); + OPENSSL_free(ctx->salt); + OPENSSL_clear_free(ctx->pass, ctx->pass_len); + memset(ctx, 0, sizeof(*ctx)); +} + +static void kdf_pbkdf1_free(void *vctx) +{ + KDF_PBKDF1 *ctx = (KDF_PBKDF1 *)vctx; + + if (ctx != NULL) { + kdf_pbkdf1_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +static void kdf_pbkdf1_reset(void *vctx) +{ + KDF_PBKDF1 *ctx = (KDF_PBKDF1 *)vctx; + void *provctx = ctx->provctx; + + kdf_pbkdf1_cleanup(ctx); + ctx->provctx = provctx; +} + +static int kdf_pbkdf1_set_membuf(unsigned char **buffer, size_t *buflen, + const OSSL_PARAM *p) +{ + OPENSSL_clear_free(*buffer, *buflen); + *buffer = NULL; + *buflen = 0; + + if (p->data_size == 0) { + if ((*buffer = OPENSSL_malloc(1)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + } else if (p->data != NULL) { + if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen)) + return 0; + } + return 1; +} + +static int kdf_pbkdf1_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_PBKDF1 *ctx = (KDF_PBKDF1 *)vctx; + const EVP_MD *md; + + if (!ossl_prov_is_running() || !kdf_pbkdf1_set_ctx_params(ctx, params)) + return 0; + + if (ctx->pass == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS); + return 0; + } + + if (ctx->salt == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT); + return 0; + } + + md = ossl_prov_digest_md(&ctx->digest); + return kdf_pbkdf1_do_derive(ctx->pass, ctx->pass_len, ctx->salt, ctx->salt_len, + ctx->iter, md, key, keylen); +} + +static int kdf_pbkdf1_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_PBKDF1 *ctx = vctx; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) + if (!kdf_pbkdf1_set_membuf(&ctx->pass, &ctx->pass_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) + if (!kdf_pbkdf1_set_membuf(&ctx->salt, &ctx->salt_len,p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_ITER)) != NULL) + if (!OSSL_PARAM_get_uint64(p, &ctx->iter)) + return 0; + return 1; +} + +static const OSSL_PARAM *kdf_pbkdf1_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), + OSSL_PARAM_uint64(OSSL_KDF_PARAM_ITER, NULL), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_pbkdf1_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, SIZE_MAX); + return -2; +} + +static const OSSL_PARAM *kdf_pbkdf1_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_pbkdf1_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pbkdf1_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pbkdf1_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pbkdf1_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pbkdf1_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pbkdf1_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pbkdf1_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pbkdf1_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pbkdf1_get_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/kdfs/pbkdf2.c b/providers/implementations/kdfs/pbkdf2.c new file mode 100644 index 000000000000..2a0ae63acc32 --- /dev/null +++ b/providers/implementations/kdfs/pbkdf2.c @@ -0,0 +1,363 @@ +/* + * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * HMAC low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <openssl/hmac.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include <openssl/core_names.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" +#include "internal/numbers.h" +#include "crypto/evp.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_util.h" +#include "pbkdf2.h" + +/* Constants specified in SP800-132 */ +#define KDF_PBKDF2_MIN_KEY_LEN_BITS 112 +#define KDF_PBKDF2_MAX_KEY_LEN_DIGEST_RATIO 0xFFFFFFFF +#define KDF_PBKDF2_MIN_ITERATIONS 1000 +#define KDF_PBKDF2_MIN_SALT_LEN (128 / 8) + +static OSSL_FUNC_kdf_newctx_fn kdf_pbkdf2_new; +static OSSL_FUNC_kdf_freectx_fn kdf_pbkdf2_free; +static OSSL_FUNC_kdf_reset_fn kdf_pbkdf2_reset; +static OSSL_FUNC_kdf_derive_fn kdf_pbkdf2_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_pbkdf2_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pbkdf2_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pbkdf2_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pbkdf2_get_ctx_params; + +static int pbkdf2_derive(const char *pass, size_t passlen, + const unsigned char *salt, int saltlen, uint64_t iter, + const EVP_MD *digest, unsigned char *key, + size_t keylen, int extra_checks); + +typedef struct { + void *provctx; + unsigned char *pass; + size_t pass_len; + unsigned char *salt; + size_t salt_len; + uint64_t iter; + PROV_DIGEST digest; + int lower_bound_checks; +} KDF_PBKDF2; + +static void kdf_pbkdf2_init(KDF_PBKDF2 *ctx); + +static void *kdf_pbkdf2_new(void *provctx) +{ + KDF_PBKDF2 *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + ctx->provctx = provctx; + kdf_pbkdf2_init(ctx); + return ctx; +} + +static void kdf_pbkdf2_cleanup(KDF_PBKDF2 *ctx) +{ + ossl_prov_digest_reset(&ctx->digest); + OPENSSL_free(ctx->salt); + OPENSSL_clear_free(ctx->pass, ctx->pass_len); + memset(ctx, 0, sizeof(*ctx)); +} + +static void kdf_pbkdf2_free(void *vctx) +{ + KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx; + + if (ctx != NULL) { + kdf_pbkdf2_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +static void kdf_pbkdf2_reset(void *vctx) +{ + KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx; + void *provctx = ctx->provctx; + + kdf_pbkdf2_cleanup(ctx); + ctx->provctx = provctx; + kdf_pbkdf2_init(ctx); +} + +static void kdf_pbkdf2_init(KDF_PBKDF2 *ctx) +{ + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx); + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, + SN_sha1, 0); + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) + /* This is an error, but there is no way to indicate such directly */ + ossl_prov_digest_reset(&ctx->digest); + ctx->iter = PKCS5_DEFAULT_ITER; + ctx->lower_bound_checks = ossl_kdf_pbkdf2_default_checks; +} + +static int pbkdf2_set_membuf(unsigned char **buffer, size_t *buflen, + const OSSL_PARAM *p) +{ + OPENSSL_clear_free(*buffer, *buflen); + *buffer = NULL; + *buflen = 0; + + if (p->data_size == 0) { + if ((*buffer = OPENSSL_malloc(1)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + } else if (p->data != NULL) { + if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen)) + return 0; + } + return 1; +} + +static int kdf_pbkdf2_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx; + const EVP_MD *md; + + if (!ossl_prov_is_running() || !kdf_pbkdf2_set_ctx_params(ctx, params)) + return 0; + + if (ctx->pass == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS); + return 0; + } + + if (ctx->salt == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT); + return 0; + } + + md = ossl_prov_digest_md(&ctx->digest); + return pbkdf2_derive((char *)ctx->pass, ctx->pass_len, + ctx->salt, ctx->salt_len, ctx->iter, + md, key, keylen, ctx->lower_bound_checks); +} + +static int kdf_pbkdf2_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_PBKDF2 *ctx = vctx; + OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx); + int pkcs5; + uint64_t iter, min_iter; + + if (params == NULL) + return 1; + + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PKCS5)) != NULL) { + if (!OSSL_PARAM_get_int(p, &pkcs5)) + return 0; + ctx->lower_bound_checks = pkcs5 == 0; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) + if (!pbkdf2_set_membuf(&ctx->pass, &ctx->pass_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) { + if (ctx->lower_bound_checks != 0 + && p->data_size < KDF_PBKDF2_MIN_SALT_LEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH); + return 0; + } + if (!pbkdf2_set_membuf(&ctx->salt, &ctx->salt_len,p)) + return 0; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_ITER)) != NULL) { + if (!OSSL_PARAM_get_uint64(p, &iter)) + return 0; + min_iter = ctx->lower_bound_checks != 0 ? KDF_PBKDF2_MIN_ITERATIONS : 1; + if (iter < min_iter) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT); + return 0; + } + ctx->iter = iter; + } + return 1; +} + +static const OSSL_PARAM *kdf_pbkdf2_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), + OSSL_PARAM_uint64(OSSL_KDF_PARAM_ITER, NULL), + OSSL_PARAM_int(OSSL_KDF_PARAM_PKCS5, NULL), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_pbkdf2_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, SIZE_MAX); + return -2; +} + +static const OSSL_PARAM *kdf_pbkdf2_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_pbkdf2_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pbkdf2_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pbkdf2_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pbkdf2_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pbkdf2_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pbkdf2_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pbkdf2_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pbkdf2_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pbkdf2_get_ctx_params }, + { 0, NULL } +}; + +/* + * This is an implementation of PKCS#5 v2.0 password based encryption key + * derivation function PBKDF2. SHA1 version verified against test vectors + * posted by Peter Gutmann to the PKCS-TNG mailing list. + * + * The constraints specified by SP800-132 have been added i.e. + * - Check the range of the key length. + * - Minimum iteration count of 1000. + * - Randomly-generated portion of the salt shall be at least 128 bits. + */ +static int pbkdf2_derive(const char *pass, size_t passlen, + const unsigned char *salt, int saltlen, uint64_t iter, + const EVP_MD *digest, unsigned char *key, + size_t keylen, int lower_bound_checks) +{ + int ret = 0; + unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4]; + int cplen, k, tkeylen, mdlen; + uint64_t j; + unsigned long i = 1; + HMAC_CTX *hctx_tpl = NULL, *hctx = NULL; + + mdlen = EVP_MD_get_size(digest); + if (mdlen <= 0) + return 0; + + /* + * This check should always be done because keylen / mdlen >= (2^32 - 1) + * results in an overflow of the loop counter 'i'. + */ + if ((keylen / mdlen) >= KDF_PBKDF2_MAX_KEY_LEN_DIGEST_RATIO) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + + if (lower_bound_checks) { + if ((keylen * 8) < KDF_PBKDF2_MIN_KEY_LEN_BITS) { + ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL); + return 0; + } + if (saltlen < KDF_PBKDF2_MIN_SALT_LEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH); + return 0; + } + if (iter < KDF_PBKDF2_MIN_ITERATIONS) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT); + return 0; + } + } + + hctx_tpl = HMAC_CTX_new(); + if (hctx_tpl == NULL) + return 0; + p = key; + tkeylen = keylen; + if (!HMAC_Init_ex(hctx_tpl, pass, passlen, digest, NULL)) + goto err; + hctx = HMAC_CTX_new(); + if (hctx == NULL) + goto err; + while (tkeylen) { + if (tkeylen > mdlen) + cplen = mdlen; + else + cplen = tkeylen; + /* + * We are unlikely to ever use more than 256 blocks (5120 bits!) but + * just in case... + */ + itmp[0] = (unsigned char)((i >> 24) & 0xff); + itmp[1] = (unsigned char)((i >> 16) & 0xff); + itmp[2] = (unsigned char)((i >> 8) & 0xff); + itmp[3] = (unsigned char)(i & 0xff); + if (!HMAC_CTX_copy(hctx, hctx_tpl)) + goto err; + if (!HMAC_Update(hctx, salt, saltlen) + || !HMAC_Update(hctx, itmp, 4) + || !HMAC_Final(hctx, digtmp, NULL)) + goto err; + memcpy(p, digtmp, cplen); + for (j = 1; j < iter; j++) { + if (!HMAC_CTX_copy(hctx, hctx_tpl)) + goto err; + if (!HMAC_Update(hctx, digtmp, mdlen) + || !HMAC_Final(hctx, digtmp, NULL)) + goto err; + for (k = 0; k < cplen; k++) + p[k] ^= digtmp[k]; + } + tkeylen -= cplen; + i++; + p += cplen; + } + ret = 1; + +err: + HMAC_CTX_free(hctx); + HMAC_CTX_free(hctx_tpl); + return ret; +} diff --git a/providers/implementations/kdfs/pbkdf2.h b/providers/implementations/kdfs/pbkdf2.h new file mode 100644 index 000000000000..7759c03136d5 --- /dev/null +++ b/providers/implementations/kdfs/pbkdf2.h @@ -0,0 +1,14 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Available in pbkdfe_fips.c, and compiled with different values depending + * on we're in the FIPS module or not. + */ +extern const int ossl_kdf_pbkdf2_default_checks; diff --git a/providers/implementations/kdfs/pbkdf2_fips.c b/providers/implementations/kdfs/pbkdf2_fips.c new file mode 100644 index 000000000000..e43ef16455f1 --- /dev/null +++ b/providers/implementations/kdfs/pbkdf2_fips.c @@ -0,0 +1,20 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "pbkdf2.h" + +/* + * For backwards compatibility reasons, + * Extra checks are done by default in fips mode only. + */ +#ifdef FIPS_MODULE +const int ossl_kdf_pbkdf2_default_checks = 1; +#else +const int ossl_kdf_pbkdf2_default_checks = 0; +#endif /* FIPS_MODULE */ diff --git a/providers/implementations/kdfs/pkcs12kdf.c b/providers/implementations/kdfs/pkcs12kdf.c new file mode 100644 index 000000000000..3218daa781e9 --- /dev/null +++ b/providers/implementations/kdfs/pkcs12kdf.c @@ -0,0 +1,300 @@ +/* + * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/trace.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include <openssl/core_names.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" +#include "internal/numbers.h" +#include "crypto/evp.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_util.h" + +static OSSL_FUNC_kdf_newctx_fn kdf_pkcs12_new; +static OSSL_FUNC_kdf_freectx_fn kdf_pkcs12_free; +static OSSL_FUNC_kdf_reset_fn kdf_pkcs12_reset; +static OSSL_FUNC_kdf_derive_fn kdf_pkcs12_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_pkcs12_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pkcs12_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pkcs12_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pkcs12_get_ctx_params; + +typedef struct { + void *provctx; + PROV_DIGEST digest; + unsigned char *pass; + size_t pass_len; + unsigned char *salt; + size_t salt_len; + uint64_t iter; + int id; +} KDF_PKCS12; + +/* PKCS12 compatible key/IV generation */ + +static int pkcs12kdf_derive(const unsigned char *pass, size_t passlen, + const unsigned char *salt, size_t saltlen, + int id, uint64_t iter, const EVP_MD *md_type, + unsigned char *out, size_t n) +{ + unsigned char *B = NULL, *D = NULL, *I = NULL, *p = NULL, *Ai = NULL; + size_t Slen, Plen, Ilen; + size_t i, j, k, u, v; + uint64_t iter_cnt; + int ret = 0, ui, vi; + EVP_MD_CTX *ctx = NULL; + + ctx = EVP_MD_CTX_new(); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto end; + } + vi = EVP_MD_get_block_size(md_type); + ui = EVP_MD_get_size(md_type); + if (ui <= 0 || vi <= 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_SIZE); + goto end; + } + u = (size_t)ui; + v = (size_t)vi; + D = OPENSSL_malloc(v); + Ai = OPENSSL_malloc(u); + B = OPENSSL_malloc(v + 1); + Slen = v * ((saltlen + v - 1) / v); + if (passlen != 0) + Plen = v * ((passlen + v - 1) / v); + else + Plen = 0; + Ilen = Slen + Plen; + I = OPENSSL_malloc(Ilen); + if (D == NULL || Ai == NULL || B == NULL || I == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto end; + } + for (i = 0; i < v; i++) + D[i] = id; + p = I; + for (i = 0; i < Slen; i++) + *p++ = salt[i % saltlen]; + for (i = 0; i < Plen; i++) + *p++ = pass[i % passlen]; + for (;;) { + if (!EVP_DigestInit_ex(ctx, md_type, NULL) + || !EVP_DigestUpdate(ctx, D, v) + || !EVP_DigestUpdate(ctx, I, Ilen) + || !EVP_DigestFinal_ex(ctx, Ai, NULL)) + goto end; + for (iter_cnt = 1; iter_cnt < iter; iter_cnt++) { + if (!EVP_DigestInit_ex(ctx, md_type, NULL) + || !EVP_DigestUpdate(ctx, Ai, u) + || !EVP_DigestFinal_ex(ctx, Ai, NULL)) + goto end; + } + memcpy(out, Ai, n < u ? n : u); + if (u >= n) { + ret = 1; + break; + } + n -= u; + out += u; + for (j = 0; j < v; j++) + B[j] = Ai[j % u]; + for (j = 0; j < Ilen; j += v) { + unsigned char *Ij = I + j; + uint16_t c = 1; + + /* Work out Ij = Ij + B + 1 */ + for (k = v; k > 0;) { + k--; + c += Ij[k] + B[k]; + Ij[k] = (unsigned char)c; + c >>= 8; + } + } + } + + end: + OPENSSL_free(Ai); + OPENSSL_free(B); + OPENSSL_free(D); + OPENSSL_free(I); + EVP_MD_CTX_free(ctx); + return ret; +} + +static void *kdf_pkcs12_new(void *provctx) +{ + KDF_PKCS12 *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + ctx->provctx = provctx; + return ctx; +} + +static void kdf_pkcs12_cleanup(KDF_PKCS12 *ctx) +{ + ossl_prov_digest_reset(&ctx->digest); + OPENSSL_free(ctx->salt); + OPENSSL_clear_free(ctx->pass, ctx->pass_len); + memset(ctx, 0, sizeof(*ctx)); +} + +static void kdf_pkcs12_free(void *vctx) +{ + KDF_PKCS12 *ctx = (KDF_PKCS12 *)vctx; + + if (ctx != NULL) { + kdf_pkcs12_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +static void kdf_pkcs12_reset(void *vctx) +{ + KDF_PKCS12 *ctx = (KDF_PKCS12 *)vctx; + void *provctx = ctx->provctx; + + kdf_pkcs12_cleanup(ctx); + ctx->provctx = provctx; +} + +static int pkcs12kdf_set_membuf(unsigned char **buffer, size_t *buflen, + const OSSL_PARAM *p) +{ + OPENSSL_clear_free(*buffer, *buflen); + *buffer = NULL; + *buflen = 0; + + if (p->data_size == 0) { + if ((*buffer = OPENSSL_malloc(1)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + } else if (p->data != NULL) { + if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen)) + return 0; + } + return 1; +} + +static int kdf_pkcs12_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_PKCS12 *ctx = (KDF_PKCS12 *)vctx; + const EVP_MD *md; + + if (!ossl_prov_is_running() || !kdf_pkcs12_set_ctx_params(ctx, params)) + return 0; + + if (ctx->pass == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS); + return 0; + } + + if (ctx->salt == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT); + return 0; + } + + md = ossl_prov_digest_md(&ctx->digest); + return pkcs12kdf_derive(ctx->pass, ctx->pass_len, ctx->salt, ctx->salt_len, + ctx->id, ctx->iter, md, key, keylen); +} + +static int kdf_pkcs12_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_PKCS12 *ctx = vctx; + OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx); + + if (params == NULL) + return 1; + + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) + if (!pkcs12kdf_set_membuf(&ctx->pass, &ctx->pass_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) + if (!pkcs12kdf_set_membuf(&ctx->salt, &ctx->salt_len,p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PKCS12_ID)) != NULL) + if (!OSSL_PARAM_get_int(p, &ctx->id)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_ITER)) != NULL) + if (!OSSL_PARAM_get_uint64(p, &ctx->iter)) + return 0; + return 1; +} + +static const OSSL_PARAM *kdf_pkcs12_settable_ctx_params( + ossl_unused void *ctx, ossl_unused void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), + OSSL_PARAM_uint64(OSSL_KDF_PARAM_ITER, NULL), + OSSL_PARAM_int(OSSL_KDF_PARAM_PKCS12_ID, NULL), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_pkcs12_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, SIZE_MAX); + return -2; +} + +static const OSSL_PARAM *kdf_pkcs12_gettable_ctx_params( + ossl_unused void *ctx, ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_pkcs12_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pkcs12_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pkcs12_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pkcs12_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pkcs12_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pkcs12_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pkcs12_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pkcs12_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pkcs12_get_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/kdfs/scrypt.c b/providers/implementations/kdfs/scrypt.c new file mode 100644 index 000000000000..a7072f785f08 --- /dev/null +++ b/providers/implementations/kdfs/scrypt.c @@ -0,0 +1,517 @@ +/* + * Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include <openssl/err.h> +#include <openssl/core_names.h> +#include <openssl/proverr.h> +#include "crypto/evp.h" +#include "internal/numbers.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" + +#ifndef OPENSSL_NO_SCRYPT + +static OSSL_FUNC_kdf_newctx_fn kdf_scrypt_new; +static OSSL_FUNC_kdf_freectx_fn kdf_scrypt_free; +static OSSL_FUNC_kdf_reset_fn kdf_scrypt_reset; +static OSSL_FUNC_kdf_derive_fn kdf_scrypt_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_scrypt_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kdf_scrypt_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_scrypt_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn kdf_scrypt_get_ctx_params; + +static int scrypt_alg(const char *pass, size_t passlen, + const unsigned char *salt, size_t saltlen, + uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem, + unsigned char *key, size_t keylen, EVP_MD *sha256, + OSSL_LIB_CTX *libctx, const char *propq); + +typedef struct { + OSSL_LIB_CTX *libctx; + char *propq; + unsigned char *pass; + size_t pass_len; + unsigned char *salt; + size_t salt_len; + uint64_t N; + uint64_t r, p; + uint64_t maxmem_bytes; + EVP_MD *sha256; +} KDF_SCRYPT; + +static void kdf_scrypt_init(KDF_SCRYPT *ctx); + +static void *kdf_scrypt_new(void *provctx) +{ + KDF_SCRYPT *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + ctx->libctx = PROV_LIBCTX_OF(provctx); + kdf_scrypt_init(ctx); + return ctx; +} + +static void kdf_scrypt_free(void *vctx) +{ + KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx; + + if (ctx != NULL) { + OPENSSL_free(ctx->propq); + EVP_MD_free(ctx->sha256); + kdf_scrypt_reset(ctx); + OPENSSL_free(ctx); + } +} + +static void kdf_scrypt_reset(void *vctx) +{ + KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx; + + OPENSSL_free(ctx->salt); + OPENSSL_clear_free(ctx->pass, ctx->pass_len); + kdf_scrypt_init(ctx); +} + +static void kdf_scrypt_init(KDF_SCRYPT *ctx) +{ + /* Default values are the most conservative recommendation given in the + * original paper of C. Percival. Derivation uses roughly 1 GiB of memory + * for this parameter choice (approx. 128 * r * N * p bytes). + */ + ctx->N = 1 << 20; + ctx->r = 8; + ctx->p = 1; + ctx->maxmem_bytes = 1025 * 1024 * 1024; +} + +static int scrypt_set_membuf(unsigned char **buffer, size_t *buflen, + const OSSL_PARAM *p) +{ + OPENSSL_clear_free(*buffer, *buflen); + *buffer = NULL; + *buflen = 0; + + if (p->data_size == 0) { + if ((*buffer = OPENSSL_malloc(1)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + } else if (p->data != NULL) { + if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen)) + return 0; + } + return 1; +} + +static int set_digest(KDF_SCRYPT *ctx) +{ + EVP_MD_free(ctx->sha256); + ctx->sha256 = EVP_MD_fetch(ctx->libctx, "sha256", ctx->propq); + if (ctx->sha256 == NULL) { + OPENSSL_free(ctx); + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOAD_SHA256); + return 0; + } + return 1; +} + +static int set_property_query(KDF_SCRYPT *ctx, const char *propq) +{ + OPENSSL_free(ctx->propq); + ctx->propq = NULL; + if (propq != NULL) { + ctx->propq = OPENSSL_strdup(propq); + if (ctx->propq == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + } + return 1; +} + +static int kdf_scrypt_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx; + + if (!ossl_prov_is_running() || !kdf_scrypt_set_ctx_params(ctx, params)) + return 0; + + if (ctx->pass == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS); + return 0; + } + + if (ctx->salt == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT); + return 0; + } + + if (ctx->sha256 == NULL && !set_digest(ctx)) + return 0; + + return scrypt_alg((char *)ctx->pass, ctx->pass_len, ctx->salt, + ctx->salt_len, ctx->N, ctx->r, ctx->p, + ctx->maxmem_bytes, key, keylen, ctx->sha256, + ctx->libctx, ctx->propq); +} + +static int is_power_of_two(uint64_t value) +{ + return (value != 0) && ((value & (value - 1)) == 0); +} + +static int kdf_scrypt_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_SCRYPT *ctx = vctx; + uint64_t u64_value; + + if (params == NULL) + return 1; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) + if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) + if (!scrypt_set_membuf(&ctx->salt, &ctx->salt_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SCRYPT_N)) + != NULL) { + if (!OSSL_PARAM_get_uint64(p, &u64_value) + || u64_value <= 1 + || !is_power_of_two(u64_value)) + return 0; + ctx->N = u64_value; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SCRYPT_R)) + != NULL) { + if (!OSSL_PARAM_get_uint64(p, &u64_value) || u64_value < 1) + return 0; + ctx->r = u64_value; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SCRYPT_P)) + != NULL) { + if (!OSSL_PARAM_get_uint64(p, &u64_value) || u64_value < 1) + return 0; + ctx->p = u64_value; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SCRYPT_MAXMEM)) + != NULL) { + if (!OSSL_PARAM_get_uint64(p, &u64_value) || u64_value < 1) + return 0; + ctx->maxmem_bytes = u64_value; + } + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING + || !set_property_query(ctx, p->data) + || !set_digest(ctx)) + return 0; + } + return 1; +} + +static const OSSL_PARAM *kdf_scrypt_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), + OSSL_PARAM_uint64(OSSL_KDF_PARAM_SCRYPT_N, NULL), + OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_R, NULL), + OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_P, NULL), + OSSL_PARAM_uint64(OSSL_KDF_PARAM_SCRYPT_MAXMEM, NULL), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_scrypt_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, SIZE_MAX); + return -2; +} + +static const OSSL_PARAM *kdf_scrypt_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_scrypt_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_scrypt_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_scrypt_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_scrypt_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_scrypt_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_scrypt_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_scrypt_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_scrypt_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_scrypt_get_ctx_params }, + { 0, NULL } +}; + +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) +static void salsa208_word_specification(uint32_t inout[16]) +{ + int i; + uint32_t x[16]; + + memcpy(x, inout, sizeof(x)); + for (i = 8; i > 0; i -= 2) { + x[4] ^= R(x[0] + x[12], 7); + x[8] ^= R(x[4] + x[0], 9); + x[12] ^= R(x[8] + x[4], 13); + x[0] ^= R(x[12] + x[8], 18); + x[9] ^= R(x[5] + x[1], 7); + x[13] ^= R(x[9] + x[5], 9); + x[1] ^= R(x[13] + x[9], 13); + x[5] ^= R(x[1] + x[13], 18); + x[14] ^= R(x[10] + x[6], 7); + x[2] ^= R(x[14] + x[10], 9); + x[6] ^= R(x[2] + x[14], 13); + x[10] ^= R(x[6] + x[2], 18); + x[3] ^= R(x[15] + x[11], 7); + x[7] ^= R(x[3] + x[15], 9); + x[11] ^= R(x[7] + x[3], 13); + x[15] ^= R(x[11] + x[7], 18); + x[1] ^= R(x[0] + x[3], 7); + x[2] ^= R(x[1] + x[0], 9); + x[3] ^= R(x[2] + x[1], 13); + x[0] ^= R(x[3] + x[2], 18); + x[6] ^= R(x[5] + x[4], 7); + x[7] ^= R(x[6] + x[5], 9); + x[4] ^= R(x[7] + x[6], 13); + x[5] ^= R(x[4] + x[7], 18); + x[11] ^= R(x[10] + x[9], 7); + x[8] ^= R(x[11] + x[10], 9); + x[9] ^= R(x[8] + x[11], 13); + x[10] ^= R(x[9] + x[8], 18); + x[12] ^= R(x[15] + x[14], 7); + x[13] ^= R(x[12] + x[15], 9); + x[14] ^= R(x[13] + x[12], 13); + x[15] ^= R(x[14] + x[13], 18); + } + for (i = 0; i < 16; ++i) + inout[i] += x[i]; + OPENSSL_cleanse(x, sizeof(x)); +} + +static void scryptBlockMix(uint32_t *B_, uint32_t *B, uint64_t r) +{ + uint64_t i, j; + uint32_t X[16], *pB; + + memcpy(X, B + (r * 2 - 1) * 16, sizeof(X)); + pB = B; + for (i = 0; i < r * 2; i++) { + for (j = 0; j < 16; j++) + X[j] ^= *pB++; + salsa208_word_specification(X); + memcpy(B_ + (i / 2 + (i & 1) * r) * 16, X, sizeof(X)); + } + OPENSSL_cleanse(X, sizeof(X)); +} + +static void scryptROMix(unsigned char *B, uint64_t r, uint64_t N, + uint32_t *X, uint32_t *T, uint32_t *V) +{ + unsigned char *pB; + uint32_t *pV; + uint64_t i, k; + + /* Convert from little endian input */ + for (pV = V, i = 0, pB = B; i < 32 * r; i++, pV++) { + *pV = *pB++; + *pV |= *pB++ << 8; + *pV |= *pB++ << 16; + *pV |= (uint32_t)*pB++ << 24; + } + + for (i = 1; i < N; i++, pV += 32 * r) + scryptBlockMix(pV, pV - 32 * r, r); + + scryptBlockMix(X, V + (N - 1) * 32 * r, r); + + for (i = 0; i < N; i++) { + uint32_t j; + j = X[16 * (2 * r - 1)] % N; + pV = V + 32 * r * j; + for (k = 0; k < 32 * r; k++) + T[k] = X[k] ^ *pV++; + scryptBlockMix(X, T, r); + } + /* Convert output to little endian */ + for (i = 0, pB = B; i < 32 * r; i++) { + uint32_t xtmp = X[i]; + *pB++ = xtmp & 0xff; + *pB++ = (xtmp >> 8) & 0xff; + *pB++ = (xtmp >> 16) & 0xff; + *pB++ = (xtmp >> 24) & 0xff; + } +} + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t)-1) +#endif + +/* + * Maximum power of two that will fit in uint64_t: this should work on + * most (all?) platforms. + */ + +#define LOG2_UINT64_MAX (sizeof(uint64_t) * 8 - 1) + +/* + * Maximum value of p * r: + * p <= ((2^32-1) * hLen) / MFLen => + * p <= ((2^32-1) * 32) / (128 * r) => + * p * r <= (2^30-1) + */ + +#define SCRYPT_PR_MAX ((1 << 30) - 1) + +static int scrypt_alg(const char *pass, size_t passlen, + const unsigned char *salt, size_t saltlen, + uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem, + unsigned char *key, size_t keylen, EVP_MD *sha256, + OSSL_LIB_CTX *libctx, const char *propq) +{ + int rv = 0; + unsigned char *B; + uint32_t *X, *V, *T; + uint64_t i, Blen, Vlen; + + /* Sanity check parameters */ + /* initial check, r,p must be non zero, N >= 2 and a power of 2 */ + if (r == 0 || p == 0 || N < 2 || (N & (N - 1))) + return 0; + /* Check p * r < SCRYPT_PR_MAX avoiding overflow */ + if (p > SCRYPT_PR_MAX / r) { + ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + + /* + * Need to check N: if 2^(128 * r / 8) overflows limit this is + * automatically satisfied since N <= UINT64_MAX. + */ + + if (16 * r <= LOG2_UINT64_MAX) { + if (N >= (((uint64_t)1) << (16 * r))) { + ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + } + + /* Memory checks: check total allocated buffer size fits in uint64_t */ + + /* + * B size in section 5 step 1.S + * Note: we know p * 128 * r < UINT64_MAX because we already checked + * p * r < SCRYPT_PR_MAX + */ + Blen = p * 128 * r; + /* + * Yet we pass it as integer to PKCS5_PBKDF2_HMAC... [This would + * have to be revised when/if PKCS5_PBKDF2_HMAC accepts size_t.] + */ + if (Blen > INT_MAX) { + ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + + /* + * Check 32 * r * (N + 2) * sizeof(uint32_t) fits in uint64_t + * This is combined size V, X and T (section 4) + */ + i = UINT64_MAX / (32 * sizeof(uint32_t)); + if (N + 2 > i / r) { + ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + Vlen = 32 * r * (N + 2) * sizeof(uint32_t); + + /* check total allocated size fits in uint64_t */ + if (Blen > UINT64_MAX - Vlen) { + ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + + /* Check that the maximum memory doesn't exceed a size_t limits */ + if (maxmem > SIZE_MAX) + maxmem = SIZE_MAX; + + if (Blen + Vlen > maxmem) { + ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED); + return 0; + } + + /* If no key return to indicate parameters are OK */ + if (key == NULL) + return 1; + + B = OPENSSL_malloc((size_t)(Blen + Vlen)); + if (B == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + X = (uint32_t *)(B + Blen); + T = X + 32 * r; + V = T + 32 * r; + if (ossl_pkcs5_pbkdf2_hmac_ex(pass, passlen, salt, saltlen, 1, sha256, + (int)Blen, B, libctx, propq) == 0) + goto err; + + for (i = 0; i < p; i++) + scryptROMix(B + 128 * r * i, r, N, X, T, V); + + if (ossl_pkcs5_pbkdf2_hmac_ex(pass, passlen, B, (int)Blen, 1, sha256, + keylen, key, libctx, propq) == 0) + goto err; + rv = 1; + err: + if (rv == 0) + ERR_raise(ERR_LIB_EVP, EVP_R_PBKDF2_ERROR); + + OPENSSL_clear_free(B, (size_t)(Blen + Vlen)); + return rv; +} + +#endif diff --git a/providers/implementations/kdfs/sshkdf.c b/providers/implementations/kdfs/sshkdf.c new file mode 100644 index 000000000000..c592ba72f1e0 --- /dev/null +++ b/providers/implementations/kdfs/sshkdf.c @@ -0,0 +1,302 @@ +/* + * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include <openssl/core_names.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" +#include "internal/numbers.h" +#include "crypto/evp.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_util.h" + +/* See RFC 4253, Section 7.2 */ +static OSSL_FUNC_kdf_newctx_fn kdf_sshkdf_new; +static OSSL_FUNC_kdf_freectx_fn kdf_sshkdf_free; +static OSSL_FUNC_kdf_reset_fn kdf_sshkdf_reset; +static OSSL_FUNC_kdf_derive_fn kdf_sshkdf_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_sshkdf_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kdf_sshkdf_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_sshkdf_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn kdf_sshkdf_get_ctx_params; + +static int SSHKDF(const EVP_MD *evp_md, + const unsigned char *key, size_t key_len, + const unsigned char *xcghash, size_t xcghash_len, + const unsigned char *session_id, size_t session_id_len, + char type, unsigned char *okey, size_t okey_len); + +typedef struct { + void *provctx; + PROV_DIGEST digest; + unsigned char *key; /* K */ + size_t key_len; + unsigned char *xcghash; /* H */ + size_t xcghash_len; + char type; /* X */ + unsigned char *session_id; + size_t session_id_len; +} KDF_SSHKDF; + +static void *kdf_sshkdf_new(void *provctx) +{ + KDF_SSHKDF *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + else + ctx->provctx = provctx; + return ctx; +} + +static void kdf_sshkdf_free(void *vctx) +{ + KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx; + + if (ctx != NULL) { + kdf_sshkdf_reset(ctx); + OPENSSL_free(ctx); + } +} + +static void kdf_sshkdf_reset(void *vctx) +{ + KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx; + void *provctx = ctx->provctx; + + ossl_prov_digest_reset(&ctx->digest); + OPENSSL_clear_free(ctx->key, ctx->key_len); + OPENSSL_clear_free(ctx->xcghash, ctx->xcghash_len); + OPENSSL_clear_free(ctx->session_id, ctx->session_id_len); + memset(ctx, 0, sizeof(*ctx)); + ctx->provctx = provctx; +} + +static int sshkdf_set_membuf(unsigned char **dst, size_t *dst_len, + const OSSL_PARAM *p) +{ + OPENSSL_clear_free(*dst, *dst_len); + *dst = NULL; + *dst_len = 0; + return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len); +} + +static int kdf_sshkdf_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx; + const EVP_MD *md; + + if (!ossl_prov_is_running() || !kdf_sshkdf_set_ctx_params(ctx, params)) + return 0; + + md = ossl_prov_digest_md(&ctx->digest); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + if (ctx->key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return 0; + } + if (ctx->xcghash == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_XCGHASH); + return 0; + } + if (ctx->session_id == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SESSION_ID); + return 0; + } + if (ctx->type == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_TYPE); + return 0; + } + return SSHKDF(md, ctx->key, ctx->key_len, + ctx->xcghash, ctx->xcghash_len, + ctx->session_id, ctx->session_id_len, + ctx->type, key, keylen); +} + +static int kdf_sshkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_SSHKDF *ctx = vctx; + OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx); + + if (params == NULL) + return 1; + + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) + if (!sshkdf_set_membuf(&ctx->key, &ctx->key_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_XCGHASH)) + != NULL) + if (!sshkdf_set_membuf(&ctx->xcghash, &ctx->xcghash_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_SESSION_ID)) + != NULL) + if (!sshkdf_set_membuf(&ctx->session_id, &ctx->session_id_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_TYPE)) + != NULL) { + const char *kdftype; + + if (!OSSL_PARAM_get_utf8_string_ptr(p, &kdftype)) + return 0; + /* Expect one character (byte in this case) */ + if (kdftype == NULL || p->data_size != 1) + return 0; + if (kdftype[0] < 65 || kdftype[0] > 70) { + ERR_raise(ERR_LIB_PROV, PROV_R_VALUE_ERROR); + return 0; + } + ctx->type = kdftype[0]; + } + return 1; +} + +static const OSSL_PARAM *kdf_sshkdf_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_XCGHASH, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_SESSION_ID, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_SSHKDF_TYPE, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_sshkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, SIZE_MAX); + return -2; +} + +static const OSSL_PARAM *kdf_sshkdf_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_sshkdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_sshkdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_sshkdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_sshkdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_sshkdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_sshkdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_sshkdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_sshkdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_sshkdf_get_ctx_params }, + { 0, NULL } +}; + +static int SSHKDF(const EVP_MD *evp_md, + const unsigned char *key, size_t key_len, + const unsigned char *xcghash, size_t xcghash_len, + const unsigned char *session_id, size_t session_id_len, + char type, unsigned char *okey, size_t okey_len) +{ + EVP_MD_CTX *md = NULL; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dsize = 0; + size_t cursize = 0; + int ret = 0; + + md = EVP_MD_CTX_new(); + if (md == NULL) + return 0; + + if (!EVP_DigestInit_ex(md, evp_md, NULL)) + goto out; + + if (!EVP_DigestUpdate(md, key, key_len)) + goto out; + + if (!EVP_DigestUpdate(md, xcghash, xcghash_len)) + goto out; + + if (!EVP_DigestUpdate(md, &type, 1)) + goto out; + + if (!EVP_DigestUpdate(md, session_id, session_id_len)) + goto out; + + if (!EVP_DigestFinal_ex(md, digest, &dsize)) + goto out; + + if (okey_len < dsize) { + memcpy(okey, digest, okey_len); + ret = 1; + goto out; + } + + memcpy(okey, digest, dsize); + + for (cursize = dsize; cursize < okey_len; cursize += dsize) { + + if (!EVP_DigestInit_ex(md, evp_md, NULL)) + goto out; + + if (!EVP_DigestUpdate(md, key, key_len)) + goto out; + + if (!EVP_DigestUpdate(md, xcghash, xcghash_len)) + goto out; + + if (!EVP_DigestUpdate(md, okey, cursize)) + goto out; + + if (!EVP_DigestFinal_ex(md, digest, &dsize)) + goto out; + + if (okey_len < cursize + dsize) { + memcpy(okey + cursize, digest, okey_len - cursize); + ret = 1; + goto out; + } + + memcpy(okey + cursize, digest, dsize); + } + + ret = 1; + +out: + EVP_MD_CTX_free(md); + OPENSSL_cleanse(digest, EVP_MAX_MD_SIZE); + return ret; +} + diff --git a/providers/implementations/kdfs/sskdf.c b/providers/implementations/kdfs/sskdf.c new file mode 100644 index 000000000000..eb54972e1c44 --- /dev/null +++ b/providers/implementations/kdfs/sskdf.c @@ -0,0 +1,559 @@ +/* + * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Refer to https://csrc.nist.gov/publications/detail/sp/800-56c/rev-1/final + * Section 4.1. + * + * The Single Step KDF algorithm is given by: + * + * Result(0) = empty bit string (i.e., the null string). + * For i = 1 to reps, do the following: + * Increment counter by 1. + * Result(i) = Result(i - 1) || H(counter || Z || FixedInfo). + * DKM = LeftmostBits(Result(reps), L)) + * + * NOTES: + * Z is a shared secret required to produce the derived key material. + * counter is a 4 byte buffer. + * FixedInfo is a bit string containing context specific data. + * DKM is the output derived key material. + * L is the required size of the DKM. + * reps = [L / H_outputBits] + * H(x) is the auxiliary function that can be either a hash, HMAC or KMAC. + * H_outputBits is the length of the output of the auxiliary function H(x). + * + * Currently there is not a comprehensive list of test vectors for this + * algorithm, especially for H(x) = HMAC and H(x) = KMAC. + * Test vectors for H(x) = Hash are indirectly used by CAVS KAS tests. + */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <openssl/hmac.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" +#include "internal/numbers.h" +#include "crypto/evp.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_util.h" + +typedef struct { + void *provctx; + EVP_MAC_CTX *macctx; /* H(x) = HMAC_hash OR H(x) = KMAC */ + PROV_DIGEST digest; /* H(x) = hash(x) */ + unsigned char *secret; + size_t secret_len; + unsigned char *info; + size_t info_len; + unsigned char *salt; + size_t salt_len; + size_t out_len; /* optional KMAC parameter */ + int is_kmac; +} KDF_SSKDF; + +#define SSKDF_MAX_INLEN (1<<30) +#define SSKDF_KMAC128_DEFAULT_SALT_SIZE (168 - 4) +#define SSKDF_KMAC256_DEFAULT_SALT_SIZE (136 - 4) + +/* KMAC uses a Customisation string of 'KDF' */ +static const unsigned char kmac_custom_str[] = { 0x4B, 0x44, 0x46 }; + +static OSSL_FUNC_kdf_newctx_fn sskdf_new; +static OSSL_FUNC_kdf_freectx_fn sskdf_free; +static OSSL_FUNC_kdf_reset_fn sskdf_reset; +static OSSL_FUNC_kdf_derive_fn sskdf_derive; +static OSSL_FUNC_kdf_derive_fn x963kdf_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn sskdf_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn sskdf_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn sskdf_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn sskdf_get_ctx_params; + +/* + * Refer to https://csrc.nist.gov/publications/detail/sp/800-56c/rev-1/final + * Section 4. One-Step Key Derivation using H(x) = hash(x) + * Note: X9.63 also uses this code with the only difference being that the + * counter is appended to the secret 'z'. + * i.e. + * result[i] = Hash(counter || z || info) for One Step OR + * result[i] = Hash(z || counter || info) for X9.63. + */ +static int SSKDF_hash_kdm(const EVP_MD *kdf_md, + const unsigned char *z, size_t z_len, + const unsigned char *info, size_t info_len, + unsigned int append_ctr, + unsigned char *derived_key, size_t derived_key_len) +{ + int ret = 0, hlen; + size_t counter, out_len, len = derived_key_len; + unsigned char c[4]; + unsigned char mac[EVP_MAX_MD_SIZE]; + unsigned char *out = derived_key; + EVP_MD_CTX *ctx = NULL, *ctx_init = NULL; + + if (z_len > SSKDF_MAX_INLEN || info_len > SSKDF_MAX_INLEN + || derived_key_len > SSKDF_MAX_INLEN + || derived_key_len == 0) + return 0; + + hlen = EVP_MD_get_size(kdf_md); + if (hlen <= 0) + return 0; + out_len = (size_t)hlen; + + ctx = EVP_MD_CTX_create(); + ctx_init = EVP_MD_CTX_create(); + if (ctx == NULL || ctx_init == NULL) + goto end; + + if (!EVP_DigestInit(ctx_init, kdf_md)) + goto end; + + for (counter = 1;; counter++) { + c[0] = (unsigned char)((counter >> 24) & 0xff); + c[1] = (unsigned char)((counter >> 16) & 0xff); + c[2] = (unsigned char)((counter >> 8) & 0xff); + c[3] = (unsigned char)(counter & 0xff); + + if (!(EVP_MD_CTX_copy_ex(ctx, ctx_init) + && (append_ctr || EVP_DigestUpdate(ctx, c, sizeof(c))) + && EVP_DigestUpdate(ctx, z, z_len) + && (!append_ctr || EVP_DigestUpdate(ctx, c, sizeof(c))) + && EVP_DigestUpdate(ctx, info, info_len))) + goto end; + if (len >= out_len) { + if (!EVP_DigestFinal_ex(ctx, out, NULL)) + goto end; + out += out_len; + len -= out_len; + if (len == 0) + break; + } else { + if (!EVP_DigestFinal_ex(ctx, mac, NULL)) + goto end; + memcpy(out, mac, len); + break; + } + } + ret = 1; +end: + EVP_MD_CTX_destroy(ctx); + EVP_MD_CTX_destroy(ctx_init); + OPENSSL_cleanse(mac, sizeof(mac)); + return ret; +} + +static int kmac_init(EVP_MAC_CTX *ctx, const unsigned char *custom, + size_t custom_len, size_t kmac_out_len, + size_t derived_key_len, unsigned char **out) +{ + OSSL_PARAM params[2]; + + /* Only KMAC has custom data - so return if not KMAC */ + if (custom == NULL) + return 1; + + params[0] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_CUSTOM, + (void *)custom, custom_len); + params[1] = OSSL_PARAM_construct_end(); + + if (!EVP_MAC_CTX_set_params(ctx, params)) + return 0; + + /* By default only do one iteration if kmac_out_len is not specified */ + if (kmac_out_len == 0) + kmac_out_len = derived_key_len; + /* otherwise check the size is valid */ + else if (!(kmac_out_len == derived_key_len + || kmac_out_len == 20 + || kmac_out_len == 28 + || kmac_out_len == 32 + || kmac_out_len == 48 + || kmac_out_len == 64)) + return 0; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_MAC_PARAM_SIZE, + &kmac_out_len); + + if (EVP_MAC_CTX_set_params(ctx, params) <= 0) + return 0; + + /* + * For kmac the output buffer can be larger than EVP_MAX_MD_SIZE: so + * alloc a buffer for this case. + */ + if (kmac_out_len > EVP_MAX_MD_SIZE) { + *out = OPENSSL_zalloc(kmac_out_len); + if (*out == NULL) + return 0; + } + return 1; +} + +/* + * Refer to https://csrc.nist.gov/publications/detail/sp/800-56c/rev-1/final + * Section 4. One-Step Key Derivation using MAC: i.e either + * H(x) = HMAC-hash(salt, x) OR + * H(x) = KMAC#(salt, x, outbits, CustomString='KDF') + */ +static int SSKDF_mac_kdm(EVP_MAC_CTX *ctx_init, + const unsigned char *kmac_custom, + size_t kmac_custom_len, size_t kmac_out_len, + const unsigned char *salt, size_t salt_len, + const unsigned char *z, size_t z_len, + const unsigned char *info, size_t info_len, + unsigned char *derived_key, size_t derived_key_len) +{ + int ret = 0; + size_t counter, out_len, len; + unsigned char c[4]; + unsigned char mac_buf[EVP_MAX_MD_SIZE]; + unsigned char *out = derived_key; + EVP_MAC_CTX *ctx = NULL; + unsigned char *mac = mac_buf, *kmac_buffer = NULL; + + if (z_len > SSKDF_MAX_INLEN || info_len > SSKDF_MAX_INLEN + || derived_key_len > SSKDF_MAX_INLEN + || derived_key_len == 0) + return 0; + + if (!kmac_init(ctx_init, kmac_custom, kmac_custom_len, kmac_out_len, + derived_key_len, &kmac_buffer)) + goto end; + if (kmac_buffer != NULL) + mac = kmac_buffer; + + if (!EVP_MAC_init(ctx_init, salt, salt_len, NULL)) + goto end; + + out_len = EVP_MAC_CTX_get_mac_size(ctx_init); /* output size */ + if (out_len <= 0 || (mac == mac_buf && out_len > sizeof(mac_buf))) + goto end; + len = derived_key_len; + + for (counter = 1;; counter++) { + c[0] = (unsigned char)((counter >> 24) & 0xff); + c[1] = (unsigned char)((counter >> 16) & 0xff); + c[2] = (unsigned char)((counter >> 8) & 0xff); + c[3] = (unsigned char)(counter & 0xff); + + ctx = EVP_MAC_CTX_dup(ctx_init); + if (!(ctx != NULL + && EVP_MAC_update(ctx, c, sizeof(c)) + && EVP_MAC_update(ctx, z, z_len) + && EVP_MAC_update(ctx, info, info_len))) + goto end; + if (len >= out_len) { + if (!EVP_MAC_final(ctx, out, NULL, len)) + goto end; + out += out_len; + len -= out_len; + if (len == 0) + break; + } else { + if (!EVP_MAC_final(ctx, mac, NULL, out_len)) + goto end; + memcpy(out, mac, len); + break; + } + EVP_MAC_CTX_free(ctx); + ctx = NULL; + } + ret = 1; +end: + if (kmac_buffer != NULL) + OPENSSL_clear_free(kmac_buffer, kmac_out_len); + else + OPENSSL_cleanse(mac_buf, sizeof(mac_buf)); + + EVP_MAC_CTX_free(ctx); + return ret; +} + +static void *sskdf_new(void *provctx) +{ + KDF_SSKDF *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ctx->provctx = provctx; + return ctx; +} + +static void sskdf_reset(void *vctx) +{ + KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; + void *provctx = ctx->provctx; + + EVP_MAC_CTX_free(ctx->macctx); + ossl_prov_digest_reset(&ctx->digest); + OPENSSL_clear_free(ctx->secret, ctx->secret_len); + OPENSSL_clear_free(ctx->info, ctx->info_len); + OPENSSL_clear_free(ctx->salt, ctx->salt_len); + memset(ctx, 0, sizeof(*ctx)); + ctx->provctx = provctx; +} + +static void sskdf_free(void *vctx) +{ + KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; + + if (ctx != NULL) { + sskdf_reset(ctx); + OPENSSL_free(ctx); + } +} + +static int sskdf_set_buffer(unsigned char **out, size_t *out_len, + const OSSL_PARAM *p) +{ + if (p->data == NULL || p->data_size == 0) + return 1; + OPENSSL_free(*out); + *out = NULL; + return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len); +} + +static size_t sskdf_size(KDF_SSKDF *ctx) +{ + int len; + const EVP_MD *md = NULL; + + if (ctx->is_kmac) + return SIZE_MAX; + + md = ossl_prov_digest_md(&ctx->digest); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + len = EVP_MD_get_size(md); + return (len <= 0) ? 0 : (size_t)len; +} + +static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; + const EVP_MD *md; + + if (!ossl_prov_is_running() || !sskdf_set_ctx_params(ctx, params)) + return 0; + if (ctx->secret == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); + return 0; + } + md = ossl_prov_digest_md(&ctx->digest); + + if (ctx->macctx != NULL) { + /* H(x) = KMAC or H(x) = HMAC */ + int ret; + const unsigned char *custom = NULL; + size_t custom_len = 0; + int default_salt_len; + EVP_MAC *mac = EVP_MAC_CTX_get0_mac(ctx->macctx); + + if (EVP_MAC_is_a(mac, OSSL_MAC_NAME_HMAC)) { + /* H(x) = HMAC(x, salt, hash) */ + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + default_salt_len = EVP_MD_get_size(md); + if (default_salt_len <= 0) + return 0; + } else if (ctx->is_kmac) { + /* H(x) = KMACzzz(x, salt, custom) */ + custom = kmac_custom_str; + custom_len = sizeof(kmac_custom_str); + if (EVP_MAC_is_a(mac, OSSL_MAC_NAME_KMAC128)) + default_salt_len = SSKDF_KMAC128_DEFAULT_SALT_SIZE; + else + default_salt_len = SSKDF_KMAC256_DEFAULT_SALT_SIZE; + } else { + ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_MAC_TYPE); + return 0; + } + /* If no salt is set then use a default_salt of zeros */ + if (ctx->salt == NULL || ctx->salt_len <= 0) { + ctx->salt = OPENSSL_zalloc(default_salt_len); + if (ctx->salt == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + ctx->salt_len = default_salt_len; + } + ret = SSKDF_mac_kdm(ctx->macctx, + custom, custom_len, ctx->out_len, + ctx->salt, ctx->salt_len, + ctx->secret, ctx->secret_len, + ctx->info, ctx->info_len, key, keylen); + return ret; + } else { + /* H(x) = hash */ + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + return SSKDF_hash_kdm(md, ctx->secret, ctx->secret_len, + ctx->info, ctx->info_len, 0, key, keylen); + } +} + +static int x963kdf_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; + const EVP_MD *md; + + if (!ossl_prov_is_running() || !sskdf_set_ctx_params(ctx, params)) + return 0; + + if (ctx->secret == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); + return 0; + } + + if (ctx->macctx != NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED); + return 0; + } + + /* H(x) = hash */ + md = ossl_prov_digest_md(&ctx->digest); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + + return SSKDF_hash_kdm(md, ctx->secret, ctx->secret_len, + ctx->info, ctx->info_len, 1, key, keylen); +} + +static int sskdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_SSKDF *ctx = vctx; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + size_t sz; + + if (params == NULL) + return 1; + + if (!ossl_prov_macctx_load_from_params(&ctx->macctx, params, + NULL, NULL, NULL, libctx)) + return 0; + if (ctx->macctx != NULL) { + if (EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->macctx), + OSSL_MAC_NAME_KMAC128) + || EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->macctx), + OSSL_MAC_NAME_KMAC256)) { + ctx->is_kmac = 1; + } + } + + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL + || (p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) + if (!sskdf_set_buffer(&ctx->secret, &ctx->secret_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO)) != NULL) + if (!sskdf_set_buffer(&ctx->info, &ctx->info_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) + if (!sskdf_set_buffer(&ctx->salt, &ctx->salt_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MAC_SIZE)) + != NULL) { + if (!OSSL_PARAM_get_size_t(p, &sz) || sz == 0) + return 0; + ctx->out_len = sz; + } + return 1; +} + +static const OSSL_PARAM *sskdf_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MAC, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), + OSSL_PARAM_size_t(OSSL_KDF_PARAM_MAC_SIZE, NULL), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int sskdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, sskdf_size(ctx)); + return -2; +} + +static const OSSL_PARAM *sskdf_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_sskdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))sskdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))sskdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))sskdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))sskdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))sskdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))sskdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))sskdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))sskdf_get_ctx_params }, + { 0, NULL } +}; + +const OSSL_DISPATCH ossl_kdf_x963_kdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))sskdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))sskdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))sskdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))x963kdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))sskdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))sskdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))sskdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))sskdf_get_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/kdfs/tls1_prf.c b/providers/implementations/kdfs/tls1_prf.c new file mode 100644 index 000000000000..a4d64b935222 --- /dev/null +++ b/providers/implementations/kdfs/tls1_prf.c @@ -0,0 +1,411 @@ +/* + * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Refer to "The TLS Protocol Version 1.0" Section 5 + * (https://tools.ietf.org/html/rfc2246#section-5) and + * "The Transport Layer Security (TLS) Protocol Version 1.2" Section 5 + * (https://tools.ietf.org/html/rfc5246#section-5). + * + * For TLS v1.0 and TLS v1.1 the TLS PRF algorithm is given by: + * + * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR + * P_SHA-1(S2, label + seed) + * + * where P_MD5 and P_SHA-1 are defined by P_<hash>, below, and S1 and S2 are + * two halves of the secret (with the possibility of one shared byte, in the + * case where the length of the original secret is odd). S1 is taken from the + * first half of the secret, S2 from the second half. + * + * For TLS v1.2 the TLS PRF algorithm is given by: + * + * PRF(secret, label, seed) = P_<hash>(secret, label + seed) + * + * where hash is SHA-256 for all cipher suites defined in RFC 5246 as well as + * those published prior to TLS v1.2 while the TLS v1.2 protocol is in effect, + * unless defined otherwise by the cipher suite. + * + * P_<hash> is an expansion function that uses a single hash function to expand + * a secret and seed into an arbitrary quantity of output: + * + * P_<hash>(secret, seed) = HMAC_<hash>(secret, A(1) + seed) + + * HMAC_<hash>(secret, A(2) + seed) + + * HMAC_<hash>(secret, A(3) + seed) + ... + * + * where + indicates concatenation. P_<hash> can be iterated as many times as + * is necessary to produce the required quantity of data. + * + * A(i) is defined as: + * A(0) = seed + * A(i) = HMAC_<hash>(secret, A(i-1)) + */ +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" +#include "internal/numbers.h" +#include "crypto/evp.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_util.h" +#include "e_os.h" + +static OSSL_FUNC_kdf_newctx_fn kdf_tls1_prf_new; +static OSSL_FUNC_kdf_freectx_fn kdf_tls1_prf_free; +static OSSL_FUNC_kdf_reset_fn kdf_tls1_prf_reset; +static OSSL_FUNC_kdf_derive_fn kdf_tls1_prf_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_tls1_prf_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kdf_tls1_prf_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_tls1_prf_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn kdf_tls1_prf_get_ctx_params; + +static int tls1_prf_alg(EVP_MAC_CTX *mdctx, EVP_MAC_CTX *sha1ctx, + const unsigned char *sec, size_t slen, + const unsigned char *seed, size_t seed_len, + unsigned char *out, size_t olen); + +#define TLS1_PRF_MAXBUF 1024 + +/* TLS KDF kdf context structure */ +typedef struct { + void *provctx; + + /* MAC context for the main digest */ + EVP_MAC_CTX *P_hash; + /* MAC context for SHA1 for the MD5/SHA-1 combined PRF */ + EVP_MAC_CTX *P_sha1; + + /* Secret value to use for PRF */ + unsigned char *sec; + size_t seclen; + /* Buffer of concatenated seed data */ + unsigned char seed[TLS1_PRF_MAXBUF]; + size_t seedlen; +} TLS1_PRF; + +static void *kdf_tls1_prf_new(void *provctx) +{ + TLS1_PRF *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + ctx->provctx = provctx; + return ctx; +} + +static void kdf_tls1_prf_free(void *vctx) +{ + TLS1_PRF *ctx = (TLS1_PRF *)vctx; + + if (ctx != NULL) { + kdf_tls1_prf_reset(ctx); + OPENSSL_free(ctx); + } +} + +static void kdf_tls1_prf_reset(void *vctx) +{ + TLS1_PRF *ctx = (TLS1_PRF *)vctx; + void *provctx = ctx->provctx; + + EVP_MAC_CTX_free(ctx->P_hash); + EVP_MAC_CTX_free(ctx->P_sha1); + OPENSSL_clear_free(ctx->sec, ctx->seclen); + OPENSSL_cleanse(ctx->seed, ctx->seedlen); + memset(ctx, 0, sizeof(*ctx)); + ctx->provctx = provctx; +} + +static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + TLS1_PRF *ctx = (TLS1_PRF *)vctx; + + if (!ossl_prov_is_running() || !kdf_tls1_prf_set_ctx_params(ctx, params)) + return 0; + + if (ctx->P_hash == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + if (ctx->sec == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); + return 0; + } + if (ctx->seedlen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SEED); + return 0; + } + if (keylen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + + return tls1_prf_alg(ctx->P_hash, ctx->P_sha1, + ctx->sec, ctx->seclen, + ctx->seed, ctx->seedlen, + key, keylen); +} + +static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + TLS1_PRF *ctx = vctx; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + + if (params == NULL) + return 1; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { + if (OPENSSL_strcasecmp(p->data, SN_md5_sha1) == 0) { + if (!ossl_prov_macctx_load_from_params(&ctx->P_hash, params, + OSSL_MAC_NAME_HMAC, + NULL, SN_md5, libctx) + || !ossl_prov_macctx_load_from_params(&ctx->P_sha1, params, + OSSL_MAC_NAME_HMAC, + NULL, SN_sha1, libctx)) + return 0; + } else { + EVP_MAC_CTX_free(ctx->P_sha1); + if (!ossl_prov_macctx_load_from_params(&ctx->P_hash, params, + OSSL_MAC_NAME_HMAC, + NULL, NULL, libctx)) + return 0; + } + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL) { + OPENSSL_clear_free(ctx->sec, ctx->seclen); + ctx->sec = NULL; + if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->sec, 0, &ctx->seclen)) + return 0; + } + /* The seed fields concatenate, so process them all */ + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SEED)) != NULL) { + for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1, + OSSL_KDF_PARAM_SEED)) { + const void *q = ctx->seed + ctx->seedlen; + size_t sz = 0; + + if (p->data_size != 0 + && p->data != NULL + && !OSSL_PARAM_get_octet_string(p, (void **)&q, + TLS1_PRF_MAXBUF - ctx->seedlen, + &sz)) + return 0; + ctx->seedlen += sz; + } + } + return 1; +} + +static const OSSL_PARAM *kdf_tls1_prf_settable_ctx_params( + ossl_unused void *ctx, ossl_unused void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_tls1_prf_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, SIZE_MAX); + return -2; +} + +static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params( + ossl_unused void *ctx, ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_tls1_prf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_tls1_prf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_tls1_prf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_tls1_prf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_tls1_prf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_tls1_prf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, + (void(*)(void))kdf_tls1_prf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_tls1_prf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, + (void(*)(void))kdf_tls1_prf_get_ctx_params }, + { 0, NULL } +}; + +/* + * Refer to "The TLS Protocol Version 1.0" Section 5 + * (https://tools.ietf.org/html/rfc2246#section-5) and + * "The Transport Layer Security (TLS) Protocol Version 1.2" Section 5 + * (https://tools.ietf.org/html/rfc5246#section-5). + * + * P_<hash> is an expansion function that uses a single hash function to expand + * a secret and seed into an arbitrary quantity of output: + * + * P_<hash>(secret, seed) = HMAC_<hash>(secret, A(1) + seed) + + * HMAC_<hash>(secret, A(2) + seed) + + * HMAC_<hash>(secret, A(3) + seed) + ... + * + * where + indicates concatenation. P_<hash> can be iterated as many times as + * is necessary to produce the required quantity of data. + * + * A(i) is defined as: + * A(0) = seed + * A(i) = HMAC_<hash>(secret, A(i-1)) + */ +static int tls1_prf_P_hash(EVP_MAC_CTX *ctx_init, + const unsigned char *sec, size_t sec_len, + const unsigned char *seed, size_t seed_len, + unsigned char *out, size_t olen) +{ + size_t chunk; + EVP_MAC_CTX *ctx = NULL, *ctx_Ai = NULL; + unsigned char Ai[EVP_MAX_MD_SIZE]; + size_t Ai_len; + int ret = 0; + + if (!EVP_MAC_init(ctx_init, sec, sec_len, NULL)) + goto err; + chunk = EVP_MAC_CTX_get_mac_size(ctx_init); + if (chunk == 0) + goto err; + /* A(0) = seed */ + ctx_Ai = EVP_MAC_CTX_dup(ctx_init); + if (ctx_Ai == NULL) + goto err; + if (seed != NULL && !EVP_MAC_update(ctx_Ai, seed, seed_len)) + goto err; + + for (;;) { + /* calc: A(i) = HMAC_<hash>(secret, A(i-1)) */ + if (!EVP_MAC_final(ctx_Ai, Ai, &Ai_len, sizeof(Ai))) + goto err; + EVP_MAC_CTX_free(ctx_Ai); + ctx_Ai = NULL; + + /* calc next chunk: HMAC_<hash>(secret, A(i) + seed) */ + ctx = EVP_MAC_CTX_dup(ctx_init); + if (ctx == NULL) + goto err; + if (!EVP_MAC_update(ctx, Ai, Ai_len)) + goto err; + /* save state for calculating next A(i) value */ + if (olen > chunk) { + ctx_Ai = EVP_MAC_CTX_dup(ctx); + if (ctx_Ai == NULL) + goto err; + } + if (seed != NULL && !EVP_MAC_update(ctx, seed, seed_len)) + goto err; + if (olen <= chunk) { + /* last chunk - use Ai as temp bounce buffer */ + if (!EVP_MAC_final(ctx, Ai, &Ai_len, sizeof(Ai))) + goto err; + memcpy(out, Ai, olen); + break; + } + if (!EVP_MAC_final(ctx, out, NULL, olen)) + goto err; + EVP_MAC_CTX_free(ctx); + ctx = NULL; + out += chunk; + olen -= chunk; + } + ret = 1; + err: + EVP_MAC_CTX_free(ctx); + EVP_MAC_CTX_free(ctx_Ai); + OPENSSL_cleanse(Ai, sizeof(Ai)); + return ret; +} + +/* + * Refer to "The TLS Protocol Version 1.0" Section 5 + * (https://tools.ietf.org/html/rfc2246#section-5) and + * "The Transport Layer Security (TLS) Protocol Version 1.2" Section 5 + * (https://tools.ietf.org/html/rfc5246#section-5). + * + * For TLS v1.0 and TLS v1.1: + * + * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR + * P_SHA-1(S2, label + seed) + * + * S1 is taken from the first half of the secret, S2 from the second half. + * + * L_S = length in bytes of secret; + * L_S1 = L_S2 = ceil(L_S / 2); + * + * For TLS v1.2: + * + * PRF(secret, label, seed) = P_<hash>(secret, label + seed) + */ +static int tls1_prf_alg(EVP_MAC_CTX *mdctx, EVP_MAC_CTX *sha1ctx, + const unsigned char *sec, size_t slen, + const unsigned char *seed, size_t seed_len, + unsigned char *out, size_t olen) +{ + if (sha1ctx != NULL) { + /* TLS v1.0 and TLS v1.1 */ + size_t i; + unsigned char *tmp; + /* calc: L_S1 = L_S2 = ceil(L_S / 2) */ + size_t L_S1 = (slen + 1) / 2; + size_t L_S2 = L_S1; + + if (!tls1_prf_P_hash(mdctx, sec, L_S1, + seed, seed_len, out, olen)) + return 0; + + if ((tmp = OPENSSL_malloc(olen)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (!tls1_prf_P_hash(sha1ctx, sec + slen - L_S2, L_S2, + seed, seed_len, tmp, olen)) { + OPENSSL_clear_free(tmp, olen); + return 0; + } + for (i = 0; i < olen; i++) + out[i] ^= tmp[i]; + OPENSSL_clear_free(tmp, olen); + return 1; + } + + /* TLS v1.2 */ + if (!tls1_prf_P_hash(mdctx, sec, slen, seed, seed_len, out, olen)) + return 0; + + return 1; +} diff --git a/providers/implementations/kdfs/x942kdf.c b/providers/implementations/kdfs/x942kdf.c new file mode 100644 index 000000000000..b1bc6f7e1ba5 --- /dev/null +++ b/providers/implementations/kdfs/x942kdf.c @@ -0,0 +1,594 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "e_os.h" +#include <openssl/core_names.h> +#include <openssl/core_dispatch.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/params.h> +#include <openssl/proverr.h> +#include "internal/packet.h" +#include "internal/der.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_util.h" +#include "prov/der_wrap.h" + +#define X942KDF_MAX_INLEN (1 << 30) + +static OSSL_FUNC_kdf_newctx_fn x942kdf_new; +static OSSL_FUNC_kdf_freectx_fn x942kdf_free; +static OSSL_FUNC_kdf_reset_fn x942kdf_reset; +static OSSL_FUNC_kdf_derive_fn x942kdf_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn x942kdf_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn x942kdf_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn x942kdf_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn x942kdf_get_ctx_params; + +typedef struct { + void *provctx; + PROV_DIGEST digest; + unsigned char *secret; + size_t secret_len; + unsigned char *acvpinfo; + size_t acvpinfo_len; + unsigned char *partyuinfo, *partyvinfo, *supp_pubinfo, *supp_privinfo; + size_t partyuinfo_len, partyvinfo_len, supp_pubinfo_len, supp_privinfo_len; + size_t dkm_len; + const unsigned char *cek_oid; + size_t cek_oid_len; + int use_keybits; +} KDF_X942; + +/* + * A table of allowed wrapping algorithms, oids and the associated output + * lengths. + * NOTE: RC2wrap and camellia128_wrap have been removed as there are no + * corresponding ciphers for these operations. + */ +static const struct { + const char *name; + const unsigned char *oid; + size_t oid_len; + size_t keklen; /* size in bytes */ +} kek_algs[] = { + { "AES-128-WRAP", ossl_der_oid_id_aes128_wrap, DER_OID_SZ_id_aes128_wrap, + 16 }, + { "AES-192-WRAP", ossl_der_oid_id_aes192_wrap, DER_OID_SZ_id_aes192_wrap, + 24 }, + { "AES-256-WRAP", ossl_der_oid_id_aes256_wrap, DER_OID_SZ_id_aes256_wrap, + 32 }, +#ifndef FIPS_MODULE + { "DES3-WRAP", ossl_der_oid_id_alg_CMS3DESwrap, + DER_OID_SZ_id_alg_CMS3DESwrap, 24 }, +#endif +}; + +static int find_alg_id(OSSL_LIB_CTX *libctx, const char *algname, + const char *propq, size_t *id) +{ + int ret = 1; + size_t i; + EVP_CIPHER *cipher; + + cipher = EVP_CIPHER_fetch(libctx, algname, propq); + if (cipher != NULL) { + for (i = 0; i < OSSL_NELEM(kek_algs); i++) { + if (EVP_CIPHER_is_a(cipher, kek_algs[i].name)) { + *id = i; + goto end; + } + } + } + ret = 0; + ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_CEK_ALG); +end: + EVP_CIPHER_free(cipher); + return ret; +} + +static int DER_w_keyinfo(WPACKET *pkt, + const unsigned char *der_oid, size_t der_oidlen, + unsigned char **pcounter) +{ + return ossl_DER_w_begin_sequence(pkt, -1) + /* Store the initial value of 1 into the counter */ + && ossl_DER_w_octet_string_uint32(pkt, -1, 1) + /* Remember where we stored the counter in the buffer */ + && (pcounter == NULL + || (*pcounter = WPACKET_get_curr(pkt)) != NULL) + && ossl_DER_w_precompiled(pkt, -1, der_oid, der_oidlen) + && ossl_DER_w_end_sequence(pkt, -1); +} + +static int der_encode_sharedinfo(WPACKET *pkt, unsigned char *buf, size_t buflen, + const unsigned char *der_oid, size_t der_oidlen, + const unsigned char *acvp, size_t acvplen, + const unsigned char *partyu, size_t partyulen, + const unsigned char *partyv, size_t partyvlen, + const unsigned char *supp_pub, size_t supp_publen, + const unsigned char *supp_priv, size_t supp_privlen, + uint32_t keylen_bits, unsigned char **pcounter) +{ + return (buf != NULL ? WPACKET_init_der(pkt, buf, buflen) : + WPACKET_init_null_der(pkt)) + && ossl_DER_w_begin_sequence(pkt, -1) + && (supp_priv == NULL + || ossl_DER_w_octet_string(pkt, 3, supp_priv, supp_privlen)) + && (supp_pub == NULL + || ossl_DER_w_octet_string(pkt, 2, supp_pub, supp_publen)) + && (keylen_bits == 0 + || ossl_DER_w_octet_string_uint32(pkt, 2, keylen_bits)) + && (partyv == NULL || ossl_DER_w_octet_string(pkt, 1, partyv, partyvlen)) + && (partyu == NULL || ossl_DER_w_octet_string(pkt, 0, partyu, partyulen)) + && (acvp == NULL || ossl_DER_w_precompiled(pkt, -1, acvp, acvplen)) + && DER_w_keyinfo(pkt, der_oid, der_oidlen, pcounter) + && ossl_DER_w_end_sequence(pkt, -1) + && WPACKET_finish(pkt); +} + +/* + * Encode the other info structure. + * + * The ANS X9.42-2003 standard uses OtherInfo: + * + * OtherInfo ::= SEQUENCE { + * keyInfo KeySpecificInfo, + * partyUInfo [0] OCTET STRING OPTIONAL, + * partyVInfo [1] OCTET STRING OPTIONAL, + * suppPubInfo [2] OCTET STRING OPTIONAL, + * suppPrivInfo [3] OCTET STRING OPTIONAL + * } + * + * KeySpecificInfo ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * counter OCTET STRING SIZE (4..4) + * } + * + * RFC2631 Section 2.1.2 Contains the following definition for OtherInfo + * + * OtherInfo ::= SEQUENCE { + * keyInfo KeySpecificInfo, + * partyAInfo [0] OCTET STRING OPTIONAL, + * suppPubInfo [2] OCTET STRING + * } + * Where suppPubInfo is the key length (in bits) (stored into 4 bytes) + * + * |keylen| is the length (in bytes) of the generated KEK. It is stored into + * suppPubInfo (in bits). It is ignored if the value is 0. + * |cek_oid| The oid of the key wrapping algorithm. + * |cek_oidlen| The length (in bytes) of the key wrapping algorithm oid, + * |acvp| is the optional blob of DER data representing one or more of the + * OtherInfo fields related to |partyu|, |partyv|, |supp_pub| and |supp_priv|. + * This field should noramlly be NULL. If |acvp| is non NULL then |partyu|, + * |partyv|, |supp_pub| and |supp_priv| should all be NULL. + * |acvp_len| is the |acvp| length (in bytes). + * |partyu| is the optional public info contributed by the initiator. + * It can be NULL. (It is also used as the ukm by CMS). + * |partyu_len| is the |partyu| length (in bytes). + * |partyv| is the optional public info contributed by the responder. + * It can be NULL. + * |partyv_len| is the |partyv| length (in bytes). + * |supp_pub| is the optional additional, mutually-known public information. + * It can be NULL. |keylen| should be 0 if this is not NULL. + * |supp_pub_len| is the |supp_pub| length (in bytes). + * |supp_priv| is the optional additional, mutually-known private information. + * It can be NULL. + * |supp_priv_len| is the |supp_priv| length (in bytes). + * |der| is the returned encoded data. It must be freed by the caller. + * |der_len| is the returned size of the encoded data. + * |out_ctr| returns a pointer to the counter data which is embedded inside the + * encoded data. This allows the counter bytes to be updated without + * re-encoding. + * + * Returns: 1 if successfully encoded, or 0 otherwise. + * Assumptions: |der|, |der_len| & |out_ctr| are not NULL. + */ +static int +x942_encode_otherinfo(size_t keylen, + const unsigned char *cek_oid, size_t cek_oid_len, + const unsigned char *acvp, size_t acvp_len, + const unsigned char *partyu, size_t partyu_len, + const unsigned char *partyv, size_t partyv_len, + const unsigned char *supp_pub, size_t supp_pub_len, + const unsigned char *supp_priv, size_t supp_priv_len, + unsigned char **der, size_t *der_len, + unsigned char **out_ctr) +{ + int ret = 0; + unsigned char *pcounter = NULL, *der_buf = NULL; + size_t der_buflen = 0; + WPACKET pkt; + uint32_t keylen_bits; + + /* keylenbits must fit into 4 bytes */ + if (keylen > 0xFFFFFF) + return 0; + keylen_bits = 8 * keylen; + + /* Calculate the size of the buffer */ + if (!der_encode_sharedinfo(&pkt, NULL, 0, cek_oid, cek_oid_len, + acvp, acvp_len, + partyu, partyu_len, partyv, partyv_len, + supp_pub, supp_pub_len, supp_priv, supp_priv_len, + keylen_bits, NULL) + || !WPACKET_get_total_written(&pkt, &der_buflen)) + goto err; + WPACKET_cleanup(&pkt); + /* Alloc the buffer */ + der_buf = OPENSSL_zalloc(der_buflen); + if (der_buf == NULL) + goto err; + /* Encode into the buffer */ + if (!der_encode_sharedinfo(&pkt, der_buf, der_buflen, cek_oid, cek_oid_len, + acvp, acvp_len, + partyu, partyu_len, partyv, partyv_len, + supp_pub, supp_pub_len, supp_priv, supp_priv_len, + keylen_bits, &pcounter)) + goto err; + /* + * Since we allocated the exact size required, the buffer should point to the + * start of the alllocated buffer at this point. + */ + if (WPACKET_get_curr(&pkt) != der_buf) + goto err; + + /* + * The data for the DER encoded octet string of a 32 bit counter = 1 + * should be 04 04 00 00 00 01 + * So just check the header is correct and skip over it. + * This counter will be incremented in the kdf update loop. + */ + if (pcounter == NULL + || pcounter[0] != 0x04 + || pcounter[1] != 0x04) + goto err; + *out_ctr = (pcounter + 2); + *der = der_buf; + *der_len = der_buflen; + ret = 1; +err: + WPACKET_cleanup(&pkt); + return ret; +} + +static int x942kdf_hash_kdm(const EVP_MD *kdf_md, + const unsigned char *z, size_t z_len, + const unsigned char *other, size_t other_len, + unsigned char *ctr, + unsigned char *derived_key, size_t derived_key_len) +{ + int ret = 0, hlen; + size_t counter, out_len, len = derived_key_len; + unsigned char mac[EVP_MAX_MD_SIZE]; + unsigned char *out = derived_key; + EVP_MD_CTX *ctx = NULL, *ctx_init = NULL; + + if (z_len > X942KDF_MAX_INLEN + || other_len > X942KDF_MAX_INLEN + || derived_key_len > X942KDF_MAX_INLEN + || derived_key_len == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); + return 0; + } + + hlen = EVP_MD_get_size(kdf_md); + if (hlen <= 0) + return 0; + out_len = (size_t)hlen; + + ctx = EVP_MD_CTX_create(); + ctx_init = EVP_MD_CTX_create(); + if (ctx == NULL || ctx_init == NULL) + goto end; + + if (!EVP_DigestInit(ctx_init, kdf_md)) + goto end; + + for (counter = 1;; counter++) { + /* updating the ctr modifies 4 bytes in the 'other' buffer */ + ctr[0] = (unsigned char)((counter >> 24) & 0xff); + ctr[1] = (unsigned char)((counter >> 16) & 0xff); + ctr[2] = (unsigned char)((counter >> 8) & 0xff); + ctr[3] = (unsigned char)(counter & 0xff); + + if (!EVP_MD_CTX_copy_ex(ctx, ctx_init) + || !EVP_DigestUpdate(ctx, z, z_len) + || !EVP_DigestUpdate(ctx, other, other_len)) + goto end; + if (len >= out_len) { + if (!EVP_DigestFinal_ex(ctx, out, NULL)) + goto end; + out += out_len; + len -= out_len; + if (len == 0) + break; + } else { + if (!EVP_DigestFinal_ex(ctx, mac, NULL)) + goto end; + memcpy(out, mac, len); + break; + } + } + ret = 1; +end: + EVP_MD_CTX_free(ctx); + EVP_MD_CTX_free(ctx_init); + OPENSSL_cleanse(mac, sizeof(mac)); + return ret; +} + +static void *x942kdf_new(void *provctx) +{ + KDF_X942 *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + ctx->provctx = provctx; + ctx->use_keybits = 1; + return ctx; +} + +static void x942kdf_reset(void *vctx) +{ + KDF_X942 *ctx = (KDF_X942 *)vctx; + void *provctx = ctx->provctx; + + ossl_prov_digest_reset(&ctx->digest); + OPENSSL_clear_free(ctx->secret, ctx->secret_len); + OPENSSL_clear_free(ctx->acvpinfo, ctx->acvpinfo_len); + OPENSSL_clear_free(ctx->partyuinfo, ctx->partyuinfo_len); + OPENSSL_clear_free(ctx->partyvinfo, ctx->partyvinfo_len); + OPENSSL_clear_free(ctx->supp_pubinfo, ctx->supp_pubinfo_len); + OPENSSL_clear_free(ctx->supp_privinfo, ctx->supp_privinfo_len); + memset(ctx, 0, sizeof(*ctx)); + ctx->provctx = provctx; + ctx->use_keybits = 1; +} + +static void x942kdf_free(void *vctx) +{ + KDF_X942 *ctx = (KDF_X942 *)vctx; + + if (ctx != NULL) { + x942kdf_reset(ctx); + OPENSSL_free(ctx); + } +} + +static int x942kdf_set_buffer(unsigned char **out, size_t *out_len, + const OSSL_PARAM *p) +{ + if (p->data_size == 0 || p->data == NULL) + return 1; + + OPENSSL_free(*out); + *out = NULL; + return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len); +} + +static size_t x942kdf_size(KDF_X942 *ctx) +{ + int len; + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + len = EVP_MD_get_size(md); + return (len <= 0) ? 0 : (size_t)len; +} + +static int x942kdf_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_X942 *ctx = (KDF_X942 *)vctx; + const EVP_MD *md; + int ret = 0; + unsigned char *ctr; + unsigned char *der = NULL; + size_t der_len = 0; + + if (!ossl_prov_is_running() || !x942kdf_set_ctx_params(ctx, params)) + return 0; + + /* + * These 2 options encode to the same field so only one of them should be + * active at once. + */ + if (ctx->use_keybits && ctx->supp_pubinfo != NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PUBINFO); + return 0; + } + /* + * If the blob of acvp data is used then the individual info fields that it + * replaces should not also be defined. + */ + if (ctx->acvpinfo != NULL + && (ctx->partyuinfo != NULL + || ctx->partyvinfo != NULL + || ctx->supp_pubinfo != NULL + || ctx->supp_privinfo != NULL)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA); + return 0; + } + if (ctx->secret == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); + return 0; + } + md = ossl_prov_digest_md(&ctx->digest); + if (md == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); + return 0; + } + if (ctx->cek_oid == NULL || ctx->cek_oid_len == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CEK_ALG); + return 0; + } + if (ctx->partyuinfo != NULL && ctx->partyuinfo_len >= X942KDF_MAX_INLEN) { + /* + * Note the ukm length MUST be 512 bits if it is used. + * For backwards compatibility the old check is being done. + */ + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_UKM_LENGTH); + return 0; + } + /* generate the otherinfo der */ + if (!x942_encode_otherinfo(ctx->use_keybits ? ctx->dkm_len : 0, + ctx->cek_oid, ctx->cek_oid_len, + ctx->acvpinfo, ctx->acvpinfo_len, + ctx->partyuinfo, ctx->partyuinfo_len, + ctx->partyvinfo, ctx->partyvinfo_len, + ctx->supp_pubinfo, ctx->supp_pubinfo_len, + ctx->supp_privinfo, ctx->supp_privinfo_len, + &der, &der_len, &ctr)) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_ENCODING); + return 0; + } + ret = x942kdf_hash_kdm(md, ctx->secret, ctx->secret_len, + der, der_len, ctr, key, keylen); + OPENSSL_free(der); + return ret; +} + +static int x942kdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p, *pq; + KDF_X942 *ctx = vctx; + OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx); + const char *propq = NULL; + size_t id; + + if (params == NULL) + return 1; + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET); + if (p == NULL) + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY); + if (p != NULL && !x942kdf_set_buffer(&ctx->secret, &ctx->secret_len, p)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_X942_ACVPINFO); + if (p != NULL + && !x942kdf_set_buffer(&ctx->acvpinfo, &ctx->acvpinfo_len, p)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_X942_PARTYUINFO); + if (p == NULL) + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_UKM); + if (p != NULL + && !x942kdf_set_buffer(&ctx->partyuinfo, &ctx->partyuinfo_len, p)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_X942_PARTYVINFO); + if (p != NULL + && !x942kdf_set_buffer(&ctx->partyvinfo, &ctx->partyvinfo_len, p)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_X942_USE_KEYBITS); + if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->use_keybits)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_X942_SUPP_PUBINFO); + if (p != NULL) { + if (!x942kdf_set_buffer(&ctx->supp_pubinfo, &ctx->supp_pubinfo_len, p)) + return 0; + ctx->use_keybits = 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_X942_SUPP_PRIVINFO); + if (p != NULL + && !x942kdf_set_buffer(&ctx->supp_privinfo, &ctx->supp_privinfo_len, p)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CEK_ALG); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + pq = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_PROPERTIES); + /* + * We already grab the properties during ossl_prov_digest_load_from_params() + * so there is no need to check the validity again.. + */ + if (pq != NULL) + propq = p->data; + if (find_alg_id(provctx, p->data, propq, &id) == 0) + return 0; + ctx->cek_oid = kek_algs[id].oid; + ctx->cek_oid_len = kek_algs[id].oid_len; + ctx->dkm_len = kek_algs[id].keklen; + } + return 1; +} + +static const OSSL_PARAM *x942kdf_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_UKM, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_X942_ACVPINFO, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_X942_PARTYUINFO, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_X942_PARTYVINFO, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_X942_SUPP_PUBINFO, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_X942_SUPP_PRIVINFO, NULL, 0), + OSSL_PARAM_int(OSSL_KDF_PARAM_X942_USE_KEYBITS, NULL), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int x942kdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + KDF_X942 *ctx = (KDF_X942 *)vctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, x942kdf_size(ctx)); + return -2; +} + +static const OSSL_PARAM *x942kdf_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_kdf_x942_kdf_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))x942kdf_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))x942kdf_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))x942kdf_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))x942kdf_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))x942kdf_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))x942kdf_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))x942kdf_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))x942kdf_get_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/kem/build.info b/providers/implementations/kem/build.info new file mode 100644 index 000000000000..dbb1b7d750d9 --- /dev/null +++ b/providers/implementations/kem/build.info @@ -0,0 +1,6 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$RSA_KEM_GOAL=../../libdefault.a ../../libfips.a + +SOURCE[$RSA_KEM_GOAL]=rsa_kem.c diff --git a/providers/implementations/kem/rsa_kem.c b/providers/implementations/kem/rsa_kem.c new file mode 100644 index 000000000000..882cf161258a --- /dev/null +++ b/providers/implementations/kem/rsa_kem.c @@ -0,0 +1,364 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * RSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" +#include "internal/nelem.h" + +#include <openssl/crypto.h> +#include <openssl/evp.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/rsa.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include "crypto/rsa.h" +#include <openssl/proverr.h> +#include "prov/provider_ctx.h" +#include "prov/implementations.h" +#include "prov/securitycheck.h" + +static OSSL_FUNC_kem_newctx_fn rsakem_newctx; +static OSSL_FUNC_kem_encapsulate_init_fn rsakem_encapsulate_init; +static OSSL_FUNC_kem_encapsulate_fn rsakem_generate; +static OSSL_FUNC_kem_decapsulate_init_fn rsakem_decapsulate_init; +static OSSL_FUNC_kem_decapsulate_fn rsakem_recover; +static OSSL_FUNC_kem_freectx_fn rsakem_freectx; +static OSSL_FUNC_kem_dupctx_fn rsakem_dupctx; +static OSSL_FUNC_kem_get_ctx_params_fn rsakem_get_ctx_params; +static OSSL_FUNC_kem_gettable_ctx_params_fn rsakem_gettable_ctx_params; +static OSSL_FUNC_kem_set_ctx_params_fn rsakem_set_ctx_params; +static OSSL_FUNC_kem_settable_ctx_params_fn rsakem_settable_ctx_params; + +/* + * Only the KEM for RSASVE as defined in SP800-56b r2 is implemented + * currently. + */ +#define KEM_OP_UNDEFINED -1 +#define KEM_OP_RSASVE 0 + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes RSA structures, so + * we use that here too. + */ +typedef struct { + OSSL_LIB_CTX *libctx; + RSA *rsa; + int op; +} PROV_RSA_CTX; + +static const OSSL_ITEM rsakem_opname_id_map[] = { + { KEM_OP_RSASVE, OSSL_KEM_PARAM_OPERATION_RSASVE }, +}; + +static int name2id(const char *name, const OSSL_ITEM *map, size_t sz) +{ + size_t i; + + if (name == NULL) + return -1; + + for (i = 0; i < sz; ++i) { + if (OPENSSL_strcasecmp(map[i].ptr, name) == 0) + return map[i].id; + } + return -1; +} + +static int rsakem_opname2id(const char *name) +{ + return name2id(name, rsakem_opname_id_map, OSSL_NELEM(rsakem_opname_id_map)); +} + +static void *rsakem_newctx(void *provctx) +{ + PROV_RSA_CTX *prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX)); + + if (prsactx == NULL) + return NULL; + prsactx->libctx = PROV_LIBCTX_OF(provctx); + prsactx->op = KEM_OP_UNDEFINED; + + return prsactx; +} + +static void rsakem_freectx(void *vprsactx) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + RSA_free(prsactx->rsa); + OPENSSL_free(prsactx); +} + +static void *rsakem_dupctx(void *vprsactx) +{ + PROV_RSA_CTX *srcctx = (PROV_RSA_CTX *)vprsactx; + PROV_RSA_CTX *dstctx; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + if (dstctx->rsa != NULL && !RSA_up_ref(dstctx->rsa)) { + OPENSSL_free(dstctx); + return NULL; + } + return dstctx; +} + +static int rsakem_init(void *vprsactx, void *vrsa, + const OSSL_PARAM params[], int operation) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (prsactx == NULL || vrsa == NULL) + return 0; + + if (!ossl_rsa_check_key(prsactx->libctx, vrsa, operation)) + return 0; + + if (!RSA_up_ref(vrsa)) + return 0; + RSA_free(prsactx->rsa); + prsactx->rsa = vrsa; + + return rsakem_set_ctx_params(prsactx, params); +} + +static int rsakem_encapsulate_init(void *vprsactx, void *vrsa, + const OSSL_PARAM params[]) +{ + return rsakem_init(vprsactx, vrsa, params, EVP_PKEY_OP_ENCAPSULATE); +} + +static int rsakem_decapsulate_init(void *vprsactx, void *vrsa, + const OSSL_PARAM params[]) +{ + return rsakem_init(vprsactx, vrsa, params, EVP_PKEY_OP_DECAPSULATE); +} + +static int rsakem_get_ctx_params(void *vprsactx, OSSL_PARAM *params) +{ + PROV_RSA_CTX *ctx = (PROV_RSA_CTX *)vprsactx; + + return ctx != NULL; +} + +static const OSSL_PARAM known_gettable_rsakem_ctx_params[] = { + OSSL_PARAM_END +}; + +static const OSSL_PARAM *rsakem_gettable_ctx_params(ossl_unused void *vprsactx, + ossl_unused void *provctx) +{ + return known_gettable_rsakem_ctx_params; +} + +static int rsakem_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + const OSSL_PARAM *p; + int op; + + if (prsactx == NULL) + return 0; + if (params == NULL) + return 1; + + + p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_OPERATION); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + op = rsakem_opname2id(p->data); + if (op < 0) + return 0; + prsactx->op = op; + } + return 1; +} + +static const OSSL_PARAM known_settable_rsakem_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_KEM_PARAM_OPERATION, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *rsakem_settable_ctx_params(ossl_unused void *vprsactx, + ossl_unused void *provctx) +{ + return known_settable_rsakem_ctx_params; +} + +/* + * NIST.SP.800-56Br2 + * 7.2.1.2 RSASVE Generate Operation (RSASVE.GENERATE). + * + * Generate a random in the range 1 < z < (n – 1) + */ +static int rsasve_gen_rand_bytes(RSA *rsa_pub, + unsigned char *out, int outlen) +{ + int ret = 0; + BN_CTX *bnctx; + BIGNUM *z, *nminus3; + + bnctx = BN_CTX_secure_new_ex(ossl_rsa_get0_libctx(rsa_pub)); + if (bnctx == NULL) + return 0; + + /* + * Generate a random in the range 1 < z < (n – 1). + * Since BN_priv_rand_range_ex() returns a value in range 0 <= r < max + * We can achieve this by adding 2.. but then we need to subtract 3 from + * the upper bound i.e: 2 + (0 <= r < (n - 3)) + */ + BN_CTX_start(bnctx); + nminus3 = BN_CTX_get(bnctx); + z = BN_CTX_get(bnctx); + ret = (z != NULL + && (BN_copy(nminus3, RSA_get0_n(rsa_pub)) != NULL) + && BN_sub_word(nminus3, 3) + && BN_priv_rand_range_ex(z, nminus3, 0, bnctx) + && BN_add_word(z, 2) + && (BN_bn2binpad(z, out, outlen) == outlen)); + BN_CTX_end(bnctx); + BN_CTX_free(bnctx); + return ret; +} + +/* + * NIST.SP.800-56Br2 + * 7.2.1.2 RSASVE Generate Operation (RSASVE.GENERATE). + */ +static int rsasve_generate(PROV_RSA_CTX *prsactx, + unsigned char *out, size_t *outlen, + unsigned char *secret, size_t *secretlen) +{ + int ret; + size_t nlen; + + /* Step (1): nlen = Ceil(len(n)/8) */ + nlen = RSA_size(prsactx->rsa); + + if (out == NULL) { + if (nlen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + if (outlen == NULL && secretlen == NULL) + return 0; + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + return 1; + } + /* + * Step (2): Generate a random byte string z of nlen bytes where + * 1 < z < n - 1 + */ + if (!rsasve_gen_rand_bytes(prsactx->rsa, secret, nlen)) + return 0; + + /* Step(3): out = RSAEP((n,e), z) */ + ret = RSA_public_encrypt(nlen, secret, out, prsactx->rsa, RSA_NO_PADDING); + if (ret) { + ret = 1; + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + } else { + OPENSSL_cleanse(secret, nlen); + } + return ret; +} + +/* + * NIST.SP.800-56Br2 + * 7.2.1.3 RSASVE Recovery Operation (RSASVE.RECOVER). + */ +static int rsasve_recover(PROV_RSA_CTX *prsactx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen) +{ + size_t nlen; + + /* Step (1): get the byte length of n */ + nlen = RSA_size(prsactx->rsa); + + if (out == NULL) { + if (nlen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + *outlen = nlen; + return 1; + } + + /* Step (2): check the input ciphertext 'inlen' matches the nlen */ + if (inlen != nlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); + return 0; + } + /* Step (3): out = RSADP((n,d), in) */ + return (RSA_private_decrypt(inlen, in, out, prsactx->rsa, RSA_NO_PADDING) > 0); +} + +static int rsakem_generate(void *vprsactx, unsigned char *out, size_t *outlen, + unsigned char *secret, size_t *secretlen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + switch (prsactx->op) { + case KEM_OP_RSASVE: + return rsasve_generate(prsactx, out, outlen, secret, secretlen); + default: + return -2; + } +} + +static int rsakem_recover(void *vprsactx, unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + switch (prsactx->op) { + case KEM_OP_RSASVE: + return rsasve_recover(prsactx, out, outlen, in, inlen); + default: + return -2; + } +} + +const OSSL_DISPATCH ossl_rsa_asym_kem_functions[] = { + { OSSL_FUNC_KEM_NEWCTX, (void (*)(void))rsakem_newctx }, + { OSSL_FUNC_KEM_ENCAPSULATE_INIT, + (void (*)(void))rsakem_encapsulate_init }, + { OSSL_FUNC_KEM_ENCAPSULATE, (void (*)(void))rsakem_generate }, + { OSSL_FUNC_KEM_DECAPSULATE_INIT, + (void (*)(void))rsakem_decapsulate_init }, + { OSSL_FUNC_KEM_DECAPSULATE, (void (*)(void))rsakem_recover }, + { OSSL_FUNC_KEM_FREECTX, (void (*)(void))rsakem_freectx }, + { OSSL_FUNC_KEM_DUPCTX, (void (*)(void))rsakem_dupctx }, + { OSSL_FUNC_KEM_GET_CTX_PARAMS, + (void (*)(void))rsakem_get_ctx_params }, + { OSSL_FUNC_KEM_GETTABLE_CTX_PARAMS, + (void (*)(void))rsakem_gettable_ctx_params }, + { OSSL_FUNC_KEM_SET_CTX_PARAMS, + (void (*)(void))rsakem_set_ctx_params }, + { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS, + (void (*)(void))rsakem_settable_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/keymgmt/build.info b/providers/implementations/keymgmt/build.info new file mode 100644 index 000000000000..0d86907aed69 --- /dev/null +++ b/providers/implementations/keymgmt/build.info @@ -0,0 +1,41 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$DH_GOAL=../../libdefault.a ../../libfips.a +$DSA_GOAL=../../libdefault.a ../../libfips.a +$EC_GOAL=../../libdefault.a ../../libfips.a +$ECX_GOAL=../../libdefault.a ../../libfips.a +$KDF_GOAL=../../libdefault.a ../../libfips.a +$MAC_GOAL=../../libdefault.a ../../libfips.a +$RSA_GOAL=../../libdefault.a ../../libfips.a + +IF[{- !$disabled{dh} -}] + SOURCE[$DH_GOAL]=dh_kmgmt.c +ENDIF +IF[{- !$disabled{dsa} -}] + SOURCE[$DSA_GOAL]=dsa_kmgmt.c +ENDIF +IF[{- !$disabled{ec} -}] + SOURCE[$EC_GOAL]=ec_kmgmt.c +ENDIF + +IF[{- !$disabled{asm} -}] + $ECDEF_s390x=S390X_EC_ASM + + # Now that we have defined all the arch specific variables, use the + # appropriate one, and define the appropriate macros + IF[$ECASM_{- $target{asm_arch} -}] + $ECDEF=$ECDEF_{- $target{asm_arch} -} + ENDIF +ENDIF + +IF[{- !$disabled{ec} -}] + SOURCE[$ECX_GOAL]=ecx_kmgmt.c + DEFINE[$ECX_GOAL]=$ECDEF +ENDIF + +SOURCE[$RSA_GOAL]=rsa_kmgmt.c + +SOURCE[$KDF_GOAL]=kdf_legacy_kmgmt.c + +SOURCE[$MAC_GOAL]=mac_legacy_kmgmt.c diff --git a/providers/implementations/keymgmt/dh_kmgmt.c b/providers/implementations/keymgmt/dh_kmgmt.c new file mode 100644 index 000000000000..9a7dde7c6627 --- /dev/null +++ b/providers/implementations/keymgmt/dh_kmgmt.c @@ -0,0 +1,881 @@ +/* + * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> /* strcmp */ +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "crypto/dh.h" +#include "internal/sizes.h" + +static OSSL_FUNC_keymgmt_new_fn dh_newdata; +static OSSL_FUNC_keymgmt_free_fn dh_freedata; +static OSSL_FUNC_keymgmt_gen_init_fn dh_gen_init; +static OSSL_FUNC_keymgmt_gen_init_fn dhx_gen_init; +static OSSL_FUNC_keymgmt_gen_set_template_fn dh_gen_set_template; +static OSSL_FUNC_keymgmt_gen_set_params_fn dh_gen_set_params; +static OSSL_FUNC_keymgmt_gen_settable_params_fn dh_gen_settable_params; +static OSSL_FUNC_keymgmt_gen_fn dh_gen; +static OSSL_FUNC_keymgmt_gen_cleanup_fn dh_gen_cleanup; +static OSSL_FUNC_keymgmt_load_fn dh_load; +static OSSL_FUNC_keymgmt_get_params_fn dh_get_params; +static OSSL_FUNC_keymgmt_gettable_params_fn dh_gettable_params; +static OSSL_FUNC_keymgmt_set_params_fn dh_set_params; +static OSSL_FUNC_keymgmt_settable_params_fn dh_settable_params; +static OSSL_FUNC_keymgmt_has_fn dh_has; +static OSSL_FUNC_keymgmt_match_fn dh_match; +static OSSL_FUNC_keymgmt_validate_fn dh_validate; +static OSSL_FUNC_keymgmt_import_fn dh_import; +static OSSL_FUNC_keymgmt_import_types_fn dh_import_types; +static OSSL_FUNC_keymgmt_export_fn dh_export; +static OSSL_FUNC_keymgmt_export_types_fn dh_export_types; +static OSSL_FUNC_keymgmt_dup_fn dh_dup; + +#define DH_POSSIBLE_SELECTIONS \ + (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) + +struct dh_gen_ctx { + OSSL_LIB_CTX *libctx; + + FFC_PARAMS *ffc_params; + int selection; + /* All these parameters are used for parameter generation only */ + /* If there is a group name then the remaining parameters are not needed */ + int group_nid; + size_t pbits; + size_t qbits; + unsigned char *seed; /* optional FIPS186-4 param for testing */ + size_t seedlen; + int gindex; /* optional FIPS186-4 generator index (ignored if -1) */ + int gen_type; /* see dhtype2id */ + int generator; /* Used by DH_PARAMGEN_TYPE_GENERATOR in non fips mode only */ + int pcounter; + int hindex; + int priv_len; + + char *mdname; + char *mdprops; + OSSL_CALLBACK *cb; + void *cbarg; + int dh_type; +}; + +static int dh_gen_type_name2id_w_default(const char *name, int type) +{ + if (strcmp(name, "default") == 0) { +#ifdef FIPS_MODULE + if (type == DH_FLAG_TYPE_DHX) + return DH_PARAMGEN_TYPE_FIPS_186_4; + + return DH_PARAMGEN_TYPE_GROUP; +#else + if (type == DH_FLAG_TYPE_DHX) + return DH_PARAMGEN_TYPE_FIPS_186_2; + + return DH_PARAMGEN_TYPE_GENERATOR; +#endif + } + + return ossl_dh_gen_type_name2id(name, type); +} + +static void *dh_newdata(void *provctx) +{ + DH *dh = NULL; + + if (ossl_prov_is_running()) { + dh = ossl_dh_new_ex(PROV_LIBCTX_OF(provctx)); + if (dh != NULL) { + DH_clear_flags(dh, DH_FLAG_TYPE_MASK); + DH_set_flags(dh, DH_FLAG_TYPE_DH); + } + } + return dh; +} + +static void *dhx_newdata(void *provctx) +{ + DH *dh = NULL; + + dh = ossl_dh_new_ex(PROV_LIBCTX_OF(provctx)); + if (dh != NULL) { + DH_clear_flags(dh, DH_FLAG_TYPE_MASK); + DH_set_flags(dh, DH_FLAG_TYPE_DHX); + } + return dh; +} + +static void dh_freedata(void *keydata) +{ + DH_free(keydata); +} + +static int dh_has(const void *keydata, int selection) +{ + const DH *dh = keydata; + int ok = 1; + + if (!ossl_prov_is_running() || dh == NULL) + return 0; + if ((selection & DH_POSSIBLE_SELECTIONS) == 0) + return 1; /* the selection is not missing */ + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && (DH_get0_pub_key(dh) != NULL); + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && (DH_get0_priv_key(dh) != NULL); + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + ok = ok && (DH_get0_p(dh) != NULL && DH_get0_g(dh) != NULL); + return ok; +} + +static int dh_match(const void *keydata1, const void *keydata2, int selection) +{ + const DH *dh1 = keydata1; + const DH *dh2 = keydata2; + int ok = 1; + + if (!ossl_prov_is_running()) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int key_checked = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + const BIGNUM *pa = DH_get0_pub_key(dh1); + const BIGNUM *pb = DH_get0_pub_key(dh2); + + if (pa != NULL && pb != NULL) { + ok = ok && BN_cmp(pa, pb) == 0; + key_checked = 1; + } + } + if (!key_checked + && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + const BIGNUM *pa = DH_get0_priv_key(dh1); + const BIGNUM *pb = DH_get0_priv_key(dh2); + + if (pa != NULL && pb != NULL) { + ok = ok && BN_cmp(pa, pb) == 0; + key_checked = 1; + } + } + ok = ok && key_checked; + } + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + FFC_PARAMS *dhparams1 = ossl_dh_get0_params((DH *)dh1); + FFC_PARAMS *dhparams2 = ossl_dh_get0_params((DH *)dh2); + + ok = ok && ossl_ffc_params_cmp(dhparams1, dhparams2, 1); + } + return ok; +} + +static int dh_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + DH *dh = keydata; + int ok = 1; + + if (!ossl_prov_is_running() || dh == NULL) + return 0; + + if ((selection & DH_POSSIBLE_SELECTIONS) == 0) + return 0; + + /* a key without parameters is meaningless */ + ok = ok && ossl_dh_params_fromdata(dh, params); + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int include_private = + selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; + + ok = ok && ossl_dh_key_fromdata(dh, params, include_private); + } + + return ok; +} + +static int dh_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, + void *cbarg) +{ + DH *dh = keydata; + OSSL_PARAM_BLD *tmpl = NULL; + OSSL_PARAM *params = NULL; + int ok = 1; + + if (!ossl_prov_is_running() || dh == NULL) + return 0; + + tmpl = OSSL_PARAM_BLD_new(); + if (tmpl == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) + ok = ok && ossl_dh_params_todata(dh, tmpl, NULL); + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int include_private = + selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; + + ok = ok && ossl_dh_key_todata(dh, tmpl, NULL, include_private); + } + + if (!ok || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) { + ok = 0; + goto err; + } + + ok = param_cb(params, cbarg); + OSSL_PARAM_free(params); +err: + OSSL_PARAM_BLD_free(tmpl); + return ok; +} + +/* IMEXPORT = IMPORT + EXPORT */ + +# define DH_IMEXPORTABLE_PARAMETERS \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_P, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_Q, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_G, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_COFACTOR, NULL, 0), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_GINDEX, NULL), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_PCOUNTER, NULL), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_H, NULL), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_PRIV_LEN, NULL), \ + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_FFC_SEED, NULL, 0), \ + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0) +# define DH_IMEXPORTABLE_PUBLIC_KEY \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0) +# define DH_IMEXPORTABLE_PRIVATE_KEY \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0) +static const OSSL_PARAM dh_all_types[] = { + DH_IMEXPORTABLE_PARAMETERS, + DH_IMEXPORTABLE_PUBLIC_KEY, + DH_IMEXPORTABLE_PRIVATE_KEY, + OSSL_PARAM_END +}; +static const OSSL_PARAM dh_parameter_types[] = { + DH_IMEXPORTABLE_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM dh_key_types[] = { + DH_IMEXPORTABLE_PUBLIC_KEY, + DH_IMEXPORTABLE_PRIVATE_KEY, + OSSL_PARAM_END +}; +static const OSSL_PARAM *dh_types[] = { + NULL, /* Index 0 = none of them */ + dh_parameter_types, /* Index 1 = parameter types */ + dh_key_types, /* Index 2 = key types */ + dh_all_types /* Index 3 = 1 + 2 */ +}; + +static const OSSL_PARAM *dh_imexport_types(int selection) +{ + int type_select = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) + type_select += 1; + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) + type_select += 2; + return dh_types[type_select]; +} + +static const OSSL_PARAM *dh_import_types(int selection) +{ + return dh_imexport_types(selection); +} + +static const OSSL_PARAM *dh_export_types(int selection) +{ + return dh_imexport_types(selection); +} + +static ossl_inline int dh_get_params(void *key, OSSL_PARAM params[]) +{ + DH *dh = key; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL + && !OSSL_PARAM_set_int(p, DH_bits(dh))) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL + && !OSSL_PARAM_set_int(p, DH_security_bits(dh))) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL + && !OSSL_PARAM_set_int(p, DH_size(dh))) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY)) != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) + return 0; + p->return_size = ossl_dh_key2buf(dh, (unsigned char **)&p->data, + p->data_size, 0); + if (p->return_size == 0) + return 0; + } + + return ossl_dh_params_todata(dh, NULL, params) + && ossl_dh_key_todata(dh, NULL, params, 1); +} + +static const OSSL_PARAM dh_params[] = { + OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + DH_IMEXPORTABLE_PARAMETERS, + DH_IMEXPORTABLE_PUBLIC_KEY, + DH_IMEXPORTABLE_PRIVATE_KEY, + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dh_gettable_params(void *provctx) +{ + return dh_params; +} + +static const OSSL_PARAM dh_known_settable_params[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dh_settable_params(void *provctx) +{ + return dh_known_settable_params; +} + +static int dh_set_params(void *key, const OSSL_PARAM params[]) +{ + DH *dh = key; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY); + if (p != NULL + && (p->data_type != OSSL_PARAM_OCTET_STRING + || !ossl_dh_buf2key(dh, p->data, p->data_size))) + return 0; + + return 1; +} + +static int dh_validate_public(const DH *dh, int checktype) +{ + const BIGNUM *pub_key = NULL; + int res = 0; + + DH_get0_key(dh, &pub_key, NULL); + if (pub_key == NULL) + return 0; + + /* The partial test is only valid for named group's with q = (p - 1) / 2 */ + if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK + && ossl_dh_is_named_safe_prime_group(dh)) + return ossl_dh_check_pub_key_partial(dh, pub_key, &res); + + return DH_check_pub_key(dh, pub_key, &res); +} + +static int dh_validate_private(const DH *dh) +{ + int status = 0; + const BIGNUM *priv_key = NULL; + + DH_get0_key(dh, NULL, &priv_key); + if (priv_key == NULL) + return 0; + return ossl_dh_check_priv_key(dh, priv_key, &status);; +} + +static int dh_validate(const void *keydata, int selection, int checktype) +{ + const DH *dh = keydata; + int ok = 1; + + if (!ossl_prov_is_running()) + return 0; + + if ((selection & DH_POSSIBLE_SELECTIONS) == 0) + return 1; /* nothing to validate */ + + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + /* + * Both of these functions check parameters. DH_check_params_ex() + * performs a lightweight check (e.g. it does not check that p is a + * safe prime) + */ + if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK) + ok = ok && DH_check_params_ex(dh); + else + ok = ok && DH_check_ex(dh); + } + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && dh_validate_public(dh, checktype); + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && dh_validate_private(dh); + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) + == OSSL_KEYMGMT_SELECT_KEYPAIR) + ok = ok && ossl_dh_check_pairwise(dh); + return ok; +} + +static void *dh_gen_init_base(void *provctx, int selection, + const OSSL_PARAM params[], int type) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx); + struct dh_gen_ctx *gctx = NULL; + + if (!ossl_prov_is_running()) + return NULL; + + if ((selection & (OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)) == 0) + return NULL; + + if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { + gctx->selection = selection; + gctx->libctx = libctx; + gctx->pbits = 2048; + gctx->qbits = 224; + gctx->mdname = NULL; +#ifdef FIPS_MODULE + gctx->gen_type = (type == DH_FLAG_TYPE_DHX) + ? DH_PARAMGEN_TYPE_FIPS_186_4 + : DH_PARAMGEN_TYPE_GROUP; +#else + gctx->gen_type = (type == DH_FLAG_TYPE_DHX) + ? DH_PARAMGEN_TYPE_FIPS_186_2 + : DH_PARAMGEN_TYPE_GENERATOR; +#endif + gctx->gindex = -1; + gctx->hindex = 0; + gctx->pcounter = -1; + gctx->generator = DH_GENERATOR_2; + gctx->dh_type = type; + } + if (!dh_gen_set_params(gctx, params)) { + OPENSSL_free(gctx); + gctx = NULL; + } + return gctx; +} + +static void *dh_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + return dh_gen_init_base(provctx, selection, params, DH_FLAG_TYPE_DH); +} + +static void *dhx_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + return dh_gen_init_base(provctx, selection, params, DH_FLAG_TYPE_DHX); +} + +static int dh_gen_set_template(void *genctx, void *templ) +{ + struct dh_gen_ctx *gctx = genctx; + DH *dh = templ; + + if (!ossl_prov_is_running() || gctx == NULL || dh == NULL) + return 0; + gctx->ffc_params = ossl_dh_get0_params(dh); + return 1; +} + +static int dh_set_gen_seed(struct dh_gen_ctx *gctx, unsigned char *seed, + size_t seedlen) +{ + OPENSSL_clear_free(gctx->seed, gctx->seedlen); + gctx->seed = NULL; + gctx->seedlen = 0; + if (seed != NULL && seedlen > 0) { + gctx->seed = OPENSSL_memdup(seed, seedlen); + if (gctx->seed == NULL) + return 0; + gctx->seedlen = seedlen; + } + return 1; +} + +static int dh_gen_common_set_params(void *genctx, const OSSL_PARAM params[]) +{ + struct dh_gen_ctx *gctx = genctx; + const OSSL_PARAM *p; + + if (gctx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_TYPE); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING + || ((gctx->gen_type = + dh_gen_type_name2id_w_default(p->data, gctx->dh_type)) == -1)) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME); + if (p != NULL) { + const DH_NAMED_GROUP *group = NULL; + + if (p->data_type != OSSL_PARAM_UTF8_STRING + || p->data == NULL + || (group = ossl_ffc_name_to_dh_named_group(p->data)) == NULL + || ((gctx->group_nid = + ossl_ffc_named_group_get_uid(group)) == NID_undef)) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + } + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PBITS)) != NULL + && !OSSL_PARAM_get_size_t(p, &gctx->pbits)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_LEN); + if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->priv_len)) + return 0; + return 1; +} + +static const OSSL_PARAM *dh_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM dh_gen_settable[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), + OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_PRIV_LEN, NULL), + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_PBITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_GENERATOR, NULL), + OSSL_PARAM_END + }; + return dh_gen_settable; +} + +static const OSSL_PARAM *dhx_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM dhx_gen_settable[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), + OSSL_PARAM_int(OSSL_PKEY_PARAM_DH_PRIV_LEN, NULL), + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_PBITS, NULL), + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_QBITS, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST_PROPS, NULL, 0), + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_GINDEX, NULL), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_FFC_SEED, NULL, 0), + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_PCOUNTER, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_H, NULL), + OSSL_PARAM_END + }; + return dhx_gen_settable; +} + +static int dhx_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + struct dh_gen_ctx *gctx = genctx; + const OSSL_PARAM *p; + + if (!dh_gen_common_set_params(genctx, params)) + return 0; + + /* Parameters related to fips186-4 and fips186-2 */ + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_GINDEX); + if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->gindex)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PCOUNTER); + if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->pcounter)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_H); + if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->hindex)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_SEED); + if (p != NULL + && (p->data_type != OSSL_PARAM_OCTET_STRING + || !dh_set_gen_seed(gctx, p->data, p->data_size))) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_QBITS)) != NULL + && !OSSL_PARAM_get_size_t(p, &gctx->qbits)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + OPENSSL_free(gctx->mdname); + gctx->mdname = OPENSSL_strdup(p->data); + if (gctx->mdname == NULL) + return 0; + } + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST_PROPS); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + OPENSSL_free(gctx->mdprops); + gctx->mdprops = OPENSSL_strdup(p->data); + if (gctx->mdprops == NULL) + return 0; + } + + /* Parameters that are not allowed for DHX */ + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_GENERATOR); + if (p != NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED); + return 0; + } + return 1; +} + +static int dh_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + struct dh_gen_ctx *gctx = genctx; + const OSSL_PARAM *p; + + if (!dh_gen_common_set_params(genctx, params)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_GENERATOR); + if (p != NULL && !OSSL_PARAM_get_int(p, &gctx->generator)) + return 0; + + /* Parameters that are not allowed for DH */ + if (OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_GINDEX) != NULL + || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PCOUNTER) != NULL + || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_H) != NULL + || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_SEED) != NULL + || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_QBITS) != NULL + || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST) != NULL + || OSSL_PARAM_locate_const(params, + OSSL_PKEY_PARAM_FFC_DIGEST_PROPS) != NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + return 1; +} + +static int dh_gencb(int p, int n, BN_GENCB *cb) +{ + struct dh_gen_ctx *gctx = BN_GENCB_get_arg(cb); + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; + + params[0] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_POTENTIAL, &p); + params[1] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_ITERATION, &n); + + return gctx->cb(params, gctx->cbarg); +} + +static void *dh_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + int ret = 0; + struct dh_gen_ctx *gctx = genctx; + DH *dh = NULL; + BN_GENCB *gencb = NULL; + FFC_PARAMS *ffc; + + if (!ossl_prov_is_running() || gctx == NULL) + return NULL; + + /* + * If a group name is selected then the type is group regardless of what the + * the user selected. This overrides rather than errors for backwards + * compatibility. + */ + if (gctx->group_nid != NID_undef) + gctx->gen_type = DH_PARAMGEN_TYPE_GROUP; + + /* For parameter generation - If there is a group name just create it */ + if (gctx->gen_type == DH_PARAMGEN_TYPE_GROUP + && gctx->ffc_params == NULL) { + /* Select a named group if there is not one already */ + if (gctx->group_nid == NID_undef) + gctx->group_nid = ossl_dh_get_named_group_uid_from_size(gctx->pbits); + if (gctx->group_nid == NID_undef) + return NULL; + dh = ossl_dh_new_by_nid_ex(gctx->libctx, gctx->group_nid); + if (dh == NULL) + return NULL; + ffc = ossl_dh_get0_params(dh); + } else { + dh = ossl_dh_new_ex(gctx->libctx); + if (dh == NULL) + return NULL; + ffc = ossl_dh_get0_params(dh); + + /* Copy the template value if one was passed */ + if (gctx->ffc_params != NULL + && !ossl_ffc_params_copy(ffc, gctx->ffc_params)) + goto end; + + if (!ossl_ffc_params_set_seed(ffc, gctx->seed, gctx->seedlen)) + goto end; + if (gctx->gindex != -1) { + ossl_ffc_params_set_gindex(ffc, gctx->gindex); + if (gctx->pcounter != -1) + ossl_ffc_params_set_pcounter(ffc, gctx->pcounter); + } else if (gctx->hindex != 0) { + ossl_ffc_params_set_h(ffc, gctx->hindex); + } + if (gctx->mdname != NULL) { + if (!ossl_ffc_set_digest(ffc, gctx->mdname, gctx->mdprops)) + goto end; + } + gctx->cb = osslcb; + gctx->cbarg = cbarg; + gencb = BN_GENCB_new(); + if (gencb != NULL) + BN_GENCB_set(gencb, dh_gencb, genctx); + + if ((gctx->selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + /* + * NOTE: The old safe prime generator code is not used in fips mode, + * (i.e internally it ignores the generator and chooses a named + * group based on pbits. + */ + if (gctx->gen_type == DH_PARAMGEN_TYPE_GENERATOR) + ret = DH_generate_parameters_ex(dh, gctx->pbits, + gctx->generator, gencb); + else + ret = ossl_dh_generate_ffc_parameters(dh, gctx->gen_type, + gctx->pbits, gctx->qbits, + gencb); + if (ret <= 0) + goto end; + } + } + + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + if (ffc->p == NULL || ffc->g == NULL) + goto end; + if (gctx->priv_len > 0) + DH_set_length(dh, (long)gctx->priv_len); + ossl_ffc_params_enable_flags(ffc, FFC_PARAM_FLAG_VALIDATE_LEGACY, + gctx->gen_type == DH_PARAMGEN_TYPE_FIPS_186_2); + if (DH_generate_key(dh) <= 0) + goto end; + } + DH_clear_flags(dh, DH_FLAG_TYPE_MASK); + DH_set_flags(dh, gctx->dh_type); + + ret = 1; +end: + if (ret <= 0) { + DH_free(dh); + dh = NULL; + } + BN_GENCB_free(gencb); + return dh; +} + +static void dh_gen_cleanup(void *genctx) +{ + struct dh_gen_ctx *gctx = genctx; + + if (gctx == NULL) + return; + + OPENSSL_free(gctx->mdname); + OPENSSL_free(gctx->mdprops); + OPENSSL_clear_free(gctx->seed, gctx->seedlen); + OPENSSL_free(gctx); +} + +static void *dh_load(const void *reference, size_t reference_sz) +{ + DH *dh = NULL; + + if (ossl_prov_is_running() && reference_sz == sizeof(dh)) { + /* The contents of the reference is the address to our object */ + dh = *(DH **)reference; + /* We grabbed, so we detach it */ + *(DH **)reference = NULL; + return dh; + } + return NULL; +} + +static void *dh_dup(const void *keydata_from, int selection) +{ + if (ossl_prov_is_running()) + return ossl_dh_dup(keydata_from, selection); + return NULL; +} + +const OSSL_DISPATCH ossl_dh_keymgmt_functions[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dh_newdata }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dh_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, (void (*)(void))dh_gen_set_template }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))dh_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))dh_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))dh_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))dh_gen_cleanup }, + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))dh_load }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dh_freedata }, + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params }, + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params }, + { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))dh_set_params }, + { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))dh_settable_params }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dh_has }, + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dh_match }, + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))dh_validate }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dh_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dh_import_types }, + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dh_export }, + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))dh_export_types }, + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))dh_dup }, + { 0, NULL } +}; + +/* For any DH key, we use the "DH" algorithms regardless of sub-type. */ +static const char *dhx_query_operation_name(int operation_id) +{ + return "DH"; +} + +const OSSL_DISPATCH ossl_dhx_keymgmt_functions[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dhx_newdata }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dhx_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, (void (*)(void))dh_gen_set_template }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))dhx_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))dhx_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))dh_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))dh_gen_cleanup }, + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))dh_load }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dh_freedata }, + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params }, + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params }, + { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))dh_set_params }, + { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))dh_settable_params }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dh_has }, + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dh_match }, + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))dh_validate }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dh_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dh_import_types }, + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dh_export }, + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))dh_export_types }, + { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, + (void (*)(void))dhx_query_operation_name }, + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))dh_dup }, + { 0, NULL } +}; diff --git a/providers/implementations/keymgmt/dsa_kmgmt.c b/providers/implementations/keymgmt/dsa_kmgmt.c new file mode 100644 index 000000000000..cd8b4410b0db --- /dev/null +++ b/providers/implementations/keymgmt/dsa_kmgmt.c @@ -0,0 +1,677 @@ +/* + * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "crypto/dsa.h" +#include "internal/sizes.h" +#include "internal/nelem.h" +#include "internal/param_build_set.h" + +static OSSL_FUNC_keymgmt_new_fn dsa_newdata; +static OSSL_FUNC_keymgmt_free_fn dsa_freedata; +static OSSL_FUNC_keymgmt_gen_init_fn dsa_gen_init; +static OSSL_FUNC_keymgmt_gen_set_template_fn dsa_gen_set_template; +static OSSL_FUNC_keymgmt_gen_set_params_fn dsa_gen_set_params; +static OSSL_FUNC_keymgmt_gen_settable_params_fn dsa_gen_settable_params; +static OSSL_FUNC_keymgmt_gen_fn dsa_gen; +static OSSL_FUNC_keymgmt_gen_cleanup_fn dsa_gen_cleanup; +static OSSL_FUNC_keymgmt_load_fn dsa_load; +static OSSL_FUNC_keymgmt_get_params_fn dsa_get_params; +static OSSL_FUNC_keymgmt_gettable_params_fn dsa_gettable_params; +static OSSL_FUNC_keymgmt_has_fn dsa_has; +static OSSL_FUNC_keymgmt_match_fn dsa_match; +static OSSL_FUNC_keymgmt_validate_fn dsa_validate; +static OSSL_FUNC_keymgmt_import_fn dsa_import; +static OSSL_FUNC_keymgmt_import_types_fn dsa_import_types; +static OSSL_FUNC_keymgmt_export_fn dsa_export; +static OSSL_FUNC_keymgmt_export_types_fn dsa_export_types; +static OSSL_FUNC_keymgmt_dup_fn dsa_dup; + +#define DSA_DEFAULT_MD "SHA256" +#define DSA_POSSIBLE_SELECTIONS \ + (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) + +struct dsa_gen_ctx { + OSSL_LIB_CTX *libctx; + + FFC_PARAMS *ffc_params; + int selection; + /* All these parameters are used for parameter generation only */ + size_t pbits; + size_t qbits; + unsigned char *seed; /* optional FIPS186-4 param for testing */ + size_t seedlen; + int gindex; /* optional FIPS186-4 generator index (ignored if -1) */ + int gen_type; /* DSA_PARAMGEN_TYPE_FIPS_186_2 or DSA_PARAMGEN_TYPE_FIPS_186_4 */ + int pcounter; + int hindex; + char *mdname; + char *mdprops; + OSSL_CALLBACK *cb; + void *cbarg; +}; +typedef struct dh_name2id_st{ + const char *name; + int id; +} DSA_GENTYPE_NAME2ID; + +static const DSA_GENTYPE_NAME2ID dsatype2id[]= +{ +#ifdef FIPS_MODULE + { "default", DSA_PARAMGEN_TYPE_FIPS_186_4 }, +#else + { "default", DSA_PARAMGEN_TYPE_FIPS_DEFAULT }, +#endif + { "fips186_4", DSA_PARAMGEN_TYPE_FIPS_186_4 }, + { "fips186_2", DSA_PARAMGEN_TYPE_FIPS_186_2 }, +}; + +static int dsa_gen_type_name2id(const char *name) +{ + size_t i; + + for (i = 0; i < OSSL_NELEM(dsatype2id); ++i) { + if (OPENSSL_strcasecmp(dsatype2id[i].name, name) == 0) + return dsatype2id[i].id; + } + return -1; +} + +static int dsa_key_todata(DSA *dsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[], + int include_private) +{ + const BIGNUM *priv = NULL, *pub = NULL; + + if (dsa == NULL) + return 0; + + DSA_get0_key(dsa, &pub, &priv); + if (include_private + && priv != NULL + && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_PRIV_KEY, priv)) + return 0; + if (pub != NULL + && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_PUB_KEY, pub)) + return 0; + + return 1; +} + +static void *dsa_newdata(void *provctx) +{ + if (!ossl_prov_is_running()) + return NULL; + return ossl_dsa_new(PROV_LIBCTX_OF(provctx)); +} + +static void dsa_freedata(void *keydata) +{ + DSA_free(keydata); +} + +static int dsa_has(const void *keydata, int selection) +{ + const DSA *dsa = keydata; + int ok = 1; + + if (!ossl_prov_is_running() || dsa == NULL) + return 0; + if ((selection & DSA_POSSIBLE_SELECTIONS) == 0) + return 1; /* the selection is not missing */ + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && (DSA_get0_pub_key(dsa) != NULL); + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && (DSA_get0_priv_key(dsa) != NULL); + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + ok = ok && (DSA_get0_p(dsa) != NULL && DSA_get0_g(dsa) != NULL); + return ok; +} + +static int dsa_match(const void *keydata1, const void *keydata2, int selection) +{ + const DSA *dsa1 = keydata1; + const DSA *dsa2 = keydata2; + int ok = 1; + + if (!ossl_prov_is_running()) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int key_checked = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + const BIGNUM *pa = DSA_get0_pub_key(dsa1); + const BIGNUM *pb = DSA_get0_pub_key(dsa2); + + if (pa != NULL && pb != NULL) { + ok = ok && BN_cmp(pa, pb) == 0; + key_checked = 1; + } + } + if (!key_checked + && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + const BIGNUM *pa = DSA_get0_priv_key(dsa1); + const BIGNUM *pb = DSA_get0_priv_key(dsa2); + + if (pa != NULL && pb != NULL) { + ok = ok && BN_cmp(pa, pb) == 0; + key_checked = 1; + } + } + ok = ok && key_checked; + } + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + FFC_PARAMS *dsaparams1 = ossl_dsa_get0_params((DSA *)dsa1); + FFC_PARAMS *dsaparams2 = ossl_dsa_get0_params((DSA *)dsa2); + + ok = ok && ossl_ffc_params_cmp(dsaparams1, dsaparams2, 1); + } + return ok; +} + +static int dsa_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + DSA *dsa = keydata; + int ok = 1; + + if (!ossl_prov_is_running() || dsa == NULL) + return 0; + + if ((selection & DSA_POSSIBLE_SELECTIONS) == 0) + return 0; + + /* a key without parameters is meaningless */ + ok = ok && ossl_dsa_ffc_params_fromdata(dsa, params); + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int include_private = + selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; + + ok = ok && ossl_dsa_key_fromdata(dsa, params, include_private); + } + + return ok; +} + +static int dsa_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, + void *cbarg) +{ + DSA *dsa = keydata; + OSSL_PARAM_BLD *tmpl; + OSSL_PARAM *params = NULL; + int ok = 1; + + if (!ossl_prov_is_running() || dsa == NULL) + return 0; + + tmpl = OSSL_PARAM_BLD_new(); + if (tmpl == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) + ok = ok && ossl_ffc_params_todata(ossl_dsa_get0_params(dsa), tmpl, NULL); + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int include_private = + selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; + + ok = ok && dsa_key_todata(dsa, tmpl, NULL, include_private); + } + + if (!ok || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) { + ok = 0; + goto err; + } + + ok = param_cb(params, cbarg); + OSSL_PARAM_free(params); +err: + OSSL_PARAM_BLD_free(tmpl); + return ok; +} + +/* IMEXPORT = IMPORT + EXPORT */ + +# define DSA_IMEXPORTABLE_PARAMETERS \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_P, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_Q, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_G, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_COFACTOR, NULL, 0), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_GINDEX, NULL), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_PCOUNTER, NULL), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_H, NULL), \ + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_FFC_SEED, NULL, 0) +# define DSA_IMEXPORTABLE_PUBLIC_KEY \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0) +# define DSA_IMEXPORTABLE_PRIVATE_KEY \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0) +static const OSSL_PARAM dsa_all_types[] = { + DSA_IMEXPORTABLE_PARAMETERS, + DSA_IMEXPORTABLE_PUBLIC_KEY, + DSA_IMEXPORTABLE_PRIVATE_KEY, + OSSL_PARAM_END +}; +static const OSSL_PARAM dsa_parameter_types[] = { + DSA_IMEXPORTABLE_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM dsa_key_types[] = { + DSA_IMEXPORTABLE_PUBLIC_KEY, + DSA_IMEXPORTABLE_PRIVATE_KEY, + OSSL_PARAM_END +}; +static const OSSL_PARAM *dsa_types[] = { + NULL, /* Index 0 = none of them */ + dsa_parameter_types, /* Index 1 = parameter types */ + dsa_key_types, /* Index 2 = key types */ + dsa_all_types /* Index 3 = 1 + 2 */ +}; + +static const OSSL_PARAM *dsa_imexport_types(int selection) +{ + int type_select = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) + type_select += 1; + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) + type_select += 2; + return dsa_types[type_select]; +} + +static const OSSL_PARAM *dsa_import_types(int selection) +{ + return dsa_imexport_types(selection); +} + +static const OSSL_PARAM *dsa_export_types(int selection) +{ + return dsa_imexport_types(selection); +} + +static ossl_inline int dsa_get_params(void *key, OSSL_PARAM params[]) +{ + DSA *dsa = key; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL + && !OSSL_PARAM_set_int(p, DSA_bits(dsa))) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL + && !OSSL_PARAM_set_int(p, DSA_security_bits(dsa))) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL + && !OSSL_PARAM_set_int(p, DSA_size(dsa))) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST)) != NULL + && !OSSL_PARAM_set_utf8_string(p, DSA_DEFAULT_MD)) + return 0; + return ossl_ffc_params_todata(ossl_dsa_get0_params(dsa), NULL, params) + && dsa_key_todata(dsa, NULL, params, 1); +} + +static const OSSL_PARAM dsa_params[] = { + OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, NULL, 0), + DSA_IMEXPORTABLE_PARAMETERS, + DSA_IMEXPORTABLE_PUBLIC_KEY, + DSA_IMEXPORTABLE_PRIVATE_KEY, + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dsa_gettable_params(void *provctx) +{ + return dsa_params; +} + +static int dsa_validate_domparams(const DSA *dsa, int checktype) +{ + int status = 0; + + return ossl_dsa_check_params(dsa, checktype, &status); +} + +static int dsa_validate_public(const DSA *dsa) +{ + int status = 0; + const BIGNUM *pub_key = NULL; + + DSA_get0_key(dsa, &pub_key, NULL); + if (pub_key == NULL) + return 0; + return ossl_dsa_check_pub_key(dsa, pub_key, &status); +} + +static int dsa_validate_private(const DSA *dsa) +{ + int status = 0; + const BIGNUM *priv_key = NULL; + + DSA_get0_key(dsa, NULL, &priv_key); + if (priv_key == NULL) + return 0; + return ossl_dsa_check_priv_key(dsa, priv_key, &status); +} + +static int dsa_validate(const void *keydata, int selection, int checktype) +{ + const DSA *dsa = keydata; + int ok = 1; + + if (!ossl_prov_is_running()) + return 0; + + if ((selection & DSA_POSSIBLE_SELECTIONS) == 0) + return 1; /* nothing to validate */ + + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + ok = ok && dsa_validate_domparams(dsa, checktype); + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && dsa_validate_public(dsa); + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && dsa_validate_private(dsa); + + /* If the whole key is selected, we do a pairwise validation */ + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) + == OSSL_KEYMGMT_SELECT_KEYPAIR) + ok = ok && ossl_dsa_check_pairwise(dsa); + return ok; +} + +static void *dsa_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx); + struct dsa_gen_ctx *gctx = NULL; + + if (!ossl_prov_is_running() || (selection & DSA_POSSIBLE_SELECTIONS) == 0) + return NULL; + + if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { + gctx->selection = selection; + gctx->libctx = libctx; + gctx->pbits = 2048; + gctx->qbits = 224; +#ifdef FIPS_MODULE + gctx->gen_type = DSA_PARAMGEN_TYPE_FIPS_186_4; +#else + gctx->gen_type = DSA_PARAMGEN_TYPE_FIPS_DEFAULT; +#endif + gctx->gindex = -1; + gctx->pcounter = -1; + gctx->hindex = 0; + } + if (!dsa_gen_set_params(gctx, params)) { + OPENSSL_free(gctx); + gctx = NULL; + } + return gctx; +} + +static int dsa_gen_set_template(void *genctx, void *templ) +{ + struct dsa_gen_ctx *gctx = genctx; + DSA *dsa = templ; + + if (!ossl_prov_is_running() || gctx == NULL || dsa == NULL) + return 0; + gctx->ffc_params = ossl_dsa_get0_params(dsa); + return 1; +} + +static int dsa_set_gen_seed(struct dsa_gen_ctx *gctx, unsigned char *seed, + size_t seedlen) +{ + OPENSSL_clear_free(gctx->seed, gctx->seedlen); + gctx->seed = NULL; + gctx->seedlen = 0; + if (seed != NULL && seedlen > 0) { + gctx->seed = OPENSSL_memdup(seed, seedlen); + if (gctx->seed == NULL) + return 0; + gctx->seedlen = seedlen; + } + return 1; +} + +static int dsa_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + struct dsa_gen_ctx *gctx = genctx; + const OSSL_PARAM *p; + + if (gctx == NULL) + return 0; + if (params == NULL) + return 1; + + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_TYPE); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING + || ((gctx->gen_type = dsa_gen_type_name2id(p->data)) == -1)) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_GINDEX); + if (p != NULL + && !OSSL_PARAM_get_int(p, &gctx->gindex)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PCOUNTER); + if (p != NULL + && !OSSL_PARAM_get_int(p, &gctx->pcounter)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_H); + if (p != NULL + && !OSSL_PARAM_get_int(p, &gctx->hindex)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_SEED); + if (p != NULL + && (p->data_type != OSSL_PARAM_OCTET_STRING + || !dsa_set_gen_seed(gctx, p->data, p->data_size))) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PBITS)) != NULL + && !OSSL_PARAM_get_size_t(p, &gctx->pbits)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_QBITS)) != NULL + && !OSSL_PARAM_get_size_t(p, &gctx->qbits)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + OPENSSL_free(gctx->mdname); + gctx->mdname = OPENSSL_strdup(p->data); + if (gctx->mdname == NULL) + return 0; + } + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST_PROPS); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + OPENSSL_free(gctx->mdprops); + gctx->mdprops = OPENSSL_strdup(p->data); + if (gctx->mdprops == NULL) + return 0; + } + return 1; +} + +static const OSSL_PARAM *dsa_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + static OSSL_PARAM settable[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE, NULL, 0), + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_PBITS, NULL), + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_QBITS, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST_PROPS, NULL, 0), + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_GINDEX, NULL), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_FFC_SEED, NULL, 0), + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_PCOUNTER, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_H, NULL), + OSSL_PARAM_END + }; + return settable; +} + +static int dsa_gencb(int p, int n, BN_GENCB *cb) +{ + struct dsa_gen_ctx *gctx = BN_GENCB_get_arg(cb); + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; + + params[0] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_POTENTIAL, &p); + params[1] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_ITERATION, &n); + + return gctx->cb(params, gctx->cbarg); +} + +static void *dsa_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct dsa_gen_ctx *gctx = genctx; + DSA *dsa = NULL; + BN_GENCB *gencb = NULL; + int ret = 0; + FFC_PARAMS *ffc; + + if (!ossl_prov_is_running() || gctx == NULL) + return NULL; + dsa = ossl_dsa_new(gctx->libctx); + if (dsa == NULL) + return NULL; + + if (gctx->gen_type == DSA_PARAMGEN_TYPE_FIPS_DEFAULT) + gctx->gen_type = (gctx->pbits >= 2048 ? DSA_PARAMGEN_TYPE_FIPS_186_4 : + DSA_PARAMGEN_TYPE_FIPS_186_2); + + gctx->cb = osslcb; + gctx->cbarg = cbarg; + gencb = BN_GENCB_new(); + if (gencb != NULL) + BN_GENCB_set(gencb, dsa_gencb, genctx); + + ffc = ossl_dsa_get0_params(dsa); + /* Copy the template value if one was passed */ + if (gctx->ffc_params != NULL + && !ossl_ffc_params_copy(ffc, gctx->ffc_params)) + goto end; + + if (gctx->seed != NULL + && !ossl_ffc_params_set_seed(ffc, gctx->seed, gctx->seedlen)) + goto end; + if (gctx->gindex != -1) { + ossl_ffc_params_set_gindex(ffc, gctx->gindex); + if (gctx->pcounter != -1) + ossl_ffc_params_set_pcounter(ffc, gctx->pcounter); + } else if (gctx->hindex != 0) { + ossl_ffc_params_set_h(ffc, gctx->hindex); + } + if (gctx->mdname != NULL) { + if (!ossl_ffc_set_digest(ffc, gctx->mdname, gctx->mdprops)) + goto end; + } + if ((gctx->selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + + if (ossl_dsa_generate_ffc_parameters(dsa, gctx->gen_type, + gctx->pbits, gctx->qbits, + gencb) <= 0) + goto end; + } + ossl_ffc_params_enable_flags(ffc, FFC_PARAM_FLAG_VALIDATE_LEGACY, + gctx->gen_type == DSA_PARAMGEN_TYPE_FIPS_186_2); + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + if (ffc->p == NULL + || ffc->q == NULL + || ffc->g == NULL) + goto end; + if (DSA_generate_key(dsa) <= 0) + goto end; + } + ret = 1; +end: + if (ret <= 0) { + DSA_free(dsa); + dsa = NULL; + } + BN_GENCB_free(gencb); + return dsa; +} + +static void dsa_gen_cleanup(void *genctx) +{ + struct dsa_gen_ctx *gctx = genctx; + + if (gctx == NULL) + return; + + OPENSSL_free(gctx->mdname); + OPENSSL_free(gctx->mdprops); + OPENSSL_clear_free(gctx->seed, gctx->seedlen); + OPENSSL_free(gctx); +} + +static void *dsa_load(const void *reference, size_t reference_sz) +{ + DSA *dsa = NULL; + + if (ossl_prov_is_running() && reference_sz == sizeof(dsa)) { + /* The contents of the reference is the address to our object */ + dsa = *(DSA **)reference; + /* We grabbed, so we detach it */ + *(DSA **)reference = NULL; + return dsa; + } + return NULL; +} + +static void *dsa_dup(const void *keydata_from, int selection) +{ + if (ossl_prov_is_running()) + return ossl_dsa_dup(keydata_from, selection); + return NULL; +} + +const OSSL_DISPATCH ossl_dsa_keymgmt_functions[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dsa_newdata }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dsa_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, (void (*)(void))dsa_gen_set_template }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))dsa_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))dsa_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))dsa_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))dsa_gen_cleanup }, + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))dsa_load }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dsa_freedata }, + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dsa_get_params }, + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dsa_gettable_params }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dsa_has }, + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dsa_match }, + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))dsa_validate }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dsa_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dsa_import_types }, + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dsa_export }, + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))dsa_export_types }, + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))dsa_dup }, + { 0, NULL } +}; diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c new file mode 100644 index 000000000000..3f1dc9e191be --- /dev/null +++ b/providers/implementations/keymgmt/ec_kmgmt.c @@ -0,0 +1,1467 @@ +/* + * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * ECDH/ECDSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/objects.h> +#include <openssl/proverr.h> +#include "crypto/bn.h" +#include "crypto/ec.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "internal/param_build_set.h" + +#ifndef FIPS_MODULE +# ifndef OPENSSL_NO_SM2 +# include "crypto/sm2.h" +# endif +#endif + +static OSSL_FUNC_keymgmt_new_fn ec_newdata; +static OSSL_FUNC_keymgmt_gen_init_fn ec_gen_init; +static OSSL_FUNC_keymgmt_gen_set_template_fn ec_gen_set_template; +static OSSL_FUNC_keymgmt_gen_set_params_fn ec_gen_set_params; +static OSSL_FUNC_keymgmt_gen_settable_params_fn ec_gen_settable_params; +static OSSL_FUNC_keymgmt_gen_fn ec_gen; +static OSSL_FUNC_keymgmt_gen_cleanup_fn ec_gen_cleanup; +static OSSL_FUNC_keymgmt_load_fn ec_load; +static OSSL_FUNC_keymgmt_free_fn ec_freedata; +static OSSL_FUNC_keymgmt_get_params_fn ec_get_params; +static OSSL_FUNC_keymgmt_gettable_params_fn ec_gettable_params; +static OSSL_FUNC_keymgmt_set_params_fn ec_set_params; +static OSSL_FUNC_keymgmt_settable_params_fn ec_settable_params; +static OSSL_FUNC_keymgmt_has_fn ec_has; +static OSSL_FUNC_keymgmt_match_fn ec_match; +static OSSL_FUNC_keymgmt_validate_fn ec_validate; +static OSSL_FUNC_keymgmt_import_fn ec_import; +static OSSL_FUNC_keymgmt_import_types_fn ec_import_types; +static OSSL_FUNC_keymgmt_export_fn ec_export; +static OSSL_FUNC_keymgmt_export_types_fn ec_export_types; +static OSSL_FUNC_keymgmt_query_operation_name_fn ec_query_operation_name; +static OSSL_FUNC_keymgmt_dup_fn ec_dup; +#ifndef FIPS_MODULE +# ifndef OPENSSL_NO_SM2 +static OSSL_FUNC_keymgmt_new_fn sm2_newdata; +static OSSL_FUNC_keymgmt_gen_init_fn sm2_gen_init; +static OSSL_FUNC_keymgmt_gen_fn sm2_gen; +static OSSL_FUNC_keymgmt_get_params_fn sm2_get_params; +static OSSL_FUNC_keymgmt_gettable_params_fn sm2_gettable_params; +static OSSL_FUNC_keymgmt_settable_params_fn sm2_settable_params; +static OSSL_FUNC_keymgmt_import_fn sm2_import; +static OSSL_FUNC_keymgmt_query_operation_name_fn sm2_query_operation_name; +static OSSL_FUNC_keymgmt_validate_fn sm2_validate; +# endif +#endif + +#define EC_DEFAULT_MD "SHA256" +#define EC_POSSIBLE_SELECTIONS \ + (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) +#define SM2_DEFAULT_MD "SM3" + +static +const char *ec_query_operation_name(int operation_id) +{ + switch (operation_id) { + case OSSL_OP_KEYEXCH: + return "ECDH"; + case OSSL_OP_SIGNATURE: + return "ECDSA"; + } + return NULL; +} + +#ifndef FIPS_MODULE +# ifndef OPENSSL_NO_SM2 +static +const char *sm2_query_operation_name(int operation_id) +{ + switch (operation_id) { + case OSSL_OP_SIGNATURE: + return "SM2"; + } + return NULL; +} +# endif +#endif + +/* + * Callers of key_to_params MUST make sure that domparams_to_params is also + * called! + * + * This function only exports the bare keypair, domain parameters and other + * parameters are exported separately. + */ +static ossl_inline +int key_to_params(const EC_KEY *eckey, OSSL_PARAM_BLD *tmpl, + OSSL_PARAM params[], int include_private, + unsigned char **pub_key) +{ + BIGNUM *x = NULL, *y = NULL; + const BIGNUM *priv_key = NULL; + const EC_POINT *pub_point = NULL; + const EC_GROUP *ecg = NULL; + size_t pub_key_len = 0; + int ret = 0; + BN_CTX *bnctx = NULL; + + if (eckey == NULL + || (ecg = EC_KEY_get0_group(eckey)) == NULL) + return 0; + + priv_key = EC_KEY_get0_private_key(eckey); + pub_point = EC_KEY_get0_public_key(eckey); + + if (pub_point != NULL) { + OSSL_PARAM *p = NULL, *px = NULL, *py = NULL; + /* + * EC_POINT_point2buf() can generate random numbers in some + * implementations so we need to ensure we use the correct libctx. + */ + bnctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(eckey)); + if (bnctx == NULL) + goto err; + + + /* If we are doing a get then check first before decoding the point */ + if (tmpl == NULL) { + p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PUB_KEY); + px = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_EC_PUB_X); + py = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_EC_PUB_Y); + } + + if (p != NULL || tmpl != NULL) { + /* convert pub_point to a octet string according to the SECG standard */ + point_conversion_form_t format = EC_KEY_get_conv_form(eckey); + + if ((pub_key_len = EC_POINT_point2buf(ecg, pub_point, + format, + pub_key, bnctx)) == 0 + || !ossl_param_build_set_octet_string(tmpl, p, + OSSL_PKEY_PARAM_PUB_KEY, + *pub_key, pub_key_len)) + goto err; + } + if (px != NULL || py != NULL) { + if (px != NULL) { + x = BN_CTX_get(bnctx); + if (x == NULL) + goto err; + } + if (py != NULL) { + y = BN_CTX_get(bnctx); + if (y == NULL) + goto err; + } + + if (!EC_POINT_get_affine_coordinates(ecg, pub_point, x, y, bnctx)) + goto err; + if (px != NULL + && !ossl_param_build_set_bn(tmpl, px, + OSSL_PKEY_PARAM_EC_PUB_X, x)) + goto err; + if (py != NULL + && !ossl_param_build_set_bn(tmpl, py, + OSSL_PKEY_PARAM_EC_PUB_Y, y)) + goto err; + } + } + + if (priv_key != NULL && include_private) { + size_t sz; + int ecbits; + + /* + * Key import/export should never leak the bit length of the secret + * scalar in the key. + * + * For this reason, on export we use padded BIGNUMs with fixed length. + * + * When importing we also should make sure that, even if short lived, + * the newly created BIGNUM is marked with the BN_FLG_CONSTTIME flag as + * soon as possible, so that any processing of this BIGNUM might opt for + * constant time implementations in the backend. + * + * Setting the BN_FLG_CONSTTIME flag alone is never enough, we also have + * to preallocate the BIGNUM internal buffer to a fixed public size big + * enough that operations performed during the processing never trigger + * a realloc which would leak the size of the scalar through memory + * accesses. + * + * Fixed Length + * ------------ + * + * The order of the large prime subgroup of the curve is our choice for + * a fixed public size, as that is generally the upper bound for + * generating a private key in EC cryptosystems and should fit all valid + * secret scalars. + * + * For padding on export we just use the bit length of the order + * converted to bytes (rounding up). + * + * For preallocating the BIGNUM storage we look at the number of "words" + * required for the internal representation of the order, and we + * preallocate 2 extra "words" in case any of the subsequent processing + * might temporarily overflow the order length. + */ + ecbits = EC_GROUP_order_bits(ecg); + if (ecbits <= 0) + goto err; + sz = (ecbits + 7 ) / 8; + + if (!ossl_param_build_set_bn_pad(tmpl, params, + OSSL_PKEY_PARAM_PRIV_KEY, + priv_key, sz)) + goto err; + } + ret = 1; + err: + BN_CTX_free(bnctx); + return ret; +} + +static ossl_inline +int otherparams_to_params(const EC_KEY *ec, OSSL_PARAM_BLD *tmpl, + OSSL_PARAM params[]) +{ + int ecdh_cofactor_mode = 0, group_check = 0; + const char *name = NULL; + point_conversion_form_t format; + + if (ec == NULL) + return 0; + + format = EC_KEY_get_conv_form(ec); + name = ossl_ec_pt_format_id2name((int)format); + if (name != NULL + && !ossl_param_build_set_utf8_string(tmpl, params, + OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + name)) + return 0; + + group_check = EC_KEY_get_flags(ec) & EC_FLAG_CHECK_NAMED_GROUP_MASK; + name = ossl_ec_check_group_type_id2name(group_check); + if (name != NULL + && !ossl_param_build_set_utf8_string(tmpl, params, + OSSL_PKEY_PARAM_EC_GROUP_CHECK_TYPE, + name)) + return 0; + + if ((EC_KEY_get_enc_flags(ec) & EC_PKEY_NO_PUBKEY) != 0 + && !ossl_param_build_set_int(tmpl, params, + OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 0)) + return 0; + + ecdh_cofactor_mode = + (EC_KEY_get_flags(ec) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0; + return ossl_param_build_set_int(tmpl, params, + OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, + ecdh_cofactor_mode); +} + +static +void *ec_newdata(void *provctx) +{ + if (!ossl_prov_is_running()) + return NULL; + return EC_KEY_new_ex(PROV_LIBCTX_OF(provctx), NULL); +} + +#ifndef FIPS_MODULE +# ifndef OPENSSL_NO_SM2 +static +void *sm2_newdata(void *provctx) +{ + if (!ossl_prov_is_running()) + return NULL; + return EC_KEY_new_by_curve_name_ex(PROV_LIBCTX_OF(provctx), NULL, NID_sm2); +} +# endif +#endif + +static +void ec_freedata(void *keydata) +{ + EC_KEY_free(keydata); +} + +static +int ec_has(const void *keydata, int selection) +{ + const EC_KEY *ec = keydata; + int ok = 1; + + if (!ossl_prov_is_running() || ec == NULL) + return 0; + if ((selection & EC_POSSIBLE_SELECTIONS) == 0) + return 1; /* the selection is not missing */ + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && (EC_KEY_get0_public_key(ec) != NULL); + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && (EC_KEY_get0_private_key(ec) != NULL); + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + ok = ok && (EC_KEY_get0_group(ec) != NULL); + /* + * We consider OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS to always be + * available, so no extra check is needed other than the previous one + * against EC_POSSIBLE_SELECTIONS. + */ + return ok; +} + +static int ec_match(const void *keydata1, const void *keydata2, int selection) +{ + const EC_KEY *ec1 = keydata1; + const EC_KEY *ec2 = keydata2; + const EC_GROUP *group_a = EC_KEY_get0_group(ec1); + const EC_GROUP *group_b = EC_KEY_get0_group(ec2); + BN_CTX *ctx = NULL; + int ok = 1; + + if (!ossl_prov_is_running()) + return 0; + + ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(ec1)); + if (ctx == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + ok = ok && group_a != NULL && group_b != NULL + && EC_GROUP_cmp(group_a, group_b, ctx) == 0; + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int key_checked = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + const EC_POINT *pa = EC_KEY_get0_public_key(ec1); + const EC_POINT *pb = EC_KEY_get0_public_key(ec2); + + if (pa != NULL && pb != NULL) { + ok = ok && EC_POINT_cmp(group_b, pa, pb, ctx) == 0; + key_checked = 1; + } + } + if (!key_checked + && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + const BIGNUM *pa = EC_KEY_get0_private_key(ec1); + const BIGNUM *pb = EC_KEY_get0_private_key(ec2); + + if (pa != NULL && pb != NULL) { + ok = ok && BN_cmp(pa, pb) == 0; + key_checked = 1; + } + } + ok = ok && key_checked; + } + BN_CTX_free(ctx); + return ok; +} + +static int common_check_sm2(const EC_KEY *ec, int sm2_wanted) +{ + const EC_GROUP *ecg = NULL; + + /* + * sm2_wanted: import the keys or domparams only on SM2 Curve + * !sm2_wanted: import the keys or domparams only not on SM2 Curve + */ + if ((ecg = EC_KEY_get0_group(ec)) == NULL + || (sm2_wanted ^ (EC_GROUP_get_curve_name(ecg) == NID_sm2))) + return 0; + return 1; +} + +static +int common_import(void *keydata, int selection, const OSSL_PARAM params[], + int sm2_wanted) +{ + EC_KEY *ec = keydata; + int ok = 1; + + if (!ossl_prov_is_running() || ec == NULL) + return 0; + + /* + * In this implementation, we can export/import only keydata in the + * following combinations: + * - domain parameters (+optional other params) + * - public key with associated domain parameters (+optional other params) + * - private key with associated domain parameters and optional public key + * (+optional other params) + * + * This means: + * - domain parameters must always be requested + * - private key must be requested alongside public key + * - other parameters are always optional + */ + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) == 0) + return 0; + + ok = ok && ossl_ec_group_fromdata(ec, params); + + if (!common_check_sm2(ec, sm2_wanted)) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int include_private = + selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; + + ok = ok && ossl_ec_key_fromdata(ec, params, include_private); + } + if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0) + ok = ok && ossl_ec_key_otherparams_fromdata(ec, params); + + return ok; +} + +static +int ec_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + return common_import(keydata, selection, params, 0); +} + +#ifndef FIPS_MODULE +# ifndef OPENSSL_NO_SM2 +static +int sm2_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + return common_import(keydata, selection, params, 1); +} +# endif +#endif + +static +int ec_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, + void *cbarg) +{ + EC_KEY *ec = keydata; + OSSL_PARAM_BLD *tmpl = NULL; + OSSL_PARAM *params = NULL; + unsigned char *pub_key = NULL, *genbuf = NULL; + BN_CTX *bnctx = NULL; + int ok = 1; + + if (!ossl_prov_is_running() || ec == NULL) + return 0; + + /* + * In this implementation, we can export/import only keydata in the + * following combinations: + * - domain parameters (+optional other params) + * - public key with associated domain parameters (+optional other params) + * - private key with associated public key and domain parameters + * (+optional other params) + * + * This means: + * - domain parameters must always be requested + * - private key must be requested alongside public key + * - other parameters are always optional + */ + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) == 0) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0 + && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0) + return 0; + + tmpl = OSSL_PARAM_BLD_new(); + if (tmpl == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + bnctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(ec)); + if (bnctx == NULL) { + ok = 0; + goto end; + } + BN_CTX_start(bnctx); + ok = ok && ossl_ec_group_todata(EC_KEY_get0_group(ec), tmpl, NULL, + ossl_ec_key_get_libctx(ec), + ossl_ec_key_get0_propq(ec), + bnctx, &genbuf); + } + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int include_private = + selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; + + ok = ok && key_to_params(ec, tmpl, NULL, include_private, &pub_key); + } + if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0) + ok = ok && otherparams_to_params(ec, tmpl, NULL); + + if (!ok || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) { + ok = 0; + goto end; + } + + ok = param_cb(params, cbarg); + OSSL_PARAM_free(params); +end: + OSSL_PARAM_BLD_free(tmpl); + OPENSSL_free(pub_key); + OPENSSL_free(genbuf); + BN_CTX_end(bnctx); + BN_CTX_free(bnctx); + return ok; +} + +/* IMEXPORT = IMPORT + EXPORT */ + +# define EC_IMEXPORTABLE_DOM_PARAMETERS \ + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), \ + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, NULL, 0), \ + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, NULL, 0),\ + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_FIELD_TYPE, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_P, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_A, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_B, NULL, 0), \ + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_GENERATOR, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_ORDER, NULL, 0), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_COFACTOR, NULL, 0), \ + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_SEED, NULL, 0), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS, NULL) + +# define EC_IMEXPORTABLE_PUBLIC_KEY \ + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0) +# define EC_IMEXPORTABLE_PRIVATE_KEY \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0) +# define EC_IMEXPORTABLE_OTHER_PARAMETERS \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, NULL), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, NULL) + +/* + * Include all the possible combinations of OSSL_PARAM arrays for + * ec_imexport_types(). + * + * They are in a separate file as it is ~100 lines of unreadable and + * uninteresting machine generated stuff. + */ +#include "ec_kmgmt_imexport.inc" + +static ossl_inline +const OSSL_PARAM *ec_imexport_types(int selection) +{ + int type_select = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + type_select += 1; + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + type_select += 2; + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + type_select += 4; + if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0) + type_select += 8; + return ec_types[type_select]; +} + +static +const OSSL_PARAM *ec_import_types(int selection) +{ + return ec_imexport_types(selection); +} + +static +const OSSL_PARAM *ec_export_types(int selection) +{ + return ec_imexport_types(selection); +} + +static int ec_get_ecm_params(const EC_GROUP *group, OSSL_PARAM params[]) +{ +#ifdef OPENSSL_NO_EC2M + return 1; +#else + int ret = 0, m; + unsigned int k1 = 0, k2 = 0, k3 = 0; + int basis_nid; + const char *basis_name = NULL; + int fid = EC_GROUP_get_field_type(group); + + if (fid != NID_X9_62_characteristic_two_field) + return 1; + + basis_nid = EC_GROUP_get_basis_type(group); + if (basis_nid == NID_X9_62_tpBasis) + basis_name = SN_X9_62_tpBasis; + else if (basis_nid == NID_X9_62_ppBasis) + basis_name = SN_X9_62_ppBasis; + else + goto err; + + m = EC_GROUP_get_degree(group); + if (!ossl_param_build_set_int(NULL, params, OSSL_PKEY_PARAM_EC_CHAR2_M, m) + || !ossl_param_build_set_utf8_string(NULL, params, + OSSL_PKEY_PARAM_EC_CHAR2_TYPE, + basis_name)) + goto err; + + if (basis_nid == NID_X9_62_tpBasis) { + if (!EC_GROUP_get_trinomial_basis(group, &k1) + || !ossl_param_build_set_int(NULL, params, + OSSL_PKEY_PARAM_EC_CHAR2_TP_BASIS, + (int)k1)) + goto err; + } else { + if (!EC_GROUP_get_pentanomial_basis(group, &k1, &k2, &k3) + || !ossl_param_build_set_int(NULL, params, + OSSL_PKEY_PARAM_EC_CHAR2_PP_K1, (int)k1) + || !ossl_param_build_set_int(NULL, params, + OSSL_PKEY_PARAM_EC_CHAR2_PP_K2, (int)k2) + || !ossl_param_build_set_int(NULL, params, + OSSL_PKEY_PARAM_EC_CHAR2_PP_K3, (int)k3)) + goto err; + } + ret = 1; +err: + return ret; +#endif /* OPENSSL_NO_EC2M */ +} + +static +int common_get_params(void *key, OSSL_PARAM params[], int sm2) +{ + int ret = 0; + EC_KEY *eck = key; + const EC_GROUP *ecg = NULL; + OSSL_PARAM *p; + unsigned char *pub_key = NULL, *genbuf = NULL; + OSSL_LIB_CTX *libctx; + const char *propq; + BN_CTX *bnctx = NULL; + + ecg = EC_KEY_get0_group(eck); + if (ecg == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_PARAMETERS_SET); + return 0; + } + + libctx = ossl_ec_key_get_libctx(eck); + propq = ossl_ec_key_get0_propq(eck); + + bnctx = BN_CTX_new_ex(libctx); + if (bnctx == NULL) + return 0; + BN_CTX_start(bnctx); + + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL + && !OSSL_PARAM_set_int(p, ECDSA_size(eck))) + goto err; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL + && !OSSL_PARAM_set_int(p, EC_GROUP_order_bits(ecg))) + goto err; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL) { + int ecbits, sec_bits; + + ecbits = EC_GROUP_order_bits(ecg); + + /* + * The following estimates are based on the values published + * in Table 2 of "NIST Special Publication 800-57 Part 1 Revision 4" + * at http://dx.doi.org/10.6028/NIST.SP.800-57pt1r4 . + * + * Note that the above reference explicitly categorizes algorithms in a + * discrete set of values {80, 112, 128, 192, 256}, and that it is + * relevant only for NIST approved Elliptic Curves, while OpenSSL + * applies the same logic also to other curves. + * + * Classifications produced by other standardazing bodies might differ, + * so the results provided for "bits of security" by this provider are + * to be considered merely indicative, and it is the users' + * responsibility to compare these values against the normative + * references that may be relevant for their intent and purposes. + */ + if (ecbits >= 512) + sec_bits = 256; + else if (ecbits >= 384) + sec_bits = 192; + else if (ecbits >= 256) + sec_bits = 128; + else if (ecbits >= 224) + sec_bits = 112; + else if (ecbits >= 160) + sec_bits = 80; + else + sec_bits = ecbits / 2; + + if (!OSSL_PARAM_set_int(p, sec_bits)) + goto err; + } + + if ((p = OSSL_PARAM_locate(params, + OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS)) + != NULL) { + int explicitparams = EC_KEY_decoded_from_explicit_params(eck); + + if (explicitparams < 0 + || !OSSL_PARAM_set_int(p, explicitparams)) + goto err; + } + + if (!sm2) { + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST)) != NULL + && !OSSL_PARAM_set_utf8_string(p, EC_DEFAULT_MD)) + goto err; + } else { + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST)) != NULL + && !OSSL_PARAM_set_utf8_string(p, SM2_DEFAULT_MD)) + goto err; + } + + /* SM2 doesn't support this PARAM */ + if (!sm2) { + p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_USE_COFACTOR_ECDH); + if (p != NULL) { + int ecdh_cofactor_mode = 0; + + ecdh_cofactor_mode = + (EC_KEY_get_flags(eck) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0; + + if (!OSSL_PARAM_set_int(p, ecdh_cofactor_mode)) + goto err; + } + } + if ((p = OSSL_PARAM_locate(params, + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY)) != NULL) { + const EC_POINT *ecp = EC_KEY_get0_public_key(key); + + if (ecp == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + goto err; + } + p->return_size = EC_POINT_point2oct(ecg, ecp, + POINT_CONVERSION_UNCOMPRESSED, + p->data, p->return_size, bnctx); + if (p->return_size == 0) + goto err; + } + + ret = ec_get_ecm_params(ecg, params) + && ossl_ec_group_todata(ecg, NULL, params, libctx, propq, bnctx, + &genbuf) + && key_to_params(eck, NULL, params, 1, &pub_key) + && otherparams_to_params(eck, NULL, params); +err: + OPENSSL_free(genbuf); + OPENSSL_free(pub_key); + BN_CTX_end(bnctx); + BN_CTX_free(bnctx); + return ret; +} + +static +int ec_get_params(void *key, OSSL_PARAM params[]) +{ + return common_get_params(key, params, 0); +} + +#ifndef OPENSSL_NO_EC2M +# define EC2M_GETTABLE_DOM_PARAMS \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_CHAR2_M, NULL), \ + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_CHAR2_TYPE, NULL, 0), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_CHAR2_TP_BASIS, NULL), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_CHAR2_PP_K1, NULL), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_CHAR2_PP_K2, NULL), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_CHAR2_PP_K3, NULL), +#else +# define EC2M_GETTABLE_DOM_PARAMS +#endif + +static const OSSL_PARAM ec_known_gettable_params[] = { + OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS, NULL), + EC_IMEXPORTABLE_DOM_PARAMETERS, + EC2M_GETTABLE_DOM_PARAMS + EC_IMEXPORTABLE_PUBLIC_KEY, + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_X, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_Y, NULL, 0), + EC_IMEXPORTABLE_PRIVATE_KEY, + EC_IMEXPORTABLE_OTHER_PARAMETERS, + OSSL_PARAM_END +}; + +static +const OSSL_PARAM *ec_gettable_params(void *provctx) +{ + return ec_known_gettable_params; +} + +static const OSSL_PARAM ec_known_settable_params[] = { + OSSL_PARAM_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, NULL), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_SEED, NULL, 0), + OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_GROUP_CHECK_TYPE, NULL, 0), + OSSL_PARAM_END +}; + +static +const OSSL_PARAM *ec_settable_params(void *provctx) +{ + return ec_known_settable_params; +} + +static +int ec_set_params(void *key, const OSSL_PARAM params[]) +{ + EC_KEY *eck = key; + const OSSL_PARAM *p; + + if (key == NULL) + return 0; + if (params == NULL) + return 1; + + + if (!ossl_ec_group_set_params((EC_GROUP *)EC_KEY_get0_group(key), params)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY); + if (p != NULL) { + BN_CTX *ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(key)); + int ret = 1; + + if (ctx == NULL + || p->data_type != OSSL_PARAM_OCTET_STRING + || !EC_KEY_oct2key(key, p->data, p->data_size, ctx)) + ret = 0; + BN_CTX_free(ctx); + if (!ret) + return 0; + } + + return ossl_ec_key_otherparams_fromdata(eck, params); +} + +#ifndef FIPS_MODULE +# ifndef OPENSSL_NO_SM2 +static +int sm2_get_params(void *key, OSSL_PARAM params[]) +{ + return common_get_params(key, params, 1); +} + +static const OSSL_PARAM sm2_known_gettable_params[] = { + OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + OSSL_PARAM_int(OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS, NULL), + EC_IMEXPORTABLE_DOM_PARAMETERS, + EC_IMEXPORTABLE_PUBLIC_KEY, + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_PUB_X, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_PUB_Y, NULL, 0), + EC_IMEXPORTABLE_PRIVATE_KEY, + OSSL_PARAM_END +}; + +static +const OSSL_PARAM *sm2_gettable_params(ossl_unused void *provctx) +{ + return sm2_known_gettable_params; +} + +static const OSSL_PARAM sm2_known_settable_params[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + OSSL_PARAM_END +}; + +static +const OSSL_PARAM *sm2_settable_params(ossl_unused void *provctx) +{ + return sm2_known_settable_params; +} + +static +int sm2_validate(const void *keydata, int selection, int checktype) +{ + const EC_KEY *eck = keydata; + int ok = 1; + BN_CTX *ctx = NULL; + + if (!ossl_prov_is_running()) + return 0; + + if ((selection & EC_POSSIBLE_SELECTIONS) == 0) + return 1; /* nothing to validate */ + + ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(eck)); + if (ctx == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + ok = ok && EC_GROUP_check(EC_KEY_get0_group(eck), ctx); + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK) + ok = ok && ossl_ec_key_public_check_quick(eck, ctx); + else + ok = ok && ossl_ec_key_public_check(eck, ctx); + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && ossl_sm2_key_private_check(eck); + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR) + ok = ok && ossl_ec_key_pairwise_check(eck, ctx); + + BN_CTX_free(ctx); + return ok; +} +# endif +#endif + +static +int ec_validate(const void *keydata, int selection, int checktype) +{ + const EC_KEY *eck = keydata; + int ok = 1; + BN_CTX *ctx = NULL; + + if (!ossl_prov_is_running()) + return 0; + + if ((selection & EC_POSSIBLE_SELECTIONS) == 0) + return 1; /* nothing to validate */ + + ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(eck)); + if (ctx == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + int flags = EC_KEY_get_flags(eck); + + if ((flags & EC_FLAG_CHECK_NAMED_GROUP) != 0) + ok = ok && EC_GROUP_check_named_curve(EC_KEY_get0_group(eck), + (flags & EC_FLAG_CHECK_NAMED_GROUP_NIST) != 0, ctx) > 0; + else + ok = ok && EC_GROUP_check(EC_KEY_get0_group(eck), ctx); + } + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK) + ok = ok && ossl_ec_key_public_check_quick(eck, ctx); + else + ok = ok && ossl_ec_key_public_check(eck, ctx); + } + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && ossl_ec_key_private_check(eck); + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR) + ok = ok && ossl_ec_key_pairwise_check(eck, ctx); + + BN_CTX_free(ctx); + return ok; +} + +struct ec_gen_ctx { + OSSL_LIB_CTX *libctx; + char *group_name; + char *encoding; + char *pt_format; + char *group_check; + char *field_type; + BIGNUM *p, *a, *b, *order, *cofactor; + unsigned char *gen, *seed; + size_t gen_len, seed_len; + int selection; + int ecdh_mode; + EC_GROUP *gen_group; +}; + +static void *ec_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx); + struct ec_gen_ctx *gctx = NULL; + + if (!ossl_prov_is_running() || (selection & (EC_POSSIBLE_SELECTIONS)) == 0) + return NULL; + + if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { + gctx->libctx = libctx; + gctx->selection = selection; + gctx->ecdh_mode = 0; + if (!ec_gen_set_params(gctx, params)) { + OPENSSL_free(gctx); + gctx = NULL; + } + } + return gctx; +} + +#ifndef FIPS_MODULE +# ifndef OPENSSL_NO_SM2 +static void *sm2_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + struct ec_gen_ctx *gctx = ec_gen_init(provctx, selection, params); + + if (gctx != NULL) { + if (gctx->group_name != NULL) + return gctx; + if ((gctx->group_name = OPENSSL_strdup("sm2")) != NULL) + return gctx; + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ec_gen_cleanup(gctx); + } + return NULL; +} +# endif +#endif + +static int ec_gen_set_group(void *genctx, const EC_GROUP *src) +{ + struct ec_gen_ctx *gctx = genctx; + EC_GROUP *group; + + group = EC_GROUP_dup(src); + if (group == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE); + return 0; + } + EC_GROUP_free(gctx->gen_group); + gctx->gen_group = group; + return 1; +} + +static int ec_gen_set_template(void *genctx, void *templ) +{ + struct ec_gen_ctx *gctx = genctx; + EC_KEY *ec = templ; + const EC_GROUP *ec_group; + + if (!ossl_prov_is_running() || gctx == NULL || ec == NULL) + return 0; + if ((ec_group = EC_KEY_get0_group(ec)) == NULL) + return 0; + return ec_gen_set_group(gctx, ec_group); +} + +#define COPY_INT_PARAM(params, key, val) \ +p = OSSL_PARAM_locate_const(params, key); \ +if (p != NULL && !OSSL_PARAM_get_int(p, &val)) \ + goto err; + +#define COPY_UTF8_PARAM(params, key, val) \ +p = OSSL_PARAM_locate_const(params, key); \ +if (p != NULL) { \ + if (p->data_type != OSSL_PARAM_UTF8_STRING) \ + goto err; \ + OPENSSL_free(val); \ + val = OPENSSL_strdup(p->data); \ + if (val == NULL) \ + goto err; \ +} + +#define COPY_OCTET_PARAM(params, key, val, len) \ +p = OSSL_PARAM_locate_const(params, key); \ +if (p != NULL) { \ + if (p->data_type != OSSL_PARAM_OCTET_STRING) \ + goto err; \ + OPENSSL_free(val); \ + len = p->data_size; \ + val = OPENSSL_memdup(p->data, p->data_size); \ + if (val == NULL) \ + goto err; \ +} + +#define COPY_BN_PARAM(params, key, bn) \ +p = OSSL_PARAM_locate_const(params, key); \ +if (p != NULL) { \ + if (bn == NULL) \ + bn = BN_new(); \ + if (bn == NULL || !OSSL_PARAM_get_BN(p, &bn)) \ + goto err; \ +} + +static int ec_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + int ret = 0; + struct ec_gen_ctx *gctx = genctx; + const OSSL_PARAM *p; + EC_GROUP *group = NULL; + + COPY_INT_PARAM(params, OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, gctx->ecdh_mode); + + COPY_UTF8_PARAM(params, OSSL_PKEY_PARAM_GROUP_NAME, gctx->group_name); + COPY_UTF8_PARAM(params, OSSL_PKEY_PARAM_EC_FIELD_TYPE, gctx->field_type); + COPY_UTF8_PARAM(params, OSSL_PKEY_PARAM_EC_ENCODING, gctx->encoding); + COPY_UTF8_PARAM(params, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, gctx->pt_format); + COPY_UTF8_PARAM(params, OSSL_PKEY_PARAM_EC_GROUP_CHECK_TYPE, gctx->group_check); + + COPY_BN_PARAM(params, OSSL_PKEY_PARAM_EC_P, gctx->p); + COPY_BN_PARAM(params, OSSL_PKEY_PARAM_EC_A, gctx->a); + COPY_BN_PARAM(params, OSSL_PKEY_PARAM_EC_B, gctx->b); + COPY_BN_PARAM(params, OSSL_PKEY_PARAM_EC_ORDER, gctx->order); + COPY_BN_PARAM(params, OSSL_PKEY_PARAM_EC_COFACTOR, gctx->cofactor); + + COPY_OCTET_PARAM(params, OSSL_PKEY_PARAM_EC_SEED, gctx->seed, gctx->seed_len); + COPY_OCTET_PARAM(params, OSSL_PKEY_PARAM_EC_GENERATOR, gctx->gen, + gctx->gen_len); + + ret = 1; +err: + EC_GROUP_free(group); + return ret; +} + +static int ec_gen_set_group_from_params(struct ec_gen_ctx *gctx) +{ + int ret = 0; + OSSL_PARAM_BLD *bld; + OSSL_PARAM *params = NULL; + EC_GROUP *group = NULL; + + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) + return 0; + + if (gctx->encoding != NULL + && !OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_EC_ENCODING, + gctx->encoding, 0)) + goto err; + + if (gctx->pt_format != NULL + && !OSSL_PARAM_BLD_push_utf8_string(bld, + OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + gctx->pt_format, 0)) + goto err; + + if (gctx->group_name != NULL) { + if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, + gctx->group_name, 0)) + goto err; + /* Ignore any other parameters if there is a group name */ + goto build; + } else if (gctx->field_type != NULL) { + if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_EC_FIELD_TYPE, + gctx->field_type, 0)) + goto err; + } else { + goto err; + } + if (gctx->p == NULL + || gctx->a == NULL + || gctx->b == NULL + || gctx->order == NULL + || !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_P, gctx->p) + || !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_A, gctx->a) + || !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_B, gctx->b) + || !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_ORDER, gctx->order)) + goto err; + + if (gctx->cofactor != NULL + && !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_COFACTOR, + gctx->cofactor)) + goto err; + + if (gctx->seed != NULL + && !OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_EC_SEED, + gctx->seed, gctx->seed_len)) + goto err; + + if (gctx->gen == NULL + || !OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_EC_GENERATOR, + gctx->gen, gctx->gen_len)) + goto err; +build: + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) + goto err; + group = EC_GROUP_new_from_params(params, gctx->libctx, NULL); + if (group == NULL) + goto err; + + EC_GROUP_free(gctx->gen_group); + gctx->gen_group = group; + + ret = 1; +err: + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + return ret; +} + +static const OSSL_PARAM *ec_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + static OSSL_PARAM settable[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), + OSSL_PARAM_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_FIELD_TYPE, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_P, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_A, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_B, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_GENERATOR, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_ORDER, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_COFACTOR, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_SEED, NULL, 0), + OSSL_PARAM_END + }; + + return settable; +} + +static int ec_gen_assign_group(EC_KEY *ec, EC_GROUP *group) +{ + if (group == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_PARAMETERS_SET); + return 0; + } + return EC_KEY_set_group(ec, group) > 0; +} + +/* + * The callback arguments (osslcb & cbarg) are not used by EC_KEY generation + */ +static void *ec_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct ec_gen_ctx *gctx = genctx; + EC_KEY *ec = NULL; + int ret = 0; + + if (!ossl_prov_is_running() + || gctx == NULL + || (ec = EC_KEY_new_ex(gctx->libctx, NULL)) == NULL) + return NULL; + + if (gctx->gen_group == NULL) { + if (!ec_gen_set_group_from_params(gctx)) + goto err; + } else { + if (gctx->encoding != NULL) { + int flags = ossl_ec_encoding_name2id(gctx->encoding); + + if (flags < 0) + goto err; + EC_GROUP_set_asn1_flag(gctx->gen_group, flags); + } + if (gctx->pt_format != NULL) { + int format = ossl_ec_pt_format_name2id(gctx->pt_format); + + if (format < 0) + goto err; + EC_GROUP_set_point_conversion_form(gctx->gen_group, format); + } + } + + /* We must always assign a group, no matter what */ + ret = ec_gen_assign_group(ec, gctx->gen_group); + + /* Whether you want it or not, you get a keypair, not just one half */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) + ret = ret && EC_KEY_generate_key(ec); + + if (gctx->ecdh_mode != -1) + ret = ret && ossl_ec_set_ecdh_cofactor_mode(ec, gctx->ecdh_mode); + + if (gctx->group_check != NULL) + ret = ret && ossl_ec_set_check_group_type_from_name(ec, gctx->group_check); + if (ret) + return ec; +err: + /* Something went wrong, throw the key away */ + EC_KEY_free(ec); + return NULL; +} + +#ifndef FIPS_MODULE +# ifndef OPENSSL_NO_SM2 +/* + * The callback arguments (osslcb & cbarg) are not used by EC_KEY generation + */ +static void *sm2_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct ec_gen_ctx *gctx = genctx; + EC_KEY *ec = NULL; + int ret = 1; + + if (gctx == NULL + || (ec = EC_KEY_new_ex(gctx->libctx, NULL)) == NULL) + return NULL; + + if (gctx->gen_group == NULL) { + if (!ec_gen_set_group_from_params(gctx)) + goto err; + } else { + if (gctx->encoding) { + int flags = ossl_ec_encoding_name2id(gctx->encoding); + + if (flags < 0) + goto err; + EC_GROUP_set_asn1_flag(gctx->gen_group, flags); + } + if (gctx->pt_format != NULL) { + int format = ossl_ec_pt_format_name2id(gctx->pt_format); + + if (format < 0) + goto err; + EC_GROUP_set_point_conversion_form(gctx->gen_group, format); + } + } + + /* We must always assign a group, no matter what */ + ret = ec_gen_assign_group(ec, gctx->gen_group); + + /* Whether you want it or not, you get a keypair, not just one half */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) + ret = ret && EC_KEY_generate_key(ec); + + if (ret) + return ec; +err: + /* Something went wrong, throw the key away */ + EC_KEY_free(ec); + return NULL; +} +# endif +#endif + +static void ec_gen_cleanup(void *genctx) +{ + struct ec_gen_ctx *gctx = genctx; + + if (gctx == NULL) + return; + + EC_GROUP_free(gctx->gen_group); + BN_free(gctx->p); + BN_free(gctx->a); + BN_free(gctx->b); + BN_free(gctx->order); + BN_free(gctx->cofactor); + OPENSSL_free(gctx->group_name); + OPENSSL_free(gctx->field_type); + OPENSSL_free(gctx->pt_format); + OPENSSL_free(gctx->encoding); + OPENSSL_free(gctx->seed); + OPENSSL_free(gctx->gen); + OPENSSL_free(gctx); +} + +static void *common_load(const void *reference, size_t reference_sz, + int sm2_wanted) +{ + EC_KEY *ec = NULL; + + if (ossl_prov_is_running() && reference_sz == sizeof(ec)) { + /* The contents of the reference is the address to our object */ + ec = *(EC_KEY **)reference; + + if (!common_check_sm2(ec, sm2_wanted)) + return NULL; + + /* We grabbed, so we detach it */ + *(EC_KEY **)reference = NULL; + return ec; + } + return NULL; +} + +static void *ec_load(const void *reference, size_t reference_sz) +{ + return common_load(reference, reference_sz, 0); +} + +#ifndef FIPS_MODULE +# ifndef OPENSSL_NO_SM2 +static void *sm2_load(const void *reference, size_t reference_sz) +{ + return common_load(reference, reference_sz, 1); +} +# endif +#endif + +static void *ec_dup(const void *keydata_from, int selection) +{ + if (ossl_prov_is_running()) + return ossl_ec_key_dup(keydata_from, selection); + return NULL; +} + +const OSSL_DISPATCH ossl_ec_keymgmt_functions[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_newdata }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))ec_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, + (void (*)(void))ec_gen_set_template }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))ec_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))ec_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))ec_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))ec_gen_cleanup }, + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))ec_load }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ec_freedata }, + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))ec_get_params }, + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))ec_gettable_params }, + { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))ec_set_params }, + { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))ec_settable_params }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ec_has }, + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ec_match }, + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))ec_validate }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ec_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ec_import_types }, + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_export }, + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ec_export_types }, + { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, + (void (*)(void))ec_query_operation_name }, + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))ec_dup }, + { 0, NULL } +}; + +#ifndef FIPS_MODULE +# ifndef OPENSSL_NO_SM2 +const OSSL_DISPATCH ossl_sm2_keymgmt_functions[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))sm2_newdata }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))sm2_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, + (void (*)(void))ec_gen_set_template }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))ec_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))ec_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))sm2_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))ec_gen_cleanup }, + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))sm2_load }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ec_freedata }, + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))sm2_get_params }, + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))sm2_gettable_params }, + { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))ec_set_params }, + { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))sm2_settable_params }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ec_has }, + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ec_match }, + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))sm2_validate }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))sm2_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ec_import_types }, + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_export }, + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ec_export_types }, + { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, + (void (*)(void))sm2_query_operation_name }, + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))ec_dup }, + { 0, NULL } +}; +# endif +#endif diff --git a/providers/implementations/keymgmt/ec_kmgmt_imexport.inc b/providers/implementations/keymgmt/ec_kmgmt_imexport.inc new file mode 100644 index 000000000000..b142e0df0c46 --- /dev/null +++ b/providers/implementations/keymgmt/ec_kmgmt_imexport.inc @@ -0,0 +1,109 @@ +/* + * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html +*/ + +/* + * This file is meant to be included from ec_kmgmt.c + */ + +static const OSSL_PARAM ec_private_key_types[] = { + EC_IMEXPORTABLE_PRIVATE_KEY, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_public_key_types[] = { + EC_IMEXPORTABLE_PUBLIC_KEY, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_key_types[] = { + EC_IMEXPORTABLE_PRIVATE_KEY, + EC_IMEXPORTABLE_PUBLIC_KEY, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_dom_parameters_types[] = { + EC_IMEXPORTABLE_DOM_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_5_types[] = { + EC_IMEXPORTABLE_PRIVATE_KEY, + EC_IMEXPORTABLE_DOM_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_6_types[] = { + EC_IMEXPORTABLE_PUBLIC_KEY, + EC_IMEXPORTABLE_DOM_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_key_domp_types[] = { + EC_IMEXPORTABLE_PRIVATE_KEY, + EC_IMEXPORTABLE_PUBLIC_KEY, + EC_IMEXPORTABLE_DOM_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_other_parameters_types[] = { + EC_IMEXPORTABLE_OTHER_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_9_types[] = { + EC_IMEXPORTABLE_PRIVATE_KEY, + EC_IMEXPORTABLE_OTHER_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_10_types[] = { + EC_IMEXPORTABLE_PUBLIC_KEY, + EC_IMEXPORTABLE_OTHER_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_11_types[] = { + EC_IMEXPORTABLE_PRIVATE_KEY, + EC_IMEXPORTABLE_PUBLIC_KEY, + EC_IMEXPORTABLE_OTHER_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_all_parameters_types[] = { + EC_IMEXPORTABLE_DOM_PARAMETERS, + EC_IMEXPORTABLE_OTHER_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_13_types[] = { + EC_IMEXPORTABLE_PRIVATE_KEY, + EC_IMEXPORTABLE_DOM_PARAMETERS, + EC_IMEXPORTABLE_OTHER_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_14_types[] = { + EC_IMEXPORTABLE_PUBLIC_KEY, + EC_IMEXPORTABLE_DOM_PARAMETERS, + EC_IMEXPORTABLE_OTHER_PARAMETERS, + OSSL_PARAM_END +}; +static const OSSL_PARAM ec_all_types[] = { + EC_IMEXPORTABLE_PRIVATE_KEY, + EC_IMEXPORTABLE_PUBLIC_KEY, + EC_IMEXPORTABLE_DOM_PARAMETERS, + EC_IMEXPORTABLE_OTHER_PARAMETERS, + OSSL_PARAM_END +}; + +static const OSSL_PARAM *ec_types[] = { + NULL, + ec_private_key_types, + ec_public_key_types, + ec_key_types, + ec_dom_parameters_types, + ec_5_types, + ec_6_types, + ec_key_domp_types, + ec_other_parameters_types, + ec_9_types, + ec_10_types, + ec_11_types, + ec_all_parameters_types, + ec_13_types, + ec_14_types, + ec_all_types +}; diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c new file mode 100644 index 000000000000..2a7f867aa56b --- /dev/null +++ b/providers/implementations/keymgmt/ecx_kmgmt.c @@ -0,0 +1,1056 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <assert.h> +#include <string.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include <openssl/evp.h> +#include <openssl/rand.h> +#include "internal/param_build_set.h" +#include <openssl/param_build.h> +#include "crypto/ecx.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#ifdef S390X_EC_ASM +# include "s390x_arch.h" +# include <openssl/sha.h> /* For SHA512_DIGEST_LENGTH */ +#endif + +static OSSL_FUNC_keymgmt_new_fn x25519_new_key; +static OSSL_FUNC_keymgmt_new_fn x448_new_key; +static OSSL_FUNC_keymgmt_new_fn ed25519_new_key; +static OSSL_FUNC_keymgmt_new_fn ed448_new_key; +static OSSL_FUNC_keymgmt_gen_init_fn x25519_gen_init; +static OSSL_FUNC_keymgmt_gen_init_fn x448_gen_init; +static OSSL_FUNC_keymgmt_gen_init_fn ed25519_gen_init; +static OSSL_FUNC_keymgmt_gen_init_fn ed448_gen_init; +static OSSL_FUNC_keymgmt_gen_fn x25519_gen; +static OSSL_FUNC_keymgmt_gen_fn x448_gen; +static OSSL_FUNC_keymgmt_gen_fn ed25519_gen; +static OSSL_FUNC_keymgmt_gen_fn ed448_gen; +static OSSL_FUNC_keymgmt_gen_cleanup_fn ecx_gen_cleanup; +static OSSL_FUNC_keymgmt_gen_set_params_fn ecx_gen_set_params; +static OSSL_FUNC_keymgmt_gen_settable_params_fn ecx_gen_settable_params; +static OSSL_FUNC_keymgmt_load_fn ecx_load; +static OSSL_FUNC_keymgmt_get_params_fn x25519_get_params; +static OSSL_FUNC_keymgmt_get_params_fn x448_get_params; +static OSSL_FUNC_keymgmt_get_params_fn ed25519_get_params; +static OSSL_FUNC_keymgmt_get_params_fn ed448_get_params; +static OSSL_FUNC_keymgmt_gettable_params_fn x25519_gettable_params; +static OSSL_FUNC_keymgmt_gettable_params_fn x448_gettable_params; +static OSSL_FUNC_keymgmt_gettable_params_fn ed25519_gettable_params; +static OSSL_FUNC_keymgmt_gettable_params_fn ed448_gettable_params; +static OSSL_FUNC_keymgmt_set_params_fn x25519_set_params; +static OSSL_FUNC_keymgmt_set_params_fn x448_set_params; +static OSSL_FUNC_keymgmt_set_params_fn ed25519_set_params; +static OSSL_FUNC_keymgmt_set_params_fn ed448_set_params; +static OSSL_FUNC_keymgmt_settable_params_fn x25519_settable_params; +static OSSL_FUNC_keymgmt_settable_params_fn x448_settable_params; +static OSSL_FUNC_keymgmt_settable_params_fn ed25519_settable_params; +static OSSL_FUNC_keymgmt_settable_params_fn ed448_settable_params; +static OSSL_FUNC_keymgmt_has_fn ecx_has; +static OSSL_FUNC_keymgmt_match_fn ecx_match; +static OSSL_FUNC_keymgmt_validate_fn x25519_validate; +static OSSL_FUNC_keymgmt_validate_fn x448_validate; +static OSSL_FUNC_keymgmt_validate_fn ed25519_validate; +static OSSL_FUNC_keymgmt_validate_fn ed448_validate; +static OSSL_FUNC_keymgmt_import_fn ecx_import; +static OSSL_FUNC_keymgmt_import_types_fn ecx_imexport_types; +static OSSL_FUNC_keymgmt_export_fn ecx_export; +static OSSL_FUNC_keymgmt_export_types_fn ecx_imexport_types; +static OSSL_FUNC_keymgmt_dup_fn ecx_dup; + +#define ECX_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR) + +struct ecx_gen_ctx { + OSSL_LIB_CTX *libctx; + char *propq; + ECX_KEY_TYPE type; + int selection; +}; + +#ifdef S390X_EC_ASM +static void *s390x_ecx_keygen25519(struct ecx_gen_ctx *gctx); +static void *s390x_ecx_keygen448(struct ecx_gen_ctx *gctx); +static void *s390x_ecd_keygen25519(struct ecx_gen_ctx *gctx); +static void *s390x_ecd_keygen448(struct ecx_gen_ctx *gctx); +#endif + +static void *x25519_new_key(void *provctx) +{ + if (!ossl_prov_is_running()) + return 0; + return ossl_ecx_key_new(PROV_LIBCTX_OF(provctx), ECX_KEY_TYPE_X25519, 0, + NULL); +} + +static void *x448_new_key(void *provctx) +{ + if (!ossl_prov_is_running()) + return 0; + return ossl_ecx_key_new(PROV_LIBCTX_OF(provctx), ECX_KEY_TYPE_X448, 0, + NULL); +} + +static void *ed25519_new_key(void *provctx) +{ + if (!ossl_prov_is_running()) + return 0; + return ossl_ecx_key_new(PROV_LIBCTX_OF(provctx), ECX_KEY_TYPE_ED25519, 0, + NULL); +} + +static void *ed448_new_key(void *provctx) +{ + if (!ossl_prov_is_running()) + return 0; + return ossl_ecx_key_new(PROV_LIBCTX_OF(provctx), ECX_KEY_TYPE_ED448, 0, + NULL); +} + +static int ecx_has(const void *keydata, int selection) +{ + const ECX_KEY *key = keydata; + int ok = 0; + + if (ossl_prov_is_running() && key != NULL) { + /* + * ECX keys always have all the parameters they need (i.e. none). + * Therefore we always return with 1, if asked about parameters. + */ + ok = 1; + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && key->haspubkey; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && key->privkey != NULL; + } + return ok; +} + +static int ecx_match(const void *keydata1, const void *keydata2, int selection) +{ + const ECX_KEY *key1 = keydata1; + const ECX_KEY *key2 = keydata2; + int ok = 1; + + if (!ossl_prov_is_running()) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + ok = ok && key1->type == key2->type; + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int key_checked = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + const unsigned char *pa = key1->haspubkey ? key1->pubkey : NULL; + const unsigned char *pb = key2->haspubkey ? key2->pubkey : NULL; + size_t pal = key1->keylen; + size_t pbl = key2->keylen; + + if (pa != NULL && pb != NULL) { + ok = ok + && key1->type == key2->type + && pal == pbl + && CRYPTO_memcmp(pa, pb, pal) == 0; + key_checked = 1; + } + } + if (!key_checked + && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + const unsigned char *pa = key1->privkey; + const unsigned char *pb = key2->privkey; + size_t pal = key1->keylen; + size_t pbl = key2->keylen; + + if (pa != NULL && pb != NULL) { + ok = ok + && key1->type == key2->type + && pal == pbl + && CRYPTO_memcmp(pa, pb, pal) == 0; + key_checked = 1; + } + } + ok = ok && key_checked; + } + return ok; +} + +static int ecx_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + ECX_KEY *key = keydata; + int ok = 1; + int include_private; + + if (!ossl_prov_is_running() || key == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return 0; + + include_private = selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; + ok = ok && ossl_ecx_key_fromdata(key, params, include_private); + + return ok; +} + +static int key_to_params(ECX_KEY *key, OSSL_PARAM_BLD *tmpl, + OSSL_PARAM params[], int include_private) +{ + if (key == NULL) + return 0; + + if (!ossl_param_build_set_octet_string(tmpl, params, + OSSL_PKEY_PARAM_PUB_KEY, + key->pubkey, key->keylen)) + return 0; + + if (include_private + && key->privkey != NULL + && !ossl_param_build_set_octet_string(tmpl, params, + OSSL_PKEY_PARAM_PRIV_KEY, + key->privkey, key->keylen)) + return 0; + + return 1; +} + +static int ecx_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, + void *cbarg) +{ + ECX_KEY *key = keydata; + OSSL_PARAM_BLD *tmpl; + OSSL_PARAM *params = NULL; + int ret = 0; + + if (!ossl_prov_is_running() || key == NULL) + return 0; + + tmpl = OSSL_PARAM_BLD_new(); + if (tmpl == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int include_private = ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0); + + if (!key_to_params(key, tmpl, NULL, include_private)) + goto err; + } + + params = OSSL_PARAM_BLD_to_param(tmpl); + if (params == NULL) + goto err; + + ret = param_cb(params, cbarg); + OSSL_PARAM_free(params); +err: + OSSL_PARAM_BLD_free(tmpl); + return ret; +} + +#define ECX_KEY_TYPES() \ +OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), \ +OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0) + +static const OSSL_PARAM ecx_key_types[] = { + ECX_KEY_TYPES(), + OSSL_PARAM_END +}; +static const OSSL_PARAM *ecx_imexport_types(int selection) +{ + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) + return ecx_key_types; + return NULL; +} + +static int ecx_get_params(void *key, OSSL_PARAM params[], int bits, int secbits, + int size) +{ + ECX_KEY *ecx = key; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL + && !OSSL_PARAM_set_int(p, bits)) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL + && !OSSL_PARAM_set_int(p, secbits)) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL + && !OSSL_PARAM_set_int(p, size)) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY)) != NULL + && (ecx->type == ECX_KEY_TYPE_X25519 + || ecx->type == ECX_KEY_TYPE_X448)) { + if (!OSSL_PARAM_set_octet_string(p, ecx->pubkey, ecx->keylen)) + return 0; + } + + return key_to_params(ecx, NULL, params, 1); +} + +static int ed_get_params(void *key, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, + OSSL_PKEY_PARAM_MANDATORY_DIGEST)) != NULL + && !OSSL_PARAM_set_utf8_string(p, "")) + return 0; + return 1; +} + +static int x25519_get_params(void *key, OSSL_PARAM params[]) +{ + return ecx_get_params(key, params, X25519_BITS, X25519_SECURITY_BITS, + X25519_KEYLEN); +} + +static int x448_get_params(void *key, OSSL_PARAM params[]) +{ + return ecx_get_params(key, params, X448_BITS, X448_SECURITY_BITS, + X448_KEYLEN); +} + +static int ed25519_get_params(void *key, OSSL_PARAM params[]) +{ + return ecx_get_params(key, params, ED25519_BITS, ED25519_SECURITY_BITS, + ED25519_SIGSIZE) + && ed_get_params(key, params); +} + +static int ed448_get_params(void *key, OSSL_PARAM params[]) +{ + return ecx_get_params(key, params, ED448_BITS, ED448_SECURITY_BITS, + ED448_SIGSIZE) + && ed_get_params(key, params); +} + +static const OSSL_PARAM ecx_gettable_params[] = { + OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + ECX_KEY_TYPES(), + OSSL_PARAM_END +}; + +static const OSSL_PARAM ed_gettable_params[] = { + OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + ECX_KEY_TYPES(), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *x25519_gettable_params(void *provctx) +{ + return ecx_gettable_params; +} + +static const OSSL_PARAM *x448_gettable_params(void *provctx) +{ + return ecx_gettable_params; +} + +static const OSSL_PARAM *ed25519_gettable_params(void *provctx) +{ + return ed_gettable_params; +} + +static const OSSL_PARAM *ed448_gettable_params(void *provctx) +{ + return ed_gettable_params; +} + +static int set_property_query(ECX_KEY *ecxkey, const char *propq) +{ + OPENSSL_free(ecxkey->propq); + ecxkey->propq = NULL; + if (propq != NULL) { + ecxkey->propq = OPENSSL_strdup(propq); + if (ecxkey->propq == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + } + return 1; +} + +static int ecx_set_params(void *key, const OSSL_PARAM params[]) +{ + ECX_KEY *ecxkey = key; + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY); + if (p != NULL) { + void *buf = ecxkey->pubkey; + + if (p->data_size != ecxkey->keylen + || !OSSL_PARAM_get_octet_string(p, &buf, sizeof(ecxkey->pubkey), + NULL)) + return 0; + OPENSSL_clear_free(ecxkey->privkey, ecxkey->keylen); + ecxkey->privkey = NULL; + ecxkey->haspubkey = 1; + } + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PROPERTIES); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING + || !set_property_query(ecxkey, p->data)) + return 0; + } + + return 1; +} + +static int x25519_set_params(void *key, const OSSL_PARAM params[]) +{ + return ecx_set_params(key, params); +} + +static int x448_set_params(void *key, const OSSL_PARAM params[]) +{ + return ecx_set_params(key, params); +} + +static int ed25519_set_params(void *key, const OSSL_PARAM params[]) +{ + return 1; +} + +static int ed448_set_params(void *key, const OSSL_PARAM params[]) +{ + return 1; +} + +static const OSSL_PARAM ecx_settable_params[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM ed_settable_params[] = { + OSSL_PARAM_END +}; + +static const OSSL_PARAM *x25519_settable_params(void *provctx) +{ + return ecx_settable_params; +} + +static const OSSL_PARAM *x448_settable_params(void *provctx) +{ + return ecx_settable_params; +} + +static const OSSL_PARAM *ed25519_settable_params(void *provctx) +{ + return ed_settable_params; +} + +static const OSSL_PARAM *ed448_settable_params(void *provctx) +{ + return ed_settable_params; +} + +static void *ecx_gen_init(void *provctx, int selection, + const OSSL_PARAM params[], ECX_KEY_TYPE type) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx); + struct ecx_gen_ctx *gctx = NULL; + + if (!ossl_prov_is_running()) + return NULL; + + if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { + gctx->libctx = libctx; + gctx->type = type; + gctx->selection = selection; + } + if (!ecx_gen_set_params(gctx, params)) { + OPENSSL_free(gctx); + gctx = NULL; + } + return gctx; +} + +static void *x25519_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + return ecx_gen_init(provctx, selection, params, ECX_KEY_TYPE_X25519); +} + +static void *x448_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + return ecx_gen_init(provctx, selection, params, ECX_KEY_TYPE_X448); +} + +static void *ed25519_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + return ecx_gen_init(provctx, selection, params, ECX_KEY_TYPE_ED25519); +} + +static void *ed448_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + return ecx_gen_init(provctx, selection, params, ECX_KEY_TYPE_ED448); +} + +static int ecx_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + struct ecx_gen_ctx *gctx = genctx; + const OSSL_PARAM *p; + + if (gctx == NULL) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME); + if (p != NULL) { + const char *groupname = NULL; + + /* + * We optionally allow setting a group name - but each algorithm only + * support one such name, so all we do is verify that it is the one we + * expected. + */ + switch (gctx->type) { + case ECX_KEY_TYPE_X25519: + groupname = "x25519"; + break; + case ECX_KEY_TYPE_X448: + groupname = "x448"; + break; + default: + /* We only support this for key exchange at the moment */ + break; + } + if (p->data_type != OSSL_PARAM_UTF8_STRING + || groupname == NULL + || OPENSSL_strcasecmp(p->data, groupname) != 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + OPENSSL_free(gctx->propq); + gctx->propq = OPENSSL_strdup(p->data); + if (gctx->propq == NULL) + return 0; + } + + return 1; +} + +static const OSSL_PARAM *ecx_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + static OSSL_PARAM settable[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_END + }; + return settable; +} + +static void *ecx_gen(struct ecx_gen_ctx *gctx) +{ + ECX_KEY *key; + unsigned char *privkey; + + if (gctx == NULL) + return NULL; + if ((key = ossl_ecx_key_new(gctx->libctx, gctx->type, 0, + gctx->propq)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + /* If we're doing parameter generation then we just return a blank key */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return key; + + if ((privkey = ossl_ecx_key_allocate_privkey(key)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + if (RAND_priv_bytes_ex(gctx->libctx, privkey, key->keylen, 0) <= 0) + goto err; + switch (gctx->type) { + case ECX_KEY_TYPE_X25519: + privkey[0] &= 248; + privkey[X25519_KEYLEN - 1] &= 127; + privkey[X25519_KEYLEN - 1] |= 64; + ossl_x25519_public_from_private(key->pubkey, privkey); + break; + case ECX_KEY_TYPE_X448: + privkey[0] &= 252; + privkey[X448_KEYLEN - 1] |= 128; + ossl_x448_public_from_private(key->pubkey, privkey); + break; + case ECX_KEY_TYPE_ED25519: + if (!ossl_ed25519_public_from_private(gctx->libctx, key->pubkey, privkey, + gctx->propq)) + goto err; + break; + case ECX_KEY_TYPE_ED448: + if (!ossl_ed448_public_from_private(gctx->libctx, key->pubkey, privkey, + gctx->propq)) + goto err; + break; + } + key->haspubkey = 1; + return key; +err: + ossl_ecx_key_free(key); + return NULL; +} + +static void *x25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct ecx_gen_ctx *gctx = genctx; + + if (!ossl_prov_is_running()) + return 0; + +#ifdef S390X_EC_ASM + if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X25519)) + return s390x_ecx_keygen25519(gctx); +#endif + return ecx_gen(gctx); +} + +static void *x448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct ecx_gen_ctx *gctx = genctx; + + if (!ossl_prov_is_running()) + return 0; + +#ifdef S390X_EC_ASM + if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X448)) + return s390x_ecx_keygen448(gctx); +#endif + return ecx_gen(gctx); +} + +static void *ed25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct ecx_gen_ctx *gctx = genctx; + + if (!ossl_prov_is_running()) + return 0; + +#ifdef S390X_EC_ASM + if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_ED25519) + && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_ED25519) + && OPENSSL_s390xcap_P.kdsa[0] + & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED25519)) + return s390x_ecd_keygen25519(gctx); +#endif + return ecx_gen(gctx); +} + +static void *ed448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct ecx_gen_ctx *gctx = genctx; + + if (!ossl_prov_is_running()) + return 0; + +#ifdef S390X_EC_ASM + if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_ED448) + && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_ED448) + && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED448)) + return s390x_ecd_keygen448(gctx); +#endif + return ecx_gen(gctx); +} + +static void ecx_gen_cleanup(void *genctx) +{ + struct ecx_gen_ctx *gctx = genctx; + + OPENSSL_free(gctx->propq); + OPENSSL_free(gctx); +} + +void *ecx_load(const void *reference, size_t reference_sz) +{ + ECX_KEY *key = NULL; + + if (ossl_prov_is_running() && reference_sz == sizeof(key)) { + /* The contents of the reference is the address to our object */ + key = *(ECX_KEY **)reference; + /* We grabbed, so we detach it */ + *(ECX_KEY **)reference = NULL; + return key; + } + return NULL; +} + +static void *ecx_dup(const void *keydata_from, int selection) +{ + if (ossl_prov_is_running()) + return ossl_ecx_key_dup(keydata_from, selection); + return NULL; +} + +static int ecx_key_pairwise_check(const ECX_KEY *ecx, int type) +{ + uint8_t pub[64]; + + switch (type) { + case ECX_KEY_TYPE_X25519: + ossl_x25519_public_from_private(pub, ecx->privkey); + break; + case ECX_KEY_TYPE_X448: + ossl_x448_public_from_private(pub, ecx->privkey); + break; + case ECX_KEY_TYPE_ED25519: + if (!ossl_ed25519_public_from_private(ecx->libctx, pub, ecx->privkey, + ecx->propq)) + return 0; + break; + case ECX_KEY_TYPE_ED448: + if (!ossl_ed448_public_from_private(ecx->libctx, pub, ecx->privkey, + ecx->propq)) + return 0; + break; + default: + return 0; + } + return CRYPTO_memcmp(ecx->pubkey, pub, ecx->keylen) == 0; +} + +static int ecx_validate(const void *keydata, int selection, int type, size_t keylen) +{ + const ECX_KEY *ecx = keydata; + int ok = keylen == ecx->keylen; + + if (!ossl_prov_is_running()) + return 0; + + if ((selection & ECX_POSSIBLE_SELECTIONS) == 0) + return 1; /* nothing to validate */ + + if (!ok) { + ERR_raise(ERR_LIB_PROV, PROV_R_ALGORITHM_MISMATCH); + return 0; + } + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && ecx->haspubkey; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && ecx->privkey != NULL; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR) + ok = ok && ecx_key_pairwise_check(ecx, type); + + return ok; +} + +static int x25519_validate(const void *keydata, int selection, int checktype) +{ + return ecx_validate(keydata, selection, ECX_KEY_TYPE_X25519, X25519_KEYLEN); +} + +static int x448_validate(const void *keydata, int selection, int checktype) +{ + return ecx_validate(keydata, selection, ECX_KEY_TYPE_X448, X448_KEYLEN); +} + +static int ed25519_validate(const void *keydata, int selection, int checktype) +{ + return ecx_validate(keydata, selection, ECX_KEY_TYPE_ED25519, ED25519_KEYLEN); +} + +static int ed448_validate(const void *keydata, int selection, int checktype) +{ + return ecx_validate(keydata, selection, ECX_KEY_TYPE_ED448, ED448_KEYLEN); +} + +#define MAKE_KEYMGMT_FUNCTIONS(alg) \ + const OSSL_DISPATCH ossl_##alg##_keymgmt_functions[] = { \ + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))alg##_new_key }, \ + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ossl_ecx_key_free }, \ + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))alg##_get_params }, \ + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))alg##_gettable_params }, \ + { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))alg##_set_params }, \ + { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))alg##_settable_params }, \ + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ecx_has }, \ + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ecx_match }, \ + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))alg##_validate }, \ + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ecx_import }, \ + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ecx_imexport_types }, \ + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ecx_export }, \ + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ecx_imexport_types }, \ + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))alg##_gen_init }, \ + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))ecx_gen_set_params }, \ + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, \ + (void (*)(void))ecx_gen_settable_params }, \ + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))alg##_gen }, \ + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))ecx_gen_cleanup }, \ + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))ecx_load }, \ + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))ecx_dup }, \ + { 0, NULL } \ + }; + +MAKE_KEYMGMT_FUNCTIONS(x25519) +MAKE_KEYMGMT_FUNCTIONS(x448) +MAKE_KEYMGMT_FUNCTIONS(ed25519) +MAKE_KEYMGMT_FUNCTIONS(ed448) + +#ifdef S390X_EC_ASM +# include "s390x_arch.h" + +static void *s390x_ecx_keygen25519(struct ecx_gen_ctx *gctx) +{ + static const unsigned char generator[] = { + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + ECX_KEY *key = ossl_ecx_key_new(gctx->libctx, ECX_KEY_TYPE_X25519, 1, + gctx->propq); + unsigned char *privkey = NULL, *pubkey; + + if (key == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* If we're doing parameter generation then we just return a blank key */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return key; + + pubkey = key->pubkey; + + privkey = ossl_ecx_key_allocate_privkey(key); + if (privkey == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (RAND_priv_bytes_ex(gctx->libctx, privkey, X25519_KEYLEN, 0) <= 0) + goto err; + + privkey[0] &= 248; + privkey[31] &= 127; + privkey[31] |= 64; + + if (s390x_x25519_mul(pubkey, generator, privkey) != 1) + goto err; + key->haspubkey = 1; + return key; + err: + ossl_ecx_key_free(key); + return NULL; +} + +static void *s390x_ecx_keygen448(struct ecx_gen_ctx *gctx) +{ + static const unsigned char generator[] = { + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + ECX_KEY *key = ossl_ecx_key_new(gctx->libctx, ECX_KEY_TYPE_X448, 1, + gctx->propq); + unsigned char *privkey = NULL, *pubkey; + + if (key == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* If we're doing parameter generation then we just return a blank key */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return key; + + pubkey = key->pubkey; + + privkey = ossl_ecx_key_allocate_privkey(key); + if (privkey == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (RAND_priv_bytes_ex(gctx->libctx, privkey, X448_KEYLEN, 0) <= 0) + goto err; + + privkey[0] &= 252; + privkey[55] |= 128; + + if (s390x_x448_mul(pubkey, generator, privkey) != 1) + goto err; + key->haspubkey = 1; + return key; + err: + ossl_ecx_key_free(key); + return NULL; +} + +static void *s390x_ecd_keygen25519(struct ecx_gen_ctx *gctx) +{ + static const unsigned char generator_x[] = { + 0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, + 0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, + 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21 + }; + static const unsigned char generator_y[] = { + 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + }; + unsigned char x_dst[32], buff[SHA512_DIGEST_LENGTH]; + ECX_KEY *key = ossl_ecx_key_new(gctx->libctx, ECX_KEY_TYPE_ED25519, 1, + gctx->propq); + unsigned char *privkey = NULL, *pubkey; + unsigned int sz; + EVP_MD *sha = NULL; + int j; + + if (key == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* If we're doing parameter generation then we just return a blank key */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return key; + + pubkey = key->pubkey; + + privkey = ossl_ecx_key_allocate_privkey(key); + if (privkey == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (RAND_priv_bytes_ex(gctx->libctx, privkey, ED25519_KEYLEN, 0) <= 0) + goto err; + + sha = EVP_MD_fetch(gctx->libctx, "SHA512", gctx->propq); + if (sha == NULL) + goto err; + j = EVP_Digest(privkey, 32, buff, &sz, sha, NULL); + EVP_MD_free(sha); + if (!j) + goto err; + + buff[0] &= 248; + buff[31] &= 63; + buff[31] |= 64; + + if (s390x_ed25519_mul(x_dst, pubkey, + generator_x, generator_y, buff) != 1) + goto err; + + pubkey[31] |= ((x_dst[0] & 0x01) << 7); + key->haspubkey = 1; + return key; + err: + ossl_ecx_key_free(key); + return NULL; +} + +static void *s390x_ecd_keygen448(struct ecx_gen_ctx *gctx) +{ + static const unsigned char generator_x[] = { + 0x5e, 0xc0, 0x0c, 0xc7, 0x2b, 0xa8, 0x26, 0x26, 0x8e, 0x93, 0x00, 0x8b, + 0xe1, 0x80, 0x3b, 0x43, 0x11, 0x65, 0xb6, 0x2a, 0xf7, 0x1a, 0xae, 0x12, + 0x64, 0xa4, 0xd3, 0xa3, 0x24, 0xe3, 0x6d, 0xea, 0x67, 0x17, 0x0f, 0x47, + 0x70, 0x65, 0x14, 0x9e, 0xda, 0x36, 0xbf, 0x22, 0xa6, 0x15, 0x1d, 0x22, + 0xed, 0x0d, 0xed, 0x6b, 0xc6, 0x70, 0x19, 0x4f, 0x00 + }; + static const unsigned char generator_y[] = { + 0x14, 0xfa, 0x30, 0xf2, 0x5b, 0x79, 0x08, 0x98, 0xad, 0xc8, 0xd7, 0x4e, + 0x2c, 0x13, 0xbd, 0xfd, 0xc4, 0x39, 0x7c, 0xe6, 0x1c, 0xff, 0xd3, 0x3a, + 0xd7, 0xc2, 0xa0, 0x05, 0x1e, 0x9c, 0x78, 0x87, 0x40, 0x98, 0xa3, 0x6c, + 0x73, 0x73, 0xea, 0x4b, 0x62, 0xc7, 0xc9, 0x56, 0x37, 0x20, 0x76, 0x88, + 0x24, 0xbc, 0xb6, 0x6e, 0x71, 0x46, 0x3f, 0x69, 0x00 + }; + unsigned char x_dst[57], buff[114]; + ECX_KEY *key = ossl_ecx_key_new(gctx->libctx, ECX_KEY_TYPE_ED448, 1, + gctx->propq); + unsigned char *privkey = NULL, *pubkey; + EVP_MD_CTX *hashctx = NULL; + EVP_MD *shake = NULL; + + if (key == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* If we're doing parameter generation then we just return a blank key */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return key; + + pubkey = key->pubkey; + + privkey = ossl_ecx_key_allocate_privkey(key); + if (privkey == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + shake = EVP_MD_fetch(gctx->libctx, "SHAKE256", gctx->propq); + if (shake == NULL) + goto err; + if (RAND_priv_bytes_ex(gctx->libctx, privkey, ED448_KEYLEN, 0) <= 0) + goto err; + + hashctx = EVP_MD_CTX_new(); + if (hashctx == NULL) + goto err; + if (EVP_DigestInit_ex(hashctx, shake, NULL) != 1) + goto err; + if (EVP_DigestUpdate(hashctx, privkey, 57) != 1) + goto err; + if (EVP_DigestFinalXOF(hashctx, buff, sizeof(buff)) != 1) + goto err; + + buff[0] &= -4; + buff[55] |= 0x80; + buff[56] = 0; + + if (s390x_ed448_mul(x_dst, pubkey, + generator_x, generator_y, buff) != 1) + goto err; + + pubkey[56] |= ((x_dst[0] & 0x01) << 7); + EVP_MD_CTX_free(hashctx); + EVP_MD_free(shake); + key->haspubkey = 1; + return key; + err: + ossl_ecx_key_free(key); + EVP_MD_CTX_free(hashctx); + EVP_MD_free(shake); + return NULL; +} +#endif diff --git a/providers/implementations/keymgmt/kdf_legacy_kmgmt.c b/providers/implementations/keymgmt/kdf_legacy_kmgmt.c new file mode 100644 index 000000000000..0b301c333b09 --- /dev/null +++ b/providers/implementations/keymgmt/kdf_legacy_kmgmt.c @@ -0,0 +1,104 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This implemments a dummy key manager for legacy KDFs that still support the + * old way of performing a KDF via EVP_PKEY_derive(). New KDFs should not be + * implemented this way. In reality there is no key data for such KDFs, so this + * key manager does very little. + */ + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/err.h> +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "prov/kdfexchange.h" + +static OSSL_FUNC_keymgmt_new_fn kdf_newdata; +static OSSL_FUNC_keymgmt_free_fn kdf_freedata; +static OSSL_FUNC_keymgmt_has_fn kdf_has; + +KDF_DATA *ossl_kdf_data_new(void *provctx) +{ + KDF_DATA *kdfdata; + + if (!ossl_prov_is_running()) + return NULL; + + kdfdata = OPENSSL_zalloc(sizeof(*kdfdata)); + if (kdfdata == NULL) + return NULL; + + kdfdata->lock = CRYPTO_THREAD_lock_new(); + if (kdfdata->lock == NULL) { + OPENSSL_free(kdfdata); + return NULL; + } + kdfdata->libctx = PROV_LIBCTX_OF(provctx); + kdfdata->refcnt = 1; + + return kdfdata; +} + +void ossl_kdf_data_free(KDF_DATA *kdfdata) +{ + int ref = 0; + + if (kdfdata == NULL) + return; + + CRYPTO_DOWN_REF(&kdfdata->refcnt, &ref, kdfdata->lock); + if (ref > 0) + return; + + CRYPTO_THREAD_lock_free(kdfdata->lock); + OPENSSL_free(kdfdata); +} + +int ossl_kdf_data_up_ref(KDF_DATA *kdfdata) +{ + int ref = 0; + + /* This is effectively doing a new operation on the KDF_DATA and should be + * adequately guarded again modules' error states. However, both current + * calls here are guarded propery in exchange/kdf_exch.c. Thus, it + * could be removed here. The concern is that something in the future + * might call this function without adequate guards. It's a cheap call, + * it seems best to leave it even though it is currently redundant. + */ + if (!ossl_prov_is_running()) + return 0; + + CRYPTO_UP_REF(&kdfdata->refcnt, &ref, kdfdata->lock); + return 1; +} + +static void *kdf_newdata(void *provctx) +{ + return ossl_kdf_data_new(provctx); +} + +static void kdf_freedata(void *kdfdata) +{ + ossl_kdf_data_free(kdfdata); +} + +static int kdf_has(const void *keydata, int selection) +{ + return 1; /* nothing is missing */ +} + +const OSSL_DISPATCH ossl_kdf_keymgmt_functions[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))kdf_newdata }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))kdf_freedata }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))kdf_has }, + { 0, NULL } +}; diff --git a/providers/implementations/keymgmt/mac_legacy_kmgmt.c b/providers/implementations/keymgmt/mac_legacy_kmgmt.c new file mode 100644 index 000000000000..c934ff164094 --- /dev/null +++ b/providers/implementations/keymgmt/mac_legacy_kmgmt.c @@ -0,0 +1,575 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* We need to use some engine deprecated APIs */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#include <string.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/proverr.h> +#include <openssl/param_build.h> +#ifndef FIPS_MODULE +# include <openssl/engine.h> +#endif +#include "internal/param_build_set.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "prov/macsignature.h" + +static OSSL_FUNC_keymgmt_new_fn mac_new; +static OSSL_FUNC_keymgmt_free_fn mac_free; +static OSSL_FUNC_keymgmt_gen_init_fn mac_gen_init; +static OSSL_FUNC_keymgmt_gen_fn mac_gen; +static OSSL_FUNC_keymgmt_gen_cleanup_fn mac_gen_cleanup; +static OSSL_FUNC_keymgmt_gen_set_params_fn mac_gen_set_params; +static OSSL_FUNC_keymgmt_gen_settable_params_fn mac_gen_settable_params; +static OSSL_FUNC_keymgmt_get_params_fn mac_get_params; +static OSSL_FUNC_keymgmt_gettable_params_fn mac_gettable_params; +static OSSL_FUNC_keymgmt_set_params_fn mac_set_params; +static OSSL_FUNC_keymgmt_settable_params_fn mac_settable_params; +static OSSL_FUNC_keymgmt_has_fn mac_has; +static OSSL_FUNC_keymgmt_match_fn mac_match; +static OSSL_FUNC_keymgmt_import_fn mac_import; +static OSSL_FUNC_keymgmt_import_types_fn mac_imexport_types; +static OSSL_FUNC_keymgmt_export_fn mac_export; +static OSSL_FUNC_keymgmt_export_types_fn mac_imexport_types; + +static OSSL_FUNC_keymgmt_new_fn mac_new_cmac; +static OSSL_FUNC_keymgmt_gettable_params_fn cmac_gettable_params; +static OSSL_FUNC_keymgmt_import_types_fn cmac_imexport_types; +static OSSL_FUNC_keymgmt_export_types_fn cmac_imexport_types; +static OSSL_FUNC_keymgmt_gen_init_fn cmac_gen_init; +static OSSL_FUNC_keymgmt_gen_set_params_fn cmac_gen_set_params; +static OSSL_FUNC_keymgmt_gen_settable_params_fn cmac_gen_settable_params; + +struct mac_gen_ctx { + OSSL_LIB_CTX *libctx; + int selection; + unsigned char *priv_key; + size_t priv_key_len; + PROV_CIPHER cipher; +}; + +MAC_KEY *ossl_mac_key_new(OSSL_LIB_CTX *libctx, int cmac) +{ + MAC_KEY *mackey; + + if (!ossl_prov_is_running()) + return NULL; + + mackey = OPENSSL_zalloc(sizeof(*mackey)); + if (mackey == NULL) + return NULL; + + mackey->lock = CRYPTO_THREAD_lock_new(); + if (mackey->lock == NULL) { + OPENSSL_free(mackey); + return NULL; + } + mackey->libctx = libctx; + mackey->refcnt = 1; + mackey->cmac = cmac; + + return mackey; +} + +void ossl_mac_key_free(MAC_KEY *mackey) +{ + int ref = 0; + + if (mackey == NULL) + return; + + CRYPTO_DOWN_REF(&mackey->refcnt, &ref, mackey->lock); + if (ref > 0) + return; + + OPENSSL_secure_clear_free(mackey->priv_key, mackey->priv_key_len); + OPENSSL_free(mackey->properties); + ossl_prov_cipher_reset(&mackey->cipher); + CRYPTO_THREAD_lock_free(mackey->lock); + OPENSSL_free(mackey); +} + +int ossl_mac_key_up_ref(MAC_KEY *mackey) +{ + int ref = 0; + + /* This is effectively doing a new operation on the MAC_KEY and should be + * adequately guarded again modules' error states. However, both current + * calls here are guarded propery in signature/mac_legacy.c. Thus, it + * could be removed here. The concern is that something in the future + * might call this function without adequate guards. It's a cheap call, + * it seems best to leave it even though it is currently redundant. + */ + if (!ossl_prov_is_running()) + return 0; + + CRYPTO_UP_REF(&mackey->refcnt, &ref, mackey->lock); + return 1; +} + +static void *mac_new(void *provctx) +{ + return ossl_mac_key_new(PROV_LIBCTX_OF(provctx), 0); +} + +static void *mac_new_cmac(void *provctx) +{ + return ossl_mac_key_new(PROV_LIBCTX_OF(provctx), 1); +} + +static void mac_free(void *mackey) +{ + ossl_mac_key_free(mackey); +} + +static int mac_has(const void *keydata, int selection) +{ + const MAC_KEY *key = keydata; + int ok = 0; + + if (ossl_prov_is_running() && key != NULL) { + /* + * MAC keys always have all the parameters they need (i.e. none). + * Therefore we always return with 1, if asked about parameters. + * Similarly for public keys. + */ + ok = 1; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = key->priv_key != NULL; + } + return ok; +} + +static int mac_match(const void *keydata1, const void *keydata2, int selection) +{ + const MAC_KEY *key1 = keydata1; + const MAC_KEY *key2 = keydata2; + int ok = 1; + + if (!ossl_prov_is_running()) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + if ((key1->priv_key == NULL && key2->priv_key != NULL) + || (key1->priv_key != NULL && key2->priv_key == NULL) + || key1->priv_key_len != key2->priv_key_len + || (key1->cipher.cipher == NULL && key2->cipher.cipher != NULL) + || (key1->cipher.cipher != NULL && key2->cipher.cipher == NULL)) + ok = 0; + else + ok = ok && (key1->priv_key == NULL /* implies key2->privkey == NULL */ + || CRYPTO_memcmp(key1->priv_key, key2->priv_key, + key1->priv_key_len) == 0); + if (key1->cipher.cipher != NULL) + ok = ok && EVP_CIPHER_is_a(key1->cipher.cipher, + EVP_CIPHER_get0_name(key2->cipher.cipher)); + } + return ok; +} + +static int mac_key_fromdata(MAC_KEY *key, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + OPENSSL_secure_clear_free(key->priv_key, key->priv_key_len); + /* allocate at least one byte to distinguish empty key from no key set */ + key->priv_key = OPENSSL_secure_malloc(p->data_size > 0 ? p->data_size : 1); + if (key->priv_key == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(key->priv_key, p->data, p->data_size); + key->priv_key_len = p->data_size; + } + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PROPERTIES); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + OPENSSL_free(key->properties); + key->properties = OPENSSL_strdup(p->data); + if (key->properties == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + } + + if (key->cmac && !ossl_prov_cipher_load_from_params(&key->cipher, params, + key->libctx)) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + if (key->priv_key != NULL) + return 1; + + return 0; +} + +static int mac_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + MAC_KEY *key = keydata; + + if (!ossl_prov_is_running() || key == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) == 0) + return 0; + + return mac_key_fromdata(key, params); +} + +static int key_to_params(MAC_KEY *key, OSSL_PARAM_BLD *tmpl, + OSSL_PARAM params[]) +{ + if (key == NULL) + return 0; + + if (key->priv_key != NULL + && !ossl_param_build_set_octet_string(tmpl, params, + OSSL_PKEY_PARAM_PRIV_KEY, + key->priv_key, key->priv_key_len)) + return 0; + + if (key->cipher.cipher != NULL + && !ossl_param_build_set_utf8_string(tmpl, params, + OSSL_PKEY_PARAM_CIPHER, + EVP_CIPHER_get0_name(key->cipher.cipher))) + return 0; + +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + if (key->cipher.engine != NULL + && !ossl_param_build_set_utf8_string(tmpl, params, + OSSL_PKEY_PARAM_ENGINE, + ENGINE_get_id(key->cipher.engine))) + return 0; +#endif + + return 1; +} + +static int mac_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, + void *cbarg) +{ + MAC_KEY *key = keydata; + OSSL_PARAM_BLD *tmpl; + OSSL_PARAM *params = NULL; + int ret = 0; + + if (!ossl_prov_is_running() || key == NULL) + return 0; + + tmpl = OSSL_PARAM_BLD_new(); + if (tmpl == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0 + && !key_to_params(key, tmpl, NULL)) + goto err; + + params = OSSL_PARAM_BLD_to_param(tmpl); + if (params == NULL) + goto err; + + ret = param_cb(params, cbarg); + OSSL_PARAM_free(params); +err: + OSSL_PARAM_BLD_free(tmpl); + return ret; +} + +static const OSSL_PARAM mac_key_types[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *mac_imexport_types(int selection) +{ + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + return mac_key_types; + return NULL; +} + +static const OSSL_PARAM cmac_key_types[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_ENGINE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *cmac_imexport_types(int selection) +{ + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + return cmac_key_types; + return NULL; +} + +static int mac_get_params(void *key, OSSL_PARAM params[]) +{ + return key_to_params(key, NULL, params); +} + +static const OSSL_PARAM *mac_gettable_params(void *provctx) +{ + static const OSSL_PARAM gettable_params[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), + OSSL_PARAM_END + }; + return gettable_params; +} + +static const OSSL_PARAM *cmac_gettable_params(void *provctx) +{ + static const OSSL_PARAM gettable_params[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_ENGINE, NULL, 0), + OSSL_PARAM_END + }; + return gettable_params; +} + +static int mac_set_params(void *keydata, const OSSL_PARAM params[]) +{ + MAC_KEY *key = keydata; + const OSSL_PARAM *p; + + if (key == NULL) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); + if (p != NULL) + return mac_key_fromdata(key, params); + + return 1; +} + +static const OSSL_PARAM *mac_settable_params(void *provctx) +{ + static const OSSL_PARAM settable_params[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), + OSSL_PARAM_END + }; + return settable_params; +} + +static void *mac_gen_init_common(void *provctx, int selection) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx); + struct mac_gen_ctx *gctx = NULL; + + if (!ossl_prov_is_running()) + return NULL; + + if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { + gctx->libctx = libctx; + gctx->selection = selection; + } + return gctx; +} + +static void *mac_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + struct mac_gen_ctx *gctx = mac_gen_init_common(provctx, selection); + + if (gctx != NULL && !mac_gen_set_params(gctx, params)) { + OPENSSL_free(gctx); + gctx = NULL; + } + return gctx; +} + +static void *cmac_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + struct mac_gen_ctx *gctx = mac_gen_init_common(provctx, selection); + + if (gctx != NULL && !cmac_gen_set_params(gctx, params)) { + OPENSSL_free(gctx); + gctx = NULL; + } + return gctx; +} + +static int mac_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + struct mac_gen_ctx *gctx = genctx; + const OSSL_PARAM *p; + + if (gctx == NULL) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + gctx->priv_key = OPENSSL_secure_malloc(p->data_size); + if (gctx->priv_key == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(gctx->priv_key, p->data, p->data_size); + gctx->priv_key_len = p->data_size; + } + + return 1; +} + +static int cmac_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + struct mac_gen_ctx *gctx = genctx; + + if (!mac_gen_set_params(genctx, params)) + return 0; + + if (!ossl_prov_cipher_load_from_params(&gctx->cipher, params, + gctx->libctx)) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + return 1; +} + +static const OSSL_PARAM *mac_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + static OSSL_PARAM settable[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), + OSSL_PARAM_END + }; + return settable; +} + +static const OSSL_PARAM *cmac_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + static OSSL_PARAM settable[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_END + }; + return settable; +} + +static void *mac_gen(void *genctx, OSSL_CALLBACK *cb, void *cbarg) +{ + struct mac_gen_ctx *gctx = genctx; + MAC_KEY *key; + + if (!ossl_prov_is_running() || gctx == NULL) + return NULL; + + if ((key = ossl_mac_key_new(gctx->libctx, 0)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + /* If we're doing parameter generation then we just return a blank key */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return key; + + if (gctx->priv_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + ossl_mac_key_free(key); + return NULL; + } + + /* + * This is horrible but required for backwards compatibility. We don't + * actually do real key generation at all. We simply copy the key that was + * previously set in the gctx. Hopefully at some point in the future all + * of this can be removed and we will only support the EVP_KDF APIs. + */ + if (!ossl_prov_cipher_copy(&key->cipher, &gctx->cipher)) { + ossl_mac_key_free(key); + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return NULL; + } + ossl_prov_cipher_reset(&gctx->cipher); + key->priv_key = gctx->priv_key; + key->priv_key_len = gctx->priv_key_len; + gctx->priv_key_len = 0; + gctx->priv_key = NULL; + + return key; +} + +static void mac_gen_cleanup(void *genctx) +{ + struct mac_gen_ctx *gctx = genctx; + + OPENSSL_secure_clear_free(gctx->priv_key, gctx->priv_key_len); + ossl_prov_cipher_reset(&gctx->cipher); + OPENSSL_free(gctx); +} + +const OSSL_DISPATCH ossl_mac_legacy_keymgmt_functions[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))mac_new }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))mac_free }, + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))mac_get_params }, + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))mac_gettable_params }, + { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))mac_set_params }, + { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))mac_settable_params }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))mac_has }, + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))mac_match }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))mac_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))mac_imexport_types }, + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))mac_export }, + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))mac_imexport_types }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))mac_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))mac_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))mac_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))mac_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))mac_gen_cleanup }, + { 0, NULL } +}; + +const OSSL_DISPATCH ossl_cmac_legacy_keymgmt_functions[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))mac_new_cmac }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))mac_free }, + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))mac_get_params }, + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))cmac_gettable_params }, + { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))mac_set_params }, + { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))mac_settable_params }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))mac_has }, + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))mac_match }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))mac_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))cmac_imexport_types }, + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))mac_export }, + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))cmac_imexport_types }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))cmac_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))cmac_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))cmac_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))mac_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))mac_gen_cleanup }, + { 0, NULL } +}; + diff --git a/providers/implementations/keymgmt/rsa_kmgmt.c b/providers/implementations/keymgmt/rsa_kmgmt.c new file mode 100644 index 000000000000..b76835ccc437 --- /dev/null +++ b/providers/implementations/keymgmt/rsa_kmgmt.c @@ -0,0 +1,744 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * RSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/rsa.h> +#include <openssl/evp.h> +#include <openssl/proverr.h> +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "crypto/rsa.h" +#include "crypto/cryptlib.h" +#include "internal/param_build_set.h" + +static OSSL_FUNC_keymgmt_new_fn rsa_newdata; +static OSSL_FUNC_keymgmt_new_fn rsapss_newdata; +static OSSL_FUNC_keymgmt_gen_init_fn rsa_gen_init; +static OSSL_FUNC_keymgmt_gen_init_fn rsapss_gen_init; +static OSSL_FUNC_keymgmt_gen_set_params_fn rsa_gen_set_params; +static OSSL_FUNC_keymgmt_gen_settable_params_fn rsa_gen_settable_params; +static OSSL_FUNC_keymgmt_gen_settable_params_fn rsapss_gen_settable_params; +static OSSL_FUNC_keymgmt_gen_fn rsa_gen; +static OSSL_FUNC_keymgmt_gen_cleanup_fn rsa_gen_cleanup; +static OSSL_FUNC_keymgmt_load_fn rsa_load; +static OSSL_FUNC_keymgmt_load_fn rsapss_load; +static OSSL_FUNC_keymgmt_free_fn rsa_freedata; +static OSSL_FUNC_keymgmt_get_params_fn rsa_get_params; +static OSSL_FUNC_keymgmt_gettable_params_fn rsa_gettable_params; +static OSSL_FUNC_keymgmt_has_fn rsa_has; +static OSSL_FUNC_keymgmt_match_fn rsa_match; +static OSSL_FUNC_keymgmt_validate_fn rsa_validate; +static OSSL_FUNC_keymgmt_import_fn rsa_import; +static OSSL_FUNC_keymgmt_import_types_fn rsa_import_types; +static OSSL_FUNC_keymgmt_export_fn rsa_export; +static OSSL_FUNC_keymgmt_export_types_fn rsa_export_types; +static OSSL_FUNC_keymgmt_query_operation_name_fn rsa_query_operation_name; +static OSSL_FUNC_keymgmt_dup_fn rsa_dup; + +#define RSA_DEFAULT_MD "SHA256" +#define RSA_PSS_DEFAULT_MD OSSL_DIGEST_NAME_SHA1 +#define RSA_POSSIBLE_SELECTIONS \ + (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) + +DEFINE_STACK_OF(BIGNUM) +DEFINE_SPECIAL_STACK_OF_CONST(BIGNUM_const, BIGNUM) + +static int pss_params_fromdata(RSA_PSS_PARAMS_30 *pss_params, int *defaults_set, + const OSSL_PARAM params[], int rsa_type, + OSSL_LIB_CTX *libctx) +{ + if (!ossl_rsa_pss_params_30_fromdata(pss_params, defaults_set, + params, libctx)) + return 0; + + /* If not a PSS type RSA, sending us PSS parameters is wrong */ + if (rsa_type != RSA_FLAG_TYPE_RSASSAPSS + && !ossl_rsa_pss_params_30_is_unrestricted(pss_params)) + return 0; + + return 1; +} + +static void *rsa_newdata(void *provctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx); + RSA *rsa; + + if (!ossl_prov_is_running()) + return NULL; + + rsa = ossl_rsa_new_with_ctx(libctx); + if (rsa != NULL) { + RSA_clear_flags(rsa, RSA_FLAG_TYPE_MASK); + RSA_set_flags(rsa, RSA_FLAG_TYPE_RSA); + } + return rsa; +} + +static void *rsapss_newdata(void *provctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx); + RSA *rsa; + + if (!ossl_prov_is_running()) + return NULL; + + rsa = ossl_rsa_new_with_ctx(libctx); + if (rsa != NULL) { + RSA_clear_flags(rsa, RSA_FLAG_TYPE_MASK); + RSA_set_flags(rsa, RSA_FLAG_TYPE_RSASSAPSS); + } + return rsa; +} + +static void rsa_freedata(void *keydata) +{ + RSA_free(keydata); +} + +static int rsa_has(const void *keydata, int selection) +{ + const RSA *rsa = keydata; + int ok = 1; + + if (rsa == NULL || !ossl_prov_is_running()) + return 0; + if ((selection & RSA_POSSIBLE_SELECTIONS) == 0) + return 1; /* the selection is not missing */ + + /* OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS are always available even if empty */ + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) + ok = ok && (RSA_get0_e(rsa) != NULL); + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && (RSA_get0_n(rsa) != NULL); + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && (RSA_get0_d(rsa) != NULL); + return ok; +} + +static int rsa_match(const void *keydata1, const void *keydata2, int selection) +{ + const RSA *rsa1 = keydata1; + const RSA *rsa2 = keydata2; + int ok = 1; + + if (!ossl_prov_is_running()) + return 0; + + /* There is always an |e| */ + ok = ok && BN_cmp(RSA_get0_e(rsa1), RSA_get0_e(rsa2)) == 0; + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int key_checked = 0; + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + const BIGNUM *pa = RSA_get0_n(rsa1); + const BIGNUM *pb = RSA_get0_n(rsa2); + + if (pa != NULL && pb != NULL) { + ok = ok && BN_cmp(pa, pb) == 0; + key_checked = 1; + } + } + if (!key_checked + && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + const BIGNUM *pa = RSA_get0_d(rsa1); + const BIGNUM *pb = RSA_get0_d(rsa2); + + if (pa != NULL && pb != NULL) { + ok = ok && BN_cmp(pa, pb) == 0; + key_checked = 1; + } + } + ok = ok && key_checked; + } + return ok; +} + +static int rsa_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + RSA *rsa = keydata; + int rsa_type; + int ok = 1; + int pss_defaults_set = 0; + + if (!ossl_prov_is_running() || rsa == NULL) + return 0; + + if ((selection & RSA_POSSIBLE_SELECTIONS) == 0) + return 0; + + rsa_type = RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK); + + if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0) + ok = ok && pss_params_fromdata(ossl_rsa_get0_pss_params_30(rsa), + &pss_defaults_set, + params, rsa_type, + ossl_rsa_get0_libctx(rsa)); + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int include_private = + selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; + + ok = ok && ossl_rsa_fromdata(rsa, params, include_private); + } + + return ok; +} + +static int rsa_export(void *keydata, int selection, + OSSL_CALLBACK *param_callback, void *cbarg) +{ + RSA *rsa = keydata; + const RSA_PSS_PARAMS_30 *pss_params = ossl_rsa_get0_pss_params_30(rsa); + OSSL_PARAM_BLD *tmpl; + OSSL_PARAM *params = NULL; + int ok = 1; + + if (!ossl_prov_is_running() || rsa == NULL) + return 0; + + if ((selection & RSA_POSSIBLE_SELECTIONS) == 0) + return 0; + + tmpl = OSSL_PARAM_BLD_new(); + if (tmpl == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0) + ok = ok && (ossl_rsa_pss_params_30_is_unrestricted(pss_params) + || ossl_rsa_pss_params_30_todata(pss_params, tmpl, NULL)); + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int include_private = + selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; + + ok = ok && ossl_rsa_todata(rsa, tmpl, NULL, include_private); + } + + if (!ok || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) { + ok = 0; + goto err; + } + + ok = param_callback(params, cbarg); + OSSL_PARAM_free(params); +err: + OSSL_PARAM_BLD_free(tmpl); + return ok; +} + +#ifdef FIPS_MODULE +/* In fips mode there are no multi-primes. */ +# define RSA_KEY_MP_TYPES() \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR1, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR2, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT1, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT2, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT1, NULL, 0), +#else +/* + * We allow up to 10 prime factors (starting with p, q). + * NOTE: there is only 9 OSSL_PKEY_PARAM_RSA_COEFFICIENT + */ +# define RSA_KEY_MP_TYPES() \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR1, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR2, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR3, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR4, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR5, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR6, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR7, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR8, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR9, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR10, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT1, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT2, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT3, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT4, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT5, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT6, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT7, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT8, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT9, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT10, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT1, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT2, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT3, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT4, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT5, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT6, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT7, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT8, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT9, NULL, 0), +#endif + +#define RSA_KEY_TYPES() \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0), \ +OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_D, NULL, 0), \ +RSA_KEY_MP_TYPES() + +/* + * This provider can export everything in an RSA key, so we use the exact + * same type description for export as for import. Other providers might + * choose to import full keys, but only export the public parts, and will + * therefore have the importkey_types and importkey_types functions return + * different arrays. + */ +static const OSSL_PARAM rsa_key_types[] = { + RSA_KEY_TYPES() + OSSL_PARAM_END +}; +/* + * We lied about the amount of factors, exponents and coefficients, the + * export and import functions can really deal with an infinite amount + * of these numbers. However, RSA keys with too many primes are futile, + * so we at least pretend to have some limits. + */ + +static const OSSL_PARAM *rsa_imexport_types(int selection) +{ + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) + return rsa_key_types; + return NULL; +} + +static const OSSL_PARAM *rsa_import_types(int selection) +{ + return rsa_imexport_types(selection); +} + +static const OSSL_PARAM *rsa_export_types(int selection) +{ + return rsa_imexport_types(selection); +} + +static int rsa_get_params(void *key, OSSL_PARAM params[]) +{ + RSA *rsa = key; + const RSA_PSS_PARAMS_30 *pss_params = ossl_rsa_get0_pss_params_30(rsa); + int rsa_type = RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK); + OSSL_PARAM *p; + int empty = RSA_get0_n(rsa) == NULL; + + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL + && (empty || !OSSL_PARAM_set_int(p, RSA_bits(rsa)))) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL + && (empty || !OSSL_PARAM_set_int(p, RSA_security_bits(rsa)))) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL + && (empty || !OSSL_PARAM_set_int(p, RSA_size(rsa)))) + return 0; + + /* + * For restricted RSA-PSS keys, we ignore the default digest request. + * With RSA-OAEP keys, this may need to be amended. + */ + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST)) != NULL + && (rsa_type != RSA_FLAG_TYPE_RSASSAPSS + || ossl_rsa_pss_params_30_is_unrestricted(pss_params))) { + if (!OSSL_PARAM_set_utf8_string(p, RSA_DEFAULT_MD)) + return 0; + } + + /* + * For non-RSA-PSS keys, we ignore the mandatory digest request. + * With RSA-OAEP keys, this may need to be amended. + */ + if ((p = OSSL_PARAM_locate(params, + OSSL_PKEY_PARAM_MANDATORY_DIGEST)) != NULL + && rsa_type == RSA_FLAG_TYPE_RSASSAPSS + && !ossl_rsa_pss_params_30_is_unrestricted(pss_params)) { + const char *mdname = + ossl_rsa_oaeppss_nid2name(ossl_rsa_pss_params_30_hashalg(pss_params)); + + if (mdname == NULL || !OSSL_PARAM_set_utf8_string(p, mdname)) + return 0; + } + return (rsa_type != RSA_FLAG_TYPE_RSASSAPSS + || ossl_rsa_pss_params_30_todata(pss_params, NULL, params)) + && ossl_rsa_todata(rsa, NULL, params, 1); +} + +static const OSSL_PARAM rsa_params[] = { + OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, NULL, 0), + RSA_KEY_TYPES() + OSSL_PARAM_END +}; + +static const OSSL_PARAM *rsa_gettable_params(void *provctx) +{ + return rsa_params; +} + +static int rsa_validate(const void *keydata, int selection, int checktype) +{ + const RSA *rsa = keydata; + int ok = 1; + + if (!ossl_prov_is_running()) + return 0; + + if ((selection & RSA_POSSIBLE_SELECTIONS) == 0) + return 1; /* nothing to validate */ + + /* If the whole key is selected, we do a pairwise validation */ + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) + == OSSL_KEYMGMT_SELECT_KEYPAIR) { + ok = ok && ossl_rsa_validate_pairwise(rsa); + } else { + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && ossl_rsa_validate_private(rsa); + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && ossl_rsa_validate_public(rsa); + } + return ok; +} + +struct rsa_gen_ctx { + OSSL_LIB_CTX *libctx; + const char *propq; + + int rsa_type; + + size_t nbits; + BIGNUM *pub_exp; + size_t primes; + + /* For PSS */ + RSA_PSS_PARAMS_30 pss_params; + int pss_defaults_set; + + /* For generation callback */ + OSSL_CALLBACK *cb; + void *cbarg; + +#if defined(FIPS_MODULE) && !defined(OPENSSL_NO_ACVP_TESTS) + /* ACVP test parameters */ + OSSL_PARAM *acvp_test_params; +#endif +}; + +static int rsa_gencb(int p, int n, BN_GENCB *cb) +{ + struct rsa_gen_ctx *gctx = BN_GENCB_get_arg(cb); + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; + + params[0] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_POTENTIAL, &p); + params[1] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_ITERATION, &n); + return gctx->cb(params, gctx->cbarg); +} + +static void *gen_init(void *provctx, int selection, int rsa_type, + const OSSL_PARAM params[]) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx); + struct rsa_gen_ctx *gctx = NULL; + + if (!ossl_prov_is_running()) + return NULL; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return NULL; + + if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { + gctx->libctx = libctx; + if ((gctx->pub_exp = BN_new()) == NULL + || !BN_set_word(gctx->pub_exp, RSA_F4)) { + goto err; + } + gctx->nbits = 2048; + gctx->primes = RSA_DEFAULT_PRIME_NUM; + gctx->rsa_type = rsa_type; + } else { + goto err; + } + + if (!rsa_gen_set_params(gctx, params)) + goto err; + return gctx; + +err: + if (gctx != NULL) + BN_free(gctx->pub_exp); + OPENSSL_free(gctx); + return NULL; +} + +static void *rsa_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + return gen_init(provctx, selection, RSA_FLAG_TYPE_RSA, params); +} + +static void *rsapss_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + return gen_init(provctx, selection, RSA_FLAG_TYPE_RSASSAPSS, params); +} + +/* + * This function is common for all RSA sub-types, to detect possible + * misuse, such as PSS parameters being passed when a plain RSA key + * is generated. + */ +static int rsa_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + struct rsa_gen_ctx *gctx = genctx; + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_BITS)) != NULL) { + if (!OSSL_PARAM_get_size_t(p, &gctx->nbits)) + return 0; + if (gctx->nbits < RSA_MIN_MODULUS_BITS) { + ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL); + return 0; + } + } + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_PRIMES)) != NULL + && !OSSL_PARAM_get_size_t(p, &gctx->primes)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E)) != NULL + && !OSSL_PARAM_get_BN(p, &gctx->pub_exp)) + return 0; + /* Only attempt to get PSS parameters when generating an RSA-PSS key */ + if (gctx->rsa_type == RSA_FLAG_TYPE_RSASSAPSS + && !pss_params_fromdata(&gctx->pss_params, &gctx->pss_defaults_set, params, + gctx->rsa_type, gctx->libctx)) + return 0; +#if defined(FIPS_MODULE) && !defined(OPENSSL_NO_ACVP_TESTS) + /* Any ACVP test related parameters are copied into a params[] */ + if (!ossl_rsa_acvp_test_gen_params_new(&gctx->acvp_test_params, params)) + return 0; +#endif + return 1; +} + +#define rsa_gen_basic \ + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, NULL), \ + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_PRIMES, NULL), \ + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0) + +/* + * The following must be kept in sync with ossl_rsa_pss_params_30_fromdata() + * in crypto/rsa/rsa_backend.c + */ +#define rsa_gen_pss \ + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_RSA_DIGEST, NULL, 0), \ + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_RSA_DIGEST_PROPS, NULL, 0), \ + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_RSA_MASKGENFUNC, NULL, 0), \ + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_RSA_MGF1_DIGEST, NULL, 0), \ + OSSL_PARAM_int(OSSL_PKEY_PARAM_RSA_PSS_SALTLEN, NULL) + +static const OSSL_PARAM *rsa_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + static OSSL_PARAM settable[] = { + rsa_gen_basic, + OSSL_PARAM_END + }; + + return settable; +} + +static const OSSL_PARAM *rsapss_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + static OSSL_PARAM settable[] = { + rsa_gen_basic, + rsa_gen_pss, + OSSL_PARAM_END + }; + + return settable; +} + +static void *rsa_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct rsa_gen_ctx *gctx = genctx; + RSA *rsa = NULL, *rsa_tmp = NULL; + BN_GENCB *gencb = NULL; + + if (!ossl_prov_is_running() || gctx == NULL) + return NULL; + + switch (gctx->rsa_type) { + case RSA_FLAG_TYPE_RSA: + /* For plain RSA keys, PSS parameters must not be set */ + if (!ossl_rsa_pss_params_30_is_unrestricted(&gctx->pss_params)) + goto err; + break; + case RSA_FLAG_TYPE_RSASSAPSS: + /* + * For plain RSA-PSS keys, PSS parameters may be set but don't have + * to, so not check. + */ + break; + default: + /* Unsupported RSA key sub-type... */ + return NULL; + } + + if ((rsa_tmp = ossl_rsa_new_with_ctx(gctx->libctx)) == NULL) + return NULL; + + gctx->cb = osslcb; + gctx->cbarg = cbarg; + gencb = BN_GENCB_new(); + if (gencb != NULL) + BN_GENCB_set(gencb, rsa_gencb, genctx); + +#if defined(FIPS_MODULE) && !defined(OPENSSL_NO_ACVP_TESTS) + if (gctx->acvp_test_params != NULL) { + if (!ossl_rsa_acvp_test_set_params(rsa_tmp, gctx->acvp_test_params)) + goto err; + } +#endif + + if (!RSA_generate_multi_prime_key(rsa_tmp, + (int)gctx->nbits, (int)gctx->primes, + gctx->pub_exp, gencb)) + goto err; + + if (!ossl_rsa_pss_params_30_copy(ossl_rsa_get0_pss_params_30(rsa_tmp), + &gctx->pss_params)) + goto err; + + RSA_clear_flags(rsa_tmp, RSA_FLAG_TYPE_MASK); + RSA_set_flags(rsa_tmp, gctx->rsa_type); + + rsa = rsa_tmp; + rsa_tmp = NULL; + err: + BN_GENCB_free(gencb); + RSA_free(rsa_tmp); + return rsa; +} + +static void rsa_gen_cleanup(void *genctx) +{ + struct rsa_gen_ctx *gctx = genctx; + + if (gctx == NULL) + return; +#if defined(FIPS_MODULE) && !defined(OPENSSL_NO_ACVP_TESTS) + ossl_rsa_acvp_test_gen_params_free(gctx->acvp_test_params); + gctx->acvp_test_params = NULL; +#endif + BN_clear_free(gctx->pub_exp); + OPENSSL_free(gctx); +} + +static void *common_load(const void *reference, size_t reference_sz, + int expected_rsa_type) +{ + RSA *rsa = NULL; + + if (ossl_prov_is_running() && reference_sz == sizeof(rsa)) { + /* The contents of the reference is the address to our object */ + rsa = *(RSA **)reference; + + if (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK) != expected_rsa_type) + return NULL; + + /* We grabbed, so we detach it */ + *(RSA **)reference = NULL; + return rsa; + } + return NULL; +} + +static void *rsa_load(const void *reference, size_t reference_sz) +{ + return common_load(reference, reference_sz, RSA_FLAG_TYPE_RSA); +} + +static void *rsapss_load(const void *reference, size_t reference_sz) +{ + return common_load(reference, reference_sz, RSA_FLAG_TYPE_RSASSAPSS); +} + +static void *rsa_dup(const void *keydata_from, int selection) +{ + if (ossl_prov_is_running() + /* do not allow creating empty keys by duplication */ + && (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) + return ossl_rsa_dup(keydata_from, selection); + return NULL; +} + +/* For any RSA key, we use the "RSA" algorithms regardless of sub-type. */ +static const char *rsa_query_operation_name(int operation_id) +{ + return "RSA"; +} + +const OSSL_DISPATCH ossl_rsa_keymgmt_functions[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))rsa_newdata }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))rsa_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, + (void (*)(void))rsa_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))rsa_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))rsa_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))rsa_gen_cleanup }, + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))rsa_load }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))rsa_freedata }, + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))rsa_get_params }, + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))rsa_gettable_params }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))rsa_has }, + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))rsa_match }, + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))rsa_validate }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))rsa_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))rsa_import_types }, + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))rsa_export }, + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))rsa_export_types }, + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))rsa_dup }, + { 0, NULL } +}; + +const OSSL_DISPATCH ossl_rsapss_keymgmt_functions[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))rsapss_newdata }, + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))rsapss_gen_init }, + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))rsa_gen_set_params }, + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, + (void (*)(void))rsapss_gen_settable_params }, + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))rsa_gen }, + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))rsa_gen_cleanup }, + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))rsapss_load }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))rsa_freedata }, + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))rsa_get_params }, + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))rsa_gettable_params }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))rsa_has }, + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))rsa_match }, + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))rsa_validate }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))rsa_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))rsa_import_types }, + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))rsa_export }, + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))rsa_export_types }, + { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, + (void (*)(void))rsa_query_operation_name }, + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))rsa_dup }, + { 0, NULL } +}; diff --git a/providers/implementations/macs/blake2_mac_impl.c b/providers/implementations/macs/blake2_mac_impl.c new file mode 100644 index 000000000000..3c6b0c2c0c07 --- /dev/null +++ b/providers/implementations/macs/blake2_mac_impl.c @@ -0,0 +1,254 @@ +/* + * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/proverr.h> + +#include "prov/blake2.h" +#include "internal/cryptlib.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" + +/* + * Forward declaration of everything implemented here. This is not strictly + * necessary for the compiler, but provides an assurance that the signatures + * of the functions in the dispatch table are correct. + */ +static OSSL_FUNC_mac_newctx_fn blake2_mac_new; +static OSSL_FUNC_mac_dupctx_fn blake2_mac_dup; +static OSSL_FUNC_mac_freectx_fn blake2_mac_free; +static OSSL_FUNC_mac_gettable_ctx_params_fn blake2_gettable_ctx_params; +static OSSL_FUNC_mac_get_ctx_params_fn blake2_get_ctx_params; +static OSSL_FUNC_mac_settable_ctx_params_fn blake2_mac_settable_ctx_params; +static OSSL_FUNC_mac_set_ctx_params_fn blake2_mac_set_ctx_params; +static OSSL_FUNC_mac_init_fn blake2_mac_init; +static OSSL_FUNC_mac_update_fn blake2_mac_update; +static OSSL_FUNC_mac_final_fn blake2_mac_final; + +struct blake2_mac_data_st { + BLAKE2_CTX ctx; + BLAKE2_PARAM params; + unsigned char key[BLAKE2_KEYBYTES]; +}; + +static void *blake2_mac_new(void *unused_provctx) +{ + struct blake2_mac_data_st *macctx; + + if (!ossl_prov_is_running()) + return NULL; + + macctx = OPENSSL_zalloc(sizeof(*macctx)); + if (macctx != NULL) { + BLAKE2_PARAM_INIT(&macctx->params); + /* ctx initialization is deferred to BLAKE2b_Init() */ + } + return macctx; +} + +static void *blake2_mac_dup(void *vsrc) +{ + struct blake2_mac_data_st *dst; + struct blake2_mac_data_st *src = vsrc; + + if (!ossl_prov_is_running()) + return NULL; + + dst = OPENSSL_zalloc(sizeof(*dst)); + if (dst == NULL) + return NULL; + + *dst = *src; + return dst; +} + +static void blake2_mac_free(void *vmacctx) +{ + struct blake2_mac_data_st *macctx = vmacctx; + + if (macctx != NULL) { + OPENSSL_cleanse(macctx->key, sizeof(macctx->key)); + OPENSSL_free(macctx); + } +} + +static size_t blake2_mac_size(void *vmacctx) +{ + struct blake2_mac_data_st *macctx = vmacctx; + + return macctx->params.digest_length; +} + +static int blake2_setkey(struct blake2_mac_data_st *macctx, + const unsigned char *key, size_t keylen) +{ + if (keylen > BLAKE2_KEYBYTES || keylen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + memcpy(macctx->key, key, keylen); + /* Pad with zeroes at the end if required */ + if (keylen < BLAKE2_KEYBYTES) + memset(macctx->key + keylen, 0, BLAKE2_KEYBYTES - keylen); + BLAKE2_PARAM_SET_KEY_LENGTH(&macctx->params, (uint8_t)keylen); + return 1; +} + +static int blake2_mac_init(void *vmacctx, const unsigned char *key, + size_t keylen, const OSSL_PARAM params[]) +{ + struct blake2_mac_data_st *macctx = vmacctx; + + if (!ossl_prov_is_running() || !blake2_mac_set_ctx_params(macctx, params)) + return 0; + if (key != NULL) { + if (!blake2_setkey(macctx, key, keylen)) + return 0; + } else if (macctx->params.key_length == 0) { + /* Check key has been set */ + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } + return BLAKE2_INIT_KEY(&macctx->ctx, &macctx->params, macctx->key); +} + +static int blake2_mac_update(void *vmacctx, + const unsigned char *data, size_t datalen) +{ + struct blake2_mac_data_st *macctx = vmacctx; + + if (datalen == 0) + return 1; + + return BLAKE2_UPDATE(&macctx->ctx, data, datalen); +} + +static int blake2_mac_final(void *vmacctx, + unsigned char *out, size_t *outl, + size_t outsize) +{ + struct blake2_mac_data_st *macctx = vmacctx; + + if (!ossl_prov_is_running()) + return 0; + + *outl = blake2_mac_size(macctx); + return BLAKE2_FINAL(out, &macctx->ctx); +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_size_t(OSSL_MAC_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_END +}; +static const OSSL_PARAM *blake2_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int blake2_get_ctx_params(void *vmacctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE)) != NULL + && !OSSL_PARAM_set_size_t(p, blake2_mac_size(vmacctx))) + return 0; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_BLOCK_SIZE)) != NULL + && !OSSL_PARAM_set_size_t(p, BLAKE2_BLOCKBYTES)) + return 0; + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_CUSTOM, NULL, 0), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_SALT, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *blake2_mac_settable_ctx_params( + ossl_unused void *ctx, ossl_unused void *p_ctx) +{ + return known_settable_ctx_params; +} + +/* + * ALL parameters should be set before init(). + */ +static int blake2_mac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[]) +{ + struct blake2_mac_data_st *macctx = vmacctx; + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_SIZE)) != NULL) { + size_t size; + + if (!OSSL_PARAM_get_size_t(p, &size) + || size < 1 + || size > BLAKE2_OUTBYTES) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_XOF_OR_INVALID_LENGTH); + return 0; + } + BLAKE2_PARAM_SET_DIGEST_LENGTH(&macctx->params, (uint8_t)size); + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL + && !blake2_setkey(macctx, p->data, p->data_size)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_CUSTOM)) + != NULL) { + /* + * The OSSL_PARAM API doesn't provide direct pointer use, so we + * must handle the OSSL_PARAM structure ourselves here + */ + if (p->data_size > BLAKE2_PERSONALBYTES) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CUSTOM_LENGTH); + return 0; + } + BLAKE2_PARAM_SET_PERSONAL(&macctx->params, p->data, p->data_size); + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_SALT)) != NULL) { + /* + * The OSSL_PARAM API doesn't provide direct pointer use, so we + * must handle the OSSL_PARAM structure ourselves here as well + */ + if (p->data_size > BLAKE2_SALTBYTES) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH); + return 0; + } + BLAKE2_PARAM_SET_SALT(&macctx->params, p->data, p->data_size); + } + return 1; +} + +const OSSL_DISPATCH BLAKE2_FUNCTIONS[] = { + { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))blake2_mac_new }, + { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))blake2_mac_dup }, + { OSSL_FUNC_MAC_FREECTX, (void (*)(void))blake2_mac_free }, + { OSSL_FUNC_MAC_INIT, (void (*)(void))blake2_mac_init }, + { OSSL_FUNC_MAC_UPDATE, (void (*)(void))blake2_mac_update }, + { OSSL_FUNC_MAC_FINAL, (void (*)(void))blake2_mac_final }, + { OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, + (void (*)(void))blake2_gettable_ctx_params }, + { OSSL_FUNC_MAC_GET_CTX_PARAMS, (void (*)(void))blake2_get_ctx_params }, + { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, + (void (*)(void))blake2_mac_settable_ctx_params }, + { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))blake2_mac_set_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/macs/blake2b_mac.c b/providers/implementations/macs/blake2b_mac.c new file mode 100644 index 000000000000..b445cbd57875 --- /dev/null +++ b/providers/implementations/macs/blake2b_mac.c @@ -0,0 +1,33 @@ +/* + * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Constants */ +#define BLAKE2_CTX BLAKE2B_CTX +#define BLAKE2_PARAM BLAKE2B_PARAM +#define BLAKE2_KEYBYTES BLAKE2B_KEYBYTES +#define BLAKE2_OUTBYTES BLAKE2B_OUTBYTES +#define BLAKE2_PERSONALBYTES BLAKE2B_PERSONALBYTES +#define BLAKE2_SALTBYTES BLAKE2B_SALTBYTES +#define BLAKE2_BLOCKBYTES BLAKE2B_BLOCKBYTES + +/* Function names */ +#define BLAKE2_PARAM_INIT ossl_blake2b_param_init +#define BLAKE2_INIT_KEY ossl_blake2b_init_key +#define BLAKE2_UPDATE ossl_blake2b_update +#define BLAKE2_FINAL ossl_blake2b_final +#define BLAKE2_PARAM_SET_DIGEST_LENGTH ossl_blake2b_param_set_digest_length +#define BLAKE2_PARAM_SET_KEY_LENGTH ossl_blake2b_param_set_key_length +#define BLAKE2_PARAM_SET_PERSONAL ossl_blake2b_param_set_personal +#define BLAKE2_PARAM_SET_SALT ossl_blake2b_param_set_salt + +/* OSSL_DISPATCH symbol */ +#define BLAKE2_FUNCTIONS ossl_blake2bmac_functions + +#include "blake2_mac_impl.c" + diff --git a/providers/implementations/macs/blake2s_mac.c b/providers/implementations/macs/blake2s_mac.c new file mode 100644 index 000000000000..6b3fa28bd36b --- /dev/null +++ b/providers/implementations/macs/blake2s_mac.c @@ -0,0 +1,32 @@ +/* + * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Constants */ +#define BLAKE2_CTX BLAKE2S_CTX +#define BLAKE2_PARAM BLAKE2S_PARAM +#define BLAKE2_KEYBYTES BLAKE2S_KEYBYTES +#define BLAKE2_OUTBYTES BLAKE2S_OUTBYTES +#define BLAKE2_PERSONALBYTES BLAKE2S_PERSONALBYTES +#define BLAKE2_SALTBYTES BLAKE2S_SALTBYTES +#define BLAKE2_BLOCKBYTES BLAKE2S_BLOCKBYTES + +/* Function names */ +#define BLAKE2_PARAM_INIT ossl_blake2s_param_init +#define BLAKE2_INIT_KEY ossl_blake2s_init_key +#define BLAKE2_UPDATE ossl_blake2s_update +#define BLAKE2_FINAL ossl_blake2s_final +#define BLAKE2_PARAM_SET_DIGEST_LENGTH ossl_blake2s_param_set_digest_length +#define BLAKE2_PARAM_SET_KEY_LENGTH ossl_blake2s_param_set_key_length +#define BLAKE2_PARAM_SET_PERSONAL ossl_blake2s_param_set_personal +#define BLAKE2_PARAM_SET_SALT ossl_blake2s_param_set_salt + +/* OSSL_DISPATCH symbol */ +#define BLAKE2_FUNCTIONS ossl_blake2smac_functions + +#include "blake2_mac_impl.c" diff --git a/providers/implementations/macs/build.info b/providers/implementations/macs/build.info new file mode 100644 index 000000000000..35db66bf23bd --- /dev/null +++ b/providers/implementations/macs/build.info @@ -0,0 +1,30 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$GMAC_GOAL=../../libdefault.a ../../libfips.a +$HMAC_GOAL=../../libdefault.a ../../libfips.a +$KMAC_GOAL=../../libdefault.a ../../libfips.a +$CMAC_GOAL=../../libdefault.a ../../libfips.a +$BLAKE2_GOAL=../../libdefault.a +$SIPHASH_GOAL=../../libdefault.a +$POLY1305_GOAL=../../libdefault.a + +SOURCE[$GMAC_GOAL]=gmac_prov.c +SOURCE[$HMAC_GOAL]=hmac_prov.c +SOURCE[$KMAC_GOAL]=kmac_prov.c + +IF[{- !$disabled{cmac} -}] + SOURCE[$CMAC_GOAL]=cmac_prov.c +ENDIF + +IF[{- !$disabled{blake2} -}] + SOURCE[$BLAKE2_GOAL]=blake2b_mac.c blake2s_mac.c +ENDIF + +IF[{- !$disabled{siphash} -}] + SOURCE[$SIPHASH_GOAL]=siphash_prov.c +ENDIF + +IF[{- !$disabled{poly1305} -}] + SOURCE[$POLY1305_GOAL]=poly1305_prov.c +ENDIF diff --git a/providers/implementations/macs/cmac_prov.c b/providers/implementations/macs/cmac_prov.c new file mode 100644 index 000000000000..96da429e844a --- /dev/null +++ b/providers/implementations/macs/cmac_prov.c @@ -0,0 +1,223 @@ +/* + * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * CMAC low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/cmac.h> + +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/provider_util.h" +#include "prov/providercommon.h" + +/* + * Forward declaration of everything implemented here. This is not strictly + * necessary for the compiler, but provides an assurance that the signatures + * of the functions in the dispatch table are correct. + */ +static OSSL_FUNC_mac_newctx_fn cmac_new; +static OSSL_FUNC_mac_dupctx_fn cmac_dup; +static OSSL_FUNC_mac_freectx_fn cmac_free; +static OSSL_FUNC_mac_gettable_ctx_params_fn cmac_gettable_ctx_params; +static OSSL_FUNC_mac_get_ctx_params_fn cmac_get_ctx_params; +static OSSL_FUNC_mac_settable_ctx_params_fn cmac_settable_ctx_params; +static OSSL_FUNC_mac_set_ctx_params_fn cmac_set_ctx_params; +static OSSL_FUNC_mac_init_fn cmac_init; +static OSSL_FUNC_mac_update_fn cmac_update; +static OSSL_FUNC_mac_final_fn cmac_final; + +/* local CMAC data */ + +struct cmac_data_st { + void *provctx; + CMAC_CTX *ctx; + PROV_CIPHER cipher; +}; + +static void *cmac_new(void *provctx) +{ + struct cmac_data_st *macctx; + + if (!ossl_prov_is_running()) + return NULL; + + if ((macctx = OPENSSL_zalloc(sizeof(*macctx))) == NULL + || (macctx->ctx = CMAC_CTX_new()) == NULL) { + OPENSSL_free(macctx); + macctx = NULL; + } else { + macctx->provctx = provctx; + } + + return macctx; +} + +static void cmac_free(void *vmacctx) +{ + struct cmac_data_st *macctx = vmacctx; + + if (macctx != NULL) { + CMAC_CTX_free(macctx->ctx); + ossl_prov_cipher_reset(&macctx->cipher); + OPENSSL_free(macctx); + } +} + +static void *cmac_dup(void *vsrc) +{ + struct cmac_data_st *src = vsrc; + struct cmac_data_st *dst; + + if (!ossl_prov_is_running()) + return NULL; + + dst = cmac_new(src->provctx); + if (dst == NULL) + return NULL; + if (!CMAC_CTX_copy(dst->ctx, src->ctx) + || !ossl_prov_cipher_copy(&dst->cipher, &src->cipher)) { + cmac_free(dst); + return NULL; + } + return dst; +} + +static size_t cmac_size(void *vmacctx) +{ + struct cmac_data_st *macctx = vmacctx; + + return EVP_CIPHER_CTX_get_block_size(CMAC_CTX_get0_cipher_ctx(macctx->ctx)); +} + +static int cmac_setkey(struct cmac_data_st *macctx, + const unsigned char *key, size_t keylen) +{ + int rv = CMAC_Init(macctx->ctx, key, keylen, + ossl_prov_cipher_cipher(&macctx->cipher), + ossl_prov_cipher_engine(&macctx->cipher)); + ossl_prov_cipher_reset(&macctx->cipher); + return rv; +} + +static int cmac_init(void *vmacctx, const unsigned char *key, + size_t keylen, const OSSL_PARAM params[]) +{ + struct cmac_data_st *macctx = vmacctx; + + if (!ossl_prov_is_running() || !cmac_set_ctx_params(macctx, params)) + return 0; + if (key != NULL) + return cmac_setkey(macctx, key, keylen); + /* Reinitialize the CMAC context */ + return CMAC_Init(macctx->ctx, NULL, 0, NULL, NULL); +} + +static int cmac_update(void *vmacctx, const unsigned char *data, + size_t datalen) +{ + struct cmac_data_st *macctx = vmacctx; + + return CMAC_Update(macctx->ctx, data, datalen); +} + +static int cmac_final(void *vmacctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + struct cmac_data_st *macctx = vmacctx; + + if (!ossl_prov_is_running()) + return 0; + + return CMAC_Final(macctx->ctx, out, outl); +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_size_t(OSSL_MAC_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_END +}; +static const OSSL_PARAM *cmac_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int cmac_get_ctx_params(void *vmacctx, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE)) != NULL + && !OSSL_PARAM_set_size_t(p, cmac_size(vmacctx))) + return 0; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_BLOCK_SIZE)) != NULL + && !OSSL_PARAM_set_size_t(p, cmac_size(vmacctx))) + return 0; + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *cmac_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +/* + * ALL parameters should be set before init(). + */ +static int cmac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[]) +{ + struct cmac_data_st *macctx = vmacctx; + OSSL_LIB_CTX *ctx = PROV_LIBCTX_OF(macctx->provctx); + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + if (!ossl_prov_cipher_load_from_params(&macctx->cipher, params, ctx)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) + return 0; + return cmac_setkey(macctx, p->data, p->data_size); + } + return 1; +} + +const OSSL_DISPATCH ossl_cmac_functions[] = { + { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))cmac_new }, + { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))cmac_dup }, + { OSSL_FUNC_MAC_FREECTX, (void (*)(void))cmac_free }, + { OSSL_FUNC_MAC_INIT, (void (*)(void))cmac_init }, + { OSSL_FUNC_MAC_UPDATE, (void (*)(void))cmac_update }, + { OSSL_FUNC_MAC_FINAL, (void (*)(void))cmac_final }, + { OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, + (void (*)(void))cmac_gettable_ctx_params }, + { OSSL_FUNC_MAC_GET_CTX_PARAMS, (void (*)(void))cmac_get_ctx_params }, + { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, + (void (*)(void))cmac_settable_ctx_params }, + { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))cmac_set_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/macs/gmac_prov.c b/providers/implementations/macs/gmac_prov.c new file mode 100644 index 000000000000..3dd38ecd7ca7 --- /dev/null +++ b/providers/implementations/macs/gmac_prov.c @@ -0,0 +1,259 @@ +/* + * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/proverr.h> + +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/provider_util.h" +#include "prov/providercommon.h" + +/* + * Forward declaration of everything implemented here. This is not strictly + * necessary for the compiler, but provides an assurance that the signatures + * of the functions in the dispatch table are correct. + */ +static OSSL_FUNC_mac_newctx_fn gmac_new; +static OSSL_FUNC_mac_dupctx_fn gmac_dup; +static OSSL_FUNC_mac_freectx_fn gmac_free; +static OSSL_FUNC_mac_gettable_params_fn gmac_gettable_params; +static OSSL_FUNC_mac_get_params_fn gmac_get_params; +static OSSL_FUNC_mac_settable_ctx_params_fn gmac_settable_ctx_params; +static OSSL_FUNC_mac_set_ctx_params_fn gmac_set_ctx_params; +static OSSL_FUNC_mac_init_fn gmac_init; +static OSSL_FUNC_mac_update_fn gmac_update; +static OSSL_FUNC_mac_final_fn gmac_final; + +/* local GMAC pkey structure */ + +struct gmac_data_st { + void *provctx; + EVP_CIPHER_CTX *ctx; /* Cipher context */ + PROV_CIPHER cipher; +}; + +static void gmac_free(void *vmacctx) +{ + struct gmac_data_st *macctx = vmacctx; + + if (macctx != NULL) { + EVP_CIPHER_CTX_free(macctx->ctx); + ossl_prov_cipher_reset(&macctx->cipher); + OPENSSL_free(macctx); + } +} + +static void *gmac_new(void *provctx) +{ + struct gmac_data_st *macctx; + + if (!ossl_prov_is_running()) + return NULL; + + if ((macctx = OPENSSL_zalloc(sizeof(*macctx))) == NULL + || (macctx->ctx = EVP_CIPHER_CTX_new()) == NULL) { + gmac_free(macctx); + return NULL; + } + macctx->provctx = provctx; + + return macctx; +} + +static void *gmac_dup(void *vsrc) +{ + struct gmac_data_st *src = vsrc; + struct gmac_data_st *dst; + + if (!ossl_prov_is_running()) + return NULL; + + dst = gmac_new(src->provctx); + if (dst == NULL) + return NULL; + + if (!EVP_CIPHER_CTX_copy(dst->ctx, src->ctx) + || !ossl_prov_cipher_copy(&dst->cipher, &src->cipher)) { + gmac_free(dst); + return NULL; + } + return dst; +} + +static size_t gmac_size(void) +{ + return EVP_GCM_TLS_TAG_LEN; +} + +static int gmac_setkey(struct gmac_data_st *macctx, + const unsigned char *key, size_t keylen) +{ + EVP_CIPHER_CTX *ctx = macctx->ctx; + + if (keylen != (size_t)EVP_CIPHER_CTX_get_key_length(ctx)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + if (!EVP_EncryptInit_ex(ctx, NULL, NULL, key, NULL)) + return 0; + return 1; +} + +static int gmac_init(void *vmacctx, const unsigned char *key, + size_t keylen, const OSSL_PARAM params[]) +{ + struct gmac_data_st *macctx = vmacctx; + + if (!ossl_prov_is_running() || !gmac_set_ctx_params(macctx, params)) + return 0; + if (key != NULL) + return gmac_setkey(macctx, key, keylen); + return EVP_EncryptInit_ex(macctx->ctx, NULL, NULL, NULL, NULL); +} + +static int gmac_update(void *vmacctx, const unsigned char *data, + size_t datalen) +{ + struct gmac_data_st *macctx = vmacctx; + EVP_CIPHER_CTX *ctx = macctx->ctx; + int outlen; + + if (datalen == 0) + return 1; + + while (datalen > INT_MAX) { + if (!EVP_EncryptUpdate(ctx, NULL, &outlen, data, INT_MAX)) + return 0; + data += INT_MAX; + datalen -= INT_MAX; + } + return EVP_EncryptUpdate(ctx, NULL, &outlen, data, datalen); +} + +static int gmac_final(void *vmacctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + struct gmac_data_st *macctx = vmacctx; + int hlen = 0; + + if (!ossl_prov_is_running()) + return 0; + + if (!EVP_EncryptFinal_ex(macctx->ctx, out, &hlen)) + return 0; + + hlen = gmac_size(); + params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, + out, (size_t)hlen); + if (!EVP_CIPHER_CTX_get_params(macctx->ctx, params)) + return 0; + + *outl = hlen; + return 1; +} + +static const OSSL_PARAM known_gettable_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_END +}; +static const OSSL_PARAM *gmac_gettable_params(void *provctx) +{ + return known_gettable_params; +} + +static int gmac_get_params(OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, gmac_size()); + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_IV, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *gmac_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +/* + * ALL parameters should be set before init(). + */ +static int gmac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[]) +{ + struct gmac_data_st *macctx = vmacctx; + EVP_CIPHER_CTX *ctx = macctx->ctx; + OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(macctx->provctx); + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + if (ctx == NULL) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_CIPHER)) != NULL) { + if (!ossl_prov_cipher_load_from_params(&macctx->cipher, params, provctx)) + return 0; + if (EVP_CIPHER_get_mode(ossl_prov_cipher_cipher(&macctx->cipher)) + != EVP_CIPH_GCM_MODE) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return 0; + } + if (!EVP_EncryptInit_ex(ctx, ossl_prov_cipher_cipher(&macctx->cipher), + ossl_prov_cipher_engine(&macctx->cipher), NULL, + NULL)) + return 0; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL) + if (p->data_type != OSSL_PARAM_OCTET_STRING + || !gmac_setkey(macctx, p->data, p->data_size)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_IV)) != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) + return 0; + + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, + p->data_size, NULL) <= 0 + || !EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, p->data)) + return 0; + } + return 1; +} + +const OSSL_DISPATCH ossl_gmac_functions[] = { + { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))gmac_new }, + { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))gmac_dup }, + { OSSL_FUNC_MAC_FREECTX, (void (*)(void))gmac_free }, + { OSSL_FUNC_MAC_INIT, (void (*)(void))gmac_init }, + { OSSL_FUNC_MAC_UPDATE, (void (*)(void))gmac_update }, + { OSSL_FUNC_MAC_FINAL, (void (*)(void))gmac_final }, + { OSSL_FUNC_MAC_GETTABLE_PARAMS, (void (*)(void))gmac_gettable_params }, + { OSSL_FUNC_MAC_GET_PARAMS, (void (*)(void))gmac_get_params }, + { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, + (void (*)(void))gmac_settable_ctx_params }, + { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))gmac_set_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/macs/hmac_prov.c b/providers/implementations/macs/hmac_prov.c new file mode 100644 index 000000000000..52ebb08b8f62 --- /dev/null +++ b/providers/implementations/macs/hmac_prov.c @@ -0,0 +1,357 @@ +/* + * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * HMAC low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + +#include <string.h> + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> + +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/provider_util.h" +#include "prov/providercommon.h" + +/* + * Forward declaration of everything implemented here. This is not strictly + * necessary for the compiler, but provides an assurance that the signatures + * of the functions in the dispatch table are correct. + */ +static OSSL_FUNC_mac_newctx_fn hmac_new; +static OSSL_FUNC_mac_dupctx_fn hmac_dup; +static OSSL_FUNC_mac_freectx_fn hmac_free; +static OSSL_FUNC_mac_gettable_ctx_params_fn hmac_gettable_ctx_params; +static OSSL_FUNC_mac_get_ctx_params_fn hmac_get_ctx_params; +static OSSL_FUNC_mac_settable_ctx_params_fn hmac_settable_ctx_params; +static OSSL_FUNC_mac_set_ctx_params_fn hmac_set_ctx_params; +static OSSL_FUNC_mac_init_fn hmac_init; +static OSSL_FUNC_mac_update_fn hmac_update; +static OSSL_FUNC_mac_final_fn hmac_final; + +/* local HMAC context structure */ + +/* typedef EVP_MAC_IMPL */ +struct hmac_data_st { + void *provctx; + HMAC_CTX *ctx; /* HMAC context */ + PROV_DIGEST digest; + unsigned char *key; + size_t keylen; + /* Length of full TLS record including the MAC and any padding */ + size_t tls_data_size; + unsigned char tls_header[13]; + int tls_header_set; + unsigned char tls_mac_out[EVP_MAX_MD_SIZE]; + size_t tls_mac_out_size; +}; + +/* Defined in ssl/s3_cbc.c */ +int ssl3_cbc_digest_record(const EVP_MD *md, + unsigned char *md_out, + size_t *md_out_size, + const unsigned char header[13], + const unsigned char *data, + size_t data_size, + size_t data_plus_mac_plus_padding_size, + const unsigned char *mac_secret, + size_t mac_secret_length, char is_sslv3); + +static void *hmac_new(void *provctx) +{ + struct hmac_data_st *macctx; + + if (!ossl_prov_is_running()) + return NULL; + + if ((macctx = OPENSSL_zalloc(sizeof(*macctx))) == NULL + || (macctx->ctx = HMAC_CTX_new()) == NULL) { + OPENSSL_free(macctx); + return NULL; + } + macctx->provctx = provctx; + + return macctx; +} + +static void hmac_free(void *vmacctx) +{ + struct hmac_data_st *macctx = vmacctx; + + if (macctx != NULL) { + HMAC_CTX_free(macctx->ctx); + ossl_prov_digest_reset(&macctx->digest); + OPENSSL_secure_clear_free(macctx->key, macctx->keylen); + OPENSSL_free(macctx); + } +} + +static void *hmac_dup(void *vsrc) +{ + struct hmac_data_st *src = vsrc; + struct hmac_data_st *dst; + HMAC_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + dst = hmac_new(src->provctx); + if (dst == NULL) + return NULL; + + ctx = dst->ctx; + *dst = *src; + dst->ctx = ctx; + dst->key = NULL; + memset(&dst->digest, 0, sizeof(dst->digest)); + + if (!HMAC_CTX_copy(dst->ctx, src->ctx) + || !ossl_prov_digest_copy(&dst->digest, &src->digest)) { + hmac_free(dst); + return NULL; + } + if (src->key != NULL) { + /* There is no "secure" OPENSSL_memdup */ + dst->key = OPENSSL_secure_malloc(src->keylen > 0 ? src->keylen : 1); + if (dst->key == NULL) { + hmac_free(dst); + return 0; + } + memcpy(dst->key, src->key, src->keylen); + } + return dst; +} + +static size_t hmac_size(struct hmac_data_st *macctx) +{ + return HMAC_size(macctx->ctx); +} + +static int hmac_block_size(struct hmac_data_st *macctx) +{ + const EVP_MD *md = ossl_prov_digest_md(&macctx->digest); + + if (md == NULL) + return 0; + return EVP_MD_block_size(md); +} + +static int hmac_setkey(struct hmac_data_st *macctx, + const unsigned char *key, size_t keylen) +{ + const EVP_MD *digest; + + if (macctx->key != NULL) + OPENSSL_secure_clear_free(macctx->key, macctx->keylen); + /* Keep a copy of the key in case we need it for TLS HMAC */ + macctx->key = OPENSSL_secure_malloc(keylen > 0 ? keylen : 1); + if (macctx->key == NULL) + return 0; + memcpy(macctx->key, key, keylen); + macctx->keylen = keylen; + + digest = ossl_prov_digest_md(&macctx->digest); + /* HMAC_Init_ex doesn't tolerate all zero params, so we must be careful */ + if (key != NULL || (macctx->tls_data_size == 0 && digest != NULL)) + return HMAC_Init_ex(macctx->ctx, key, keylen, digest, + ossl_prov_digest_engine(&macctx->digest)); + return 1; +} + +static int hmac_init(void *vmacctx, const unsigned char *key, + size_t keylen, const OSSL_PARAM params[]) +{ + struct hmac_data_st *macctx = vmacctx; + + if (!ossl_prov_is_running() || !hmac_set_ctx_params(macctx, params)) + return 0; + + if (key != NULL) + return hmac_setkey(macctx, key, keylen); + + /* Just reinit the HMAC context */ + return HMAC_Init_ex(macctx->ctx, NULL, 0, NULL, NULL); +} + +static int hmac_update(void *vmacctx, const unsigned char *data, + size_t datalen) +{ + struct hmac_data_st *macctx = vmacctx; + + if (macctx->tls_data_size > 0) { + /* We're doing a TLS HMAC */ + if (!macctx->tls_header_set) { + /* We expect the first update call to contain the TLS header */ + if (datalen != sizeof(macctx->tls_header)) + return 0; + memcpy(macctx->tls_header, data, datalen); + macctx->tls_header_set = 1; + return 1; + } + /* macctx->tls_data_size is datalen plus the padding length */ + if (macctx->tls_data_size < datalen) + return 0; + + return ssl3_cbc_digest_record(ossl_prov_digest_md(&macctx->digest), + macctx->tls_mac_out, + &macctx->tls_mac_out_size, + macctx->tls_header, + data, + datalen, + macctx->tls_data_size, + macctx->key, + macctx->keylen, + 0); + } + + return HMAC_Update(macctx->ctx, data, datalen); +} + +static int hmac_final(void *vmacctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + unsigned int hlen; + struct hmac_data_st *macctx = vmacctx; + + if (!ossl_prov_is_running()) + return 0; + if (macctx->tls_data_size > 0) { + if (macctx->tls_mac_out_size == 0) + return 0; + if (outl != NULL) + *outl = macctx->tls_mac_out_size; + memcpy(out, macctx->tls_mac_out, macctx->tls_mac_out_size); + return 1; + } + if (!HMAC_Final(macctx->ctx, out, &hlen)) + return 0; + *outl = hlen; + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_size_t(OSSL_MAC_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_END +}; +static const OSSL_PARAM *hmac_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int hmac_get_ctx_params(void *vmacctx, OSSL_PARAM params[]) +{ + struct hmac_data_st *macctx = vmacctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE)) != NULL + && !OSSL_PARAM_set_size_t(p, hmac_size(macctx))) + return 0; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_BLOCK_SIZE)) != NULL + && !OSSL_PARAM_set_int(p, hmac_block_size(macctx))) + return 0; + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0), + OSSL_PARAM_int(OSSL_MAC_PARAM_DIGEST_NOINIT, NULL), + OSSL_PARAM_int(OSSL_MAC_PARAM_DIGEST_ONESHOT, NULL), + OSSL_PARAM_size_t(OSSL_MAC_PARAM_TLS_DATA_SIZE, NULL), + OSSL_PARAM_END +}; +static const OSSL_PARAM *hmac_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +static int set_flag(const OSSL_PARAM params[], const char *key, int mask, + int *flags) +{ + const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, key); + int flag = 0; + + if (p != NULL) { + if (!OSSL_PARAM_get_int(p, &flag)) + return 0; + if (flag == 0) + *flags &= ~mask; + else + *flags |= mask; + } + return 1; +} + +/* + * ALL parameters should be set before init(). + */ +static int hmac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[]) +{ + struct hmac_data_st *macctx = vmacctx; + OSSL_LIB_CTX *ctx = PROV_LIBCTX_OF(macctx->provctx); + const OSSL_PARAM *p; + int flags = 0; + + if (params == NULL) + return 1; + + if (!ossl_prov_digest_load_from_params(&macctx->digest, params, ctx)) + return 0; + + if (!set_flag(params, OSSL_MAC_PARAM_DIGEST_NOINIT, EVP_MD_CTX_FLAG_NO_INIT, + &flags)) + return 0; + if (!set_flag(params, OSSL_MAC_PARAM_DIGEST_ONESHOT, EVP_MD_CTX_FLAG_ONESHOT, + &flags)) + return 0; + if (flags) + HMAC_CTX_set_flags(macctx->ctx, flags); + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) + return 0; + if (!hmac_setkey(macctx, p->data, p->data_size)) + return 0; + } + + if ((p = OSSL_PARAM_locate_const(params, + OSSL_MAC_PARAM_TLS_DATA_SIZE)) != NULL) { + if (!OSSL_PARAM_get_size_t(p, &macctx->tls_data_size)) + return 0; + } + return 1; +} + +const OSSL_DISPATCH ossl_hmac_functions[] = { + { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))hmac_new }, + { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))hmac_dup }, + { OSSL_FUNC_MAC_FREECTX, (void (*)(void))hmac_free }, + { OSSL_FUNC_MAC_INIT, (void (*)(void))hmac_init }, + { OSSL_FUNC_MAC_UPDATE, (void (*)(void))hmac_update }, + { OSSL_FUNC_MAC_FINAL, (void (*)(void))hmac_final }, + { OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, + (void (*)(void))hmac_gettable_ctx_params }, + { OSSL_FUNC_MAC_GET_CTX_PARAMS, (void (*)(void))hmac_get_ctx_params }, + { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, + (void (*)(void))hmac_settable_ctx_params }, + { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))hmac_set_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/macs/kmac_prov.c b/providers/implementations/macs/kmac_prov.c new file mode 100644 index 000000000000..b2f85398b4e2 --- /dev/null +++ b/providers/implementations/macs/kmac_prov.c @@ -0,0 +1,627 @@ +/* + * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * See SP800-185 "Appendix A - KMAC, .... in Terms of Keccak[c]" + * + * Inputs are: + * K = Key (len(K) < 2^2040 bits) + * X = Input + * L = Output length (0 <= L < 2^2040 bits) + * S = Customization String Default="" (len(S) < 2^2040 bits) + * + * KMAC128(K, X, L, S) + * { + * newX = bytepad(encode_string(K), 168) || X || right_encode(L). + * T = bytepad(encode_string("KMAC") || encode_string(S), 168). + * return KECCAK[256](T || newX || 00, L). + * } + * + * KMAC256(K, X, L, S) + * { + * newX = bytepad(encode_string(K), 136) || X || right_encode(L). + * T = bytepad(encode_string("KMAC") || encode_string(S), 136). + * return KECCAK[512](T || newX || 00, L). + * } + * + * KMAC128XOF(K, X, L, S) + * { + * newX = bytepad(encode_string(K), 168) || X || right_encode(0). + * T = bytepad(encode_string("KMAC") || encode_string(S), 168). + * return KECCAK[256](T || newX || 00, L). + * } + * + * KMAC256XOF(K, X, L, S) + * { + * newX = bytepad(encode_string(K), 136) || X || right_encode(0). + * T = bytepad(encode_string("KMAC") || encode_string(S), 136). + * return KECCAK[512](T || newX || 00, L). + * } + * + */ + +#include <stdlib.h> +#include <string.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/proverr.h> + +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/provider_util.h" +#include "prov/providercommon.h" +#include "internal/cryptlib.h" /* ossl_assert */ + +/* + * Forward declaration of everything implemented here. This is not strictly + * necessary for the compiler, but provides an assurance that the signatures + * of the functions in the dispatch table are correct. + */ +static OSSL_FUNC_mac_newctx_fn kmac128_new; +static OSSL_FUNC_mac_newctx_fn kmac256_new; +static OSSL_FUNC_mac_dupctx_fn kmac_dup; +static OSSL_FUNC_mac_freectx_fn kmac_free; +static OSSL_FUNC_mac_gettable_ctx_params_fn kmac_gettable_ctx_params; +static OSSL_FUNC_mac_get_ctx_params_fn kmac_get_ctx_params; +static OSSL_FUNC_mac_settable_ctx_params_fn kmac_settable_ctx_params; +static OSSL_FUNC_mac_set_ctx_params_fn kmac_set_ctx_params; +static OSSL_FUNC_mac_init_fn kmac_init; +static OSSL_FUNC_mac_update_fn kmac_update; +static OSSL_FUNC_mac_final_fn kmac_final; + +#define KMAC_MAX_BLOCKSIZE ((1600 - 128 * 2) / 8) /* 168 */ + +/* + * Length encoding will be a 1 byte size + length in bits (3 bytes max) + * This gives a range of 0..0XFFFFFF bits = 2097151 bytes). + */ +#define KMAC_MAX_OUTPUT_LEN (0xFFFFFF / 8) +#define KMAC_MAX_ENCODED_HEADER_LEN (1 + 3) + +/* + * Restrict the maximum length of the customisation string. This must not + * exceed 64 bits = 8k bytes. + */ +#define KMAC_MAX_CUSTOM 512 + +/* Maximum size of encoded custom string */ +#define KMAC_MAX_CUSTOM_ENCODED (KMAC_MAX_CUSTOM + KMAC_MAX_ENCODED_HEADER_LEN) + +/* Maximum key size in bytes = 512 (4096 bits) */ +#define KMAC_MAX_KEY 512 +#define KMAC_MIN_KEY 4 + +/* + * Maximum Encoded Key size will be padded to a multiple of the blocksize + * i.e KMAC_MAX_KEY + KMAC_MAX_ENCODED_HEADER_LEN = 512 + 4 + * Padded to a multiple of KMAC_MAX_BLOCKSIZE + */ +#define KMAC_MAX_KEY_ENCODED (KMAC_MAX_BLOCKSIZE * 4) + +/* Fixed value of encode_string("KMAC") */ +static const unsigned char kmac_string[] = { + 0x01, 0x20, 0x4B, 0x4D, 0x41, 0x43 +}; + +#define KMAC_FLAG_XOF_MODE 1 + +struct kmac_data_st { + void *provctx; + EVP_MD_CTX *ctx; + PROV_DIGEST digest; + size_t out_len; + size_t key_len; + size_t custom_len; + /* If xof_mode = 1 then we use right_encode(0) */ + int xof_mode; + /* key and custom are stored in encoded form */ + unsigned char key[KMAC_MAX_KEY_ENCODED]; + unsigned char custom[KMAC_MAX_CUSTOM_ENCODED]; +}; + +static int encode_string(unsigned char *out, size_t out_max_len, size_t *out_len, + const unsigned char *in, size_t in_len); +static int right_encode(unsigned char *out, size_t out_max_len, size_t *out_len, + size_t bits); +static int bytepad(unsigned char *out, size_t *out_len, + const unsigned char *in1, size_t in1_len, + const unsigned char *in2, size_t in2_len, + size_t w); +static int kmac_bytepad_encode_key(unsigned char *out, size_t out_max_len, + size_t *out_len, + const unsigned char *in, size_t in_len, + size_t w); + +static void kmac_free(void *vmacctx) +{ + struct kmac_data_st *kctx = vmacctx; + + if (kctx != NULL) { + EVP_MD_CTX_free(kctx->ctx); + ossl_prov_digest_reset(&kctx->digest); + OPENSSL_cleanse(kctx->key, kctx->key_len); + OPENSSL_cleanse(kctx->custom, kctx->custom_len); + OPENSSL_free(kctx); + } +} + +/* + * We have KMAC implemented as a hash, which we can use instead of + * reimplementing the EVP functionality with direct use of + * keccak_mac_init() and friends. + */ +static struct kmac_data_st *kmac_new(void *provctx) +{ + struct kmac_data_st *kctx; + + if (!ossl_prov_is_running()) + return NULL; + + if ((kctx = OPENSSL_zalloc(sizeof(*kctx))) == NULL + || (kctx->ctx = EVP_MD_CTX_new()) == NULL) { + kmac_free(kctx); + return NULL; + } + kctx->provctx = provctx; + return kctx; +} + +static void *kmac_fetch_new(void *provctx, const OSSL_PARAM *params) +{ + struct kmac_data_st *kctx = kmac_new(provctx); + + if (kctx == NULL) + return 0; + if (!ossl_prov_digest_load_from_params(&kctx->digest, params, + PROV_LIBCTX_OF(provctx))) { + kmac_free(kctx); + return 0; + } + + kctx->out_len = EVP_MD_get_size(ossl_prov_digest_md(&kctx->digest)); + return kctx; +} + +static void *kmac128_new(void *provctx) +{ + static const OSSL_PARAM kmac128_params[] = { + OSSL_PARAM_utf8_string("digest", OSSL_DIGEST_NAME_KECCAK_KMAC128, + sizeof(OSSL_DIGEST_NAME_KECCAK_KMAC128)), + OSSL_PARAM_END + }; + return kmac_fetch_new(provctx, kmac128_params); +} + +static void *kmac256_new(void *provctx) +{ + static const OSSL_PARAM kmac256_params[] = { + OSSL_PARAM_utf8_string("digest", OSSL_DIGEST_NAME_KECCAK_KMAC256, + sizeof(OSSL_DIGEST_NAME_KECCAK_KMAC256)), + OSSL_PARAM_END + }; + return kmac_fetch_new(provctx, kmac256_params); +} + +static void *kmac_dup(void *vsrc) +{ + struct kmac_data_st *src = vsrc; + struct kmac_data_st *dst; + + if (!ossl_prov_is_running()) + return NULL; + + dst = kmac_new(src->provctx); + if (dst == NULL) + return NULL; + + if (!EVP_MD_CTX_copy(dst->ctx, src->ctx) + || !ossl_prov_digest_copy(&dst->digest, &src->digest)) { + kmac_free(dst); + return NULL; + } + + dst->out_len = src->out_len; + dst->key_len = src->key_len; + dst->custom_len = src->custom_len; + dst->xof_mode = src->xof_mode; + memcpy(dst->key, src->key, src->key_len); + memcpy(dst->custom, src->custom, dst->custom_len); + + return dst; +} + +static int kmac_setkey(struct kmac_data_st *kctx, const unsigned char *key, + size_t keylen) +{ + const EVP_MD *digest = ossl_prov_digest_md(&kctx->digest); + int w = EVP_MD_get_block_size(digest); + + if (keylen < KMAC_MIN_KEY || keylen > KMAC_MAX_KEY) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + if (w < 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH); + return 0; + } + if (!kmac_bytepad_encode_key(kctx->key, sizeof(kctx->key), &kctx->key_len, + key, keylen, (size_t)w)) + return 0; + return 1; +} + +/* + * The init() assumes that any ctrl methods are set beforehand for + * md, key and custom. Setting the fields afterwards will have no + * effect on the output mac. + */ +static int kmac_init(void *vmacctx, const unsigned char *key, + size_t keylen, const OSSL_PARAM params[]) +{ + struct kmac_data_st *kctx = vmacctx; + EVP_MD_CTX *ctx = kctx->ctx; + unsigned char *out; + size_t out_len, block_len; + int res, t; + + if (!ossl_prov_is_running() || !kmac_set_ctx_params(kctx, params)) + return 0; + + if (key != NULL) { + if (!kmac_setkey(kctx, key, keylen)) + return 0; + } else if (kctx->key_len == 0) { + /* Check key has been set */ + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } + if (!EVP_DigestInit_ex(kctx->ctx, ossl_prov_digest_md(&kctx->digest), + NULL)) + return 0; + + t = EVP_MD_get_block_size(ossl_prov_digest_md(&kctx->digest)); + if (t < 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH); + return 0; + } + block_len = t; + + /* Set default custom string if it is not already set */ + if (kctx->custom_len == 0) { + const OSSL_PARAM cparams[] = { + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_CUSTOM, "", 0), + OSSL_PARAM_END + }; + (void)kmac_set_ctx_params(kctx, cparams); + } + + if (!bytepad(NULL, &out_len, kmac_string, sizeof(kmac_string), + kctx->custom, kctx->custom_len, block_len)) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return 0; + } + out = OPENSSL_malloc(out_len); + if (out == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + res = bytepad(out, NULL, kmac_string, sizeof(kmac_string), + kctx->custom, kctx->custom_len, block_len) + && EVP_DigestUpdate(ctx, out, out_len) + && EVP_DigestUpdate(ctx, kctx->key, kctx->key_len); + OPENSSL_free(out); + return res; +} + +static int kmac_update(void *vmacctx, const unsigned char *data, + size_t datalen) +{ + struct kmac_data_st *kctx = vmacctx; + + return EVP_DigestUpdate(kctx->ctx, data, datalen); +} + +static int kmac_final(void *vmacctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + struct kmac_data_st *kctx = vmacctx; + EVP_MD_CTX *ctx = kctx->ctx; + size_t lbits, len; + unsigned char encoded_outlen[KMAC_MAX_ENCODED_HEADER_LEN]; + int ok; + + if (!ossl_prov_is_running()) + return 0; + + /* KMAC XOF mode sets the encoded length to 0 */ + lbits = (kctx->xof_mode ? 0 : (kctx->out_len * 8)); + + ok = right_encode(encoded_outlen, sizeof(encoded_outlen), &len, lbits) + && EVP_DigestUpdate(ctx, encoded_outlen, len) + && EVP_DigestFinalXOF(ctx, out, kctx->out_len); + *outl = kctx->out_len; + return ok; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_size_t(OSSL_MAC_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_END +}; +static const OSSL_PARAM *kmac_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int kmac_get_ctx_params(void *vmacctx, OSSL_PARAM params[]) +{ + struct kmac_data_st *kctx = vmacctx; + OSSL_PARAM *p; + int sz; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE)) != NULL + && !OSSL_PARAM_set_size_t(p, kctx->out_len)) + return 0; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_BLOCK_SIZE)) != NULL) { + sz = EVP_MD_block_size(ossl_prov_digest_md(&kctx->digest)); + if (!OSSL_PARAM_set_int(p, sz)) + return 0; + } + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_int(OSSL_MAC_PARAM_XOF, NULL), + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_CUSTOM, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *kmac_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +/* + * The following params can be set any time before final(): + * - "outlen" or "size": The requested output length. + * - "xof": If set, this indicates that right_encoded(0) + * is part of the digested data, otherwise it + * uses right_encoded(requested output length). + * + * All other params should be set before init(). + */ +static int kmac_set_ctx_params(void *vmacctx, const OSSL_PARAM *params) +{ + struct kmac_data_st *kctx = vmacctx; + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_XOF)) != NULL + && !OSSL_PARAM_get_int(p, &kctx->xof_mode)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_SIZE)) != NULL) { + size_t sz = 0; + + if (!OSSL_PARAM_get_size_t(p, &sz)) + return 0; + if (sz > KMAC_MAX_OUTPUT_LEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_OUTPUT_LENGTH); + return 0; + } + kctx->out_len = sz; + } + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL + && !kmac_setkey(kctx, p->data, p->data_size)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_CUSTOM)) + != NULL) { + if (p->data_size > KMAC_MAX_CUSTOM) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CUSTOM_LENGTH); + return 0; + } + if (!encode_string(kctx->custom, sizeof(kctx->custom), &kctx->custom_len, + p->data, p->data_size)) + return 0; + } + return 1; +} + +/* Encoding/Padding Methods. */ + +/* Returns the number of bytes required to store 'bits' into a byte array */ +static unsigned int get_encode_size(size_t bits) +{ + unsigned int cnt = 0, sz = sizeof(size_t); + + while (bits && (cnt < sz)) { + ++cnt; + bits >>= 8; + } + /* If bits is zero 1 byte is required */ + if (cnt == 0) + cnt = 1; + return cnt; +} + +/* + * Convert an integer into bytes . The number of bytes is appended + * to the end of the buffer. Returns an array of bytes 'out' of size + * *out_len. + * + * e.g if bits = 32, out[2] = { 0x20, 0x01 } + */ +static int right_encode(unsigned char *out, size_t out_max_len, size_t *out_len, + size_t bits) +{ + unsigned int len = get_encode_size(bits); + int i; + + if (len >= out_max_len) { + ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE); + return 0; + } + + /* MSB's are at the start of the bytes array */ + for (i = len - 1; i >= 0; --i) { + out[i] = (unsigned char)(bits & 0xFF); + bits >>= 8; + } + /* Tack the length onto the end */ + out[len] = (unsigned char)len; + + /* The Returned length includes the tacked on byte */ + *out_len = len + 1; + return 1; +} + +/* + * Encodes a string with a left encoded length added. Note that the + * in_len is converted to bits (*8). + * + * e.g- in="KMAC" gives out[6] = { 0x01, 0x20, 0x4B, 0x4D, 0x41, 0x43 } + * len bits K M A C + */ +static int encode_string(unsigned char *out, size_t out_max_len, size_t *out_len, + const unsigned char *in, size_t in_len) +{ + if (in == NULL) { + *out_len = 0; + } else { + size_t i, bits, len, sz; + + bits = 8 * in_len; + len = get_encode_size(bits); + sz = 1 + len + in_len; + + if (sz > out_max_len) { + ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE); + return 0; + } + + out[0] = (unsigned char)len; + for (i = len; i > 0; --i) { + out[i] = (bits & 0xFF); + bits >>= 8; + } + memcpy(out + len + 1, in, in_len); + *out_len = sz; + } + return 1; +} + +/* + * Returns a zero padded encoding of the inputs in1 and an optional + * in2 (can be NULL). The padded output must be a multiple of the blocksize 'w'. + * The value of w is in bytes (< 256). + * + * The returned output is: + * zero_padded(multiple of w, (left_encode(w) || in1 [|| in2]) + */ +static int bytepad(unsigned char *out, size_t *out_len, + const unsigned char *in1, size_t in1_len, + const unsigned char *in2, size_t in2_len, size_t w) +{ + int len; + unsigned char *p = out; + int sz = w; + + if (out == NULL) { + if (out_len == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + sz = 2 + in1_len + (in2 != NULL ? in2_len : 0); + *out_len = (sz + w - 1) / w * w; + return 1; + } + + if (!ossl_assert(w <= 255)) + return 0; + + /* Left encoded w */ + *p++ = 1; + *p++ = (unsigned char)w; + /* || in1 */ + memcpy(p, in1, in1_len); + p += in1_len; + /* [ || in2 ] */ + if (in2 != NULL && in2_len > 0) { + memcpy(p, in2, in2_len); + p += in2_len; + } + /* Figure out the pad size (divisible by w) */ + len = p - out; + sz = (len + w - 1) / w * w; + /* zero pad the end of the buffer */ + if (sz != len) + memset(p, 0, sz - len); + if (out_len != NULL) + *out_len = sz; + return 1; +} + +/* Returns out = bytepad(encode_string(in), w) */ +static int kmac_bytepad_encode_key(unsigned char *out, size_t out_max_len, + size_t *out_len, + const unsigned char *in, size_t in_len, + size_t w) +{ + unsigned char tmp[KMAC_MAX_KEY + KMAC_MAX_ENCODED_HEADER_LEN]; + size_t tmp_len; + + if (!encode_string(tmp, sizeof(tmp), &tmp_len, in, in_len)) + return 0; + if (!bytepad(NULL, out_len, tmp, tmp_len, NULL, 0, w)) + return 0; + if (!ossl_assert(*out_len <= out_max_len)) + return 0; + return bytepad(out, NULL, tmp, tmp_len, NULL, 0, w); +} + +const OSSL_DISPATCH ossl_kmac128_functions[] = { + { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))kmac128_new }, + { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))kmac_dup }, + { OSSL_FUNC_MAC_FREECTX, (void (*)(void))kmac_free }, + { OSSL_FUNC_MAC_INIT, (void (*)(void))kmac_init }, + { OSSL_FUNC_MAC_UPDATE, (void (*)(void))kmac_update }, + { OSSL_FUNC_MAC_FINAL, (void (*)(void))kmac_final }, + { OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, + (void (*)(void))kmac_gettable_ctx_params }, + { OSSL_FUNC_MAC_GET_CTX_PARAMS, (void (*)(void))kmac_get_ctx_params }, + { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, + (void (*)(void))kmac_settable_ctx_params }, + { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))kmac_set_ctx_params }, + { 0, NULL } +}; + +const OSSL_DISPATCH ossl_kmac256_functions[] = { + { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))kmac256_new }, + { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))kmac_dup }, + { OSSL_FUNC_MAC_FREECTX, (void (*)(void))kmac_free }, + { OSSL_FUNC_MAC_INIT, (void (*)(void))kmac_init }, + { OSSL_FUNC_MAC_UPDATE, (void (*)(void))kmac_update }, + { OSSL_FUNC_MAC_FINAL, (void (*)(void))kmac_final }, + { OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, + (void (*)(void))kmac_gettable_ctx_params }, + { OSSL_FUNC_MAC_GET_CTX_PARAMS, (void (*)(void))kmac_get_ctx_params }, + { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, + (void (*)(void))kmac_settable_ctx_params }, + { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))kmac_set_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/macs/poly1305_prov.c b/providers/implementations/macs/poly1305_prov.c new file mode 100644 index 000000000000..f922802ea79c --- /dev/null +++ b/providers/implementations/macs/poly1305_prov.c @@ -0,0 +1,187 @@ +/* + * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/proverr.h> + +#include "crypto/poly1305.h" + +#include "prov/implementations.h" +#include "prov/providercommon.h" + +/* + * Forward declaration of everything implemented here. This is not strictly + * necessary for the compiler, but provides an assurance that the signatures + * of the functions in the dispatch table are correct. + */ +static OSSL_FUNC_mac_newctx_fn poly1305_new; +static OSSL_FUNC_mac_dupctx_fn poly1305_dup; +static OSSL_FUNC_mac_freectx_fn poly1305_free; +static OSSL_FUNC_mac_gettable_params_fn poly1305_gettable_params; +static OSSL_FUNC_mac_get_params_fn poly1305_get_params; +static OSSL_FUNC_mac_settable_ctx_params_fn poly1305_settable_ctx_params; +static OSSL_FUNC_mac_set_ctx_params_fn poly1305_set_ctx_params; +static OSSL_FUNC_mac_init_fn poly1305_init; +static OSSL_FUNC_mac_update_fn poly1305_update; +static OSSL_FUNC_mac_final_fn poly1305_final; + +struct poly1305_data_st { + void *provctx; + int updated; + POLY1305 poly1305; /* Poly1305 data */ +}; + +static void *poly1305_new(void *provctx) +{ + struct poly1305_data_st *ctx; + + if (!ossl_prov_is_running()) + return NULL; + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + ctx->provctx = provctx; + return ctx; +} + +static void poly1305_free(void *vmacctx) +{ + OPENSSL_free(vmacctx); +} + +static void *poly1305_dup(void *vsrc) +{ + struct poly1305_data_st *src = vsrc; + struct poly1305_data_st *dst; + + if (!ossl_prov_is_running()) + return NULL; + dst = OPENSSL_malloc(sizeof(*dst)); + if (dst == NULL) + return NULL; + + *dst = *src; + return dst; +} + +static size_t poly1305_size(void) +{ + return POLY1305_DIGEST_SIZE; +} + +static int poly1305_setkey(struct poly1305_data_st *ctx, + const unsigned char *key, size_t keylen) +{ + if (keylen != POLY1305_KEY_SIZE) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + Poly1305_Init(&ctx->poly1305, key); + ctx->updated = 0; + return 1; +} + +static int poly1305_init(void *vmacctx, const unsigned char *key, + size_t keylen, const OSSL_PARAM params[]) +{ + struct poly1305_data_st *ctx = vmacctx; + + /* initialize the context in MAC_ctrl function */ + if (!ossl_prov_is_running() || !poly1305_set_ctx_params(ctx, params)) + return 0; + if (key != NULL) + return poly1305_setkey(ctx, key, keylen); + /* no reinitialization of context with the same key is allowed */ + return ctx->updated == 0; +} + +static int poly1305_update(void *vmacctx, const unsigned char *data, + size_t datalen) +{ + struct poly1305_data_st *ctx = vmacctx; + + ctx->updated = 1; + if (datalen == 0) + return 1; + + /* poly1305 has nothing to return in its update function */ + Poly1305_Update(&ctx->poly1305, data, datalen); + return 1; +} + +static int poly1305_final(void *vmacctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + struct poly1305_data_st *ctx = vmacctx; + + if (!ossl_prov_is_running()) + return 0; + ctx->updated = 1; + Poly1305_Final(&ctx->poly1305, out); + *outl = poly1305_size(); + return 1; +} + +static const OSSL_PARAM known_gettable_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_END +}; +static const OSSL_PARAM *poly1305_gettable_params(void *provctx) +{ + return known_gettable_params; +} + +static int poly1305_get_params(OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE)) != NULL) + return OSSL_PARAM_set_size_t(p, poly1305_size()); + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *poly1305_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +static int poly1305_set_ctx_params(void *vmacctx, const OSSL_PARAM *params) +{ + struct poly1305_data_st *ctx = vmacctx; + const OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL + && !poly1305_setkey(ctx, p->data, p->data_size)) + return 0; + return 1; +} + +const OSSL_DISPATCH ossl_poly1305_functions[] = { + { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))poly1305_new }, + { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))poly1305_dup }, + { OSSL_FUNC_MAC_FREECTX, (void (*)(void))poly1305_free }, + { OSSL_FUNC_MAC_INIT, (void (*)(void))poly1305_init }, + { OSSL_FUNC_MAC_UPDATE, (void (*)(void))poly1305_update }, + { OSSL_FUNC_MAC_FINAL, (void (*)(void))poly1305_final }, + { OSSL_FUNC_MAC_GETTABLE_PARAMS, (void (*)(void))poly1305_gettable_params }, + { OSSL_FUNC_MAC_GET_PARAMS, (void (*)(void))poly1305_get_params }, + { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, + (void (*)(void))poly1305_settable_ctx_params }, + { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))poly1305_set_ctx_params }, + { 0, NULL } +}; diff --git a/providers/implementations/macs/siphash_prov.c b/providers/implementations/macs/siphash_prov.c new file mode 100644 index 000000000000..a28cdb33ac20 --- /dev/null +++ b/providers/implementations/macs/siphash_prov.c @@ -0,0 +1,237 @@ +/* + * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/proverr.h> + +#include "crypto/siphash.h" + +#include "prov/implementations.h" +#include "prov/providercommon.h" + +/* + * Forward declaration of everything implemented here. This is not strictly + * necessary for the compiler, but provides an assurance that the signatures + * of the functions in the dispatch table are correct. + */ +static OSSL_FUNC_mac_newctx_fn siphash_new; +static OSSL_FUNC_mac_dupctx_fn siphash_dup; +static OSSL_FUNC_mac_freectx_fn siphash_free; +static OSSL_FUNC_mac_gettable_ctx_params_fn siphash_gettable_ctx_params; +static OSSL_FUNC_mac_get_ctx_params_fn siphash_get_ctx_params; +static OSSL_FUNC_mac_settable_ctx_params_fn siphash_settable_ctx_params; +static OSSL_FUNC_mac_set_ctx_params_fn siphash_set_params; +static OSSL_FUNC_mac_init_fn siphash_init; +static OSSL_FUNC_mac_update_fn siphash_update; +static OSSL_FUNC_mac_final_fn siphash_final; + +struct siphash_data_st { + void *provctx; + SIPHASH siphash; /* Siphash data */ + SIPHASH sipcopy; /* Siphash data copy for reinitialization */ + unsigned int crounds, drounds; +}; + +static unsigned int crounds(struct siphash_data_st *ctx) +{ + return ctx->crounds != 0 ? ctx->crounds : SIPHASH_C_ROUNDS; +} + +static unsigned int drounds(struct siphash_data_st *ctx) +{ + return ctx->drounds != 0 ? ctx->drounds : SIPHASH_D_ROUNDS; +} + +static void *siphash_new(void *provctx) +{ + struct siphash_data_st *ctx; + + if (!ossl_prov_is_running()) + return NULL; + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) + ctx->provctx = provctx; + return ctx; +} + +static void siphash_free(void *vmacctx) +{ + OPENSSL_free(vmacctx); +} + +static void *siphash_dup(void *vsrc) +{ + struct siphash_data_st *ssrc = vsrc; + struct siphash_data_st *sdst; + + if (!ossl_prov_is_running()) + return NULL; + sdst = OPENSSL_malloc(sizeof(*sdst)); + if (sdst == NULL) + return NULL; + + *sdst = *ssrc; + return sdst; +} + +static size_t siphash_size(void *vmacctx) +{ + struct siphash_data_st *ctx = vmacctx; + + return SipHash_hash_size(&ctx->siphash); +} + +static int siphash_setkey(struct siphash_data_st *ctx, + const unsigned char *key, size_t keylen) +{ + int ret; + + if (keylen != SIPHASH_KEY_SIZE) + return 0; + ret = SipHash_Init(&ctx->siphash, key, crounds(ctx), drounds(ctx)); + if (ret) + ctx->sipcopy = ctx->siphash; + return ret; +} + +static int siphash_init(void *vmacctx, const unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + struct siphash_data_st *ctx = vmacctx; + + if (!ossl_prov_is_running() || !siphash_set_params(ctx, params)) + return 0; + /* + * Without a key, there is not much to do here, + * The actual initialization happens through controls. + */ + if (key == NULL) { + ctx->siphash = ctx->sipcopy; + return 1; + } + return siphash_setkey(ctx, key, keylen); +} + +static int siphash_update(void *vmacctx, const unsigned char *data, + size_t datalen) +{ + struct siphash_data_st *ctx = vmacctx; + + if (datalen == 0) + return 1; + + SipHash_Update(&ctx->siphash, data, datalen); + return 1; +} + +static int siphash_final(void *vmacctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + struct siphash_data_st *ctx = vmacctx; + size_t hlen = siphash_size(ctx); + + if (!ossl_prov_is_running() || outsize < hlen) + return 0; + + *outl = hlen; + return SipHash_Final(&ctx->siphash, out, hlen); +} + +static const OSSL_PARAM *siphash_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_uint(OSSL_MAC_PARAM_C_ROUNDS, NULL), + OSSL_PARAM_uint(OSSL_MAC_PARAM_D_ROUNDS, NULL), + OSSL_PARAM_END + }; + + return known_gettable_ctx_params; +} + +static int siphash_get_ctx_params(void *vmacctx, OSSL_PARAM params[]) +{ + struct siphash_data_st *ctx = vmacctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE)) != NULL + && !OSSL_PARAM_set_size_t(p, siphash_size(vmacctx))) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_C_ROUNDS)) != NULL + && !OSSL_PARAM_set_uint(p, crounds(ctx))) + return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_D_ROUNDS)) != NULL + && !OSSL_PARAM_set_uint(p, drounds(ctx))) + return 0; + return 1; +} + +static const OSSL_PARAM *siphash_settable_ctx_params(ossl_unused void *ctx, + void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0), + OSSL_PARAM_uint(OSSL_MAC_PARAM_C_ROUNDS, NULL), + OSSL_PARAM_uint(OSSL_MAC_PARAM_D_ROUNDS, NULL), + OSSL_PARAM_END + }; + + return known_settable_ctx_params; +} + +static int siphash_set_params(void *vmacctx, const OSSL_PARAM *params) +{ + struct siphash_data_st *ctx = vmacctx; + const OSSL_PARAM *p = NULL; + size_t size; + + if (params == NULL) + return 1; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_SIZE)) != NULL) { + if (!OSSL_PARAM_get_size_t(p, &size) + || !SipHash_set_hash_size(&ctx->siphash, size) + || !SipHash_set_hash_size(&ctx->sipcopy, size)) + return 0; + } + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_C_ROUNDS)) != NULL + && !OSSL_PARAM_get_uint(p, &ctx->crounds)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_D_ROUNDS)) != NULL + && !OSSL_PARAM_get_uint(p, &ctx->drounds)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL) + if (p->data_type != OSSL_PARAM_OCTET_STRING + || !siphash_setkey(ctx, p->data, p->data_size)) + return 0; + return 1; +} + +const OSSL_DISPATCH ossl_siphash_functions[] = { + { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))siphash_new }, + { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))siphash_dup }, + { OSSL_FUNC_MAC_FREECTX, (void (*)(void))siphash_free }, + { OSSL_FUNC_MAC_INIT, (void (*)(void))siphash_init }, + { OSSL_FUNC_MAC_UPDATE, (void (*)(void))siphash_update }, + { OSSL_FUNC_MAC_FINAL, (void (*)(void))siphash_final }, + { OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, + (void (*)(void))siphash_gettable_ctx_params }, + { OSSL_FUNC_MAC_GET_CTX_PARAMS, (void (*)(void))siphash_get_ctx_params }, + { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, + (void (*)(void))siphash_settable_ctx_params }, + { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))siphash_set_params }, + { 0, NULL } +}; diff --git a/providers/implementations/rands/build.info b/providers/implementations/rands/build.info new file mode 100644 index 000000000000..8bcac43be7cc --- /dev/null +++ b/providers/implementations/rands/build.info @@ -0,0 +1,6 @@ +SUBDIRS=seeding + +$RANDS_GOAL=../../libdefault.a ../../libfips.a + +SOURCE[$RANDS_GOAL]=drbg.c test_rng.c drbg_ctr.c drbg_hash.c drbg_hmac.c crngt.c +SOURCE[../../libdefault.a]=seed_src.c diff --git a/providers/implementations/rands/crngt.c b/providers/implementations/rands/crngt.c new file mode 100644 index 000000000000..4095994bda11 --- /dev/null +++ b/providers/implementations/rands/crngt.c @@ -0,0 +1,198 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Implementation of the FIPS 140-2 section 4.9.2 Conditional Tests. + */ + +#include <string.h> +#include <openssl/evp.h> +#include <openssl/core_dispatch.h> +#include <openssl/params.h> +#include <openssl/self_test.h> +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "internal/cryptlib.h" +#include "crypto/rand_pool.h" +#include "drbg_local.h" +#include "prov/seeding.h" + +typedef struct crng_test_global_st { + unsigned char crngt_prev[EVP_MAX_MD_SIZE]; + EVP_MD *md; + int preloaded; + CRYPTO_RWLOCK *lock; +} CRNG_TEST_GLOBAL; + +static int crngt_get_entropy(PROV_CTX *provctx, const EVP_MD *digest, + unsigned char *buf, unsigned char *md, + unsigned int *md_size) +{ + int r; + size_t n; + unsigned char *p; + + n = ossl_prov_get_entropy(provctx, &p, 0, CRNGT_BUFSIZ, CRNGT_BUFSIZ); + if (n == CRNGT_BUFSIZ) { + r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, digest, NULL); + if (r != 0) + memcpy(buf, p, CRNGT_BUFSIZ); + ossl_prov_cleanup_entropy(provctx, p, n); + return r != 0; + } + if (n != 0) + ossl_prov_cleanup_entropy(provctx, p, n); + return 0; +} + +static void rand_crng_ossl_ctx_free(void *vcrngt_glob) +{ + CRNG_TEST_GLOBAL *crngt_glob = vcrngt_glob; + + CRYPTO_THREAD_lock_free(crngt_glob->lock); + EVP_MD_free(crngt_glob->md); + OPENSSL_free(crngt_glob); +} + +static void *rand_crng_ossl_ctx_new(OSSL_LIB_CTX *ctx) +{ + CRNG_TEST_GLOBAL *crngt_glob = OPENSSL_zalloc(sizeof(*crngt_glob)); + + if (crngt_glob == NULL) + return NULL; + + if ((crngt_glob->md = EVP_MD_fetch(ctx, "SHA256", "")) == NULL) { + OPENSSL_free(crngt_glob); + return NULL; + } + + if ((crngt_glob->lock = CRYPTO_THREAD_lock_new()) == NULL) { + EVP_MD_free(crngt_glob->md); + OPENSSL_free(crngt_glob); + return NULL; + } + + return crngt_glob; +} + +static const OSSL_LIB_CTX_METHOD rand_crng_ossl_ctx_method = { + OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY, + rand_crng_ossl_ctx_new, + rand_crng_ossl_ctx_free, +}; + +static int prov_crngt_compare_previous(const unsigned char *prev, + const unsigned char *cur, + size_t sz) +{ + const int res = memcmp(prev, cur, sz) != 0; + + if (!res) + ossl_set_error_state(OSSL_SELF_TEST_TYPE_CRNG); + return res; +} + +size_t ossl_crngt_get_entropy(PROV_DRBG *drbg, + unsigned char **pout, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance) +{ + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned char buf[CRNGT_BUFSIZ]; + unsigned char *ent, *entp, *entbuf; + unsigned int sz; + size_t bytes_needed; + size_t r = 0, s, t; + int crng_test_pass = 1; + OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(drbg->provctx); + CRNG_TEST_GLOBAL *crngt_glob + = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_RAND_CRNGT_INDEX, + &rand_crng_ossl_ctx_method); + OSSL_CALLBACK *stcb = NULL; + void *stcbarg = NULL; + OSSL_SELF_TEST *st = NULL; + + if (crngt_glob == NULL) + return 0; + + if (!CRYPTO_THREAD_write_lock(crngt_glob->lock)) + return 0; + + if (!crngt_glob->preloaded) { + if (!crngt_get_entropy(drbg->provctx, crngt_glob->md, buf, + crngt_glob->crngt_prev, NULL)) { + OPENSSL_cleanse(buf, sizeof(buf)); + goto unlock_return; + } + crngt_glob->preloaded = 1; + } + + /* + * Calculate how many bytes of seed material we require, rounded up + * to the nearest byte. If the entropy is of less than full quality, + * the amount required should be scaled up appropriately here. + */ + bytes_needed = (entropy + 7) / 8; + if (bytes_needed < min_len) + bytes_needed = min_len; + if (bytes_needed > max_len) + goto unlock_return; + entp = ent = OPENSSL_secure_malloc(bytes_needed); + if (ent == NULL) + goto unlock_return; + + OSSL_SELF_TEST_get_callback(libctx, &stcb, &stcbarg); + if (stcb != NULL) { + st = OSSL_SELF_TEST_new(stcb, stcbarg); + if (st == NULL) + goto err; + OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_CRNG, + OSSL_SELF_TEST_DESC_RNG); + } + + for (t = bytes_needed; t > 0;) { + /* Care needs to be taken to avoid overrunning the buffer */ + s = t >= CRNGT_BUFSIZ ? CRNGT_BUFSIZ : t; + entbuf = t >= CRNGT_BUFSIZ ? entp : buf; + if (!crngt_get_entropy(drbg->provctx, crngt_glob->md, entbuf, md, &sz)) + goto err; + if (t < CRNGT_BUFSIZ) + memcpy(entp, buf, t); + /* Force a failure here if the callback returns 1 */ + if (OSSL_SELF_TEST_oncorrupt_byte(st, md)) + memcpy(md, crngt_glob->crngt_prev, sz); + if (!prov_crngt_compare_previous(crngt_glob->crngt_prev, md, sz)) { + crng_test_pass = 0; + goto err; + } + /* Update for next block */ + memcpy(crngt_glob->crngt_prev, md, sz); + entp += s; + t -= s; + } + r = bytes_needed; + *pout = ent; + ent = NULL; + + err: + OSSL_SELF_TEST_onend(st, crng_test_pass); + OSSL_SELF_TEST_free(st); + OPENSSL_secure_clear_free(ent, bytes_needed); + + unlock_return: + CRYPTO_THREAD_unlock(crngt_glob->lock); + return r; +} + +void ossl_crngt_cleanup_entropy(ossl_unused PROV_DRBG *drbg, + unsigned char *out, size_t outlen) +{ + OPENSSL_secure_clear_free(out, outlen); +} diff --git a/providers/implementations/rands/drbg.c b/providers/implementations/rands/drbg.c new file mode 100644 index 000000000000..c8fe66aa573f --- /dev/null +++ b/providers/implementations/rands/drbg.c @@ -0,0 +1,934 @@ +/* + * Copyright 2011-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/rand.h> +#include <openssl/evp.h> +#include "crypto/rand.h" +#include <openssl/proverr.h> +#include "drbg_local.h" +#include "internal/thread_once.h" +#include "crypto/cryptlib.h" +#include "prov/seeding.h" +#include "crypto/rand_pool.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" + +/* + * Support framework for NIST SP 800-90A DRBG + * + * See manual page PROV_DRBG(7) for a general overview. + * + * The OpenSSL model is to have new and free functions, and that new + * does all initialization. That is not the NIST model, which has + * instantiation and un-instantiate, and re-use within a new/free + * lifecycle. (No doubt this comes from the desire to support hardware + * DRBG, where allocation of resources on something like an HSM is + * a much bigger deal than just re-setting an allocated resource.) + */ + +/* NIST SP 800-90A DRBG recommends the use of a personalization string. */ +static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING; + +static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch, + int function); + +static int rand_drbg_restart(PROV_DRBG *drbg); + +int ossl_drbg_lock(void *vctx) +{ + PROV_DRBG *drbg = vctx; + + if (drbg == NULL || drbg->lock == NULL) + return 1; + return CRYPTO_THREAD_write_lock(drbg->lock); +} + +void ossl_drbg_unlock(void *vctx) +{ + PROV_DRBG *drbg = vctx; + + if (drbg != NULL && drbg->lock != NULL) + CRYPTO_THREAD_unlock(drbg->lock); +} + +static int ossl_drbg_lock_parent(PROV_DRBG *drbg) +{ + void *parent = drbg->parent; + + if (parent != NULL + && drbg->parent_lock != NULL + && !drbg->parent_lock(parent)) { + ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); + return 0; + } + return 1; +} + +static void ossl_drbg_unlock_parent(PROV_DRBG *drbg) +{ + void *parent = drbg->parent; + + if (parent != NULL && drbg->parent_unlock != NULL) + drbg->parent_unlock(parent); +} + +static int get_parent_strength(PROV_DRBG *drbg, unsigned int *str) +{ + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + void *parent = drbg->parent; + int res; + + if (drbg->parent_get_ctx_params == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH); + return 0; + } + + *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, str); + if (!ossl_drbg_lock_parent(drbg)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT); + return 0; + } + res = drbg->parent_get_ctx_params(parent, params); + ossl_drbg_unlock_parent(drbg); + if (!res) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH); + return 0; + } + return 1; +} + +static unsigned int get_parent_reseed_count(PROV_DRBG *drbg) +{ + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + void *parent = drbg->parent; + unsigned int r = 0; + + *params = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_COUNTER, &r); + if (!ossl_drbg_lock_parent(drbg)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT); + goto err; + } + if (!drbg->parent_get_ctx_params(parent, params)) + r = 0; + ossl_drbg_unlock_parent(drbg); + return r; + + err: + r = tsan_load(&drbg->reseed_counter) - 2; + if (r == 0) + r = UINT_MAX; + return r; +} + +/* + * Implements the get_entropy() callback + * + * If the DRBG has a parent, then the required amount of entropy input + * is fetched using the parent's ossl_prov_drbg_generate(). + * + * Otherwise, the entropy is polled from the system entropy sources + * using ossl_pool_acquire_entropy(). + * + * If a random pool has been added to the DRBG using RAND_add(), then + * its entropy will be used up first. + */ +size_t ossl_drbg_get_seed(void *vdrbg, unsigned char **pout, + int entropy, size_t min_len, + size_t max_len, int prediction_resistance, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + size_t bytes_needed; + unsigned char *buffer; + + /* Figure out how many bytes we need */ + bytes_needed = entropy >= 0 ? (entropy + 7) / 8 : 0; + if (bytes_needed < min_len) + bytes_needed = min_len; + if (bytes_needed > max_len) + bytes_needed = max_len; + + /* Allocate storage */ + buffer = OPENSSL_secure_malloc(bytes_needed); + if (buffer == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + /* + * Get random data. Include our DRBG address as + * additional input, in order to provide a distinction between + * different DRBG child instances. + * + * Note: using the sizeof() operator on a pointer triggers + * a warning in some static code analyzers, but it's + * intentional and correct here. + */ + if (!ossl_prov_drbg_generate(drbg, buffer, bytes_needed, + drbg->strength, prediction_resistance, + (unsigned char *)&drbg, sizeof(drbg))) { + OPENSSL_secure_clear_free(buffer, bytes_needed); + ERR_raise(ERR_LIB_PROV, PROV_R_GENERATE_ERROR); + return 0; + } + *pout = buffer; + return bytes_needed; +} + +/* Implements the cleanup_entropy() callback */ +void ossl_drbg_clear_seed(ossl_unused void *vdrbg, + unsigned char *out, size_t outlen) +{ + OPENSSL_secure_clear_free(out, outlen); +} + +static size_t get_entropy(PROV_DRBG *drbg, unsigned char **pout, int entropy, + size_t min_len, size_t max_len, + int prediction_resistance) +{ + size_t bytes; + unsigned int p_str; + + if (drbg->parent == NULL) +#ifdef FIPS_MODULE + return ossl_crngt_get_entropy(drbg, pout, entropy, min_len, max_len, + prediction_resistance); +#else + return ossl_prov_get_entropy(drbg->provctx, pout, entropy, min_len, + max_len); +#endif + + if (drbg->parent_get_seed == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_CANNOT_SUPPLY_ENTROPY_SEED); + return 0; + } + if (!get_parent_strength(drbg, &p_str)) + return 0; + if (drbg->strength > p_str) { + /* + * We currently don't support the algorithm from NIST SP 800-90C + * 10.1.2 to use a weaker DRBG as source + */ + ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_STRENGTH_TOO_WEAK); + return 0; + } + + /* + * Our lock is already held, but we need to lock our parent before + * generating bits from it. Note: taking the lock will be a no-op + * if locking is not required (while drbg->parent->lock == NULL). + */ + if (!ossl_drbg_lock_parent(drbg)) + return 0; + /* + * Get random data from parent. Include our DRBG address as + * additional input, in order to provide a distinction between + * different DRBG child instances. + * + * Note: using the sizeof() operator on a pointer triggers + * a warning in some static code analyzers, but it's + * intentional and correct here. + */ + bytes = drbg->parent_get_seed(drbg->parent, pout, drbg->strength, + min_len, max_len, prediction_resistance, + (unsigned char *)&drbg, sizeof(drbg)); + ossl_drbg_unlock_parent(drbg); + return bytes; +} + +static void cleanup_entropy(PROV_DRBG *drbg, unsigned char *out, size_t outlen) +{ + if (drbg->parent == NULL) { +#ifdef FIPS_MODULE + ossl_crngt_cleanup_entropy(drbg, out, outlen); +#else + ossl_prov_cleanup_entropy(drbg->provctx, out, outlen); +#endif + } else if (drbg->parent_clear_seed != NULL) { + if (!ossl_drbg_lock_parent(drbg)) + return; + drbg->parent_clear_seed(drbg, out, outlen); + ossl_drbg_unlock_parent(drbg); + } +} + +#ifndef PROV_RAND_GET_RANDOM_NONCE +typedef struct prov_drbg_nonce_global_st { + CRYPTO_RWLOCK *rand_nonce_lock; + int rand_nonce_count; +} PROV_DRBG_NONCE_GLOBAL; + +/* + * drbg_ossl_ctx_new() calls drgb_setup() which calls rand_drbg_get_nonce() + * which needs to get the rand_nonce_lock out of the OSSL_LIB_CTX...but since + * drbg_ossl_ctx_new() hasn't finished running yet we need the rand_nonce_lock + * to be in a different global data object. Otherwise we will go into an + * infinite recursion loop. + */ +static void *prov_drbg_nonce_ossl_ctx_new(OSSL_LIB_CTX *libctx) +{ + PROV_DRBG_NONCE_GLOBAL *dngbl = OPENSSL_zalloc(sizeof(*dngbl)); + + if (dngbl == NULL) + return NULL; + + dngbl->rand_nonce_lock = CRYPTO_THREAD_lock_new(); + if (dngbl->rand_nonce_lock == NULL) { + OPENSSL_free(dngbl); + return NULL; + } + + return dngbl; +} + +static void prov_drbg_nonce_ossl_ctx_free(void *vdngbl) +{ + PROV_DRBG_NONCE_GLOBAL *dngbl = vdngbl; + + if (dngbl == NULL) + return; + + CRYPTO_THREAD_lock_free(dngbl->rand_nonce_lock); + + OPENSSL_free(dngbl); +} + +static const OSSL_LIB_CTX_METHOD drbg_nonce_ossl_ctx_method = { + OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY, + prov_drbg_nonce_ossl_ctx_new, + prov_drbg_nonce_ossl_ctx_free, +}; + +/* Get a nonce from the operating system */ +static size_t prov_drbg_get_nonce(PROV_DRBG *drbg, unsigned char **pout, + size_t min_len, size_t max_len) +{ + size_t ret = 0, n; + unsigned char *buf = NULL; + OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(drbg->provctx); + PROV_DRBG_NONCE_GLOBAL *dngbl + = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_DRBG_NONCE_INDEX, + &drbg_nonce_ossl_ctx_method); + struct { + void *drbg; + int count; + } data; + + if (dngbl == NULL) + return 0; + + if (drbg->parent != NULL && drbg->parent_nonce != NULL) { + n = drbg->parent_nonce(drbg->parent, NULL, 0, drbg->min_noncelen, + drbg->max_noncelen); + if (n > 0 && (buf = OPENSSL_malloc(n)) != NULL) { + ret = drbg->parent_nonce(drbg->parent, buf, 0, + drbg->min_noncelen, drbg->max_noncelen); + if (ret == n) { + *pout = buf; + return ret; + } + OPENSSL_free(buf); + } + } + + /* Use the built in nonce source plus some of our specifics */ + memset(&data, 0, sizeof(data)); + data.drbg = drbg; + CRYPTO_atomic_add(&dngbl->rand_nonce_count, 1, &data.count, + dngbl->rand_nonce_lock); + return ossl_prov_get_nonce(drbg->provctx, pout, min_len, max_len, + &data, sizeof(data)); +} +#endif /* PROV_RAND_GET_RANDOM_NONCE */ + +/* + * Instantiate |drbg|, after it has been initialized. Use |pers| and + * |perslen| as prediction-resistance input. + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success, 0 on failure. + */ +int ossl_prov_drbg_instantiate(PROV_DRBG *drbg, unsigned int strength, + int prediction_resistance, + const unsigned char *pers, size_t perslen) +{ + unsigned char *nonce = NULL, *entropy = NULL; + size_t noncelen = 0, entropylen = 0; + size_t min_entropy, min_entropylen, max_entropylen; + + if (strength > drbg->strength) { + ERR_raise(ERR_LIB_PROV, PROV_R_INSUFFICIENT_DRBG_STRENGTH); + goto end; + } + min_entropy = drbg->strength; + min_entropylen = drbg->min_entropylen; + max_entropylen = drbg->max_entropylen; + + if (pers == NULL) { + pers = (const unsigned char *)ossl_pers_string; + perslen = sizeof(ossl_pers_string); + } + if (perslen > drbg->max_perslen) { + ERR_raise(ERR_LIB_PROV, PROV_R_PERSONALISATION_STRING_TOO_LONG); + goto end; + } + + if (drbg->state != EVP_RAND_STATE_UNINITIALISED) { + if (drbg->state == EVP_RAND_STATE_ERROR) + ERR_raise(ERR_LIB_PROV, PROV_R_IN_ERROR_STATE); + else + ERR_raise(ERR_LIB_PROV, PROV_R_ALREADY_INSTANTIATED); + goto end; + } + + drbg->state = EVP_RAND_STATE_ERROR; + + if (drbg->min_noncelen > 0) { + if (drbg->parent_nonce != NULL) { + noncelen = drbg->parent_nonce(drbg->parent, NULL, drbg->strength, + drbg->min_noncelen, + drbg->max_noncelen); + if (noncelen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE); + goto end; + } + nonce = OPENSSL_malloc(noncelen); + if (nonce == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE); + goto end; + } + if (noncelen != drbg->parent_nonce(drbg->parent, nonce, + drbg->strength, + drbg->min_noncelen, + drbg->max_noncelen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE); + goto end; + } +#ifndef PROV_RAND_GET_RANDOM_NONCE + } else if (drbg->parent != NULL) { +#endif + /* + * NIST SP800-90Ar1 section 9.1 says you can combine getting + * the entropy and nonce in 1 call by increasing the entropy + * with 50% and increasing the minimum length to accommodate + * the length of the nonce. We do this in case a nonce is + * required and there is no parental nonce capability. + */ + min_entropy += drbg->strength / 2; + min_entropylen += drbg->min_noncelen; + max_entropylen += drbg->max_noncelen; + } +#ifndef PROV_RAND_GET_RANDOM_NONCE + else { /* parent == NULL */ + noncelen = prov_drbg_get_nonce(drbg, &nonce, drbg->min_noncelen, + drbg->max_noncelen); + if (noncelen < drbg->min_noncelen + || noncelen > drbg->max_noncelen) { + ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE); + goto end; + } + } +#endif + } + + drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter); + if (drbg->reseed_next_counter) { + drbg->reseed_next_counter++; + if (!drbg->reseed_next_counter) + drbg->reseed_next_counter = 1; + } + + entropylen = get_entropy(drbg, &entropy, min_entropy, + min_entropylen, max_entropylen, + prediction_resistance); + if (entropylen < min_entropylen + || entropylen > max_entropylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_ENTROPY); + goto end; + } + + if (!drbg->instantiate(drbg, entropy, entropylen, nonce, noncelen, + pers, perslen)) { + cleanup_entropy(drbg, entropy, entropylen); + ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_INSTANTIATING_DRBG); + goto end; + } + cleanup_entropy(drbg, entropy, entropylen); + + drbg->state = EVP_RAND_STATE_READY; + drbg->generate_counter = 1; + drbg->reseed_time = time(NULL); + tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter); + + end: + if (nonce != NULL) + ossl_prov_cleanup_nonce(drbg->provctx, nonce, noncelen); + if (drbg->state == EVP_RAND_STATE_READY) + return 1; + return 0; +} + +/* + * Uninstantiate |drbg|. Must be instantiated before it can be used. + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success, 0 on failure. + */ +int ossl_prov_drbg_uninstantiate(PROV_DRBG *drbg) +{ + drbg->state = EVP_RAND_STATE_UNINITIALISED; + return 1; +} + +/* + * Reseed |drbg|, mixing in the specified data + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success, 0 on failure. + */ +int ossl_prov_drbg_reseed(PROV_DRBG *drbg, int prediction_resistance, + const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adinlen) +{ + unsigned char *entropy = NULL; + size_t entropylen = 0; + + if (!ossl_prov_is_running()) + return 0; + + if (drbg->state != EVP_RAND_STATE_READY) { + /* try to recover from previous errors */ + rand_drbg_restart(drbg); + + if (drbg->state == EVP_RAND_STATE_ERROR) { + ERR_raise(ERR_LIB_PROV, PROV_R_IN_ERROR_STATE); + return 0; + } + if (drbg->state == EVP_RAND_STATE_UNINITIALISED) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_INSTANTIATED); + return 0; + } + } + + if (ent != NULL) { + if (ent_len < drbg->min_entropylen) { + ERR_raise(ERR_LIB_RAND, RAND_R_ENTROPY_OUT_OF_RANGE); + drbg->state = EVP_RAND_STATE_ERROR; + return 0; + } + if (ent_len > drbg->max_entropylen) { + ERR_raise(ERR_LIB_RAND, RAND_R_ENTROPY_INPUT_TOO_LONG); + drbg->state = EVP_RAND_STATE_ERROR; + return 0; + } + } + + if (adin == NULL) { + adinlen = 0; + } else if (adinlen > drbg->max_adinlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_ADDITIONAL_INPUT_TOO_LONG); + return 0; + } + + drbg->state = EVP_RAND_STATE_ERROR; + + drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter); + if (drbg->reseed_next_counter) { + drbg->reseed_next_counter++; + if (!drbg->reseed_next_counter) + drbg->reseed_next_counter = 1; + } + + if (ent != NULL) { +#ifdef FIPS_MODULE + /* + * NIST SP-800-90A mandates that entropy *shall not* be provided + * by the consuming application. Instead the data is added as additional + * input. + * + * (NIST SP-800-90Ar1, Sections 9.1 and 9.2) + */ + if (!drbg->reseed(drbg, NULL, 0, ent, ent_len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED); + return 0; + } +#else + if (!drbg->reseed(drbg, ent, ent_len, adin, adinlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED); + return 0; + } + /* There isn't much point adding the same additional input twice */ + adin = NULL; + adinlen = 0; +#endif + } + + /* Reseed using our sources in addition */ + entropylen = get_entropy(drbg, &entropy, drbg->strength, + drbg->min_entropylen, drbg->max_entropylen, + prediction_resistance); + if (entropylen < drbg->min_entropylen + || entropylen > drbg->max_entropylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_ENTROPY); + goto end; + } + + if (!drbg->reseed(drbg, entropy, entropylen, adin, adinlen)) + goto end; + + drbg->state = EVP_RAND_STATE_READY; + drbg->generate_counter = 1; + drbg->reseed_time = time(NULL); + tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter); + if (drbg->parent != NULL) + drbg->parent_reseed_counter = get_parent_reseed_count(drbg); + + end: + cleanup_entropy(drbg, entropy, entropylen); + if (drbg->state == EVP_RAND_STATE_READY) + return 1; + return 0; +} + +/* + * Generate |outlen| bytes into the buffer at |out|. Reseed if we need + * to or if |prediction_resistance| is set. Additional input can be + * sent in |adin| and |adinlen|. + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success, 0 on failure. + * + */ +int ossl_prov_drbg_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, + unsigned int strength, int prediction_resistance, + const unsigned char *adin, size_t adinlen) +{ + int fork_id; + int reseed_required = 0; + + if (!ossl_prov_is_running()) + return 0; + + if (drbg->state != EVP_RAND_STATE_READY) { + /* try to recover from previous errors */ + rand_drbg_restart(drbg); + + if (drbg->state == EVP_RAND_STATE_ERROR) { + ERR_raise(ERR_LIB_PROV, PROV_R_IN_ERROR_STATE); + return 0; + } + if (drbg->state == EVP_RAND_STATE_UNINITIALISED) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_INSTANTIATED); + return 0; + } + } + if (strength > drbg->strength) { + ERR_raise(ERR_LIB_PROV, PROV_R_INSUFFICIENT_DRBG_STRENGTH); + return 0; + } + + if (outlen > drbg->max_request) { + ERR_raise(ERR_LIB_PROV, PROV_R_REQUEST_TOO_LARGE_FOR_DRBG); + return 0; + } + if (adinlen > drbg->max_adinlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_ADDITIONAL_INPUT_TOO_LONG); + return 0; + } + + fork_id = openssl_get_fork_id(); + + if (drbg->fork_id != fork_id) { + drbg->fork_id = fork_id; + reseed_required = 1; + } + + if (drbg->reseed_interval > 0) { + if (drbg->generate_counter >= drbg->reseed_interval) + reseed_required = 1; + } + if (drbg->reseed_time_interval > 0) { + time_t now = time(NULL); + if (now < drbg->reseed_time + || now - drbg->reseed_time >= drbg->reseed_time_interval) + reseed_required = 1; + } + if (drbg->parent != NULL + && get_parent_reseed_count(drbg) != drbg->parent_reseed_counter) + reseed_required = 1; + + if (reseed_required || prediction_resistance) { + if (!ossl_prov_drbg_reseed(drbg, prediction_resistance, NULL, 0, + adin, adinlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_RESEED_ERROR); + return 0; + } + adin = NULL; + adinlen = 0; + } + + if (!drbg->generate(drbg, out, outlen, adin, adinlen)) { + drbg->state = EVP_RAND_STATE_ERROR; + ERR_raise(ERR_LIB_PROV, PROV_R_GENERATE_ERROR); + return 0; + } + + drbg->generate_counter++; + + return 1; +} + +/* + * Restart |drbg|, using the specified entropy or additional input + * + * Tries its best to get the drbg instantiated by all means, + * regardless of its current state. + * + * Optionally, a |buffer| of |len| random bytes can be passed, + * which is assumed to contain at least |entropy| bits of entropy. + * + * If |entropy| > 0, the buffer content is used as entropy input. + * + * If |entropy| == 0, the buffer content is used as additional input + * + * Returns 1 on success, 0 on failure. + * + * This function is used internally only. + */ +static int rand_drbg_restart(PROV_DRBG *drbg) +{ + /* repair error state */ + if (drbg->state == EVP_RAND_STATE_ERROR) + drbg->uninstantiate(drbg); + + /* repair uninitialized state */ + if (drbg->state == EVP_RAND_STATE_UNINITIALISED) + /* reinstantiate drbg */ + ossl_prov_drbg_instantiate(drbg, drbg->strength, 0, NULL, 0); + + return drbg->state == EVP_RAND_STATE_READY; +} + +/* Provider support from here down */ +static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch, + int function) +{ + if (dispatch != NULL) + while (dispatch->function_id != 0) { + if (dispatch->function_id == function) + return dispatch; + dispatch++; + } + return NULL; +} + +int ossl_drbg_enable_locking(void *vctx) +{ + PROV_DRBG *drbg = vctx; + + if (drbg != NULL && drbg->lock == NULL) { + if (drbg->parent_enable_locking != NULL) + if (!drbg->parent_enable_locking(drbg->parent)) { + ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); + return 0; + } + drbg->lock = CRYPTO_THREAD_lock_new(); + if (drbg->lock == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK); + return 0; + } + } + return 1; +} + +/* + * Allocate memory and initialize a new DRBG. The DRBG is allocated on + * the secure heap if |secure| is nonzero and the secure heap is enabled. + * The |parent|, if not NULL, will be used as random source for reseeding. + * This also requires the parent's provider context and the parent's lock. + * + * Returns a pointer to the new DRBG instance on success, NULL on failure. + */ +PROV_DRBG *ossl_rand_drbg_new + (void *provctx, void *parent, const OSSL_DISPATCH *p_dispatch, + int (*dnew)(PROV_DRBG *ctx), + int (*instantiate)(PROV_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *nonce, size_t noncelen, + const unsigned char *pers, size_t perslen), + int (*uninstantiate)(PROV_DRBG *ctx), + int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len), + int (*generate)(PROV_DRBG *, unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adin_len)) +{ + PROV_DRBG *drbg; + unsigned int p_str; + const OSSL_DISPATCH *pfunc; + + if (!ossl_prov_is_running()) + return NULL; + + drbg = OPENSSL_zalloc(sizeof(*drbg)); + if (drbg == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + drbg->provctx = provctx; + drbg->instantiate = instantiate; + drbg->uninstantiate = uninstantiate; + drbg->reseed = reseed; + drbg->generate = generate; + drbg->fork_id = openssl_get_fork_id(); + + /* Extract parent's functions */ + drbg->parent = parent; + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_ENABLE_LOCKING)) != NULL) + drbg->parent_enable_locking = OSSL_FUNC_rand_enable_locking(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_LOCK)) != NULL) + drbg->parent_lock = OSSL_FUNC_rand_lock(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_UNLOCK)) != NULL) + drbg->parent_unlock = OSSL_FUNC_rand_unlock(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS)) != NULL) + drbg->parent_get_ctx_params = OSSL_FUNC_rand_get_ctx_params(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_NONCE)) != NULL) + drbg->parent_nonce = OSSL_FUNC_rand_nonce(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GET_SEED)) != NULL) + drbg->parent_get_seed = OSSL_FUNC_rand_get_seed(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_CLEAR_SEED)) != NULL) + drbg->parent_clear_seed = OSSL_FUNC_rand_clear_seed(pfunc); + + /* Set some default maximums up */ + drbg->max_entropylen = DRBG_MAX_LENGTH; + drbg->max_noncelen = DRBG_MAX_LENGTH; + drbg->max_perslen = DRBG_MAX_LENGTH; + drbg->max_adinlen = DRBG_MAX_LENGTH; + drbg->generate_counter = 1; + drbg->reseed_counter = 1; + drbg->reseed_interval = RESEED_INTERVAL; + drbg->reseed_time_interval = TIME_INTERVAL; + + if (!dnew(drbg)) + goto err; + + if (parent != NULL) { + if (!get_parent_strength(drbg, &p_str)) + goto err; + if (drbg->strength > p_str) { + /* + * We currently don't support the algorithm from NIST SP 800-90C + * 10.1.2 to use a weaker DRBG as source + */ + ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_STRENGTH_TOO_WEAK); + goto err; + } + } +#ifdef TSAN_REQUIRES_LOCKING + if (!ossl_drbg_enable_locking(drbg)) + goto err; +#endif + return drbg; + + err: + ossl_rand_drbg_free(drbg); + return NULL; +} + +void ossl_rand_drbg_free(PROV_DRBG *drbg) +{ + if (drbg == NULL) + return; + + CRYPTO_THREAD_lock_free(drbg->lock); + OPENSSL_free(drbg); +} + +int ossl_drbg_get_ctx_params(PROV_DRBG *drbg, OSSL_PARAM params[]) +{ + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE); + if (p != NULL && !OSSL_PARAM_set_int(p, drbg->state)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH); + if (p != NULL && !OSSL_PARAM_set_int(p, drbg->strength)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST); + if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_request)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MIN_ENTROPYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->min_entropylen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_ENTROPYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_entropylen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MIN_NONCELEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->min_noncelen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_NONCELEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_noncelen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_PERSLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_perslen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_ADINLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_adinlen)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_REQUESTS); + if (p != NULL && !OSSL_PARAM_set_uint(p, drbg->reseed_interval)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_TIME); + if (p != NULL && !OSSL_PARAM_set_time_t(p, drbg->reseed_time)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL); + if (p != NULL && !OSSL_PARAM_set_time_t(p, drbg->reseed_time_interval)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_COUNTER); + if (p != NULL + && !OSSL_PARAM_set_uint(p, tsan_load(&drbg->reseed_counter))) + return 0; + return 1; +} + +int ossl_drbg_set_ctx_params(PROV_DRBG *drbg, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_REQUESTS); + if (p != NULL && !OSSL_PARAM_get_uint(p, &drbg->reseed_interval)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL); + if (p != NULL && !OSSL_PARAM_get_time_t(p, &drbg->reseed_time_interval)) + return 0; + return 1; +} diff --git a/providers/implementations/rands/drbg_ctr.c b/providers/implementations/rands/drbg_ctr.c new file mode 100644 index 000000000000..451113c4d162 --- /dev/null +++ b/providers/implementations/rands/drbg_ctr.c @@ -0,0 +1,755 @@ +/* + * Copyright 2011-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/rand.h> +#include <openssl/aes.h> +#include <openssl/proverr.h> +#include "crypto/modes.h" +#include "internal/thread_once.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "drbg_local.h" + +static OSSL_FUNC_rand_newctx_fn drbg_ctr_new_wrapper; +static OSSL_FUNC_rand_freectx_fn drbg_ctr_free; +static OSSL_FUNC_rand_instantiate_fn drbg_ctr_instantiate_wrapper; +static OSSL_FUNC_rand_uninstantiate_fn drbg_ctr_uninstantiate_wrapper; +static OSSL_FUNC_rand_generate_fn drbg_ctr_generate_wrapper; +static OSSL_FUNC_rand_reseed_fn drbg_ctr_reseed_wrapper; +static OSSL_FUNC_rand_settable_ctx_params_fn drbg_ctr_settable_ctx_params; +static OSSL_FUNC_rand_set_ctx_params_fn drbg_ctr_set_ctx_params; +static OSSL_FUNC_rand_gettable_ctx_params_fn drbg_ctr_gettable_ctx_params; +static OSSL_FUNC_rand_get_ctx_params_fn drbg_ctr_get_ctx_params; +static OSSL_FUNC_rand_verify_zeroization_fn drbg_ctr_verify_zeroization; + +/* + * The state of a DRBG AES-CTR. + */ +typedef struct rand_drbg_ctr_st { + EVP_CIPHER_CTX *ctx_ecb; + EVP_CIPHER_CTX *ctx_ctr; + EVP_CIPHER_CTX *ctx_df; + EVP_CIPHER *cipher_ecb; + EVP_CIPHER *cipher_ctr; + size_t keylen; + int use_df; + unsigned char K[32]; + unsigned char V[16]; + /* Temporary block storage used by ctr_df */ + unsigned char bltmp[16]; + size_t bltmp_pos; + unsigned char KX[48]; +} PROV_DRBG_CTR; + +/* + * Implementation of NIST SP 800-90A CTR DRBG. + */ +static void inc_128(PROV_DRBG_CTR *ctr) +{ + unsigned char *p = &ctr->V[0]; + u32 n = 16, c = 1; + + do { + --n; + c += p[n]; + p[n] = (u8)c; + c >>= 8; + } while (n); +} + +static void ctr_XOR(PROV_DRBG_CTR *ctr, const unsigned char *in, size_t inlen) +{ + size_t i, n; + + if (in == NULL || inlen == 0) + return; + + /* + * Any zero padding will have no effect on the result as we + * are XORing. So just process however much input we have. + */ + n = inlen < ctr->keylen ? inlen : ctr->keylen; + for (i = 0; i < n; i++) + ctr->K[i] ^= in[i]; + if (inlen <= ctr->keylen) + return; + + n = inlen - ctr->keylen; + if (n > 16) { + /* Should never happen */ + n = 16; + } + for (i = 0; i < n; i++) + ctr->V[i] ^= in[i + ctr->keylen]; +} + +/* + * Process a complete block using BCC algorithm of SP 800-90A 10.3.3 + */ +__owur static int ctr_BCC_block(PROV_DRBG_CTR *ctr, unsigned char *out, + const unsigned char *in, int len) +{ + int i, outlen = AES_BLOCK_SIZE; + + for (i = 0; i < len; i++) + out[i] ^= in[i]; + + if (!EVP_CipherUpdate(ctr->ctx_df, out, &outlen, out, len) + || outlen != len) + return 0; + return 1; +} + + +/* + * Handle several BCC operations for as much data as we need for K and X + */ +__owur static int ctr_BCC_blocks(PROV_DRBG_CTR *ctr, const unsigned char *in) +{ + unsigned char in_tmp[48]; + unsigned char num_of_blk = 2; + + memcpy(in_tmp, in, 16); + memcpy(in_tmp + 16, in, 16); + if (ctr->keylen != 16) { + memcpy(in_tmp + 32, in, 16); + num_of_blk = 3; + } + return ctr_BCC_block(ctr, ctr->KX, in_tmp, AES_BLOCK_SIZE * num_of_blk); +} + +/* + * Initialise BCC blocks: these have the value 0,1,2 in leftmost positions: + * see 10.3.1 stage 7. + */ +__owur static int ctr_BCC_init(PROV_DRBG_CTR *ctr) +{ + unsigned char bltmp[48] = {0}; + unsigned char num_of_blk; + + memset(ctr->KX, 0, 48); + num_of_blk = ctr->keylen == 16 ? 2 : 3; + bltmp[(AES_BLOCK_SIZE * 1) + 3] = 1; + bltmp[(AES_BLOCK_SIZE * 2) + 3] = 2; + return ctr_BCC_block(ctr, ctr->KX, bltmp, num_of_blk * AES_BLOCK_SIZE); +} + +/* + * Process several blocks into BCC algorithm, some possibly partial + */ +__owur static int ctr_BCC_update(PROV_DRBG_CTR *ctr, + const unsigned char *in, size_t inlen) +{ + if (in == NULL || inlen == 0) + return 1; + + /* If we have partial block handle it first */ + if (ctr->bltmp_pos) { + size_t left = 16 - ctr->bltmp_pos; + + /* If we now have a complete block process it */ + if (inlen >= left) { + memcpy(ctr->bltmp + ctr->bltmp_pos, in, left); + if (!ctr_BCC_blocks(ctr, ctr->bltmp)) + return 0; + ctr->bltmp_pos = 0; + inlen -= left; + in += left; + } + } + + /* Process zero or more complete blocks */ + for (; inlen >= 16; in += 16, inlen -= 16) { + if (!ctr_BCC_blocks(ctr, in)) + return 0; + } + + /* Copy any remaining partial block to the temporary buffer */ + if (inlen > 0) { + memcpy(ctr->bltmp + ctr->bltmp_pos, in, inlen); + ctr->bltmp_pos += inlen; + } + return 1; +} + +__owur static int ctr_BCC_final(PROV_DRBG_CTR *ctr) +{ + if (ctr->bltmp_pos) { + memset(ctr->bltmp + ctr->bltmp_pos, 0, 16 - ctr->bltmp_pos); + if (!ctr_BCC_blocks(ctr, ctr->bltmp)) + return 0; + } + return 1; +} + +__owur static int ctr_df(PROV_DRBG_CTR *ctr, + const unsigned char *in1, size_t in1len, + const unsigned char *in2, size_t in2len, + const unsigned char *in3, size_t in3len) +{ + static unsigned char c80 = 0x80; + size_t inlen; + unsigned char *p = ctr->bltmp; + int outlen = AES_BLOCK_SIZE; + + if (!ctr_BCC_init(ctr)) + return 0; + if (in1 == NULL) + in1len = 0; + if (in2 == NULL) + in2len = 0; + if (in3 == NULL) + in3len = 0; + inlen = in1len + in2len + in3len; + /* Initialise L||N in temporary block */ + *p++ = (inlen >> 24) & 0xff; + *p++ = (inlen >> 16) & 0xff; + *p++ = (inlen >> 8) & 0xff; + *p++ = inlen & 0xff; + + /* NB keylen is at most 32 bytes */ + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p = (unsigned char)((ctr->keylen + 16) & 0xff); + ctr->bltmp_pos = 8; + if (!ctr_BCC_update(ctr, in1, in1len) + || !ctr_BCC_update(ctr, in2, in2len) + || !ctr_BCC_update(ctr, in3, in3len) + || !ctr_BCC_update(ctr, &c80, 1) + || !ctr_BCC_final(ctr)) + return 0; + /* Set up key K */ + if (!EVP_CipherInit_ex(ctr->ctx_ecb, NULL, NULL, ctr->KX, NULL, -1)) + return 0; + /* X follows key K */ + if (!EVP_CipherUpdate(ctr->ctx_ecb, ctr->KX, &outlen, ctr->KX + ctr->keylen, + AES_BLOCK_SIZE) + || outlen != AES_BLOCK_SIZE) + return 0; + if (!EVP_CipherUpdate(ctr->ctx_ecb, ctr->KX + 16, &outlen, ctr->KX, + AES_BLOCK_SIZE) + || outlen != AES_BLOCK_SIZE) + return 0; + if (ctr->keylen != 16) + if (!EVP_CipherUpdate(ctr->ctx_ecb, ctr->KX + 32, &outlen, + ctr->KX + 16, AES_BLOCK_SIZE) + || outlen != AES_BLOCK_SIZE) + return 0; + return 1; +} + +/* + * NB the no-df Update in SP800-90A specifies a constant input length + * of seedlen, however other uses of this algorithm pad the input with + * zeroes if necessary and have up to two parameters XORed together, + * so we handle both cases in this function instead. + */ +__owur static int ctr_update(PROV_DRBG *drbg, + const unsigned char *in1, size_t in1len, + const unsigned char *in2, size_t in2len, + const unsigned char *nonce, size_t noncelen) +{ + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + int outlen = AES_BLOCK_SIZE; + unsigned char V_tmp[48], out[48]; + unsigned char len; + + /* correct key is already set up. */ + memcpy(V_tmp, ctr->V, 16); + inc_128(ctr); + memcpy(V_tmp + 16, ctr->V, 16); + if (ctr->keylen == 16) { + len = 32; + } else { + inc_128(ctr); + memcpy(V_tmp + 32, ctr->V, 16); + len = 48; + } + if (!EVP_CipherUpdate(ctr->ctx_ecb, out, &outlen, V_tmp, len) + || outlen != len) + return 0; + memcpy(ctr->K, out, ctr->keylen); + memcpy(ctr->V, out + ctr->keylen, 16); + + if (ctr->use_df) { + /* If no input reuse existing derived value */ + if (in1 != NULL || nonce != NULL || in2 != NULL) + if (!ctr_df(ctr, in1, in1len, nonce, noncelen, in2, in2len)) + return 0; + /* If this a reuse input in1len != 0 */ + if (in1len) + ctr_XOR(ctr, ctr->KX, drbg->seedlen); + } else { + ctr_XOR(ctr, in1, in1len); + ctr_XOR(ctr, in2, in2len); + } + + if (!EVP_CipherInit_ex(ctr->ctx_ecb, NULL, NULL, ctr->K, NULL, -1) + || !EVP_CipherInit_ex(ctr->ctx_ctr, NULL, NULL, ctr->K, NULL, -1)) + return 0; + return 1; +} + +static int drbg_ctr_instantiate(PROV_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *nonce, size_t noncelen, + const unsigned char *pers, size_t perslen) +{ + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + + if (entropy == NULL) + return 0; + + memset(ctr->K, 0, sizeof(ctr->K)); + memset(ctr->V, 0, sizeof(ctr->V)); + if (!EVP_CipherInit_ex(ctr->ctx_ecb, NULL, NULL, ctr->K, NULL, -1)) + return 0; + + inc_128(ctr); + if (!ctr_update(drbg, entropy, entropylen, pers, perslen, nonce, noncelen)) + return 0; + return 1; +} + +static int drbg_ctr_instantiate_wrapper(void *vdrbg, unsigned int strength, + int prediction_resistance, + const unsigned char *pstr, + size_t pstr_len, + const OSSL_PARAM params[]) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + if (!ossl_prov_is_running() || !drbg_ctr_set_ctx_params(drbg, params)) + return 0; + return ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance, + pstr, pstr_len); +} + +static int drbg_ctr_reseed(PROV_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *adin, size_t adinlen) +{ + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + + if (entropy == NULL) + return 0; + + inc_128(ctr); + if (!ctr_update(drbg, entropy, entropylen, adin, adinlen, NULL, 0)) + return 0; + return 1; +} + +static int drbg_ctr_reseed_wrapper(void *vdrbg, int prediction_resistance, + const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return ossl_prov_drbg_reseed(drbg, prediction_resistance, ent, ent_len, + adin, adin_len); +} + +static void ctr96_inc(unsigned char *counter) +{ + u32 n = 12, c = 1; + + do { + --n; + c += counter[n]; + counter[n] = (u8)c; + c >>= 8; + } while (n); +} + +static int drbg_ctr_generate(PROV_DRBG *drbg, + unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adinlen) +{ + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + unsigned int ctr32, blocks; + int outl, buflen; + + if (adin != NULL && adinlen != 0) { + inc_128(ctr); + + if (!ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0)) + return 0; + /* This means we reuse derived value */ + if (ctr->use_df) { + adin = NULL; + adinlen = 1; + } + } else { + adinlen = 0; + } + + inc_128(ctr); + + if (outlen == 0) { + inc_128(ctr); + + if (!ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0)) + return 0; + return 1; + } + + memset(out, 0, outlen); + + do { + if (!EVP_CipherInit_ex(ctr->ctx_ctr, + NULL, NULL, NULL, ctr->V, -1)) + return 0; + + /*- + * outlen has type size_t while EVP_CipherUpdate takes an + * int argument and thus cannot be guaranteed to process more + * than 2^31-1 bytes at a time. We process such huge generate + * requests in 2^30 byte chunks, which is the greatest multiple + * of AES block size lower than or equal to 2^31-1. + */ + buflen = outlen > (1U << 30) ? (1U << 30) : outlen; + blocks = (buflen + 15) / 16; + + ctr32 = GETU32(ctr->V + 12) + blocks; + if (ctr32 < blocks) { + /* 32-bit counter overflow into V. */ + if (ctr32 != 0) { + blocks -= ctr32; + buflen = blocks * 16; + ctr32 = 0; + } + ctr96_inc(ctr->V); + } + PUTU32(ctr->V + 12, ctr32); + + if (!EVP_CipherUpdate(ctr->ctx_ctr, out, &outl, out, buflen) + || outl != buflen) + return 0; + + out += buflen; + outlen -= buflen; + } while (outlen); + + if (!ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0)) + return 0; + return 1; +} + +static int drbg_ctr_generate_wrapper + (void *vdrbg, unsigned char *out, size_t outlen, + unsigned int strength, int prediction_resistance, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return ossl_prov_drbg_generate(drbg, out, outlen, strength, + prediction_resistance, adin, adin_len); +} + +static int drbg_ctr_uninstantiate(PROV_DRBG *drbg) +{ + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + + OPENSSL_cleanse(ctr->K, sizeof(ctr->K)); + OPENSSL_cleanse(ctr->V, sizeof(ctr->V)); + OPENSSL_cleanse(ctr->bltmp, sizeof(ctr->bltmp)); + OPENSSL_cleanse(ctr->KX, sizeof(ctr->KX)); + ctr->bltmp_pos = 0; + return ossl_prov_drbg_uninstantiate(drbg); +} + +static int drbg_ctr_uninstantiate_wrapper(void *vdrbg) +{ + return drbg_ctr_uninstantiate((PROV_DRBG *)vdrbg); +} + +static int drbg_ctr_verify_zeroization(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + + PROV_DRBG_VERYIFY_ZEROIZATION(ctr->K); + PROV_DRBG_VERYIFY_ZEROIZATION(ctr->V); + PROV_DRBG_VERYIFY_ZEROIZATION(ctr->bltmp); + PROV_DRBG_VERYIFY_ZEROIZATION(ctr->KX); + if (ctr->bltmp_pos != 0) + return 0; + return 1; +} + +static int drbg_ctr_init_lengths(PROV_DRBG *drbg) +{ + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + int res = 1; + + /* Maximum number of bits per request = 2^19 = 2^16 bytes */ + drbg->max_request = 1 << 16; + if (ctr->use_df) { + drbg->min_entropylen = 0; + drbg->max_entropylen = DRBG_MAX_LENGTH; + drbg->min_noncelen = 0; + drbg->max_noncelen = DRBG_MAX_LENGTH; + drbg->max_perslen = DRBG_MAX_LENGTH; + drbg->max_adinlen = DRBG_MAX_LENGTH; + + if (ctr->keylen > 0) { + drbg->min_entropylen = ctr->keylen; + drbg->min_noncelen = drbg->min_entropylen / 2; + } + } else { + const size_t len = ctr->keylen > 0 ? drbg->seedlen : DRBG_MAX_LENGTH; + + drbg->min_entropylen = len; + drbg->max_entropylen = len; + /* Nonce not used */ + drbg->min_noncelen = 0; + drbg->max_noncelen = 0; + drbg->max_perslen = len; + drbg->max_adinlen = len; + } + return res; +} + +static int drbg_ctr_init(PROV_DRBG *drbg) +{ + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + size_t keylen; + + if (ctr->cipher_ctr == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CIPHER); + return 0; + } + ctr->keylen = keylen = EVP_CIPHER_get_key_length(ctr->cipher_ctr); + if (ctr->ctx_ecb == NULL) + ctr->ctx_ecb = EVP_CIPHER_CTX_new(); + if (ctr->ctx_ctr == NULL) + ctr->ctx_ctr = EVP_CIPHER_CTX_new(); + if (ctr->ctx_ecb == NULL || ctr->ctx_ctr == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_CipherInit_ex(ctr->ctx_ecb, + ctr->cipher_ecb, NULL, NULL, NULL, 1) + || !EVP_CipherInit_ex(ctr->ctx_ctr, + ctr->cipher_ctr, NULL, NULL, NULL, 1)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_INITIALISE_CIPHERS); + goto err; + } + + drbg->strength = keylen * 8; + drbg->seedlen = keylen + 16; + + if (ctr->use_df) { + /* df initialisation */ + static const unsigned char df_key[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + + if (ctr->ctx_df == NULL) + ctr->ctx_df = EVP_CIPHER_CTX_new(); + if (ctr->ctx_df == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + /* Set key schedule for df_key */ + if (!EVP_CipherInit_ex(ctr->ctx_df, + ctr->cipher_ecb, NULL, df_key, NULL, 1)) { + ERR_raise(ERR_LIB_PROV, PROV_R_DERIVATION_FUNCTION_INIT_FAILED); + goto err; + } + } + return drbg_ctr_init_lengths(drbg); + +err: + EVP_CIPHER_CTX_free(ctr->ctx_ecb); + EVP_CIPHER_CTX_free(ctr->ctx_ctr); + ctr->ctx_ecb = ctr->ctx_ctr = NULL; + return 0; +} + +static int drbg_ctr_new(PROV_DRBG *drbg) +{ + PROV_DRBG_CTR *ctr; + + ctr = OPENSSL_secure_zalloc(sizeof(*ctr)); + if (ctr == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + ctr->use_df = 1; + drbg->data = ctr; + return drbg_ctr_init_lengths(drbg); +} + +static void *drbg_ctr_new_wrapper(void *provctx, void *parent, + const OSSL_DISPATCH *parent_dispatch) +{ + return ossl_rand_drbg_new(provctx, parent, parent_dispatch, &drbg_ctr_new, + &drbg_ctr_instantiate, &drbg_ctr_uninstantiate, + &drbg_ctr_reseed, &drbg_ctr_generate); +} + +static void drbg_ctr_free(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_CTR *ctr; + + if (drbg != NULL && (ctr = (PROV_DRBG_CTR *)drbg->data) != NULL) { + EVP_CIPHER_CTX_free(ctr->ctx_ecb); + EVP_CIPHER_CTX_free(ctr->ctx_ctr); + EVP_CIPHER_CTX_free(ctr->ctx_df); + EVP_CIPHER_free(ctr->cipher_ecb); + EVP_CIPHER_free(ctr->cipher_ctr); + + OPENSSL_secure_clear_free(ctr, sizeof(*ctr)); + } + ossl_rand_drbg_free(drbg); +} + +static int drbg_ctr_get_ctx_params(void *vdrbg, OSSL_PARAM params[]) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_USE_DF); + if (p != NULL && !OSSL_PARAM_set_int(p, ctr->use_df)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_CIPHER); + if (p != NULL) { + if (ctr->cipher_ctr == NULL + || !OSSL_PARAM_set_utf8_string(p, + EVP_CIPHER_get0_name(ctr->cipher_ctr))) + return 0; + } + + return ossl_drbg_get_ctx_params(drbg, params); +} + +static const OSSL_PARAM *drbg_ctr_gettable_ctx_params(ossl_unused void *vctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_int(OSSL_DRBG_PARAM_USE_DF, NULL), + OSSL_PARAM_DRBG_GETTABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +static int drbg_ctr_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_DRBG *ctx = (PROV_DRBG *)vctx; + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)ctx->data; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const OSSL_PARAM *p; + char *ecb; + const char *propquery = NULL; + int i, cipher_init = 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_USE_DF)) != NULL + && OSSL_PARAM_get_int(p, &i)) { + /* FIPS errors out in the drbg_ctr_init() call later */ + ctr->use_df = i != 0; + cipher_init = 1; + } + + if ((p = OSSL_PARAM_locate_const(params, + OSSL_DRBG_PARAM_PROPERTIES)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + propquery = (const char *)p->data; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_CIPHER)) != NULL) { + const char *base = (const char *)p->data; + size_t ctr_str_len = sizeof("CTR") - 1; + size_t ecb_str_len = sizeof("ECB") - 1; + + if (p->data_type != OSSL_PARAM_UTF8_STRING + || p->data_size < ctr_str_len) + return 0; + if (OPENSSL_strcasecmp("CTR", base + p->data_size - ctr_str_len) != 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_REQUIRE_CTR_MODE_CIPHER); + return 0; + } + if ((ecb = OPENSSL_strndup(base, p->data_size)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + strcpy(ecb + p->data_size - ecb_str_len, "ECB"); + EVP_CIPHER_free(ctr->cipher_ecb); + EVP_CIPHER_free(ctr->cipher_ctr); + ctr->cipher_ctr = EVP_CIPHER_fetch(libctx, base, propquery); + ctr->cipher_ecb = EVP_CIPHER_fetch(libctx, ecb, propquery); + OPENSSL_free(ecb); + if (ctr->cipher_ctr == NULL || ctr->cipher_ecb == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_FIND_CIPHERS); + return 0; + } + cipher_init = 1; + } + + if (cipher_init && !drbg_ctr_init(ctx)) + return 0; + + return ossl_drbg_set_ctx_params(ctx, params); +} + +static const OSSL_PARAM *drbg_ctr_settable_ctx_params(ossl_unused void *vctx, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_int(OSSL_DRBG_PARAM_USE_DF, NULL), + OSSL_PARAM_DRBG_SETTABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +const OSSL_DISPATCH ossl_drbg_ctr_functions[] = { + { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))drbg_ctr_new_wrapper }, + { OSSL_FUNC_RAND_FREECTX, (void(*)(void))drbg_ctr_free }, + { OSSL_FUNC_RAND_INSTANTIATE, + (void(*)(void))drbg_ctr_instantiate_wrapper }, + { OSSL_FUNC_RAND_UNINSTANTIATE, + (void(*)(void))drbg_ctr_uninstantiate_wrapper }, + { OSSL_FUNC_RAND_GENERATE, (void(*)(void))drbg_ctr_generate_wrapper }, + { OSSL_FUNC_RAND_RESEED, (void(*)(void))drbg_ctr_reseed_wrapper }, + { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))ossl_drbg_enable_locking }, + { OSSL_FUNC_RAND_LOCK, (void(*)(void))ossl_drbg_lock }, + { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))ossl_drbg_unlock }, + { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS, + (void(*)(void))drbg_ctr_settable_ctx_params }, + { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_ctr_set_ctx_params }, + { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, + (void(*)(void))drbg_ctr_gettable_ctx_params }, + { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_ctr_get_ctx_params }, + { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, + (void(*)(void))drbg_ctr_verify_zeroization }, + { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))ossl_drbg_get_seed }, + { OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))ossl_drbg_clear_seed }, + { 0, NULL } +}; diff --git a/providers/implementations/rands/drbg_hash.c b/providers/implementations/rands/drbg_hash.c new file mode 100644 index 000000000000..6deb0a29256b --- /dev/null +++ b/providers/implementations/rands/drbg_hash.c @@ -0,0 +1,529 @@ +/* + * Copyright 2011-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <openssl/sha.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/rand.h> +#include <openssl/core_dispatch.h> +#include <openssl/proverr.h> +#include "internal/thread_once.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "prov/provider_util.h" +#include "prov/implementations.h" +#include "drbg_local.h" + +static OSSL_FUNC_rand_newctx_fn drbg_hash_new_wrapper; +static OSSL_FUNC_rand_freectx_fn drbg_hash_free; +static OSSL_FUNC_rand_instantiate_fn drbg_hash_instantiate_wrapper; +static OSSL_FUNC_rand_uninstantiate_fn drbg_hash_uninstantiate_wrapper; +static OSSL_FUNC_rand_generate_fn drbg_hash_generate_wrapper; +static OSSL_FUNC_rand_reseed_fn drbg_hash_reseed_wrapper; +static OSSL_FUNC_rand_settable_ctx_params_fn drbg_hash_settable_ctx_params; +static OSSL_FUNC_rand_set_ctx_params_fn drbg_hash_set_ctx_params; +static OSSL_FUNC_rand_gettable_ctx_params_fn drbg_hash_gettable_ctx_params; +static OSSL_FUNC_rand_get_ctx_params_fn drbg_hash_get_ctx_params; +static OSSL_FUNC_rand_verify_zeroization_fn drbg_hash_verify_zeroization; + +/* 888 bits from SP800-90Ar1 10.1 table 2 */ +#define HASH_PRNG_MAX_SEEDLEN (888/8) + +/* 440 bits from SP800-90Ar1 10.1 table 2 */ +#define HASH_PRNG_SMALL_SEEDLEN (440/8) + +/* Determine what seedlen to use based on the block length */ +#define MAX_BLOCKLEN_USING_SMALL_SEEDLEN (256/8) +#define INBYTE_IGNORE ((unsigned char)0xFF) + +typedef struct rand_drbg_hash_st { + PROV_DIGEST digest; + EVP_MD_CTX *ctx; + size_t blocklen; + unsigned char V[HASH_PRNG_MAX_SEEDLEN]; + unsigned char C[HASH_PRNG_MAX_SEEDLEN]; + /* Temporary value storage: should always exceed max digest length */ + unsigned char vtmp[HASH_PRNG_MAX_SEEDLEN]; +} PROV_DRBG_HASH; + +/* + * SP800-90Ar1 10.3.1 Derivation function using a Hash Function (Hash_df). + * The input string used is composed of: + * inbyte - An optional leading byte (ignore if equal to INBYTE_IGNORE) + * in - input string 1 (A Non NULL value). + * in2 - optional input string (Can be NULL). + * in3 - optional input string (Can be NULL). + * These are concatenated as part of the DigestUpdate process. + */ +static int hash_df(PROV_DRBG *drbg, unsigned char *out, + const unsigned char inbyte, + const unsigned char *in, size_t inlen, + const unsigned char *in2, size_t in2len, + const unsigned char *in3, size_t in3len) +{ + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; + EVP_MD_CTX *ctx = hash->ctx; + unsigned char *vtmp = hash->vtmp; + /* tmp = counter || num_bits_returned || [inbyte] */ + unsigned char tmp[1 + 4 + 1]; + int tmp_sz = 0; + size_t outlen = drbg->seedlen; + size_t num_bits_returned = outlen * 8; + /* + * No need to check outlen size here, as the standard only ever needs + * seedlen bytes which is always less than the maximum permitted. + */ + + /* (Step 3) counter = 1 (tmp[0] is the 8 bit counter) */ + tmp[tmp_sz++] = 1; + /* tmp[1..4] is the fixed 32 bit no_of_bits_to_return */ + tmp[tmp_sz++] = (unsigned char)((num_bits_returned >> 24) & 0xff); + tmp[tmp_sz++] = (unsigned char)((num_bits_returned >> 16) & 0xff); + tmp[tmp_sz++] = (unsigned char)((num_bits_returned >> 8) & 0xff); + tmp[tmp_sz++] = (unsigned char)(num_bits_returned & 0xff); + /* Tack the additional input byte onto the end of tmp if it exists */ + if (inbyte != INBYTE_IGNORE) + tmp[tmp_sz++] = inbyte; + + /* (Step 4) */ + for (;;) { + /* + * (Step 4.1) out = out || Hash(tmp || in || [in2] || [in3]) + * (where tmp = counter || num_bits_returned || [inbyte]) + */ + if (!(EVP_DigestInit_ex(ctx, ossl_prov_digest_md(&hash->digest), NULL) + && EVP_DigestUpdate(ctx, tmp, tmp_sz) + && EVP_DigestUpdate(ctx, in, inlen) + && (in2 == NULL || EVP_DigestUpdate(ctx, in2, in2len)) + && (in3 == NULL || EVP_DigestUpdate(ctx, in3, in3len)))) + return 0; + + if (outlen < hash->blocklen) { + if (!EVP_DigestFinal(ctx, vtmp, NULL)) + return 0; + memcpy(out, vtmp, outlen); + OPENSSL_cleanse(vtmp, hash->blocklen); + break; + } else if(!EVP_DigestFinal(ctx, out, NULL)) { + return 0; + } + + outlen -= hash->blocklen; + if (outlen == 0) + break; + /* (Step 4.2) counter++ */ + tmp[0]++; + out += hash->blocklen; + } + return 1; +} + +/* Helper function that just passes 2 input parameters to hash_df() */ +static int hash_df1(PROV_DRBG *drbg, unsigned char *out, + const unsigned char in_byte, + const unsigned char *in1, size_t in1len) +{ + return hash_df(drbg, out, in_byte, in1, in1len, NULL, 0, NULL, 0); +} + +/* + * Add 2 byte buffers together. The first elements in each buffer are the top + * most bytes. The result is stored in the dst buffer. + * The final carry is ignored i.e: dst = (dst + in) mod (2^seedlen_bits). + * where dst size is drbg->seedlen, and inlen <= drbg->seedlen. + */ +static int add_bytes(PROV_DRBG *drbg, unsigned char *dst, + unsigned char *in, size_t inlen) +{ + size_t i; + int result; + const unsigned char *add; + unsigned char carry = 0, *d; + + assert(drbg->seedlen >= 1 && inlen >= 1 && inlen <= drbg->seedlen); + + d = &dst[drbg->seedlen - 1]; + add = &in[inlen - 1]; + + for (i = inlen; i > 0; i--, d--, add--) { + result = *d + *add + carry; + carry = (unsigned char)(result >> 8); + *d = (unsigned char)(result & 0xff); + } + + if (carry != 0) { + /* Add the carry to the top of the dst if inlen is not the same size */ + for (i = drbg->seedlen - inlen; i > 0; --i, d--) { + *d += 1; /* Carry can only be 1 */ + if (*d != 0) /* exit if carry doesnt propagate to the next byte */ + break; + } + } + return 1; +} + +/* V = (V + Hash(inbyte || V || [additional_input]) mod (2^seedlen) */ +static int add_hash_to_v(PROV_DRBG *drbg, unsigned char inbyte, + const unsigned char *adin, size_t adinlen) +{ + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; + EVP_MD_CTX *ctx = hash->ctx; + + return EVP_DigestInit_ex(ctx, ossl_prov_digest_md(&hash->digest), NULL) + && EVP_DigestUpdate(ctx, &inbyte, 1) + && EVP_DigestUpdate(ctx, hash->V, drbg->seedlen) + && (adin == NULL || EVP_DigestUpdate(ctx, adin, adinlen)) + && EVP_DigestFinal(ctx, hash->vtmp, NULL) + && add_bytes(drbg, hash->V, hash->vtmp, hash->blocklen); +} + +/* + * The Hashgen() as listed in SP800-90Ar1 10.1.1.4 Hash_DRBG_Generate_Process. + * + * drbg contains the current value of V. + * outlen is the requested number of bytes. + * out is a buffer to return the generated bits. + * + * The algorithm to generate the bits is: + * data = V + * w = NULL + * for (i = 1 to m) { + * W = W || Hash(data) + * data = (data + 1) mod (2^seedlen) + * } + * out = Leftmost(W, outlen) + * + * Returns zero if an error occurs otherwise it returns 1. + */ +static int hash_gen(PROV_DRBG *drbg, unsigned char *out, size_t outlen) +{ + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; + unsigned char one = 1; + + if (outlen == 0) + return 1; + memcpy(hash->vtmp, hash->V, drbg->seedlen); + for(;;) { + if (!EVP_DigestInit_ex(hash->ctx, ossl_prov_digest_md(&hash->digest), + NULL) + || !EVP_DigestUpdate(hash->ctx, hash->vtmp, drbg->seedlen)) + return 0; + + if (outlen < hash->blocklen) { + if (!EVP_DigestFinal(hash->ctx, hash->vtmp, NULL)) + return 0; + memcpy(out, hash->vtmp, outlen); + return 1; + } else { + if (!EVP_DigestFinal(hash->ctx, out, NULL)) + return 0; + outlen -= hash->blocklen; + if (outlen == 0) + break; + out += hash->blocklen; + } + add_bytes(drbg, hash->vtmp, &one, 1); + } + return 1; +} + +/* + * SP800-90Ar1 10.1.1.2 Hash_DRBG_Instantiate_Process: + * + * ent is entropy input obtained from a randomness source of length ent_len. + * nonce is a string of bytes of length nonce_len. + * pstr is a personalization string received from an application. May be NULL. + * + * Returns zero if an error occurs otherwise it returns 1. + */ +static int drbg_hash_instantiate(PROV_DRBG *drbg, + const unsigned char *ent, size_t ent_len, + const unsigned char *nonce, size_t nonce_len, + const unsigned char *pstr, size_t pstr_len) +{ + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; + + EVP_MD_CTX_free(hash->ctx); + hash->ctx = EVP_MD_CTX_new(); + + /* (Step 1-3) V = Hash_df(entropy||nonce||pers, seedlen) */ + return hash->ctx != NULL + && hash_df(drbg, hash->V, INBYTE_IGNORE, + ent, ent_len, nonce, nonce_len, pstr, pstr_len) + /* (Step 4) C = Hash_df(0x00||V, seedlen) */ + && hash_df1(drbg, hash->C, 0x00, hash->V, drbg->seedlen); +} + +static int drbg_hash_instantiate_wrapper(void *vdrbg, unsigned int strength, + int prediction_resistance, + const unsigned char *pstr, + size_t pstr_len, + const OSSL_PARAM params[]) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + if (!ossl_prov_is_running() || !drbg_hash_set_ctx_params(drbg, params)) + return 0; + return ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance, + pstr, pstr_len); +} + +/* + * SP800-90Ar1 10.1.1.3 Hash_DRBG_Reseed_Process: + * + * ent is entropy input bytes obtained from a randomness source. + * addin is additional input received from an application. May be NULL. + * + * Returns zero if an error occurs otherwise it returns 1. + */ +static int drbg_hash_reseed(PROV_DRBG *drbg, + const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; + + /* (Step 1-2) V = Hash_df(0x01 || V || entropy_input || additional_input) */ + /* V about to be updated so use C as output instead */ + if (!hash_df(drbg, hash->C, 0x01, hash->V, drbg->seedlen, ent, ent_len, + adin, adin_len)) + return 0; + memcpy(hash->V, hash->C, drbg->seedlen); + /* (Step 4) C = Hash_df(0x00||V, seedlen) */ + return hash_df1(drbg, hash->C, 0x00, hash->V, drbg->seedlen); +} + +static int drbg_hash_reseed_wrapper(void *vdrbg, int prediction_resistance, + const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return ossl_prov_drbg_reseed(drbg, prediction_resistance, ent, ent_len, + adin, adin_len); +} + +/* + * SP800-90Ar1 10.1.1.4 Hash_DRBG_Generate_Process: + * + * Generates pseudo random bytes using the drbg. + * out is a buffer to fill with outlen bytes of pseudo random data. + * addin is additional input received from an application. May be NULL. + * + * Returns zero if an error occurs otherwise it returns 1. + */ +static int drbg_hash_generate(PROV_DRBG *drbg, + unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; + unsigned char counter[4]; + int reseed_counter = drbg->generate_counter; + + counter[0] = (unsigned char)((reseed_counter >> 24) & 0xff); + counter[1] = (unsigned char)((reseed_counter >> 16) & 0xff); + counter[2] = (unsigned char)((reseed_counter >> 8) & 0xff); + counter[3] = (unsigned char)(reseed_counter & 0xff); + + return hash->ctx != NULL + && (adin == NULL + /* (Step 2) if adin != NULL then V = V + Hash(0x02||V||adin) */ + || adin_len == 0 + || add_hash_to_v(drbg, 0x02, adin, adin_len)) + /* (Step 3) Hashgen(outlen, V) */ + && hash_gen(drbg, out, outlen) + /* (Step 4/5) H = V = (V + Hash(0x03||V) mod (2^seedlen_bits) */ + && add_hash_to_v(drbg, 0x03, NULL, 0) + /* (Step 5) V = (V + H + C + reseed_counter) mod (2^seedlen_bits) */ + /* V = (V + C) mod (2^seedlen_bits) */ + && add_bytes(drbg, hash->V, hash->C, drbg->seedlen) + /* V = (V + reseed_counter) mod (2^seedlen_bits) */ + && add_bytes(drbg, hash->V, counter, 4); +} + +static int drbg_hash_generate_wrapper + (void *vdrbg, unsigned char *out, size_t outlen, unsigned int strength, + int prediction_resistance, const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return ossl_prov_drbg_generate(drbg, out, outlen, strength, + prediction_resistance, adin, adin_len); +} + +static int drbg_hash_uninstantiate(PROV_DRBG *drbg) +{ + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; + + OPENSSL_cleanse(hash->V, sizeof(hash->V)); + OPENSSL_cleanse(hash->C, sizeof(hash->C)); + OPENSSL_cleanse(hash->vtmp, sizeof(hash->vtmp)); + return ossl_prov_drbg_uninstantiate(drbg); +} + +static int drbg_hash_uninstantiate_wrapper(void *vdrbg) +{ + return drbg_hash_uninstantiate((PROV_DRBG *)vdrbg); +} + +static int drbg_hash_verify_zeroization(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; + + PROV_DRBG_VERYIFY_ZEROIZATION(hash->V); + PROV_DRBG_VERYIFY_ZEROIZATION(hash->C); + PROV_DRBG_VERYIFY_ZEROIZATION(hash->vtmp); + return 1; +} + +static int drbg_hash_new(PROV_DRBG *ctx) +{ + PROV_DRBG_HASH *hash; + + hash = OPENSSL_secure_zalloc(sizeof(*hash)); + if (hash == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + ctx->data = hash; + ctx->seedlen = HASH_PRNG_MAX_SEEDLEN; + ctx->max_entropylen = DRBG_MAX_LENGTH; + ctx->max_noncelen = DRBG_MAX_LENGTH; + ctx->max_perslen = DRBG_MAX_LENGTH; + ctx->max_adinlen = DRBG_MAX_LENGTH; + + /* Maximum number of bits per request = 2^19 = 2^16 bytes */ + ctx->max_request = 1 << 16; + return 1; +} + +static void *drbg_hash_new_wrapper(void *provctx, void *parent, + const OSSL_DISPATCH *parent_dispatch) +{ + return ossl_rand_drbg_new(provctx, parent, parent_dispatch, &drbg_hash_new, + &drbg_hash_instantiate, &drbg_hash_uninstantiate, + &drbg_hash_reseed, &drbg_hash_generate); +} + +static void drbg_hash_free(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_HASH *hash; + + if (drbg != NULL && (hash = (PROV_DRBG_HASH *)drbg->data) != NULL) { + EVP_MD_CTX_free(hash->ctx); + ossl_prov_digest_reset(&hash->digest); + OPENSSL_secure_clear_free(hash, sizeof(*hash)); + } + ossl_rand_drbg_free(drbg); +} + +static int drbg_hash_get_ctx_params(void *vdrbg, OSSL_PARAM params[]) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; + const EVP_MD *md; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_DIGEST); + if (p != NULL) { + md = ossl_prov_digest_md(&hash->digest); + if (md == NULL || !OSSL_PARAM_set_utf8_string(p, EVP_MD_get0_name(md))) + return 0; + } + + return ossl_drbg_get_ctx_params(drbg, params); +} + +static const OSSL_PARAM *drbg_hash_gettable_ctx_params(ossl_unused void *vctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_DRBG_GETTABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +static int drbg_hash_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_DRBG *ctx = (PROV_DRBG *)vctx; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)ctx->data; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const EVP_MD *md; + + if (!ossl_prov_digest_load_from_params(&hash->digest, params, libctx)) + return 0; + + md = ossl_prov_digest_md(&hash->digest); + if (md != NULL) { + if ((EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF) != 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED); + return 0; + } + + /* These are taken from SP 800-90 10.1 Table 2 */ + hash->blocklen = EVP_MD_get_size(md); + /* See SP800-57 Part1 Rev4 5.6.1 Table 3 */ + ctx->strength = 64 * (hash->blocklen >> 3); + if (ctx->strength > 256) + ctx->strength = 256; + if (hash->blocklen > MAX_BLOCKLEN_USING_SMALL_SEEDLEN) + ctx->seedlen = HASH_PRNG_MAX_SEEDLEN; + else + ctx->seedlen = HASH_PRNG_SMALL_SEEDLEN; + + ctx->min_entropylen = ctx->strength / 8; + ctx->min_noncelen = ctx->min_entropylen / 2; + } + + return ossl_drbg_set_ctx_params(ctx, params); +} + +static const OSSL_PARAM *drbg_hash_settable_ctx_params(ossl_unused void *vctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_DRBG_SETTABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +const OSSL_DISPATCH ossl_drbg_hash_functions[] = { + { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))drbg_hash_new_wrapper }, + { OSSL_FUNC_RAND_FREECTX, (void(*)(void))drbg_hash_free }, + { OSSL_FUNC_RAND_INSTANTIATE, + (void(*)(void))drbg_hash_instantiate_wrapper }, + { OSSL_FUNC_RAND_UNINSTANTIATE, + (void(*)(void))drbg_hash_uninstantiate_wrapper }, + { OSSL_FUNC_RAND_GENERATE, (void(*)(void))drbg_hash_generate_wrapper }, + { OSSL_FUNC_RAND_RESEED, (void(*)(void))drbg_hash_reseed_wrapper }, + { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))ossl_drbg_enable_locking }, + { OSSL_FUNC_RAND_LOCK, (void(*)(void))ossl_drbg_lock }, + { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))ossl_drbg_unlock }, + { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS, + (void(*)(void))drbg_hash_settable_ctx_params }, + { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_hash_set_ctx_params }, + { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, + (void(*)(void))drbg_hash_gettable_ctx_params }, + { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_hash_get_ctx_params }, + { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, + (void(*)(void))drbg_hash_verify_zeroization }, + { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))ossl_drbg_get_seed }, + { OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))ossl_drbg_clear_seed }, + { 0, NULL } +}; diff --git a/providers/implementations/rands/drbg_hmac.c b/providers/implementations/rands/drbg_hmac.c new file mode 100644 index 000000000000..e68465a78cd9 --- /dev/null +++ b/providers/implementations/rands/drbg_hmac.c @@ -0,0 +1,432 @@ +/* + * Copyright 2011-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/rand.h> +#include <openssl/proverr.h> +#include "prov/provider_util.h" +#include "internal/thread_once.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "drbg_local.h" + +static OSSL_FUNC_rand_newctx_fn drbg_hmac_new_wrapper; +static OSSL_FUNC_rand_freectx_fn drbg_hmac_free; +static OSSL_FUNC_rand_instantiate_fn drbg_hmac_instantiate_wrapper; +static OSSL_FUNC_rand_uninstantiate_fn drbg_hmac_uninstantiate_wrapper; +static OSSL_FUNC_rand_generate_fn drbg_hmac_generate_wrapper; +static OSSL_FUNC_rand_reseed_fn drbg_hmac_reseed_wrapper; +static OSSL_FUNC_rand_settable_ctx_params_fn drbg_hmac_settable_ctx_params; +static OSSL_FUNC_rand_set_ctx_params_fn drbg_hmac_set_ctx_params; +static OSSL_FUNC_rand_gettable_ctx_params_fn drbg_hmac_gettable_ctx_params; +static OSSL_FUNC_rand_get_ctx_params_fn drbg_hmac_get_ctx_params; +static OSSL_FUNC_rand_verify_zeroization_fn drbg_hmac_verify_zeroization; + +typedef struct rand_drbg_hmac_st { + EVP_MAC_CTX *ctx; /* H(x) = HMAC_hash OR H(x) = KMAC */ + PROV_DIGEST digest; /* H(x) = hash(x) */ + size_t blocklen; + unsigned char K[EVP_MAX_MD_SIZE]; + unsigned char V[EVP_MAX_MD_SIZE]; +} PROV_DRBG_HMAC; + +/* + * Called twice by SP800-90Ar1 10.1.2.2 HMAC_DRBG_Update_Process. + * + * hmac is an object that holds the input/output Key and Value (K and V). + * inbyte is 0x00 on the first call and 0x01 on the second call. + * in1, in2, in3 are optional inputs that can be NULL. + * in1len, in2len, in3len are the lengths of the input buffers. + * + * The returned K,V is: + * hmac->K = HMAC(hmac->K, hmac->V || inbyte || [in1] || [in2] || [in3]) + * hmac->V = HMAC(hmac->K, hmac->V) + * + * Returns zero if an error occurs otherwise it returns 1. + */ +static int do_hmac(PROV_DRBG_HMAC *hmac, unsigned char inbyte, + const unsigned char *in1, size_t in1len, + const unsigned char *in2, size_t in2len, + const unsigned char *in3, size_t in3len) +{ + EVP_MAC_CTX *ctx = hmac->ctx; + + if (!EVP_MAC_init(ctx, hmac->K, hmac->blocklen, NULL) + /* K = HMAC(K, V || inbyte || [in1] || [in2] || [in3]) */ + || !EVP_MAC_update(ctx, hmac->V, hmac->blocklen) + || !EVP_MAC_update(ctx, &inbyte, 1) + || !(in1 == NULL || in1len == 0 || EVP_MAC_update(ctx, in1, in1len)) + || !(in2 == NULL || in2len == 0 || EVP_MAC_update(ctx, in2, in2len)) + || !(in3 == NULL || in3len == 0 || EVP_MAC_update(ctx, in3, in3len)) + || !EVP_MAC_final(ctx, hmac->K, NULL, sizeof(hmac->K))) + return 0; + + /* V = HMAC(K, V) */ + return EVP_MAC_init(ctx, hmac->K, hmac->blocklen, NULL) + && EVP_MAC_update(ctx, hmac->V, hmac->blocklen) + && EVP_MAC_final(ctx, hmac->V, NULL, sizeof(hmac->V)); +} + +/* + * SP800-90Ar1 10.1.2.2 HMAC_DRBG_Update_Process + * + * + * Updates the drbg objects Key(K) and Value(V) using the following algorithm: + * K,V = do_hmac(hmac, 0, in1, in2, in3) + * if (any input is not NULL) + * K,V = do_hmac(hmac, 1, in1, in2, in3) + * + * where in1, in2, in3 are optional input buffers that can be NULL. + * in1len, in2len, in3len are the lengths of the input buffers. + * + * Returns zero if an error occurs otherwise it returns 1. + */ +static int drbg_hmac_update(PROV_DRBG *drbg, + const unsigned char *in1, size_t in1len, + const unsigned char *in2, size_t in2len, + const unsigned char *in3, size_t in3len) +{ + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; + + /* (Steps 1-2) K = HMAC(K, V||0x00||provided_data). V = HMAC(K,V) */ + if (!do_hmac(hmac, 0x00, in1, in1len, in2, in2len, in3, in3len)) + return 0; + /* (Step 3) If provided_data == NULL then return (K,V) */ + if (in1len == 0 && in2len == 0 && in3len == 0) + return 1; + /* (Steps 4-5) K = HMAC(K, V||0x01||provided_data). V = HMAC(K,V) */ + return do_hmac(hmac, 0x01, in1, in1len, in2, in2len, in3, in3len); +} + +/* + * SP800-90Ar1 10.1.2.3 HMAC_DRBG_Instantiate_Process: + * + * This sets the drbg Key (K) to all zeros, and Value (V) to all 1's. + * and then calls (K,V) = drbg_hmac_update() with input parameters: + * ent = entropy data (Can be NULL) of length ent_len. + * nonce = nonce data (Can be NULL) of length nonce_len. + * pstr = personalization data (Can be NULL) of length pstr_len. + * + * Returns zero if an error occurs otherwise it returns 1. + */ +static int drbg_hmac_instantiate(PROV_DRBG *drbg, + const unsigned char *ent, size_t ent_len, + const unsigned char *nonce, size_t nonce_len, + const unsigned char *pstr, size_t pstr_len) +{ + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; + + if (hmac->ctx == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MAC); + return 0; + } + + /* (Step 2) Key = 0x00 00...00 */ + memset(hmac->K, 0x00, hmac->blocklen); + /* (Step 3) V = 0x01 01...01 */ + memset(hmac->V, 0x01, hmac->blocklen); + /* (Step 4) (K,V) = HMAC_DRBG_Update(entropy||nonce||pers string, K, V) */ + return drbg_hmac_update(drbg, ent, ent_len, nonce, nonce_len, pstr, + pstr_len); +} + +static int drbg_hmac_instantiate_wrapper(void *vdrbg, unsigned int strength, + int prediction_resistance, + const unsigned char *pstr, + size_t pstr_len, + const OSSL_PARAM params[]) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + if (!ossl_prov_is_running() || !drbg_hmac_set_ctx_params(drbg, params)) + return 0; + return ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance, + pstr, pstr_len); +} + +/* + * SP800-90Ar1 10.1.2.4 HMAC_DRBG_Reseed_Process: + * + * Reseeds the drbg's Key (K) and Value (V) by calling + * (K,V) = drbg_hmac_update() with the following input parameters: + * ent = entropy input data (Can be NULL) of length ent_len. + * adin = additional input data (Can be NULL) of length adin_len. + * + * Returns zero if an error occurs otherwise it returns 1. + */ +static int drbg_hmac_reseed(PROV_DRBG *drbg, + const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len) +{ + /* (Step 2) (K,V) = HMAC_DRBG_Update(entropy||additional_input, K, V) */ + return drbg_hmac_update(drbg, ent, ent_len, adin, adin_len, NULL, 0); +} + +static int drbg_hmac_reseed_wrapper(void *vdrbg, int prediction_resistance, + const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return ossl_prov_drbg_reseed(drbg, prediction_resistance, ent, ent_len, + adin, adin_len); +} + +/* + * SP800-90Ar1 10.1.2.5 HMAC_DRBG_Generate_Process: + * + * Generates pseudo random bytes and updates the internal K,V for the drbg. + * out is a buffer to fill with outlen bytes of pseudo random data. + * adin is an additional_input string of size adin_len that may be NULL. + * + * Returns zero if an error occurs otherwise it returns 1. + */ +static int drbg_hmac_generate(PROV_DRBG *drbg, + unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; + EVP_MAC_CTX *ctx = hmac->ctx; + const unsigned char *temp = hmac->V; + + /* (Step 2) if adin != NULL then (K,V) = HMAC_DRBG_Update(adin, K, V) */ + if (adin != NULL + && adin_len > 0 + && !drbg_hmac_update(drbg, adin, adin_len, NULL, 0, NULL, 0)) + return 0; + + /* + * (Steps 3-5) temp = NULL + * while (len(temp) < outlen) { + * V = HMAC(K, V) + * temp = temp || V + * } + */ + for (;;) { + if (!EVP_MAC_init(ctx, hmac->K, hmac->blocklen, NULL) + || !EVP_MAC_update(ctx, temp, hmac->blocklen)) + return 0; + + if (outlen > hmac->blocklen) { + if (!EVP_MAC_final(ctx, out, NULL, outlen)) + return 0; + temp = out; + } else { + if (!EVP_MAC_final(ctx, hmac->V, NULL, sizeof(hmac->V))) + return 0; + memcpy(out, hmac->V, outlen); + break; + } + out += hmac->blocklen; + outlen -= hmac->blocklen; + } + /* (Step 6) (K,V) = HMAC_DRBG_Update(adin, K, V) */ + if (!drbg_hmac_update(drbg, adin, adin_len, NULL, 0, NULL, 0)) + return 0; + + return 1; +} + +static int drbg_hmac_generate_wrapper + (void *vdrbg, unsigned char *out, size_t outlen, unsigned int strength, + int prediction_resistance, const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return ossl_prov_drbg_generate(drbg, out, outlen, strength, + prediction_resistance, adin, adin_len); +} + +static int drbg_hmac_uninstantiate(PROV_DRBG *drbg) +{ + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; + + OPENSSL_cleanse(hmac->K, sizeof(hmac->K)); + OPENSSL_cleanse(hmac->V, sizeof(hmac->V)); + return ossl_prov_drbg_uninstantiate(drbg); +} + +static int drbg_hmac_uninstantiate_wrapper(void *vdrbg) +{ + return drbg_hmac_uninstantiate((PROV_DRBG *)vdrbg); +} + +static int drbg_hmac_verify_zeroization(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; + + PROV_DRBG_VERYIFY_ZEROIZATION(hmac->K); + PROV_DRBG_VERYIFY_ZEROIZATION(hmac->V); + return 1; +} + +static int drbg_hmac_new(PROV_DRBG *drbg) +{ + PROV_DRBG_HMAC *hmac; + + hmac = OPENSSL_secure_zalloc(sizeof(*hmac)); + if (hmac == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + drbg->data = hmac; + /* See SP800-57 Part1 Rev4 5.6.1 Table 3 */ + drbg->max_entropylen = DRBG_MAX_LENGTH; + drbg->max_noncelen = DRBG_MAX_LENGTH; + drbg->max_perslen = DRBG_MAX_LENGTH; + drbg->max_adinlen = DRBG_MAX_LENGTH; + + /* Maximum number of bits per request = 2^19 = 2^16 bytes */ + drbg->max_request = 1 << 16; + return 1; +} + +static void *drbg_hmac_new_wrapper(void *provctx, void *parent, + const OSSL_DISPATCH *parent_dispatch) +{ + return ossl_rand_drbg_new(provctx, parent, parent_dispatch, &drbg_hmac_new, + &drbg_hmac_instantiate, &drbg_hmac_uninstantiate, + &drbg_hmac_reseed, &drbg_hmac_generate); +} + +static void drbg_hmac_free(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_HMAC *hmac; + + if (drbg != NULL && (hmac = (PROV_DRBG_HMAC *)drbg->data) != NULL) { + EVP_MAC_CTX_free(hmac->ctx); + ossl_prov_digest_reset(&hmac->digest); + OPENSSL_secure_clear_free(hmac, sizeof(*hmac)); + } + ossl_rand_drbg_free(drbg); +} + +static int drbg_hmac_get_ctx_params(void *vdrbg, OSSL_PARAM params[]) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; + const char *name; + const EVP_MD *md; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAC); + if (p != NULL) { + if (hmac->ctx == NULL) + return 0; + name = EVP_MAC_get0_name(EVP_MAC_CTX_get0_mac(hmac->ctx)); + if (!OSSL_PARAM_set_utf8_string(p, name)) + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_DIGEST); + if (p != NULL) { + md = ossl_prov_digest_md(&hmac->digest); + if (md == NULL || !OSSL_PARAM_set_utf8_string(p, EVP_MD_get0_name(md))) + return 0; + } + + return ossl_drbg_get_ctx_params(drbg, params); +} + +static const OSSL_PARAM *drbg_hmac_gettable_ctx_params(ossl_unused void *vctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_MAC, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_DRBG_GETTABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +static int drbg_hmac_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_DRBG *ctx = (PROV_DRBG *)vctx; + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)ctx->data; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const EVP_MD *md; + + if (!ossl_prov_digest_load_from_params(&hmac->digest, params, libctx)) + return 0; + + /* + * Confirm digest is allowed. We allow all digests that are not XOF + * (such as SHAKE). In FIPS mode, the fetch will fail for non-approved + * digests. + */ + md = ossl_prov_digest_md(&hmac->digest); + if (md != NULL && (EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF) != 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED); + return 0; + } + + if (!ossl_prov_macctx_load_from_params(&hmac->ctx, params, + NULL, NULL, NULL, libctx)) + return 0; + + if (hmac->ctx != NULL) { + /* These are taken from SP 800-90 10.1 Table 2 */ + hmac->blocklen = EVP_MD_get_size(md); + /* See SP800-57 Part1 Rev4 5.6.1 Table 3 */ + ctx->strength = 64 * (int)(hmac->blocklen >> 3); + if (ctx->strength > 256) + ctx->strength = 256; + ctx->seedlen = hmac->blocklen; + ctx->min_entropylen = ctx->strength / 8; + ctx->min_noncelen = ctx->min_entropylen / 2; + } + + return ossl_drbg_set_ctx_params(ctx, params); +} + +static const OSSL_PARAM *drbg_hmac_settable_ctx_params(ossl_unused void *vctx, + ossl_unused void *p_ctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_MAC, NULL, 0), + OSSL_PARAM_DRBG_SETTABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +const OSSL_DISPATCH ossl_drbg_ossl_hmac_functions[] = { + { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))drbg_hmac_new_wrapper }, + { OSSL_FUNC_RAND_FREECTX, (void(*)(void))drbg_hmac_free }, + { OSSL_FUNC_RAND_INSTANTIATE, + (void(*)(void))drbg_hmac_instantiate_wrapper }, + { OSSL_FUNC_RAND_UNINSTANTIATE, + (void(*)(void))drbg_hmac_uninstantiate_wrapper }, + { OSSL_FUNC_RAND_GENERATE, (void(*)(void))drbg_hmac_generate_wrapper }, + { OSSL_FUNC_RAND_RESEED, (void(*)(void))drbg_hmac_reseed_wrapper }, + { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))ossl_drbg_enable_locking }, + { OSSL_FUNC_RAND_LOCK, (void(*)(void))ossl_drbg_lock }, + { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))ossl_drbg_unlock }, + { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS, + (void(*)(void))drbg_hmac_settable_ctx_params }, + { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_hmac_set_ctx_params }, + { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, + (void(*)(void))drbg_hmac_gettable_ctx_params }, + { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_hmac_get_ctx_params }, + { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, + (void(*)(void))drbg_hmac_verify_zeroization }, + { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))ossl_drbg_get_seed }, + { OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))ossl_drbg_clear_seed }, + { 0, NULL } +}; diff --git a/providers/implementations/rands/drbg_local.h b/providers/implementations/rands/drbg_local.h new file mode 100644 index 000000000000..8bc5df89c236 --- /dev/null +++ b/providers/implementations/rands/drbg_local.h @@ -0,0 +1,259 @@ +/* + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef OSSL_CRYPTO_PROV_LOCAL_H +# define OSSL_CRYPTO_PROV_LOCAL_H + +# include <openssl/evp.h> +# include <openssl/core_dispatch.h> +# include <openssl/core_names.h> +# include <openssl/params.h> +# include "internal/tsan_assist.h" +# include "internal/nelem.h" +# include "internal/numbers.h" +# include "prov/provider_ctx.h" + +/* How many times to read the TSC as a randomness source. */ +# define TSC_READ_COUNT 4 + +/* Maximum reseed intervals */ +# define MAX_RESEED_INTERVAL (1 << 24) +# define MAX_RESEED_TIME_INTERVAL (1 << 20) /* approx. 12 days */ + +/* Default reseed intervals */ +# define RESEED_INTERVAL (1 << 8) +# define TIME_INTERVAL (60*60) /* 1 hour */ + +/* + * The number of bytes that constitutes an atomic lump of entropy with respect + * to the FIPS 140-2 section 4.9.2 Conditional Tests. The size is somewhat + * arbitrary, the smaller the value, the less entropy is consumed on first + * read but the higher the probability of the test failing by accident. + * + * The value is in bytes. + */ +#define CRNGT_BUFSIZ 16 + +/* + * Maximum input size for the DRBG (entropy, nonce, personalization string) + * + * NIST SP800 90Ar1 allows a maximum of (1 << 35) bits i.e., (1 << 32) bytes. + * + * We lower it to 'only' INT32_MAX bytes, which is equivalent to 2 gigabytes. + */ +# define DRBG_MAX_LENGTH INT32_MAX + +/* The default nonce */ +#ifdef CHARSET_EBCDIC +# define DRBG_DEFAULT_PERS_STRING { 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x53, \ + 0x4c, 0x20, 0x4e, 0x49, 0x53, 0x54, 0x20, 0x53, 0x50, 0x20, 0x38, 0x30, \ + 0x30, 0x2d, 0x39, 0x30, 0x41, 0x20, 0x44, 0x52, 0x42, 0x47, 0x00}; +#else +# define DRBG_DEFAULT_PERS_STRING "OpenSSL NIST SP 800-90A DRBG" +#endif + +typedef struct prov_drbg_st PROV_DRBG; + +/* DRBG status values */ +typedef enum drbg_status_e { + DRBG_UNINITIALISED, + DRBG_READY, + DRBG_ERROR +} DRBG_STATUS; + +/* + * The state of all types of DRBGs. + */ +struct prov_drbg_st { + CRYPTO_RWLOCK *lock; + PROV_CTX *provctx; + + /* Virtual functions are cache here */ + int (*instantiate)(PROV_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *nonce, size_t noncelen, + const unsigned char *pers, size_t perslen); + int (*uninstantiate)(PROV_DRBG *ctx); + int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len); + int (*generate)(PROV_DRBG *, unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adin_len); + + /* Parent PROV_RAND and its dispatch table functions */ + void *parent; + OSSL_FUNC_rand_enable_locking_fn *parent_enable_locking; + OSSL_FUNC_rand_lock_fn *parent_lock; + OSSL_FUNC_rand_unlock_fn *parent_unlock; + OSSL_FUNC_rand_get_ctx_params_fn *parent_get_ctx_params; + OSSL_FUNC_rand_nonce_fn *parent_nonce; + OSSL_FUNC_rand_get_seed_fn *parent_get_seed; + OSSL_FUNC_rand_clear_seed_fn *parent_clear_seed; + + const OSSL_DISPATCH *parent_dispatch; + + /* + * Stores the return value of openssl_get_fork_id() as of when we last + * reseeded. The DRBG reseeds automatically whenever drbg->fork_id != + * openssl_get_fork_id(). Used to provide fork-safety and reseed this + * DRBG in the child process. + */ + int fork_id; + unsigned short flags; /* various external flags */ + + /* + * The following parameters are setup by the per-type "init" function. + * + * The supported types and their init functions are: + * (1) CTR_DRBG: drbg_ctr_init(). + * (2) HMAC_DRBG: drbg_hmac_init(). + * (3) HASH_DRBG: drbg_hash_init(). + * + * The parameters are closely related to the ones described in + * section '10.2.1 CTR_DRBG' of [NIST SP 800-90Ar1], with one + * crucial difference: In the NIST standard, all counts are given + * in bits, whereas in OpenSSL entropy counts are given in bits + * and buffer lengths are given in bytes. + * + * Since this difference has lead to some confusion in the past, + * (see [GitHub Issue #2443], formerly [rt.openssl.org #4055]) + * the 'len' suffix has been added to all buffer sizes for + * clarification. + */ + + unsigned int strength; + size_t max_request; + size_t min_entropylen, max_entropylen; + size_t min_noncelen, max_noncelen; + size_t max_perslen, max_adinlen; + + /* + * Counts the number of generate requests since the last reseed + * (Starts at 1). This value is the reseed_counter as defined in + * NIST SP 800-90Ar1 + */ + unsigned int generate_counter; + /* + * Maximum number of generate requests until a reseed is required. + * This value is ignored if it is zero. + */ + unsigned int reseed_interval; + /* Stores the time when the last reseeding occurred */ + time_t reseed_time; + /* + * Specifies the maximum time interval (in seconds) between reseeds. + * This value is ignored if it is zero. + */ + time_t reseed_time_interval; + /* + * Counts the number of reseeds since instantiation. + * This value is ignored if it is zero. + * + * This counter is used only for seed propagation from the <master> DRBG + * to its two children, the <public> and <private> DRBG. This feature is + * very special and its sole purpose is to ensure that any randomness which + * is added by PROV_add() or PROV_seed() will have an immediate effect on + * the output of PROV_bytes() resp. PROV_priv_bytes(). + */ + TSAN_QUALIFIER unsigned int reseed_counter; + unsigned int reseed_next_counter; + unsigned int parent_reseed_counter; + + size_t seedlen; + DRBG_STATUS state; + + /* DRBG specific data */ + void *data; + + /* Entropy and nonce gathering callbacks */ + void *callback_arg; + OSSL_INOUT_CALLBACK *get_entropy_fn; + OSSL_CALLBACK *cleanup_entropy_fn; + OSSL_INOUT_CALLBACK *get_nonce_fn; + OSSL_CALLBACK *cleanup_nonce_fn; +}; + +PROV_DRBG *ossl_rand_drbg_new + (void *provctx, void *parent, const OSSL_DISPATCH *parent_dispatch, + int (*dnew)(PROV_DRBG *ctx), + int (*instantiate)(PROV_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *nonce, size_t noncelen, + const unsigned char *pers, size_t perslen), + int (*uninstantiate)(PROV_DRBG *ctx), + int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len), + int (*generate)(PROV_DRBG *, unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adin_len)); +void ossl_rand_drbg_free(PROV_DRBG *drbg); + +int ossl_prov_drbg_instantiate(PROV_DRBG *drbg, unsigned int strength, + int prediction_resistance, + const unsigned char *pers, size_t perslen); + +int ossl_prov_drbg_uninstantiate(PROV_DRBG *drbg); + +int ossl_prov_drbg_reseed(PROV_DRBG *drbg, int prediction_resistance, + const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adinlen); + +int ossl_prov_drbg_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, + unsigned int strength, int prediction_resistance, + const unsigned char *adin, size_t adinlen); + +/* Seeding api */ +OSSL_FUNC_rand_get_seed_fn ossl_drbg_get_seed; +OSSL_FUNC_rand_clear_seed_fn ossl_drbg_clear_seed; + +/* Verify that an array of numeric values is all zero */ +#define PROV_DRBG_VERYIFY_ZEROIZATION(v) \ + { \ + size_t i; \ + \ + for (i = 0; i < OSSL_NELEM(v); i++) \ + if ((v)[i] != 0) \ + return 0; \ + } + +/* locking api */ +OSSL_FUNC_rand_enable_locking_fn ossl_drbg_enable_locking; +OSSL_FUNC_rand_lock_fn ossl_drbg_lock; +OSSL_FUNC_rand_unlock_fn ossl_drbg_unlock; + +/* Common parameters for all of our DRBGs */ +int ossl_drbg_get_ctx_params(PROV_DRBG *drbg, OSSL_PARAM params[]); +int ossl_drbg_set_ctx_params(PROV_DRBG *drbg, const OSSL_PARAM params[]); + +#define OSSL_PARAM_DRBG_SETTABLE_CTX_COMMON \ + OSSL_PARAM_uint(OSSL_DRBG_PARAM_RESEED_REQUESTS, NULL), \ + OSSL_PARAM_uint64(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL, NULL) + +#define OSSL_PARAM_DRBG_GETTABLE_CTX_COMMON \ + OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, NULL), \ + OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL), \ + OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MIN_ENTROPYLEN, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_ENTROPYLEN, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MIN_NONCELEN, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_NONCELEN, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_PERSLEN, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_ADINLEN, NULL), \ + OSSL_PARAM_uint(OSSL_DRBG_PARAM_RESEED_COUNTER, NULL), \ + OSSL_PARAM_time_t(OSSL_DRBG_PARAM_RESEED_TIME, NULL), \ + OSSL_PARAM_uint(OSSL_DRBG_PARAM_RESEED_REQUESTS, NULL), \ + OSSL_PARAM_uint64(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL, NULL) + +/* Continuous test "entropy" calls */ +size_t ossl_crngt_get_entropy(PROV_DRBG *drbg, + unsigned char **pout, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance); +void ossl_crngt_cleanup_entropy(PROV_DRBG *drbg, + unsigned char *out, size_t outlen); + +#endif diff --git a/providers/implementations/rands/seed_src.c b/providers/implementations/rands/seed_src.c new file mode 100644 index 000000000000..7a4b780bb469 --- /dev/null +++ b/providers/implementations/rands/seed_src.c @@ -0,0 +1,253 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> +#include <openssl/rand.h> +#include <openssl/core_dispatch.h> +#include <openssl/e_os2.h> +#include <openssl/params.h> +#include <openssl/core_names.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/randerr.h> +#include <openssl/proverr.h> +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "crypto/rand.h" +#include "crypto/rand_pool.h" + +static OSSL_FUNC_rand_newctx_fn seed_src_new; +static OSSL_FUNC_rand_freectx_fn seed_src_free; +static OSSL_FUNC_rand_instantiate_fn seed_src_instantiate; +static OSSL_FUNC_rand_uninstantiate_fn seed_src_uninstantiate; +static OSSL_FUNC_rand_generate_fn seed_src_generate; +static OSSL_FUNC_rand_reseed_fn seed_src_reseed; +static OSSL_FUNC_rand_gettable_ctx_params_fn seed_src_gettable_ctx_params; +static OSSL_FUNC_rand_get_ctx_params_fn seed_src_get_ctx_params; +static OSSL_FUNC_rand_verify_zeroization_fn seed_src_verify_zeroization; +static OSSL_FUNC_rand_enable_locking_fn seed_src_enable_locking; +static OSSL_FUNC_rand_lock_fn seed_src_lock; +static OSSL_FUNC_rand_unlock_fn seed_src_unlock; +static OSSL_FUNC_rand_get_seed_fn seed_get_seed; +static OSSL_FUNC_rand_clear_seed_fn seed_clear_seed; + +typedef struct { + void *provctx; + int state; +} PROV_SEED_SRC; + +static void *seed_src_new(void *provctx, void *parent, + const OSSL_DISPATCH *parent_dispatch) +{ + PROV_SEED_SRC *s; + + if (parent != NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT); + return NULL; + } + + s = OPENSSL_zalloc(sizeof(*s)); + if (s == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + s->provctx = provctx; + s->state = EVP_RAND_STATE_UNINITIALISED; + return s; +} + +static void seed_src_free(void *vseed) +{ + OPENSSL_free(vseed); +} + +static int seed_src_instantiate(void *vseed, unsigned int strength, + int prediction_resistance, + const unsigned char *pstr, size_t pstr_len, + ossl_unused const OSSL_PARAM params[]) +{ + PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed; + + s->state = EVP_RAND_STATE_READY; + return 1; +} + +static int seed_src_uninstantiate(void *vseed) +{ + PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed; + + s->state = EVP_RAND_STATE_UNINITIALISED; + return 1; +} + +static int seed_src_generate(void *vseed, unsigned char *out, size_t outlen, + unsigned int strength, + ossl_unused int prediction_resistance, + ossl_unused const unsigned char *adin, + ossl_unused size_t adin_len) +{ + PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed; + size_t entropy_available; + RAND_POOL *pool; + + if (s->state != EVP_RAND_STATE_READY) { + ERR_raise(ERR_LIB_PROV, + s->state == EVP_RAND_STATE_ERROR ? PROV_R_IN_ERROR_STATE + : PROV_R_NOT_INSTANTIATED); + return 0; + } + + pool = ossl_rand_pool_new(strength, 1, outlen, outlen); + if (pool == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + /* Get entropy by polling system entropy sources. */ + entropy_available = ossl_pool_acquire_entropy(pool); + + if (entropy_available > 0) + memcpy(out, ossl_rand_pool_buffer(pool), ossl_rand_pool_length(pool)); + + ossl_rand_pool_free(pool); + return entropy_available > 0; +} + +static int seed_src_reseed(void *vseed, + ossl_unused int prediction_resistance, + ossl_unused const unsigned char *ent, + ossl_unused size_t ent_len, + ossl_unused const unsigned char *adin, + ossl_unused size_t adin_len) +{ + PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed; + + if (s->state != EVP_RAND_STATE_READY) { + ERR_raise(ERR_LIB_PROV, + s->state == EVP_RAND_STATE_ERROR ? PROV_R_IN_ERROR_STATE + : PROV_R_NOT_INSTANTIATED); + return 0; + } + return 1; +} + +static int seed_src_get_ctx_params(void *vseed, OSSL_PARAM params[]) +{ + PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE); + if (p != NULL && !OSSL_PARAM_set_int(p, s->state)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH); + if (p != NULL && !OSSL_PARAM_set_int(p, 1024)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST); + if (p != NULL && !OSSL_PARAM_set_size_t(p, 128)) + return 0; + return 1; +} + +static const OSSL_PARAM *seed_src_gettable_ctx_params(ossl_unused void *vseed, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, NULL), + OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL), + OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +static int seed_src_verify_zeroization(ossl_unused void *vseed) +{ + return 1; +} + +static size_t seed_get_seed(void *vseed, unsigned char **pout, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance, + const unsigned char *adin, size_t adin_len) +{ + size_t bytes_needed; + unsigned char *p; + + /* + * Figure out how many bytes we need. + * This assumes that the seed sources provide eight bits of entropy + * per byte. For lower quality sources, the formula will need to be + * different. + */ + bytes_needed = entropy >= 0 ? (entropy + 7) / 8 : 0; + if (bytes_needed < min_len) + bytes_needed = min_len; + if (bytes_needed > max_len) { + ERR_raise(ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK); + return 0; + } + + p = OPENSSL_secure_malloc(bytes_needed); + if (p == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + if (seed_src_generate(vseed, p, bytes_needed, 0, prediction_resistance, + adin, adin_len) != 0) { + *pout = p; + return bytes_needed; + } + OPENSSL_secure_clear_free(p, bytes_needed); + return 0; +} + +static void seed_clear_seed(ossl_unused void *vdrbg, + unsigned char *out, size_t outlen) +{ + OPENSSL_secure_clear_free(out, outlen); +} + +static int seed_src_enable_locking(ossl_unused void *vseed) +{ + return 1; +} + +int seed_src_lock(ossl_unused void *vctx) +{ + return 1; +} + +void seed_src_unlock(ossl_unused void *vctx) +{ +} + +const OSSL_DISPATCH ossl_seed_src_functions[] = { + { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))seed_src_new }, + { OSSL_FUNC_RAND_FREECTX, (void(*)(void))seed_src_free }, + { OSSL_FUNC_RAND_INSTANTIATE, + (void(*)(void))seed_src_instantiate }, + { OSSL_FUNC_RAND_UNINSTANTIATE, + (void(*)(void))seed_src_uninstantiate }, + { OSSL_FUNC_RAND_GENERATE, (void(*)(void))seed_src_generate }, + { OSSL_FUNC_RAND_RESEED, (void(*)(void))seed_src_reseed }, + { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))seed_src_enable_locking }, + { OSSL_FUNC_RAND_LOCK, (void(*)(void))seed_src_lock }, + { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))seed_src_unlock }, + { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, + (void(*)(void))seed_src_gettable_ctx_params }, + { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))seed_src_get_ctx_params }, + { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, + (void(*)(void))seed_src_verify_zeroization }, + { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))seed_get_seed }, + { OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))seed_clear_seed }, + { 0, NULL } +}; diff --git a/providers/implementations/rands/seeding/build.info b/providers/implementations/rands/seeding/build.info new file mode 100644 index 000000000000..2788146ad42a --- /dev/null +++ b/providers/implementations/rands/seeding/build.info @@ -0,0 +1,10 @@ +$COMMON=rand_unix.c rand_win.c rand_tsc.c rand_cpu_x86.c +IF[{- $config{target} =~ /vxworks/i -}] + $COMMON=$COMMON rand_vxworks.c +ENDIF +IF[{- $config{target} =~ /vms/i -}] + $COMMON=$COMMON rand_vms.c +ENDIF + +SOURCE[../../../libdefault.a]=$COMMON + diff --git a/providers/implementations/rands/seeding/rand_cpu_x86.c b/providers/implementations/rands/seeding/rand_cpu_x86.c new file mode 100644 index 000000000000..0e062fa45aa2 --- /dev/null +++ b/providers/implementations/rands/seeding/rand_cpu_x86.c @@ -0,0 +1,107 @@ +/* + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "internal/cryptlib.h" +#include <openssl/opensslconf.h> +#include "crypto/rand_pool.h" +#include "prov/seeding.h" + +#ifdef OPENSSL_RAND_SEED_RDCPU +# if defined(OPENSSL_SYS_TANDEM) && defined(_TNS_X_TARGET) +# include <builtin.h> /* _rdrand64 */ +# include <string.h> /* memcpy */ +# else +size_t OPENSSL_ia32_rdseed_bytes(unsigned char *buf, size_t len); +size_t OPENSSL_ia32_rdrand_bytes(unsigned char *buf, size_t len); +# endif + +static size_t get_hardware_random_value(unsigned char *buf, size_t len); + +/* + * Acquire entropy using Intel-specific cpu instructions + * + * Uses the RDSEED instruction if available, otherwise uses + * RDRAND if available. + * + * For the differences between RDSEED and RDRAND, and why RDSEED + * is the preferred choice, see https://goo.gl/oK3KcN + * + * Returns the total entropy count, if it exceeds the requested + * entropy count. Otherwise, returns an entropy count of 0. + */ +size_t ossl_prov_acquire_entropy_from_cpu(RAND_POOL *pool) +{ + size_t bytes_needed; + unsigned char *buffer; + + bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + if (bytes_needed > 0) { + buffer = ossl_rand_pool_add_begin(pool, bytes_needed); + + if (buffer != NULL) { + if (get_hardware_random_value(buffer, bytes_needed) == bytes_needed) { + ossl_rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed); + } else { + ossl_rand_pool_add_end(pool, 0, 0); + } + } + } + + return ossl_rand_pool_entropy_available(pool); +} + +#if defined(OPENSSL_SYS_TANDEM) && defined(_TNS_X_TARGET) +/* Obtain random bytes from the x86 hardware random function in 64 bit chunks */ +static size_t get_hardware_random_value(unsigned char *buf, size_t len) +{ + size_t bytes_remaining = len; + + while (bytes_remaining > 0) { + /* Always use 64 bit fetch, then use the lower bytes as needed. */ + /* The platform is big-endian. */ + uint64_t random_value = 0; + + if (_rdrand64(&random_value) != 0) { + unsigned char *random_buffer = (unsigned char *)&random_value; + + if (bytes_remaining >= sizeof(random_value)) { + memcpy(buf, random_buffer, sizeof(random_value)); + bytes_remaining -= sizeof(random_value); + buf += sizeof(random_value); + } else { + memcpy(buf, + random_buffer + (sizeof(random_value) - bytes_remaining), + bytes_remaining); + bytes_remaining = 0; /* This will terminate the loop */ + } + } else + break; + } + if (bytes_remaining == 0) + return len; + return 0; +} +#else +static size_t get_hardware_random_value(unsigned char *buf, size_t len) { + /* Whichever comes first, use RDSEED, RDRAND or nothing */ + if ((OPENSSL_ia32cap_P[2] & (1 << 18)) != 0) { + if (OPENSSL_ia32_rdseed_bytes(buf, len) != len) + return 0; + } else if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) { + if (OPENSSL_ia32_rdrand_bytes(buf, len) != len) + return 0; + } else + return 0; + return len; +} +#endif + +#else +NON_EMPTY_TRANSLATION_UNIT +#endif diff --git a/providers/implementations/rands/seeding/rand_tsc.c b/providers/implementations/rands/seeding/rand_tsc.c new file mode 100644 index 000000000000..98dd836b24d9 --- /dev/null +++ b/providers/implementations/rands/seeding/rand_tsc.c @@ -0,0 +1,48 @@ +/* + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "internal/cryptlib.h" +#include <openssl/opensslconf.h> +#include "crypto/rand_pool.h" +#include "prov/seeding.h" + +#ifdef OPENSSL_RAND_SEED_RDTSC +/* + * IMPORTANT NOTE: It is not currently possible to use this code + * because we are not sure about the amount of randomness it provides. + * Some SP800-90B tests have been run, but there is internal skepticism. + * So for now this code is not used. + */ +# error "RDTSC enabled? Should not be possible!" + +/* + * Acquire entropy from high-speed clock + * + * Since we get some randomness from the low-order bits of the + * high-speed clock, it can help. + * + * Returns the total entropy count, if it exceeds the requested + * entropy count. Otherwise, returns an entropy count of 0. + */ +size_t ossl_prov_acquire_entropy_from_tsc(RAND_POOL *pool) +{ + unsigned char c; + int i; + + if ((OPENSSL_ia32cap_P[0] & (1 << 4)) != 0) { + for (i = 0; i < TSC_READ_COUNT; i++) { + c = (unsigned char)(OPENSSL_rdtsc() & 0xFF); + ossl_rand_pool_add(pool, &c, 1, 4); + } + } + return ossl_rand_pool_entropy_available(pool); +} +#else +NON_EMPTY_TRANSLATION_UNIT +#endif diff --git a/providers/implementations/rands/seeding/rand_unix.c b/providers/implementations/rands/seeding/rand_unix.c new file mode 100644 index 000000000000..750afca58ed7 --- /dev/null +++ b/providers/implementations/rands/seeding/rand_unix.c @@ -0,0 +1,882 @@ +/* + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif +#include "../e_os.h" +#include <stdio.h> +#include "internal/cryptlib.h" +#include <openssl/rand.h> +#include <openssl/crypto.h> +#include "crypto/rand_pool.h" +#include "crypto/rand.h" +#include <stdio.h> +#include "internal/dso.h" +#include "prov/seeding.h" + +#ifdef __linux +# include <sys/syscall.h> +# ifdef DEVRANDOM_WAIT +# include <sys/shm.h> +# include <sys/utsname.h> +# endif +#endif +#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(OPENSSL_SYS_UEFI) +# include <sys/types.h> +# include <sys/sysctl.h> +# include <sys/param.h> +#endif +#if defined(__OpenBSD__) +# include <sys/param.h> +#endif +#if defined(__DragonFly__) +# include <sys/param.h> +# include <sys/random.h> +#endif + +#if (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS)) \ + || defined(__DJGPP__) +# include <sys/types.h> +# include <sys/stat.h> +# include <fcntl.h> +# include <unistd.h> +# include <sys/time.h> + +static uint64_t get_time_stamp(void); +static uint64_t get_timer_bits(void); + +/* Macro to convert two thirty two bit values into a sixty four bit one */ +# define TWO32TO64(a, b) ((((uint64_t)(a)) << 32) + (b)) + +/* + * Check for the existence and support of POSIX timers. The standard + * says that the _POSIX_TIMERS macro will have a positive value if they + * are available. + * + * However, we want an additional constraint: that the timer support does + * not require an extra library dependency. Early versions of glibc + * require -lrt to be specified on the link line to access the timers, + * so this needs to be checked for. + * + * It is worse because some libraries define __GLIBC__ but don't + * support the version testing macro (e.g. uClibc). This means + * an extra check is needed. + * + * The final condition is: + * "have posix timers and either not glibc or glibc without -lrt" + * + * The nested #if sequences are required to avoid using a parameterised + * macro that might be undefined. + */ +# undef OSSL_POSIX_TIMER_OKAY +/* On some systems, _POSIX_TIMERS is defined but empty. + * Subtracting by 0 when comparing avoids an error in this case. */ +# if defined(_POSIX_TIMERS) && _POSIX_TIMERS -0 > 0 +# if defined(__GLIBC__) +# if defined(__GLIBC_PREREQ) +# if __GLIBC_PREREQ(2, 17) +# define OSSL_POSIX_TIMER_OKAY +# endif +# endif +# else +# define OSSL_POSIX_TIMER_OKAY +# endif +# endif +#endif /* (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS)) + || defined(__DJGPP__) */ + +#if defined(OPENSSL_RAND_SEED_NONE) +/* none means none. this simplifies the following logic */ +# undef OPENSSL_RAND_SEED_OS +# undef OPENSSL_RAND_SEED_GETRANDOM +# undef OPENSSL_RAND_SEED_LIBRANDOM +# undef OPENSSL_RAND_SEED_DEVRANDOM +# undef OPENSSL_RAND_SEED_RDTSC +# undef OPENSSL_RAND_SEED_RDCPU +# undef OPENSSL_RAND_SEED_EGD +#endif + +#if defined(OPENSSL_SYS_UEFI) && !defined(OPENSSL_RAND_SEED_NONE) +# error "UEFI only supports seeding NONE" +#endif + +#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) \ + || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) \ + || defined(OPENSSL_SYS_UEFI)) + +# if defined(OPENSSL_SYS_VOS) + +# ifndef OPENSSL_RAND_SEED_OS +# error "Unsupported seeding method configured; must be os" +# endif + +# if defined(OPENSSL_SYS_VOS_HPPA) && defined(OPENSSL_SYS_VOS_IA32) +# error "Unsupported HP-PA and IA32 at the same time." +# endif +# if !defined(OPENSSL_SYS_VOS_HPPA) && !defined(OPENSSL_SYS_VOS_IA32) +# error "Must have one of HP-PA or IA32" +# endif + +/* + * The following algorithm repeatedly samples the real-time clock (RTC) to + * generate a sequence of unpredictable data. The algorithm relies upon the + * uneven execution speed of the code (due to factors such as cache misses, + * interrupts, bus activity, and scheduling) and upon the rather large + * relative difference between the speed of the clock and the rate at which + * it can be read. If it is ported to an environment where execution speed + * is more constant or where the RTC ticks at a much slower rate, or the + * clock can be read with fewer instructions, it is likely that the results + * would be far more predictable. This should only be used for legacy + * platforms. + * + * As a precaution, we assume only 2 bits of entropy per byte. + */ +size_t ossl_pool_acquire_entropy(RAND_POOL *pool) +{ + short int code; + int i, k; + size_t bytes_needed; + struct timespec ts; + unsigned char v; +# ifdef OPENSSL_SYS_VOS_HPPA + long duration; + extern void s$sleep(long *_duration, short int *_code); +# else + long long duration; + extern void s$sleep2(long long *_duration, short int *_code); +# endif + + bytes_needed = ossl_rand_pool_bytes_needed(pool, 4 /*entropy_factor*/); + + for (i = 0; i < bytes_needed; i++) { + /* + * burn some cpu; hope for interrupts, cache collisions, bus + * interference, etc. + */ + for (k = 0; k < 99; k++) + ts.tv_nsec = random(); + +# ifdef OPENSSL_SYS_VOS_HPPA + /* sleep for 1/1024 of a second (976 us). */ + duration = 1; + s$sleep(&duration, &code); +# else + /* sleep for 1/65536 of a second (15 us). */ + duration = 1; + s$sleep2(&duration, &code); +# endif + + /* Get wall clock time, take 8 bits. */ + clock_gettime(CLOCK_REALTIME, &ts); + v = (unsigned char)(ts.tv_nsec & 0xFF); + ossl_rand_pool_add(pool, arg, &v, sizeof(v) , 2); + } + return ossl_rand_pool_entropy_available(pool); +} + +void ossl_rand_pool_cleanup(void) +{ +} + +void ossl_rand_pool_keep_random_devices_open(int keep) +{ +} + +# else + +# if defined(OPENSSL_RAND_SEED_EGD) && \ + (defined(OPENSSL_NO_EGD) || !defined(DEVRANDOM_EGD)) +# error "Seeding uses EGD but EGD is turned off or no device given" +# endif + +# if defined(OPENSSL_RAND_SEED_DEVRANDOM) && !defined(DEVRANDOM) +# error "Seeding uses urandom but DEVRANDOM is not configured" +# endif + +# if defined(OPENSSL_RAND_SEED_OS) +# if !defined(DEVRANDOM) +# error "OS seeding requires DEVRANDOM to be configured" +# endif +# define OPENSSL_RAND_SEED_GETRANDOM +# define OPENSSL_RAND_SEED_DEVRANDOM +# endif + +# if defined(OPENSSL_RAND_SEED_LIBRANDOM) +# error "librandom not (yet) supported" +# endif + +# if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND) +/* + * sysctl_random(): Use sysctl() to read a random number from the kernel + * Returns the number of bytes returned in buf on success, -1 on failure. + */ +static ssize_t sysctl_random(char *buf, size_t buflen) +{ + int mib[2]; + size_t done = 0; + size_t len; + + /* + * Note: sign conversion between size_t and ssize_t is safe even + * without a range check, see comment in syscall_random() + */ + + /* + * On FreeBSD old implementations returned longs, newer versions support + * variable sizes up to 256 byte. The code below would not work properly + * when the sysctl returns long and we want to request something not a + * multiple of longs, which should never be the case. + */ +#if defined(__FreeBSD__) + if (!ossl_assert(buflen % sizeof(long) == 0)) { + errno = EINVAL; + return -1; + } +#endif + + /* + * On NetBSD before 4.0 KERN_ARND was an alias for KERN_URND, and only + * filled in an int, leaving the rest uninitialized. Since NetBSD 4.0 + * it returns a variable number of bytes with the current version supporting + * up to 256 bytes. + * Just return an error on older NetBSD versions. + */ +#if defined(__NetBSD__) && __NetBSD_Version__ < 400000000 + errno = ENOSYS; + return -1; +#endif + + mib[0] = CTL_KERN; + mib[1] = KERN_ARND; + + do { + len = buflen > 256 ? 256 : buflen; + if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) + return done > 0 ? done : -1; + done += len; + buf += len; + buflen -= len; + } while (buflen > 0); + + return done; +} +# endif + +# if defined(OPENSSL_RAND_SEED_GETRANDOM) + +# if defined(__linux) && !defined(__NR_getrandom) +# if defined(__arm__) +# define __NR_getrandom (__NR_SYSCALL_BASE+384) +# elif defined(__i386__) +# define __NR_getrandom 355 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define __NR_getrandom (__X32_SYSCALL_BIT + 318) +# else +# define __NR_getrandom 318 +# endif +# elif defined(__xtensa__) +# define __NR_getrandom 338 +# elif defined(__s390__) || defined(__s390x__) +# define __NR_getrandom 349 +# elif defined(__bfin__) +# define __NR_getrandom 389 +# elif defined(__powerpc__) +# define __NR_getrandom 359 +# elif defined(__mips__) || defined(__mips64) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_getrandom (__NR_Linux + 353) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_getrandom (__NR_Linux + 313) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_getrandom (__NR_Linux + 317) +# endif +# elif defined(__hppa__) +# define __NR_getrandom (__NR_Linux + 339) +# elif defined(__sparc__) +# define __NR_getrandom 347 +# elif defined(__ia64__) +# define __NR_getrandom 1339 +# elif defined(__alpha__) +# define __NR_getrandom 511 +# elif defined(__sh__) +# if defined(__SH5__) +# define __NR_getrandom 373 +# else +# define __NR_getrandom 384 +# endif +# elif defined(__avr32__) +# define __NR_getrandom 317 +# elif defined(__microblaze__) +# define __NR_getrandom 385 +# elif defined(__m68k__) +# define __NR_getrandom 352 +# elif defined(__cris__) +# define __NR_getrandom 356 +# elif defined(__aarch64__) +# define __NR_getrandom 278 +# else /* generic */ +# define __NR_getrandom 278 +# endif +# endif + +/* + * syscall_random(): Try to get random data using a system call + * returns the number of bytes returned in buf, or < 0 on error. + */ +static ssize_t syscall_random(void *buf, size_t buflen) +{ + /* + * Note: 'buflen' equals the size of the buffer which is used by the + * get_entropy() callback of the RAND_DRBG. It is roughly bounded by + * + * 2 * RAND_POOL_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^14 + * + * which is way below the OSSL_SSIZE_MAX limit. Therefore sign conversion + * between size_t and ssize_t is safe even without a range check. + */ + + /* + * Do runtime detection to find getentropy(). + * + * Known OSs that should support this: + * - Darwin since 16 (OSX 10.12, IOS 10.0). + * - Solaris since 11.3 + * - OpenBSD since 5.6 + * - Linux since 3.17 with glibc 2.25 + * - FreeBSD since 12.0 (1200061) + * + * Note: Sometimes getentropy() can be provided but not implemented + * internally. So we need to check errno for ENOSYS + */ +# if !defined(__DragonFly__) && !defined(__NetBSD__) +# if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__) && !defined(__hpux) + extern int getentropy(void *buffer, size_t length) __attribute__((weak)); + + if (getentropy != NULL) { + if (getentropy(buf, buflen) == 0) + return (ssize_t)buflen; + if (errno != ENOSYS) + return -1; + } +# elif defined(OPENSSL_APPLE_CRYPTO_RANDOM) + + if (CCRandomGenerateBytes(buf, buflen) == kCCSuccess) + return (ssize_t)buflen; + + return -1; +# else + union { + void *p; + int (*f)(void *buffer, size_t length); + } p_getentropy; + + /* + * We could cache the result of the lookup, but we normally don't + * call this function often. + */ + ERR_set_mark(); + p_getentropy.p = DSO_global_lookup("getentropy"); + ERR_pop_to_mark(); + if (p_getentropy.p != NULL) + return p_getentropy.f(buf, buflen) == 0 ? (ssize_t)buflen : -1; +# endif +# endif /* !__DragonFly__ */ + + /* Linux supports this since version 3.17 */ +# if defined(__linux) && defined(__NR_getrandom) + return syscall(__NR_getrandom, buf, buflen, 0); +# elif (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND) + return sysctl_random(buf, buflen); +# elif (defined(__DragonFly__) && __DragonFly_version >= 500700) \ + || (defined(__NetBSD__) && __NetBSD_Version >= 1000000000) + return getrandom(buf, buflen, 0); +# else + errno = ENOSYS; + return -1; +# endif +} +# endif /* defined(OPENSSL_RAND_SEED_GETRANDOM) */ + +# if defined(OPENSSL_RAND_SEED_DEVRANDOM) +static const char *random_device_paths[] = { DEVRANDOM }; +static struct random_device { + int fd; + dev_t dev; + ino_t ino; + mode_t mode; + dev_t rdev; +} random_devices[OSSL_NELEM(random_device_paths)]; +static int keep_random_devices_open = 1; + +# if defined(__linux) && defined(DEVRANDOM_WAIT) \ + && defined(OPENSSL_RAND_SEED_GETRANDOM) +static void *shm_addr; + +static void cleanup_shm(void) +{ + shmdt(shm_addr); +} + +/* + * Ensure that the system randomness source has been adequately seeded. + * This is done by having the first start of libcrypto, wait until the device + * /dev/random becomes able to supply a byte of entropy. Subsequent starts + * of the library and later reseedings do not need to do this. + */ +static int wait_random_seeded(void) +{ + static int seeded = OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID < 0; + static const int kernel_version[] = { DEVRANDOM_SAFE_KERNEL }; + int kernel[2]; + int shm_id, fd, r; + char c, *p; + struct utsname un; + fd_set fds; + + if (!seeded) { + /* See if anything has created the global seeded indication */ + if ((shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1, 0)) == -1) { + /* + * Check the kernel's version and fail if it is too recent. + * + * Linux kernels from 4.8 onwards do not guarantee that + * /dev/urandom is properly seeded when /dev/random becomes + * readable. However, such kernels support the getentropy(2) + * system call and this should always succeed which renders + * this alternative but essentially identical source moot. + */ + if (uname(&un) == 0) { + kernel[0] = atoi(un.release); + p = strchr(un.release, '.'); + kernel[1] = p == NULL ? 0 : atoi(p + 1); + if (kernel[0] > kernel_version[0] + || (kernel[0] == kernel_version[0] + && kernel[1] >= kernel_version[1])) { + return 0; + } + } + /* Open /dev/random and wait for it to be readable */ + if ((fd = open(DEVRANDOM_WAIT, O_RDONLY)) != -1) { + if (DEVRANDM_WAIT_USE_SELECT && fd < FD_SETSIZE) { + FD_ZERO(&fds); + FD_SET(fd, &fds); + while ((r = select(fd + 1, &fds, NULL, NULL, NULL)) < 0 + && errno == EINTR); + } else { + while ((r = read(fd, &c, 1)) < 0 && errno == EINTR); + } + close(fd); + if (r == 1) { + seeded = 1; + /* Create the shared memory indicator */ + shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1, + IPC_CREAT | S_IRUSR | S_IRGRP | S_IROTH); + } + } + } + if (shm_id != -1) { + seeded = 1; + /* + * Map the shared memory to prevent its premature destruction. + * If this call fails, it isn't a big problem. + */ + shm_addr = shmat(shm_id, NULL, SHM_RDONLY); + if (shm_addr != (void *)-1) + OPENSSL_atexit(&cleanup_shm); + } + } + return seeded; +} +# else /* defined __linux && DEVRANDOM_WAIT && OPENSSL_RAND_SEED_GETRANDOM */ +static int wait_random_seeded(void) +{ + return 1; +} +# endif + +/* + * Verify that the file descriptor associated with the random source is + * still valid. The rationale for doing this is the fact that it is not + * uncommon for daemons to close all open file handles when daemonizing. + * So the handle might have been closed or even reused for opening + * another file. + */ +static int check_random_device(struct random_device * rd) +{ + struct stat st; + + return rd->fd != -1 + && fstat(rd->fd, &st) != -1 + && rd->dev == st.st_dev + && rd->ino == st.st_ino + && ((rd->mode ^ st.st_mode) & ~(S_IRWXU | S_IRWXG | S_IRWXO)) == 0 + && rd->rdev == st.st_rdev; +} + +/* + * Open a random device if required and return its file descriptor or -1 on error + */ +static int get_random_device(size_t n) +{ + struct stat st; + struct random_device * rd = &random_devices[n]; + + /* reuse existing file descriptor if it is (still) valid */ + if (check_random_device(rd)) + return rd->fd; + + /* open the random device ... */ + if ((rd->fd = open(random_device_paths[n], O_RDONLY)) == -1) + return rd->fd; + + /* ... and cache its relevant stat(2) data */ + if (fstat(rd->fd, &st) != -1) { + rd->dev = st.st_dev; + rd->ino = st.st_ino; + rd->mode = st.st_mode; + rd->rdev = st.st_rdev; + } else { + close(rd->fd); + rd->fd = -1; + } + + return rd->fd; +} + +/* + * Close a random device making sure it is a random device + */ +static void close_random_device(size_t n) +{ + struct random_device * rd = &random_devices[n]; + + if (check_random_device(rd)) + close(rd->fd); + rd->fd = -1; +} + +int ossl_rand_pool_init(void) +{ + size_t i; + + for (i = 0; i < OSSL_NELEM(random_devices); i++) + random_devices[i].fd = -1; + + return 1; +} + +void ossl_rand_pool_cleanup(void) +{ + size_t i; + + for (i = 0; i < OSSL_NELEM(random_devices); i++) + close_random_device(i); +} + +void ossl_rand_pool_keep_random_devices_open(int keep) +{ + if (!keep) + ossl_rand_pool_cleanup(); + + keep_random_devices_open = keep; +} + +# else /* !defined(OPENSSL_RAND_SEED_DEVRANDOM) */ + +int ossl_rand_pool_init(void) +{ + return 1; +} + +void ossl_rand_pool_cleanup(void) +{ +} + +void ossl_rand_pool_keep_random_devices_open(int keep) +{ +} + +# endif /* defined(OPENSSL_RAND_SEED_DEVRANDOM) */ + +/* + * Try the various seeding methods in turn, exit when successful. + * + * If more than one entropy source is available, is it + * preferable to stop as soon as enough entropy has been collected + * (as favored by @rsalz) or should one rather be defensive and add + * more entropy than requested and/or from different sources? + * + * Currently, the user can select multiple entropy sources in the + * configure step, yet in practice only the first available source + * will be used. A more flexible solution has been requested, but + * currently it is not clear how this can be achieved without + * overengineering the problem. There are many parameters which + * could be taken into account when selecting the order and amount + * of input from the different entropy sources (trust, quality, + * possibility of blocking). + */ +size_t ossl_pool_acquire_entropy(RAND_POOL *pool) +{ +# if defined(OPENSSL_RAND_SEED_NONE) + return ossl_rand_pool_entropy_available(pool); +# else + size_t entropy_available = 0; + + (void)entropy_available; /* avoid compiler warning */ + +# if defined(OPENSSL_RAND_SEED_GETRANDOM) + { + size_t bytes_needed; + unsigned char *buffer; + ssize_t bytes; + /* Maximum allowed number of consecutive unsuccessful attempts */ + int attempts = 3; + + bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + while (bytes_needed != 0 && attempts-- > 0) { + buffer = ossl_rand_pool_add_begin(pool, bytes_needed); + bytes = syscall_random(buffer, bytes_needed); + if (bytes > 0) { + ossl_rand_pool_add_end(pool, bytes, 8 * bytes); + bytes_needed -= bytes; + attempts = 3; /* reset counter after successful attempt */ + } else if (bytes < 0 && errno != EINTR) { + break; + } + } + } + entropy_available = ossl_rand_pool_entropy_available(pool); + if (entropy_available > 0) + return entropy_available; +# endif + +# if defined(OPENSSL_RAND_SEED_LIBRANDOM) + { + /* Not yet implemented. */ + } +# endif + +# if defined(OPENSSL_RAND_SEED_DEVRANDOM) + if (wait_random_seeded()) { + size_t bytes_needed; + unsigned char *buffer; + size_t i; + + bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + for (i = 0; bytes_needed > 0 && i < OSSL_NELEM(random_device_paths); + i++) { + ssize_t bytes = 0; + /* Maximum number of consecutive unsuccessful attempts */ + int attempts = 3; + const int fd = get_random_device(i); + + if (fd == -1) + continue; + + while (bytes_needed != 0 && attempts-- > 0) { + buffer = ossl_rand_pool_add_begin(pool, bytes_needed); + bytes = read(fd, buffer, bytes_needed); + + if (bytes > 0) { + ossl_rand_pool_add_end(pool, bytes, 8 * bytes); + bytes_needed -= bytes; + attempts = 3; /* reset counter on successful attempt */ + } else if (bytes < 0 && errno != EINTR) { + break; + } + } + if (bytes < 0 || !keep_random_devices_open) + close_random_device(i); + + bytes_needed = ossl_rand_pool_bytes_needed(pool, 1); + } + entropy_available = ossl_rand_pool_entropy_available(pool); + if (entropy_available > 0) + return entropy_available; + } +# endif + +# if defined(OPENSSL_RAND_SEED_RDTSC) + entropy_available = ossl_prov_acquire_entropy_from_tsc(pool); + if (entropy_available > 0) + return entropy_available; +# endif + +# if defined(OPENSSL_RAND_SEED_RDCPU) + entropy_available = ossl_prov_acquire_entropy_from_cpu(pool); + if (entropy_available > 0) + return entropy_available; +# endif + +# if defined(OPENSSL_RAND_SEED_EGD) + { + static const char *paths[] = { DEVRANDOM_EGD, NULL }; + size_t bytes_needed; + unsigned char *buffer; + int i; + + bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + for (i = 0; bytes_needed > 0 && paths[i] != NULL; i++) { + size_t bytes = 0; + int num; + + buffer = ossl_rand_pool_add_begin(pool, bytes_needed); + num = RAND_query_egd_bytes(paths[i], + buffer, (int)bytes_needed); + if (num == (int)bytes_needed) + bytes = bytes_needed; + + ossl_rand_pool_add_end(pool, bytes, 8 * bytes); + bytes_needed = ossl_rand_pool_bytes_needed(pool, 1); + } + entropy_available = ossl_rand_pool_entropy_available(pool); + if (entropy_available > 0) + return entropy_available; + } +# endif + + return ossl_rand_pool_entropy_available(pool); +# endif +} +# endif +#endif + +#if (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS)) \ + || defined(__DJGPP__) +int ossl_pool_add_nonce_data(RAND_POOL *pool) +{ + struct { + pid_t pid; + CRYPTO_THREAD_ID tid; + uint64_t time; + } data; + + /* Erase the entire structure including any padding */ + memset(&data, 0, sizeof(data)); + + /* + * Add process id, thread id, and a high resolution timestamp to + * ensure that the nonce is unique with high probability for + * different process instances. + */ + data.pid = getpid(); + data.tid = CRYPTO_THREAD_get_current_id(); + data.time = get_time_stamp(); + + return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +int ossl_rand_pool_add_additional_data(RAND_POOL *pool) +{ + struct { + int fork_id; + CRYPTO_THREAD_ID tid; + uint64_t time; + } data; + + /* Erase the entire structure including any padding */ + memset(&data, 0, sizeof(data)); + + /* + * Add some noise from the thread id and a high resolution timer. + * The fork_id adds some extra fork-safety. + * The thread id adds a little randomness if the drbg is accessed + * concurrently (which is the case for the <master> drbg). + */ + data.fork_id = openssl_get_fork_id(); + data.tid = CRYPTO_THREAD_get_current_id(); + data.time = get_timer_bits(); + + return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + + +/* + * Get the current time with the highest possible resolution + * + * The time stamp is added to the nonce, so it is optimized for not repeating. + * The current time is ideal for this purpose, provided the computer's clock + * is synchronized. + */ +static uint64_t get_time_stamp(void) +{ +# if defined(OSSL_POSIX_TIMER_OKAY) + { + struct timespec ts; + + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) + return TWO32TO64(ts.tv_sec, ts.tv_nsec); + } +# endif +# if defined(__unix__) \ + || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) + { + struct timeval tv; + + if (gettimeofday(&tv, NULL) == 0) + return TWO32TO64(tv.tv_sec, tv.tv_usec); + } +# endif + return time(NULL); +} + +/* + * Get an arbitrary timer value of the highest possible resolution + * + * The timer value is added as random noise to the additional data, + * which is not considered a trusted entropy sourec, so any result + * is acceptable. + */ +static uint64_t get_timer_bits(void) +{ + uint64_t res = OPENSSL_rdtsc(); + + if (res != 0) + return res; + +# if defined(__sun) || defined(__hpux) + return gethrtime(); +# elif defined(_AIX) + { + timebasestruct_t t; + + read_wall_time(&t, TIMEBASE_SZ); + return TWO32TO64(t.tb_high, t.tb_low); + } +# elif defined(OSSL_POSIX_TIMER_OKAY) + { + struct timespec ts; + +# ifdef CLOCK_BOOTTIME +# define CLOCK_TYPE CLOCK_BOOTTIME +# elif defined(_POSIX_MONOTONIC_CLOCK) +# define CLOCK_TYPE CLOCK_MONOTONIC +# else +# define CLOCK_TYPE CLOCK_REALTIME +# endif + + if (clock_gettime(CLOCK_TYPE, &ts) == 0) + return TWO32TO64(ts.tv_sec, ts.tv_nsec); + } +# endif +# if defined(__unix__) \ + || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) + { + struct timeval tv; + + if (gettimeofday(&tv, NULL) == 0) + return TWO32TO64(tv.tv_sec, tv.tv_usec); + } +# endif + return time(NULL); +} +#endif /* (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS)) + || defined(__DJGPP__) */ diff --git a/providers/implementations/rands/seeding/rand_vms.c b/providers/implementations/rands/seeding/rand_vms.c new file mode 100644 index 000000000000..f12ecb3b075e --- /dev/null +++ b/providers/implementations/rands/seeding/rand_vms.c @@ -0,0 +1,615 @@ +/* + * Copyright 2001-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "e_os.h" + +#define __NEW_STARLET 1 /* New starlet definitions since VMS 7.0 */ +#include <unistd.h> +#include "internal/cryptlib.h" +#include <openssl/rand.h> +#include "crypto/rand.h" +#include "crypto/rand_pool.h" +#include "prov/seeding.h" +#include <descrip.h> +#include <dvidef.h> +#include <jpidef.h> +#include <rmidef.h> +#include <syidef.h> +#include <ssdef.h> +#include <starlet.h> +#include <efndef.h> +#include <gen64def.h> +#include <iosbdef.h> +#include <iledef.h> +#include <lib$routines.h> +#ifdef __DECC +# pragma message disable DOLLARID +#endif + +#include <dlfcn.h> /* SYS$GET_ENTROPY presence */ + +#ifndef OPENSSL_RAND_SEED_OS +# error "Unsupported seeding method configured; must be os" +#endif + +/* + * DATA COLLECTION METHOD + * ====================== + * + * This is a method to get low quality entropy. + * It works by collecting all kinds of statistical data that + * VMS offers and using them as random seed. + */ + +/* We need to make sure we have the right size pointer in some cases */ +#if __INITIAL_POINTER_SIZE == 64 +# pragma pointer_size save +# pragma pointer_size 32 +#endif +typedef uint32_t *uint32_t__ptr32; +#if __INITIAL_POINTER_SIZE == 64 +# pragma pointer_size restore +#endif + +struct item_st { + short length, code; /* length is number of bytes */ +}; + +static const struct item_st DVI_item_data[] = { + {4, DVI$_ERRCNT}, + {4, DVI$_REFCNT}, +}; + +static const struct item_st JPI_item_data[] = { + {4, JPI$_BUFIO}, + {4, JPI$_CPUTIM}, + {4, JPI$_DIRIO}, + {4, JPI$_IMAGECOUNT}, + {4, JPI$_PAGEFLTS}, + {4, JPI$_PID}, + {4, JPI$_PPGCNT}, + {4, JPI$_WSPEAK}, + /* + * Note: the direct result is just a 32-bit address. However, it points + * to a list of 4 32-bit words, so we make extra space for them so we can + * do in-place replacement of values + */ + {16, JPI$_FINALEXC}, +}; + +static const struct item_st JPI_item_data_64bit[] = { + {8, JPI$_LAST_LOGIN_I}, + {8, JPI$_LOGINTIM}, +}; + +static const struct item_st RMI_item_data[] = { + {4, RMI$_COLPG}, + {4, RMI$_MWAIT}, + {4, RMI$_CEF}, + {4, RMI$_PFW}, + {4, RMI$_LEF}, + {4, RMI$_LEFO}, + {4, RMI$_HIB}, + {4, RMI$_HIBO}, + {4, RMI$_SUSP}, + {4, RMI$_SUSPO}, + {4, RMI$_FPG}, + {4, RMI$_COM}, + {4, RMI$_COMO}, + {4, RMI$_CUR}, +#if defined __alpha + {4, RMI$_FRLIST}, + {4, RMI$_MODLIST}, +#endif + {4, RMI$_FAULTS}, + {4, RMI$_PREADS}, + {4, RMI$_PWRITES}, + {4, RMI$_PWRITIO}, + {4, RMI$_PREADIO}, + {4, RMI$_GVALFLTS}, + {4, RMI$_WRTINPROG}, + {4, RMI$_FREFLTS}, + {4, RMI$_DZROFLTS}, + {4, RMI$_SYSFAULTS}, + {4, RMI$_ISWPCNT}, + {4, RMI$_DIRIO}, + {4, RMI$_BUFIO}, + {4, RMI$_MBREADS}, + {4, RMI$_MBWRITES}, + {4, RMI$_LOGNAM}, + {4, RMI$_FCPCALLS}, + {4, RMI$_FCPREAD}, + {4, RMI$_FCPWRITE}, + {4, RMI$_FCPCACHE}, + {4, RMI$_FCPCPU}, + {4, RMI$_FCPHIT}, + {4, RMI$_FCPSPLIT}, + {4, RMI$_FCPFAULT}, + {4, RMI$_ENQNEW}, + {4, RMI$_ENQCVT}, + {4, RMI$_DEQ}, + {4, RMI$_BLKAST}, + {4, RMI$_ENQWAIT}, + {4, RMI$_ENQNOTQD}, + {4, RMI$_DLCKSRCH}, + {4, RMI$_DLCKFND}, + {4, RMI$_NUMLOCKS}, + {4, RMI$_NUMRES}, + {4, RMI$_ARRLOCPK}, + {4, RMI$_DEPLOCPK}, + {4, RMI$_ARRTRAPK}, + {4, RMI$_TRCNGLOS}, + {4, RMI$_RCVBUFFL}, + {4, RMI$_ENQNEWLOC}, + {4, RMI$_ENQNEWIN}, + {4, RMI$_ENQNEWOUT}, + {4, RMI$_ENQCVTLOC}, + {4, RMI$_ENQCVTIN}, + {4, RMI$_ENQCVTOUT}, + {4, RMI$_DEQLOC}, + {4, RMI$_DEQIN}, + {4, RMI$_DEQOUT}, + {4, RMI$_BLKLOC}, + {4, RMI$_BLKIN}, + {4, RMI$_BLKOUT}, + {4, RMI$_DIRIN}, + {4, RMI$_DIROUT}, + /* We currently get a fault when trying these */ +#if 0 + {140, RMI$_MSCP_EVERYTHING}, /* 35 32-bit words */ + {152, RMI$_DDTM_ALL}, /* 38 32-bit words */ + {80, RMI$_TMSCP_EVERYTHING} /* 20 32-bit words */ +#endif + {4, RMI$_LPZ_PAGCNT}, + {4, RMI$_LPZ_HITS}, + {4, RMI$_LPZ_MISSES}, + {4, RMI$_LPZ_EXPCNT}, + {4, RMI$_LPZ_ALLOCF}, + {4, RMI$_LPZ_ALLOC2}, + {4, RMI$_ACCESS}, + {4, RMI$_ALLOC}, + {4, RMI$_FCPCREATE}, + {4, RMI$_VOLWAIT}, + {4, RMI$_FCPTURN}, + {4, RMI$_FCPERASE}, + {4, RMI$_OPENS}, + {4, RMI$_FIDHIT}, + {4, RMI$_FIDMISS}, + {4, RMI$_FILHDR_HIT}, + {4, RMI$_DIRFCB_HIT}, + {4, RMI$_DIRFCB_MISS}, + {4, RMI$_DIRDATA_HIT}, + {4, RMI$_EXTHIT}, + {4, RMI$_EXTMISS}, + {4, RMI$_QUOHIT}, + {4, RMI$_QUOMISS}, + {4, RMI$_STORAGMAP_HIT}, + {4, RMI$_VOLLCK}, + {4, RMI$_SYNCHLCK}, + {4, RMI$_SYNCHWAIT}, + {4, RMI$_ACCLCK}, + {4, RMI$_XQPCACHEWAIT}, + {4, RMI$_DIRDATA_MISS}, + {4, RMI$_FILHDR_MISS}, + {4, RMI$_STORAGMAP_MISS}, + {4, RMI$_PROCCNTMAX}, + {4, RMI$_PROCBATCNT}, + {4, RMI$_PROCINTCNT}, + {4, RMI$_PROCNETCNT}, + {4, RMI$_PROCSWITCHCNT}, + {4, RMI$_PROCBALSETCNT}, + {4, RMI$_PROCLOADCNT}, + {4, RMI$_BADFLTS}, + {4, RMI$_EXEFAULTS}, + {4, RMI$_HDRINSWAPS}, + {4, RMI$_HDROUTSWAPS}, + {4, RMI$_IOPAGCNT}, + {4, RMI$_ISWPCNTPG}, + {4, RMI$_OSWPCNT}, + {4, RMI$_OSWPCNTPG}, + {4, RMI$_RDFAULTS}, + {4, RMI$_TRANSFLTS}, + {4, RMI$_WRTFAULTS}, +#if defined __alpha + {4, RMI$_USERPAGES}, +#endif + {4, RMI$_VMSPAGES}, + {4, RMI$_TTWRITES}, + {4, RMI$_BUFOBJPAG}, + {4, RMI$_BUFOBJPAGPEAK}, + {4, RMI$_BUFOBJPAGS01}, + {4, RMI$_BUFOBJPAGS2}, + {4, RMI$_BUFOBJPAGMAXS01}, + {4, RMI$_BUFOBJPAGMAXS2}, + {4, RMI$_BUFOBJPAGPEAKS01}, + {4, RMI$_BUFOBJPAGPEAKS2}, + {4, RMI$_BUFOBJPGLTMAXS01}, + {4, RMI$_BUFOBJPGLTMAXS2}, + {4, RMI$_DLCK_INCMPLT}, + {4, RMI$_DLCKMSGS_IN}, + {4, RMI$_DLCKMSGS_OUT}, + {4, RMI$_MCHKERRS}, + {4, RMI$_MEMERRS}, +}; + +static const struct item_st RMI_item_data_64bit[] = { +#if defined __ia64 + {8, RMI$_FRLIST}, + {8, RMI$_MODLIST}, +#endif + {8, RMI$_LCKMGR_REQCNT}, + {8, RMI$_LCKMGR_REQTIME}, + {8, RMI$_LCKMGR_SPINCNT}, + {8, RMI$_LCKMGR_SPINTIME}, + {8, RMI$_CPUINTSTK}, + {8, RMI$_CPUMPSYNCH}, + {8, RMI$_CPUKERNEL}, + {8, RMI$_CPUEXEC}, + {8, RMI$_CPUSUPER}, + {8, RMI$_CPUUSER}, +#if defined __ia64 + {8, RMI$_USERPAGES}, +#endif + {8, RMI$_TQETOTAL}, + {8, RMI$_TQESYSUB}, + {8, RMI$_TQEUSRTIMR}, + {8, RMI$_TQEUSRWAKE}, +}; + +static const struct item_st SYI_item_data[] = { + {4, SYI$_PAGEFILE_FREE}, +}; + +/* + * Input: + * items_data - an array of lengths and codes + * items_data_num - number of elements in that array + * + * Output: + * items - pre-allocated ILE3 array to be filled. + * It's assumed to have items_data_num elements plus + * one extra for the terminating NULL element + * databuffer - pre-allocated 32-bit word array. + * + * Returns the number of elements used in databuffer + */ +static size_t prepare_item_list(const struct item_st *items_input, + size_t items_input_num, + ILE3 *items, + uint32_t__ptr32 databuffer) +{ + size_t data_sz = 0; + + for (; items_input_num-- > 0; items_input++, items++) { + + items->ile3$w_code = items_input->code; + /* Special treatment of JPI$_FINALEXC */ + if (items->ile3$w_code == JPI$_FINALEXC) + items->ile3$w_length = 4; + else + items->ile3$w_length = items_input->length; + + items->ile3$ps_bufaddr = databuffer; + items->ile3$ps_retlen_addr = 0; + + databuffer += items_input->length / sizeof(databuffer[0]); + data_sz += items_input->length; + } + /* Terminating NULL entry */ + items->ile3$w_length = items->ile3$w_code = 0; + items->ile3$ps_bufaddr = items->ile3$ps_retlen_addr = NULL; + + return data_sz / sizeof(databuffer[0]); +} + +static void massage_JPI(ILE3 *items) +{ + /* + * Special treatment of JPI$_FINALEXC + * The result of that item's data buffer is a 32-bit address to a list of + * 4 32-bit words. + */ + for (; items->ile3$w_length != 0; items++) { + if (items->ile3$w_code == JPI$_FINALEXC) { + uint32_t *data = items->ile3$ps_bufaddr; + uint32_t *ptr = (uint32_t *)*data; + size_t j; + + /* + * We know we made space for 4 32-bit words, so we can do in-place + * replacement. + */ + for (j = 0; j < 4; j++) + data[j] = ptr[j]; + + break; + } + } +} + +/* + * This number expresses how many bits of data contain 1 bit of entropy. + * + * For the moment, we assume about 0.05 entropy bits per data bit, or 1 + * bit of entropy per 20 data bits. + */ +#define ENTROPY_FACTOR 20 + +size_t data_collect_method(RAND_POOL *pool) +{ + ILE3 JPI_items_64bit[OSSL_NELEM(JPI_item_data_64bit) + 1]; + ILE3 RMI_items_64bit[OSSL_NELEM(RMI_item_data_64bit) + 1]; + ILE3 DVI_items[OSSL_NELEM(DVI_item_data) + 1]; + ILE3 JPI_items[OSSL_NELEM(JPI_item_data) + 1]; + ILE3 RMI_items[OSSL_NELEM(RMI_item_data) + 1]; + ILE3 SYI_items[OSSL_NELEM(SYI_item_data) + 1]; + union { + /* This ensures buffer starts at 64 bit boundary */ + uint64_t dummy; + uint32_t buffer[OSSL_NELEM(JPI_item_data_64bit) * 2 + + OSSL_NELEM(RMI_item_data_64bit) * 2 + + OSSL_NELEM(DVI_item_data) + + OSSL_NELEM(JPI_item_data) + + OSSL_NELEM(RMI_item_data) + + OSSL_NELEM(SYI_item_data) + + 4 /* For JPI$_FINALEXC */]; + } data; + size_t total_elems = 0; + size_t total_length = 0; + size_t bytes_needed = ossl_rand_pool_bytes_needed(pool, ENTROPY_FACTOR); + size_t bytes_remaining = ossl_rand_pool_bytes_remaining(pool); + + /* Take all the 64-bit items first, to ensure proper alignment of data */ + total_elems += + prepare_item_list(JPI_item_data_64bit, OSSL_NELEM(JPI_item_data_64bit), + JPI_items_64bit, &data.buffer[total_elems]); + total_elems += + prepare_item_list(RMI_item_data_64bit, OSSL_NELEM(RMI_item_data_64bit), + RMI_items_64bit, &data.buffer[total_elems]); + /* Now the 32-bit items */ + total_elems += prepare_item_list(DVI_item_data, OSSL_NELEM(DVI_item_data), + DVI_items, &data.buffer[total_elems]); + total_elems += prepare_item_list(JPI_item_data, OSSL_NELEM(JPI_item_data), + JPI_items, &data.buffer[total_elems]); + total_elems += prepare_item_list(RMI_item_data, OSSL_NELEM(RMI_item_data), + RMI_items, &data.buffer[total_elems]); + total_elems += prepare_item_list(SYI_item_data, OSSL_NELEM(SYI_item_data), + SYI_items, &data.buffer[total_elems]); + total_length = total_elems * sizeof(data.buffer[0]); + + /* Fill data.buffer with various info bits from this process */ + { + uint32_t status; + uint32_t efn; + IOSB iosb; + $DESCRIPTOR(SYSDEVICE,"SYS$SYSDEVICE:"); + + if ((status = sys$getdviw(EFN$C_ENF, 0, &SYSDEVICE, DVI_items, + 0, 0, 0, 0, 0)) != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, JPI_items_64bit, 0, 0, 0)) + != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, JPI_items, 0, 0, 0)) + != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$getsyiw(EFN$C_ENF, 0, 0, SYI_items, 0, 0, 0)) + != SS$_NORMAL) { + lib$signal(status); + return 0; + } + /* + * The RMI service is a bit special, as there is no synchronous + * variant, so we MUST create an event flag to synchronise on. + */ + if ((status = lib$get_ef(&efn)) != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$getrmi(efn, 0, 0, RMI_items_64bit, &iosb, 0, 0)) + != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$synch(efn, &iosb)) != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if (iosb.iosb$l_getxxi_status != SS$_NORMAL) { + lib$signal(iosb.iosb$l_getxxi_status); + return 0; + } + if ((status = sys$getrmi(efn, 0, 0, RMI_items, &iosb, 0, 0)) + != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$synch(efn, &iosb)) != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if (iosb.iosb$l_getxxi_status != SS$_NORMAL) { + lib$signal(iosb.iosb$l_getxxi_status); + return 0; + } + if ((status = lib$free_ef(&efn)) != SS$_NORMAL) { + lib$signal(status); + return 0; + } + } + + massage_JPI(JPI_items); + + /* + * If we can't feed the requirements from the caller, we're in deep trouble. + */ + if (!ossl_assert(total_length >= bytes_needed)) { + ERR_raise_data(ERR_LIB_RAND, RAND_R_RANDOM_POOL_UNDERFLOW, + "Needed: %zu, Available: %zu", + bytes_needed, total_length); + return 0; + } + + /* + * Try not to overfeed the pool + */ + if (total_length > bytes_remaining) + total_length = bytes_remaining; + + /* We give the pessimistic value for the amount of entropy */ + ossl_rand_pool_add(pool, (unsigned char *)data.buffer, total_length, + 8 * total_length / ENTROPY_FACTOR); + return ossl_rand_pool_entropy_available(pool); +} + +/* + * SYS$GET_ENTROPY METHOD + * ====================== + * + * This is a high entropy method based on a new system service that is + * based on getentropy() from FreeBSD 12. It's only used if available, + * and its availability is detected at run-time. + * + * We assume that this function provides full entropy random output. + */ +#define PUBLIC_VECTORS "SYS$LIBRARY:SYS$PUBLIC_VECTORS.EXE" +#define GET_ENTROPY "SYS$GET_ENTROPY" + +static int get_entropy_address_flag = 0; +static int (*get_entropy_address)(void *buffer, size_t buffer_size) = NULL; +static int init_get_entropy_address(void) +{ + if (get_entropy_address_flag == 0) + get_entropy_address = dlsym(dlopen(PUBLIC_VECTORS, 0), GET_ENTROPY); + get_entropy_address_flag = 1; + return get_entropy_address != NULL; +} + +size_t get_entropy_method(RAND_POOL *pool) +{ + /* + * The documentation says that SYS$GET_ENTROPY will give a maximum of + * 256 bytes of data. + */ + unsigned char buffer[256]; + size_t bytes_needed; + size_t bytes_to_get = 0; + uint32_t status; + + for (bytes_needed = ossl_rand_pool_bytes_needed(pool, 1); + bytes_needed > 0; + bytes_needed -= bytes_to_get) { + bytes_to_get = + bytes_needed > sizeof(buffer) ? sizeof(buffer) : bytes_needed; + + status = get_entropy_address(buffer, bytes_to_get); + if (status == SS$_RETRY) { + /* Set to zero so the loop doesn't diminish |bytes_needed| */ + bytes_to_get = 0; + /* Should sleep some amount of time */ + continue; + } + + if (status != SS$_NORMAL) { + lib$signal(status); + return 0; + } + + ossl_rand_pool_add(pool, buffer, bytes_to_get, 8 * bytes_to_get); + } + + return ossl_rand_pool_entropy_available(pool); +} + +/* + * MAIN ENTROPY ACQUISITION FUNCTIONS + * ================================== + * + * These functions are called by the RAND / DRBG functions + */ + +size_t ossl_pool_acquire_entropy(RAND_POOL *pool) +{ + if (init_get_entropy_address()) + return get_entropy_method(pool); + return data_collect_method(pool); +} + +int ossl_pool_add_nonce_data(RAND_POOL *pool) +{ + /* + * Two variables to ensure that two nonces won't ever be the same + */ + static unsigned __int64 last_time = 0; + static unsigned __int32 last_seq = 0; + + struct { + pid_t pid; + CRYPTO_THREAD_ID tid; + unsigned __int64 time; + unsigned __int32 seq; + } data; + + /* Erase the entire structure including any padding */ + memset(&data, 0, sizeof(data)); + + /* + * Add process id, thread id, a timestamp, and a sequence number in case + * the same time stamp is repeated, to ensure that the nonce is unique + * with high probability for different process instances. + * + * The normal OpenVMS time is specified to be high granularity (100ns), + * but the time update granularity given by sys$gettim() may be lower. + * + * OpenVMS version 8.4 (which is the latest for Alpha and Itanium) and + * on have sys$gettim_prec() as well, which is supposedly having a better + * time update granularity, but tests on Itanium (and even Alpha) have + * shown that compared with sys$gettim(), the difference is marginal, + * so of very little significance in terms of entropy. + * Given that, and that it's a high ask to expect everyone to have + * upgraded to OpenVMS version 8.4, only sys$gettim() is used, and a + * sequence number is added as well, in case sys$gettim() returns the + * same time value more than once. + * + * This function is assumed to be called under thread lock, and does + * therefore not take concurrency into account. + */ + data.pid = getpid(); + data.tid = CRYPTO_THREAD_get_current_id(); + data.seq = 0; + sys$gettim((void*)&data.time); + + if (data.time == last_time) { + data.seq = ++last_seq; + } else { + last_time = data.time; + last_seq = 0; + } + + return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +int ossl_rand_pool_init(void) +{ + return 1; +} + +void ossl_rand_pool_cleanup(void) +{ +} + +void ossl_rand_pool_keep_random_devices_open(int keep) +{ +} diff --git a/providers/implementations/rands/seeding/rand_vxworks.c b/providers/implementations/rands/seeding/rand_vxworks.c new file mode 100644 index 000000000000..12be9357bf28 --- /dev/null +++ b/providers/implementations/rands/seeding/rand_vxworks.c @@ -0,0 +1,167 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/opensslconf.h> + +#include <openssl/rand.h> +#include "crypto/rand_pool.h" +#include "crypto/rand.h" +#include "internal/cryptlib.h" +#include "prov/seeding.h" +#include <version.h> +#include <taskLib.h> + +#if defined(OPENSSL_RAND_SEED_NONE) +/* none means none */ +# undef OPENSSL_RAND_SEED_OS +#endif + +#if defined(OPENSSL_RAND_SEED_OS) +# if _WRS_VXWORKS_MAJOR >= 7 +# define RAND_SEED_VXRANDLIB +# else +# error "VxWorks <7 only support RAND_SEED_NONE" +# endif +#endif + +#if defined(RAND_SEED_VXRANDLIB) +# include <randomNumGen.h> +#endif + +/* Macro to convert two thirty two bit values into a sixty four bit one */ +#define TWO32TO64(a, b) ((((uint64_t)(a)) << 32) + (b)) + +static uint64_t get_time_stamp(void) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) + return TWO32TO64(ts.tv_sec, ts.tv_nsec); + return time(NULL); +} + +static uint64_t get_timer_bits(void) +{ + uint64_t res = OPENSSL_rdtsc(); + struct timespec ts; + + if (res != 0) + return res; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + return TWO32TO64(ts.tv_sec, ts.tv_nsec); + return time(NULL); +} + +/* + * empty implementation + * vxworks does not need to init/cleanup or keep open the random lib + */ +int ossl_rand_pool_init(void) +{ + return 1; +} + +void ossl_rand_pool_cleanup(void) +{ +} + +void ossl_rand_pool_keep_random_devices_open(int keep) +{ +} + +int ossl_rand_pool_add_additional_data(RAND_POOL *pool) +{ + struct { + CRYPTO_THREAD_ID tid; + uint64_t time; + } data; + + memset(&data, 0, sizeof(data)); + + /* + * Add some noise from the thread id and a high resolution timer. + * The thread id adds a little randomness if the drbg is accessed + * concurrently (which is the case for the <master> drbg). + */ + data.tid = CRYPTO_THREAD_get_current_id(); + data.time = get_timer_bits(); + + return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +int ossl_pool_add_nonce_data(RAND_POOL *pool) +{ + struct { + pid_t pid; + CRYPTO_THREAD_ID tid; + uint64_t time; + } data; + + memset(&data, 0, sizeof(data)); + + /* + * Add process id, thread id, and a high resolution timestamp to + * ensure that the nonce is unique with high probability for + * different process instances. + */ + data.pid = getpid(); + data.tid = CRYPTO_THREAD_get_current_id(); + data.time = get_time_stamp(); + + return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +size_t ossl_pool_acquire_entropy(RAND_POOL *pool) +{ +#if defined(RAND_SEED_VXRANDLIB) + /* vxRandLib based entropy method */ + size_t bytes_needed; + + bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + if (bytes_needed > 0) + { + int retryCount = 0; + STATUS result = ERROR; + unsigned char *buffer; + + buffer = ossl_rand_pool_add_begin(pool, bytes_needed); + while ((result != OK) && (retryCount < 10)) { + RANDOM_NUM_GEN_STATUS status = randStatus(); + + if ((status == RANDOM_NUM_GEN_ENOUGH_ENTROPY) + || (status == RANDOM_NUM_GEN_MAX_ENTROPY) ) { + result = randBytes(buffer, bytes_needed); + if (result == OK) + ossl_rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed); + /* + * no else here: randStatus said ok, if randBytes failed + * it will result in another loop or no entropy + */ + } else { + /* + * give a minimum delay here to allow OS to collect more + * entropy. taskDelay duration will depend on the system tick, + * this is by design as the sw-random lib uses interrupts + * which will at least happen during ticks + */ + taskDelay(5); + } + retryCount++; + } + } + return ossl_rand_pool_entropy_available(pool); +#else + /* + * SEED_NONE means none, without randlib we dont have entropy and + * rely on it being added externally + */ + return ossl_rand_pool_entropy_available(pool); +#endif /* defined(RAND_SEED_VXRANDLIB) */ +} diff --git a/providers/implementations/rands/seeding/rand_win.c b/providers/implementations/rands/seeding/rand_win.c new file mode 100644 index 000000000000..cf903f3cb5a2 --- /dev/null +++ b/providers/implementations/rands/seeding/rand_win.c @@ -0,0 +1,183 @@ +/* + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "internal/cryptlib.h" +#include <openssl/rand.h> +#include "crypto/rand_pool.h" +#include "crypto/rand.h" +#include "prov/seeding.h" + +#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) + +# ifndef OPENSSL_RAND_SEED_OS +# error "Unsupported seeding method configured; must be os" +# endif + +# include <windows.h> +/* On Windows Vista or higher use BCrypt instead of the legacy CryptoAPI */ +# if defined(_MSC_VER) && _MSC_VER > 1500 /* 1500 = Visual Studio 2008 */ \ + && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 +# define USE_BCRYPTGENRANDOM +# endif + +# ifdef USE_BCRYPTGENRANDOM +# include <bcrypt.h> +# ifdef _MSC_VER +# pragma comment(lib, "bcrypt.lib") +# endif +# ifndef STATUS_SUCCESS +# define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +# endif +# else +# include <wincrypt.h> +/* + * Intel hardware RNG CSP -- available from + * http://developer.intel.com/design/security/rng/redist_license.htm + */ +# define PROV_INTEL_SEC 22 +# define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider" +# endif + +size_t ossl_pool_acquire_entropy(RAND_POOL *pool) +{ +# ifndef USE_BCRYPTGENRANDOM + HCRYPTPROV hProvider; +# endif + unsigned char *buffer; + size_t bytes_needed; + size_t entropy_available = 0; + + +# ifdef OPENSSL_RAND_SEED_RDTSC + entropy_available = ossl_prov_acquire_entropy_from_tsc(pool); + if (entropy_available > 0) + return entropy_available; +# endif + +# ifdef OPENSSL_RAND_SEED_RDCPU + entropy_available = ossl_prov_acquire_entropy_from_cpu(pool); + if (entropy_available > 0) + return entropy_available; +# endif + +# ifdef USE_BCRYPTGENRANDOM + bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + buffer = ossl_rand_pool_add_begin(pool, bytes_needed); + if (buffer != NULL) { + size_t bytes = 0; + if (BCryptGenRandom(NULL, buffer, bytes_needed, + BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS) + bytes = bytes_needed; + + ossl_rand_pool_add_end(pool, bytes, 8 * bytes); + entropy_available = ossl_rand_pool_entropy_available(pool); + } + if (entropy_available > 0) + return entropy_available; +# else + bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + buffer = ossl_rand_pool_add_begin(pool, bytes_needed); + if (buffer != NULL) { + size_t bytes = 0; + /* poll the CryptoAPI PRNG */ + if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) { + if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0) + bytes = bytes_needed; + + CryptReleaseContext(hProvider, 0); + } + + ossl_rand_pool_add_end(pool, bytes, 8 * bytes); + entropy_available = ossl_rand_pool_entropy_available(pool); + } + if (entropy_available > 0) + return entropy_available; + + bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + buffer = ossl_rand_pool_add_begin(pool, bytes_needed); + if (buffer != NULL) { + size_t bytes = 0; + /* poll the Pentium PRG with CryptoAPI */ + if (CryptAcquireContextW(&hProvider, NULL, + INTEL_DEF_PROV, PROV_INTEL_SEC, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) { + if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0) + bytes = bytes_needed; + + CryptReleaseContext(hProvider, 0); + } + ossl_rand_pool_add_end(pool, bytes, 8 * bytes); + entropy_available = ossl_rand_pool_entropy_available(pool); + } + if (entropy_available > 0) + return entropy_available; +# endif + + return ossl_rand_pool_entropy_available(pool); +} + + +int ossl_pool_add_nonce_data(RAND_POOL *pool) +{ + struct { + DWORD pid; + DWORD tid; + FILETIME time; + } data; + + /* Erase the entire structure including any padding */ + memset(&data, 0, sizeof(data)); + + /* + * Add process id, thread id, and a high resolution timestamp to + * ensure that the nonce is unique with high probability for + * different process instances. + */ + data.pid = GetCurrentProcessId(); + data.tid = GetCurrentThreadId(); + GetSystemTimeAsFileTime(&data.time); + + return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +int ossl_rand_pool_add_additional_data(RAND_POOL *pool) +{ + struct { + DWORD tid; + LARGE_INTEGER time; + } data; + + /* Erase the entire structure including any padding */ + memset(&data, 0, sizeof(data)); + + /* + * Add some noise from the thread id and a high resolution timer. + * The thread id adds a little randomness if the drbg is accessed + * concurrently (which is the case for the <master> drbg). + */ + data.tid = GetCurrentThreadId(); + QueryPerformanceCounter(&data.time); + return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +int ossl_rand_pool_init(void) +{ + return 1; +} + +void ossl_rand_pool_cleanup(void) +{ +} + +void ossl_rand_pool_keep_random_devices_open(int keep) +{ +} + +#endif diff --git a/providers/implementations/rands/test_rng.c b/providers/implementations/rands/test_rng.c new file mode 100644 index 000000000000..4e7fed0fc7b1 --- /dev/null +++ b/providers/implementations/rands/test_rng.c @@ -0,0 +1,296 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> +#include <openssl/core_dispatch.h> +#include <openssl/e_os2.h> +#include <openssl/params.h> +#include <openssl/core_names.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/randerr.h> +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "prov/provider_util.h" +#include "prov/implementations.h" + +static OSSL_FUNC_rand_newctx_fn test_rng_new; +static OSSL_FUNC_rand_freectx_fn test_rng_free; +static OSSL_FUNC_rand_instantiate_fn test_rng_instantiate; +static OSSL_FUNC_rand_uninstantiate_fn test_rng_uninstantiate; +static OSSL_FUNC_rand_generate_fn test_rng_generate; +static OSSL_FUNC_rand_reseed_fn test_rng_reseed; +static OSSL_FUNC_rand_nonce_fn test_rng_nonce; +static OSSL_FUNC_rand_settable_ctx_params_fn test_rng_settable_ctx_params; +static OSSL_FUNC_rand_set_ctx_params_fn test_rng_set_ctx_params; +static OSSL_FUNC_rand_gettable_ctx_params_fn test_rng_gettable_ctx_params; +static OSSL_FUNC_rand_get_ctx_params_fn test_rng_get_ctx_params; +static OSSL_FUNC_rand_verify_zeroization_fn test_rng_verify_zeroization; +static OSSL_FUNC_rand_enable_locking_fn test_rng_enable_locking; +static OSSL_FUNC_rand_lock_fn test_rng_lock; +static OSSL_FUNC_rand_unlock_fn test_rng_unlock; +static OSSL_FUNC_rand_get_seed_fn test_rng_get_seed; + +typedef struct { + void *provctx; + int state; + unsigned int strength; + size_t max_request; + unsigned char *entropy, *nonce; + size_t entropy_len, entropy_pos, nonce_len; + CRYPTO_RWLOCK *lock; +} PROV_TEST_RNG; + +static void *test_rng_new(void *provctx, void *parent, + const OSSL_DISPATCH *parent_dispatch) +{ + PROV_TEST_RNG *t; + + t = OPENSSL_zalloc(sizeof(*t)); + if (t == NULL) + return NULL; + + t->max_request = INT_MAX; + t->provctx = provctx; + t->state = EVP_RAND_STATE_UNINITIALISED; + return t; +} + +static void test_rng_free(void *vtest) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + + if (t == NULL) + return; + OPENSSL_free(t->entropy); + OPENSSL_free(t->nonce); + CRYPTO_THREAD_lock_free(t->lock); + OPENSSL_free(t); +} + +static int test_rng_instantiate(void *vtest, unsigned int strength, + int prediction_resistance, + const unsigned char *pstr, size_t pstr_len, + const OSSL_PARAM params[]) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + + if (!test_rng_set_ctx_params(t, params) || strength > t->strength) + return 0; + + t->state = EVP_RAND_STATE_READY; + t->entropy_pos = 0; + + return 1; +} + +static int test_rng_uninstantiate(void *vtest) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + + t->entropy_pos = 0; + t->state = EVP_RAND_STATE_UNINITIALISED; + return 1; +} + +static int test_rng_generate(void *vtest, unsigned char *out, size_t outlen, + unsigned int strength, int prediction_resistance, + const unsigned char *adin, size_t adin_len) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + + if (strength > t->strength || t->entropy_len - t->entropy_pos < outlen) + return 0; + memcpy(out, t->entropy + t->entropy_pos, outlen); + t->entropy_pos += outlen; + return 1; +} + +static int test_rng_reseed(ossl_unused void *vtest, + ossl_unused int prediction_resistance, + ossl_unused const unsigned char *ent, + ossl_unused size_t ent_len, + ossl_unused const unsigned char *adin, + ossl_unused size_t adin_len) +{ + return 1; +} + +static size_t test_rng_nonce(void *vtest, unsigned char *out, + unsigned int strength, + ossl_unused size_t min_noncelen, + ossl_unused size_t max_noncelen) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + + if (t->nonce == NULL || strength > t->strength) + return 0; + + if (out != NULL) + memcpy(out, t->nonce, t->nonce_len); + return t->nonce_len; +} + +static int test_rng_get_ctx_params(void *vtest, OSSL_PARAM params[]) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE); + if (p != NULL && !OSSL_PARAM_set_int(p, t->state)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH); + if (p != NULL && !OSSL_PARAM_set_int(p, t->strength)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST); + if (p != NULL && !OSSL_PARAM_set_size_t(p, t->max_request)) + return 0; + return 1; +} + +static const OSSL_PARAM *test_rng_gettable_ctx_params(ossl_unused void *vtest, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, NULL), + OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL), + OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL), + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +static int test_rng_set_ctx_params(void *vtest, const OSSL_PARAM params[]) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + const OSSL_PARAM *p; + void *ptr = NULL; + size_t size = 0; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_STRENGTH); + if (p != NULL && !OSSL_PARAM_get_uint(p, &t->strength)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_TEST_ENTROPY); + if (p != NULL) { + if (!OSSL_PARAM_get_octet_string(p, &ptr, 0, &size)) + return 0; + OPENSSL_free(t->entropy); + t->entropy = ptr; + t->entropy_len = size; + t->entropy_pos = 0; + ptr = NULL; + } + + p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_TEST_NONCE); + if (p != NULL) { + if (!OSSL_PARAM_get_octet_string(p, &ptr, 0, &size)) + return 0; + OPENSSL_free(t->nonce); + t->nonce = ptr; + t->nonce_len = size; + } + + p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_MAX_REQUEST); + if (p != NULL && !OSSL_PARAM_get_size_t(p, &t->max_request)) + return 0; + + return 1; +} + +static const OSSL_PARAM *test_rng_settable_ctx_params(ossl_unused void *vtest, + ossl_unused void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_RAND_PARAM_TEST_ENTROPY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_RAND_PARAM_TEST_NONCE, NULL, 0), + OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL), + OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int test_rng_verify_zeroization(ossl_unused void *vtest) +{ + return 1; +} + +static size_t test_rng_get_seed(void *vtest, unsigned char **pout, + int entropy, size_t min_len, size_t max_len, + ossl_unused int prediction_resistance, + ossl_unused const unsigned char *adin, + ossl_unused size_t adin_len) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + + *pout = t->entropy; + return t->entropy_len > max_len ? max_len : t->entropy_len; +} + +static int test_rng_enable_locking(void *vtest) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + + if (t != NULL && t->lock == NULL) { + t->lock = CRYPTO_THREAD_lock_new(); + if (t->lock == NULL) { + ERR_raise(ERR_LIB_PROV, RAND_R_FAILED_TO_CREATE_LOCK); + return 0; + } + } + return 1; +} + +static int test_rng_lock(void *vtest) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + + if (t == NULL || t->lock == NULL) + return 1; + return CRYPTO_THREAD_write_lock(t->lock); +} + +static void test_rng_unlock(void *vtest) +{ + PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + + if (t != NULL && t->lock != NULL) + CRYPTO_THREAD_unlock(t->lock); +} + +const OSSL_DISPATCH ossl_test_rng_functions[] = { + { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))test_rng_new }, + { OSSL_FUNC_RAND_FREECTX, (void(*)(void))test_rng_free }, + { OSSL_FUNC_RAND_INSTANTIATE, + (void(*)(void))test_rng_instantiate }, + { OSSL_FUNC_RAND_UNINSTANTIATE, + (void(*)(void))test_rng_uninstantiate }, + { OSSL_FUNC_RAND_GENERATE, (void(*)(void))test_rng_generate }, + { OSSL_FUNC_RAND_RESEED, (void(*)(void))test_rng_reseed }, + { OSSL_FUNC_RAND_NONCE, (void(*)(void))test_rng_nonce }, + { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))test_rng_enable_locking }, + { OSSL_FUNC_RAND_LOCK, (void(*)(void))test_rng_lock }, + { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))test_rng_unlock }, + { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS, + (void(*)(void))test_rng_settable_ctx_params }, + { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))test_rng_set_ctx_params }, + { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, + (void(*)(void))test_rng_gettable_ctx_params }, + { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))test_rng_get_ctx_params }, + { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, + (void(*)(void))test_rng_verify_zeroization }, + { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))test_rng_get_seed }, + { 0, NULL } +}; diff --git a/providers/implementations/signature/build.info b/providers/implementations/signature/build.info new file mode 100644 index 000000000000..fd3be7f3b9dd --- /dev/null +++ b/providers/implementations/signature/build.info @@ -0,0 +1,30 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$DSA_GOAL=../../libdefault.a ../../libfips.a +$EC_GOAL=../../libdefault.a ../../libfips.a +$MAC_GOAL=../../libdefault.a ../../libfips.a +$RSA_GOAL=../../libdefault.a ../../libfips.a +$SM2_GOAL=../../libdefault.a + +IF[{- !$disabled{dsa} -}] + SOURCE[$DSA_GOAL]=dsa_sig.c +ENDIF + +IF[{- !$disabled{ec} -}] + SOURCE[$EC_GOAL]=eddsa_sig.c ecdsa_sig.c +ENDIF + +IF[{- !$disabled{sm2} -}] + SOURCE[$SM2_GOAL]=sm2_sig.c +ENDIF + +SOURCE[$RSA_GOAL]=rsa_sig.c + +DEPEND[rsa_sig.o]=../../common/include/prov/der_rsa.h +DEPEND[dsa_sig.o]=../../common/include/prov/der_dsa.h +DEPEND[ecdsa_sig.o]=../../common/include/prov/der_ec.h +DEPEND[eddsa_sig.o]=../../common/include/prov/der_ecx.h +DEPEND[sm2_sig.o]=../../common/include/prov/der_sm2.h + +SOURCE[$MAC_GOAL]=mac_legacy_sig.c diff --git a/providers/implementations/signature/dsa_sig.c b/providers/implementations/signature/dsa_sig.c new file mode 100644 index 000000000000..28fd7c498e99 --- /dev/null +++ b/providers/implementations/signature/dsa_sig.c @@ -0,0 +1,601 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> + +#include <openssl/crypto.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/err.h> +#include <openssl/dsa.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include "internal/nelem.h" +#include "internal/sizes.h" +#include "internal/cryptlib.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/securitycheck.h" +#include "crypto/dsa.h" +#include "prov/der_dsa.h" + +static OSSL_FUNC_signature_newctx_fn dsa_newctx; +static OSSL_FUNC_signature_sign_init_fn dsa_sign_init; +static OSSL_FUNC_signature_verify_init_fn dsa_verify_init; +static OSSL_FUNC_signature_sign_fn dsa_sign; +static OSSL_FUNC_signature_verify_fn dsa_verify; +static OSSL_FUNC_signature_digest_sign_init_fn dsa_digest_sign_init; +static OSSL_FUNC_signature_digest_sign_update_fn dsa_digest_signverify_update; +static OSSL_FUNC_signature_digest_sign_final_fn dsa_digest_sign_final; +static OSSL_FUNC_signature_digest_verify_init_fn dsa_digest_verify_init; +static OSSL_FUNC_signature_digest_verify_update_fn dsa_digest_signverify_update; +static OSSL_FUNC_signature_digest_verify_final_fn dsa_digest_verify_final; +static OSSL_FUNC_signature_freectx_fn dsa_freectx; +static OSSL_FUNC_signature_dupctx_fn dsa_dupctx; +static OSSL_FUNC_signature_get_ctx_params_fn dsa_get_ctx_params; +static OSSL_FUNC_signature_gettable_ctx_params_fn dsa_gettable_ctx_params; +static OSSL_FUNC_signature_set_ctx_params_fn dsa_set_ctx_params; +static OSSL_FUNC_signature_settable_ctx_params_fn dsa_settable_ctx_params; +static OSSL_FUNC_signature_get_ctx_md_params_fn dsa_get_ctx_md_params; +static OSSL_FUNC_signature_gettable_ctx_md_params_fn dsa_gettable_ctx_md_params; +static OSSL_FUNC_signature_set_ctx_md_params_fn dsa_set_ctx_md_params; +static OSSL_FUNC_signature_settable_ctx_md_params_fn dsa_settable_ctx_md_params; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes DSA structures, so + * we use that here too. + */ + +typedef struct { + OSSL_LIB_CTX *libctx; + char *propq; + DSA *dsa; + + /* + * Flag to determine if the hash function can be changed (1) or not (0) + * Because it's dangerous to change during a DigestSign or DigestVerify + * operation, this flag is cleared by their Init function, and set again + * by their Final function. + */ + unsigned int flag_allow_md : 1; + + char mdname[OSSL_MAX_NAME_SIZE]; + + /* The Algorithm Identifier of the combined signature algorithm */ + unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE]; + unsigned char *aid; + size_t aid_len; + + /* main digest */ + EVP_MD *md; + EVP_MD_CTX *mdctx; + int operation; +} PROV_DSA_CTX; + + +static size_t dsa_get_md_size(const PROV_DSA_CTX *pdsactx) +{ + if (pdsactx->md != NULL) + return EVP_MD_get_size(pdsactx->md); + return 0; +} + +static void *dsa_newctx(void *provctx, const char *propq) +{ + PROV_DSA_CTX *pdsactx; + + if (!ossl_prov_is_running()) + return NULL; + + pdsactx = OPENSSL_zalloc(sizeof(PROV_DSA_CTX)); + if (pdsactx == NULL) + return NULL; + + pdsactx->libctx = PROV_LIBCTX_OF(provctx); + pdsactx->flag_allow_md = 1; + if (propq != NULL && (pdsactx->propq = OPENSSL_strdup(propq)) == NULL) { + OPENSSL_free(pdsactx); + pdsactx = NULL; + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + } + return pdsactx; +} + +static int dsa_setup_md(PROV_DSA_CTX *ctx, + const char *mdname, const char *mdprops) +{ + if (mdprops == NULL) + mdprops = ctx->propq; + + if (mdname != NULL) { + int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); + WPACKET pkt; + EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops); + int md_nid = ossl_digest_get_approved_nid_with_sha1(ctx->libctx, md, + sha1_allowed); + size_t mdname_len = strlen(mdname); + + if (md == NULL || md_nid < 0) { + if (md == NULL) + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "%s could not be fetched", mdname); + if (md_nid < 0) + ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, + "digest=%s", mdname); + if (mdname_len >= sizeof(ctx->mdname)) + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "%s exceeds name buffer length", mdname); + EVP_MD_free(md); + return 0; + } + + if (!ctx->flag_allow_md) { + if (ctx->mdname[0] != '\0' && !EVP_MD_is_a(md, ctx->mdname)) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, + "digest %s != %s", mdname, ctx->mdname); + EVP_MD_free(md); + return 0; + } + EVP_MD_free(md); + return 1; + } + + EVP_MD_CTX_free(ctx->mdctx); + EVP_MD_free(ctx->md); + + /* + * We do not care about DER writing errors. + * All it really means is that for some reason, there's no + * AlgorithmIdentifier to be had, but the operation itself is + * still valid, just as long as it's not used to construct + * anything that needs an AlgorithmIdentifier. + */ + ctx->aid_len = 0; + if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf)) + && ossl_DER_w_algorithmIdentifier_DSA_with_MD(&pkt, -1, ctx->dsa, + md_nid) + && WPACKET_finish(&pkt)) { + WPACKET_get_total_written(&pkt, &ctx->aid_len); + ctx->aid = WPACKET_get_curr(&pkt); + } + WPACKET_cleanup(&pkt); + + ctx->mdctx = NULL; + ctx->md = md; + OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname)); + } + return 1; +} + +static int dsa_signverify_init(void *vpdsactx, void *vdsa, + const OSSL_PARAM params[], int operation) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + + if (!ossl_prov_is_running() + || pdsactx == NULL) + return 0; + + if (vdsa == NULL && pdsactx->dsa == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } + + if (vdsa != NULL) { + if (!ossl_dsa_check_key(pdsactx->libctx, vdsa, + operation == EVP_PKEY_OP_SIGN)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + if (!DSA_up_ref(vdsa)) + return 0; + DSA_free(pdsactx->dsa); + pdsactx->dsa = vdsa; + } + + pdsactx->operation = operation; + + if (!dsa_set_ctx_params(pdsactx, params)) + return 0; + + return 1; +} + +static int dsa_sign_init(void *vpdsactx, void *vdsa, const OSSL_PARAM params[]) +{ + return dsa_signverify_init(vpdsactx, vdsa, params, EVP_PKEY_OP_SIGN); +} + +static int dsa_verify_init(void *vpdsactx, void *vdsa, + const OSSL_PARAM params[]) +{ + return dsa_signverify_init(vpdsactx, vdsa, params, EVP_PKEY_OP_VERIFY); +} + +static int dsa_sign(void *vpdsactx, unsigned char *sig, size_t *siglen, + size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + int ret; + unsigned int sltmp; + size_t dsasize = DSA_size(pdsactx->dsa); + size_t mdsize = dsa_get_md_size(pdsactx); + + if (!ossl_prov_is_running()) + return 0; + + if (sig == NULL) { + *siglen = dsasize; + return 1; + } + + if (sigsize < (size_t)dsasize) + return 0; + + if (mdsize != 0 && tbslen != mdsize) + return 0; + + ret = ossl_dsa_sign_int(0, tbs, tbslen, sig, &sltmp, pdsactx->dsa); + if (ret <= 0) + return 0; + + *siglen = sltmp; + return 1; +} + +static int dsa_verify(void *vpdsactx, const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + size_t mdsize = dsa_get_md_size(pdsactx); + + if (!ossl_prov_is_running() || (mdsize != 0 && tbslen != mdsize)) + return 0; + + return DSA_verify(0, tbs, tbslen, sig, siglen, pdsactx->dsa); +} + +static int dsa_digest_signverify_init(void *vpdsactx, const char *mdname, + void *vdsa, const OSSL_PARAM params[], + int operation) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + + if (!ossl_prov_is_running()) + return 0; + + if (!dsa_signverify_init(vpdsactx, vdsa, params, operation)) + return 0; + + if (!dsa_setup_md(pdsactx, mdname, NULL)) + return 0; + + pdsactx->flag_allow_md = 0; + + if (pdsactx->mdctx == NULL) { + pdsactx->mdctx = EVP_MD_CTX_new(); + if (pdsactx->mdctx == NULL) + goto error; + } + + if (!EVP_DigestInit_ex2(pdsactx->mdctx, pdsactx->md, params)) + goto error; + + return 1; + + error: + EVP_MD_CTX_free(pdsactx->mdctx); + pdsactx->mdctx = NULL; + return 0; +} + +static int dsa_digest_sign_init(void *vpdsactx, const char *mdname, + void *vdsa, const OSSL_PARAM params[]) +{ + return dsa_digest_signverify_init(vpdsactx, mdname, vdsa, params, + EVP_PKEY_OP_SIGN); +} + +static int dsa_digest_verify_init(void *vpdsactx, const char *mdname, + void *vdsa, const OSSL_PARAM params[]) +{ + return dsa_digest_signverify_init(vpdsactx, mdname, vdsa, params, + EVP_PKEY_OP_VERIFY); +} + +int dsa_digest_signverify_update(void *vpdsactx, const unsigned char *data, + size_t datalen) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + + if (pdsactx == NULL || pdsactx->mdctx == NULL) + return 0; + + return EVP_DigestUpdate(pdsactx->mdctx, data, datalen); +} + +int dsa_digest_sign_final(void *vpdsactx, unsigned char *sig, size_t *siglen, + size_t sigsize) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (!ossl_prov_is_running() || pdsactx == NULL || pdsactx->mdctx == NULL) + return 0; + + /* + * If sig is NULL then we're just finding out the sig size. Other fields + * are ignored. Defer to dsa_sign. + */ + if (sig != NULL) { + /* + * There is the possibility that some externally provided + * digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow - + * but that problem is much larger than just in DSA. + */ + if (!EVP_DigestFinal_ex(pdsactx->mdctx, digest, &dlen)) + return 0; + } + + pdsactx->flag_allow_md = 1; + + return dsa_sign(vpdsactx, sig, siglen, sigsize, digest, (size_t)dlen); +} + + +int dsa_digest_verify_final(void *vpdsactx, const unsigned char *sig, + size_t siglen) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (!ossl_prov_is_running() || pdsactx == NULL || pdsactx->mdctx == NULL) + return 0; + + /* + * There is the possibility that some externally provided + * digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow - + * but that problem is much larger than just in DSA. + */ + if (!EVP_DigestFinal_ex(pdsactx->mdctx, digest, &dlen)) + return 0; + + pdsactx->flag_allow_md = 1; + + return dsa_verify(vpdsactx, sig, siglen, digest, (size_t)dlen); +} + +static void dsa_freectx(void *vpdsactx) +{ + PROV_DSA_CTX *ctx = (PROV_DSA_CTX *)vpdsactx; + + OPENSSL_free(ctx->propq); + EVP_MD_CTX_free(ctx->mdctx); + EVP_MD_free(ctx->md); + ctx->propq = NULL; + ctx->mdctx = NULL; + ctx->md = NULL; + DSA_free(ctx->dsa); + OPENSSL_free(ctx); +} + +static void *dsa_dupctx(void *vpdsactx) +{ + PROV_DSA_CTX *srcctx = (PROV_DSA_CTX *)vpdsactx; + PROV_DSA_CTX *dstctx; + + if (!ossl_prov_is_running()) + return NULL; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + dstctx->dsa = NULL; + dstctx->md = NULL; + dstctx->mdctx = NULL; + dstctx->propq = NULL; + + if (srcctx->dsa != NULL && !DSA_up_ref(srcctx->dsa)) + goto err; + dstctx->dsa = srcctx->dsa; + + if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md)) + goto err; + dstctx->md = srcctx->md; + + if (srcctx->mdctx != NULL) { + dstctx->mdctx = EVP_MD_CTX_new(); + if (dstctx->mdctx == NULL + || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx)) + goto err; + } + if (srcctx->propq != NULL) { + dstctx->propq = OPENSSL_strdup(srcctx->propq); + if (dstctx->propq == NULL) + goto err; + } + + return dstctx; + err: + dsa_freectx(dstctx); + return NULL; +} + +static int dsa_get_ctx_params(void *vpdsactx, OSSL_PARAM *params) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + OSSL_PARAM *p; + + if (pdsactx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + if (p != NULL + && !OSSL_PARAM_set_octet_string(p, pdsactx->aid, pdsactx->aid_len)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, pdsactx->mdname)) + return 0; + + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dsa_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int dsa_set_ctx_params(void *vpdsactx, const OSSL_PARAM params[]) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + const OSSL_PARAM *p; + + if (pdsactx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL) { + char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = mdname; + char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = mdprops; + const OSSL_PARAM *propsp = + OSSL_PARAM_locate_const(params, + OSSL_SIGNATURE_PARAM_PROPERTIES); + + if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname))) + return 0; + if (propsp != NULL + && !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops))) + return 0; + if (!dsa_setup_md(pdsactx, mdname, mdprops)) + return 0; + } + + return 1; +} + +static const OSSL_PARAM settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM settable_ctx_params_no_digest[] = { + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dsa_settable_ctx_params(void *vpdsactx, + ossl_unused void *provctx) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + + if (pdsactx != NULL && !pdsactx->flag_allow_md) + return settable_ctx_params_no_digest; + return settable_ctx_params; +} + +static int dsa_get_ctx_md_params(void *vpdsactx, OSSL_PARAM *params) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + + if (pdsactx->mdctx == NULL) + return 0; + + return EVP_MD_CTX_get_params(pdsactx->mdctx, params); +} + +static const OSSL_PARAM *dsa_gettable_ctx_md_params(void *vpdsactx) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + + if (pdsactx->md == NULL) + return 0; + + return EVP_MD_gettable_ctx_params(pdsactx->md); +} + +static int dsa_set_ctx_md_params(void *vpdsactx, const OSSL_PARAM params[]) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + + if (pdsactx->mdctx == NULL) + return 0; + + return EVP_MD_CTX_set_params(pdsactx->mdctx, params); +} + +static const OSSL_PARAM *dsa_settable_ctx_md_params(void *vpdsactx) +{ + PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; + + if (pdsactx->md == NULL) + return 0; + + return EVP_MD_settable_ctx_params(pdsactx->md); +} + +const OSSL_DISPATCH ossl_dsa_signature_functions[] = { + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))dsa_newctx }, + { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))dsa_sign_init }, + { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))dsa_sign }, + { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))dsa_verify_init }, + { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))dsa_verify }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, + (void (*)(void))dsa_digest_sign_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, + (void (*)(void))dsa_digest_signverify_update }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, + (void (*)(void))dsa_digest_sign_final }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, + (void (*)(void))dsa_digest_verify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE, + (void (*)(void))dsa_digest_signverify_update }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL, + (void (*)(void))dsa_digest_verify_final }, + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))dsa_freectx }, + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))dsa_dupctx }, + { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))dsa_get_ctx_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, + (void (*)(void))dsa_gettable_ctx_params }, + { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))dsa_set_ctx_params }, + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, + (void (*)(void))dsa_settable_ctx_params }, + { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS, + (void (*)(void))dsa_get_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS, + (void (*)(void))dsa_gettable_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS, + (void (*)(void))dsa_set_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS, + (void (*)(void))dsa_settable_ctx_md_params }, + { 0, NULL } +}; diff --git a/providers/implementations/signature/ecdsa_sig.c b/providers/implementations/signature/ecdsa_sig.c new file mode 100644 index 000000000000..865d49d1004f --- /dev/null +++ b/providers/implementations/signature/ecdsa_sig.c @@ -0,0 +1,619 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * ECDSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> /* memcpy */ +#include <openssl/crypto.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/dsa.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include "internal/nelem.h" +#include "internal/sizes.h" +#include "internal/cryptlib.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/securitycheck.h" +#include "crypto/ec.h" +#include "prov/der_ec.h" + +static OSSL_FUNC_signature_newctx_fn ecdsa_newctx; +static OSSL_FUNC_signature_sign_init_fn ecdsa_sign_init; +static OSSL_FUNC_signature_verify_init_fn ecdsa_verify_init; +static OSSL_FUNC_signature_sign_fn ecdsa_sign; +static OSSL_FUNC_signature_verify_fn ecdsa_verify; +static OSSL_FUNC_signature_digest_sign_init_fn ecdsa_digest_sign_init; +static OSSL_FUNC_signature_digest_sign_update_fn ecdsa_digest_signverify_update; +static OSSL_FUNC_signature_digest_sign_final_fn ecdsa_digest_sign_final; +static OSSL_FUNC_signature_digest_verify_init_fn ecdsa_digest_verify_init; +static OSSL_FUNC_signature_digest_verify_update_fn ecdsa_digest_signverify_update; +static OSSL_FUNC_signature_digest_verify_final_fn ecdsa_digest_verify_final; +static OSSL_FUNC_signature_freectx_fn ecdsa_freectx; +static OSSL_FUNC_signature_dupctx_fn ecdsa_dupctx; +static OSSL_FUNC_signature_get_ctx_params_fn ecdsa_get_ctx_params; +static OSSL_FUNC_signature_gettable_ctx_params_fn ecdsa_gettable_ctx_params; +static OSSL_FUNC_signature_set_ctx_params_fn ecdsa_set_ctx_params; +static OSSL_FUNC_signature_settable_ctx_params_fn ecdsa_settable_ctx_params; +static OSSL_FUNC_signature_get_ctx_md_params_fn ecdsa_get_ctx_md_params; +static OSSL_FUNC_signature_gettable_ctx_md_params_fn ecdsa_gettable_ctx_md_params; +static OSSL_FUNC_signature_set_ctx_md_params_fn ecdsa_set_ctx_md_params; +static OSSL_FUNC_signature_settable_ctx_md_params_fn ecdsa_settable_ctx_md_params; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes DSA structures, so + * we use that here too. + */ + +typedef struct { + OSSL_LIB_CTX *libctx; + char *propq; + EC_KEY *ec; + char mdname[OSSL_MAX_NAME_SIZE]; + + /* + * Flag to determine if the hash function can be changed (1) or not (0) + * Because it's dangerous to change during a DigestSign or DigestVerify + * operation, this flag is cleared by their Init function, and set again + * by their Final function. + */ + unsigned int flag_allow_md : 1; + + /* The Algorithm Identifier of the combined signature algorithm */ + unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE]; + unsigned char *aid; + size_t aid_len; + size_t mdsize; + int operation; + + EVP_MD *md; + EVP_MD_CTX *mdctx; + /* + * Internally used to cache the results of calling the EC group + * sign_setup() methods which are then passed to the sign operation. + * This is used by CAVS failure tests to terminate a loop if the signature + * is not valid. + * This could of also been done with a simple flag. + */ + BIGNUM *kinv; + BIGNUM *r; +#if !defined(OPENSSL_NO_ACVP_TESTS) + /* + * This indicates that KAT (CAVS) test is running. Externally an app will + * override the random callback such that the generated private key and k + * are known. + * Normal operation will loop to choose a new k if the signature is not + * valid - but for this mode of operation it forces a failure instead. + */ + unsigned int kattest; +#endif +} PROV_ECDSA_CTX; + +static void *ecdsa_newctx(void *provctx, const char *propq) +{ + PROV_ECDSA_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(PROV_ECDSA_CTX)); + if (ctx == NULL) + return NULL; + + ctx->flag_allow_md = 1; + ctx->libctx = PROV_LIBCTX_OF(provctx); + if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL) { + OPENSSL_free(ctx); + ctx = NULL; + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + } + return ctx; +} + +static int ecdsa_signverify_init(void *vctx, void *ec, + const OSSL_PARAM params[], int operation) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + + if (!ossl_prov_is_running() + || ctx == NULL) + return 0; + + if (ec == NULL && ctx->ec == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } + + if (ec != NULL) { + if (!ossl_ec_check_key(ctx->libctx, ec, operation == EVP_PKEY_OP_SIGN)) + return 0; + if (!EC_KEY_up_ref(ec)) + return 0; + EC_KEY_free(ctx->ec); + ctx->ec = ec; + } + + ctx->operation = operation; + + if (!ecdsa_set_ctx_params(ctx, params)) + return 0; + + return 1; +} + +static int ecdsa_sign_init(void *vctx, void *ec, const OSSL_PARAM params[]) +{ + return ecdsa_signverify_init(vctx, ec, params, EVP_PKEY_OP_SIGN); +} + +static int ecdsa_verify_init(void *vctx, void *ec, const OSSL_PARAM params[]) +{ + return ecdsa_signverify_init(vctx, ec, params, EVP_PKEY_OP_VERIFY); +} + +static int ecdsa_sign(void *vctx, unsigned char *sig, size_t *siglen, + size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + int ret; + unsigned int sltmp; + size_t ecsize = ECDSA_size(ctx->ec); + + if (!ossl_prov_is_running()) + return 0; + + if (sig == NULL) { + *siglen = ecsize; + return 1; + } + +#if !defined(OPENSSL_NO_ACVP_TESTS) + if (ctx->kattest && !ECDSA_sign_setup(ctx->ec, NULL, &ctx->kinv, &ctx->r)) + return 0; +#endif + + if (sigsize < (size_t)ecsize) + return 0; + + if (ctx->mdsize != 0 && tbslen != ctx->mdsize) + return 0; + + ret = ECDSA_sign_ex(0, tbs, tbslen, sig, &sltmp, ctx->kinv, ctx->r, ctx->ec); + if (ret <= 0) + return 0; + + *siglen = sltmp; + return 1; +} + +static int ecdsa_verify(void *vctx, const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + + if (!ossl_prov_is_running() || (ctx->mdsize != 0 && tbslen != ctx->mdsize)) + return 0; + + return ECDSA_verify(0, tbs, tbslen, sig, siglen, ctx->ec); +} + +static int ecdsa_setup_md(PROV_ECDSA_CTX *ctx, const char *mdname, + const char *mdprops) +{ + EVP_MD *md = NULL; + size_t mdname_len; + int md_nid, sha1_allowed; + WPACKET pkt; + + if (mdname == NULL) + return 1; + + mdname_len = strlen(mdname); + if (mdname_len >= sizeof(ctx->mdname)) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "%s exceeds name buffer length", mdname); + return 0; + } + if (mdprops == NULL) + mdprops = ctx->propq; + md = EVP_MD_fetch(ctx->libctx, mdname, mdprops); + if (md == NULL) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "%s could not be fetched", mdname); + return 0; + } + sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); + md_nid = ossl_digest_get_approved_nid_with_sha1(ctx->libctx, md, + sha1_allowed); + if (md_nid < 0) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, + "digest=%s", mdname); + EVP_MD_free(md); + return 0; + } + + if (!ctx->flag_allow_md) { + if (ctx->mdname[0] != '\0' && !EVP_MD_is_a(md, ctx->mdname)) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, + "digest %s != %s", mdname, ctx->mdname); + EVP_MD_free(md); + return 0; + } + EVP_MD_free(md); + return 1; + } + + EVP_MD_CTX_free(ctx->mdctx); + EVP_MD_free(ctx->md); + + ctx->aid_len = 0; + if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf)) + && ossl_DER_w_algorithmIdentifier_ECDSA_with_MD(&pkt, -1, ctx->ec, + md_nid) + && WPACKET_finish(&pkt)) { + WPACKET_get_total_written(&pkt, &ctx->aid_len); + ctx->aid = WPACKET_get_curr(&pkt); + } + WPACKET_cleanup(&pkt); + ctx->mdctx = NULL; + ctx->md = md; + ctx->mdsize = EVP_MD_get_size(ctx->md); + OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname)); + + return 1; +} + +static int ecdsa_digest_signverify_init(void *vctx, const char *mdname, + void *ec, const OSSL_PARAM params[], + int operation) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (!ecdsa_signverify_init(vctx, ec, params, operation) + || !ecdsa_setup_md(ctx, mdname, NULL)) + return 0; + + ctx->flag_allow_md = 0; + + if (ctx->mdctx == NULL) { + ctx->mdctx = EVP_MD_CTX_new(); + if (ctx->mdctx == NULL) + goto error; + } + + if (!EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params)) + goto error; + return 1; +error: + EVP_MD_CTX_free(ctx->mdctx); + ctx->mdctx = NULL; + return 0; +} + +static int ecdsa_digest_sign_init(void *vctx, const char *mdname, void *ec, + const OSSL_PARAM params[]) +{ + return ecdsa_digest_signverify_init(vctx, mdname, ec, params, + EVP_PKEY_OP_SIGN); +} + +static int ecdsa_digest_verify_init(void *vctx, const char *mdname, void *ec, + const OSSL_PARAM params[]) +{ + return ecdsa_digest_signverify_init(vctx, mdname, ec, params, + EVP_PKEY_OP_VERIFY); +} + +int ecdsa_digest_signverify_update(void *vctx, const unsigned char *data, + size_t datalen) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + + if (ctx == NULL || ctx->mdctx == NULL) + return 0; + + return EVP_DigestUpdate(ctx->mdctx, data, datalen); +} + +int ecdsa_digest_sign_final(void *vctx, unsigned char *sig, size_t *siglen, + size_t sigsize) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (!ossl_prov_is_running() || ctx == NULL || ctx->mdctx == NULL) + return 0; + + /* + * If sig is NULL then we're just finding out the sig size. Other fields + * are ignored. Defer to ecdsa_sign. + */ + if (sig != NULL + && !EVP_DigestFinal_ex(ctx->mdctx, digest, &dlen)) + return 0; + ctx->flag_allow_md = 1; + return ecdsa_sign(vctx, sig, siglen, sigsize, digest, (size_t)dlen); +} + +int ecdsa_digest_verify_final(void *vctx, const unsigned char *sig, + size_t siglen) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (!ossl_prov_is_running() || ctx == NULL || ctx->mdctx == NULL) + return 0; + + if (!EVP_DigestFinal_ex(ctx->mdctx, digest, &dlen)) + return 0; + ctx->flag_allow_md = 1; + return ecdsa_verify(ctx, sig, siglen, digest, (size_t)dlen); +} + +static void ecdsa_freectx(void *vctx) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + + OPENSSL_free(ctx->propq); + EVP_MD_CTX_free(ctx->mdctx); + EVP_MD_free(ctx->md); + ctx->propq = NULL; + ctx->mdctx = NULL; + ctx->md = NULL; + ctx->mdsize = 0; + EC_KEY_free(ctx->ec); + BN_clear_free(ctx->kinv); + BN_clear_free(ctx->r); + OPENSSL_free(ctx); +} + +static void *ecdsa_dupctx(void *vctx) +{ + PROV_ECDSA_CTX *srcctx = (PROV_ECDSA_CTX *)vctx; + PROV_ECDSA_CTX *dstctx; + + if (!ossl_prov_is_running()) + return NULL; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + dstctx->ec = NULL; + dstctx->md = NULL; + dstctx->mdctx = NULL; + dstctx->propq = NULL; + + if (srcctx->ec != NULL && !EC_KEY_up_ref(srcctx->ec)) + goto err; + /* Test KATS should not need to be supported */ + if (srcctx->kinv != NULL || srcctx->r != NULL) + goto err; + dstctx->ec = srcctx->ec; + + if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md)) + goto err; + dstctx->md = srcctx->md; + + if (srcctx->mdctx != NULL) { + dstctx->mdctx = EVP_MD_CTX_new(); + if (dstctx->mdctx == NULL + || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx)) + goto err; + } + + if (srcctx->propq != NULL) { + dstctx->propq = OPENSSL_strdup(srcctx->propq); + if (dstctx->propq == NULL) + goto err; + } + + return dstctx; + err: + ecdsa_freectx(dstctx); + return NULL; +} + +static int ecdsa_get_ctx_params(void *vctx, OSSL_PARAM *params) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + OSSL_PARAM *p; + + if (ctx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + if (p != NULL && !OSSL_PARAM_set_octet_string(p, ctx->aid, ctx->aid_len)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->mdsize)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, ctx->md == NULL + ? ctx->mdname + : EVP_MD_get0_name(ctx->md))) + return 0; + + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *ecdsa_gettable_ctx_params(ossl_unused void *vctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int ecdsa_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + const OSSL_PARAM *p; + size_t mdsize = 0; + + if (ctx == NULL) + return 0; + if (params == NULL) + return 1; + +#if !defined(OPENSSL_NO_ACVP_TESTS) + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_KAT); + if (p != NULL && !OSSL_PARAM_get_uint(p, &ctx->kattest)) + return 0; +#endif + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL) { + char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = mdname; + char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = mdprops; + const OSSL_PARAM *propsp = + OSSL_PARAM_locate_const(params, + OSSL_SIGNATURE_PARAM_PROPERTIES); + + if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname))) + return 0; + if (propsp != NULL + && !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops))) + return 0; + if (!ecdsa_setup_md(ctx, mdname, mdprops)) + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &mdsize) + || (!ctx->flag_allow_md && mdsize != ctx->mdsize)) + return 0; + ctx->mdsize = mdsize; + } + + return 1; +} + +static const OSSL_PARAM settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_KAT, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM settable_ctx_params_no_digest[] = { + OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_KAT, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *ecdsa_settable_ctx_params(void *vctx, + ossl_unused void *provctx) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + + if (ctx != NULL && !ctx->flag_allow_md) + return settable_ctx_params_no_digest; + return settable_ctx_params; +} + +static int ecdsa_get_ctx_md_params(void *vctx, OSSL_PARAM *params) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + + if (ctx->mdctx == NULL) + return 0; + + return EVP_MD_CTX_get_params(ctx->mdctx, params); +} + +static const OSSL_PARAM *ecdsa_gettable_ctx_md_params(void *vctx) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + + if (ctx->md == NULL) + return 0; + + return EVP_MD_gettable_ctx_params(ctx->md); +} + +static int ecdsa_set_ctx_md_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + + if (ctx->mdctx == NULL) + return 0; + + return EVP_MD_CTX_set_params(ctx->mdctx, params); +} + +static const OSSL_PARAM *ecdsa_settable_ctx_md_params(void *vctx) +{ + PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; + + if (ctx->md == NULL) + return 0; + + return EVP_MD_settable_ctx_params(ctx->md); +} + +const OSSL_DISPATCH ossl_ecdsa_signature_functions[] = { + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))ecdsa_newctx }, + { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))ecdsa_sign_init }, + { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))ecdsa_sign }, + { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))ecdsa_verify_init }, + { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))ecdsa_verify }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, + (void (*)(void))ecdsa_digest_sign_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, + (void (*)(void))ecdsa_digest_signverify_update }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, + (void (*)(void))ecdsa_digest_sign_final }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, + (void (*)(void))ecdsa_digest_verify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE, + (void (*)(void))ecdsa_digest_signverify_update }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL, + (void (*)(void))ecdsa_digest_verify_final }, + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))ecdsa_freectx }, + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))ecdsa_dupctx }, + { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))ecdsa_get_ctx_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, + (void (*)(void))ecdsa_gettable_ctx_params }, + { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))ecdsa_set_ctx_params }, + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, + (void (*)(void))ecdsa_settable_ctx_params }, + { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS, + (void (*)(void))ecdsa_get_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS, + (void (*)(void))ecdsa_gettable_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS, + (void (*)(void))ecdsa_set_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS, + (void (*)(void))ecdsa_settable_ctx_md_params }, + { 0, NULL } +}; diff --git a/providers/implementations/signature/eddsa_sig.c b/providers/implementations/signature/eddsa_sig.c new file mode 100644 index 000000000000..c78f1fbb5fa6 --- /dev/null +++ b/providers/implementations/signature/eddsa_sig.c @@ -0,0 +1,468 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/crypto.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/err.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include "internal/nelem.h" +#include "internal/sizes.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/der_ecx.h" +#include "crypto/ecx.h" + +#ifdef S390X_EC_ASM +# include "s390x_arch.h" + +# define S390X_CAN_SIGN(edtype) \ +((OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_##edtype)) \ +&& (OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_##edtype)) \ +&& (OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_VERIFY_##edtype))) + +static int s390x_ed25519_digestsign(const ECX_KEY *edkey, unsigned char *sig, + const unsigned char *tbs, size_t tbslen); +static int s390x_ed448_digestsign(const ECX_KEY *edkey, unsigned char *sig, + const unsigned char *tbs, size_t tbslen); +static int s390x_ed25519_digestverify(const ECX_KEY *edkey, + const unsigned char *sig, + const unsigned char *tbs, size_t tbslen); +static int s390x_ed448_digestverify(const ECX_KEY *edkey, + const unsigned char *sig, + const unsigned char *tbs, size_t tbslen); + +#endif /* S390X_EC_ASM */ + +static OSSL_FUNC_signature_newctx_fn eddsa_newctx; +static OSSL_FUNC_signature_digest_sign_init_fn eddsa_digest_signverify_init; +static OSSL_FUNC_signature_digest_sign_fn ed25519_digest_sign; +static OSSL_FUNC_signature_digest_sign_fn ed448_digest_sign; +static OSSL_FUNC_signature_digest_verify_fn ed25519_digest_verify; +static OSSL_FUNC_signature_digest_verify_fn ed448_digest_verify; +static OSSL_FUNC_signature_freectx_fn eddsa_freectx; +static OSSL_FUNC_signature_dupctx_fn eddsa_dupctx; +static OSSL_FUNC_signature_get_ctx_params_fn eddsa_get_ctx_params; +static OSSL_FUNC_signature_gettable_ctx_params_fn eddsa_gettable_ctx_params; + +typedef struct { + OSSL_LIB_CTX *libctx; + ECX_KEY *key; + + /* The Algorithm Identifier of the signature algorithm */ + unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE]; + unsigned char *aid; + size_t aid_len; +} PROV_EDDSA_CTX; + +static void *eddsa_newctx(void *provctx, const char *propq_unused) +{ + PROV_EDDSA_CTX *peddsactx; + + if (!ossl_prov_is_running()) + return NULL; + + peddsactx = OPENSSL_zalloc(sizeof(PROV_EDDSA_CTX)); + if (peddsactx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + peddsactx->libctx = PROV_LIBCTX_OF(provctx); + + return peddsactx; +} + +static int eddsa_digest_signverify_init(void *vpeddsactx, const char *mdname, + void *vedkey, + ossl_unused const OSSL_PARAM params[]) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + ECX_KEY *edkey = (ECX_KEY *)vedkey; + WPACKET pkt; + int ret; + + if (!ossl_prov_is_running()) + return 0; + + if (mdname != NULL && mdname[0] != '\0') { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); + return 0; + } + + if (edkey == NULL) { + if (peddsactx->key != NULL) + /* there is nothing to do on reinit */ + return 1; + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } + + if (!ossl_ecx_key_up_ref(edkey)) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return 0; + } + + /* + * We do not care about DER writing errors. + * All it really means is that for some reason, there's no + * AlgorithmIdentifier to be had, but the operation itself is + * still valid, just as long as it's not used to construct + * anything that needs an AlgorithmIdentifier. + */ + peddsactx->aid_len = 0; + ret = WPACKET_init_der(&pkt, peddsactx->aid_buf, sizeof(peddsactx->aid_buf)); + switch (edkey->type) { + case ECX_KEY_TYPE_ED25519: + ret = ret && ossl_DER_w_algorithmIdentifier_ED25519(&pkt, -1, edkey); + break; + case ECX_KEY_TYPE_ED448: + ret = ret && ossl_DER_w_algorithmIdentifier_ED448(&pkt, -1, edkey); + break; + default: + /* Should never happen */ + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + ossl_ecx_key_free(edkey); + return 0; + } + if (ret && WPACKET_finish(&pkt)) { + WPACKET_get_total_written(&pkt, &peddsactx->aid_len); + peddsactx->aid = WPACKET_get_curr(&pkt); + } + WPACKET_cleanup(&pkt); + + peddsactx->key = edkey; + + return 1; +} + +int ed25519_digest_sign(void *vpeddsactx, unsigned char *sigret, + size_t *siglen, size_t sigsize, + const unsigned char *tbs, size_t tbslen) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + const ECX_KEY *edkey = peddsactx->key; + + if (!ossl_prov_is_running()) + return 0; + + if (sigret == NULL) { + *siglen = ED25519_SIGSIZE; + return 1; + } + if (sigsize < ED25519_SIGSIZE) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (edkey->privkey == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } +#ifdef S390X_EC_ASM + if (S390X_CAN_SIGN(ED25519)) { + if (s390x_ed25519_digestsign(edkey, sigret, tbs, tbslen) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN); + return 0; + } + *siglen = ED25519_SIGSIZE; + return 1; + } +#endif /* S390X_EC_ASM */ + if (ossl_ed25519_sign(sigret, tbs, tbslen, edkey->pubkey, edkey->privkey, + peddsactx->libctx, NULL) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN); + return 0; + } + *siglen = ED25519_SIGSIZE; + return 1; +} + +int ed448_digest_sign(void *vpeddsactx, unsigned char *sigret, + size_t *siglen, size_t sigsize, + const unsigned char *tbs, size_t tbslen) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + const ECX_KEY *edkey = peddsactx->key; + + if (!ossl_prov_is_running()) + return 0; + + if (sigret == NULL) { + *siglen = ED448_SIGSIZE; + return 1; + } + if (sigsize < ED448_SIGSIZE) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (edkey->privkey == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } +#ifdef S390X_EC_ASM + if (S390X_CAN_SIGN(ED448)) { + if (s390x_ed448_digestsign(edkey, sigret, tbs, tbslen) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN); + return 0; + } + *siglen = ED448_SIGSIZE; + return 1; + } +#endif /* S390X_EC_ASM */ + if (ossl_ed448_sign(peddsactx->libctx, sigret, tbs, tbslen, edkey->pubkey, + edkey->privkey, NULL, 0, edkey->propq) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN); + return 0; + } + *siglen = ED448_SIGSIZE; + return 1; +} + +int ed25519_digest_verify(void *vpeddsactx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, + size_t tbslen) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + const ECX_KEY *edkey = peddsactx->key; + + if (!ossl_prov_is_running() || siglen != ED25519_SIGSIZE) + return 0; + +#ifdef S390X_EC_ASM + if (S390X_CAN_SIGN(ED25519)) + return s390x_ed25519_digestverify(edkey, sig, tbs, tbslen); +#endif /* S390X_EC_ASM */ + + return ossl_ed25519_verify(tbs, tbslen, sig, edkey->pubkey, + peddsactx->libctx, edkey->propq); +} + +int ed448_digest_verify(void *vpeddsactx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, + size_t tbslen) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + const ECX_KEY *edkey = peddsactx->key; + + if (!ossl_prov_is_running() || siglen != ED448_SIGSIZE) + return 0; + +#ifdef S390X_EC_ASM + if (S390X_CAN_SIGN(ED448)) + return s390x_ed448_digestverify(edkey, sig, tbs, tbslen); +#endif /* S390X_EC_ASM */ + + return ossl_ed448_verify(peddsactx->libctx, tbs, tbslen, sig, edkey->pubkey, + NULL, 0, edkey->propq); +} + +static void eddsa_freectx(void *vpeddsactx) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + + ossl_ecx_key_free(peddsactx->key); + + OPENSSL_free(peddsactx); +} + +static void *eddsa_dupctx(void *vpeddsactx) +{ + PROV_EDDSA_CTX *srcctx = (PROV_EDDSA_CTX *)vpeddsactx; + PROV_EDDSA_CTX *dstctx; + + if (!ossl_prov_is_running()) + return NULL; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + dstctx->key = NULL; + + if (srcctx->key != NULL && !ossl_ecx_key_up_ref(srcctx->key)) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + goto err; + } + dstctx->key = srcctx->key; + + return dstctx; + err: + eddsa_freectx(dstctx); + return NULL; +} + +static int eddsa_get_ctx_params(void *vpeddsactx, OSSL_PARAM *params) +{ + PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx; + OSSL_PARAM *p; + + if (peddsactx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + if (p != NULL && !OSSL_PARAM_set_octet_string(p, peddsactx->aid, + peddsactx->aid_len)) + return 0; + + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *eddsa_gettable_ctx_params(ossl_unused void *vpeddsactx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +const OSSL_DISPATCH ossl_ed25519_signature_functions[] = { + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))eddsa_newctx }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, + (void (*)(void))eddsa_digest_signverify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, + (void (*)(void))ed25519_digest_sign }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, + (void (*)(void))eddsa_digest_signverify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, + (void (*)(void))ed25519_digest_verify }, + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))eddsa_freectx }, + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))eddsa_dupctx }, + { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))eddsa_get_ctx_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, + (void (*)(void))eddsa_gettable_ctx_params }, + { 0, NULL } +}; + +const OSSL_DISPATCH ossl_ed448_signature_functions[] = { + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))eddsa_newctx }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, + (void (*)(void))eddsa_digest_signverify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, + (void (*)(void))ed448_digest_sign }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, + (void (*)(void))eddsa_digest_signverify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, + (void (*)(void))ed448_digest_verify }, + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))eddsa_freectx }, + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))eddsa_dupctx }, + { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))eddsa_get_ctx_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, + (void (*)(void))eddsa_gettable_ctx_params }, + { 0, NULL } +}; + +#ifdef S390X_EC_ASM + +static int s390x_ed25519_digestsign(const ECX_KEY *edkey, unsigned char *sig, + const unsigned char *tbs, size_t tbslen) +{ + int rc; + union { + struct { + unsigned char sig[64]; + unsigned char priv[32]; + } ed25519; + unsigned long long buff[512]; + } param; + + memset(¶m, 0, sizeof(param)); + memcpy(param.ed25519.priv, edkey->privkey, sizeof(param.ed25519.priv)); + + rc = s390x_kdsa(S390X_EDDSA_SIGN_ED25519, ¶m.ed25519, tbs, tbslen); + OPENSSL_cleanse(param.ed25519.priv, sizeof(param.ed25519.priv)); + if (rc != 0) + return 0; + + s390x_flip_endian32(sig, param.ed25519.sig); + s390x_flip_endian32(sig + 32, param.ed25519.sig + 32); + return 1; +} + +static int s390x_ed448_digestsign(const ECX_KEY *edkey, unsigned char *sig, + const unsigned char *tbs, size_t tbslen) +{ + int rc; + union { + struct { + unsigned char sig[128]; + unsigned char priv[64]; + } ed448; + unsigned long long buff[512]; + } param; + + memset(¶m, 0, sizeof(param)); + memcpy(param.ed448.priv + 64 - 57, edkey->privkey, 57); + + rc = s390x_kdsa(S390X_EDDSA_SIGN_ED448, ¶m.ed448, tbs, tbslen); + OPENSSL_cleanse(param.ed448.priv, sizeof(param.ed448.priv)); + if (rc != 0) + return 0; + + s390x_flip_endian64(param.ed448.sig, param.ed448.sig); + s390x_flip_endian64(param.ed448.sig + 64, param.ed448.sig + 64); + memcpy(sig, param.ed448.sig, 57); + memcpy(sig + 57, param.ed448.sig + 64, 57); + return 1; +} + +static int s390x_ed25519_digestverify(const ECX_KEY *edkey, + const unsigned char *sig, + const unsigned char *tbs, size_t tbslen) +{ + union { + struct { + unsigned char sig[64]; + unsigned char pub[32]; + } ed25519; + unsigned long long buff[512]; + } param; + + memset(¶m, 0, sizeof(param)); + s390x_flip_endian32(param.ed25519.sig, sig); + s390x_flip_endian32(param.ed25519.sig + 32, sig + 32); + s390x_flip_endian32(param.ed25519.pub, edkey->pubkey); + + return s390x_kdsa(S390X_EDDSA_VERIFY_ED25519, + ¶m.ed25519, tbs, tbslen) == 0 ? 1 : 0; +} + +static int s390x_ed448_digestverify(const ECX_KEY *edkey, + const unsigned char *sig, + const unsigned char *tbs, + size_t tbslen) +{ + union { + struct { + unsigned char sig[128]; + unsigned char pub[64]; + } ed448; + unsigned long long buff[512]; + } param; + + memset(¶m, 0, sizeof(param)); + memcpy(param.ed448.sig, sig, 57); + s390x_flip_endian64(param.ed448.sig, param.ed448.sig); + memcpy(param.ed448.sig + 64, sig + 57, 57); + s390x_flip_endian64(param.ed448.sig + 64, param.ed448.sig + 64); + memcpy(param.ed448.pub, edkey->pubkey, 57); + s390x_flip_endian64(param.ed448.pub, param.ed448.pub); + + return s390x_kdsa(S390X_EDDSA_VERIFY_ED448, + ¶m.ed448, tbs, tbslen) == 0 ? 1 : 0; +} + +#endif /* S390X_EC_ASM */ diff --git a/providers/implementations/signature/mac_legacy_sig.c b/providers/implementations/signature/mac_legacy_sig.c new file mode 100644 index 000000000000..6be605c8c60f --- /dev/null +++ b/providers/implementations/signature/mac_legacy_sig.c @@ -0,0 +1,267 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* We need to use some engine deprecated APIs */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#include <openssl/crypto.h> +#include <openssl/evp.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/params.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#ifndef FIPS_MODULE +# include <openssl/engine.h> +#endif +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/macsignature.h" +#include "prov/providercommon.h" + +static OSSL_FUNC_signature_newctx_fn mac_hmac_newctx; +static OSSL_FUNC_signature_newctx_fn mac_siphash_newctx; +static OSSL_FUNC_signature_newctx_fn mac_poly1305_newctx; +static OSSL_FUNC_signature_newctx_fn mac_cmac_newctx; +static OSSL_FUNC_signature_digest_sign_init_fn mac_digest_sign_init; +static OSSL_FUNC_signature_digest_sign_update_fn mac_digest_sign_update; +static OSSL_FUNC_signature_digest_sign_final_fn mac_digest_sign_final; +static OSSL_FUNC_signature_freectx_fn mac_freectx; +static OSSL_FUNC_signature_dupctx_fn mac_dupctx; +static OSSL_FUNC_signature_set_ctx_params_fn mac_set_ctx_params; +static OSSL_FUNC_signature_settable_ctx_params_fn mac_hmac_settable_ctx_params; +static OSSL_FUNC_signature_settable_ctx_params_fn mac_siphash_settable_ctx_params; +static OSSL_FUNC_signature_settable_ctx_params_fn mac_poly1305_settable_ctx_params; +static OSSL_FUNC_signature_settable_ctx_params_fn mac_cmac_settable_ctx_params; + +typedef struct { + OSSL_LIB_CTX *libctx; + char *propq; + MAC_KEY *key; + EVP_MAC_CTX *macctx; +} PROV_MAC_CTX; + +static void *mac_newctx(void *provctx, const char *propq, const char *macname) +{ + PROV_MAC_CTX *pmacctx; + EVP_MAC *mac = NULL; + + if (!ossl_prov_is_running()) + return NULL; + + pmacctx = OPENSSL_zalloc(sizeof(PROV_MAC_CTX)); + if (pmacctx == NULL) + return NULL; + + pmacctx->libctx = PROV_LIBCTX_OF(provctx); + if (propq != NULL && (pmacctx->propq = OPENSSL_strdup(propq)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + mac = EVP_MAC_fetch(pmacctx->libctx, macname, propq); + if (mac == NULL) + goto err; + + pmacctx->macctx = EVP_MAC_CTX_new(mac); + if (pmacctx->macctx == NULL) + goto err; + + EVP_MAC_free(mac); + + return pmacctx; + + err: + OPENSSL_free(pmacctx->propq); + OPENSSL_free(pmacctx); + EVP_MAC_free(mac); + return NULL; +} + +#define MAC_NEWCTX(funcname, macname) \ + static void *mac_##funcname##_newctx(void *provctx, const char *propq) \ + { \ + return mac_newctx(provctx, propq, macname); \ + } + +MAC_NEWCTX(hmac, "HMAC") +MAC_NEWCTX(siphash, "SIPHASH") +MAC_NEWCTX(poly1305, "POLY1305") +MAC_NEWCTX(cmac, "CMAC") + +static int mac_digest_sign_init(void *vpmacctx, const char *mdname, void *vkey, + const OSSL_PARAM params[]) +{ + PROV_MAC_CTX *pmacctx = (PROV_MAC_CTX *)vpmacctx; + const char *ciphername = NULL, *engine = NULL; + + if (!ossl_prov_is_running() + || pmacctx == NULL) + return 0; + + if (pmacctx->key == NULL && vkey == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } + + if (vkey != NULL) { + if (!ossl_mac_key_up_ref(vkey)) + return 0; + ossl_mac_key_free(pmacctx->key); + pmacctx->key = vkey; + } + + if (pmacctx->key->cipher.cipher != NULL) + ciphername = (char *)EVP_CIPHER_get0_name(pmacctx->key->cipher.cipher); +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + if (pmacctx->key->cipher.engine != NULL) + engine = (char *)ENGINE_get_id(pmacctx->key->cipher.engine); +#endif + + if (!ossl_prov_set_macctx(pmacctx->macctx, NULL, + (char *)ciphername, + (char *)mdname, + (char *)engine, + pmacctx->key->properties, + NULL, 0)) + return 0; + + if (!EVP_MAC_init(pmacctx->macctx, pmacctx->key->priv_key, + pmacctx->key->priv_key_len, params)) + return 0; + + return 1; +} + +int mac_digest_sign_update(void *vpmacctx, const unsigned char *data, + size_t datalen) +{ + PROV_MAC_CTX *pmacctx = (PROV_MAC_CTX *)vpmacctx; + + if (pmacctx == NULL || pmacctx->macctx == NULL) + return 0; + + return EVP_MAC_update(pmacctx->macctx, data, datalen); +} + +int mac_digest_sign_final(void *vpmacctx, unsigned char *mac, size_t *maclen, + size_t macsize) +{ + PROV_MAC_CTX *pmacctx = (PROV_MAC_CTX *)vpmacctx; + + if (!ossl_prov_is_running() || pmacctx == NULL || pmacctx->macctx == NULL) + return 0; + + return EVP_MAC_final(pmacctx->macctx, mac, maclen, macsize); +} + +static void mac_freectx(void *vpmacctx) +{ + PROV_MAC_CTX *ctx = (PROV_MAC_CTX *)vpmacctx; + + OPENSSL_free(ctx->propq); + EVP_MAC_CTX_free(ctx->macctx); + ossl_mac_key_free(ctx->key); + OPENSSL_free(ctx); +} + +static void *mac_dupctx(void *vpmacctx) +{ + PROV_MAC_CTX *srcctx = (PROV_MAC_CTX *)vpmacctx; + PROV_MAC_CTX *dstctx; + + if (!ossl_prov_is_running()) + return NULL; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + dstctx->propq = NULL; + dstctx->key = NULL; + dstctx->macctx = NULL; + + if (srcctx->propq != NULL && (dstctx->propq = OPENSSL_strdup(srcctx->propq)) == NULL) + goto err; + + if (srcctx->key != NULL && !ossl_mac_key_up_ref(srcctx->key)) + goto err; + dstctx->key = srcctx->key; + + if (srcctx->macctx != NULL) { + dstctx->macctx = EVP_MAC_CTX_dup(srcctx->macctx); + if (dstctx->macctx == NULL) + goto err; + } + + return dstctx; + err: + mac_freectx(dstctx); + return NULL; +} + +static int mac_set_ctx_params(void *vpmacctx, const OSSL_PARAM params[]) +{ + PROV_MAC_CTX *ctx = (PROV_MAC_CTX *)vpmacctx; + + return EVP_MAC_CTX_set_params(ctx->macctx, params); +} + +static const OSSL_PARAM *mac_settable_ctx_params(ossl_unused void *ctx, + void *provctx, + const char *macname) +{ + EVP_MAC *mac = EVP_MAC_fetch(PROV_LIBCTX_OF(provctx), macname, + NULL); + const OSSL_PARAM *params; + + if (mac == NULL) + return NULL; + + params = EVP_MAC_settable_ctx_params(mac); + EVP_MAC_free(mac); + + return params; +} + +#define MAC_SETTABLE_CTX_PARAMS(funcname, macname) \ + static const OSSL_PARAM *mac_##funcname##_settable_ctx_params(void *ctx, \ + void *provctx) \ + { \ + return mac_settable_ctx_params(ctx, provctx, macname); \ + } + +MAC_SETTABLE_CTX_PARAMS(hmac, "HMAC") +MAC_SETTABLE_CTX_PARAMS(siphash, "SIPHASH") +MAC_SETTABLE_CTX_PARAMS(poly1305, "POLY1305") +MAC_SETTABLE_CTX_PARAMS(cmac, "CMAC") + +#define MAC_SIGNATURE_FUNCTIONS(funcname) \ + const OSSL_DISPATCH ossl_mac_legacy_##funcname##_signature_functions[] = { \ + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))mac_##funcname##_newctx }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \ + (void (*)(void))mac_digest_sign_init }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, \ + (void (*)(void))mac_digest_sign_update }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, \ + (void (*)(void))mac_digest_sign_final }, \ + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))mac_freectx }, \ + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))mac_dupctx }, \ + { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \ + (void (*)(void))mac_set_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \ + (void (*)(void))mac_##funcname##_settable_ctx_params }, \ + { 0, NULL } \ + }; + +MAC_SIGNATURE_FUNCTIONS(hmac) +MAC_SIGNATURE_FUNCTIONS(siphash) +MAC_SIGNATURE_FUNCTIONS(poly1305) +MAC_SIGNATURE_FUNCTIONS(cmac) diff --git a/providers/implementations/signature/rsa_sig.c b/providers/implementations/signature/rsa_sig.c new file mode 100644 index 000000000000..7023a866131e --- /dev/null +++ b/providers/implementations/signature/rsa_sig.c @@ -0,0 +1,1474 @@ +/* + * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * RSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/err.h> +#include <openssl/rsa.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/proverr.h> +#include "internal/cryptlib.h" +#include "internal/nelem.h" +#include "internal/sizes.h" +#include "crypto/rsa.h" +#include "prov/providercommon.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/der_rsa.h" +#include "prov/securitycheck.h" + +#define RSA_DEFAULT_DIGEST_NAME OSSL_DIGEST_NAME_SHA1 + +static OSSL_FUNC_signature_newctx_fn rsa_newctx; +static OSSL_FUNC_signature_sign_init_fn rsa_sign_init; +static OSSL_FUNC_signature_verify_init_fn rsa_verify_init; +static OSSL_FUNC_signature_verify_recover_init_fn rsa_verify_recover_init; +static OSSL_FUNC_signature_sign_fn rsa_sign; +static OSSL_FUNC_signature_verify_fn rsa_verify; +static OSSL_FUNC_signature_verify_recover_fn rsa_verify_recover; +static OSSL_FUNC_signature_digest_sign_init_fn rsa_digest_sign_init; +static OSSL_FUNC_signature_digest_sign_update_fn rsa_digest_signverify_update; +static OSSL_FUNC_signature_digest_sign_final_fn rsa_digest_sign_final; +static OSSL_FUNC_signature_digest_verify_init_fn rsa_digest_verify_init; +static OSSL_FUNC_signature_digest_verify_update_fn rsa_digest_signverify_update; +static OSSL_FUNC_signature_digest_verify_final_fn rsa_digest_verify_final; +static OSSL_FUNC_signature_freectx_fn rsa_freectx; +static OSSL_FUNC_signature_dupctx_fn rsa_dupctx; +static OSSL_FUNC_signature_get_ctx_params_fn rsa_get_ctx_params; +static OSSL_FUNC_signature_gettable_ctx_params_fn rsa_gettable_ctx_params; +static OSSL_FUNC_signature_set_ctx_params_fn rsa_set_ctx_params; +static OSSL_FUNC_signature_settable_ctx_params_fn rsa_settable_ctx_params; +static OSSL_FUNC_signature_get_ctx_md_params_fn rsa_get_ctx_md_params; +static OSSL_FUNC_signature_gettable_ctx_md_params_fn rsa_gettable_ctx_md_params; +static OSSL_FUNC_signature_set_ctx_md_params_fn rsa_set_ctx_md_params; +static OSSL_FUNC_signature_settable_ctx_md_params_fn rsa_settable_ctx_md_params; + +static OSSL_ITEM padding_item[] = { + { RSA_PKCS1_PADDING, OSSL_PKEY_RSA_PAD_MODE_PKCSV15 }, + { RSA_NO_PADDING, OSSL_PKEY_RSA_PAD_MODE_NONE }, + { RSA_X931_PADDING, OSSL_PKEY_RSA_PAD_MODE_X931 }, + { RSA_PKCS1_PSS_PADDING, OSSL_PKEY_RSA_PAD_MODE_PSS }, + { 0, NULL } +}; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes RSA structures, so + * we use that here too. + */ + +typedef struct { + OSSL_LIB_CTX *libctx; + char *propq; + RSA *rsa; + int operation; + + /* + * Flag to determine if the hash function can be changed (1) or not (0) + * Because it's dangerous to change during a DigestSign or DigestVerify + * operation, this flag is cleared by their Init function, and set again + * by their Final function. + */ + unsigned int flag_allow_md : 1; + unsigned int mgf1_md_set : 1; + + /* main digest */ + EVP_MD *md; + EVP_MD_CTX *mdctx; + int mdnid; + char mdname[OSSL_MAX_NAME_SIZE]; /* Purely informational */ + + /* RSA padding mode */ + int pad_mode; + /* message digest for MGF1 */ + EVP_MD *mgf1_md; + int mgf1_mdnid; + char mgf1_mdname[OSSL_MAX_NAME_SIZE]; /* Purely informational */ + /* PSS salt length */ + int saltlen; + /* Minimum salt length or -1 if no PSS parameter restriction */ + int min_saltlen; + + /* Temp buffer */ + unsigned char *tbuf; + +} PROV_RSA_CTX; + +/* True if PSS parameters are restricted */ +#define rsa_pss_restricted(prsactx) (prsactx->min_saltlen != -1) + +static size_t rsa_get_md_size(const PROV_RSA_CTX *prsactx) +{ + if (prsactx->md != NULL) + return EVP_MD_get_size(prsactx->md); + return 0; +} + +static int rsa_check_padding(const PROV_RSA_CTX *prsactx, + const char *mdname, const char *mgf1_mdname, + int mdnid) +{ + switch(prsactx->pad_mode) { + case RSA_NO_PADDING: + if (mdname != NULL || mdnid != NID_undef) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE); + return 0; + } + break; + case RSA_X931_PADDING: + if (RSA_X931_hash_id(mdnid) == -1) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_X931_DIGEST); + return 0; + } + break; + case RSA_PKCS1_PSS_PADDING: + if (rsa_pss_restricted(prsactx)) + if ((mdname != NULL && !EVP_MD_is_a(prsactx->md, mdname)) + || (mgf1_mdname != NULL + && !EVP_MD_is_a(prsactx->mgf1_md, mgf1_mdname))) { + ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED); + return 0; + } + break; + default: + break; + } + + return 1; +} + +static int rsa_check_parameters(PROV_RSA_CTX *prsactx, int min_saltlen) +{ + if (prsactx->pad_mode == RSA_PKCS1_PSS_PADDING) { + int max_saltlen; + + /* See if minimum salt length exceeds maximum possible */ + max_saltlen = RSA_size(prsactx->rsa) - EVP_MD_get_size(prsactx->md); + if ((RSA_bits(prsactx->rsa) & 0x7) == 1) + max_saltlen--; + if (min_saltlen < 0 || min_saltlen > max_saltlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH); + return 0; + } + prsactx->min_saltlen = min_saltlen; + } + return 1; +} + +static void *rsa_newctx(void *provctx, const char *propq) +{ + PROV_RSA_CTX *prsactx = NULL; + char *propq_copy = NULL; + + if (!ossl_prov_is_running()) + return NULL; + + if ((prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX))) == NULL + || (propq != NULL + && (propq_copy = OPENSSL_strdup(propq)) == NULL)) { + OPENSSL_free(prsactx); + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + prsactx->libctx = PROV_LIBCTX_OF(provctx); + prsactx->flag_allow_md = 1; + prsactx->propq = propq_copy; + /* Maximum for sign, auto for verify */ + prsactx->saltlen = RSA_PSS_SALTLEN_AUTO; + prsactx->min_saltlen = -1; + return prsactx; +} + +static int rsa_pss_compute_saltlen(PROV_RSA_CTX *ctx) +{ + int saltlen = ctx->saltlen; + + if (saltlen == RSA_PSS_SALTLEN_DIGEST) { + saltlen = EVP_MD_get_size(ctx->md); + } else if (saltlen == RSA_PSS_SALTLEN_AUTO || saltlen == RSA_PSS_SALTLEN_MAX) { + saltlen = RSA_size(ctx->rsa) - EVP_MD_get_size(ctx->md) - 2; + if ((RSA_bits(ctx->rsa) & 0x7) == 1) + saltlen--; + } + if (saltlen < 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return -1; + } else if (saltlen < ctx->min_saltlen) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL, + "minimum salt length: %d, actual salt length: %d", + ctx->min_saltlen, saltlen); + return -1; + } + return saltlen; +} + +static unsigned char *rsa_generate_signature_aid(PROV_RSA_CTX *ctx, + unsigned char *aid_buf, + size_t buf_len, + size_t *aid_len) +{ + WPACKET pkt; + unsigned char *aid = NULL; + int saltlen; + RSA_PSS_PARAMS_30 pss_params; + int ret; + + if (!WPACKET_init_der(&pkt, aid_buf, buf_len)) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + switch(ctx->pad_mode) { + case RSA_PKCS1_PADDING: + ret = ossl_DER_w_algorithmIdentifier_MDWithRSAEncryption(&pkt, -1, + ctx->mdnid); + + if (ret > 0) { + break; + } else if (ret == 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + goto cleanup; + } + ERR_raise_data(ERR_LIB_PROV, ERR_R_UNSUPPORTED, + "Algorithm ID generation - md NID: %d", + ctx->mdnid); + goto cleanup; + case RSA_PKCS1_PSS_PADDING: + saltlen = rsa_pss_compute_saltlen(ctx); + if (saltlen < 0) + goto cleanup; + if (!ossl_rsa_pss_params_30_set_defaults(&pss_params) + || !ossl_rsa_pss_params_30_set_hashalg(&pss_params, ctx->mdnid) + || !ossl_rsa_pss_params_30_set_maskgenhashalg(&pss_params, + ctx->mgf1_mdnid) + || !ossl_rsa_pss_params_30_set_saltlen(&pss_params, saltlen) + || !ossl_DER_w_algorithmIdentifier_RSA_PSS(&pkt, -1, + RSA_FLAG_TYPE_RSASSAPSS, + &pss_params)) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + goto cleanup; + } + break; + default: + ERR_raise_data(ERR_LIB_PROV, ERR_R_UNSUPPORTED, + "Algorithm ID generation - pad mode: %d", + ctx->pad_mode); + goto cleanup; + } + if (WPACKET_finish(&pkt)) { + WPACKET_get_total_written(&pkt, aid_len); + aid = WPACKET_get_curr(&pkt); + } + cleanup: + WPACKET_cleanup(&pkt); + return aid; +} + +static int rsa_setup_md(PROV_RSA_CTX *ctx, const char *mdname, + const char *mdprops) +{ + if (mdprops == NULL) + mdprops = ctx->propq; + + if (mdname != NULL) { + EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops); + int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); + int md_nid = ossl_digest_rsa_sign_get_md_nid(ctx->libctx, md, + sha1_allowed); + size_t mdname_len = strlen(mdname); + + if (md == NULL + || md_nid <= 0 + || !rsa_check_padding(ctx, mdname, NULL, md_nid) + || mdname_len >= sizeof(ctx->mdname)) { + if (md == NULL) + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "%s could not be fetched", mdname); + if (md_nid <= 0) + ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, + "digest=%s", mdname); + if (mdname_len >= sizeof(ctx->mdname)) + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "%s exceeds name buffer length", mdname); + EVP_MD_free(md); + return 0; + } + + if (!ctx->flag_allow_md) { + if (ctx->mdname[0] != '\0' && !EVP_MD_is_a(md, ctx->mdname)) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, + "digest %s != %s", mdname, ctx->mdname); + EVP_MD_free(md); + return 0; + } + EVP_MD_free(md); + return 1; + } + + if (!ctx->mgf1_md_set) { + if (!EVP_MD_up_ref(md)) { + EVP_MD_free(md); + return 0; + } + EVP_MD_free(ctx->mgf1_md); + ctx->mgf1_md = md; + ctx->mgf1_mdnid = md_nid; + OPENSSL_strlcpy(ctx->mgf1_mdname, mdname, sizeof(ctx->mgf1_mdname)); + } + + EVP_MD_CTX_free(ctx->mdctx); + EVP_MD_free(ctx->md); + + ctx->mdctx = NULL; + ctx->md = md; + ctx->mdnid = md_nid; + OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname)); + } + + return 1; +} + +static int rsa_setup_mgf1_md(PROV_RSA_CTX *ctx, const char *mdname, + const char *mdprops) +{ + size_t len; + EVP_MD *md = NULL; + int mdnid; + + if (mdprops == NULL) + mdprops = ctx->propq; + + if ((md = EVP_MD_fetch(ctx->libctx, mdname, mdprops)) == NULL) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "%s could not be fetched", mdname); + return 0; + } + /* The default for mgf1 is SHA1 - so allow SHA1 */ + if ((mdnid = ossl_digest_rsa_sign_get_md_nid(ctx->libctx, md, 1)) <= 0 + || !rsa_check_padding(ctx, NULL, mdname, mdnid)) { + if (mdnid <= 0) + ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, + "digest=%s", mdname); + EVP_MD_free(md); + return 0; + } + len = OPENSSL_strlcpy(ctx->mgf1_mdname, mdname, sizeof(ctx->mgf1_mdname)); + if (len >= sizeof(ctx->mgf1_mdname)) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "%s exceeds name buffer length", mdname); + EVP_MD_free(md); + return 0; + } + + EVP_MD_free(ctx->mgf1_md); + ctx->mgf1_md = md; + ctx->mgf1_mdnid = mdnid; + ctx->mgf1_md_set = 1; + return 1; +} + +static int rsa_signverify_init(void *vprsactx, void *vrsa, + const OSSL_PARAM params[], int operation) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (!ossl_prov_is_running() || prsactx == NULL) + return 0; + + if (vrsa == NULL && prsactx->rsa == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } + + if (vrsa != NULL) { + if (!ossl_rsa_check_key(prsactx->libctx, vrsa, operation)) + return 0; + + if (!RSA_up_ref(vrsa)) + return 0; + RSA_free(prsactx->rsa); + prsactx->rsa = vrsa; + } + + prsactx->operation = operation; + + /* Maximum for sign, auto for verify */ + prsactx->saltlen = RSA_PSS_SALTLEN_AUTO; + prsactx->min_saltlen = -1; + + switch (RSA_test_flags(prsactx->rsa, RSA_FLAG_TYPE_MASK)) { + case RSA_FLAG_TYPE_RSA: + prsactx->pad_mode = RSA_PKCS1_PADDING; + break; + case RSA_FLAG_TYPE_RSASSAPSS: + prsactx->pad_mode = RSA_PKCS1_PSS_PADDING; + + { + const RSA_PSS_PARAMS_30 *pss = + ossl_rsa_get0_pss_params_30(prsactx->rsa); + + if (!ossl_rsa_pss_params_30_is_unrestricted(pss)) { + int md_nid = ossl_rsa_pss_params_30_hashalg(pss); + int mgf1md_nid = ossl_rsa_pss_params_30_maskgenhashalg(pss); + int min_saltlen = ossl_rsa_pss_params_30_saltlen(pss); + const char *mdname, *mgf1mdname; + size_t len; + + mdname = ossl_rsa_oaeppss_nid2name(md_nid); + mgf1mdname = ossl_rsa_oaeppss_nid2name(mgf1md_nid); + + if (mdname == NULL) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "PSS restrictions lack hash algorithm"); + return 0; + } + if (mgf1mdname == NULL) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "PSS restrictions lack MGF1 hash algorithm"); + return 0; + } + + len = OPENSSL_strlcpy(prsactx->mdname, mdname, + sizeof(prsactx->mdname)); + if (len >= sizeof(prsactx->mdname)) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "hash algorithm name too long"); + return 0; + } + len = OPENSSL_strlcpy(prsactx->mgf1_mdname, mgf1mdname, + sizeof(prsactx->mgf1_mdname)); + if (len >= sizeof(prsactx->mgf1_mdname)) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "MGF1 hash algorithm name too long"); + return 0; + } + prsactx->saltlen = min_saltlen; + + /* call rsa_setup_mgf1_md before rsa_setup_md to avoid duplication */ + if (!rsa_setup_mgf1_md(prsactx, mgf1mdname, prsactx->propq) + || !rsa_setup_md(prsactx, mdname, prsactx->propq) + || !rsa_check_parameters(prsactx, min_saltlen)) + return 0; + } + } + + break; + default: + ERR_raise(ERR_LIB_RSA, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + + if (!rsa_set_ctx_params(prsactx, params)) + return 0; + + return 1; +} + +static int setup_tbuf(PROV_RSA_CTX *ctx) +{ + if (ctx->tbuf != NULL) + return 1; + if ((ctx->tbuf = OPENSSL_malloc(RSA_size(ctx->rsa))) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + return 1; +} + +static void clean_tbuf(PROV_RSA_CTX *ctx) +{ + if (ctx->tbuf != NULL) + OPENSSL_cleanse(ctx->tbuf, RSA_size(ctx->rsa)); +} + +static void free_tbuf(PROV_RSA_CTX *ctx) +{ + clean_tbuf(ctx); + OPENSSL_free(ctx->tbuf); + ctx->tbuf = NULL; +} + +static int rsa_sign_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) +{ + if (!ossl_prov_is_running()) + return 0; + return rsa_signverify_init(vprsactx, vrsa, params, EVP_PKEY_OP_SIGN); +} + +static int rsa_sign(void *vprsactx, unsigned char *sig, size_t *siglen, + size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + int ret; + size_t rsasize = RSA_size(prsactx->rsa); + size_t mdsize = rsa_get_md_size(prsactx); + + if (!ossl_prov_is_running()) + return 0; + + if (sig == NULL) { + *siglen = rsasize; + return 1; + } + + if (sigsize < rsasize) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_SIGNATURE_SIZE, + "is %zu, should be at least %zu", sigsize, rsasize); + return 0; + } + + if (mdsize != 0) { + if (tbslen != mdsize) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH); + return 0; + } + +#ifndef FIPS_MODULE + if (EVP_MD_is_a(prsactx->md, OSSL_DIGEST_NAME_MDC2)) { + unsigned int sltmp; + + if (prsactx->pad_mode != RSA_PKCS1_PADDING) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE, + "only PKCS#1 padding supported with MDC2"); + return 0; + } + ret = RSA_sign_ASN1_OCTET_STRING(0, tbs, tbslen, sig, &sltmp, + prsactx->rsa); + + if (ret <= 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + ret = sltmp; + goto end; + } +#endif + switch (prsactx->pad_mode) { + case RSA_X931_PADDING: + if ((size_t)RSA_size(prsactx->rsa) < tbslen + 1) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL, + "RSA key size = %d, expected minimum = %d", + RSA_size(prsactx->rsa), tbslen + 1); + return 0; + } + if (!setup_tbuf(prsactx)) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(prsactx->tbuf, tbs, tbslen); + prsactx->tbuf[tbslen] = RSA_X931_hash_id(prsactx->mdnid); + ret = RSA_private_encrypt(tbslen + 1, prsactx->tbuf, + sig, prsactx->rsa, RSA_X931_PADDING); + clean_tbuf(prsactx); + break; + + case RSA_PKCS1_PADDING: + { + unsigned int sltmp; + + ret = RSA_sign(prsactx->mdnid, tbs, tbslen, sig, &sltmp, + prsactx->rsa); + if (ret <= 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + ret = sltmp; + } + break; + + case RSA_PKCS1_PSS_PADDING: + /* Check PSS restrictions */ + if (rsa_pss_restricted(prsactx)) { + switch (prsactx->saltlen) { + case RSA_PSS_SALTLEN_DIGEST: + if (prsactx->min_saltlen > EVP_MD_get_size(prsactx->md)) { + ERR_raise_data(ERR_LIB_PROV, + PROV_R_PSS_SALTLEN_TOO_SMALL, + "minimum salt length set to %d, " + "but the digest only gives %d", + prsactx->min_saltlen, + EVP_MD_get_size(prsactx->md)); + return 0; + } + /* FALLTHRU */ + default: + if (prsactx->saltlen >= 0 + && prsactx->saltlen < prsactx->min_saltlen) { + ERR_raise_data(ERR_LIB_PROV, + PROV_R_PSS_SALTLEN_TOO_SMALL, + "minimum salt length set to %d, but the" + "actual salt length is only set to %d", + prsactx->min_saltlen, + prsactx->saltlen); + return 0; + } + break; + } + } + if (!setup_tbuf(prsactx)) + return 0; + if (!RSA_padding_add_PKCS1_PSS_mgf1(prsactx->rsa, + prsactx->tbuf, tbs, + prsactx->md, prsactx->mgf1_md, + prsactx->saltlen)) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + ret = RSA_private_encrypt(RSA_size(prsactx->rsa), prsactx->tbuf, + sig, prsactx->rsa, RSA_NO_PADDING); + clean_tbuf(prsactx); + break; + + default: + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE, + "Only X.931, PKCS#1 v1.5 or PSS padding allowed"); + return 0; + } + } else { + ret = RSA_private_encrypt(tbslen, tbs, sig, prsactx->rsa, + prsactx->pad_mode); + } + +#ifndef FIPS_MODULE + end: +#endif + if (ret <= 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + + *siglen = ret; + return 1; +} + +static int rsa_verify_recover_init(void *vprsactx, void *vrsa, + const OSSL_PARAM params[]) +{ + if (!ossl_prov_is_running()) + return 0; + return rsa_signverify_init(vprsactx, vrsa, params, + EVP_PKEY_OP_VERIFYRECOVER); +} + +static int rsa_verify_recover(void *vprsactx, + unsigned char *rout, + size_t *routlen, + size_t routsize, + const unsigned char *sig, + size_t siglen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + int ret; + + if (!ossl_prov_is_running()) + return 0; + + if (rout == NULL) { + *routlen = RSA_size(prsactx->rsa); + return 1; + } + + if (prsactx->md != NULL) { + switch (prsactx->pad_mode) { + case RSA_X931_PADDING: + if (!setup_tbuf(prsactx)) + return 0; + ret = RSA_public_decrypt(siglen, sig, prsactx->tbuf, prsactx->rsa, + RSA_X931_PADDING); + if (ret < 1) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + ret--; + if (prsactx->tbuf[ret] != RSA_X931_hash_id(prsactx->mdnid)) { + ERR_raise(ERR_LIB_PROV, PROV_R_ALGORITHM_MISMATCH); + return 0; + } + if (ret != EVP_MD_get_size(prsactx->md)) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH, + "Should be %d, but got %d", + EVP_MD_get_size(prsactx->md), ret); + return 0; + } + + *routlen = ret; + if (rout != prsactx->tbuf) { + if (routsize < (size_t)ret) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL, + "buffer size is %d, should be %d", + routsize, ret); + return 0; + } + memcpy(rout, prsactx->tbuf, ret); + } + break; + + case RSA_PKCS1_PADDING: + { + size_t sltmp; + + ret = ossl_rsa_verify(prsactx->mdnid, NULL, 0, rout, &sltmp, + sig, siglen, prsactx->rsa); + if (ret <= 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + ret = sltmp; + } + break; + + default: + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE, + "Only X.931 or PKCS#1 v1.5 padding allowed"); + return 0; + } + } else { + ret = RSA_public_decrypt(siglen, sig, rout, prsactx->rsa, + prsactx->pad_mode); + if (ret < 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + } + *routlen = ret; + return 1; +} + +static int rsa_verify_init(void *vprsactx, void *vrsa, + const OSSL_PARAM params[]) +{ + if (!ossl_prov_is_running()) + return 0; + return rsa_signverify_init(vprsactx, vrsa, params, EVP_PKEY_OP_VERIFY); +} + +static int rsa_verify(void *vprsactx, const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + size_t rslen; + + if (!ossl_prov_is_running()) + return 0; + if (prsactx->md != NULL) { + switch (prsactx->pad_mode) { + case RSA_PKCS1_PADDING: + if (!RSA_verify(prsactx->mdnid, tbs, tbslen, sig, siglen, + prsactx->rsa)) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + return 1; + case RSA_X931_PADDING: + if (!setup_tbuf(prsactx)) + return 0; + if (rsa_verify_recover(prsactx, prsactx->tbuf, &rslen, 0, + sig, siglen) <= 0) + return 0; + break; + case RSA_PKCS1_PSS_PADDING: + { + int ret; + size_t mdsize; + + /* + * We need to check this for the RSA_verify_PKCS1_PSS_mgf1() + * call + */ + mdsize = rsa_get_md_size(prsactx); + if (tbslen != mdsize) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH, + "Should be %d, but got %d", + mdsize, tbslen); + return 0; + } + + if (!setup_tbuf(prsactx)) + return 0; + ret = RSA_public_decrypt(siglen, sig, prsactx->tbuf, + prsactx->rsa, RSA_NO_PADDING); + if (ret <= 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + ret = RSA_verify_PKCS1_PSS_mgf1(prsactx->rsa, tbs, + prsactx->md, prsactx->mgf1_md, + prsactx->tbuf, + prsactx->saltlen); + if (ret <= 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + return 1; + } + default: + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE, + "Only X.931, PKCS#1 v1.5 or PSS padding allowed"); + return 0; + } + } else { + if (!setup_tbuf(prsactx)) + return 0; + rslen = RSA_public_decrypt(siglen, sig, prsactx->tbuf, prsactx->rsa, + prsactx->pad_mode); + if (rslen == 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB); + return 0; + } + } + + if ((rslen != tbslen) || memcmp(tbs, prsactx->tbuf, rslen)) + return 0; + + return 1; +} + +static int rsa_digest_signverify_init(void *vprsactx, const char *mdname, + void *vrsa, const OSSL_PARAM params[], + int operation) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (!ossl_prov_is_running()) + return 0; + + if (!rsa_signverify_init(vprsactx, vrsa, params, operation)) + return 0; + + if (mdname != NULL + /* was rsa_setup_md already called in rsa_signverify_init()? */ + && (mdname[0] == '\0' || OPENSSL_strcasecmp(prsactx->mdname, mdname) != 0) + && !rsa_setup_md(prsactx, mdname, prsactx->propq)) + return 0; + + prsactx->flag_allow_md = 0; + + if (prsactx->mdctx == NULL) { + prsactx->mdctx = EVP_MD_CTX_new(); + if (prsactx->mdctx == NULL) + goto error; + } + + if (!EVP_DigestInit_ex2(prsactx->mdctx, prsactx->md, params)) + goto error; + + return 1; + + error: + EVP_MD_CTX_free(prsactx->mdctx); + prsactx->mdctx = NULL; + return 0; +} + +static int rsa_digest_signverify_update(void *vprsactx, + const unsigned char *data, + size_t datalen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (prsactx == NULL || prsactx->mdctx == NULL) + return 0; + + return EVP_DigestUpdate(prsactx->mdctx, data, datalen); +} + +static int rsa_digest_sign_init(void *vprsactx, const char *mdname, + void *vrsa, const OSSL_PARAM params[]) +{ + if (!ossl_prov_is_running()) + return 0; + return rsa_digest_signverify_init(vprsactx, mdname, vrsa, + params, EVP_PKEY_OP_SIGN); +} + +static int rsa_digest_sign_final(void *vprsactx, unsigned char *sig, + size_t *siglen, size_t sigsize) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (!ossl_prov_is_running() || prsactx == NULL) + return 0; + prsactx->flag_allow_md = 1; + if (prsactx->mdctx == NULL) + return 0; + /* + * If sig is NULL then we're just finding out the sig size. Other fields + * are ignored. Defer to rsa_sign. + */ + if (sig != NULL) { + /* + * The digests used here are all known (see rsa_get_md_nid()), so they + * should not exceed the internal buffer size of EVP_MAX_MD_SIZE. + */ + if (!EVP_DigestFinal_ex(prsactx->mdctx, digest, &dlen)) + return 0; + } + + return rsa_sign(vprsactx, sig, siglen, sigsize, digest, (size_t)dlen); +} + +static int rsa_digest_verify_init(void *vprsactx, const char *mdname, + void *vrsa, const OSSL_PARAM params[]) +{ + if (!ossl_prov_is_running()) + return 0; + return rsa_digest_signverify_init(vprsactx, mdname, vrsa, + params, EVP_PKEY_OP_VERIFY); +} + +int rsa_digest_verify_final(void *vprsactx, const unsigned char *sig, + size_t siglen) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (!ossl_prov_is_running()) + return 0; + + if (prsactx == NULL) + return 0; + prsactx->flag_allow_md = 1; + if (prsactx->mdctx == NULL) + return 0; + + /* + * The digests used here are all known (see rsa_get_md_nid()), so they + * should not exceed the internal buffer size of EVP_MAX_MD_SIZE. + */ + if (!EVP_DigestFinal_ex(prsactx->mdctx, digest, &dlen)) + return 0; + + return rsa_verify(vprsactx, sig, siglen, digest, (size_t)dlen); +} + +static void rsa_freectx(void *vprsactx) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (prsactx == NULL) + return; + + EVP_MD_CTX_free(prsactx->mdctx); + EVP_MD_free(prsactx->md); + EVP_MD_free(prsactx->mgf1_md); + OPENSSL_free(prsactx->propq); + free_tbuf(prsactx); + RSA_free(prsactx->rsa); + + OPENSSL_clear_free(prsactx, sizeof(*prsactx)); +} + +static void *rsa_dupctx(void *vprsactx) +{ + PROV_RSA_CTX *srcctx = (PROV_RSA_CTX *)vprsactx; + PROV_RSA_CTX *dstctx; + + if (!ossl_prov_is_running()) + return NULL; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + *dstctx = *srcctx; + dstctx->rsa = NULL; + dstctx->md = NULL; + dstctx->mdctx = NULL; + dstctx->tbuf = NULL; + dstctx->propq = NULL; + + if (srcctx->rsa != NULL && !RSA_up_ref(srcctx->rsa)) + goto err; + dstctx->rsa = srcctx->rsa; + + if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md)) + goto err; + dstctx->md = srcctx->md; + + if (srcctx->mgf1_md != NULL && !EVP_MD_up_ref(srcctx->mgf1_md)) + goto err; + dstctx->mgf1_md = srcctx->mgf1_md; + + if (srcctx->mdctx != NULL) { + dstctx->mdctx = EVP_MD_CTX_new(); + if (dstctx->mdctx == NULL + || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx)) + goto err; + } + + if (srcctx->propq != NULL) { + dstctx->propq = OPENSSL_strdup(srcctx->propq); + if (dstctx->propq == NULL) + goto err; + } + + return dstctx; + err: + rsa_freectx(dstctx); + return NULL; +} + +static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + OSSL_PARAM *p; + + if (prsactx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + if (p != NULL) { + /* The Algorithm Identifier of the combined signature algorithm */ + unsigned char aid_buf[128]; + unsigned char *aid; + size_t aid_len; + + aid = rsa_generate_signature_aid(prsactx, aid_buf, + sizeof(aid_buf), &aid_len); + if (aid == NULL || !OSSL_PARAM_set_octet_string(p, aid, aid_len)) + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PAD_MODE); + if (p != NULL) + switch (p->data_type) { + case OSSL_PARAM_INTEGER: + if (!OSSL_PARAM_set_int(p, prsactx->pad_mode)) + return 0; + break; + case OSSL_PARAM_UTF8_STRING: + { + int i; + const char *word = NULL; + + for (i = 0; padding_item[i].id != 0; i++) { + if (prsactx->pad_mode == (int)padding_item[i].id) { + word = padding_item[i].ptr; + break; + } + } + + if (word != NULL) { + if (!OSSL_PARAM_set_utf8_string(p, word)) + return 0; + } else { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + } + } + break; + default: + return 0; + } + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->mdname)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_MGF1_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->mgf1_mdname)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN); + if (p != NULL) { + if (p->data_type == OSSL_PARAM_INTEGER) { + if (!OSSL_PARAM_set_int(p, prsactx->saltlen)) + return 0; + } else if (p->data_type == OSSL_PARAM_UTF8_STRING) { + const char *value = NULL; + + switch (prsactx->saltlen) { + case RSA_PSS_SALTLEN_DIGEST: + value = OSSL_PKEY_RSA_PSS_SALT_LEN_DIGEST; + break; + case RSA_PSS_SALTLEN_MAX: + value = OSSL_PKEY_RSA_PSS_SALT_LEN_MAX; + break; + case RSA_PSS_SALTLEN_AUTO: + value = OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO; + break; + default: + { + int len = BIO_snprintf(p->data, p->data_size, "%d", + prsactx->saltlen); + + if (len <= 0) + return 0; + p->return_size = len; + break; + } + } + if (value != NULL + && !OSSL_PARAM_set_utf8_string(p, value)) + return 0; + } + } + + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *rsa_gettable_ctx_params(ossl_unused void *vprsactx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + const OSSL_PARAM *p; + int pad_mode; + int saltlen; + char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = NULL; + char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = NULL; + char mgf1mdname[OSSL_MAX_NAME_SIZE] = "", *pmgf1mdname = NULL; + char mgf1mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmgf1mdprops = NULL; + + if (prsactx == NULL) + return 0; + if (params == NULL) + return 1; + + pad_mode = prsactx->pad_mode; + saltlen = prsactx->saltlen; + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL) { + const OSSL_PARAM *propsp = + OSSL_PARAM_locate_const(params, + OSSL_SIGNATURE_PARAM_PROPERTIES); + + pmdname = mdname; + if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname))) + return 0; + + if (propsp != NULL) { + pmdprops = mdprops; + if (!OSSL_PARAM_get_utf8_string(propsp, + &pmdprops, sizeof(mdprops))) + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PAD_MODE); + if (p != NULL) { + const char *err_extra_text = NULL; + + switch (p->data_type) { + case OSSL_PARAM_INTEGER: /* Support for legacy pad mode number */ + if (!OSSL_PARAM_get_int(p, &pad_mode)) + return 0; + break; + case OSSL_PARAM_UTF8_STRING: + { + int i; + + if (p->data == NULL) + return 0; + + for (i = 0; padding_item[i].id != 0; i++) { + if (strcmp(p->data, padding_item[i].ptr) == 0) { + pad_mode = padding_item[i].id; + break; + } + } + } + break; + default: + return 0; + } + + switch (pad_mode) { + case RSA_PKCS1_OAEP_PADDING: + /* + * OAEP padding is for asymmetric cipher only so is not compatible + * with signature use. + */ + err_extra_text = "OAEP padding not allowed for signing / verifying"; + goto bad_pad; + case RSA_PKCS1_PSS_PADDING: + if ((prsactx->operation + & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY)) == 0) { + err_extra_text = + "PSS padding only allowed for sign and verify operations"; + goto bad_pad; + } + break; + case RSA_PKCS1_PADDING: + err_extra_text = "PKCS#1 padding not allowed with RSA-PSS"; + goto cont; + case RSA_NO_PADDING: + err_extra_text = "No padding not allowed with RSA-PSS"; + goto cont; + case RSA_X931_PADDING: + err_extra_text = "X.931 padding not allowed with RSA-PSS"; + cont: + if (RSA_test_flags(prsactx->rsa, + RSA_FLAG_TYPE_MASK) == RSA_FLAG_TYPE_RSA) + break; + /* FALLTHRU */ + default: + bad_pad: + if (err_extra_text == NULL) + ERR_raise(ERR_LIB_PROV, + PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE); + else + ERR_raise_data(ERR_LIB_PROV, + PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE, + err_extra_text); + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN); + if (p != NULL) { + if (pad_mode != RSA_PKCS1_PSS_PADDING) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED, + "PSS saltlen can only be specified if " + "PSS padding has been specified first"); + return 0; + } + + switch (p->data_type) { + case OSSL_PARAM_INTEGER: /* Support for legacy pad mode number */ + if (!OSSL_PARAM_get_int(p, &saltlen)) + return 0; + break; + case OSSL_PARAM_UTF8_STRING: + if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_DIGEST) == 0) + saltlen = RSA_PSS_SALTLEN_DIGEST; + else if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_MAX) == 0) + saltlen = RSA_PSS_SALTLEN_MAX; + else if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO) == 0) + saltlen = RSA_PSS_SALTLEN_AUTO; + else + saltlen = atoi(p->data); + break; + default: + return 0; + } + + /* + * RSA_PSS_SALTLEN_MAX seems curiously named in this check. + * Contrary to what it's name suggests, it's the currently + * lowest saltlen number possible. + */ + if (saltlen < RSA_PSS_SALTLEN_MAX) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH); + return 0; + } + + if (rsa_pss_restricted(prsactx)) { + switch (saltlen) { + case RSA_PSS_SALTLEN_AUTO: + if (prsactx->operation == EVP_PKEY_OP_VERIFY) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH, + "Cannot use autodetected salt length"); + return 0; + } + break; + case RSA_PSS_SALTLEN_DIGEST: + if (prsactx->min_saltlen > EVP_MD_get_size(prsactx->md)) { + ERR_raise_data(ERR_LIB_PROV, + PROV_R_PSS_SALTLEN_TOO_SMALL, + "Should be more than %d, but would be " + "set to match digest size (%d)", + prsactx->min_saltlen, + EVP_MD_get_size(prsactx->md)); + return 0; + } + break; + default: + if (saltlen >= 0 && saltlen < prsactx->min_saltlen) { + ERR_raise_data(ERR_LIB_PROV, + PROV_R_PSS_SALTLEN_TOO_SMALL, + "Should be more than %d, " + "but would be set to %d", + prsactx->min_saltlen, saltlen); + return 0; + } + } + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MGF1_DIGEST); + if (p != NULL) { + const OSSL_PARAM *propsp = + OSSL_PARAM_locate_const(params, + OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES); + + pmgf1mdname = mgf1mdname; + if (!OSSL_PARAM_get_utf8_string(p, &pmgf1mdname, sizeof(mgf1mdname))) + return 0; + + if (propsp != NULL) { + pmgf1mdprops = mgf1mdprops; + if (!OSSL_PARAM_get_utf8_string(propsp, + &pmgf1mdprops, sizeof(mgf1mdprops))) + return 0; + } + + if (pad_mode != RSA_PKCS1_PSS_PADDING) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MGF1_MD); + return 0; + } + } + + prsactx->saltlen = saltlen; + prsactx->pad_mode = pad_mode; + + if (prsactx->md == NULL && pmdname == NULL + && pad_mode == RSA_PKCS1_PSS_PADDING) + pmdname = RSA_DEFAULT_DIGEST_NAME; + + if (pmgf1mdname != NULL + && !rsa_setup_mgf1_md(prsactx, pmgf1mdname, pmgf1mdprops)) + return 0; + + if (pmdname != NULL) { + if (!rsa_setup_md(prsactx, pmdname, pmdprops)) + return 0; + } else { + if (!rsa_check_padding(prsactx, NULL, NULL, prsactx->mdnid)) + return 0; + } + return 1; +} + +static const OSSL_PARAM settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM settable_ctx_params_no_digest[] = { + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *rsa_settable_ctx_params(void *vprsactx, + ossl_unused void *provctx) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (prsactx != NULL && !prsactx->flag_allow_md) + return settable_ctx_params_no_digest; + return settable_ctx_params; +} + +static int rsa_get_ctx_md_params(void *vprsactx, OSSL_PARAM *params) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (prsactx->mdctx == NULL) + return 0; + + return EVP_MD_CTX_get_params(prsactx->mdctx, params); +} + +static const OSSL_PARAM *rsa_gettable_ctx_md_params(void *vprsactx) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (prsactx->md == NULL) + return 0; + + return EVP_MD_gettable_ctx_params(prsactx->md); +} + +static int rsa_set_ctx_md_params(void *vprsactx, const OSSL_PARAM params[]) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (prsactx->mdctx == NULL) + return 0; + + return EVP_MD_CTX_set_params(prsactx->mdctx, params); +} + +static const OSSL_PARAM *rsa_settable_ctx_md_params(void *vprsactx) +{ + PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + + if (prsactx->md == NULL) + return 0; + + return EVP_MD_settable_ctx_params(prsactx->md); +} + +const OSSL_DISPATCH ossl_rsa_signature_functions[] = { + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))rsa_newctx }, + { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))rsa_sign_init }, + { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))rsa_sign }, + { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))rsa_verify_init }, + { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))rsa_verify }, + { OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT, + (void (*)(void))rsa_verify_recover_init }, + { OSSL_FUNC_SIGNATURE_VERIFY_RECOVER, + (void (*)(void))rsa_verify_recover }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, + (void (*)(void))rsa_digest_sign_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, + (void (*)(void))rsa_digest_signverify_update }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, + (void (*)(void))rsa_digest_sign_final }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, + (void (*)(void))rsa_digest_verify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE, + (void (*)(void))rsa_digest_signverify_update }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL, + (void (*)(void))rsa_digest_verify_final }, + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))rsa_freectx }, + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))rsa_dupctx }, + { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))rsa_get_ctx_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, + (void (*)(void))rsa_gettable_ctx_params }, + { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))rsa_set_ctx_params }, + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, + (void (*)(void))rsa_settable_ctx_params }, + { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS, + (void (*)(void))rsa_get_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS, + (void (*)(void))rsa_gettable_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS, + (void (*)(void))rsa_set_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS, + (void (*)(void))rsa_settable_ctx_md_params }, + { 0, NULL } +}; diff --git a/providers/implementations/signature/sm2_sig.c b/providers/implementations/signature/sm2_sig.c new file mode 100644 index 000000000000..fffb280c776a --- /dev/null +++ b/providers/implementations/signature/sm2_sig.c @@ -0,0 +1,564 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * ECDSA low level APIs are deprecated for public use, but still ok for + * internal use - SM2 implemetation uses ECDSA_size() function. + */ +#include "internal/deprecated.h" + +#include <string.h> /* memcpy */ +#include <openssl/crypto.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/dsa.h> +#include <openssl/params.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/proverr.h> +#include "internal/nelem.h" +#include "internal/sizes.h" +#include "internal/cryptlib.h" +#include "internal/sm3.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "crypto/ec.h" +#include "crypto/sm2.h" +#include "prov/der_sm2.h" + +static OSSL_FUNC_signature_newctx_fn sm2sig_newctx; +static OSSL_FUNC_signature_sign_init_fn sm2sig_signature_init; +static OSSL_FUNC_signature_verify_init_fn sm2sig_signature_init; +static OSSL_FUNC_signature_sign_fn sm2sig_sign; +static OSSL_FUNC_signature_verify_fn sm2sig_verify; +static OSSL_FUNC_signature_digest_sign_init_fn sm2sig_digest_signverify_init; +static OSSL_FUNC_signature_digest_sign_update_fn sm2sig_digest_signverify_update; +static OSSL_FUNC_signature_digest_sign_final_fn sm2sig_digest_sign_final; +static OSSL_FUNC_signature_digest_verify_init_fn sm2sig_digest_signverify_init; +static OSSL_FUNC_signature_digest_verify_update_fn sm2sig_digest_signverify_update; +static OSSL_FUNC_signature_digest_verify_final_fn sm2sig_digest_verify_final; +static OSSL_FUNC_signature_freectx_fn sm2sig_freectx; +static OSSL_FUNC_signature_dupctx_fn sm2sig_dupctx; +static OSSL_FUNC_signature_get_ctx_params_fn sm2sig_get_ctx_params; +static OSSL_FUNC_signature_gettable_ctx_params_fn sm2sig_gettable_ctx_params; +static OSSL_FUNC_signature_set_ctx_params_fn sm2sig_set_ctx_params; +static OSSL_FUNC_signature_settable_ctx_params_fn sm2sig_settable_ctx_params; +static OSSL_FUNC_signature_get_ctx_md_params_fn sm2sig_get_ctx_md_params; +static OSSL_FUNC_signature_gettable_ctx_md_params_fn sm2sig_gettable_ctx_md_params; +static OSSL_FUNC_signature_set_ctx_md_params_fn sm2sig_set_ctx_md_params; +static OSSL_FUNC_signature_settable_ctx_md_params_fn sm2sig_settable_ctx_md_params; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes EC structures, so + * we use that here too. + */ +typedef struct { + OSSL_LIB_CTX *libctx; + char *propq; + EC_KEY *ec; + + /* + * Flag to termine if the 'z' digest needs to be computed and fed to the + * hash function. + * This flag should be set on initialization and the compuation should + * be performed only once, on first update. + */ + unsigned int flag_compute_z_digest : 1; + + char mdname[OSSL_MAX_NAME_SIZE]; + + /* The Algorithm Identifier of the combined signature algorithm */ + unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE]; + unsigned char *aid; + size_t aid_len; + + /* main digest */ + EVP_MD *md; + EVP_MD_CTX *mdctx; + size_t mdsize; + + /* SM2 ID used for calculating the Z value */ + unsigned char *id; + size_t id_len; +} PROV_SM2_CTX; + +static int sm2sig_set_mdname(PROV_SM2_CTX *psm2ctx, const char *mdname) +{ + if (psm2ctx->md == NULL) /* We need an SM3 md to compare with */ + psm2ctx->md = EVP_MD_fetch(psm2ctx->libctx, psm2ctx->mdname, + psm2ctx->propq); + if (psm2ctx->md == NULL) + return 0; + + if (mdname == NULL) + return 1; + + if (strlen(mdname) >= sizeof(psm2ctx->mdname) + || !EVP_MD_is_a(psm2ctx->md, mdname)) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, "digest=%s", + mdname); + return 0; + } + + OPENSSL_strlcpy(psm2ctx->mdname, mdname, sizeof(psm2ctx->mdname)); + return 1; +} + +static void *sm2sig_newctx(void *provctx, const char *propq) +{ + PROV_SM2_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_SM2_CTX)); + + if (ctx == NULL) + return NULL; + + ctx->libctx = PROV_LIBCTX_OF(provctx); + if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL) { + OPENSSL_free(ctx); + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + ctx->mdsize = SM3_DIGEST_LENGTH; + strcpy(ctx->mdname, OSSL_DIGEST_NAME_SM3); + return ctx; +} + +static int sm2sig_signature_init(void *vpsm2ctx, void *ec, + const OSSL_PARAM params[]) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + + if (!ossl_prov_is_running() + || psm2ctx == NULL) + return 0; + + if (ec == NULL && psm2ctx->ec == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); + return 0; + } + + if (ec != NULL) { + if (!EC_KEY_up_ref(ec)) + return 0; + EC_KEY_free(psm2ctx->ec); + psm2ctx->ec = ec; + } + + return sm2sig_set_ctx_params(psm2ctx, params); +} + +static int sm2sig_sign(void *vpsm2ctx, unsigned char *sig, size_t *siglen, + size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx; + int ret; + unsigned int sltmp; + /* SM2 uses ECDSA_size as well */ + size_t ecsize = ECDSA_size(ctx->ec); + + if (sig == NULL) { + *siglen = ecsize; + return 1; + } + + if (sigsize < (size_t)ecsize) + return 0; + + if (ctx->mdsize != 0 && tbslen != ctx->mdsize) + return 0; + + ret = ossl_sm2_internal_sign(tbs, tbslen, sig, &sltmp, ctx->ec); + if (ret <= 0) + return 0; + + *siglen = sltmp; + return 1; +} + +static int sm2sig_verify(void *vpsm2ctx, const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx; + + if (ctx->mdsize != 0 && tbslen != ctx->mdsize) + return 0; + + return ossl_sm2_internal_verify(tbs, tbslen, sig, siglen, ctx->ec); +} + +static void free_md(PROV_SM2_CTX *ctx) +{ + EVP_MD_CTX_free(ctx->mdctx); + EVP_MD_free(ctx->md); + ctx->mdctx = NULL; + ctx->md = NULL; +} + +static int sm2sig_digest_signverify_init(void *vpsm2ctx, const char *mdname, + void *ec, const OSSL_PARAM params[]) +{ + PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx; + int md_nid; + WPACKET pkt; + int ret = 0; + + if (!sm2sig_signature_init(vpsm2ctx, ec, params) + || !sm2sig_set_mdname(ctx, mdname)) + return ret; + + if (ctx->mdctx == NULL) { + ctx->mdctx = EVP_MD_CTX_new(); + if (ctx->mdctx == NULL) + goto error; + } + + md_nid = EVP_MD_get_type(ctx->md); + + /* + * We do not care about DER writing errors. + * All it really means is that for some reason, there's no + * AlgorithmIdentifier to be had, but the operation itself is + * still valid, just as long as it's not used to construct + * anything that needs an AlgorithmIdentifier. + */ + ctx->aid_len = 0; + if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf)) + && ossl_DER_w_algorithmIdentifier_SM2_with_MD(&pkt, -1, ctx->ec, md_nid) + && WPACKET_finish(&pkt)) { + WPACKET_get_total_written(&pkt, &ctx->aid_len); + ctx->aid = WPACKET_get_curr(&pkt); + } + WPACKET_cleanup(&pkt); + + if (!EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params)) + goto error; + + ctx->flag_compute_z_digest = 1; + + ret = 1; + + error: + return ret; +} + +static int sm2sig_compute_z_digest(PROV_SM2_CTX *ctx) +{ + uint8_t *z = NULL; + int ret = 1; + + if (ctx->flag_compute_z_digest) { + /* Only do this once */ + ctx->flag_compute_z_digest = 0; + + if ((z = OPENSSL_zalloc(ctx->mdsize)) == NULL + /* get hashed prefix 'z' of tbs message */ + || !ossl_sm2_compute_z_digest(z, ctx->md, ctx->id, ctx->id_len, + ctx->ec) + || !EVP_DigestUpdate(ctx->mdctx, z, ctx->mdsize)) + ret = 0; + OPENSSL_free(z); + } + + return ret; +} + +int sm2sig_digest_signverify_update(void *vpsm2ctx, const unsigned char *data, + size_t datalen) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + + if (psm2ctx == NULL || psm2ctx->mdctx == NULL) + return 0; + + return sm2sig_compute_z_digest(psm2ctx) + && EVP_DigestUpdate(psm2ctx->mdctx, data, datalen); +} + +int sm2sig_digest_sign_final(void *vpsm2ctx, unsigned char *sig, size_t *siglen, + size_t sigsize) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (psm2ctx == NULL || psm2ctx->mdctx == NULL) + return 0; + + /* + * If sig is NULL then we're just finding out the sig size. Other fields + * are ignored. Defer to sm2sig_sign. + */ + if (sig != NULL) { + if (!(sm2sig_compute_z_digest(psm2ctx) + && EVP_DigestFinal_ex(psm2ctx->mdctx, digest, &dlen))) + return 0; + } + + return sm2sig_sign(vpsm2ctx, sig, siglen, sigsize, digest, (size_t)dlen); +} + + +int sm2sig_digest_verify_final(void *vpsm2ctx, const unsigned char *sig, + size_t siglen) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (psm2ctx == NULL + || psm2ctx->mdctx == NULL + || EVP_MD_get_size(psm2ctx->md) > (int)sizeof(digest)) + return 0; + + if (!(sm2sig_compute_z_digest(psm2ctx) + && EVP_DigestFinal_ex(psm2ctx->mdctx, digest, &dlen))) + return 0; + + return sm2sig_verify(vpsm2ctx, sig, siglen, digest, (size_t)dlen); +} + +static void sm2sig_freectx(void *vpsm2ctx) +{ + PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx; + + free_md(ctx); + EC_KEY_free(ctx->ec); + OPENSSL_free(ctx->id); + OPENSSL_free(ctx); +} + +static void *sm2sig_dupctx(void *vpsm2ctx) +{ + PROV_SM2_CTX *srcctx = (PROV_SM2_CTX *)vpsm2ctx; + PROV_SM2_CTX *dstctx; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + if (dstctx == NULL) + return NULL; + + *dstctx = *srcctx; + dstctx->ec = NULL; + dstctx->md = NULL; + dstctx->mdctx = NULL; + + if (srcctx->ec != NULL && !EC_KEY_up_ref(srcctx->ec)) + goto err; + dstctx->ec = srcctx->ec; + + if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md)) + goto err; + dstctx->md = srcctx->md; + + if (srcctx->mdctx != NULL) { + dstctx->mdctx = EVP_MD_CTX_new(); + if (dstctx->mdctx == NULL + || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx)) + goto err; + } + + if (srcctx->id != NULL) { + dstctx->id = OPENSSL_malloc(srcctx->id_len); + if (dstctx->id == NULL) + goto err; + dstctx->id_len = srcctx->id_len; + memcpy(dstctx->id, srcctx->id, srcctx->id_len); + } + + return dstctx; + err: + sm2sig_freectx(dstctx); + return NULL; +} + +static int sm2sig_get_ctx_params(void *vpsm2ctx, OSSL_PARAM *params) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + OSSL_PARAM *p; + + if (psm2ctx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + if (p != NULL + && !OSSL_PARAM_set_octet_string(p, psm2ctx->aid, psm2ctx->aid_len)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, psm2ctx->mdsize)) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, psm2ctx->md == NULL + ? psm2ctx->mdname + : EVP_MD_get0_name(psm2ctx->md))) + return 0; + + return 1; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *sm2sig_gettable_ctx_params(ossl_unused void *vpsm2ctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int sm2sig_set_ctx_params(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + const OSSL_PARAM *p; + size_t mdsize; + + if (psm2ctx == NULL) + return 0; + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DIST_ID); + if (p != NULL) { + void *tmp_id = NULL; + size_t tmp_idlen = 0; + + /* + * If the 'z' digest has already been computed, the ID is set too late + */ + if (!psm2ctx->flag_compute_z_digest) + return 0; + + if (p->data_size != 0 + && !OSSL_PARAM_get_octet_string(p, &tmp_id, 0, &tmp_idlen)) + return 0; + OPENSSL_free(psm2ctx->id); + psm2ctx->id = tmp_id; + psm2ctx->id_len = tmp_idlen; + } + + /* + * The following code checks that the size is the same as the SM3 digest + * size returning an error otherwise. + * If there is ever any different digest algorithm allowed with SM2 + * this needs to be adjusted accordingly. + */ + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (p != NULL && (!OSSL_PARAM_get_size_t(p, &mdsize) + || mdsize != psm2ctx->mdsize)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL) { + char *mdname = NULL; + + if (!OSSL_PARAM_get_utf8_string(p, &mdname, 0)) + return 0; + if (!sm2sig_set_mdname(psm2ctx, mdname)) { + OPENSSL_free(mdname); + return 0; + } + OPENSSL_free(mdname); + } + + return 1; +} + +static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_DIST_ID, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *sm2sig_settable_ctx_params(ossl_unused void *vpsm2ctx, + ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +static int sm2sig_get_ctx_md_params(void *vpsm2ctx, OSSL_PARAM *params) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + + if (psm2ctx->mdctx == NULL) + return 0; + + return EVP_MD_CTX_get_params(psm2ctx->mdctx, params); +} + +static const OSSL_PARAM *sm2sig_gettable_ctx_md_params(void *vpsm2ctx) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + + if (psm2ctx->md == NULL) + return 0; + + return EVP_MD_gettable_ctx_params(psm2ctx->md); +} + +static int sm2sig_set_ctx_md_params(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + + if (psm2ctx->mdctx == NULL) + return 0; + + return EVP_MD_CTX_set_params(psm2ctx->mdctx, params); +} + +static const OSSL_PARAM *sm2sig_settable_ctx_md_params(void *vpsm2ctx) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + + if (psm2ctx->md == NULL) + return 0; + + return EVP_MD_settable_ctx_params(psm2ctx->md); +} + +const OSSL_DISPATCH ossl_sm2_signature_functions[] = { + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))sm2sig_newctx }, + { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))sm2sig_signature_init }, + { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))sm2sig_sign }, + { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))sm2sig_signature_init }, + { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))sm2sig_verify }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, + (void (*)(void))sm2sig_digest_signverify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, + (void (*)(void))sm2sig_digest_signverify_update }, + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, + (void (*)(void))sm2sig_digest_sign_final }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, + (void (*)(void))sm2sig_digest_signverify_init }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE, + (void (*)(void))sm2sig_digest_signverify_update }, + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL, + (void (*)(void))sm2sig_digest_verify_final }, + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))sm2sig_freectx }, + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))sm2sig_dupctx }, + { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))sm2sig_get_ctx_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, + (void (*)(void))sm2sig_gettable_ctx_params }, + { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))sm2sig_set_ctx_params }, + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, + (void (*)(void))sm2sig_settable_ctx_params }, + { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS, + (void (*)(void))sm2sig_get_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS, + (void (*)(void))sm2sig_gettable_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS, + (void (*)(void))sm2sig_set_ctx_md_params }, + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS, + (void (*)(void))sm2sig_settable_ctx_md_params }, + { 0, NULL } +}; diff --git a/providers/implementations/storemgmt/build.info b/providers/implementations/storemgmt/build.info new file mode 100644 index 000000000000..8e6445a4e7cf --- /dev/null +++ b/providers/implementations/storemgmt/build.info @@ -0,0 +1,6 @@ +# We make separate GOAL variables for each algorithm, to make it easy to +# switch each to the Legacy provider when needed. + +$STORE_GOAL=../../libdefault.a + +SOURCE[$STORE_GOAL]=file_store.c file_store_any2obj.c diff --git a/providers/implementations/storemgmt/file_store.c b/providers/implementations/storemgmt/file_store.c new file mode 100644 index 000000000000..6d6312659bea --- /dev/null +++ b/providers/implementations/storemgmt/file_store.c @@ -0,0 +1,790 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* This file has quite some overlap with engines/e_loader_attic.c */ + +#include <string.h> +#include <sys/stat.h> +#include <ctype.h> /* isdigit */ +#include <assert.h> + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/params.h> +#include <openssl/decoder.h> +#include <openssl/proverr.h> +#include <openssl/store.h> /* The OSSL_STORE_INFO type numbers */ +#include "internal/cryptlib.h" +#include "internal/o_dir.h" +#include "crypto/decoder.h" +#include "crypto/ctype.h" /* ossl_isdigit() */ +#include "prov/implementations.h" +#include "prov/bio.h" +#include "file_store_local.h" + +DEFINE_STACK_OF(OSSL_STORE_INFO) + +#ifdef _WIN32 +# define stat _stat +#endif + +#ifndef S_ISDIR +# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) +#endif + +static OSSL_FUNC_store_open_fn file_open; +static OSSL_FUNC_store_attach_fn file_attach; +static OSSL_FUNC_store_settable_ctx_params_fn file_settable_ctx_params; +static OSSL_FUNC_store_set_ctx_params_fn file_set_ctx_params; +static OSSL_FUNC_store_load_fn file_load; +static OSSL_FUNC_store_eof_fn file_eof; +static OSSL_FUNC_store_close_fn file_close; + +/* + * This implementation makes full use of OSSL_DECODER, and then some. + * It uses its own internal decoder implementation that reads DER and + * passes that on to the data callback; this decoder is created with + * internal OpenSSL functions, thereby bypassing the need for a surrounding + * provider. This is ok, since this is a local decoder, not meant for + * public consumption. It also uses the libcrypto internal decoder + * setup function ossl_decoder_ctx_setup_for_pkey(), to allow the + * last resort decoder to be added first (and thereby be executed last). + * Finally, it sets up its own construct and cleanup functions. + * + * Essentially, that makes this implementation a kind of glorified decoder. + */ + +struct file_ctx_st { + void *provctx; + char *uri; /* The URI we currently try to load */ + enum { + IS_FILE = 0, /* Read file and pass results */ + IS_DIR /* Pass directory entry names */ + } type; + + union { + /* Used with |IS_FILE| */ + struct { + BIO *file; + + OSSL_DECODER_CTX *decoderctx; + char *input_type; + char *propq; /* The properties we got as a parameter */ + } file; + + /* Used with |IS_DIR| */ + struct { + OPENSSL_DIR_CTX *ctx; + int end_reached; + + /* + * When a search expression is given, these are filled in. + * |search_name| contains the file basename to look for. + * The string is exactly 8 characters long. + */ + char search_name[9]; + + /* + * The directory reading utility we have combines opening with + * reading the first name. To make sure we can detect the end + * at the right time, we read early and cache the name. + */ + const char *last_entry; + int last_errno; + } dir; + } _; + + /* Expected object type. May be unspecified */ + int expected_type; +}; + +static void free_file_ctx(struct file_ctx_st *ctx) +{ + if (ctx == NULL) + return; + + OPENSSL_free(ctx->uri); + if (ctx->type != IS_DIR) { + OSSL_DECODER_CTX_free(ctx->_.file.decoderctx); + OPENSSL_free(ctx->_.file.propq); + OPENSSL_free(ctx->_.file.input_type); + } + OPENSSL_free(ctx); +} + +static struct file_ctx_st *new_file_ctx(int type, const char *uri, + void *provctx) +{ + struct file_ctx_st *ctx = NULL; + + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL + && (uri == NULL || (ctx->uri = OPENSSL_strdup(uri)) != NULL)) { + ctx->type = type; + ctx->provctx = provctx; + return ctx; + } + free_file_ctx(ctx); + return NULL; +} + +static OSSL_DECODER_CONSTRUCT file_load_construct; +static OSSL_DECODER_CLEANUP file_load_cleanup; + +/*- + * Opening / attaching streams and directories + * ------------------------------------------- + */ + +/* + * Function to service both file_open() and file_attach() + * + * + */ +static struct file_ctx_st *file_open_stream(BIO *source, const char *uri, + void *provctx) +{ + struct file_ctx_st *ctx; + + if ((ctx = new_file_ctx(IS_FILE, uri, provctx)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + ctx->_.file.file = source; + + return ctx; + err: + free_file_ctx(ctx); + return NULL; +} + +static void *file_open_dir(const char *path, const char *uri, void *provctx) +{ + struct file_ctx_st *ctx; + + if ((ctx = new_file_ctx(IS_DIR, uri, provctx)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, path); + ctx->_.dir.last_errno = errno; + if (ctx->_.dir.last_entry == NULL) { + if (ctx->_.dir.last_errno != 0) { + ERR_raise_data(ERR_LIB_SYS, ctx->_.dir.last_errno, + "Calling OPENSSL_DIR_read(\"%s\")", path); + goto err; + } + ctx->_.dir.end_reached = 1; + } + return ctx; + err: + file_close(ctx); + return NULL; +} + +static void *file_open(void *provctx, const char *uri) +{ + struct file_ctx_st *ctx = NULL; + struct stat st; + struct { + const char *path; + unsigned int check_absolute:1; + } path_data[2]; + size_t path_data_n = 0, i; + const char *path; + BIO *bio; + + ERR_set_mark(); + + /* + * First step, just take the URI as is. + */ + path_data[path_data_n].check_absolute = 0; + path_data[path_data_n++].path = uri; + + /* + * Second step, if the URI appears to start with the 'file' scheme, + * extract the path and make that the second path to check. + * There's a special case if the URI also contains an authority, then + * the full URI shouldn't be used as a path anywhere. + */ + if (OPENSSL_strncasecmp(uri, "file:", 5) == 0) { + const char *p = &uri[5]; + + if (strncmp(&uri[5], "//", 2) == 0) { + path_data_n--; /* Invalidate using the full URI */ + if (OPENSSL_strncasecmp(&uri[7], "localhost/", 10) == 0) { + p = &uri[16]; + } else if (uri[7] == '/') { + p = &uri[7]; + } else { + ERR_clear_last_mark(); + ERR_raise(ERR_LIB_PROV, PROV_R_URI_AUTHORITY_UNSUPPORTED); + return NULL; + } + } + + path_data[path_data_n].check_absolute = 1; +#ifdef _WIN32 + /* Windows file: URIs with a drive letter start with a / */ + if (p[0] == '/' && p[2] == ':' && p[3] == '/') { + char c = tolower(p[1]); + + if (c >= 'a' && c <= 'z') { + p++; + /* We know it's absolute, so no need to check */ + path_data[path_data_n].check_absolute = 0; + } + } +#endif + path_data[path_data_n++].path = p; + } + + + for (i = 0, path = NULL; path == NULL && i < path_data_n; i++) { + /* + * If the scheme "file" was an explicit part of the URI, the path must + * be absolute. So says RFC 8089 + */ + if (path_data[i].check_absolute && path_data[i].path[0] != '/') { + ERR_clear_last_mark(); + ERR_raise_data(ERR_LIB_PROV, PROV_R_PATH_MUST_BE_ABSOLUTE, + "Given path=%s", path_data[i].path); + return NULL; + } + + if (stat(path_data[i].path, &st) < 0) { + ERR_raise_data(ERR_LIB_SYS, errno, + "calling stat(%s)", + path_data[i].path); + } else { + path = path_data[i].path; + } + } + if (path == NULL) { + ERR_clear_last_mark(); + return NULL; + } + + /* Successfully found a working path, clear possible collected errors */ + ERR_pop_to_mark(); + + if (S_ISDIR(st.st_mode)) + ctx = file_open_dir(path, uri, provctx); + else if ((bio = BIO_new_file(path, "rb")) == NULL + || (ctx = file_open_stream(bio, uri, provctx)) == NULL) + BIO_free_all(bio); + + return ctx; +} + +void *file_attach(void *provctx, OSSL_CORE_BIO *cin) +{ + struct file_ctx_st *ctx; + BIO *new_bio = ossl_bio_new_from_core_bio(provctx, cin); + + if (new_bio == NULL) + return NULL; + + ctx = file_open_stream(new_bio, NULL, provctx); + if (ctx == NULL) + BIO_free(new_bio); + return ctx; +} + +/*- + * Setting parameters + * ------------------ + */ + +static const OSSL_PARAM *file_settable_ctx_params(void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_int(OSSL_STORE_PARAM_EXPECT, NULL), + OSSL_PARAM_octet_string(OSSL_STORE_PARAM_SUBJECT, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_INPUT_TYPE, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int file_set_ctx_params(void *loaderctx, const OSSL_PARAM params[]) +{ + struct file_ctx_st *ctx = loaderctx; + const OSSL_PARAM *p; + + if (params == NULL) + return 1; + + if (ctx->type != IS_DIR) { + /* these parameters are ignored for directories */ + p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_PROPERTIES); + if (p != NULL) { + OPENSSL_free(ctx->_.file.propq); + ctx->_.file.propq = NULL; + if (!OSSL_PARAM_get_utf8_string(p, &ctx->_.file.propq, 0)) + return 0; + } + p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_INPUT_TYPE); + if (p != NULL) { + OPENSSL_free(ctx->_.file.input_type); + ctx->_.file.input_type = NULL; + if (!OSSL_PARAM_get_utf8_string(p, &ctx->_.file.input_type, 0)) + return 0; + } + } + p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_EXPECT); + if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->expected_type)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SUBJECT); + if (p != NULL) { + const unsigned char *der = NULL; + size_t der_len = 0; + X509_NAME *x509_name; + unsigned long hash; + int ok; + + if (ctx->type != IS_DIR) { + ERR_raise(ERR_LIB_PROV, + PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES); + return 0; + } + + if (!OSSL_PARAM_get_octet_string_ptr(p, (const void **)&der, &der_len) + || (x509_name = d2i_X509_NAME(NULL, &der, der_len)) == NULL) + return 0; + hash = X509_NAME_hash_ex(x509_name, + ossl_prov_ctx_get0_libctx(ctx->provctx), NULL, + &ok); + BIO_snprintf(ctx->_.dir.search_name, sizeof(ctx->_.dir.search_name), + "%08lx", hash); + X509_NAME_free(x509_name); + if (ok == 0) + return 0; + } + return 1; +} + +/*- + * Loading an object from a stream + * ------------------------------- + */ + +struct file_load_data_st { + OSSL_CALLBACK *object_cb; + void *object_cbarg; +}; + +static int file_load_construct(OSSL_DECODER_INSTANCE *decoder_inst, + const OSSL_PARAM *params, void *construct_data) +{ + struct file_load_data_st *data = construct_data; + + /* + * At some point, we may find it justifiable to recognise PKCS#12 and + * handle it specially here, making |file_load()| return pass its + * contents one piece at ta time, like |e_loader_attic.c| does. + * + * However, that currently means parsing them out, which converts the + * DER encoded PKCS#12 into a bunch of EVP_PKEYs and X509s, just to + * have to re-encode them into DER to create an object abstraction for + * each of them. + * It's much simpler (less churn) to pass on the object abstraction we + * get to the load_result callback and leave it to that one to do the + * work. If that's libcrypto code, we know that it has much better + * possibilities to handle the EVP_PKEYs and X509s without the extra + * churn. + */ + + return data->object_cb(params, data->object_cbarg); +} + +void file_load_cleanup(void *construct_data) +{ + /* Nothing to do */ +} + +static int file_setup_decoders(struct file_ctx_st *ctx) +{ + OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(ctx->provctx); + const OSSL_ALGORITHM *to_algo = NULL; + int ok = 0; + + /* Setup for this session, so only if not already done */ + if (ctx->_.file.decoderctx == NULL) { + if ((ctx->_.file.decoderctx = OSSL_DECODER_CTX_new()) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Make sure the input type is set */ + if (!OSSL_DECODER_CTX_set_input_type(ctx->_.file.decoderctx, + ctx->_.file.input_type)) { + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + + /* + * Where applicable, set the outermost structure name. + * The goal is to avoid the STORE object types that are + * potentially password protected but aren't interesting + * for this load. + */ + switch (ctx->expected_type) { + case OSSL_STORE_INFO_CERT: + if (!OSSL_DECODER_CTX_set_input_structure(ctx->_.file.decoderctx, + "Certificate")) { + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + break; + case OSSL_STORE_INFO_CRL: + if (!OSSL_DECODER_CTX_set_input_structure(ctx->_.file.decoderctx, + "CertificateList")) { + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + break; + default: + break; + } + + for (to_algo = ossl_any_to_obj_algorithm; + to_algo->algorithm_names != NULL; + to_algo++) { + OSSL_DECODER *to_obj = NULL; + OSSL_DECODER_INSTANCE *to_obj_inst = NULL; + + /* + * Create the internal last resort decoder implementation + * together with a "decoder instance". + * The decoder doesn't need any identification or to be + * attached to any provider, since it's only used locally. + */ + to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL); + if (to_obj != NULL) + to_obj_inst = ossl_decoder_instance_new(to_obj, ctx->provctx); + OSSL_DECODER_free(to_obj); + if (to_obj_inst == NULL) + goto err; + + if (!ossl_decoder_ctx_add_decoder_inst(ctx->_.file.decoderctx, + to_obj_inst)) { + ossl_decoder_instance_free(to_obj_inst); + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + } + /* Add on the usual extra decoders */ + if (!OSSL_DECODER_CTX_add_extra(ctx->_.file.decoderctx, + libctx, ctx->_.file.propq)) { + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + + /* + * Then install our constructor hooks, which just passes decoded + * data to the load callback + */ + if (!OSSL_DECODER_CTX_set_construct(ctx->_.file.decoderctx, + file_load_construct) + || !OSSL_DECODER_CTX_set_cleanup(ctx->_.file.decoderctx, + file_load_cleanup)) { + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + } + + ok = 1; + err: + return ok; +} + +static int file_load_file(struct file_ctx_st *ctx, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct file_load_data_st data; + int ret, err; + + /* Setup the decoders (one time shot per session */ + + if (!file_setup_decoders(ctx)) + return 0; + + /* Setup for this object */ + + data.object_cb = object_cb; + data.object_cbarg = object_cbarg; + OSSL_DECODER_CTX_set_construct_data(ctx->_.file.decoderctx, &data); + OSSL_DECODER_CTX_set_passphrase_cb(ctx->_.file.decoderctx, pw_cb, pw_cbarg); + + /* Launch */ + + ERR_set_mark(); + ret = OSSL_DECODER_from_bio(ctx->_.file.decoderctx, ctx->_.file.file); + if (BIO_eof(ctx->_.file.file) + && ((err = ERR_peek_last_error()) != 0) + && ERR_GET_LIB(err) == ERR_LIB_OSSL_DECODER + && ERR_GET_REASON(err) == ERR_R_UNSUPPORTED) + ERR_pop_to_mark(); + else + ERR_clear_last_mark(); + return ret; +} + +/*- + * Loading a name object from a directory + * -------------------------------------- + */ + +static char *file_name_to_uri(struct file_ctx_st *ctx, const char *name) +{ + char *data = NULL; + + assert(name != NULL); + { + const char *pathsep = ossl_ends_with_dirsep(ctx->uri) ? "" : "/"; + long calculated_length = strlen(ctx->uri) + strlen(pathsep) + + strlen(name) + 1 /* \0 */; + + data = OPENSSL_zalloc(calculated_length); + if (data == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + OPENSSL_strlcat(data, ctx->uri, calculated_length); + OPENSSL_strlcat(data, pathsep, calculated_length); + OPENSSL_strlcat(data, name, calculated_length); + } + return data; +} + +static int file_name_check(struct file_ctx_st *ctx, const char *name) +{ + const char *p = NULL; + size_t len = strlen(ctx->_.dir.search_name); + + /* If there are no search criteria, all names are accepted */ + if (ctx->_.dir.search_name[0] == '\0') + return 1; + + /* If the expected type isn't supported, no name is accepted */ + if (ctx->expected_type != 0 + && ctx->expected_type != OSSL_STORE_INFO_CERT + && ctx->expected_type != OSSL_STORE_INFO_CRL) + return 0; + + /* + * First, check the basename + */ + if (OPENSSL_strncasecmp(name, ctx->_.dir.search_name, len) != 0 + || name[len] != '.') + return 0; + p = &name[len + 1]; + + /* + * Then, if the expected type is a CRL, check that the extension starts + * with 'r' + */ + if (*p == 'r') { + p++; + if (ctx->expected_type != 0 + && ctx->expected_type != OSSL_STORE_INFO_CRL) + return 0; + } else if (ctx->expected_type == OSSL_STORE_INFO_CRL) { + return 0; + } + + /* + * Last, check that the rest of the extension is a decimal number, at + * least one digit long. + */ + if (!isdigit(*p)) + return 0; + while (isdigit(*p)) + p++; + +#ifdef __VMS + /* + * One extra step here, check for a possible generation number. + */ + if (*p == ';') + for (p++; *p != '\0'; p++) + if (!ossl_isdigit(*p)) + break; +#endif + + /* + * If we've reached the end of the string at this point, we've successfully + * found a fitting file name. + */ + return *p == '\0'; +} + +static int file_load_dir_entry(struct file_ctx_st *ctx, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + /* Prepare as much as possible in advance */ + static const int object_type = OSSL_OBJECT_NAME; + OSSL_PARAM object[] = { + OSSL_PARAM_int(OSSL_OBJECT_PARAM_TYPE, (int *)&object_type), + OSSL_PARAM_utf8_string(OSSL_OBJECT_PARAM_DATA, NULL, 0), + OSSL_PARAM_END + }; + char *newname = NULL; + int ok; + + /* Loop until we get an error or until we have a suitable name */ + do { + if (ctx->_.dir.last_entry == NULL) { + if (!ctx->_.dir.end_reached) { + assert(ctx->_.dir.last_errno != 0); + ERR_raise(ERR_LIB_SYS, ctx->_.dir.last_errno); + } + /* file_eof() will tell if EOF was reached */ + return 0; + } + + /* flag acceptable names */ + if (ctx->_.dir.last_entry[0] != '.' + && file_name_check(ctx, ctx->_.dir.last_entry)) { + + /* If we can't allocate the new name, we fail */ + if ((newname = + file_name_to_uri(ctx, ctx->_.dir.last_entry)) == NULL) + return 0; + } + + /* + * On the first call (with a NULL context), OPENSSL_DIR_read() + * cares about the second argument. On the following calls, it + * only cares that it isn't NULL. Therefore, we can safely give + * it our URI here. + */ + ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, ctx->uri); + ctx->_.dir.last_errno = errno; + if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0) + ctx->_.dir.end_reached = 1; + } while (newname == NULL); + + object[1].data = newname; + object[1].data_size = strlen(newname); + ok = object_cb(object, object_cbarg); + OPENSSL_free(newname); + return ok; +} + +/*- + * Loading, local dispatcher + * ------------------------- + */ + +static int file_load(void *loaderctx, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct file_ctx_st *ctx = loaderctx; + + switch (ctx->type) { + case IS_FILE: + return file_load_file(ctx, object_cb, object_cbarg, pw_cb, pw_cbarg); + case IS_DIR: + return + file_load_dir_entry(ctx, object_cb, object_cbarg, pw_cb, pw_cbarg); + default: + break; + } + + /* ctx->type has an unexpected value */ + assert(0); + return 0; +} + +/*- + * Eof detection and closing + * ------------------------- + */ + +static int file_eof(void *loaderctx) +{ + struct file_ctx_st *ctx = loaderctx; + + switch (ctx->type) { + case IS_DIR: + return ctx->_.dir.end_reached; + case IS_FILE: + /* + * BIO_pending() checks any filter BIO. + * BIO_eof() checks the source BIO. + */ + return !BIO_pending(ctx->_.file.file) + && BIO_eof(ctx->_.file.file); + } + + /* ctx->type has an unexpected value */ + assert(0); + return 1; +} + +static int file_close_dir(struct file_ctx_st *ctx) +{ + if (ctx->_.dir.ctx != NULL) + OPENSSL_DIR_end(&ctx->_.dir.ctx); + free_file_ctx(ctx); + return 1; +} + +static int file_close_stream(struct file_ctx_st *ctx) +{ + /* + * This frees either the provider BIO filter (for file_attach()) OR + * the allocated file BIO (for file_open()). + */ + BIO_free(ctx->_.file.file); + ctx->_.file.file = NULL; + + free_file_ctx(ctx); + return 1; +} + +static int file_close(void *loaderctx) +{ + struct file_ctx_st *ctx = loaderctx; + + switch (ctx->type) { + case IS_DIR: + return file_close_dir(ctx); + case IS_FILE: + return file_close_stream(ctx); + } + + /* ctx->type has an unexpected value */ + assert(0); + return 1; +} + +const OSSL_DISPATCH ossl_file_store_functions[] = { + { OSSL_FUNC_STORE_OPEN, (void (*)(void))file_open }, + { OSSL_FUNC_STORE_ATTACH, (void (*)(void))file_attach }, + { OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS, + (void (*)(void))file_settable_ctx_params }, + { OSSL_FUNC_STORE_SET_CTX_PARAMS, (void (*)(void))file_set_ctx_params }, + { OSSL_FUNC_STORE_LOAD, (void (*)(void))file_load }, + { OSSL_FUNC_STORE_EOF, (void (*)(void))file_eof }, + { OSSL_FUNC_STORE_CLOSE, (void (*)(void))file_close }, + { 0, NULL }, +}; diff --git a/providers/implementations/storemgmt/file_store_any2obj.c b/providers/implementations/storemgmt/file_store_any2obj.c new file mode 100644 index 000000000000..28601683bf6e --- /dev/null +++ b/providers/implementations/storemgmt/file_store_any2obj.c @@ -0,0 +1,261 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This is a decoder that's completely internal to the 'file:' store + * implementation. Only code in file_store.c know about this one. Because + * of this close relationship, we can cut certain corners, such as making + * assumptions about the "provider context", which is currently simply the + * provider context that the file_store.c code operates within. + * + * All this does is to read known binary encodings (currently: DER, MSBLOB, + * PVK) from the input if it can, and passes it on to the data callback as + * an object abstraction, leaving it to the callback to figure out what it + * actually is. + * + * This MUST be made the last decoder in a chain, leaving it to other more + * specialized decoders to recognise and process their stuff first. + */ + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/bio.h> +#include <openssl/buffer.h> +#include <openssl/err.h> +#include <openssl/asn1err.h> +#include <openssl/params.h> +#include "internal/asn1.h" +#include "crypto/pem.h" /* For internal PVK and "blob" headers */ +#include "prov/bio.h" +#include "file_store_local.h" + +/* + * newctx and freectx are not strictly necessary. However, the method creator, + * ossl_decoder_from_algorithm(), demands that they exist, so we make sure to + * oblige. + */ + +static OSSL_FUNC_decoder_newctx_fn any2obj_newctx; +static OSSL_FUNC_decoder_freectx_fn any2obj_freectx; + +static void *any2obj_newctx(void *provctx) +{ + return provctx; +} + +static void any2obj_freectx(void *vctx) +{ +} + +static int any2obj_decode_final(void *provctx, int objtype, BUF_MEM *mem, + OSSL_CALLBACK *data_cb, void *data_cbarg) +{ + /* + * 1 indicates that we successfully decoded something, or not at all. + * Ending up "empty handed" is not an error. + */ + int ok = 1; + + if (mem != NULL) { + OSSL_PARAM params[3]; + + params[0] = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); + params[1] = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, + mem->data, mem->length); + params[2] = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + BUF_MEM_free(mem); + } + return ok; +} + +static OSSL_FUNC_decoder_decode_fn der2obj_decode; +static int der2obj_decode(void *provctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + BIO *in = ossl_bio_new_from_core_bio(provctx, cin); + BUF_MEM *mem = NULL; + int ok; + + if (in == NULL) + return 0; + + ERR_set_mark(); + ok = (asn1_d2i_read_bio(in, &mem) >= 0); + ERR_pop_to_mark(); + if (!ok && mem != NULL) { + BUF_MEM_free(mem); + mem = NULL; + } + BIO_free(in); + + /* any2obj_decode_final() frees |mem| for us */ + return any2obj_decode_final(provctx, OSSL_OBJECT_UNKNOWN, mem, + data_cb, data_cbarg); +} + +static OSSL_FUNC_decoder_decode_fn msblob2obj_decode; +static int msblob2obj_decode(void *provctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + BIO *in = ossl_bio_new_from_core_bio(provctx, cin); + BUF_MEM *mem = NULL; + size_t mem_len = 0, mem_want; + const unsigned char *p; + unsigned int bitlen, magic; + int isdss = -1; + int ispub = -1; + int ok = 0; + + if (in == NULL) + goto err; + + mem_want = 16; /* The size of the MSBLOB header */ + if ((mem = BUF_MEM_new()) == NULL + || !BUF_MEM_grow(mem, mem_want)) { + ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + + ERR_set_mark(); + ok = BIO_read(in, &mem->data[0], mem_want) == (int)mem_want; + mem_len += mem_want; + ERR_pop_to_mark(); + if (!ok) + goto next; + + + ERR_set_mark(); + p = (unsigned char *)&mem->data[0]; + ok = ossl_do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) > 0; + ERR_pop_to_mark(); + if (!ok) + goto next; + + ok = 0; + mem_want = ossl_blob_length(bitlen, isdss, ispub); + if (!BUF_MEM_grow(mem, mem_len + mem_want)) { + ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + + ERR_set_mark(); + ok = BIO_read(in, &mem->data[mem_len], mem_want) == (int)mem_want; + mem_len += mem_want; + ERR_pop_to_mark(); + + next: + /* Free resources we no longer need. */ + BIO_free(in); + if (!ok && mem != NULL) { + BUF_MEM_free(mem); + mem = NULL; + } + + /* any2obj_decode_final() frees |mem| for us */ + return any2obj_decode_final(provctx, OSSL_OBJECT_PKEY, mem, + data_cb, data_cbarg); + + err: + BIO_free(in); + BUF_MEM_free(mem); + return 0; +} + +static OSSL_FUNC_decoder_decode_fn pvk2obj_decode; +static int pvk2obj_decode(void *provctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + BIO *in = ossl_bio_new_from_core_bio(provctx, cin); + BUF_MEM *mem = NULL; + size_t mem_len = 0, mem_want; + const unsigned char *p; + unsigned int saltlen, keylen; + int ok = 0; + + if (in == NULL) + goto err; + + mem_want = 24; /* The size of the PVK header */ + if ((mem = BUF_MEM_new()) == NULL + || !BUF_MEM_grow(mem, mem_want)) { + ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + + ERR_set_mark(); + ok = BIO_read(in, &mem->data[0], mem_want) == (int)mem_want; + mem_len += mem_want; + ERR_pop_to_mark(); + if (!ok) + goto next; + + + ERR_set_mark(); + p = (unsigned char *)&mem->data[0]; + ok = ossl_do_PVK_header(&p, 24, 0, &saltlen, &keylen) > 0; + ERR_pop_to_mark(); + if (!ok) + goto next; + + ok = 0; + mem_want = saltlen + keylen; + if (!BUF_MEM_grow(mem, mem_len + mem_want)) { + ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + + ERR_set_mark(); + ok = BIO_read(in, &mem->data[mem_len], mem_want) == (int)mem_want; + mem_len += mem_want; + ERR_pop_to_mark(); + + next: + /* Free resources we no longer need. */ + BIO_free(in); + if (!ok && mem != NULL) { + BUF_MEM_free(mem); + mem = NULL; + } + + /* any2obj_decode_final() frees |mem| for us */ + return any2obj_decode_final(provctx, OSSL_OBJECT_PKEY, mem, + data_cb, data_cbarg); + + err: + BIO_free(in); + BUF_MEM_free(mem); + return 0; +} + +#define MAKE_DECODER(fromtype, objtype) \ + static const OSSL_DISPATCH fromtype##_to_obj_decoder_functions[] = { \ + { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))any2obj_newctx }, \ + { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))any2obj_freectx }, \ + { OSSL_FUNC_DECODER_DECODE, (void (*)(void))fromtype##2obj_decode }, \ + { 0, NULL } \ + } + +MAKE_DECODER(der, OSSL_OBJECT_UNKNOWN); +MAKE_DECODER(msblob, OSSL_OBJECT_PKEY); +MAKE_DECODER(pvk, OSSL_OBJECT_PKEY); + +const OSSL_ALGORITHM ossl_any_to_obj_algorithm[] = { + { "obj", "input=DER", der_to_obj_decoder_functions }, + { "obj", "input=MSBLOB", msblob_to_obj_decoder_functions }, + { "obj", "input=PVK", pvk_to_obj_decoder_functions }, + { NULL, } +}; diff --git a/providers/implementations/storemgmt/file_store_local.h b/providers/implementations/storemgmt/file_store_local.h new file mode 100644 index 000000000000..b7d9e585163e --- /dev/null +++ b/providers/implementations/storemgmt/file_store_local.h @@ -0,0 +1,11 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +extern const OSSL_ALGORITHM ossl_any_to_obj_algorithm[]; + |
