[openssl-commits] [openssl] master update

yang.yang at baishancloud.com yang.yang at baishancloud.com
Fri Sep 7 10:15:05 UTC 2018


The branch master has been updated
       via  f922dac87d859cc7419207301533fe89582ac3ea (commit)
       via  81c7945388a49799f819f5ca5bfe6acd506840c3 (commit)
       via  571286b0a463b02ef2f9040a7e5d602635854832 (commit)
       via  675f4ceef880f9c4eb0fda5dacd18b001fefb5bc (commit)
       via  a6c4cb845a031f09c6303a2c3452e253d0d01518 (commit)
       via  4803717f5e3bcfba3e3442e1611f421bf1090a47 (commit)
       via  00433bad41bfa492f2e204675d42061314028ff2 (commit)
       via  0a8fdef7523ae796ca2e734c279791737148c001 (commit)
       via  00902d9414b4c6e46f78d7a6b6c8edc4d313d4b7 (commit)
       via  5bd0abe7a2f76d8c80f566ae615c10113884d843 (commit)
      from  63c5ac801f7ccdbc1e975f880eb74c1bed63d5e4 (commit)


- Log -----------------------------------------------------------------
commit f922dac87d859cc7419207301533fe89582ac3ea
Author: Paul Yang <yang.yang at baishancloud.com>
Date:   Thu Sep 6 10:36:11 2018 +0800

    Add missing SM2err and fix doc nits
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7113)

commit 81c7945388a49799f819f5ca5bfe6acd506840c3
Author: Paul Yang <yang.yang at baishancloud.com>
Date:   Wed Sep 5 22:01:33 2018 +0800

    Allow EVP_MD_CTX_set_pkey_ctx to accept NULL pctx
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7113)

commit 571286b0a463b02ef2f9040a7e5d602635854832
Author: Paul Yang <yang.yang at baishancloud.com>
Date:   Wed Sep 5 20:20:33 2018 +0800

    Add a SM2(7) man page
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7113)

commit 675f4ceef880f9c4eb0fda5dacd18b001fefb5bc
Author: Paul Yang <yang.yang at baishancloud.com>
Date:   Wed Sep 5 15:19:17 2018 +0800

    Update document for SM2 stuffs
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7113)

commit a6c4cb845a031f09c6303a2c3452e253d0d01518
Author: Jack Lloyd <jack.lloyd at ribose.com>
Date:   Tue Sep 4 23:25:29 2018 +0800

    Add test case for SM2 evp verification
    
    This test case is originally submitted in #6757, by Jack Lloyd. The test
    case has been modified to use the a different method to set the ID when
    computing the Z hash of SM2 signature.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    Reviewed-by: Paul Yang <yang.yang at baishancloud.com>
    (Merged from https://github.com/openssl/openssl/pull/7113)

commit 4803717f5e3bcfba3e3442e1611f421bf1090a47
Author: Paul Yang <yang.yang at baishancloud.com>
Date:   Tue Sep 4 17:21:10 2018 +0800

    Support setting SM2 ID
    
    zero-length ID is allowed, but it's not allowed to skip the ID.
    
    Fixes: #6534
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7113)

commit 00433bad41bfa492f2e204675d42061314028ff2
Author: Paul Yang <yang.yang at baishancloud.com>
Date:   Tue Sep 4 01:24:55 2018 +0800

    Make SM2 ID stick to specification
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7113)

commit 0a8fdef7523ae796ca2e734c279791737148c001
Author: Paul Yang <yang.yang at baishancloud.com>
Date:   Tue Sep 4 00:51:04 2018 +0800

    Support pmeth->digest_custom
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7113)

commit 00902d9414b4c6e46f78d7a6b6c8edc4d313d4b7
Author: Paul Yang <yang.yang at baishancloud.com>
Date:   Mon Sep 3 23:56:41 2018 +0800

    Introduce EVP_MD_CTX_set_pkey_ctx
    
    Thus users can use this function to set customized EVP_PKEY_CTX to
    EVP_MD_CTX structure.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7113)

commit 5bd0abe7a2f76d8c80f566ae615c10113884d843
Author: Paul Yang <yang.yang at baishancloud.com>
Date:   Mon Sep 3 22:08:17 2018 +0800

    Remove unnecessary sm2_za.c
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7113)

-----------------------------------------------------------------------

Summary of changes:
 crypto/err/openssl.txt            |   6 ++
 crypto/evp/digest.c               |  12 ++-
 crypto/evp/evp_lib.c              |  19 +++++
 crypto/evp/m_sigver.c             |  17 +++--
 crypto/evp/pmeth_lib.c            |  22 +++++-
 crypto/include/internal/evp_int.h |   8 ++
 crypto/include/internal/sm2.h     |  20 +++--
 crypto/include/internal/sm2err.h  |   6 ++
 crypto/sm2/build.info             |   2 +-
 crypto/sm2/sm2_err.c              |   8 ++
 crypto/sm2/sm2_pmeth.c            | 106 ++++++++++++++++++++++----
 crypto/sm2/sm2_sign.c             | 153 ++++++++++++++++++++++++++++++++++----
 crypto/sm2/sm2_za.c               | 132 --------------------------------
 doc/man3/EVP_DigestInit.pod       |  20 ++++-
 doc/man3/EVP_DigestSignInit.pod   |  11 ++-
 doc/man3/EVP_DigestVerifyInit.pod |   9 ++-
 doc/man3/EVP_PKEY_CTX_ctrl.pod    |  22 +++++-
 doc/man3/EVP_PKEY_meth_new.pod    |  17 +++++
 doc/man7/SM2.pod                  |  79 ++++++++++++++++++++
 include/openssl/ec.h              |  16 ++++
 include/openssl/evp.h             |   9 +++
 test/evp_extra_test.c             |  93 +++++++++++++++++++++++
 test/sm2_internal_test.c          |   7 +-
 util/libcrypto.num                |   3 +
 util/private.num                  |   3 +
 25 files changed, 609 insertions(+), 191 deletions(-)
 delete mode 100644 crypto/sm2/sm2_za.c
 create mode 100644 doc/man7/SM2.pod

diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 3ecd44b..2c8572b 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -1080,12 +1080,15 @@ RSA_F_RSA_VERIFY:119:RSA_verify
 RSA_F_RSA_VERIFY_ASN1_OCTET_STRING:120:RSA_verify_ASN1_OCTET_STRING
 RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1:126:RSA_verify_PKCS1_PSS_mgf1
 RSA_F_SETUP_TBUF:167:setup_tbuf
+SM2_F_PKEY_SM2_COPY:115:pkey_sm2_copy
 SM2_F_PKEY_SM2_CTRL:109:pkey_sm2_ctrl
 SM2_F_PKEY_SM2_CTRL_STR:110:pkey_sm2_ctrl_str
+SM2_F_PKEY_SM2_DIGEST_CUSTOM:114:pkey_sm2_digest_custom
 SM2_F_PKEY_SM2_INIT:111:pkey_sm2_init
 SM2_F_PKEY_SM2_SIGN:112:pkey_sm2_sign
 SM2_F_SM2_COMPUTE_MSG_HASH:100:sm2_compute_msg_hash
 SM2_F_SM2_COMPUTE_USERID_DIGEST:101:sm2_compute_userid_digest
+SM2_F_SM2_COMPUTE_Z_DIGEST:113:sm2_compute_z_digest
 SM2_F_SM2_DECRYPT:102:sm2_decrypt
 SM2_F_SM2_ENCRYPT:103:sm2_encrypt
 SM2_F_SM2_PLAINTEXT_SIZE:104:sm2_plaintext_size
@@ -2554,6 +2557,9 @@ RSA_R_WRONG_SIGNATURE_LENGTH:119:wrong signature length
 SM2_R_ASN1_ERROR:100:asn1 error
 SM2_R_BAD_SIGNATURE:101:bad signature
 SM2_R_BUFFER_TOO_SMALL:107:buffer too small
+SM2_R_DIST_ID_TOO_LARGE:110:dist id too large
+SM2_R_ID_NOT_SET:112:id not set
+SM2_R_ID_TOO_LARGE:111:id too large
 SM2_R_INVALID_CURVE:108:invalid curve
 SM2_R_INVALID_DIGEST:102:invalid digest
 SM2_R_INVALID_DIGEST_TYPE:103:invalid digest type
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index c380dca..f78dab7 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -32,7 +32,12 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
         && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
         OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
     }
-    EVP_PKEY_CTX_free(ctx->pctx);
+    /*
+     * pctx should be freed by the user of EVP_MD_CTX
+     * if EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set
+     */
+    if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX))
+        EVP_PKEY_CTX_free(ctx->pctx);
 #ifndef OPENSSL_NO_ENGINE
     ENGINE_finish(ctx->engine);
 #endif
@@ -224,6 +229,9 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
     EVP_MD_CTX_reset(out);
     memcpy(out, in, sizeof(*out));
 
