Projects
Mega:24.09
openssh
_service:tar_scm:feature-add-SMx-support.patch
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:feature-add-SMx-support.patch of Package openssh
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 --- Makefile.in | 4 +- authfd.c | 2 + authfile.c | 1 + cipher.c | 1 + digest-openssl.c | 1 + digest.h | 3 +- kex.c | 1 + kex.h | 3 + kexecdh.c | 23 +- kexgen.c | 3 + kexsm2.c | 406 ++++++++++++++++++++++++++ mac.c | 1 + pathnames.h | 1 + regress/agent.sh | 9 + regress/keytype.sh | 2 + regress/knownhosts-command.sh | 1 + regress/misc/fuzz-harness/sig_fuzz.cc | 4 + regress/unittests/kex/test_kex.c | 3 + ssh-ecdsa.c | 6 +- ssh-keygen.c | 12 +- ssh-keyscan.c | 12 +- ssh-sm2.c | 381 ++++++++++++++++++++++++ ssh_api.c | 2 + sshconnect2.c | 1 + sshd.c | 7 + sshkey.c | 21 ++ sshkey.h | 2 + 27 files changed, 899 insertions(+), 14 deletions(-) create mode 100644 kexsm2.c create mode 100644 ssh-sm2.c diff --git a/Makefile.in b/Makefile.in index 5fec5b3..7dcda3e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -102,14 +102,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 \ - monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-ecdsa-sk.o \ + monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-sm2.o ssh-ecdsa-sk.o \ ssh-ed25519-sk.o ssh-rsa.o dh.o \ msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ 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 \ - 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 --- a/authfd.c +++ b/authfd.c @@ -583,6 +583,8 @@ ssh_add_identity_constrained(int sock, struct sshkey *key, case KEY_DSA_CERT: case KEY_ECDSA: case KEY_ECDSA_CERT: + case KEY_SM2: + case KEY_SM2_CERT: case KEY_ECDSA_SK: case KEY_ECDSA_SK_CERT: #endif diff --git a/authfile.c b/authfile.c index 445f2dd..3884031 100644 --- a/authfile.c +++ b/authfile.c @@ -332,6 +332,7 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase, case KEY_RSA: case KEY_DSA: case KEY_ECDSA: + case KEY_SM2: #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_XMSS: diff --git a/cipher.c b/cipher.c index 609450d..7f98413 100644 --- a/cipher.c +++ b/cipher.c @@ -86,6 +86,7 @@ static const struct sshcipher ciphers[] = { #endif { "chacha20-poly1305@openssh.com", 8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL }, + { "sm4-ctr", 16, 16, 0, 0, 0, EVP_sm4_ctr }, { "none", 8, 0, 0, 0, CFLAG_NONE, NULL }, { NULL, 0, 0, 0, 0, 0, NULL } diff --git a/digest-openssl.c b/digest-openssl.c index 94730e9..fa92360 100644 --- a/digest-openssl.c +++ b/digest-openssl.c @@ -61,6 +61,7 @@ const struct ssh_digest digests[] = { { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 }, { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 }, { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 }, + { SSH_DIGEST_SM3, "SM3", 32, EVP_sm3 }, { -1, NULL, 0, NULL }, }; diff --git a/digest.h b/digest.h index c7ceeb3..520722c 100644 --- a/digest.h +++ b/digest.h @@ -27,7 +27,8 @@ #define SSH_DIGEST_SHA256 2 #define SSH_DIGEST_SHA384 3 #define SSH_DIGEST_SHA512 4 -#define SSH_DIGEST_MAX 5 +#define SSH_DIGEST_SM3 5 +#define SSH_DIGEST_MAX 6 struct sshbuf; struct ssh_digest_ctx; diff --git a/kex.c b/kex.c index 0fbd0ca..e9dfcc2 100644 --- a/kex.c +++ b/kex.c @@ -125,6 +125,7 @@ static const struct kexalg kexalgs[] = { SSH_DIGEST_SHA512 }, #endif #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ + { "sm2-sm3", KEX_SM2_SM3, NID_sm2, SSH_DIGEST_SM3 }, { NULL, 0, -1, -1}, }; static const struct kexalg gss_kexalgs[] = { diff --git a/kex.h b/kex.h index 0fac9d3..044ec18 100644 --- a/kex.h +++ b/kex.h @@ -102,6 +102,7 @@ enum kex_exchange { KEX_ECDH_SHA2, KEX_C25519_SHA256, KEX_KEM_SNTRUP761X25519_SHA512, + KEX_SM2_SM3, #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], __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); +int SM2KAP_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, const EC_KEY *eckey, int server); + #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) void dump_digest(const char *, const u_char *, int); #endif diff --git a/kexecdh.c b/kexecdh.c index efb2e55..69ec13b 100644 --- a/kexecdh.c +++ b/kexecdh.c @@ -44,7 +44,7 @@ static int kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, - const EC_GROUP *, struct sshbuf **); + const EC_GROUP *, struct sshbuf **, int server); int kex_ecdh_keypair(struct kex *kex) @@ -124,7 +124,7 @@ kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, (r = sshbuf_get_u32(server_blob, NULL)) != 0) goto out; if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, group, - shared_secretp)) != 0) + shared_secretp, 1)) != 0) goto out; *server_blobp = server_blob; server_blob = NULL; @@ -136,7 +136,7 @@ kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, static int kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, - EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp) + EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp, int server) { struct sshbuf *buf = NULL; BIGNUM *shared_secret = NULL; @@ -176,11 +176,20 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, r = SSH_ERR_ALLOC_FAIL; goto out; } - if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || + if (kex->ec_nid == NID_sm2) { + if (SM2KAP_compute_key(kbuf, klen, dh_pub, key, server) != (int)klen || BN_bin2bn(kbuf, klen, shared_secret) == NULL) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + } else { + if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || + BN_bin2bn(kbuf, klen, shared_secret) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } } + #ifdef DEBUG_KEXECDH dump_digest("shared secret", kbuf, klen); #endif @@ -203,7 +212,7 @@ kex_ecdh_dec(struct kex *kex, const struct sshbuf *server_blob, int r; r = kex_ecdh_dec_key_group(kex, server_blob, kex->ec_client_key, - kex->ec_group, shared_secretp); + kex->ec_group, shared_secretp, 0); EC_KEY_free(kex->ec_client_key); kex->ec_client_key = NULL; return r; diff --git a/kexgen.c b/kexgen.c index ca70484..4855d5c 100644 --- a/kexgen.c +++ b/kexgen.c @@ -111,6 +111,7 @@ kex_gen_client(struct ssh *ssh) r = kex_dh_keypair(kex); break; case KEX_ECDH_SHA2: + case KEX_SM2_SM3: r = kex_ecdh_keypair(kex); break; #endif @@ -182,6 +183,7 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) r = kex_dh_dec(kex, server_blob, &shared_secret); break; case KEX_ECDH_SHA2: + case KEX_SM2_SM3: 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) &shared_secret); break; case KEX_ECDH_SHA2: + case KEX_SM2_SM3: r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; diff --git a/kexsm2.c b/kexsm2.c new file mode 100644 index 0000000..f507557 --- /dev/null +++ b/kexsm2.c @@ -0,0 +1,406 @@ +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/bn.h> +#include <string.h> +#include <openssl/ecdh.h> +#include <openssl/ec.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) { + 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) { + goto done; + } + + if (!EVP_DigestInit(hash, digest)) { + goto done; + } + + /* Z = h(ENTL || ID || a || b || xG || yG || xA || yA) */ + + if (id_len >= (UINT16_MAX / 8)) { + /* too large */ + goto done; + } + + entl = (uint16_t)(8 * id_len); + + e_byte = entl >> 8; + if (!EVP_DigestUpdate(hash, &e_byte, 1)) { + goto done; + } + e_byte = entl & 0xFF; + if (!EVP_DigestUpdate(hash, &e_byte, 1)) { + goto done; + } + + if (id_len > 0 && !EVP_DigestUpdate(hash, id, id_len)) { + goto done; + } + + if (!EC_GROUP_get_curve(group, p, a, b, ctx)) { + goto done; + } + + p_bytes = BN_num_bytes(p); + buf = OPENSSL_zalloc(p_bytes); + if (buf == NULL) { + 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)) { + goto done; + } + + rc = 1; + + done: + OPENSSL_free(buf); + BN_CTX_free(ctx); + EVP_MD_CTX_free(hash); + return rc; +} + + +/* GM/T003_2012 Defined Key Derive Function */ +int kdf_gmt003_2012(unsigned char *out, size_t outlen, const unsigned char *Z, size_t Zlen, const unsigned char *SharedInfo, size_t SharedInfolen, const EVP_MD *md) +{ + EVP_MD_CTX *mctx = NULL; + unsigned int counter; + unsigned char ctr[4]; + size_t mdlen; + int retval = 0; + unsigned char dgst[EVP_MAX_MD_SIZE]; + + if (!out || !outlen) return retval; + if (md == NULL) { + md = EVP_sm3(); + } + mdlen = EVP_MD_size(md); + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) { + goto err; + } + + for (counter = 1;; counter++) { + if (!EVP_DigestInit(mctx, md)) { + goto err; + } + ctr[0] = (unsigned char)((counter >> 24) & 0xFF); + ctr[1] = (unsigned char)((counter >> 16) & 0xFF); + ctr[2] = (unsigned char)((counter >> 8) & 0xFF); + ctr[3] = (unsigned char)(counter & 0xFF); + + if (!EVP_DigestUpdate(mctx, Z, Zlen)) { + goto err; + } + if (!EVP_DigestUpdate(mctx, ctr, sizeof(ctr))) { + goto err; + } + if (!EVP_DigestUpdate(mctx, SharedInfo, SharedInfolen)) { + goto err; + } + if (!EVP_DigestFinal(mctx, dgst, NULL)) { + goto err; + } + + if (outlen > mdlen) { + memcpy(out, dgst, mdlen); + out += mdlen; + outlen -= mdlen; + } else { + memcpy(out, dgst, outlen); + memset(dgst, 0, mdlen); + break; + } + } + + retval = 1; + +err: + EVP_MD_CTX_free(mctx); + return retval; +} + +int sm2_kap_compute_key(void *out, size_t outlen, int server,\ + const uint8_t *peer_uid, int peer_uid_len, const uint8_t *self_uid, int self_uid_len, \ + const EC_KEY *peer_ecdhe_key, const EC_KEY *self_ecdhe_key, const EC_KEY *peer_pub_key, const EC_KEY *self_eckey, \ + const EVP_MD *md) +{ + BN_CTX *ctx = NULL; + EC_POINT *UorV = NULL; + const EC_POINT *Rs, *Rp; + BIGNUM *Xs = NULL, *Xp = NULL, *h = NULL, *t = NULL, *two_power_w = NULL, *order = NULL; + const BIGNUM *priv_key, *r; + const EC_GROUP *group; + int w; + int ret = -1; + size_t buflen, len; + unsigned char *buf = NULL; + + if (outlen > INT_MAX) { + goto err; + } + + if (!peer_pub_key || !self_eckey) { + goto err; + } + + priv_key = EC_KEY_get0_private_key(self_eckey); + if (!priv_key) { + goto err; + } + + if (!peer_ecdhe_key || !self_ecdhe_key) { + goto err; + } + + Rs = EC_KEY_get0_public_key(self_ecdhe_key); + Rp = EC_KEY_get0_public_key(peer_ecdhe_key); + r = EC_KEY_get0_private_key(self_ecdhe_key); + + if (!Rs || !Rp || !r) { + goto err; + } + + ctx = BN_CTX_new(); + Xs = BN_new(); + Xp = BN_new(); + h = BN_new(); + t = BN_new(); + two_power_w = BN_new(); + order = BN_new(); + if (!Xs || !Xp || !h || !t || !two_power_w || !order) { + goto err; + } + + group = EC_KEY_get0_group(self_eckey); + + /*Second: Caculate -- w*/ + if (!EC_GROUP_get_order(group, order, ctx) || !EC_GROUP_get_cofactor(group, h, ctx)) { + goto err; + } + + w = (BN_num_bits(order) + 1) / 2 - 1; + if (!BN_lshift(two_power_w, BN_value_one(), w)) { + goto err; + } + + /*Third: Caculate -- X = 2 ^ w + (x & (2 ^ w - 1)) = 2 ^ w + (x mod 2 ^ w)*/ + UorV = EC_POINT_new(group); + + if (!UorV) { + goto err; + } + + /*Test peer public key On curve*/ + if (!EC_POINT_is_on_curve(group, Rp, ctx)) { + goto err; + } + + /*Get x*/ + if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { + if (!EC_POINT_get_affine_coordinates_GFp(group, Rs, Xs, NULL, ctx)) { + goto err; + } + + if (!EC_POINT_get_affine_coordinates_GFp(group, Rp, Xp, NULL, ctx)) { + goto err; + } + } + + /*x mod 2 ^ w*/ + /*Caculate Self x*/ + if (!BN_nnmod(Xs, Xs, two_power_w, ctx)) { + goto err; + } + + if (!BN_add(Xs, Xs, two_power_w)) { + goto err; + } + + /*Caculate Peer x*/ + if (!BN_nnmod(Xp, Xp, two_power_w, ctx)) { + goto err; + } + + if (!BN_add(Xp, Xp, two_power_w)) { + goto err; + } + + /*Forth: Caculate t*/ + if (!BN_mod_mul(t, Xs, r, order, ctx)) { + goto err; + } + + if (!BN_mod_add(t, t, priv_key, order, ctx)) { + goto err; + } + + /*Fifth: Caculate V or U*/ + if (!BN_mul(t, t, h, ctx)) { + goto err; + } + + /* [x]R */ + if (!EC_POINT_mul(group, UorV, NULL, Rp, Xp, ctx)) { + goto err; + } + + /* P + [x]R */ + if (!EC_POINT_add(group, UorV, UorV, EC_KEY_get0_public_key(peer_pub_key), ctx)) { + goto err; + } + + if (!EC_POINT_mul(group, UorV, NULL, UorV, t, ctx)) { + goto err; + } + + /* Detect UorV is in */ + if (EC_POINT_is_at_infinity(group, UorV)) { + goto err; + } + + /*Sixth: Caculate Key -- Need Xuorv, Yuorv, Zc, Zs, klen*/ + { + /* + size_t buflen, len; + unsigned char *buf = NULL; + */ + size_t elemet_len, idx; + + elemet_len = (size_t)((EC_GROUP_get_degree(group) + 7) / 8); + buflen = elemet_len * 2 + 32 * 2 + 1; /*add 1 byte tag*/ + buf = (unsigned char *)OPENSSL_malloc(buflen + 10); + if (!buf) { + goto err; + } + memset(buf, 0, buflen + 10); + /*1 : Get public key for UorV, Notice: the first byte is a tag, not a valid char*/ + idx = EC_POINT_point2oct(group, UorV, 4, buf, buflen, ctx); + if (!idx) { + goto err; + } + + if (!server) { + /*SIDE A*/ + len = buflen - idx; + if (!sm2_compute_z_digest( (unsigned char *)(buf + idx), md, (const uint8_t *)self_uid, self_uid_len, self_eckey)) { + goto err; + } + len = 32; + idx += len; + } + + /*Caculate Peer Z*/ + len = buflen - idx; + if (!sm2_compute_z_digest( (unsigned char *)(buf + idx), md, (const uint8_t *)peer_uid, peer_uid_len, peer_pub_key)) { + goto err; + } + len = 32; + idx += len; + + if (server) { + /*SIDE B*/ + len = buflen - idx; + if (!sm2_compute_z_digest( (unsigned char *)(buf + idx), md, (const uint8_t *)self_uid, self_uid_len, self_eckey)) { + goto err; + } + len = 32; + idx += len; + } + + len = outlen; + if (!kdf_gmt003_2012(out, len, (const unsigned char *)(buf + 1), idx - 1, NULL, 0, md)) { + goto err; + } + } + + ret = outlen; + +err: + if (Xs) BN_free(Xs); + if (Xp) BN_free(Xp); + if (h) BN_free(h); + if (t) BN_free(t); + if (two_power_w) BN_free(two_power_w); + if (order) BN_free(order); + if (UorV) EC_POINT_free(UorV); + if (buf) OPENSSL_free(buf); + if (ctx) BN_CTX_free(ctx); + + return ret; +} + +int SM2KAP_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, const EC_KEY *eckey, int server) +{ + int ret = 0; + EC_KEY *pubkey = NULL; + unsigned char id[16] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; + + if ((pubkey = EC_KEY_new_by_curve_name(NID_sm2)) == NULL) { + return ret; + } + + if (EC_KEY_set_public_key(pubkey, pub_key) != 1) { + ret = 0; + goto out; + } + + ret = sm2_kap_compute_key(out, outlen, server, id, sizeof(id), id, sizeof(id), pubkey, eckey, pubkey, eckey, (EVP_MD*)EVP_sm3()); + +out: + EC_KEY_free(pubkey); + return ret; +} diff --git a/mac.c b/mac.c index bf051ba..2de17a0 100644 --- a/mac.c +++ b/mac.c @@ -65,6 +65,7 @@ static const struct macalg macs[] = { { "hmac-md5-96", SSH_DIGEST, SSH_DIGEST_MD5, 96, 0, 0, 0 }, { "umac-64@openssh.com", SSH_UMAC, 0, 0, 128, 64, 0 }, { "umac-128@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 0 }, + { "hmac-sm3", SSH_DIGEST, SSH_DIGEST_SM3, 0, 0, 0, 0 }, /* Encrypt-then-MAC variants */ { "hmac-sha1-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 1 }, diff --git a/pathnames.h b/pathnames.h index a094888..0a805ad 100644 --- a/pathnames.h +++ b/pathnames.h @@ -80,6 +80,7 @@ #define _PATH_SSH_CLIENT_ID_XMSS _PATH_SSH_USER_DIR "/id_xmss" #define _PATH_SSH_CLIENT_ID_ECDSA_SK _PATH_SSH_USER_DIR "/id_ecdsa_sk" #define _PATH_SSH_CLIENT_ID_ED25519_SK _PATH_SSH_USER_DIR "/id_ed25519_sk" +#define _PATH_SSH_CLIENT_ID_SM2 _PATH_SSH_USER_DIR "/id_sm2" /* * 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 --- a/regress/agent.sh +++ b/regress/agent.sh @@ -87,9 +87,18 @@ fi for t in ${SSH_KEYTYPES}; do trace "connect via agent using $t key" if [ "$t" = "ssh-dss" ]; then + sed -i "/PubkeyAcceptedAlgorithms/d" $OBJ/ssh_proxy + sed -i "/PubkeyAcceptedAlgorithms/d" $OBJ/sshd_proxy echo "PubkeyAcceptedAlgorithms +ssh-dss" >> $OBJ/ssh_proxy echo "PubkeyAcceptedAlgorithms +ssh-dss" >> $OBJ/sshd_proxy fi + if [ "$t" = "sm2" ]; then + sed -i "/PubkeyAcceptedAlgorithms/d" $OBJ/ssh_proxy + sed -i "/PubkeyAcceptedAlgorithms/d" $OBJ/sshd_proxy + echo "PubkeyAcceptedAlgorithms +sm2,sm2-cert" >> $OBJ/ssh_proxy + echo "PubkeyAcceptedAlgorithms +sm2,sm2-cert" >> $OBJ/sshd_proxy + fi + ${SSH} -F $OBJ/ssh_proxy -i $OBJ/$t-agent.pub -oIdentitiesOnly=yes \ somehost exit 52 r=$? diff --git a/regress/keytype.sh b/regress/keytype.sh index f1c0451..2665bd6 100644 --- a/regress/keytype.sh +++ b/regress/keytype.sh @@ -18,6 +18,7 @@ for i in ${SSH_KEYTYPES}; do ecdsa-sha2-nistp521) ktypes="$ktypes ecdsa-521" ;; sk-ssh-ed25519*) ktypes="$ktypes ed25519-sk" ;; sk-ecdsa-sha2-nistp256*) ktypes="$ktypes ecdsa-sk" ;; + sm2) ktypes="$ktypes sm2-256" ;; esac done @@ -44,6 +45,7 @@ kname_to_ktype() { rsa-*) echo rsa-sha2-512,rsa-sha2-256,ssh-rsa;; ed25519-sk) echo sk-ssh-ed25519@openssh.com;; ecdsa-sk) echo sk-ecdsa-sha2-nistp256@openssh.com;; + sm2-256) echo sm2;; esac } diff --git a/regress/knownhosts-command.sh b/regress/knownhosts-command.sh index 8472ec8..7f56fb1 100644 --- a/regress/knownhosts-command.sh +++ b/regress/knownhosts-command.sh @@ -41,6 +41,7 @@ ${SSH} -F $OBJ/ssh_proxy x true && fail "ssh connect succeeded with bad exit" for keytype in ${SSH_HOSTKEY_TYPES} ; do algs=$keytype test "x$keytype" = "xssh-dss" && continue + test "x$keytype" = "xsm2" && continue test "x$keytype" = "xssh-rsa" && algs=ssh-rsa,rsa-sha2-256,rsa-sha2-512 verbose "keytype $keytype" cat > $OBJ/knownhosts_command << _EOF diff --git a/regress/misc/fuzz-harness/sig_fuzz.cc b/regress/misc/fuzz-harness/sig_fuzz.cc index b32502b..f260692 100644 --- a/regress/misc/fuzz-harness/sig_fuzz.cc +++ b/regress/misc/fuzz-harness/sig_fuzz.cc @@ -30,6 +30,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* sig, size_t slen) static struct sshkey *ecdsa256 = generate_or_die(KEY_ECDSA, 256); static struct sshkey *ecdsa384 = generate_or_die(KEY_ECDSA, 384); static struct sshkey *ecdsa521 = generate_or_die(KEY_ECDSA, 521); + static struct sshkey *sm2 = generate_or_die(KEY_SM2, 256); #endif struct sshkey_sig_details *details = NULL; static struct sshkey *ed25519 = generate_or_die(KEY_ED25519, 0); @@ -53,6 +54,9 @@ int LLVMFuzzerTestOneInput(const uint8_t* sig, size_t slen) sshkey_verify(ecdsa521, sig, slen, (const u_char *)data, dlen, NULL, 0, &details); sshkey_sig_details_free(details); details = NULL; + sshkey_verify(sm2, sig, slen, (const u_char *)data, dlen, NULL, 0, &details); + sshkey_sig_details_free(details); + details = NULL; #endif 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 --- 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) #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server; + server2->kex->kex[KEX_SM2_SM3] = kex_gen_server; 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) #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ do_kex_with_key(kex, KEY_ED25519, 256); + do_kex_with_key(kex, KEY_SM2, 256); } void @@ -201,6 +203,7 @@ kex_tests(void) do_kex("diffie-hellman-group-exchange-sha1"); do_kex("diffie-hellman-group14-sha1"); do_kex("diffie-hellman-group1-sha1"); + do_kex("sm2-sm3"); # ifdef USE_SNTRUP761X25519 do_kex("sntrup761x25519-sha512@openssh.com"); # endif /* USE_SNTRUP761X25519 */ diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index b705157..5445ab5 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -256,7 +256,8 @@ ssh_ecdsa_sign(struct sshkey *key, *sigp = 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)) 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, 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) return SSH_ERR_INVALID_ARGUMENT; diff --git a/ssh-keygen.c b/ssh-keygen.c index 0bff209..46f4998 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) *bitsp = DEFAULT_BITS_DSA; break; case KEY_ECDSA: + case KEY_SM2: 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) fatal("Invalid RSA key length: maximum is %d bits", OPENSSL_RSA_MAX_MODULUS_BITS); break; + case KEY_SM2: + if (*bitsp != 256) + fatal("Invalid SM2 key length: must be 256 bits"); + break; 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) case KEY_ECDSA: name = _PATH_SSH_CLIENT_ID_ECDSA; break; + case KEY_SM2: + name = _PATH_SSH_CLIENT_ID_SM2; + break; 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) break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: + case KEY_SM2: 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) break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: + case KEY_SM2: if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa)) fatal("PEM_write_EC_PUBKEY failed"); break; @@ -3280,7 +3290,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" - " [-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa]\n" + " [-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa | sm2]\n" " [-w provider] [-Z cipher]\n" " 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 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c @@ -68,9 +68,10 @@ int ssh_port = SSH_DEFAULT_PORT; #define KT_XMSS (1<<4) #define KT_ECDSA_SK (1<<5) #define KT_ED25519_SK (1<<6) +#define KT_SM2 (1<<7) #define KT_MIN KT_DSA -#define KT_MAX KT_ED25519_SK +#define KT_MAX KT_SM2 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) "ecdsa-sha2-nistp384," "ecdsa-sha2-nistp521"; break; + case KT_SM2: + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? + "sm2-cert" : + "sm2"; + break; 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) 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; + c->c_ssh->kex->kex[KEX_SM2_SM3] = kex_gen_client; # endif #endif c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; @@ -789,6 +796,9 @@ main(int argc, char **argv) case KEY_ECDSA: get_keytypes |= KT_ECDSA; break; + case KEY_SM2: + get_keytypes |= KT_SM2; + break; case KEY_RSA: get_keytypes |= KT_RSA; break; diff --git a/ssh-sm2.c b/ssh-sm2.c new file mode 100644 index 0000000..75e9731 --- /dev/null +++ b/ssh-sm2.c @@ -0,0 +1,381 @@ +#include "includes.h" +#include <sys/types.h> +#include <openssl/bn.h> +#include <openssl/ecdsa.h> +#include <openssl/evp.h> + +#include <string.h> +#include "sshbuf.h" +#include "ssherr.h" +#include "digest.h" +#include "sshkey.h" + +#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) +{ + u_char *sig = NULL; + 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; + + if (lenp != NULL) + *lenp = 0; + if (sigp != NULL) + *sigp = NULL; + + if (key == NULL || key->ecdsa == NULL || + sshkey_type_plain(key->type) != KEY_SM2) + return SSH_ERR_INVALID_ARGUMENT; + + if ((key_sm2 = EVP_PKEY_new()) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + + 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; + } + + 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)) { + 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); + } + 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) { + 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_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, pkey)) != 1) { + ret = SSH_ERR_INTERNAL_ERROR; + goto out; + } + + if ((EVP_DigestVerifyUpdate(mctx, data, datalen)) != 1) { + ret = SSH_ERR_INTERNAL_ERROR; + goto out; + } + + if ((EVP_DigestVerifyFinal(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_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 *sig = NULL; + char *ktype = NULL; + 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; + + 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 ((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; + } + + 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 ((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 (ret = sm2_verify_sig(key_sm2, data, datalen, sig, slen)) { + goto out; + } + + ret = 0; +out: + EVP_PKEY_free(key_sm2); + 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 +++ b/ssh_api.c @@ -115,6 +115,7 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; # ifdef OPENSSL_HAS_ECC ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_server; + ssh->kex->kex[KEX_SM2_SM3] = kex_gen_server; # endif #endif /* WITH_OPENSSL */ ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server; @@ -133,6 +134,7 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; # ifdef OPENSSL_HAS_ECC ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; + ssh->kex->kex[KEX_SM2_SM3] = kex_gen_client; # endif #endif /* WITH_OPENSSL */ ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; diff --git a/sshconnect2.c b/sshconnect2.c index 3acfdb6..3fbff57 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -326,6 +326,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; + ssh->kex->kex[KEX_SM2_SM3] = kex_gen_client; # endif # ifdef GSSAPI if (options.gss_keyex) { diff --git a/sshd.c b/sshd.c index f366457..52c66ed 100644 --- a/sshd.c +++ b/sshd.c @@ -695,6 +695,7 @@ list_hostkey_types(void) /* FALLTHROUGH */ case KEY_DSA: case KEY_ECDSA: + case KEY_SM2: case KEY_ED25519: case KEY_ECDSA_SK: case KEY_ED25519_SK: @@ -716,6 +717,7 @@ list_hostkey_types(void) /* FALLTHROUGH */ case KEY_DSA_CERT: case KEY_ECDSA_CERT: + case KEY_SM2_CERT: 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) case KEY_RSA_CERT: case KEY_DSA_CERT: case KEY_ECDSA_CERT: + case KEY_SM2_CERT: 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) continue; switch (type) { case KEY_ECDSA: + case KEY_SM2: case KEY_ECDSA_SK: case KEY_ECDSA_CERT: + case KEY_SM2_CERT: case KEY_ECDSA_SK_CERT: if (key->ecdsa_nid != nid) continue; @@ -2012,6 +2017,7 @@ main(int ac, char **av) case KEY_RSA: case KEY_DSA: case KEY_ECDSA: + case KEY_SM2: case KEY_ED25519: case KEY_ECDSA_SK: case KEY_ED25519_SK: @@ -2573,6 +2579,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; + kex->kex[KEX_SM2_SM3] = kex_gen_server; # endif # ifdef GSSAPI if (options.gss_keyex) { diff --git a/sshkey.c b/sshkey.c index 1735159..1aee244 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 }; @@ -340,6 +344,8 @@ key_type_is_ecdsa_variant(int type) case KEY_ECDSA_CERT: case KEY_ECDSA_SK: case KEY_ECDSA_SK_CERT: + case KEY_SM2: + case KEY_SM2_CERT: return 1; } return 0; @@ -548,6 +554,8 @@ sshkey_type_plain(int type) return KEY_ED25519_SK; case KEY_XMSS_CERT: return KEY_XMSS; + case KEY_SM2_CERT: + return KEY_SM2; 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) else if (strcmp(name, "nistp521") == 0) return NID_secp521r1; # endif /* OPENSSL_HAS_NISTP521 */ + else if (strcmp(name, "sm2") == 0) + return NID_sm2; else return -1; } @@ -686,6 +698,8 @@ sshkey_curve_nid_to_bits(int nid) case NID_secp521r1: return 521; # endif /* OPENSSL_HAS_NISTP521 */ + case NID_sm2: + return 256; default: return 0; } @@ -720,6 +734,8 @@ sshkey_curve_nid_to_name(int nid) case NID_secp521r1: return "nistp521"; # endif /* OPENSSL_HAS_NISTP521 */ + case NID_sm2: + return "sm2"; default: return NULL; } @@ -3424,6 +3440,7 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: + case KEY_SM2: 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, #ifdef WITH_OPENSSL case KEY_DSA: case KEY_ECDSA: + case KEY_SM2: case KEY_RSA: break; /* see below */ #endif /* WITH_OPENSSL */ @@ -3665,6 +3683,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); + if (prv->ecdsa_nid == NID_sm2) { + prv->type = KEY_SM2; + } if (prv->ecdsa_nid == -1 || 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 --- a/sshkey.h +++ b/sshkey.h @@ -68,6 +68,8 @@ enum sshkey_types { KEY_DSA_CERT, KEY_ECDSA_CERT, KEY_ED25519_CERT, + KEY_SM2, + KEY_SM2_CERT, KEY_XMSS, KEY_XMSS_CERT, KEY_ECDSA_SK, -- 2.23.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2