summaryrefslogtreecommitdiff
path: root/feature-add-SMx-support.patch
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2024-07-03 02:42:38 +0000
committerCoprDistGit <infra@openeuler.org>2024-07-03 02:42:38 +0000
commit3c362eae690284f325824e38431881825e32ffdd (patch)
treed2d0e11b92bf88d35c270559d268845d391a4703 /feature-add-SMx-support.patch
parent62f0a34c39a6846b6a86f2bbc7fb8c319bd46d94 (diff)
automatic import of openssh
Diffstat (limited to 'feature-add-SMx-support.patch')
-rw-r--r--feature-add-SMx-support.patch820
1 files changed, 442 insertions, 378 deletions
diff --git a/feature-add-SMx-support.patch b/feature-add-SMx-support.patch
index e8b0f3c..d7fe61c 100644
--- a/feature-add-SMx-support.patch
+++ b/feature-add-SMx-support.patch
@@ -1,7 +1,13 @@
-From d2e28809c673f914b49147ca3fa31e08b9e885d7 Mon Sep 17 00:00:00 2001
-From: renmingshuai <renmingshuai@huawei.com>
-Date: Sat, 29 Jul 2023 10:50:29 +0800
-Subject: [PATCH] feature add sm2
+From 93b312c0263cbf40f66448ff7ddbea7a2def1953 Mon Sep 17 00:00:00 2001
+From: kircher <majun65@huawei.com>
+Date: Fri, 29 Jul 2022 10:45:08 +0800
+Subject: [PATCH] add SMx support in openssh
+HostKeyAlgorithms sm2
+KexAlgorithms sm2-sm3
+MACs hmac-sm3
+Ciphers sm4-ctr
+PubkeyAcceptedAlgorithms sm2
+FingerprintHash sm3
---
Makefile.in | 4 +-
@@ -25,21 +31,21 @@ Subject: [PATCH] feature add sm2
ssh-ecdsa.c | 6 +-
ssh-keygen.c | 12 +-
ssh-keyscan.c | 12 +-
- ssh-sm2.c | 381 ++++++++++++++++++++++++
+ ssh-sm2.c | 230 +++++++++++++++
ssh_api.c | 2 +
sshconnect2.c | 1 +
sshd.c | 7 +
- sshkey.c | 21 ++
- sshkey.h | 2 +
- 27 files changed, 899 insertions(+), 14 deletions(-)
+ sshkey.c | 62 +++-
+ sshkey.h | 9 +
+ 27 files changed, 794 insertions(+), 16 deletions(-)
create mode 100644 kexsm2.c
create mode 100644 ssh-sm2.c
diff --git a/Makefile.in b/Makefile.in
-index 5fec5b3..7dcda3e 100644
+index 07bf440..1393190 100644
--- a/Makefile.in
+++ b/Makefile.in
-@@ -102,14 +102,14 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
+@@ -100,14 +100,14 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
log.o match.o moduli.o nchan.o packet.o \
readpass.o ttymodes.o xmalloc.o addr.o addrmatch.o \
atomicio.o dispatch.o mac.o misc.o utf8.o \
@@ -50,17 +56,17 @@ index 5fec5b3..7dcda3e 100644
ssh-pkcs11.o ssh-pkcs11-uri.o smult_curve25519_ref.o \
poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \
ssh-ed25519.o digest-openssl.o digest-libc.o \
- hmac.o ed25519.o hash.o \
+ hmac.o sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \
- kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
+ kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o kexsm2.o \
kexgexc.o kexgexs.o \
kexsntrup761x25519.o sntrup761.o kexgen.o \
kexgssc.o \
diff --git a/authfd.c b/authfd.c
-index 25a3636..bcc25a7 100644
+index 9f092f7..163b4b5 100644
--- a/authfd.c
+++ b/authfd.c
-@@ -583,6 +583,8 @@ ssh_add_identity_constrained(int sock, struct sshkey *key,
+@@ -512,6 +512,8 @@ ssh_add_identity_constrained(int sock, struct sshkey *key,
case KEY_DSA_CERT:
case KEY_ECDSA:
case KEY_ECDSA_CERT:
@@ -70,10 +76,10 @@ index 25a3636..bcc25a7 100644
case KEY_ECDSA_SK_CERT:
#endif
diff --git a/authfile.c b/authfile.c
-index 445f2dd..3884031 100644
+index 666730b..dce1e84 100644
--- a/authfile.c
+++ b/authfile.c
-@@ -332,6 +332,7 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
+@@ -343,6 +343,7 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
case KEY_RSA:
case KEY_DSA:
case KEY_ECDSA:
@@ -82,10 +88,10 @@ index 445f2dd..3884031 100644
case KEY_ED25519:
case KEY_XMSS:
diff --git a/cipher.c b/cipher.c
-index 609450d..7f98413 100644
+index b54b994..039e414 100644
--- a/cipher.c
+++ b/cipher.c
-@@ -86,6 +86,7 @@ static const struct sshcipher ciphers[] = {
+@@ -88,6 +88,7 @@ static const struct sshcipher ciphers[] = {
#endif
{ "chacha20-poly1305@openssh.com",
8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL },
@@ -120,10 +126,10 @@ index c7ceeb3..520722c 100644
struct sshbuf;
struct ssh_digest_ctx;
diff --git a/kex.c b/kex.c
-index 0fbd0ca..e9dfcc2 100644
+index d0a9dee..6284f90 100644
--- a/kex.c
+++ b/kex.c
-@@ -125,6 +125,7 @@ static const struct kexalg kexalgs[] = {
+@@ -124,6 +124,7 @@ static const struct kexalg kexalgs[] = {
SSH_DIGEST_SHA512 },
#endif
#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
@@ -132,7 +138,7 @@ index 0fbd0ca..e9dfcc2 100644
};
static const struct kexalg gss_kexalgs[] = {
diff --git a/kex.h b/kex.h
-index 0fac9d3..044ec18 100644
+index d26ba26..8b95227 100644
--- a/kex.h
+++ b/kex.h
@@ -102,6 +102,7 @@ enum kex_exchange {
@@ -143,7 +149,7 @@ index 0fac9d3..044ec18 100644
#ifdef GSSAPI
KEX_GSS_GRP1_SHA1,
KEX_GSS_GRP14_SHA1,
-@@ -287,6 +288,8 @@ int kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
+@@ -277,6 +278,8 @@ int kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
@@ -217,7 +223,7 @@ index efb2e55..69ec13b 100644
kex->ec_client_key = NULL;
return r;
diff --git a/kexgen.c b/kexgen.c
-index ca70484..4855d5c 100644
+index 31f90f5..f3eff47 100644
--- a/kexgen.c
+++ b/kexgen.c
@@ -111,6 +111,7 @@ kex_gen_client(struct ssh *ssh)
@@ -236,7 +242,7 @@ index ca70484..4855d5c 100644
r = kex_ecdh_dec(kex, server_blob, &shared_secret);
break;
#endif
-@@ -298,6 +300,7 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
+@@ -280,6 +282,7 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
&shared_secret);
break;
case KEX_ECDH_SHA2:
@@ -681,7 +687,7 @@ index a094888..0a805ad 100644
/*
* Configuration file in user's home directory. This file need not be
diff --git a/regress/agent.sh b/regress/agent.sh
-index 5f10606..3ab40b4 100644
+index f187b67..42a5124 100644
--- a/regress/agent.sh
+++ b/regress/agent.sh
@@ -87,9 +87,18 @@ fi
@@ -758,10 +764,10 @@ index b32502b..f260692 100644
sshkey_verify(ed25519, sig, slen, (const u_char *)data, dlen, NULL, 0, &details);
sshkey_sig_details_free(details);
diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c
-index c26761e..d335b29 100644
+index 3bd71a9..312e8f2 100644
--- a/regress/unittests/kex/test_kex.c
+++ b/regress/unittests/kex/test_kex.c
-@@ -151,6 +151,7 @@ do_kex_with_key(char *kex, int keytype, int bits)
+@@ -152,6 +152,7 @@ do_kex_with_key(char *kex, int keytype, int bits)
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
@@ -769,7 +775,7 @@ index c26761e..d335b29 100644
server2->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
server2->kex->load_host_public_key = server->kex->load_host_public_key;
server2->kex->load_host_private_key = server->kex->load_host_private_key;
-@@ -185,6 +186,7 @@ do_kex(char *kex)
+@@ -186,6 +187,7 @@ do_kex(char *kex)
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
do_kex_with_key(kex, KEY_ED25519, 256);
@@ -777,7 +783,7 @@ index c26761e..d335b29 100644
}
void
-@@ -201,6 +203,7 @@ kex_tests(void)
+@@ -202,6 +204,7 @@ kex_tests(void)
do_kex("diffie-hellman-group-exchange-sha1");
do_kex("diffie-hellman-group14-sha1");
do_kex("diffie-hellman-group1-sha1");
@@ -786,10 +792,10 @@ index c26761e..d335b29 100644
do_kex("sntrup761x25519-sha512@openssh.com");
# endif /* USE_SNTRUP761X25519 */
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
-index b705157..5445ab5 100644
+index b036796..6697be6 100644
--- a/ssh-ecdsa.c
+++ b/ssh-ecdsa.c
-@@ -256,7 +256,8 @@ ssh_ecdsa_sign(struct sshkey *key,
+@@ -66,7 +66,8 @@ ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
*sigp = NULL;
if (key == NULL || key->ecdsa == NULL ||
@@ -799,21 +805,21 @@ index b705157..5445ab5 100644
return SSH_ERR_INVALID_ARGUMENT;
if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1)
-@@ -332,7 +333,8 @@ ssh_ecdsa_verify(const struct sshkey *key,
+@@ -133,7 +134,8 @@ ssh_ecdsa_verify(const struct sshkey *key,
unsigned char *sigb = NULL, *psig = NULL;
if (key == NULL || key->ecdsa == NULL ||
- sshkey_type_plain(key->type) != KEY_ECDSA ||
-+ (sshkey_type_plain(key->type) != KEY_ECDSA &&
-+ sshkey_type_plain(key->type) != KEY_SM2) ||
- sig == NULL || siglen == 0)
++ (sshkey_type_plain(key->type) != KEY_ECDSA &&
++ sshkey_type_plain(key->type) != KEY_SM2) ||
+ signature == NULL || signaturelen == 0)
return SSH_ERR_INVALID_ARGUMENT;
diff --git a/ssh-keygen.c b/ssh-keygen.c
-index 0bff209..46f4998 100644
+index b9c4dce..bd6ea16 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
-@@ -193,6 +193,7 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp)
+@@ -192,6 +192,7 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp)
*bitsp = DEFAULT_BITS_DSA;
break;
case KEY_ECDSA:
@@ -821,7 +827,7 @@ index 0bff209..46f4998 100644
if (name != NULL &&
(nid = sshkey_ecdsa_nid_from_name(name)) > 0)
*bitsp = sshkey_curve_nid_to_bits(nid);
-@@ -219,6 +220,10 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp)
+@@ -224,6 +225,10 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp)
fatal("Invalid RSA key length: maximum is %d bits",
OPENSSL_RSA_MAX_MODULUS_BITS);
break;
@@ -832,7 +838,7 @@ index 0bff209..46f4998 100644
case KEY_ECDSA:
if (sshkey_ecdsa_bits_to_nid(*bitsp) == -1)
#ifdef OPENSSL_HAS_NISTP521
-@@ -275,6 +280,9 @@ ask_filename(struct passwd *pw, const char *prompt)
+@@ -280,6 +285,9 @@ ask_filename(struct passwd *pw, const char *prompt)
case KEY_ECDSA:
name = _PATH_SSH_CLIENT_ID_ECDSA;
break;
@@ -842,7 +848,7 @@ index 0bff209..46f4998 100644
case KEY_ECDSA_SK_CERT:
case KEY_ECDSA_SK:
name = _PATH_SSH_CLIENT_ID_ECDSA_SK;
-@@ -386,6 +394,7 @@ do_convert_to_pkcs8(struct sshkey *k)
+@@ -391,6 +399,7 @@ do_convert_to_pkcs8(struct sshkey *k)
break;
#ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
@@ -850,7 +856,7 @@ index 0bff209..46f4998 100644
if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa))
fatal("PEM_write_EC_PUBKEY failed");
break;
-@@ -410,6 +419,7 @@ do_convert_to_pem(struct sshkey *k)
+@@ -415,6 +424,7 @@ do_convert_to_pem(struct sshkey *k)
break;
#ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
@@ -858,7 +864,7 @@ index 0bff209..46f4998 100644
if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa))
fatal("PEM_write_EC_PUBKEY failed");
break;
-@@ -3280,7 +3290,7 @@ usage(void)
+@@ -3148,7 +3158,7 @@ usage(void)
fprintf(stderr,
"usage: ssh-keygen [-q] [-a rounds] [-b bits] [-C comment] [-f output_keyfile]\n"
" [-m format] [-N new_passphrase] [-O option]\n"
@@ -868,10 +874,10 @@ index 0bff209..46f4998 100644
" ssh-keygen -p [-a rounds] [-f keyfile] [-m format] [-N new_passphrase]\n"
" [-P old_passphrase] [-Z cipher]\n"
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
-index 245c73d..b402a21 100644
+index 9ec4d9a..be2af0a 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
-@@ -68,9 +68,10 @@ int ssh_port = SSH_DEFAULT_PORT;
+@@ -63,9 +63,10 @@ int ssh_port = SSH_DEFAULT_PORT;
#define KT_XMSS (1<<4)
#define KT_ECDSA_SK (1<<5)
#define KT_ED25519_SK (1<<6)
@@ -883,7 +889,7 @@ index 245c73d..b402a21 100644
int get_cert = 0;
int get_keytypes = KT_RSA|KT_ECDSA|KT_ED25519|KT_ECDSA_SK|KT_ED25519_SK;
-@@ -267,6 +268,11 @@ keygrab_ssh2(con *c)
+@@ -261,6 +262,11 @@ keygrab_ssh2(con *c)
"ecdsa-sha2-nistp384,"
"ecdsa-sha2-nistp521";
break;
@@ -895,7 +901,7 @@ index 245c73d..b402a21 100644
case KT_ECDSA_SK:
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
"sk-ecdsa-sha2-nistp256-cert-v01@openssh.com" :
-@@ -296,6 +302,7 @@ keygrab_ssh2(con *c)
+@@ -290,6 +296,7 @@ keygrab_ssh2(con *c)
c->c_ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
# ifdef OPENSSL_HAS_ECC
c->c_ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
@@ -903,7 +909,7 @@ index 245c73d..b402a21 100644
# endif
#endif
c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
-@@ -789,6 +796,9 @@ main(int argc, char **argv)
+@@ -730,6 +737,9 @@ main(int argc, char **argv)
case KEY_ECDSA:
get_keytypes |= KT_ECDSA;
break;
@@ -915,10 +921,10 @@ index 245c73d..b402a21 100644
break;
diff --git a/ssh-sm2.c b/ssh-sm2.c
new file mode 100644
-index 0000000..75e9731
+index 0000000..c242139
--- /dev/null
+++ b/ssh-sm2.c
-@@ -0,0 +1,381 @@
+@@ -0,0 +1,230 @@
+#include "includes.h"
+#include <sys/types.h>
+#include <openssl/bn.h>
@@ -933,167 +939,30 @@ index 0000000..75e9731
+
+#include "openbsd-compat/openssl-compat.h"
+
-+/* Reuse some ECDSA internals */
-+extern struct sshkey_impl_funcs sshkey_ecdsa_funcs;
-+
+const unsigned char *sm2_id = (const unsigned char *)"1234567812345678";
+
-+static void
-+ssh_sm2_cleanup(struct sshkey *k)
-+{
-+ EC_KEY_free(k->ecdsa);
-+ k->ecdsa = NULL;
-+}
-+
-+static int
-+ssh_sm2_equal(const struct sshkey *a, const struct sshkey *b)
-+{
-+ if (!sshkey_ecdsa_funcs.equal(a, b))
-+ return 0;
-+ return 1;
-+}
-+
-+static int
-+ssh_sm2_serialize_public(const struct sshkey *key, struct sshbuf *b,
-+ enum sshkey_serialize_rep opts)
-+{
-+ int r;
-+
-+ if ((r = sshkey_ecdsa_funcs.serialize_public(key, b, opts)) != 0)
-+ return r;
-+
-+ return 0;
-+}
-+
-+static int
-+ssh_sm2_deserialize_public(const char *ktype, struct sshbuf *b,
-+ struct sshkey *key)
-+{
-+ int r;
-+
-+ if ((r = sshkey_ecdsa_funcs.deserialize_public(ktype, b, key)) != 0)
-+ return r;
-+ return 0;
-+}
-+
-+static int
-+ssh_sm2_serialize_private(const struct sshkey *key, struct sshbuf *b,
-+ enum sshkey_serialize_rep opts)
-+{
-+ int r;
-+
-+ if ((r = sshkey_ecdsa_funcs.serialize_private(key, b, opts)) != 0)
-+ return r;
-+
-+ return 0;
-+}
-+
-+static int
-+ssh_sm2_deserialize_private(const char *ktype, struct sshbuf *b,
-+ struct sshkey *key)
-+{
-+ int r;
-+
-+ if ((r = sshkey_ecdsa_funcs.deserialize_private(ktype, b, key)) != 0)
-+ return r;
-+
-+ return 0;
-+}
-+
-+static int
-+ssh_sm2_generate(struct sshkey *k, int bits)
-+{
-+ EC_KEY *private;
-+
-+ k->ecdsa_nid = NID_sm2;
-+ if ((private = EC_KEY_new_by_curve_name(k->ecdsa_nid)) == NULL)
-+ return SSH_ERR_ALLOC_FAIL;
-+ if (EC_KEY_generate_key(private) != 1) {
-+ EC_KEY_free(private);
-+ return SSH_ERR_LIBCRYPTO_ERROR;
-+ }
-+ EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
-+ k->ecdsa = private;
-+ return 0;
-+}
-+
-+static int
-+ssh_sm2_copy_public(const struct sshkey *from, struct sshkey *to)
-+{
-+ int r;
-+
-+ if ((r = sshkey_ecdsa_funcs.copy_public(from, to)) != 0)
-+ return r;
-+ return 0;
-+}
-+
-+static int
-+sm2_get_sig(EVP_PKEY *pkey, const u_char *data,
-+ size_t datalen, u_char *sig, size_t *slen)
-+{
-+ EVP_PKEY_CTX *pctx = NULL;
-+ EVP_MD_CTX *mctx = NULL;
-+ int ret = SSH_ERR_INTERNAL_ERROR;
-+
-+ if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
-+ ret = SSH_ERR_ALLOC_FAIL;
-+ goto out;
-+ }
-+ if ((mctx = EVP_MD_CTX_new()) == NULL) {
-+ ret = SSH_ERR_ALLOC_FAIL;
-+ goto out;
-+ }
-+ if (EVP_PKEY_CTX_set1_id(pctx, sm2_id, 16) != 1) {
-+ ret = SSH_ERR_INTERNAL_ERROR;
-+ goto out;
-+ }
-+
-+ EVP_MD_CTX_set_pkey_ctx(mctx, pctx);
-+
-+ if ((EVP_DigestSignInit(mctx, NULL, EVP_sm3(), NULL, pkey)) != 1) {
-+ ret = SSH_ERR_INTERNAL_ERROR;
-+ goto out;
-+ }
-+
-+ if ((EVP_DigestSignUpdate(mctx, data, datalen)) != 1) {
-+ ret = SSH_ERR_INTERNAL_ERROR;
-+ goto out;
-+ }
-+
-+ if ((EVP_DigestSignFinal(mctx, sig, slen)) != 1) {
-+ ret = SSH_ERR_INTERNAL_ERROR;
-+ goto out;
-+ }
-+ ret = 0;
-+
-+out:
-+ EVP_PKEY_CTX_free(pctx);
-+ EVP_MD_CTX_free(mctx);
-+ return ret;
-+}
-+
-+static int
-+ssh_sm2_sign(struct sshkey *key,
-+ u_char **sigp, size_t *lenp,
-+ const u_char *data, size_t datalen,
-+ const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
++int
++ssh_sm2_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
++ const u_char *data, size_t datalen, u_int compat)
+{
+ u_char *sig = NULL;
-+ size_t slen = 0;
++ size_t slen = 0;
+ int pkey_len = 0;
+ int r = 0;
+ int len = 0;
+ EVP_PKEY *key_sm2 = NULL;
-+ struct sshbuf *b = NULL;
-+ int ret = SSH_ERR_INTERNAL_ERROR;
++ struct sshbuf *b = NULL;
++ EVP_PKEY_CTX *pctx = NULL;
++ EVP_MD_CTX *mctx = NULL;
++ int ret = SSH_ERR_INTERNAL_ERROR;
+
-+ if (lenp != NULL)
-+ *lenp = 0;
-+ if (sigp != NULL)
-+ *sigp = NULL;
++ if (lenp != NULL)
++ *lenp = 0;
++ if (sigp != NULL)
++ *sigp = NULL;
+
+ if (key == NULL || key->ecdsa == NULL ||
-+ sshkey_type_plain(key->type) != KEY_SM2)
++ sshkey_type_plain(key->type) != KEY_SM2)
+ return SSH_ERR_INVALID_ARGUMENT;
+
+ if ((key_sm2 = EVP_PKEY_new()) == NULL) {
@@ -1105,201 +974,187 @@ index 0000000..75e9731
+ goto out;
+ }
+
-+ if ((pkey_len = EVP_PKEY_size(key_sm2)) == 0) {
-+ ret = SSH_ERR_INVALID_ARGUMENT;
++ if ((pkey_len = EVP_PKEY_size(key_sm2)) == 0) {
++ ret = SSH_ERR_INVALID_ARGUMENT;
+ goto out;
-+ }
++ }
+
+ slen = pkey_len;
-+
-+ if ((sig = OPENSSL_malloc(pkey_len)) == NULL) {
-+ ret = SSH_ERR_ALLOC_FAIL;
-+ goto out;
-+ }
-+
-+ if (ret = sm2_get_sig(key_sm2, data, datalen, sig, &slen)) {
++
++ if ((EVP_PKEY_set_alias_type(key_sm2, EVP_PKEY_SM2)) != 1) {
++ ret = SSH_ERR_INTERNAL_ERROR;
+ goto out;
+ }
+
-+ if ((b = sshbuf_new()) == NULL) {
++ if ((sig = OPENSSL_malloc(pkey_len)) == NULL) {
+ ret = SSH_ERR_ALLOC_FAIL;
+ goto out;
-+ }
-+
-+ if ((r = sshbuf_put_cstring(b, "sm2")) != 0 ||
-+ (r = sshbuf_put_string(b, sig, slen)) != 0)
-+ goto out;
-+ len = sshbuf_len(b);
-+ if (sigp != NULL) {
-+ if ((*sigp = malloc(len)) == NULL) {
-+ ret = SSH_ERR_ALLOC_FAIL;
-+ goto out;
-+ }
-+ memcpy(*sigp, sshbuf_ptr(b), len);
-+ }
-+ if (lenp != NULL)
-+ *lenp = len;
-+ ret = 0;
-+
-+out:
-+ EVP_PKEY_free(key_sm2);
-+ if (sig != NULL) {
-+ explicit_bzero(sig, slen);
-+ OPENSSL_free(sig);
-+ }
-+ sshbuf_free(b);
-+ return ret;
-+}
-+
-+static int
-+sm2_verify_sig(EVP_PKEY *pkey, const u_char *data,
-+ size_t datalen, const u_char *sig, size_t slen)
-+{
-+ EVP_PKEY_CTX *pctx = NULL;
-+ EVP_MD_CTX *mctx = NULL;
-+ int ret = SSH_ERR_INTERNAL_ERROR;
++ }
+
-+ if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
++ if ((pctx = EVP_PKEY_CTX_new(key_sm2, NULL)) == NULL) {
+ ret = SSH_ERR_ALLOC_FAIL;
-+ goto out;
-+ }
-+
-+ if ((mctx = EVP_MD_CTX_new()) == NULL) {
-+ ret = SSH_ERR_ALLOC_FAIL;
-+ goto out;
++ goto out;
+ }
+
+ if (EVP_PKEY_CTX_set1_id(pctx, sm2_id, 16) != 1) {
+ ret = SSH_ERR_INTERNAL_ERROR;
-+ goto out;
++ goto out;
+ }
++
++ if ((mctx = EVP_MD_CTX_new()) == NULL) {
++ ret = SSH_ERR_ALLOC_FAIL;
++ goto out;
++ }
++
+ EVP_MD_CTX_set_pkey_ctx(mctx, pctx);
+
-+ if ((EVP_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, pkey)) != 1) {
++ if ((EVP_DigestSignInit(mctx, NULL, EVP_sm3(), NULL, key_sm2)) != 1) {
+ ret = SSH_ERR_INTERNAL_ERROR;
+ goto out;
+ }
+
-+ if ((EVP_DigestVerifyUpdate(mctx, data, datalen)) != 1) {
++ if ((EVP_DigestSignUpdate(mctx, data, datalen)) != 1) {
+ ret = SSH_ERR_INTERNAL_ERROR;
-+ goto out;
++ goto out;
+ }
-+
-+ if ((EVP_DigestVerifyFinal(mctx, sig, slen)) != 1) {
++
++ if ((EVP_DigestSignFinal(mctx, sig, &slen)) != 1) {
+ ret = SSH_ERR_INTERNAL_ERROR;
-+ goto out;
++ goto out;
+ }
+
++ if ((b = sshbuf_new()) == NULL) {
++ ret = SSH_ERR_ALLOC_FAIL;
++ goto out;
++ }
++
++ if ((r = sshbuf_put_cstring(b, "sm2")) != 0 ||
++ (r = sshbuf_put_string(b, sig, slen)) != 0)
++ goto out;
++ len = sshbuf_len(b);
++ if (sigp != NULL) {
++ if ((*sigp = malloc(len)) == NULL) {
++ ret = SSH_ERR_ALLOC_FAIL;
++ goto out;
++ }
++ memcpy(*sigp, sshbuf_ptr(b), len);
++ }
++ if (lenp != NULL)
++ *lenp = len;
+ ret = 0;
++
+out:
++ EVP_PKEY_free(key_sm2);
++ if (sig != NULL) {
++ explicit_bzero(sig, slen);
++ OPENSSL_free(sig);
++ }
+ EVP_PKEY_CTX_free(pctx);
+ EVP_MD_CTX_free(mctx);
++ sshbuf_free(b);
+ return ret;
+}
+
-+static int
++int
+ssh_sm2_verify(const struct sshkey *key,
+ const u_char *signature, size_t signaturelen,
-+ const u_char *data, size_t datalen, const char *alg, u_int compat,
-+ struct sshkey_sig_details **detailsp)
++ const u_char *data, size_t datalen, u_int compat)
+{
+ const u_char *sig = NULL;
+ char *ktype = NULL;
+ size_t slen = 0;
-+ int pkey_len = 0;
-+ int r = 0;
-+ int len = 0;
++ int pkey_len = 0;
++ int r = 0;
++ int len = 0;
+ EVP_PKEY *key_sm2 = NULL;
-+ struct sshbuf *b = NULL;
-+ int ret = SSH_ERR_INTERNAL_ERROR;
++ struct sshbuf *b = NULL;
++ EVP_PKEY_CTX *pctx = NULL;
++ EVP_MD_CTX *mctx = NULL;
++ int ret = SSH_ERR_INTERNAL_ERROR;
+
-+ if (key == NULL ||
-+ sshkey_type_plain(key->type) != KEY_SM2 ||
-+ signature == NULL || signaturelen == 0)
-+ return SSH_ERR_INVALID_ARGUMENT;
++ if (key == NULL ||
++ sshkey_type_plain(key->type) != KEY_SM2 ||
++ signature == NULL || signaturelen == 0)
++ return SSH_ERR_INVALID_ARGUMENT;
+
-+ if ((b = sshbuf_from(signature, signaturelen)) == NULL)
-+ return SSH_ERR_ALLOC_FAIL;
++ if ((b = sshbuf_from(signature, signaturelen)) == NULL)
++ return SSH_ERR_ALLOC_FAIL;
+
-+ if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
-+ (r = sshbuf_get_string_direct(b, &sig, &slen)) != 0)
-+ goto out;
++ if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
++ (r = sshbuf_get_string_direct(b, &sig, &slen)) != 0)
++ goto out;
+
+ if (strcmp("sm2", ktype) != 0) {
-+ ret = SSH_ERR_KEY_TYPE_MISMATCH;
-+ goto out;
++ ret = SSH_ERR_KEY_TYPE_MISMATCH;
++ goto out;
+ }
+
-+ if (sshbuf_len(b) != 0) {
-+ ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
-+ goto out;
-+ }
++ if (sshbuf_len(b) != 0) {
++ ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
++ goto out;
++ }
+
-+ if ((key_sm2 = EVP_PKEY_new()) == NULL) {
-+ ret = SSH_ERR_ALLOC_FAIL;
-+ goto out;
-+ }
++ if ((key_sm2 = EVP_PKEY_new()) == NULL) {
++ ret = SSH_ERR_ALLOC_FAIL;
++ goto out;
++ }
+
-+ if ((EVP_PKEY_set1_EC_KEY(key_sm2, key->ecdsa)) != 1) {
++ if ((EVP_PKEY_set1_EC_KEY(key_sm2, key->ecdsa)) != 1) {
++ ret = SSH_ERR_INTERNAL_ERROR;
++ goto out;
++ }
++
++ if ((pkey_len = EVP_PKEY_size(key_sm2)) == 0) {
++ ret = SSH_ERR_INVALID_ARGUMENT;
++ goto out;
++ }
++
++ if ((EVP_PKEY_set_alias_type(key_sm2, EVP_PKEY_SM2)) != 1) {
++ ret = SSH_ERR_INTERNAL_ERROR;
++ goto out;
++ }
++
++ if ((pctx = EVP_PKEY_CTX_new(key_sm2, NULL)) == NULL) {
++ ret = SSH_ERR_ALLOC_FAIL;
++ goto out;
++ }
++
++ if (EVP_PKEY_CTX_set1_id(pctx, sm2_id, 16) != 1) {
++ ret = SSH_ERR_INTERNAL_ERROR;
++ goto out;
++ }
++
++ if ((mctx = EVP_MD_CTX_new()) == NULL) {
++ ret = SSH_ERR_ALLOC_FAIL;
++ goto out;
++ }
++
++ EVP_MD_CTX_set_pkey_ctx(mctx, pctx);
++
++ if ((EVP_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, key_sm2)) != 1) {
+ ret = SSH_ERR_INTERNAL_ERROR;
-+ goto out;
++ goto out;
+ }
-+
-+ if ((pkey_len = EVP_PKEY_size(key_sm2)) == 0) {
-+ ret = SSH_ERR_INVALID_ARGUMENT;
-+ goto out;
++
++ if ((EVP_DigestVerifyUpdate(mctx, data, datalen)) != 1) {
++ ret = SSH_ERR_INTERNAL_ERROR;
++ goto out;
+ }
-+
-+ if (ret = sm2_verify_sig(key_sm2, data, datalen, sig, slen)) {
-+ goto out;
++
++ if ((EVP_DigestVerifyFinal(mctx, sig, slen)) != 1) {
++ ret = SSH_ERR_INTERNAL_ERROR;
++ goto out;
+ }
+
+ ret = 0;
+out:
+ EVP_PKEY_free(key_sm2);
-+ sshbuf_free(b);
++ EVP_PKEY_CTX_free(pctx);
++ EVP_MD_CTX_free(mctx);
++ sshbuf_free(b);
+ free(ktype);
+ return ret;
+}
-+
-+static const struct sshkey_impl_funcs sshkey_sm2_funcs = {
-+ /* .size = */ NULL,
-+ /* .alloc = */ NULL,
-+ /* .cleanup = */ ssh_sm2_cleanup,
-+ /* .equal = */ ssh_sm2_equal,
-+ /* .ssh_serialize_public = */ ssh_sm2_serialize_public,
-+ /* .ssh_deserialize_public = */ ssh_sm2_deserialize_public,
-+ /* .ssh_serialize_private = */ ssh_sm2_serialize_private,
-+ /* .ssh_deserialize_private = */ssh_sm2_deserialize_private,
-+ /* .generate = */ ssh_sm2_generate,
-+ /* .copy_public = */ ssh_sm2_copy_public,
-+ /* .sign = */ ssh_sm2_sign,
-+ /* .verify = */ ssh_sm2_verify,
-+};
-+
-+const struct sshkey_impl sshkey_sm2_impl = {
-+ /* .name = */ "sm2",
-+ /* .shortname = */ "SM2",
-+ /* .sigalg = */ NULL,
-+ /* .type = */ KEY_SM2,
-+ /* .nid = */ NID_sm2,
-+ /* .cert = */ 0,
-+ /* .sigonly = */ 0,
-+ /* .keybits = */ 256,
-+ /* .funcs = */ &sshkey_sm2_funcs,
-+};
-+
-+const struct sshkey_impl sshkey_sm2_cert_impl = {
-+ /* .name = */ "sm2-cert",
-+ /* .shortname = */ "SM2-CERT",
-+ /* .sigalg = */ NULL,
-+ /* .type = */ KEY_SM2_CERT,
-+ /* .nid = */ NID_sm2,
-+ /* .cert = */ 1,
-+ /* .sigonly = */ 0,
-+ /* .keybits = */ 256,
-+ /* .funcs = */ &sshkey_sm2_funcs,
-+};
diff --git a/ssh_api.c b/ssh_api.c
index d3c6617..adc2598 100644
--- a/ssh_api.c
@@ -1321,10 +1176,10 @@ index d3c6617..adc2598 100644
#endif /* WITH_OPENSSL */
ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
diff --git a/sshconnect2.c b/sshconnect2.c
-index 3acfdb6..3fbff57 100644
+index fafc0a2..9a01f1a 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
-@@ -326,6 +326,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
+@@ -327,6 +327,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
# ifdef OPENSSL_HAS_ECC
ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
@@ -1333,10 +1188,10 @@ index 3acfdb6..3fbff57 100644
# ifdef GSSAPI
if (options.gss_keyex) {
diff --git a/sshd.c b/sshd.c
-index f366457..52c66ed 100644
+index 8424e33..57d70fe 100644
--- a/sshd.c
+++ b/sshd.c
-@@ -695,6 +695,7 @@ list_hostkey_types(void)
+@@ -706,6 +706,7 @@ list_hostkey_types(void)
/* FALLTHROUGH */
case KEY_DSA:
case KEY_ECDSA:
@@ -1344,7 +1199,7 @@ index f366457..52c66ed 100644
case KEY_ED25519:
case KEY_ECDSA_SK:
case KEY_ED25519_SK:
-@@ -716,6 +717,7 @@ list_hostkey_types(void)
+@@ -727,6 +728,7 @@ list_hostkey_types(void)
/* FALLTHROUGH */
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
@@ -1352,7 +1207,7 @@ index f366457..52c66ed 100644
case KEY_ED25519_CERT:
case KEY_ECDSA_SK_CERT:
case KEY_ED25519_SK_CERT:
-@@ -742,6 +744,7 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
+@@ -753,6 +755,7 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
case KEY_RSA_CERT:
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
@@ -1360,7 +1215,7 @@ index f366457..52c66ed 100644
case KEY_ED25519_CERT:
case KEY_ECDSA_SK_CERT:
case KEY_ED25519_SK_CERT:
-@@ -758,8 +761,10 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
+@@ -769,8 +772,10 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
continue;
switch (type) {
case KEY_ECDSA:
@@ -1371,7 +1226,7 @@ index f366457..52c66ed 100644
case KEY_ECDSA_SK_CERT:
if (key->ecdsa_nid != nid)
continue;
-@@ -2012,6 +2017,7 @@ main(int ac, char **av)
+@@ -1983,6 +1988,7 @@ main(int ac, char **av)
case KEY_RSA:
case KEY_DSA:
case KEY_ECDSA:
@@ -1379,7 +1234,7 @@ index f366457..52c66ed 100644
case KEY_ED25519:
case KEY_ECDSA_SK:
case KEY_ED25519_SK:
-@@ -2573,6 +2579,7 @@ do_ssh2_kex(struct ssh *ssh)
+@@ -2572,6 +2578,7 @@ do_ssh2_kex(struct ssh *ssh)
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
# ifdef OPENSSL_HAS_ECC
kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
@@ -1388,28 +1243,19 @@ index f366457..52c66ed 100644
# ifdef GSSAPI
if (options.gss_keyex) {
diff --git a/sshkey.c b/sshkey.c
-index 1735159..1aee244 100644
+index b0c2189..51f8e51 100644
--- a/sshkey.c
+++ b/sshkey.c
-@@ -130,6 +130,8 @@ extern const struct sshkey_impl sshkey_dsa_cert_impl;
- extern const struct sshkey_impl sshkey_xmss_impl;
- extern const struct sshkey_impl sshkey_xmss_cert_impl;
- #endif
-+extern const struct sshkey_impl sshkey_sm2_impl;
-+extern const struct sshkey_impl sshkey_sm2_cert_impl;
-
- static int ssh_gss_equal(const struct sshkey *, const struct sshkey *)
- {
-@@ -237,6 +239,8 @@ const struct sshkey_impl * const keyimpls[] = {
- &sshkey_xmss_cert_impl,
- #endif
- &sshkey_gss_kex_impl,
-+ &sshkey_sm2_impl,
-+ &sshkey_sm2_cert_impl,
- NULL
+@@ -159,6 +159,8 @@ static const struct keytype keytypes[] = {
+ # endif /* OPENSSL_HAS_ECC */
+ #endif /* WITH_OPENSSL */
+ { "null", "null", NULL, KEY_NULL, 0, 0, 0 },
++ { "sm2", "SM2", NULL, KEY_SM2, NID_sm2, 0, 0 },
++ { "sm2-cert", "SM2-CERT", NULL, KEY_SM2_CERT, NID_sm2, 1, 0 },
+ { NULL, NULL, NULL, -1, -1, 0, 0 }
};
-@@ -340,6 +344,8 @@ key_type_is_ecdsa_variant(int type)
+@@ -233,6 +235,8 @@ key_type_is_ecdsa_variant(int type)
case KEY_ECDSA_CERT:
case KEY_ECDSA_SK:
case KEY_ECDSA_SK_CERT:
@@ -1418,7 +1264,25 @@ index 1735159..1aee244 100644
return 1;
}
return 0;
-@@ -548,6 +554,8 @@ sshkey_type_plain(int type)
+@@ -342,6 +346,8 @@ sshkey_size(const struct sshkey *k)
+ case KEY_ECDSA_CERT:
+ case KEY_ECDSA_SK:
+ case KEY_ECDSA_SK_CERT:
++ case KEY_SM2:
++ case KEY_SM2_CERT:
+ return sshkey_curve_nid_to_bits(k->ecdsa_nid);
+ #endif /* WITH_OPENSSL */
+ case KEY_ED25519:
+@@ -366,6 +372,8 @@ sshkey_type_is_valid_ca(int type)
+ case KEY_ED25519:
+ case KEY_ED25519_SK:
+ case KEY_XMSS:
++ case KEY_SM2:
++ case KEY_SM2_CERT:
+ return 1;
+ default:
+ return 0;
+@@ -445,6 +453,8 @@ sshkey_type_plain(int type)
return KEY_ED25519_SK;
case KEY_XMSS_CERT:
return KEY_XMSS;
@@ -1427,16 +1291,7 @@ index 1735159..1aee244 100644
default:
return type;
}
-@@ -564,6 +572,8 @@ sshkey_type_certified(int type)
- return KEY_DSA_CERT;
- case KEY_ECDSA:
- return KEY_ECDSA_CERT;
-+ case KEY_SM2:
-+ return KEY_SM2_CERT;
- case KEY_ECDSA_SK:
- return KEY_ECDSA_SK_CERT;
- case KEY_ED25519:
-@@ -670,6 +680,8 @@ sshkey_curve_name_to_nid(const char *name)
+@@ -540,6 +550,8 @@ sshkey_curve_name_to_nid(const char *name)
else if (strcmp(name, "nistp521") == 0)
return NID_secp521r1;
# endif /* OPENSSL_HAS_NISTP521 */
@@ -1445,7 +1300,7 @@ index 1735159..1aee244 100644
else
return -1;
}
-@@ -686,6 +698,8 @@ sshkey_curve_nid_to_bits(int nid)
+@@ -556,6 +568,8 @@ sshkey_curve_nid_to_bits(int nid)
case NID_secp521r1:
return 521;
# endif /* OPENSSL_HAS_NISTP521 */
@@ -1454,7 +1309,7 @@ index 1735159..1aee244 100644
default:
return 0;
}
-@@ -720,6 +734,8 @@ sshkey_curve_nid_to_name(int nid)
+@@ -590,6 +604,8 @@ sshkey_curve_nid_to_name(int nid)
case NID_secp521r1:
return "nistp521";
# endif /* OPENSSL_HAS_NISTP521 */
@@ -1463,7 +1318,195 @@ index 1735159..1aee244 100644
default:
return NULL;
}
-@@ -3424,6 +3440,7 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf,
+@@ -695,6 +711,8 @@ sshkey_new(int type)
+ case KEY_ECDSA_CERT:
+ case KEY_ECDSA_SK:
+ case KEY_ECDSA_SK_CERT:
++ case KEY_SM2:
++ case KEY_SM2_CERT:
+ /* Cannot do anything until we know the group */
+ break;
+ #endif /* WITH_OPENSSL */
+@@ -749,6 +767,8 @@ sshkey_free(struct sshkey *k)
+ /* FALLTHROUGH */
+ case KEY_ECDSA:
+ case KEY_ECDSA_CERT:
++ case KEY_SM2:
++ case KEY_SM2_CERT:
+ EC_KEY_free(k->ecdsa);
+ k->ecdsa = NULL;
+ break;
+@@ -858,6 +878,8 @@ sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
+ /* FALLTHROUGH */
+ case KEY_ECDSA_CERT:
+ case KEY_ECDSA:
++ case KEY_SM2:
++ case KEY_SM2_CERT:
+ if (a->ecdsa == NULL || b->ecdsa == NULL ||
+ EC_KEY_get0_public_key(a->ecdsa) == NULL ||
+ EC_KEY_get0_public_key(b->ecdsa) == NULL)
+@@ -933,6 +955,7 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain,
+ #ifdef WITH_OPENSSL
+ case KEY_DSA_CERT:
+ case KEY_ECDSA_CERT:
++ case KEY_SM2_CERT:
+ case KEY_ECDSA_SK_CERT:
+ case KEY_RSA_CERT:
+ #endif /* WITH_OPENSSL */
+@@ -962,6 +985,7 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain,
+ # ifdef OPENSSL_HAS_ECC
+ case KEY_ECDSA:
+ case KEY_ECDSA_SK:
++ case KEY_SM2:
+ if (key->ecdsa == NULL)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
+@@ -1436,6 +1460,8 @@ sshkey_read(struct sshkey *ret, char **cpp)
+ case KEY_DSA:
+ case KEY_ECDSA:
+ case KEY_ECDSA_SK:
++ case KEY_SM2:
++ case KEY_SM2_CERT:
+ case KEY_ED25519:
+ case KEY_ED25519_SK:
+ case KEY_DSA_CERT:
+@@ -1535,6 +1561,7 @@ sshkey_read(struct sshkey *ret, char **cpp)
+ break;
+ # ifdef OPENSSL_HAS_ECC
+ case KEY_ECDSA:
++ case KEY_SM2:
+ EC_KEY_free(ret->ecdsa);
+ ret->ecdsa = k->ecdsa;
+ ret->ecdsa_nid = k->ecdsa_nid;
+@@ -1795,7 +1822,7 @@ sshkey_ecdsa_key_to_nid(EC_KEY *k)
+ }
+
+ static int
+-ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap)
++ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap, int sm2)
+ {
+ EC_KEY *private;
+ int ret = SSH_ERR_INTERNAL_ERROR;
+@@ -1804,6 +1831,9 @@ ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if ((*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1)
+ return SSH_ERR_KEY_LENGTH;
++ if (sm2 && bits == 256) {
++ *nid = NID_sm2;
++ }
+ *ecdsap = NULL;
+ if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) {
+ ret = SSH_ERR_ALLOC_FAIL;
+@@ -1857,7 +1887,11 @@ sshkey_generate(int type, u_int bits, struct sshkey **keyp)
+ # ifdef OPENSSL_HAS_ECC
+ case KEY_ECDSA:
+ ret = ecdsa_generate_private_key(bits, &k->ecdsa_nid,
+- &k->ecdsa);
++ &k->ecdsa, 0);
++ break;
++ case KEY_SM2:
++ ret = ecdsa_generate_private_key(bits, &k->ecdsa_nid,
++ &k->ecdsa, 1);
+ break;
+ # endif /* OPENSSL_HAS_ECC */
+ case KEY_RSA:
+@@ -1993,6 +2027,8 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
+ case KEY_ECDSA_CERT:
+ case KEY_ECDSA_SK:
+ case KEY_ECDSA_SK_CERT:
++ case KEY_SM2:
++ case KEY_SM2_CERT:
+ n->ecdsa_nid = k->ecdsa_nid;
+ n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
+ if (n->ecdsa == NULL) {
+@@ -2548,6 +2584,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
+ break;
+ # ifdef OPENSSL_HAS_ECC
+ case KEY_ECDSA_CERT:
++ case KEY_SM2_CERT:
+ case KEY_ECDSA_SK_CERT:
+ /* Skip nonce */
+ if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
+@@ -2557,6 +2594,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
+ /* FALLTHROUGH */
+ case KEY_ECDSA:
+ case KEY_ECDSA_SK:
++ case KEY_SM2:
+ if ((key = sshkey_new(type)) == NULL) {
+ ret = SSH_ERR_ALLOC_FAIL;
+ goto out;
+@@ -2865,6 +2903,10 @@ sshkey_sign(struct sshkey *key,
+ case KEY_ECDSA:
+ r = ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat);
+ break;
++ case KEY_SM2:
++ case KEY_SM2_CERT:
++ r = ssh_sm2_sign(key, sigp, lenp, data, datalen, compat);
++ break;
+ # endif /* OPENSSL_HAS_ECC */
+ case KEY_RSA_CERT:
+ case KEY_RSA:
+@@ -2920,6 +2962,9 @@ sshkey_verify(const struct sshkey *key,
+ case KEY_ECDSA_CERT:
+ case KEY_ECDSA:
+ return ssh_ecdsa_verify(key, sig, siglen, data, dlen, compat);
++ case KEY_SM2:
++ case KEY_SM2_CERT:
++ return ssh_sm2_verify(key, sig, siglen, data, dlen, compat);
+ case KEY_ECDSA_SK_CERT:
+ case KEY_ECDSA_SK:
+ return ssh_ecdsa_sk_verify(key, sig, siglen, data, dlen,
+@@ -2963,6 +3008,9 @@ sshkey_to_certified(struct sshkey *k)
+ case KEY_ECDSA:
+ newtype = KEY_ECDSA_CERT;
+ break;
++ case KEY_SM2:
++ newtype = KEY_SM2_CERT;
++ break;
+ case KEY_ECDSA_SK:
+ newtype = KEY_ECDSA_SK_CERT;
+ break;
+@@ -3067,6 +3115,7 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
+ break;
+ # ifdef OPENSSL_HAS_ECC
+ case KEY_ECDSA_CERT:
++ case KEY_SM2_CERT:
+ case KEY_ECDSA_SK_CERT:
+ if ((ret = sshbuf_put_cstring(cert,
+ sshkey_curve_nid_to_name(k->ecdsa_nid))) != 0 ||
+@@ -3380,6 +3429,7 @@ sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf,
+ break;
+ # ifdef OPENSSL_HAS_ECC
+ case KEY_ECDSA:
++ case KEY_SM2:
+ if ((r = sshbuf_put_cstring(b,
+ sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
+ (r = sshbuf_put_eckey(b, key->ecdsa)) != 0 ||
+@@ -3388,6 +3438,7 @@ sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf,
+ goto out;
+ break;
+ case KEY_ECDSA_CERT:
++ case KEY_SM2_CERT:
+ if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
+ r = SSH_ERR_INVALID_ARGUMENT;
+ goto out;
+@@ -3605,6 +3656,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
+ break;
+ # ifdef OPENSSL_HAS_ECC
+ case KEY_ECDSA:
++ case KEY_SM2:
+ if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) {
+ r = SSH_ERR_INVALID_ARGUMENT;
+ goto out;
+@@ -3624,6 +3676,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
+ goto out;
+ /* FALLTHROUGH */
+ case KEY_ECDSA_CERT:
++ case KEY_SM2_CERT:
+ if ((r = sshbuf_get_bignum2(buf, &exponent)) != 0)
+ goto out;
+ if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
+@@ -4519,6 +4572,7 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf,
break;
#ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
@@ -1471,7 +1514,7 @@ index 1735159..1aee244 100644
if (format == SSHKEY_PRIVATE_PEM) {
success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
cipher, passphrase, len, NULL, NULL);
-@@ -3485,6 +3502,7 @@ sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
+@@ -4580,6 +4634,7 @@ sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
#ifdef WITH_OPENSSL
case KEY_DSA:
case KEY_ECDSA:
@@ -1479,7 +1522,7 @@ index 1735159..1aee244 100644
case KEY_RSA:
break; /* see below */
#endif /* WITH_OPENSSL */
-@@ -3665,6 +3683,9 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
+@@ -4760,6 +4815,9 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
prv->type = KEY_ECDSA;
prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa);
@@ -1490,10 +1533,18 @@ index 1735159..1aee244 100644
sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
diff --git a/sshkey.h b/sshkey.h
-index 8d662d1..c8d2662 100644
+index 43eef5e..3b84096 100644
--- a/sshkey.h
+++ b/sshkey.h
-@@ -68,6 +68,8 @@ enum sshkey_types {
+@@ -31,6 +31,7 @@
+ #ifdef WITH_OPENSSL
+ #include <openssl/rsa.h>
+ #include <openssl/dsa.h>
++#include <openssl/evp.h>
+ # ifdef OPENSSL_HAS_ECC
+ # include <openssl/ec.h>
+ # include <openssl/ecdsa.h>
+@@ -65,6 +66,8 @@ enum sshkey_types {
KEY_DSA_CERT,
KEY_ECDSA_CERT,
KEY_ED25519_CERT,
@@ -1502,6 +1553,19 @@ index 8d662d1..c8d2662 100644
KEY_XMSS,
KEY_XMSS_CERT,
KEY_ECDSA_SK,
+@@ -323,6 +326,12 @@ int ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
+ int ssh_xmss_verify(const struct sshkey *key,
+ const u_char *signature, size_t signaturelen,
+ const u_char *data, size_t datalen, u_int compat);
++int ssh_sm2_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
++ const u_char *data, size_t datalen, u_int compat);
++int ssh_sm2_verify(const struct sshkey *key,
++ const u_char *signature, size_t signaturelen,
++ const u_char *data, size_t datalen, u_int compat);
++
+ #endif
+
+ #if !defined(WITH_OPENSSL)
--
2.23.0