+    /* copied EVP_MD_CTX should free the copied EVP_PKEY_CTX */
+    EVP_MD_CTX_clear_flags(out, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
+
     /* Null these variables, since they are getting fixed up
      * properly below.  Anything else may cause a memleak and/or
      * double free if any of the memory allocations below fail
diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c
index 6c48199..1b3c984 100644
--- a/crypto/evp/evp_lib.c
+++ b/crypto/evp/evp_lib.c
@@ -460,6 +460,25 @@ EVP_PKEY_CTX *EVP_MD_CTX_pkey_ctx(const EVP_MD_CTX *ctx)
     return ctx->pctx;
 }
 
+void EVP_MD_CTX_set_pkey_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pctx)
+{
+    /*
+     * it's reasonable to set NULL pctx (a.k.a clear the ctx->pctx), so
+     * we have to deal with the cleanup job here.
+     */
+    if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX))
+        EVP_PKEY_CTX_free(ctx->pctx);
+
+    ctx->pctx = pctx;
+
+    if (pctx != NULL) {
+        /* make sure pctx is not freed when destroying EVP_MD_CTX */
+        EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
+    } else {
+        EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
+    }
+}
+
 void *EVP_MD_CTX_md_data(const EVP_MD_CTX *ctx)
 {
     return ctx->md_data;
diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c
index 2377944..94e37f0 100644
--- a/crypto/evp/m_sigver.c
+++ b/crypto/evp/m_sigver.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -75,6 +75,13 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
         return 1;
     if (!EVP_DigestInit_ex(ctx, type, e))
         return 0;
+    /*
+     * This indicates the current algorithm requires
+     * special treatment before hashing the tbs-message.
+     */
+    if (ctx->pctx->pmeth->digest_custom != NULL)
+        return ctx->pctx->pmeth->digest_custom(ctx->pctx, ctx);
+
     return 1;
 }
 
@@ -176,9 +183,9 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig,
     else
         vctx = 0;
     if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) {
-        if (vctx) {
+        if (vctx)
             r = ctx->pctx->pmeth->verifyctx(ctx->pctx, sig, siglen, ctx);
-        } else
+        else
             r = EVP_DigestFinal_ex(ctx, md, &mdlen);
     } else {
         EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new();
@@ -188,10 +195,10 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig,
             EVP_MD_CTX_free(tmp_ctx);
             return -1;
         }
-        if (vctx) {
+        if (vctx)
             r = tmp_ctx->pctx->pmeth->verifyctx(tmp_ctx->pctx,
                                                 sig, siglen, tmp_ctx);
-        } else
+        else
             r = EVP_DigestFinal_ex(tmp_ctx, md, &mdlen);
         EVP_MD_CTX_free(tmp_ctx);
     }
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index ef923fd..633cb88 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -367,6 +367,7 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
                       int cmd, int p1, void *p2)
 {
     int ret;
+
     if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) {
         EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED);
         return -2;
@@ -374,6 +375,10 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
     if ((keytype != -1) && (ctx->pmeth->pkey_id != keytype))
         return -1;
 
+    /* Skip the operation checks since this is called in a very early stage */
+    if (ctx->pmeth->digest_custom != NULL)
+        goto doit;
+
     if (ctx->operation == EVP_PKEY_OP_UNDEFINED) {
         EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_NO_OPERATION_SET);
         return -1;
@@ -384,13 +389,13 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
         return -1;
     }
 
+ doit:
     ret = ctx->pmeth->ctrl(ctx, cmd, p1, p2);
 
     if (ret == -2)
         EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED);
 
     return ret;
-
 }
 
 int EVP_PKEY_CTX_ctrl_uint64(EVP_PKEY_CTX *ctx, int keytype, int optype,
@@ -655,6 +660,13 @@ void EVP_PKEY_meth_set_param_check(EVP_PKEY_METHOD *pmeth,
     pmeth->param_check = check;
 }
 
+void EVP_PKEY_meth_set_digest_custom(EVP_PKEY_METHOD *pmeth,
+                                     int (*digest_custom) (EVP_PKEY_CTX *ctx,
+                                                           EVP_MD_CTX *mctx))
+{
+    pmeth->digest_custom = digest_custom;
+}
+
 void EVP_PKEY_meth_get_init(const EVP_PKEY_METHOD *pmeth,
                             int (**pinit) (EVP_PKEY_CTX *ctx))
 {
@@ -842,3 +854,11 @@ void EVP_PKEY_meth_get_param_check(const EVP_PKEY_METHOD *pmeth,
     if (*pcheck)
         *pcheck = pmeth->param_check;
 }
+
+void EVP_PKEY_meth_get_digest_custom(EVP_PKEY_METHOD *pmeth,
+                                     int (**pdigest_custom) (EVP_PKEY_CTX *ctx,
+                                                             EVP_MD_CTX *mctx))
+{
+    if (pdigest_custom != NULL)
+        *pdigest_custom = pmeth->digest_custom;
+}
diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h
index daf2e45..d86aed3 100644
--- a/crypto/include/internal/evp_int.h
+++ b/crypto/include/internal/evp_int.h
@@ -10,6 +10,12 @@
 #include <openssl/evp.h>
 #include "internal/refcount.h"
 
+/*
+ * Don't free up md_ctx->pctx in EVP_MD_CTX_reset, use the reserved flag
+ * values in evp.h
+ */
+#define EVP_MD_CTX_FLAG_KEEP_PKEY_CTX   0x0400
+
 struct evp_pkey_ctx_st {
     /* Method associated with this operation */
     const EVP_PKEY_METHOD *pmeth;
@@ -79,6 +85,8 @@ struct evp_pkey_method_st {
     int (*check) (EVP_PKEY *pkey);
     int (*public_check) (EVP_PKEY *pkey);
     int (*param_check) (EVP_PKEY *pkey);
+
+    int (*digest_custom) (EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
 } /* EVP_PKEY_METHOD */ ;
 
 DEFINE_STACK_OF_CONST(EVP_PKEY_METHOD)
diff --git a/crypto/include/internal/sm2.h b/crypto/include/internal/sm2.h
index 23e3895..5c5cd4b 100644
--- a/crypto/include/internal/sm2.h
+++ b/crypto/include/internal/sm2.h
@@ -20,22 +20,27 @@
 /* The default user id as specified in GM/T 0009-2012 */
 #  define SM2_DEFAULT_USERID "1234567812345678"
 
-int sm2_compute_userid_digest(uint8_t *out,
-                              const EVP_MD *digest,
-                              const char *user_id, const EC_KEY *key);
+int sm2_compute_z_digest(uint8_t *out,
+                         const EVP_MD *digest,
+                         const uint8_t *id,
+                         const size_t id_len,
+                         const EC_KEY *key);
 
 /*
- * SM2 signature operation. Computes ZA (user id digest) and then signs
- * H(ZA || msg) using SM2
+ * SM2 signature operation. Computes Z and then signs H(Z || msg) using SM2
  */
 ECDSA_SIG *sm2_do_sign(const EC_KEY *key,
                        const EVP_MD *digest,
-                       const char *user_id, const uint8_t *msg, size_t msg_len);
+                       const uint8_t *id,
+                       const size_t id_len,
+                       const uint8_t *msg, size_t msg_len);
 
 int sm2_do_verify(const EC_KEY *key,
                   const EVP_MD *digest,
                   const ECDSA_SIG *signature,
-                  const char *user_id, const uint8_t *msg, size_t msg_len);
+                  const uint8_t *id,
+                  const size_t id_len,
+                  const uint8_t *msg, size_t msg_len);
 
 /*
  * SM2 signature generation.
@@ -49,7 +54,6 @@ int sm2_sign(const unsigned char *dgst, int dgstlen,
 int sm2_verify(const unsigned char *dgst, int dgstlen,
                const unsigned char *sig, int siglen, EC_KEY *eckey);
 
-
 /*
  * SM2 encryption
  */
diff --git a/crypto/include/internal/sm2err.h b/crypto/include/internal/sm2err.h
index 9a7e2b6..a4db1b7 100644
--- a/crypto/include/internal/sm2err.h
+++ b/crypto/include/internal/sm2err.h
@@ -23,12 +23,15 @@ int ERR_load_SM2_strings(void);
 /*
  * SM2 function codes.
  */
+#  define SM2_F_PKEY_SM2_COPY                              115
 #  define SM2_F_PKEY_SM2_CTRL                              109
 #  define SM2_F_PKEY_SM2_CTRL_STR                          110
+#  define SM2_F_PKEY_SM2_DIGEST_CUSTOM                     114
 #  define SM2_F_PKEY_SM2_INIT                              111
 #  define SM2_F_PKEY_SM2_SIGN                              112
 #  define SM2_F_SM2_COMPUTE_MSG_HASH                       100
 #  define SM2_F_SM2_COMPUTE_USERID_DIGEST                  101
+#  define SM2_F_SM2_COMPUTE_Z_DIGEST                       113
 #  define SM2_F_SM2_DECRYPT                                102
 #  define SM2_F_SM2_ENCRYPT                                103
 #  define SM2_F_SM2_PLAINTEXT_SIZE                         104
@@ -43,6 +46,9 @@ int ERR_load_SM2_strings(void);
 #  define SM2_R_ASN1_ERROR                                 100
 #  define SM2_R_BAD_SIGNATURE                              101
 #  define SM2_R_BUFFER_TOO_SMALL                           107
+#  define SM2_R_DIST_ID_TOO_LARGE                          110
+#  define SM2_R_ID_NOT_SET                                 112
+#  define SM2_R_ID_TOO_LARGE                               111
 #  define SM2_R_INVALID_CURVE                              108
 #  define SM2_R_INVALID_DIGEST                             102
 #  define SM2_R_INVALID_DIGEST_TYPE                        103
diff --git a/crypto/sm2/build.info b/crypto/sm2/build.info
index c1e84f4..be76d96 100644
--- a/crypto/sm2/build.info
+++ b/crypto/sm2/build.info
@@ -1,5 +1,5 @@
 LIBS=../../libcrypto
 SOURCE[../../libcrypto]=\
-        sm2_za.c sm2_sign.c sm2_crypt.c sm2_err.c sm2_pmeth.c
+        sm2_sign.c sm2_crypt.c sm2_err.c sm2_pmeth.c
 
 
diff --git a/crypto/sm2/sm2_err.c b/crypto/sm2/sm2_err.c
index 035abdc..653c679 100644
--- a/crypto/sm2/sm2_err.c
+++ b/crypto/sm2/sm2_err.c
@@ -14,14 +14,19 @@
 #ifndef OPENSSL_NO_ERR
 
 static const ERR_STRING_DATA SM2_str_functs[] = {
+    {ERR_PACK(ERR_LIB_SM2, SM2_F_PKEY_SM2_COPY, 0), "pkey_sm2_copy"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_PKEY_SM2_CTRL, 0), "pkey_sm2_ctrl"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_PKEY_SM2_CTRL_STR, 0), "pkey_sm2_ctrl_str"},
+    {ERR_PACK(ERR_LIB_SM2, SM2_F_PKEY_SM2_DIGEST_CUSTOM, 0),
+     "pkey_sm2_digest_custom"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_PKEY_SM2_INIT, 0), "pkey_sm2_init"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_PKEY_SM2_SIGN, 0), "pkey_sm2_sign"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_COMPUTE_MSG_HASH, 0),
      "sm2_compute_msg_hash"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_COMPUTE_USERID_DIGEST, 0),
      "sm2_compute_userid_digest"},
