The branch master has been updated via a48309cb5c58be8fa310608124925d4729664cf8 (commit) via bfb56a974d93908b5d6ede39655ece442ff7a755 (commit) via 989684227b669b5deb52ca05aa99f798fe0852e3 (commit) via fb2a6954fbfde3890deb572014f6d135808bf43b (commit) via ce64d3eee06a64e78ea5be7e8f0dd7172aa78259 (commit) from 7a032be7f293bd80e3fe18c5568cf382b0b79543 (commit)
- Log ----------------------------------------------------------------- commit a48309cb5c58be8fa310608124925d4729664cf8 Author: Matt Caswell <m...@openssl.org> Date: Fri Sep 18 12:10:21 2020 +0100 Document the provider side SM2 Asymmetric Cipher support Reviewed-by: Shane Lontis <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/12913) commit bfb56a974d93908b5d6ede39655ece442ff7a755 Author: Matt Caswell <m...@openssl.org> Date: Fri Sep 18 11:57:24 2020 +0100 Extend the SM2 asym cipher test Ensure we test getting and setting ctx params Reviewed-by: Shane Lontis <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/12913) commit 989684227b669b5deb52ca05aa99f798fe0852e3 Author: Matt Caswell <m...@openssl.org> Date: Fri Sep 18 11:06:34 2020 +0100 Remove some dead SM2 code Reviewed-by: Shane Lontis <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/12913) commit fb2a6954fbfde3890deb572014f6d135808bf43b Author: Matt Caswell <m...@openssl.org> Date: Fri Sep 18 10:41:58 2020 +0100 Clean up some SM2 related TODOs in the tests Now that we have full SM2 support, we can remove some TODOs from the tests. Reviewed-by: Shane Lontis <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/12913) commit ce64d3eee06a64e78ea5be7e8f0dd7172aa78259 Author: Matt Caswell <m...@openssl.org> Date: Fri Sep 18 09:55:16 2020 +0100 Move SM2 asymmetric encryption to be available in the default provider Fixes #12908 Reviewed-by: Shane Lontis <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/12913) ----------------------------------------------------------------------- Summary of changes: crypto/evp/pmeth_lib.c | 3 - crypto/sm2/build.info | 2 +- crypto/sm2/sm2_pmeth.c | 393 --------------------- doc/man7/EVP_ASYM_CIPHER-SM2.pod | 41 +++ doc/man7/{SM2.pod => EVP_PKEY-SM2.pod} | 5 +- doc/man7/OSSL_PROVIDER-default.pod | 2 + doc/man7/provider-asym_cipher.pod | 9 + include/crypto/evp.h | 1 - include/openssl/core_names.h | 3 + providers/common/include/prov/provider_util.h | 8 + providers/common/provider_util.c | 12 +- providers/defltprov.c | 3 + providers/implementations/asymciphers/build.info | 5 + providers/implementations/asymciphers/sm2_enc.c | 225 ++++++++++++ .../implementations/include/prov/implementations.h | 3 + test/evp_extra_test.c | 75 ++-- test/recipes/20-test_pkeyutl.t | 10 +- test/recipes/25-test_req.t | 18 +- 18 files changed, 370 insertions(+), 448 deletions(-) delete mode 100644 crypto/sm2/sm2_pmeth.c create mode 100644 doc/man7/EVP_ASYM_CIPHER-SM2.pod rename doc/man7/{SM2.pod => EVP_PKEY-SM2.pod} (94%) create mode 100644 providers/implementations/asymciphers/sm2_enc.c diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 26193cd644..656a0e065a 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -75,9 +75,6 @@ static pmeth_fn standard_methods[] = { ed25519_pkey_method, ed448_pkey_method, # endif -# ifndef OPENSSL_NO_SM2 - sm2_pkey_method, -# endif }; DECLARE_OBJ_BSEARCH_CMP_FN(const EVP_PKEY_METHOD *, pmeth_fn, pmeth_func); diff --git a/crypto/sm2/build.info b/crypto/sm2/build.info index be76d96d31..402a76cc5d 100644 --- a/crypto/sm2/build.info +++ b/crypto/sm2/build.info @@ -1,5 +1,5 @@ LIBS=../../libcrypto SOURCE[../../libcrypto]=\ - sm2_sign.c sm2_crypt.c sm2_err.c sm2_pmeth.c + sm2_sign.c sm2_crypt.c sm2_err.c diff --git a/crypto/sm2/sm2_pmeth.c b/crypto/sm2/sm2_pmeth.c deleted file mode 100644 index 32713a5ac4..0000000000 --- a/crypto/sm2/sm2_pmeth.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright 2006-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 - */ - -/* - * ECDSA low level APIs are deprecated for public use, but still ok for - * internal use. - */ -#include "internal/deprecated.h" - -#include "internal/cryptlib.h" -#include <openssl/asn1t.h> -#include <openssl/ec.h> -#include <openssl/evp.h> -#include "crypto/evp.h" -#include "crypto/sm2.h" -#include "crypto/sm2err.h" -#include "crypto/ec.h" - -/* EC pkey context structure */ - -typedef struct { - /* message digest */ - const EVP_MD *md; - /* Distinguishing Identifier, ISO/IEC 15946-3, FIPS 196 */ - uint8_t *id; - size_t id_len; - /* id_set indicates if the 'id' field is set (1) or not (0) */ - int id_set; -} SM2_PKEY_CTX; - -static int pkey_sm2_init(EVP_PKEY_CTX *ctx) -{ - SM2_PKEY_CTX *smctx; - - if ((smctx = OPENSSL_zalloc(sizeof(*smctx))) == NULL) { - SM2err(SM2_F_PKEY_SM2_INIT, ERR_R_MALLOC_FAILURE); - return 0; - } - - ctx->data = smctx; - return 1; -} - -static void pkey_sm2_cleanup(EVP_PKEY_CTX *ctx) -{ - SM2_PKEY_CTX *smctx = ctx->data; - - if (smctx != NULL) { - OPENSSL_free(smctx->id); - OPENSSL_free(smctx); - ctx->data = NULL; - } -} - -static int pkey_sm2_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src) -{ - SM2_PKEY_CTX *dctx, *sctx; - - if (!pkey_sm2_init(dst)) - return 0; - sctx = src->data; - dctx = dst->data; - if (sctx->id != NULL) { - dctx->id = OPENSSL_malloc(sctx->id_len); - if (dctx->id == NULL) { - SM2err(SM2_F_PKEY_SM2_COPY, ERR_R_MALLOC_FAILURE); - pkey_sm2_cleanup(dst); - return 0; - } - memcpy(dctx->id, sctx->id, sctx->id_len); - } - dctx->id_len = sctx->id_len; - dctx->id_set = sctx->id_set; - dctx->md = sctx->md; - - return 1; -} - -static int pkey_sm2_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, - const unsigned char *tbs, size_t tbslen) -{ - int ret; - unsigned int sltmp; - EC_KEY *ec = ctx->pkey->pkey.ec; - const int sig_sz = ECDSA_size(ctx->pkey->pkey.ec); - - if (sig_sz <= 0) { - return 0; - } - - if (sig == NULL) { - *siglen = (size_t)sig_sz; - return 1; - } - - if (*siglen < (size_t)sig_sz) { - SM2err(SM2_F_PKEY_SM2_SIGN, SM2_R_BUFFER_TOO_SMALL); - return 0; - } - - ret = sm2_internal_sign(tbs, tbslen, sig, &sltmp, ec); - - if (ret <= 0) - return ret; - *siglen = (size_t)sltmp; - return 1; -} - -static int pkey_sm2_verify(EVP_PKEY_CTX *ctx, - const unsigned char *sig, size_t siglen, - const unsigned char *tbs, size_t tbslen) -{ - EC_KEY *ec = ctx->pkey->pkey.ec; - - return sm2_internal_verify(tbs, tbslen, sig, siglen, ec); -} - -static int pkey_sm2_encrypt(EVP_PKEY_CTX *ctx, - unsigned char *out, size_t *outlen, - const unsigned char *in, size_t inlen) -{ - int ret; - EC_KEY *ec = ctx->pkey->pkey.ec; - SM2_PKEY_CTX *dctx = ctx->data; - const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md; - OPENSSL_CTX *libctx = ec_key_get_libctx(ec); - const char *propq = ec_key_get0_propq(ec); - EVP_MD *fetched_md = NULL; - - if (out == NULL) { - if (!sm2_ciphertext_size(ec, md, inlen, outlen)) - return -1; - else - return 1; - } - - fetched_md = EVP_MD_fetch(libctx, EVP_MD_name(md), propq); - if (fetched_md == NULL) - return 0; - ret = sm2_encrypt(ec, fetched_md, in, inlen, out, outlen); - EVP_MD_free(fetched_md); - return ret; -} - -static int pkey_sm2_decrypt(EVP_PKEY_CTX *ctx, - unsigned char *out, size_t *outlen, - const unsigned char *in, size_t inlen) -{ - int ret; - EC_KEY *ec = ctx->pkey->pkey.ec; - SM2_PKEY_CTX *dctx = ctx->data; - const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md; - OPENSSL_CTX *libctx = ec_key_get_libctx(ec); - const char *propq = ec_key_get0_propq(ec); - EVP_MD *fetched_md = NULL; - - if (out == NULL) { - if (!sm2_plaintext_size(ec, md, inlen, outlen)) - return -1; - else - return 1; - } - - fetched_md = EVP_MD_fetch(libctx, EVP_MD_name(md), propq); - if (fetched_md == NULL) - return 0; - ret = sm2_decrypt(ec, fetched_md, in, inlen, out, outlen); - EVP_MD_free(fetched_md); - return ret; -} - -static int pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) -{ - SM2_PKEY_CTX *smctx = ctx->data; - uint8_t *tmp_id; - - switch (type) { - case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID: - /* - * This control could be removed, which would signal it being - * unsupported. However, that means that when the caller uses - * the correct curve, it may interpret the unsupported signal - * as an error, so it's better to accept the control, check the - * value and return a corresponding value. - */ - if (p1 != NID_sm2) { - SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_INVALID_CURVE); - return 0; - } - return 1; - - case EVP_PKEY_CTRL_MD: - smctx->md = p2; - return 1; - - case EVP_PKEY_CTRL_GET_MD: - *(const EVP_MD **)p2 = smctx->md; - return 1; - - case EVP_PKEY_CTRL_SET1_ID: - if (p1 > 0) { - tmp_id = OPENSSL_malloc(p1); - if (tmp_id == NULL) { - SM2err(SM2_F_PKEY_SM2_CTRL, ERR_R_MALLOC_FAILURE); - return 0; - } - memcpy(tmp_id, p2, p1); - OPENSSL_free(smctx->id); - smctx->id = tmp_id; - } else { - /* set null-ID */ - OPENSSL_free(smctx->id); - smctx->id = NULL; - } - smctx->id_len = (size_t)p1; - smctx->id_set = 1; - return 1; - - case EVP_PKEY_CTRL_GET1_ID: - memcpy(p2, smctx->id, smctx->id_len); - return 1; - - case EVP_PKEY_CTRL_GET1_ID_LEN: - *(size_t *)p2 = smctx->id_len; - return 1; - - case EVP_PKEY_CTRL_DIGESTINIT: - /* nothing to be inited, this is to suppress the error... */ - return 1; - - default: - return -2; - } -} - -static int pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx, - const char *type, const char *value) -{ - uint8_t *hex_id; - long hex_len = 0; - int ret = 0; - - if (strcmp(type, "ec_paramgen_curve") == 0) { - int nid = NID_undef; - - if (((nid = EC_curve_nist2nid(value)) == NID_undef) - && ((nid = OBJ_sn2nid(value)) == NID_undef) - && ((nid = OBJ_ln2nid(value)) == NID_undef)) { - SM2err(SM2_F_PKEY_SM2_CTRL_STR, SM2_R_INVALID_CURVE); - return 0; - } - return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid); - } else if (strcmp(type, "ec_param_enc") == 0) { - int param_enc; - - if (strcmp(value, "explicit") == 0) - param_enc = 0; - else if (strcmp(value, "named_curve") == 0) - param_enc = OPENSSL_EC_NAMED_CURVE; - else - return -2; - return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc); - } else if (strcmp(type, "distid") == 0) { - return pkey_sm2_ctrl(ctx, EVP_PKEY_CTRL_SET1_ID, - (int)strlen(value), (void *)value); - } else if (strcmp(type, "hexdistid") == 0) { - hex_id = OPENSSL_hexstr2buf((const char *)value, &hex_len); - if (hex_id == NULL) { - SM2err(SM2_F_PKEY_SM2_CTRL_STR, ERR_R_PASSED_INVALID_ARGUMENT); - return 0; - } - ret = pkey_sm2_ctrl(ctx, EVP_PKEY_CTRL_SET1_ID, (int)hex_len, - (void *)hex_id); - OPENSSL_free(hex_id); - return ret; - } - - return -2; -} - -static int pkey_sm2_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) -{ - uint8_t z[EVP_MAX_MD_SIZE]; - SM2_PKEY_CTX *smctx = ctx->data; - EC_KEY *ec = ctx->pkey->pkey.ec; - const EVP_MD *md = EVP_MD_CTX_md(mctx); - int mdlen = EVP_MD_size(md); - - if (!smctx->id_set) { - /* - * An ID value must be set. The specifications are not clear whether a - * NULL is allowed. We only allow it if set explicitly for maximum - * flexibility. - */ - SM2err(SM2_F_PKEY_SM2_DIGEST_CUSTOM, SM2_R_ID_NOT_SET); - return 0; - } - - if (mdlen < 0) { - SM2err(SM2_F_PKEY_SM2_DIGEST_CUSTOM, SM2_R_INVALID_DIGEST); - return 0; - } - - /* get hashed prefix 'z' of tbs message */ - if (!sm2_compute_z_digest(z, md, smctx->id, smctx->id_len, ec)) - return 0; - - return EVP_DigestUpdate(mctx, z, (size_t)mdlen); -} - -static int pkey_sm2_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) -{ - EC_KEY *ec = NULL; - int ret; - - ec = EC_KEY_new_by_curve_name(NID_sm2); - if (ec == NULL) - return 0; - if (!ossl_assert(ret = EVP_PKEY_assign_EC_KEY(pkey, ec))) - EC_KEY_free(ec); - return ret; -} - -static int pkey_sm2_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) -{ - EC_KEY *ec = NULL; - - ec = EC_KEY_new_by_curve_name(NID_sm2); - if (ec == NULL) - return 0; - if (!ossl_assert(EVP_PKEY_assign_EC_KEY(pkey, ec))) { - EC_KEY_free(ec); - return 0; - } - /* Note: if error is returned, we count on caller to free pkey->pkey.ec */ - if (ctx->pkey != NULL - && !EVP_PKEY_copy_parameters(pkey, ctx->pkey)) - return 0; - - return EC_KEY_generate_key(ec); -} - -static const EVP_PKEY_METHOD sm2_pkey_meth = { - EVP_PKEY_SM2, - 0, - pkey_sm2_init, - pkey_sm2_copy, - pkey_sm2_cleanup, - - 0, - pkey_sm2_paramgen, - - 0, - pkey_sm2_keygen, - - 0, - pkey_sm2_sign, - - 0, - pkey_sm2_verify, - - 0, 0, - - 0, 0, 0, 0, - - 0, - pkey_sm2_encrypt, - - 0, - pkey_sm2_decrypt, - - 0, - 0, - pkey_sm2_ctrl, - pkey_sm2_ctrl_str, - - 0, 0, - - 0, 0, 0, - - pkey_sm2_digest_custom -}; - -const EVP_PKEY_METHOD *sm2_pkey_method(void) -{ - return &sm2_pkey_meth; -} diff --git a/doc/man7/EVP_ASYM_CIPHER-SM2.pod b/doc/man7/EVP_ASYM_CIPHER-SM2.pod new file mode 100644 index 0000000000..27f0032b78 --- /dev/null +++ b/doc/man7/EVP_ASYM_CIPHER-SM2.pod @@ -0,0 +1,41 @@ +=pod + +=head1 NAME + +EVP_ASYM_CIPHER-SM2 +- SM2 Asymmetric Cipher algorithm support + +=head1 DESCRIPTION + +Asymmetric Cipher support for the B<SM2> key type. + +=head2 SM2 Asymmetric Cipher parameters + +=over 4 + +=item "digest" (B<OSSL_ASYM_CIPHER_PARAM_DIGEST>) <UTF8 string> + +=item "digest-props" (B<OSSL_ASYM_CIPHER_PARAM_DIGEST_PROPS>) <UTF8 string> + +See L<provider-asym_cipher(7)/Asymmetric Cipher Parameters>. + +=back + +=head1 SEE ALSO + +L<EVP_PKEY-SM2(7)>, +L<EVP_PKEY(3)>, +L<provider-asym_cipher(7)>, +L<provider-keymgmt(7)>, +L<OSSL_PROVIDER-default(7)> + +=head1 COPYRIGHT + +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 +L<https://www.openssl.org/source/license.html>. + +=cut diff --git a/doc/man7/SM2.pod b/doc/man7/EVP_PKEY-SM2.pod similarity index 94% rename from doc/man7/SM2.pod rename to doc/man7/EVP_PKEY-SM2.pod index de52d05329..bb6258c873 100644 --- a/doc/man7/SM2.pod +++ b/doc/man7/EVP_PKEY-SM2.pod @@ -2,7 +2,8 @@ =head1 NAME -SM2 - Chinese SM2 signature and encryption algorithm support +EVP_PKEY-SM2, EVP_KEYMGMT-SM2, SM2 +- EVP_PKEY keytype support for the Chinese SM2 signature and encryption algorithms =head1 DESCRIPTION @@ -33,7 +34,7 @@ that B<EVP_PKEY_CTX> should be assigned to the B<EVP_MD_CTX>, like this: There is normally no need to pass a B<pctx> parameter to EVP_DigestSignInit() or EVP_DigestVerifyInit() in such a scenario. -SM2 can be tested with the L<openssl-speed(1)> application since version 3.0.0. +SM2 can be tested with the L<openssl-speed(1)> application since version 3.0. Currently, the only valid algorithm name is B<sm2>. =head1 EXAMPLES diff --git a/doc/man7/OSSL_PROVIDER-default.pod b/doc/man7/OSSL_PROVIDER-default.pod index 848c887b29..da6185c4d3 100644 --- a/doc/man7/OSSL_PROVIDER-default.pod +++ b/doc/man7/OSSL_PROVIDER-default.pod @@ -180,6 +180,8 @@ The OpenSSL default provider supports these operations and algorithms: =item RSA, see L<EVP_ASYM_CIPHER-RSA(7)> +=item SM2, see L<EVP_ASYM_CIPHER-SM2(7)> + =back =head2 Asymmetric Key Encapsulation diff --git a/doc/man7/provider-asym_cipher.pod b/doc/man7/provider-asym_cipher.pod index 5531a08f37..ca3e12fa85 100644 --- a/doc/man7/provider-asym_cipher.pod +++ b/doc/man7/provider-asym_cipher.pod @@ -193,10 +193,19 @@ further details. Gets or sets the name of the OAEP digest algorithm used when OAEP padding is in use. +=item "digest" (B<OSSL_ASYM_CIPHER_PARAM_DIGEST>) <UTF8 string> + +Gets or sets the name of the digest algorithm used by the algorithm (where +applicable). + =item "digest-props" (B<OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS>) <UTF8 string> Gets or sets the properties to use when fetching the OAEP digest algorithm. +=item "digest-props" (B<OSSL_ASYM_CIPHER_PARAM_DIGEST_PROPS>) <UTF8 string> + +Gets or sets the properties to use when fetching the cipher digest algorithm. + =item "mgf1-digest" (B<OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST>) <UTF8 string> Gets or sets the name of the MGF1 digest algorithm used when OAEP or PSS padding diff --git a/include/crypto/evp.h b/include/crypto/evp.h index 7016606757..835224a7aa 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -156,7 +156,6 @@ const EVP_PKEY_METHOD *dh_pkey_method(void); const EVP_PKEY_METHOD *dhx_pkey_method(void); const EVP_PKEY_METHOD *dsa_pkey_method(void); const EVP_PKEY_METHOD *ec_pkey_method(void); -const EVP_PKEY_METHOD *sm2_pkey_method(void); const EVP_PKEY_METHOD *ecx25519_pkey_method(void); const EVP_PKEY_METHOD *ecx448_pkey_method(void); const EVP_PKEY_METHOD *ed25519_pkey_method(void); 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 <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 <crypto/sm2.h> +#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[]; diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index afb9966bfa..1cc4f94941 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -982,7 +982,7 @@ static int test_EVP_SM2(void) { int ret = 0; EVP_PKEY *pkey = NULL; - EVP_PKEY *params = NULL; + EVP_PKEY *pkeyparams = NULL; EVP_PKEY_CTX *pctx = NULL; EVP_PKEY_CTX *kctx = NULL; EVP_PKEY_CTX *sctx = NULL; @@ -1000,6 +1000,11 @@ static int test_EVP_SM2(void) uint8_t sm2_id[] = {1, 2, 3, 4, 'l', 'e', 't', 't', 'e', 'r'}; + OSSL_PARAM sparams[2] = {OSSL_PARAM_END, OSSL_PARAM_END}; + OSSL_PARAM gparams[2] = {OSSL_PARAM_END, OSSL_PARAM_END}; + int i; + char mdname[20]; + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_SM2, NULL); if (!TEST_ptr(pctx)) goto done; @@ -1011,10 +1016,10 @@ static int test_EVP_SM2(void) if (!TEST_true(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_sm2))) goto done; - if (!TEST_true(EVP_PKEY_paramgen(pctx, ¶ms))) + if (!TEST_true(EVP_PKEY_paramgen(pctx, &pkeyparams))) goto done; - kctx = EVP_PKEY_CTX_new(params, NULL); + kctx = EVP_PKEY_CTX_new(pkeyparams, NULL); if (!TEST_ptr(kctx)) goto done; @@ -1070,34 +1075,54 @@ static int test_EVP_SM2(void) goto done; /* now check encryption/decryption */ - /* - * SM2 public key encrytion is not moved into default provider yet, - * so we make sure the key gets downgraded for the moment being. - * TODO Remove this call when provided SM2 encryption is implemented - */ - if (!TEST_ptr(EVP_PKEY_get0(pkey))) - goto done; - if (!TEST_ptr(cctx = EVP_PKEY_CTX_new(pkey, NULL))) - goto done; + gparams[0] = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_DIGEST, + mdname, sizeof(mdname)); + for (i = 0; i < 2; i++) { + EVP_PKEY_CTX_free(cctx); - if (!TEST_true(EVP_PKEY_encrypt_init(cctx))) - goto done; + sparams[0] = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_DIGEST, + i == 0 ? "SM3" : "SHA2-256", + 0); - if (!TEST_true(EVP_PKEY_encrypt(cctx, ciphertext, &ctext_len, kMsg, sizeof(kMsg)))) - goto done; + if (!TEST_ptr(cctx = EVP_PKEY_CTX_new(pkey, NULL))) + goto done; - if (!TEST_true(EVP_PKEY_decrypt_init(cctx))) - goto done; + if (!TEST_true(EVP_PKEY_encrypt_init(cctx))) + goto done; - if (!TEST_true(EVP_PKEY_decrypt(cctx, plaintext, &ptext_len, ciphertext, ctext_len))) - goto done; + if (!TEST_true(EVP_PKEY_CTX_set_params(cctx, sparams))) + goto done; - if (!TEST_true(ptext_len == sizeof(kMsg))) - goto done; + if (!TEST_true(EVP_PKEY_encrypt(cctx, ciphertext, &ctext_len, kMsg, + sizeof(kMsg)))) + goto done; - if (!TEST_true(memcmp(plaintext, kMsg, sizeof(kMsg)) == 0)) - goto done; + if (!TEST_true(EVP_PKEY_decrypt_init(cctx))) + goto done; + + if (!TEST_true(EVP_PKEY_CTX_set_params(cctx, sparams))) + goto done; + + if (!TEST_true(EVP_PKEY_decrypt(cctx, plaintext, &ptext_len, ciphertext, + ctext_len))) + goto done; + + if (!TEST_true(EVP_PKEY_CTX_get_params(cctx, gparams))) + goto done; + + /* Test we're still using the digest we think we are */ + if (i == 0 && !TEST_int_eq(strcmp(mdname, "SM3"), 0)) + goto done; + if (i == 1 && !TEST_int_eq(strcmp(mdname, "SHA2-256"), 0)) + goto done; + + if (!TEST_true(ptext_len == sizeof(kMsg))) + goto done; + + if (!TEST_true(memcmp(plaintext, kMsg, sizeof(kMsg)) == 0)) + goto done; + } ret = 1; done: @@ -1106,7 +1131,7 @@ done: EVP_PKEY_CTX_free(sctx); EVP_PKEY_CTX_free(cctx); EVP_PKEY_free(pkey); - EVP_PKEY_free(params); + EVP_PKEY_free(pkeyparams); EVP_MD_CTX_free(md_ctx); EVP_MD_CTX_free(md_ctx_verify); OPENSSL_free(sig); diff --git a/test/recipes/20-test_pkeyutl.t b/test/recipes/20-test_pkeyutl.t index 3c135630f7..19bc327758 100644 --- a/test/recipes/20-test_pkeyutl.t +++ b/test/recipes/20-test_pkeyutl.t @@ -24,20 +24,14 @@ SKIP: { skip "Skipping tests that require EC, SM2 or SM3", 2 if disabled("ec") || disabled("sm2") || disabled("sm3"); - # TODO(3.0) Remove this when we have a SM2 keymgmt and decoder - my @tmp_sm2_hack = qw(-engine loader_attic) - unless disabled('dynamic-engine') || disabled('deprecated-3.0'); - skip "Skipping tests that require dynamic enginess (temporary meaasure)", 2 - unless @tmp_sm2_hack; - # SM2 - ok_nofips(run(app(([ 'openssl', 'pkeyutl', @tmp_sm2_hack, '-sign', + ok_nofips(run(app(([ 'openssl', 'pkeyutl', '-sign', '-in', srctop_file('test', 'certs', 'sm2.pem'), '-inkey', srctop_file('test', 'certs', 'sm2.key'), '-out', 'sm2.sig', '-rawin', '-digest', 'sm3', '-pkeyopt', 'distid:someid']))), "Sign a piece of data using SM2"); - ok_nofips(run(app(([ 'openssl', 'pkeyutl', @tmp_sm2_hack, + ok_nofips(run(app(([ 'openssl', 'pkeyutl', '-verify', '-certin', '-in', srctop_file('test', 'certs', 'sm2.pem'), '-inkey', srctop_file('test', 'certs', 'sm2.pem'), diff --git a/test/recipes/25-test_req.t b/test/recipes/25-test_req.t index b00b8c3404..8d26be2bf0 100644 --- a/test/recipes/25-test_req.t +++ b/test/recipes/25-test_req.t @@ -29,14 +29,6 @@ if (disabled("rsa")) { note("There should not be more that at most 80 per line"); } -# TODO(3.0) This should be removed as soon as missing support is added -# Identified problems: -# - SM2 lacks provider-native keymgmt and decoder -# - ED25519, ED448, X25519 and X448 signature implementations do not -# respond to the "algorithm-id" parameter request. -my @tmp_loader_hack = qw(-engine loader_attic) - unless disabled('dynamic-engine') || disabled('deprecated-3.0'); - # Check for duplicate -addext parameters, and one "working" case. my @addext_args = ( "openssl", "req", "-new", "-out", "testreq.pem", "-config", srctop_file("test", "test.cnf"), @req_new ); @@ -195,28 +187,28 @@ subtest "generating SM2 certificate requests" => sub { SKIP: { skip "SM2 is not supported by this OpenSSL build", 4 - if disabled("sm2") || !@tmp_loader_hack; - ok(run(app(["openssl", "req", @tmp_loader_hack, + if disabled("sm2"); + ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"), "-new", "-key", srctop_file("test", "certs", "sm2.key"), "-sigopt", "distid:1234567812345678", "-out", "testreq-sm2.pem", "-sm3"])), "Generating SM2 certificate request"); - ok(run(app(["openssl", "req", @tmp_loader_hack, + ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"), "-verify", "-in", "testreq-sm2.pem", "-noout", "-vfyopt", "distid:1234567812345678", "-sm3"])), "Verifying signature on SM2 certificate request"); - ok(run(app(["openssl", "req", @tmp_loader_hack, + ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"), "-new", "-key", srctop_file("test", "certs", "sm2.key"), "-sigopt", "hexdistid:DEADBEEF", "-out", "testreq-sm2.pem", "-sm3"])), "Generating SM2 certificate request with hex id"); - ok(run(app(["openssl", "req", @tmp_loader_hack, + ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"), "-verify", "-in", "testreq-sm2.pem", "-noout", "-vfyopt", "hexdistid:DEADBEEF", "-sm3"])),