Import regress tests for SM2. Not yet linked to the build.
authortb <tb@openbsd.org>
Wed, 18 Aug 2021 16:06:56 +0000 (16:06 +0000)
committertb <tb@openbsd.org>
Wed, 18 Aug 2021 16:06:56 +0000 (16:06 +0000)
Part of Github PR #105

regress/lib/libcrypto/sm2/Makefile [new file with mode: 0644]
regress/lib/libcrypto/sm2/sm2crypttest.c [new file with mode: 0644]
regress/lib/libcrypto/sm2/sm2evptest.c [new file with mode: 0644]
regress/lib/libcrypto/sm2/sm2sigtest.c [new file with mode: 0644]

diff --git a/regress/lib/libcrypto/sm2/Makefile b/regress/lib/libcrypto/sm2/Makefile
new file mode 100644 (file)
index 0000000..8aa07f7
--- /dev/null
@@ -0,0 +1,23 @@
+#      $OpenBSD: Makefile,v 1.1.1.1 2021/08/18 16:06:56 tb Exp $
+
+PROGS +=       sm2crypttest
+PROGS +=       sm2evptest
+PROGS +=       sm2sigtest
+
+LDADD =                ${CRYPTO_INT}
+DPADD =                ${LIBCRYPTO}
+WARNINGS =     Yes
+
+CFLAGS +=      -DLIBRESSL_INTERNAL -Wundef -Werror
+CFLAGS +=      -I${BSDSRCDIR}/lib/libcrypto/sm2
+CFLAGS +=      -I${BSDSRCDIR}/regress/lib/libssl/unit
+
+.for p in ${PROGS}
+REGRESS_TARGETS += run-$p
+run-$p: $p
+       @echo '\n======== $@ ========'
+       ./$p
+.PHONY: run-$p
+.endfor
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libcrypto/sm2/sm2crypttest.c b/regress/lib/libcrypto/sm2/sm2crypttest.c
new file mode 100644 (file)
index 0000000..30a03b2
--- /dev/null
@@ -0,0 +1,191 @@
+/*     $OpenBSD: sm2crypttest.c,v 1.1.1.1 2021/08/18 16:06:56 tb Exp $ */
+/*
+ * Copyright (c) 2017, 2019 Ribose Inc
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/bn.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#ifdef OPENSSL_NO_SM2
+int main(int argc, char *argv[])
+{
+    printf("No SM2 support\n");
+    return (0);
+}
+#else
+#include <openssl/sm2.h>
+#include "sm2_locl.h"
+
+static EC_GROUP *
+create_EC_group(const char *p_hex, const char *a_hex, const char *b_hex,
+    const char *x_hex, const char *y_hex, const char *order_hex,
+    const char *cof_hex)
+{
+       BIGNUM *p = NULL;
+       BIGNUM *a = NULL;
+       BIGNUM *b = NULL;
+       BIGNUM *g_x = NULL;
+       BIGNUM *g_y = NULL;
+       BIGNUM *order = NULL;
+       BIGNUM *cof = NULL;
+       EC_POINT *generator = NULL;
+       EC_GROUP *group = NULL;
+
+       BN_hex2bn(&p, p_hex);
+       BN_hex2bn(&a, a_hex);
+       BN_hex2bn(&b, b_hex);
+
+       group = EC_GROUP_new_curve_GFp(p, a, b, NULL);
+       BN_free(p);
+       BN_free(a);
+       BN_free(b);
+
+       if (group == NULL)
+               return NULL;
+
+       generator = EC_POINT_new(group);
+       if (generator == NULL)
+               return NULL;
+
+       BN_hex2bn(&g_x, x_hex);
+       BN_hex2bn(&g_y, y_hex);
+
+       if (EC_POINT_set_affine_coordinates(group, generator, g_x, g_y,
+           NULL) == 0)
+               return NULL;
+
+       BN_free(g_x);
+       BN_free(g_y);
+
+       BN_hex2bn(&order, order_hex);
+       BN_hex2bn(&cof, cof_hex);
+
+       if (EC_GROUP_set_generator(group, generator, order, cof) == 0)
+               return NULL;
+
+       EC_POINT_free(generator);
+       BN_free(order);
+       BN_free(cof);
+
+       return group;
+}
+
+static int
+test_sm2(const EC_GROUP *group, const EVP_MD *digest, const char *privkey_hex,
+    const char *message)
+{
+       const size_t msg_len = strlen(message);
+
+       BIGNUM *priv = NULL;
+       EC_KEY *key = NULL;
+       EC_POINT *pt = NULL;
+       size_t ctext_len = 0;
+       uint8_t *ctext = NULL;
+       uint8_t *recovered = NULL;
+       size_t recovered_len = msg_len;
+       int rc = 0;
+
+       BN_hex2bn(&priv, privkey_hex);
+
+       key = EC_KEY_new();
+       EC_KEY_set_group(key, group);
+       EC_KEY_set_private_key(key, priv);
+
+       pt = EC_POINT_new(group);
+       EC_POINT_mul(group, pt, priv, NULL, NULL, NULL);
+
+       EC_KEY_set_public_key(key, pt);
+       BN_free(priv);
+       EC_POINT_free(pt);
+
+       if (!SM2_ciphertext_size(key, digest, msg_len, &ctext_len))
+               goto done;
+       ctext = calloc(1, ctext_len);
+       if (ctext == NULL)
+               goto done;
+
+       rc = SM2_encrypt(key, digest, (const uint8_t *)message, msg_len, ctext, &ctext_len);
+
+       if (rc == 0)
+               goto done;
+
+       recovered = calloc(1, msg_len);
+       if (recovered == NULL)
+               goto done;
+       rc = SM2_decrypt(key, digest, ctext, ctext_len, recovered, &recovered_len);
+
+       if (rc == 0)
+               goto done;
+       if (recovered_len != msg_len)
+               goto done;
+       if (memcmp(recovered, message, msg_len) != 0)
+               goto done;
+
+       rc = 1;
+ done:
+
+       free(ctext);
+       free(recovered);
+       EC_KEY_free(key);
+       return rc;
+}
+
+int
+main(int argc, char **argv)
+{
+       int rc;
+       EC_GROUP *test_group =
+               create_EC_group
+               ("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
+                "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
+                "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
+                "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
+                "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2",
+                "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
+                "1");
+
+       if (test_group == NULL)
+               return 1;
+
+       rc = test_sm2(test_group, EVP_sm3(),
+           "1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0",
+           "encryption standard");
+
+       if (rc == 0)
+               return 1;
+
+       /* Same test as above except using SHA-256 instead of SM3 */
+       rc = test_sm2(test_group, EVP_sha256(),
+           "1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0",
+           "encryption standard");
+       if (rc == 0)
+               return 1;
+
+       EC_GROUP_free(test_group);
+
+       printf("SUCCESS\n");
+
+       return 0;
+}
+
+#endif
diff --git a/regress/lib/libcrypto/sm2/sm2evptest.c b/regress/lib/libcrypto/sm2/sm2evptest.c
new file mode 100644 (file)
index 0000000..9302461
--- /dev/null
@@ -0,0 +1,256 @@
+/*     $OpenBSD: sm2evptest.c,v 1.1.1.1 2021/08/18 16:06:56 tb Exp $ */
+/*
+ * Copyright (c) 2017, 2019 Ribose Inc
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+
+#include "tests.h"
+
+#ifdef OPENSSL_NO_SM2
+int
+main(int argc, char *argv[])
+{
+       printf("No SM2 support\n");
+       return (0);
+}
+#else
+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 *input = "message digest";
+       const char *user_id = "ALICE123@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 *bufio = NULL;
+       EVP_PKEY *pkey = NULL;
+       EVP_MD_CTX *md_ctx_verify = NULL;
+       EVP_PKEY_CTX *verify_ctx = NULL;
+
+       bufio = BIO_new_mem_buf(pubkey, strlen(pubkey));
+       CHECK_GOTO(bufio != NULL);
+
+       pkey = PEM_read_bio_PUBKEY(bufio, NULL, NULL, NULL);
+       CHECK_GOTO(pkey != NULL);
+
+       CHECK_GOTO(EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2));
+
+       md_ctx_verify = EVP_MD_CTX_new();
+       CHECK_GOTO(md_ctx_verify != NULL);
+
+       CHECK_GOTO(EVP_DigestVerifyInit(md_ctx_verify, &verify_ctx, EVP_sm3(), NULL, pkey));
+
+       CHECK_GOTO(EVP_PKEY_CTX_set_sm2_uid(verify_ctx, user_id, strlen(user_id)) > 0);
+
+       CHECK_GOTO(EVP_PKEY_CTX_hash_sm2_uid(verify_ctx) > 0);
+
+       CHECK_GOTO(EVP_DigestVerifyUpdate(md_ctx_verify, input, strlen(input)));
+
+       CHECK_GOTO(EVP_DigestVerifyFinal(md_ctx_verify, signature, sizeof(signature)));
+
+       rc = 1;
+ err:
+       BIO_free(bufio);
+       EVP_PKEY_free(pkey);
+       EVP_MD_CTX_free(md_ctx_verify);
+       return rc;
+}
+
+static int
+test_EVP_SM2(void)
+{
+       int ret = 0;
+       EVP_PKEY *pkey = NULL;
+       EVP_PKEY *params = NULL;
+       EVP_PKEY_CTX *pctx = NULL;
+       EVP_PKEY_CTX *sign_ctx = NULL;
+       EVP_PKEY_CTX *verify_ctx = NULL;
+       EVP_PKEY_CTX *kctx = NULL;
+       size_t sig_len = 0;
+       unsigned char *sig = NULL;
+       EVP_MD_CTX *md_ctx = NULL;
+       EVP_MD_CTX *md_ctx_verify = NULL;
+       EVP_PKEY_CTX *cctx = NULL;
+       int useid;
+       const char *uid_str = "nobody@example.com";
+       uint8_t uid_buf[32] = {0};
+       size_t uid_len = 0;
+
+       uint8_t ciphertext[128];
+       size_t ctext_len = sizeof(ciphertext);
+
+       uint8_t plaintext[8];
+       size_t ptext_len = sizeof(plaintext);
+
+       uint8_t kMsg[4] = {1, 2, 3, 4};
+
+       pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+       CHECK_GOTO(pctx != NULL);
+
+       CHECK_GOTO(EVP_PKEY_paramgen_init(pctx) == 1);
+
+       CHECK_GOTO(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_sm2));
+
+       CHECK_GOTO(EVP_PKEY_paramgen(pctx, &params));
+
+       kctx = EVP_PKEY_CTX_new(params, NULL);
+       CHECK_GOTO(kctx != NULL);
+
+       CHECK_GOTO(EVP_PKEY_keygen_init(kctx));
+
+       CHECK_GOTO(EVP_PKEY_keygen(kctx, &pkey));
+
+       CHECK_GOTO(EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2));
+
+       md_ctx = EVP_MD_CTX_new();
+       CHECK_GOTO(md_ctx != NULL);
+
+       md_ctx_verify = EVP_MD_CTX_new();
+       CHECK_GOTO(md_ctx_verify != NULL);
+
+       for (useid = 0; useid <= 1; ++useid) {
+               CHECK_GOTO(EVP_DigestSignInit(md_ctx, &sign_ctx, EVP_sm3(), NULL, pkey));
+
+               if (useid) {
+                       CHECK_GOTO(EVP_PKEY_CTX_set_sm2_uid(sign_ctx, uid_str, strlen(uid_str)) > 0);
+
+                       CHECK_GOTO(EVP_PKEY_CTX_get_sm2_uid_len(sign_ctx, &uid_len) > 0);
+
+                       CHECK_GOTO(uid_len == strlen(uid_str));
+
+                       CHECK_GOTO(EVP_PKEY_CTX_get_sm2_uid(sign_ctx, uid_buf) > 0);
+
+                       CHECK_GOTO(memcmp(uid_buf, uid_str, uid_len) == 0);
+
+                       CHECK_GOTO(EVP_PKEY_CTX_hash_sm2_uid(sign_ctx) > 0);
+               }
+
+               CHECK_GOTO(EVP_DigestSignUpdate(md_ctx, kMsg, sizeof(kMsg)));
+
+               /* Determine the size of the signature. */
+               CHECK_GOTO(EVP_DigestSignFinal(md_ctx, NULL, &sig_len));
+
+               CHECK_GOTO(sig_len == (size_t) EVP_PKEY_size(pkey));
+
+               sig = malloc(sig_len);
+               CHECK_GOTO(sig != NULL);
+
+               CHECK_GOTO(EVP_DigestSignFinal(md_ctx, sig, &sig_len));
+
+               /* Ensure that the signature round-trips. */
+
+               CHECK_GOTO(EVP_DigestVerifyInit(md_ctx_verify, &verify_ctx, EVP_sm3(), NULL, pkey));
+
+               if (useid) {
+                       CHECK_GOTO(EVP_PKEY_CTX_set_sm2_uid(verify_ctx, uid_str, strlen(uid_str)) > 0);
+
+                       CHECK_GOTO(EVP_PKEY_CTX_get_sm2_uid_len(verify_ctx, &uid_len) > 0);
+
+                       CHECK_GOTO(uid_len == strlen(uid_str));
+
+                       CHECK_GOTO(EVP_PKEY_CTX_get_sm2_uid(verify_ctx, uid_buf) > 0);
+
+                       CHECK_GOTO(memcmp(uid_buf, uid_str, uid_len) == 0);
+
+                       CHECK_GOTO(EVP_PKEY_CTX_hash_sm2_uid(verify_ctx) > 0);
+               }
+
+               CHECK_GOTO(EVP_DigestVerifyUpdate(md_ctx_verify, kMsg, sizeof(kMsg)));
+
+               CHECK_GOTO(EVP_DigestVerifyFinal(md_ctx_verify, sig, sig_len));
+
+               free(sig);
+               sig = NULL;
+       }
+
+       /* now check encryption/decryption */
+
+       cctx = EVP_PKEY_CTX_new(pkey, NULL);
+       CHECK_GOTO(cctx != NULL);
+
+       CHECK_GOTO(EVP_PKEY_encrypt_init(cctx));
+
+       CHECK_GOTO(EVP_PKEY_encrypt(cctx, ciphertext, &ctext_len, kMsg, sizeof(kMsg)));
+
+       CHECK_GOTO(EVP_PKEY_decrypt_init(cctx));
+
+       CHECK_GOTO(EVP_PKEY_decrypt(cctx, plaintext, &ptext_len, ciphertext, ctext_len));
+
+       CHECK_GOTO(ptext_len == sizeof(kMsg));
+
+       CHECK_GOTO(memcmp(plaintext, kMsg, sizeof(kMsg)) == 0);
+
+       ret = 1;
+ err:
+       EVP_PKEY_free(params);
+       EVP_MD_CTX_free(md_ctx);
+       EVP_MD_CTX_free(md_ctx_verify);
+       EVP_PKEY_CTX_free(pctx);
+       EVP_PKEY_CTX_free(kctx);
+       EVP_PKEY_CTX_free(cctx);
+       EVP_PKEY_free(pkey);
+       free(sig);
+       return ret;
+}
+
+int
+main(int argc, char *argv[])
+{
+       if (!test_EVP_SM2()) {
+               fprintf(stderr, "test_EVP_SM2() failed.\n");
+               fflush(stderr);
+               return 1;
+       }
+       if (!test_EVP_SM2_verify()) {
+               fprintf(stderr, "test_EVP_SM2_verify() failed.\n");
+               fflush(stderr);
+               return 1;
+       }
+
+       printf("SUCCESS\n");
+
+       return 0;
+}
+
+#endif
diff --git a/regress/lib/libcrypto/sm2/sm2sigtest.c b/regress/lib/libcrypto/sm2/sm2sigtest.c
new file mode 100644 (file)
index 0000000..bd15679
--- /dev/null
@@ -0,0 +1,170 @@
+/*     $OpenBSD: sm2sigtest.c,v 1.1.1.1 2021/08/18 16:06:56 tb Exp $ */
+/*
+ * Copyright (c) 2017, 2019 Ribose Inc
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/bn.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#ifdef OPENSSL_NO_SM2
+int
+main(int argc, char *argv[])
+{
+    printf("No SM2 support\n");
+    return (0);
+}
+#else
+#include <openssl/sm2.h>
+#include "sm2_locl.h"
+
+static EC_GROUP *
+create_EC_group(const char *p_hex, const char *a_hex, const char *b_hex,
+    const char *x_hex, const char *y_hex, const char *order_hex,
+    const char *cof_hex)
+{
+       BIGNUM *p = NULL;
+       BIGNUM *a = NULL;
+       BIGNUM *b = NULL;
+       BIGNUM *g_x = NULL;
+       BIGNUM *g_y = NULL;
+       BIGNUM *order = NULL;
+       BIGNUM *cof = NULL;
+       EC_POINT *generator = NULL;
+       EC_GROUP *group = NULL;
+
+       BN_hex2bn(&p, p_hex);
+       BN_hex2bn(&a, a_hex);
+       BN_hex2bn(&b, b_hex);
+
+       group = EC_GROUP_new_curve_GFp(p, a, b, NULL);
+       BN_free(p);
+       BN_free(a);
+       BN_free(b);
+
+       if (group == NULL)
+               return NULL;
+
+       generator = EC_POINT_new(group);
+       if (generator == NULL)
+               return NULL;
+
+       BN_hex2bn(&g_x, x_hex);
+       BN_hex2bn(&g_y, y_hex);
+
+       if (EC_POINT_set_affine_coordinates(group, generator, g_x, g_y,
+           NULL) == 0)
+               return NULL;
+
+       BN_free(g_x);
+       BN_free(g_y);
+
+       BN_hex2bn(&order, order_hex);
+       BN_hex2bn(&cof, cof_hex);
+
+       if (EC_GROUP_set_generator(group, generator, order, cof) == 0)
+               return NULL;
+
+       EC_POINT_free(generator);
+       BN_free(order);
+       BN_free(cof);
+
+       return group;
+}
+
+
+static int
+test_sm2(const EC_GROUP *group, const char *userid, const char *privkey_hex,
+    const char *message)
+{
+       const size_t msg_len = strlen(message);
+       int ok = -1;
+       BIGNUM *priv = NULL;
+       EC_POINT *pt = NULL;
+       EC_KEY *key = NULL;
+       ECDSA_SIG *sig = NULL;
+       const BIGNUM *sig_r = NULL;
+       const BIGNUM *sig_s = NULL;
+
+       BN_hex2bn(&priv, privkey_hex);
+
+       key = EC_KEY_new();
+       EC_KEY_set_group(key, group);
+       EC_KEY_set_private_key(key, priv);
+
+       pt = EC_POINT_new(group);
+       EC_POINT_mul(group, pt, priv, NULL, NULL, NULL);
+       EC_KEY_set_public_key(key, pt);
+
+       sig = sm2_do_sign(key, EVP_sm3(), userid, strlen(userid),
+           (const uint8_t *)message, msg_len);
+
+       if (sig == NULL)
+               return 0;
+
+       ECDSA_SIG_get0(sig, &sig_r, &sig_s);
+
+       ok = sm2_do_verify(key, EVP_sm3(), sig, userid, strlen(userid),
+           (const uint8_t *)message, msg_len);
+
+       ECDSA_SIG_free(sig);
+       EC_POINT_free(pt);
+       EC_KEY_free(key);
+       BN_free(priv);
+
+       return ok;
+}
+
+int
+main(int argc, char **argv)
+{
+       int rc = 0;
+       /* From draft-shen-sm2-ecdsa-02 */
+       EC_GROUP *test_group =
+               create_EC_group
+               ("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
+                "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
+                "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
+                "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
+                "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2",
+                "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
+                "1");
+
+       if (test_group == NULL)
+               return 1;
+
+       rc = test_sm2(test_group, "ALICE123@YAHOO.COM",
+           "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263",
+           "message digest");
+
+       EC_GROUP_free(test_group);
+
+       if (rc <= 0)
+               return 1;
+
+
+       printf("SUCCESS\n");
+
+       return 0;
+}
+
+#endif