+    {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_COMPUTE_Z_DIGEST, 0),
+     "sm2_compute_z_digest"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_DECRYPT, 0), "sm2_decrypt"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_ENCRYPT, 0), "sm2_encrypt"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_PLAINTEXT_SIZE, 0), "sm2_plaintext_size"},
@@ -36,6 +41,9 @@ static const ERR_STRING_DATA SM2_str_reasons[] = {
     {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_ASN1_ERROR), "asn1 error"},
     {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_BAD_SIGNATURE), "bad signature"},
     {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_BUFFER_TOO_SMALL), "buffer too small"},
+    {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_DIST_ID_TOO_LARGE), "dist id too large"},
+    {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_ID_NOT_SET), "id not set"},
+    {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_ID_TOO_LARGE), "id too large"},
     {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_INVALID_CURVE), "invalid curve"},
     {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_INVALID_DIGEST), "invalid digest"},
     {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_INVALID_DIGEST_TYPE),
diff --git a/crypto/sm2/sm2_pmeth.c b/crypto/sm2/sm2_pmeth.c
index b027131..3e42065 100644
--- a/crypto/sm2/sm2_pmeth.c
+++ b/crypto/sm2/sm2_pmeth.c
@@ -22,28 +22,34 @@ typedef struct {
     EC_GROUP *gen_group;
     /* message digest */
     const EVP_MD *md;
+    /* Distinguishing Identifier, ISO/IEC 15946-3 */
+    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 *dctx;
+    SM2_PKEY_CTX *smctx;
 
-    if ((dctx = OPENSSL_zalloc(sizeof(*dctx))) == NULL) {
+    if ((smctx = OPENSSL_zalloc(sizeof(*smctx))) == NULL) {
         SM2err(SM2_F_PKEY_SM2_INIT, ERR_R_MALLOC_FAILURE);
         return 0;
     }
 
-    ctx->data = dctx;
+    ctx->data = smctx;
     return 1;
 }
 
 static void pkey_sm2_cleanup(EVP_PKEY_CTX *ctx)
 {
-    SM2_PKEY_CTX *dctx = ctx->data;
+    SM2_PKEY_CTX *smctx = ctx->data;
 
-    if (dctx != NULL) {
-        EC_GROUP_free(dctx->gen_group);
-        OPENSSL_free(dctx);
+    if (smctx != NULL) {
+        EC_GROUP_free(smctx->gen_group);
+        OPENSSL_free(smctx->id);
+        OPENSSL_free(smctx);
         ctx->data = NULL;
     }
 }
@@ -63,6 +69,17 @@ static int pkey_sm2_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
             return 0;
         }
     }
+    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;
@@ -145,8 +162,9 @@ static int pkey_sm2_decrypt(EVP_PKEY_CTX *ctx,
 
 static int pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
 {
-    SM2_PKEY_CTX *dctx = ctx->data;
+    SM2_PKEY_CTX *smctx = ctx->data;
     EC_GROUP *group;
+    uint8_t *tmp_id;
 
     switch (type) {
     case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
@@ -155,29 +173,55 @@ static int pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
             SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_INVALID_CURVE);
             return 0;
         }
-        EC_GROUP_free(dctx->gen_group);
-        dctx->gen_group = group;
+        EC_GROUP_free(smctx->gen_group);
+        smctx->gen_group = group;
         return 1;
 
     case EVP_PKEY_CTRL_EC_PARAM_ENC:
-        if (dctx->gen_group == NULL) {
+        if (smctx->gen_group == NULL) {
             SM2err(SM2_F_PKEY_SM2_CTRL, SM2_R_NO_PARAMETERS_SET);
             return 0;
         }
-        EC_GROUP_set_asn1_flag(dctx->gen_group, p1);
+        EC_GROUP_set_asn1_flag(smctx->gen_group, p1);
         return 1;
 
     case EVP_PKEY_CTRL_MD:
-        dctx->md = p2;
+        smctx->md = p2;
         return 1;
 
     case EVP_PKEY_CTRL_GET_MD:
-        *(const EVP_MD **)p2 = dctx->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;
 
     default:
         return -2;
-
     }
 }
 
@@ -209,6 +253,30 @@ static int pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx,
     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);
