Move SM2 asymmetric encryption to be available in the default provider
authorMatt Caswell <matt@openssl.org>
Fri, 18 Sep 2020 08:55:16 +0000 (09:55 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 25 Sep 2020 10:13:53 +0000 (11:13 +0100)
Fixes #12908

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12913)

include/openssl/core_names.h
providers/common/include/prov/provider_util.h
providers/common/provider_util.c
providers/defltprov.c
providers/implementations/asymciphers/build.info
providers/implementations/asymciphers/sm2_enc.c [new file with mode: 0644]
providers/implementations/include/prov/implementations.h

index a8d4d51..c9f2bfa 100644 (file)
@@ -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
index d964f83..83f6d63 100644 (file)
@@ -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
index 4259d71..2e9fe8d 100644 (file)
@@ -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)
index 8564ddd..dee48fb 100644 (file)
@@ -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 }
 };
 
index b4033d8..4b629d0 100644 (file)
@@ -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 (file)
index 0000000..4f2f64b
--- /dev/null
@@ -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 }
+};
index b67b4c7..dd45523 100644 (file)
@@ -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[];