From ce64d3eee06a64e78ea5be7e8f0dd7172aa78259 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 18 Sep 2020 09:55:16 +0100 Subject: [PATCH] Move SM2 asymmetric encryption to be available in the default provider Fixes #12908 Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/12913) --- include/openssl/core_names.h | 3 + providers/common/include/prov/provider_util.h | 8 + providers/common/provider_util.c | 12 +- providers/defltprov.c | 3 + .../implementations/asymciphers/build.info | 5 + .../implementations/asymciphers/sm2_enc.c | 225 ++++++++++++++++++ .../include/prov/implementations.h | 3 + 7 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 providers/implementations/asymciphers/sm2_enc.c diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index a8d4d51533..c9f2bfab5e 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -432,6 +432,9 @@ extern "C" { #define OSSL_SIGNATURE_PARAM_DIGEST_SIZE OSSL_PKEY_PARAM_DIGEST_SIZE /* Asym cipher parameters */ +#define OSSL_ASYM_CIPHER_PARAM_DIGEST OSSL_PKEY_PARAM_DIGEST +#define OSSL_ASYM_CIPHER_PARAM_PROPERTIES OSSL_PKEY_PARAM_PROPERTIES +#define OSSL_ASYM_CIPHER_PARAM_ENGINE OSSL_PKEY_PARAM_ENGINE #define OSSL_ASYM_CIPHER_PARAM_PAD_MODE OSSL_PKEY_PARAM_PAD_MODE #define OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST \ OSSL_PKEY_PARAM_MGF1_DIGEST diff --git a/providers/common/include/prov/provider_util.h b/providers/common/include/prov/provider_util.h index d964f832ad..83f6d63ed7 100644 --- a/providers/common/include/prov/provider_util.h +++ b/providers/common/include/prov/provider_util.h @@ -58,6 +58,14 @@ const EVP_CIPHER *ossl_prov_cipher_cipher(const PROV_CIPHER *pc); ENGINE *ossl_prov_cipher_engine(const PROV_CIPHER *pc); /* Digest functions */ + +/* + * Fetch a digest from the specified libctx using the provided mdname and + * propquery. Store the result in the PROV_DIGEST and return the fetched md. + */ +const EVP_MD *ossl_prov_digest_fetch(PROV_DIGEST *pd, OPENSSL_CTX *libctx, + const char *mdname, const char *propquery); + /* * Load a digest from the specified parameters with the specified context. * The params "properties", "engine" and "digest" are used to determine the diff --git a/providers/common/provider_util.c b/providers/common/provider_util.c index 4259d7167a..2e9fe8d5da 100644 --- a/providers/common/provider_util.c +++ b/providers/common/provider_util.c @@ -124,6 +124,15 @@ int ossl_prov_digest_copy(PROV_DIGEST *dst, const PROV_DIGEST *src) return 1; } +const EVP_MD *ossl_prov_digest_fetch(PROV_DIGEST *pd, OPENSSL_CTX *libctx, + const char *mdname, const char *propquery) +{ + EVP_MD_free(pd->alloc_md); + pd->md = pd->alloc_md = EVP_MD_fetch(libctx, mdname, propquery); + + return pd->md; +} + int ossl_prov_digest_load_from_params(PROV_DIGEST *pd, const OSSL_PARAM params[], OPENSSL_CTX *ctx) @@ -141,9 +150,8 @@ int ossl_prov_digest_load_from_params(PROV_DIGEST *pd, if (p->data_type != OSSL_PARAM_UTF8_STRING) return 0; - EVP_MD_free(pd->alloc_md); ERR_set_mark(); - pd->md = pd->alloc_md = EVP_MD_fetch(ctx, p->data, propquery); + ossl_prov_digest_fetch(pd, ctx, p->data, propquery); /* TODO legacy stuff, to be removed */ #ifndef FIPS_MODULE /* Inside the FIPS module, we don't support legacy digests */ if (pd->md == NULL) diff --git a/providers/defltprov.c b/providers/defltprov.c index 8564ddd5ca..dee48fb255 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -381,6 +381,9 @@ static const OSSL_ALGORITHM deflt_signature[] = { static const OSSL_ALGORITHM deflt_asym_cipher[] = { { "RSA:rsaEncryption", "provider=default", rsa_asym_cipher_functions }, +#ifndef OPENSSL_NO_SM2 + { "SM2", "provider=default", sm2_asym_cipher_functions }, +#endif { NULL, NULL, NULL } }; diff --git a/providers/implementations/asymciphers/build.info b/providers/implementations/asymciphers/build.info index b4033d8a7d..4b629d04ee 100644 --- a/providers/implementations/asymciphers/build.info +++ b/providers/implementations/asymciphers/build.info @@ -2,5 +2,10 @@ # switch each to the Legacy provider when needed. $RSA_GOAL=../../libimplementations.a +$SM2_GOAL=../../libimplementations.a SOURCE[$RSA_GOAL]=rsa_enc.c + +IF[{- !$disabled{"sm2"} -}] + SOURCE[$SM2_GOAL]=sm2_enc.c +ENDIF diff --git a/providers/implementations/asymciphers/sm2_enc.c b/providers/implementations/asymciphers/sm2_enc.c new file mode 100644 index 0000000000..4f2f64bb1a --- /dev/null +++ b/providers/implementations/asymciphers/sm2_enc.c @@ -0,0 +1,225 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include "prov/providercommonerr.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 { + OPENSSL_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_LIBRARY_CONTEXT_OF(provctx); + + return psm2ctx; +} + +static int sm2_init(void *vpsm2ctx, void *vkey) +{ + 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 1; +} + +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 (!sm2_ciphertext_size(psm2ctx->key, md, inlen, outlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + return 1; + } + + return 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 (!sm2_plaintext_size(psm2ctx->key, md, inlen, outlen)) + return 0; + return 1; + } + + return 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; + 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 || params == 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_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 *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 || params == NULL) + return 0; + + 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 *provctx) +{ + return known_settable_ctx_params; +} + +const OSSL_DISPATCH 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/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index b67b4c7361..dd45523ae9 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -307,6 +307,9 @@ extern const OSSL_DISPATCH sm2_signature_functions[]; /* Asym Cipher */ extern const OSSL_DISPATCH rsa_asym_cipher_functions[]; +#ifndef OPENSSL_NO_SM2 +extern const OSSL_DISPATCH sm2_asym_cipher_functions[]; +#endif /* Asym Key encapsulation */ extern const OSSL_DISPATCH rsa_asym_kem_functions[]; -- 2.39.2