+
+    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;
+    }
+
+    /* 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, EVP_MD_size(md));
+}
+
 const EVP_PKEY_METHOD sm2_pkey_meth = {
     EVP_PKEY_SM2,
     0,
@@ -241,5 +309,11 @@ const EVP_PKEY_METHOD sm2_pkey_meth = {
     0,
     0,
     pkey_sm2_ctrl,
-    pkey_sm2_ctrl_str
+    pkey_sm2_ctrl_str,
+
+    0, 0,
+
+    0, 0, 0,
+
+    pkey_sm2_digest_custom
 };
diff --git a/crypto/sm2/sm2_sign.c b/crypto/sm2/sm2_sign.c
index f1185c1..e594ffd 100644
--- a/crypto/sm2/sm2_sign.c
+++ b/crypto/sm2/sm2_sign.c
@@ -18,14 +18,132 @@
 #include <openssl/bn.h>
 #include <string.h>
 
+int sm2_compute_z_digest(uint8_t *out,
+                         const EVP_MD *digest,
+                         const uint8_t *id,
+                         const size_t id_len,
+                         const EC_KEY *key)
+{
+    int rc = 0;
+    const EC_GROUP *group = EC_KEY_get0_group(key);
+    BN_CTX *ctx = NULL;
+    EVP_MD_CTX *hash = NULL;
+    BIGNUM *p = NULL;
+    BIGNUM *a = NULL;
+    BIGNUM *b = NULL;
+    BIGNUM *xG = NULL;
+    BIGNUM *yG = NULL;
+    BIGNUM *xA = NULL;
+    BIGNUM *yA = NULL;
+    int p_bytes = 0;
+    uint8_t *buf = NULL;
+    uint16_t entl = 0;
+    uint8_t e_byte = 0;
+
+    hash = EVP_MD_CTX_new();
+    ctx = BN_CTX_new();
+    if (hash == NULL || ctx == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_Z_DIGEST, ERR_R_MALLOC_FAILURE);
+        goto done;
+    }
+
+    p = BN_CTX_get(ctx);
+    a = BN_CTX_get(ctx);
+    b = BN_CTX_get(ctx);
+    xG = BN_CTX_get(ctx);
+    yG = BN_CTX_get(ctx);
+    xA = BN_CTX_get(ctx);
+    yA = BN_CTX_get(ctx);
+
+    if (yA == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_Z_DIGEST, ERR_R_MALLOC_FAILURE);
+        goto done;
+    }
+
+    if (!EVP_DigestInit(hash, digest)) {
+        SM2err(SM2_F_SM2_COMPUTE_Z_DIGEST, ERR_R_EVP_LIB);
+        goto done;
+    }
+
+    /* Z = h(ENTL || ID || a || b || xG || yG || xA || yA) */
+
+    if (id_len >= (UINT16_MAX / 8)) {
+        /* too large */
+        SM2err(SM2_F_SM2_COMPUTE_Z_DIGEST, SM2_R_ID_TOO_LARGE);
+        goto done;
+    }
+
+    entl = (uint16_t)(8 * id_len);
+
+    e_byte = entl >> 8;
+    if (!EVP_DigestUpdate(hash, &e_byte, 1)) {
+        SM2err(SM2_F_SM2_COMPUTE_Z_DIGEST, ERR_R_EVP_LIB);
+        goto done;
+    }
+    e_byte = entl & 0xFF;
+    if (!EVP_DigestUpdate(hash, &e_byte, 1)) {
+        SM2err(SM2_F_SM2_COMPUTE_Z_DIGEST, ERR_R_EVP_LIB);
+        goto done;
+    }
+
+    if (id_len > 0 && !EVP_DigestUpdate(hash, id, id_len)) {
+        SM2err(SM2_F_SM2_COMPUTE_Z_DIGEST, ERR_R_EVP_LIB);
+        goto done;
+    }
+
+    if (!EC_GROUP_get_curve(group, p, a, b, ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_Z_DIGEST, ERR_R_EC_LIB);
+        goto done;
+    }
+
+    p_bytes = BN_num_bytes(p);
+    buf = OPENSSL_zalloc(p_bytes);
+    if (buf == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_Z_DIGEST, ERR_R_MALLOC_FAILURE);
+        goto done;
+    }
+
+    if (BN_bn2binpad(a, buf, p_bytes) < 0
+            || !EVP_DigestUpdate(hash, buf, p_bytes)
+            || BN_bn2binpad(b, buf, p_bytes) < 0
+            || !EVP_DigestUpdate(hash, buf, p_bytes)
+            || !EC_POINT_get_affine_coordinates(group,
+                                                EC_GROUP_get0_generator(group),
+                                                xG, yG, ctx)
+            || BN_bn2binpad(xG, buf, p_bytes) < 0
+            || !EVP_DigestUpdate(hash, buf, p_bytes)
+            || BN_bn2binpad(yG, buf, p_bytes) < 0
+            || !EVP_DigestUpdate(hash, buf, p_bytes)
+            || !EC_POINT_get_affine_coordinates(group,
+                                                EC_KEY_get0_public_key(key),
+                                                xA, yA, ctx)
+            || BN_bn2binpad(xA, buf, p_bytes) < 0
+            || !EVP_DigestUpdate(hash, buf, p_bytes)
+            || BN_bn2binpad(yA, buf, p_bytes) < 0
+            || !EVP_DigestUpdate(hash, buf, p_bytes)
+            || !EVP_DigestFinal(hash, out, NULL)) {
+        SM2err(SM2_F_SM2_COMPUTE_Z_DIGEST, ERR_R_INTERNAL_ERROR);
+        goto done;
+    }
+
+    rc = 1;
+
+ done:
+    OPENSSL_free(buf);
+    BN_CTX_free(ctx);
+    EVP_MD_CTX_free(hash);
+    return rc;
+}
+
 static BIGNUM *sm2_compute_msg_hash(const EVP_MD *digest,
                                     const EC_KEY *key,
-                                    const char *user_id,
+                                    const uint8_t *id,
+                                    const size_t id_len,
                                     const uint8_t *msg, size_t msg_len)
 {
     EVP_MD_CTX *hash = EVP_MD_CTX_new();
     const int md_size = EVP_MD_size(digest);
-    uint8_t *za = NULL;
+    uint8_t *z = NULL;
     BIGNUM *e = NULL;
 
     if (md_size < 0) {
@@ -33,32 +151,32 @@ static BIGNUM *sm2_compute_msg_hash(const EVP_MD *digest,
         goto done;
     }
 
-    za = OPENSSL_zalloc(md_size);
-    if (hash == NULL || za == NULL) {
+    z = OPENSSL_zalloc(md_size);
+    if (hash == NULL || z == NULL) {
         SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_MALLOC_FAILURE);
         goto done;
     }
 
-    if (!sm2_compute_userid_digest(za, digest, user_id, key)) {
+    if (!sm2_compute_z_digest(z, digest, id, id_len, key)) {
         /* SM2err already called */
         goto done;
     }
 
     if (!EVP_DigestInit(hash, digest)
-            || !EVP_DigestUpdate(hash, za, md_size)
+            || !EVP_DigestUpdate(hash, z, md_size)
             || !EVP_DigestUpdate(hash, msg, msg_len)
-               /* reuse za buffer to hold H(ZA || M) */
-            || !EVP_DigestFinal(hash, za, NULL)) {
+               /* reuse z buffer to hold H(Z || M) */
+            || !EVP_DigestFinal(hash, z, NULL)) {
         SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_EVP_LIB);
         goto done;
     }
 
-    e = BN_bin2bn(za, md_size, NULL);
+    e = BN_bin2bn(z, md_size, NULL);
     if (e == NULL)
         SM2err(SM2_F_SM2_COMPUTE_MSG_HASH, ERR_R_INTERNAL_ERROR);
 
  done:
-    OPENSSL_free(za);
+    OPENSSL_free(z);
     EVP_MD_CTX_free(hash);
     return e;
 }
@@ -85,7 +203,6 @@ static ECDSA_SIG *sm2_sig_gen(const EC_KEY *key, const BIGNUM *e)
         goto done;
     }
 
-
     BN_CTX_start(ctx);
     k = BN_CTX_get(ctx);
     rk = BN_CTX_get(ctx);
@@ -116,7 +233,7 @@ static ECDSA_SIG *sm2_sig_gen(const EC_KEY *key, const BIGNUM *e)
 
         if (!EC_POINT_mul(group, kG, k, NULL, NULL, ctx)
                 || !EC_POINT_get_affine_coordinates(group, kG, x1, NULL,
-                                                        ctx)
+                                                    ctx)
                 || !BN_mod_add(r, e, x1, order, ctx)) {
             SM2err(SM2_F_SM2_SIG_GEN, ERR_R_INTERNAL_ERROR);
             goto done;
@@ -245,12 +362,14 @@ static int sm2_sig_verify(const EC_KEY *key, const ECDSA_SIG *sig,
 
 ECDSA_SIG *sm2_do_sign(const EC_KEY *key,
                        const EVP_MD *digest,
-                       const char *user_id, const uint8_t *msg, size_t msg_len)
+                       const uint8_t *id,
+                       const size_t id_len,
+                       const uint8_t *msg, size_t msg_len)
 {
     BIGNUM *e = NULL;
     ECDSA_SIG *sig = NULL;
 
-    e = sm2_compute_msg_hash(digest, key, user_id, msg, msg_len);
+    e = sm2_compute_msg_hash(digest, key, id, id_len, msg, msg_len);
     if (e == NULL) {
         /* SM2err already called */
         goto done;
@@ -266,12 +385,14 @@ ECDSA_SIG *sm2_do_sign(const EC_KEY *key,
 int sm2_do_verify(const EC_KEY *key,
                   const EVP_MD *digest,
                   const ECDSA_SIG *sig,
-                  const char *user_id, const uint8_t *msg, size_t msg_len)
+                  const uint8_t *id,
+                  const size_t id_len,
+                  const uint8_t *msg, size_t msg_len)
 {
     BIGNUM *e = NULL;
     int ret = 0;
 
-    e = sm2_compute_msg_hash(digest, key, user_id, msg, msg_len);
+    e = sm2_compute_msg_hash(digest, key, id, id_len, msg, msg_len);
     if (e == NULL) {
         /* SM2err already called */
         goto done;
diff --git a/crypto/sm2/sm2_za.c b/crypto/sm2/sm2_za.c
deleted file mode 100644
index 320bee1..0000000
--- a/crypto/sm2/sm2_za.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
- * Copyright 2017 Ribose Inc. All Rights Reserved.
- * Ported from Ribose contributions from Botan.
- *
- * Licensed under the OpenSSL license (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/sm2.h"
-#include "internal/sm2err.h"
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/bn.h>
-#include <string.h>
-#include "internal/numbers.h"
-
-int sm2_compute_userid_digest(uint8_t *out,
-                              const EVP_MD *digest,
-                              const char *user_id,
-                              const EC_KEY *key)
-{
-    int rc = 0;
-    const EC_GROUP *group = EC_KEY_get0_group(key);
-    BN_CTX *ctx = NULL;
-    EVP_MD_CTX *hash = NULL;
-    BIGNUM *p = NULL;
-    BIGNUM *a = NULL;
-    BIGNUM *b = NULL;
-    BIGNUM *xG = NULL;
-    BIGNUM *yG = NULL;
-    BIGNUM *xA = NULL;
-    BIGNUM *yA = NULL;
-    int p_bytes = 0;
-    uint8_t *buf = NULL;
-    size_t uid_len = 0;
-    uint16_t entla = 0;
-    uint8_t e_byte = 0;
-
-    hash = EVP_MD_CTX_new();
-    ctx = BN_CTX_new();
-    if (hash == NULL || ctx == NULL) {
-        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_MALLOC_FAILURE);
-        goto done;
-    }
-
-    p = BN_CTX_get(ctx);
-    a = BN_CTX_get(ctx);
-    b = BN_CTX_get(ctx);
-    xG = BN_CTX_get(ctx);
-    yG = BN_CTX_get(ctx);
-    xA = BN_CTX_get(ctx);
-    yA = BN_CTX_get(ctx);
-
-    if (yA == NULL) {
-        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_MALLOC_FAILURE);
-        goto done;
-    }
-
-    if (!EVP_DigestInit(hash, digest)) {
-        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_EVP_LIB);
-        goto done;
-    }
-
-    /* ZA = H256(ENTLA || IDA || a || b || xG || yG || xA || yA) */
-
-    uid_len = strlen(user_id);
-    if (uid_len >= (UINT16_MAX / 8)) {
-        /* too large */
-        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, SM2_R_USER_ID_TOO_LARGE);
-        goto done;
-    }
-
-    entla = (uint16_t)(8 * uid_len);
-
-    e_byte = entla >> 8;
-    if (!EVP_DigestUpdate(hash, &e_byte, 1)) {
-        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_EVP_LIB);
-        goto done;
-    }
-    e_byte = entla & 0xFF;
-    if (!EVP_DigestUpdate(hash, &e_byte, 1)
-            || !EVP_DigestUpdate(hash, user_id, uid_len)) {
-        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_EVP_LIB);
-        goto done;
-    }
-
-    if (!EC_GROUP_get_curve(group, p, a, b, ctx)) {
-        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_EC_LIB);
-        goto done;
-    }
-
-    p_bytes = BN_num_bytes(p);
-    buf = OPENSSL_zalloc(p_bytes);
-    if (buf == NULL) {
-        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_MALLOC_FAILURE);
-        goto done;
-    }
-
-    if (BN_bn2binpad(a, buf, p_bytes) < 0
-            || !EVP_DigestUpdate(hash, buf, p_bytes)
-            || BN_bn2binpad(b, buf, p_bytes) < 0
-            || !EVP_DigestUpdate(hash, buf, p_bytes)
-            || !EC_POINT_get_affine_coordinates(group,
-                                                EC_GROUP_get0_generator(group),
-                                                xG, yG, ctx)
-            || BN_bn2binpad(xG, buf, p_bytes) < 0
-            || !EVP_DigestUpdate(hash, buf, p_bytes)
-            || BN_bn2binpad(yG, buf, p_bytes) < 0
-            || !EVP_DigestUpdate(hash, buf, p_bytes)
-            || !EC_POINT_get_affine_coordinates(group,
-                                                EC_KEY_get0_public_key(key),
-                                                xA, yA, ctx)
-            || BN_bn2binpad(xA, buf, p_bytes) < 0
-            || !EVP_DigestUpdate(hash, buf, p_bytes)
-            || BN_bn2binpad(yA, buf, p_bytes) < 0
-            || !EVP_DigestUpdate(hash, buf, p_bytes)
-            || !EVP_DigestFinal(hash, out, NULL)) {
-        SM2err(SM2_F_SM2_COMPUTE_USERID_DIGEST, ERR_R_INTERNAL_ERROR);
-        goto done;
-    }
-
-    rc = 1;
-
- done:
-    OPENSSL_free(buf);
-    BN_CTX_free(ctx);
-    EVP_MD_CTX_free(hash);
-    return rc;
-}
diff --git a/doc/man3/EVP_DigestInit.pod b/doc/man3/EVP_DigestInit.pod
index 67f4f02..0fedd17 100644
--- a/doc/man3/EVP_DigestInit.pod
+++ b/doc/man3/EVP_DigestInit.pod
@@ -11,7 +11,8 @@ EVP_MD_block_size, EVP_MD_CTX_md, EVP_MD_CTX_size,
 EVP_MD_CTX_block_size, EVP_MD_CTX_type, EVP_MD_CTX_md_data,
 EVP_md_null,
 EVP_get_digestbyname, EVP_get_digestbynid,
-EVP_get_digestbyobj - EVP digest routines
+EVP_get_digestbyobj,
+EVP_MD_CTX_set_pkey_ctx - EVP digest routines
 
 =head1 SYNOPSIS
 
@@ -54,6 +55,8 @@ EVP_get_digestbyobj - EVP digest routines
  const EVP_MD *EVP_get_digestbynid(int type);
  const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *o);
 
+ void EVP_MD_CTX_set_pkey_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pctx);
+
 =head1 DESCRIPTION
 
 The EVP digest routines are a high level interface to message digests,
@@ -179,6 +182,15 @@ EVP_get_digestbyobj()
 Returns an B<EVP_MD> structure when passed a digest name, a digest B<NID> or an
 B<ASN1_OBJECT> structure respectively.
 
+=item EVP_MD_CTX_set_pkey_ctx()
+
+Assigns an B<EVP_PKEY_CTX> to B<EVP_MD_CTX>. This is usually used to provide
+a customzied B<EVP_PKEY_CTX> to L<EVP_DigestSignInit(3)> or
+L<EVP_DigestVerifyInit(3)>. The B<pctx> passed to this function should be freed
+by the caller. A NULL B<pctx> pointer is also allowed to clear the B<EVP_PKEY_CTX>
+assigned to B<ctx>. In such case, freeing the cleared B<EVP_PKEY_CTX> or not
+depends on how the B<EVP_PKEY_CTX> is created.
+
 =back
 
 =head1 FLAGS
@@ -256,6 +268,10 @@ EVP_get_digestbyobj()
 
 Returns either an B<EVP_MD> structure or NULL if an error occurs.
 
+=item EVP_MD_CTX_set_pkey_ctx()
+
+This function has no return value.
+
 =back
 
 =head1 NOTES
@@ -360,6 +376,8 @@ later, so now EVP_sha1() can be used with RSA and DSA.
 
 EVP_dss1() was removed in OpenSSL 1.1.0.
 
+EVP_MD_CTX_set_pkey_ctx() was added in 1.1.1.
+
 =head1 COPYRIGHT
 
 Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man3/EVP_DigestSignInit.pod b/doc/man3/EVP_DigestSignInit.pod
index fe2be7b..773de87 100644
--- a/doc/man3/EVP_DigestSignInit.pod
+++ b/doc/man3/EVP_DigestSignInit.pod
@@ -28,8 +28,15 @@ EVP_MD_CTX_new() before calling this function. If B<pctx> is not NULL, the
 EVP_PKEY_CTX of the signing operation will be written to B<*pctx>: this can
 be used to set alternative signing options. Note that any existing value in
 B<*pctx> is overwritten. The EVP_PKEY_CTX value returned must not be freed
-directly by the application (it will be freed automatically when the EVP_MD_CTX
-is freed). The digest B<type> may be NULL if the signing algorithm supports it.
+directly by the application if B<ctx> is not assigned an EVP_PKEY_CTX value before
+being passed to EVP_DigestSignInit() (which means the EVP_PKEY_CTX is created
+inside EVP_DigestSignInit() and it will be freed automatically when the
+EVP_MD_CTX is freed).
+
+The digest B<type> may be NULL if the signing algorithm supports it.
+
+No B<EVP_PKEY_CTX> will be created by EVP_DigsetSignInit() if the passed B<ctx>
+has already been assigned one via L<EVP_MD_CTX_set_ctx(3)>. See also L<SM2(7)>.
 
 Only EVP_PKEY types that support signing can be used with these functions. This
 includes MAC algorithms where the MAC generation is considered as a form of
diff --git a/doc/man3/EVP_DigestVerifyInit.pod b/doc/man3/EVP_DigestVerifyInit.pod
index 0d25deb..e93ac2e 100644
--- a/doc/man3/EVP_DigestVerifyInit.pod
+++ b/doc/man3/EVP_DigestVerifyInit.pod
@@ -26,10 +26,15 @@ B<type> from ENGINE B<e> and public key B<pkey>. B<ctx> must be created
 with EVP_MD_CTX_new() before calling this function. If B<pctx> is not NULL, the
 EVP_PKEY_CTX of the verification operation will be written to B<*pctx>: this
 can be used to set alternative verification options. Note that any existing
-value in B<*pctx> is overwritten. The EVP_PKEY_CTX value returned must not be
-freed directly by the application (it will be freed automatically when the
+value in B<*pctx> is overwritten. The EVP_PKEY_CTX value returned must not be freed
+directly by the application if B<ctx> is not assigned an EVP_PKEY_CTX value before
+being passed to EVP_DigestSignInit() (which means the EVP_PKEY_CTX is created
+inside EVP_DigestSignInit() and it will be freed automatically when the
 EVP_MD_CTX is freed).
 
+No B<EVP_PKEY_CTX> will be created by EVP_DigsetSignInit() if the passed B<ctx>
+has already been assigned one via L<EVP_MD_CTX_set_ctx(3)>. See also L<SM2(7)>.
+
 EVP_DigestVerifyUpdate() hashes B<cnt> bytes of data at B<d> into the
 verification context B<ctx>. This function can be called several times on the
 same B<ctx> to include additional data. This function is currently implemented
diff --git a/doc/man3/EVP_PKEY_CTX_ctrl.pod b/doc/man3/EVP_PKEY_CTX_ctrl.pod
index 7eb9796..e1a107c 100644
--- a/doc/man3/EVP_PKEY_CTX_ctrl.pod
+++ b/doc/man3/EVP_PKEY_CTX_ctrl.pod
@@ -17,7 +17,9 @@ EVP_PKEY_CTX_set_dh_paramgen_generator,
 EVP_PKEY_CTX_set_dh_pad,
 EVP_PKEY_CTX_set_dh_nid,
 EVP_PKEY_CTX_set_ec_paramgen_curve_nid,
-EVP_PKEY_CTX_set_ec_param_enc - algorithm specific control operations
+EVP_PKEY_CTX_set_ec_param_enc,
+EVP_PKEY_CTX_set1_id, EVP_PKEY_CTX_get1_id, EVP_PKEY_CTX_get1_id_len
+- algorithm specific control operations
 
 =head1 SYNOPSIS
 
@@ -53,6 +55,10 @@ EVP_PKEY_CTX_set_ec_param_enc - algorithm specific control operations
  int EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid);
  int EVP_PKEY_CTX_set_ec_param_enc(EVP_PKEY_CTX *ctx, int param_enc);
 
+ int EVP_PKEY_CTX_set1_id(EVP_PKEY_CTX *ctx, void *id, size_t id_len);
+ int EVP_PKEY_CTX_get1_id(EVP_PKEY_CTX *ctx, void *id);
+ int EVP_PKEY_CTX_get1_id_len(EVP_PKEY_CTX *ctx, size_t *id_len);
+
 =head1 DESCRIPTION
 
 The function EVP_PKEY_CTX_ctrl() sends a control operation to the context
@@ -160,6 +166,17 @@ For maximum compatibility the named curve form should be used. Note: the
 B<OPENSSL_EC_NAMED_CURVE> value was only added to OpenSSL 1.1.0; previous
 versions should use 0 instead.
 
+The EVP_PKEY_CTX_set1_id(), EVP_PKEY_CTX_get1_id() and EVP_PKEY_CTX_get1_id_len()
+macros are used to manipulate the special identifier field for specific signature
+algorithms such as SM2. The EVP_PKEY_CTX_set1_id() sets an ID pointed by B<id> with
+the length B<id_len> to the library. The library takes a copy of the id so that
+the caller can safely free the original memory pointed to by B<id>. The
+EVP_PKEY_CTX_get1_id_len() macro returns the length of the ID set via a previous
+call to EVP_PKEY_CTX_set1_id(). The length is usually used to allocate adequate
+memory for further calls to EVP_PKEY_CTX_get1_id(). The EVP_PKEY_CTX_get1_id()
+macro returns the previously set ID value to caller in B<id>. The caller should
+allocate adequate memory space for the B<id> before calling EVP_PKEY_CTX_get1_id().
+
 =head1 RETURN VALUES
 
 EVP_PKEY_CTX_ctrl() and its macros return a positive value for success and 0
@@ -179,7 +196,8 @@ L<EVP_PKEY_keygen(3)>
 
 =head1 HISTORY
 
-These functions were first added to OpenSSL 1.0.0.
+EVP_PKEY_CTX_set1_id(), EVP_PKEY_CTX_get1_id() and EVP_PKEY_CTX_get1_id_len()
+macros were added in 1.1.1, other functions were first added to OpenSSL 1.0.0.
 
 =head1 COPYRIGHT
 
diff --git a/doc/man3/EVP_PKEY_meth_new.pod b/doc/man3/EVP_PKEY_meth_new.pod
index ddc99d2..db803fc 100644
--- a/doc/man3/EVP_PKEY_meth_new.pod
+++ b/doc/man3/EVP_PKEY_meth_new.pod
@@ -10,12 +10,14 @@ EVP_PKEY_meth_set_verify, EVP_PKEY_meth_set_verify_recover, EVP_PKEY_meth_set_si
 EVP_PKEY_meth_set_verifyctx, EVP_PKEY_meth_set_encrypt, EVP_PKEY_meth_set_decrypt,
 EVP_PKEY_meth_set_derive, EVP_PKEY_meth_set_ctrl, EVP_PKEY_meth_set_check,
 EVP_PKEY_meth_set_public_check, EVP_PKEY_meth_set_param_check,
+EVP_PKEY_meth_set_digest_custom,
 EVP_PKEY_meth_get_init, EVP_PKEY_meth_get_copy, EVP_PKEY_meth_get_cleanup,
 EVP_PKEY_meth_get_paramgen, EVP_PKEY_meth_get_keygen, EVP_PKEY_meth_get_sign,
 EVP_PKEY_meth_get_verify, EVP_PKEY_meth_get_verify_recover, EVP_PKEY_meth_get_signctx,
 EVP_PKEY_meth_get_verifyctx, EVP_PKEY_meth_get_encrypt, EVP_PKEY_meth_get_decrypt,
 EVP_PKEY_meth_get_derive, EVP_PKEY_meth_get_ctrl, EVP_PKEY_meth_get_check,
 EVP_PKEY_meth_get_public_check, EVP_PKEY_meth_get_param_check,
+EVP_PKEY_meth_get_digest_custom,
 EVP_PKEY_meth_remove
 - manipulating EVP_PKEY_METHOD structure
 
@@ -116,6 +118,9 @@ EVP_PKEY_meth_remove
                                      int (*check) (EVP_PKEY *pkey));
  void EVP_PKEY_meth_set_param_check(EVP_PKEY_METHOD *pmeth,
                                     int (*check) (EVP_PKEY *pkey));
+ void EVP_PKEY_meth_set_digest_custom(EVP_PKEY_METHOD *pmeth,
+                                     int (*digest_custom) (EVP_PKEY_CTX *ctx,
+                                                           EVP_MD_CTX *mctx));
 
  void EVP_PKEY_meth_get_init(const EVP_PKEY_METHOD *pmeth,
                              int (**pinit) (EVP_PKEY_CTX *ctx));
@@ -201,6 +206,9 @@ EVP_PKEY_meth_remove
                                      int (**pcheck) (EVP_PKEY *pkey));
  void EVP_PKEY_meth_get_param_check(const EVP_PKEY_METHOD *pmeth,
                                     int (**pcheck) (EVP_PKEY *pkey));
+ void EVP_PKEY_meth_get_digest_custom(EVP_PKEY_METHOD *pmeth,
+                                     int (**pdigest_custom) (EVP_PKEY_CTX *ctx,
+                                                             EVP_MD_CTX *mctx));
 
 =head1 DESCRIPTION
 
@@ -334,6 +342,15 @@ key-pair, the public component and parameters respectively for a given B<pkey>.
 They could be called by L<EVP_PKEY_check(3)>, L<EVP_PKEY_public_check(3)> and
 L<EVP_PKEY_param_check(3)> respectively.
 
+ int (*digest_custom) (EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
+
+The digest_custom() method is used to generate customized digest content before
+the real message is passed to functions like L<EVP_DigestSignUpdate(3)> or
+L<EVP_DigestVerifyInit(3)>. This is usually required by some public key
+signature algorithms like SM2 which requires a hashed prefix to the message to
+be signed. The digest_custom() function will be called by L<EVP_DigestSignInit(3)>
+and L<EVP_DigestVerifyInit(3)>.
+
 =head2 Functions
 
 EVP_PKEY_meth_new() creates and returns a new B<EVP_PKEY_METHOD> object,
diff --git a/doc/man7/SM2.pod b/doc/man7/SM2.pod
new file mode 100644
index 0000000..029dc73
--- /dev/null
+++ b/doc/man7/SM2.pod
@@ -0,0 +1,79 @@
+=pod
+
+=head1 NAME
+
+SM2 - Chinese SM2 signature and encryption algorithm support
+
+=head1 DESCRIPTION
+
+The B<SM2> algorithm was first defined by the Chinese national standard GM/T
+0003-2012 and was later standardized by ISO as ISO/IEC 14888. B<SM2> is actually
+an elliptic curve based algorithm. The current implementation in OpenSSL supports
+both signature and encryption schemes via the EVP interface.
+
+When doing the B<SM2> signature algorithm, it requires a distinguishing identifier
+to form the message prefix which is hashed before the real message is hashed.
+
+=head1 NOTES
+
+B<SM2> signatures can be generated by using the 'DigestSign' series of APIs, for
+instance, EVP_DigestSignInit(), EVP_DigestSignUpdate() and EVP_DigestSignFinal().
+Ditto for the verification process by calling the 'DigestVerify' series of APIs.
+
+There are several special steps that need to be done before computing an B<SM2>
+signature.
+
+The B<EVP_PKEY> structure will default to using ECDSA for signatures when it is
+created. It should be set to B<EVP_PKEY_SM2> by calling:
+
+ EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2);
+
+Then an ID should be set by calling:
+
+ EVP_PKEY_CTX_set1_id(pctx, id, id_len);
+
+When calling the EVP_DigestSignInit() or EVP_DigestVerifyInit() functions, a
+pre-allocated B<EVP_PKEY_CTX> should be assigned to the B<EVP_MD_CTX>. This is
+done by calling:
+
+ EVP_MD_CTX_set_pkey_ctx(mctx, pctx);
+
+And normally there is no need to pass a B<pctx> parameter to EVP_DigestSignInit()
+or EVP_DigestVerifyInit() in such a scenario.
+
+=head1 EXAMPLE
+
+This example demonstrates the calling sequence for using an B<EVP_PKEY> to verify
+a message with the SM2 signature algorithm and the SM3 hash algorithm:
+
+ #include <openssl/evp.h>
+
+ /* obtain an EVP_PKEY using whatever methods... */
+ EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2);
+ mctx = EVP_MD_CTX_new();
+ pctx = EVP_PKEY_CTX_new(pkey, NULL);
+ EVP_PKEY_CTX_set1_id(pctx, id, id_len);
+ EVP_MD_CTX_set_pkey_ctx(mctx, pctx);;
+ EVP_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, pkey);
+ EVP_DigestVerifyUpdate(mctx, msg, msg_len);
+ EVP_DigestVerifyFinal(mctx, sig, sig_len)
+
+=head1 SEE ALSO
+
+L<EVP_PKEY_CTX_new(3)>,
+L<EVP_PKEY_set_alias_type(3)>,
+L<EVP_DigestSignInit(3)>,
+L<EVP_DigestVerifyInit(3)>,
+L<EVP_PKEY_CTX_set1_id(3)>,
+L<EVP_MD_CTX_set_pkey_ctx(3)>
+
+=head1 COPYRIGHT
+
+Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (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/include/openssl/ec.h b/include/openssl/ec.h
index 9cbb8b8..4d70da7 100644
--- a/include/openssl/ec.h
+++ b/include/openssl/ec.h
@@ -1429,6 +1429,19 @@ void EC_KEY_METHOD_get_verify(const EC_KEY_METHOD *meth,
                                 EVP_PKEY_OP_DERIVE, \
                                 EVP_PKEY_CTRL_GET_EC_KDF_UKM, 0, (void *)(p))
 
+/* SM2 will skip the operation check so no need to pass operation here */
+# define EVP_PKEY_CTX_set1_id(ctx, id, id_len) \
+        EVP_PKEY_CTX_ctrl(ctx, -1, -1, \
+                                EVP_PKEY_CTRL_SET1_ID, (int)id_len, (void*)(id))
+
+# define EVP_PKEY_CTX_get1_id(ctx, id) \
+        EVP_PKEY_CTX_ctrl(ctx, -1, -1, \
+                                EVP_PKEY_CTRL_GET1_ID, 0, (void*)(id))
+
+# define EVP_PKEY_CTX_get1_id_len(ctx, id_len) \
+        EVP_PKEY_CTX_ctrl(ctx, -1, -1, \
+                                EVP_PKEY_CTRL_GET1_ID_LEN, 0, (void*)(id_len))
+
 # define EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID             (EVP_PKEY_ALG_CTRL + 1)
 # define EVP_PKEY_CTRL_EC_PARAM_ENC                      (EVP_PKEY_ALG_CTRL + 2)
 # define EVP_PKEY_CTRL_EC_ECDH_COFACTOR                  (EVP_PKEY_ALG_CTRL + 3)
@@ -1439,6 +1452,9 @@ void EC_KEY_METHOD_get_verify(const EC_KEY_METHOD *meth,
 # define EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN                 (EVP_PKEY_ALG_CTRL + 8)
 # define EVP_PKEY_CTRL_EC_KDF_UKM                        (EVP_PKEY_ALG_CTRL + 9)
 # define EVP_PKEY_CTRL_GET_EC_KDF_UKM                    (EVP_PKEY_ALG_CTRL + 10)
+# define EVP_PKEY_CTRL_SET1_ID                           (EVP_PKEY_ALG_CTRL + 11)
+# define EVP_PKEY_CTRL_GET1_ID                           (EVP_PKEY_ALG_CTRL + 12)
+# define EVP_PKEY_CTRL_GET1_ID_LEN                       (EVP_PKEY_ALG_CTRL + 13)
 /* KDF types */
 # define EVP_PKEY_ECDH_KDF_NONE                          1
 # define EVP_PKEY_ECDH_KDF_X9_62                         2
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 185cc29..8c80519 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -180,6 +180,7 @@ int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd,
  * if the following flag is set.
  */
 # define EVP_MD_CTX_FLAG_FINALISE        0x0200
+/* NOTE: 0x0400 is reserved for internal usage in evp_int.h */
 
 EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len);
 EVP_CIPHER *EVP_CIPHER_meth_dup(const EVP_CIPHER *cipher);
@@ -453,6 +454,7 @@ void EVP_MD_CTX_set_update_fn(EVP_MD_CTX *ctx,
 # define EVP_MD_CTX_block_size(e)        EVP_MD_block_size(EVP_MD_CTX_md(e))
 # define EVP_MD_CTX_type(e)              EVP_MD_type(EVP_MD_CTX_md(e))
 EVP_PKEY_CTX *EVP_MD_CTX_pkey_ctx(const EVP_MD_CTX *ctx);
+void EVP_MD_CTX_set_pkey_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pctx);
 void *EVP_MD_CTX_md_data(const EVP_MD_CTX *ctx);
 
 int EVP_CIPHER_nid(const EVP_CIPHER *cipher);
@@ -1519,6 +1521,10 @@ void EVP_PKEY_meth_set_public_check(EVP_PKEY_METHOD *pmeth,
 void EVP_PKEY_meth_set_param_check(EVP_PKEY_METHOD *pmeth,
                                    int (*check) (EVP_PKEY *pkey));
 
+void EVP_PKEY_meth_set_digest_custom(EVP_PKEY_METHOD *pmeth,
+                                     int (*digest_custom) (EVP_PKEY_CTX *ctx,
+                                                           EVP_MD_CTX *mctx));
+
 void EVP_PKEY_meth_get_init(const EVP_PKEY_METHOD *pmeth,
                             int (**pinit) (EVP_PKEY_CTX *ctx));
 
@@ -1620,6 +1626,9 @@ void EVP_PKEY_meth_get_public_check(const EVP_PKEY_METHOD *pmeth,
 void EVP_PKEY_meth_get_param_check(const EVP_PKEY_METHOD *pmeth,
                                    int (**pcheck) (EVP_PKEY *pkey));
 
+void EVP_PKEY_meth_get_digest_custom(EVP_PKEY_METHOD *pmeth,
+                                     int (**pdigest_custom) (EVP_PKEY_CTX *ctx,
+                                                             EVP_MD_CTX *mctx));
 void EVP_add_alg_module(void);
 
 
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index 33a957f..f0b0040 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -16,6 +16,7 @@
 #include <openssl/evp.h>
 #include <openssl/rsa.h>
 #include <openssl/x509.h>
+#include <openssl/pem.h>
 #include "testutil.h"
 #include "internal/nelem.h"
 #include "internal/evp_int.h"
@@ -523,6 +524,84 @@ static int test_EVP_PKCS82PKEY(void)
 
 #ifndef OPENSSL_NO_SM2
 
+static int test_EVP_SM2_verify(void)
+{
+    /* From https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02#appendix-A */
+    const char *pubkey =
+       "-----BEGIN PUBLIC KEY-----\n"
+       "MIIBMzCB7AYHKoZIzj0CATCB4AIBATAsBgcqhkjOPQEBAiEAhULWnkwETxjouSQ1\n"
+       "v2/33kVyg5FcRVF9ci7biwjx38MwRAQgeHlotPoyw/0kF4Quc7v+/y88hItoMdfg\n"
+       "7GUiizk35JgEIGPkxtOyOwyEnPhCQUhL/kj2HVmlsWugbm4S0donxSSaBEEEQh3r\n"
+       "1hti6rZ0ZDTrw8wxXjIiCzut1QvcTE5sFH/t1D0GgFEry7QsB9RzSdIVO3DE5df9\n"
+       "/L+jbqGoWEG55G4JogIhAIVC1p5MBE8Y6LkkNb9v990pdyBjBIVijVrnTufDLnm3\n"
+       "AgEBA0IABArkx3mKoPEZRxvuEYJb5GICu3nipYRElel8BP9N8lSKfAJA+I8c1OFj\n"
+       "Uqc8F7fxbwc1PlOhdtaEqf4Ma7eY6Fc=\n"
+       "-----END PUBLIC KEY-----\n";
+
+    const char *msg = "message digest";
+    const char *id = "ALICE123 at YAHOO.COM";
+
+    const uint8_t signature[] = {
+       0x30, 0x44, 0x02, 0x20,
+
+       0x40, 0xF1, 0xEC, 0x59, 0xF7, 0x93, 0xD9, 0xF4, 0x9E, 0x09, 0xDC,
+       0xEF, 0x49, 0x13, 0x0D, 0x41, 0x94, 0xF7, 0x9F, 0xB1, 0xEE, 0xD2,
+       0xCA, 0xA5, 0x5B, 0xAC, 0xDB, 0x49, 0xC4, 0xE7, 0x55, 0xD1,
+
+       0x02, 0x20,
+
+       0x6F, 0xC6, 0xDA, 0xC3, 0x2C, 0x5D, 0x5C, 0xF1, 0x0C, 0x77, 0xDF,
+       0xB2, 0x0F, 0x7C, 0x2E, 0xB6, 0x67, 0xA4, 0x57, 0x87, 0x2F, 0xB0,
+       0x9E, 0xC5, 0x63, 0x27, 0xA6, 0x7E, 0xC7, 0xDE, 0xEB, 0xE7
+    };
+
+    int rc = 0;
+    BIO *bio = NULL;
+    EVP_PKEY *pkey = NULL;
+    EVP_MD_CTX *mctx = NULL;
+    EVP_PKEY_CTX *pctx = NULL;
+
+    bio = BIO_new_mem_buf(pubkey, strlen(pubkey));
+    if (!TEST_true(bio != NULL))
+        goto done;
+
+    pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
+    if (!TEST_true(pkey != NULL))
+        goto done;
+
+    if (!TEST_true(EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)))
+        goto done;
+
+    if (!TEST_ptr(mctx = EVP_MD_CTX_new()))
+        goto done;
+
+    if (!TEST_ptr(pctx = EVP_PKEY_CTX_new(pkey, NULL)))
+        goto done;
+
+    if (!TEST_int_gt(EVP_PKEY_CTX_set1_id(pctx, (const uint8_t *)id,
+                                          strlen(id)), 0))
+        goto done;
+
+    EVP_MD_CTX_set_pkey_ctx(mctx, pctx);
+
+    if (!TEST_true(EVP_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, pkey)))
+        goto done;
+
+    if (!TEST_true(EVP_DigestVerifyUpdate(mctx, msg, strlen(msg))))
+        goto done;
+
+    if (!TEST_true(EVP_DigestVerifyFinal(mctx, signature, sizeof(signature))))
+        goto done;
+    rc = 1;
+
+ done:
+    BIO_free(bio);
+    EVP_PKEY_free(pkey);
+    EVP_PKEY_CTX_free(pctx);
+    EVP_MD_CTX_free(mctx);
+    return rc;
+}
+
 static int test_EVP_SM2(void)
 {
     int ret = 0;
@@ -530,6 +609,7 @@ static int test_EVP_SM2(void)
     EVP_PKEY *params = NULL;
     EVP_PKEY_CTX *pctx = NULL;
     EVP_PKEY_CTX *kctx = NULL;
+    EVP_PKEY_CTX *sctx = NULL;
     size_t sig_len = 0;
     unsigned char *sig = NULL;
     EVP_MD_CTX *md_ctx = NULL;
@@ -542,6 +622,8 @@ static int test_EVP_SM2(void)
     uint8_t plaintext[8];
     size_t ptext_len = sizeof(plaintext);
 
+    uint8_t sm2_id[] = {1, 2, 3, 4, 'l', 'e', 't', 't', 'e', 'r'};
+
     pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
     if (!TEST_ptr(pctx))
         goto done;
@@ -574,6 +656,15 @@ static int test_EVP_SM2(void)
     if (!TEST_ptr(md_ctx_verify = EVP_MD_CTX_new()))
         goto done;
 
+    if (!TEST_ptr(sctx = EVP_PKEY_CTX_new(pkey, NULL)))
+        goto done;
+
+    EVP_MD_CTX_set_pkey_ctx(md_ctx, sctx);
+    EVP_MD_CTX_set_pkey_ctx(md_ctx_verify, sctx);
+
+    if (!TEST_int_gt(EVP_PKEY_CTX_set1_id(sctx, sm2_id, sizeof(sm2_id)), 0))
+        goto done;
+
     if (!TEST_true(EVP_DigestSignInit(md_ctx, NULL, EVP_sm3(), NULL, pkey)))
         goto done;
 
@@ -631,6 +722,7 @@ static int test_EVP_SM2(void)
 done:
     EVP_PKEY_CTX_free(pctx);
     EVP_PKEY_CTX_free(kctx);
+    EVP_PKEY_CTX_free(sctx);
     EVP_PKEY_CTX_free(cctx);
     EVP_PKEY_free(pkey);
     EVP_PKEY_free(params);
@@ -832,6 +924,7 @@ int setup_tests(void)
 #endif
 #ifndef OPENSSL_NO_SM2
     ADD_TEST(test_EVP_SM2);
+    ADD_TEST(test_EVP_SM2_verify);
 #endif
     ADD_ALL_TESTS(test_set_get_raw_keys, OSSL_NELEM(keys));
     custom_pmeth = EVP_PKEY_meth_new(0xdefaced, 0);
diff --git a/test/sm2_internal_test.c b/test/sm2_internal_test.c
index 0d145e8..015fa85 100644
--- a/test/sm2_internal_test.c
+++ b/test/sm2_internal_test.c
@@ -294,7 +294,8 @@ static int test_sm2_sign(const EC_GROUP *group,
         goto done;
 
     start_fake_rand(k_hex);
-    sig = sm2_do_sign(key, EVP_sm3(), userid, (const uint8_t *)message, msg_len);
+    sig = sm2_do_sign(key, EVP_sm3(), (const uint8_t *)userid, strlen(userid),
+                      (const uint8_t *)message, msg_len);
     if (!TEST_ptr(sig)
             || !TEST_size_t_eq(fake_rand_bytes_offset, fake_rand_size)) {
         restore_rand();
@@ -310,8 +311,8 @@ static int test_sm2_sign(const EC_GROUP *group,
             || !TEST_BN_eq(s, sig_s))
         goto done;
 
-    ok = sm2_do_verify(key, EVP_sm3(), sig, userid, (const uint8_t *)message,
-                       msg_len);
+    ok = sm2_do_verify(key, EVP_sm3(), sig, (const uint8_t *)userid,
+                       strlen(userid), (const uint8_t *)message, msg_len);
 
     /* We goto done whether this passes or fails */
     TEST_true(ok);
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 81171fe..c4460c9 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4574,3 +4574,6 @@ EC_GROUP_set_curve                      4527	1_1_1	EXIST::FUNCTION:EC
 EC_GROUP_get_curve                      4528	1_1_1	EXIST::FUNCTION:EC
 OCSP_resp_get0_tbs_sigalg               4529	1_1_0j	EXIST::FUNCTION:OCSP
 OCSP_resp_get0_respdata                 4530	1_1_0j	EXIST::FUNCTION:OCSP
+EVP_MD_CTX_set_pkey_ctx                 4531	1_1_1	EXIST::FUNCTION:
+EVP_PKEY_meth_set_digest_custom         4532	1_1_1	EXIST::FUNCTION:
+EVP_PKEY_meth_get_digest_custom         4533	1_1_1	EXIST::FUNCTION:
diff --git a/util/private.num b/util/private.num
index b90e33d..0391091 100644
--- a/util/private.num
+++ b/util/private.num
@@ -413,3 +413,6 @@ SSLv23_method                           define
 SSLv23_server_method                    define
 X509_STORE_set_lookup_crls_cb           define
 X509_STORE_set_verify_func              define
+EVP_PKEY_CTX_set1_id                    define
+EVP_PKEY_CTX_get1_id                    define
+EVP_PKEY_CTX_get1_id_len                define


More information about the openssl-commits mailing list