Projects
Eulaceura:Factory
gnupg2
_service:obs_scm:supports-sm2-algorithm-signatu...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:supports-sm2-algorithm-signature-and-uses-sm3-hash-algorithm.patch of Package gnupg2
From 12689a050972bc6a07c0b8dfdd379c50087b614b Mon Sep 17 00:00:00 2001 From: zhengxiaoxiao <zhengxiaoxiao2@huawei.com> Date: Sat, 26 Oct 2024 16:59:41 +0800 Subject: [PATCH] Supports sm2 algorithm signature and uses sm3 hash algorithm. Co-authored-by: Huaxin Lu <luhuaxin1@huawei.com> Signed-off-by: zhengxiaoxiao <zhengxiaoxiao2@huawei.com> --- agent/pksign.c | 25 +++++++- common/Makefile.am | 3 + common/openpgp-oid.c | 31 +++++++++ common/openpgpdefs.h | 4 ++ common/sm2.c | 149 +++++++++++++++++++++++++++++++++++++++++++ common/sm2.h | 24 +++++++ common/util.h | 3 + configure.ac | 10 +++ g10/keygen.c | 3 + g10/misc.c | 13 +++- g10/pkglue.c | 5 ++ g10/sig-check.c | 12 ++++ g10/sign.c | 16 ++++- sm/gpgsm.c | 3 + 14 files changed, 295 insertions(+), 6 deletions(-) create mode 100644 common/sm2.c create mode 100644 common/sm2.h diff --git a/agent/pksign.c b/agent/pksign.c index a7b5c57..249bcd9 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -28,7 +28,9 @@ #include "agent.h" #include "../common/i18n.h" - +#ifdef GPG_USE_SM2 +#include "../common/sm2.h" +#endif static int do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash, @@ -209,7 +211,14 @@ do_encode_dsa (const byte *md, size_t mdlen, int pkalgo, gcry_sexp_t pkey, mdlen = qbits/8; /* Create the S-expression. */ - err = gcry_sexp_build (&hash, NULL, +#ifdef GPG_USE_SM2 + if (pkey_is_sm2(pkey)) + err = gcry_sexp_build (&hash, NULL, + "(data (flags sm2) (hash %s %b))", + "sm3", (int)mdlen, md); + else +#endif + err = gcry_sexp_build (&hash, NULL, "(data (flags rfc6979) (hash %s %b))", rfc6979_hash_algo_string (mdlen), (int)mdlen, md); @@ -494,6 +503,18 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, { /* No smartcard, but a private key (in S_SKEY). */ +#ifdef GPG_USE_SM2 + /* calculate sm2 digest */ + if (pkey_is_sm2(s_skey)) + { + if (!s_pkey) + agent_public_key_from_file (ctrl, ctrl->keygrip, &s_pkey); + + err = update_sm2_hash_value (data, datalen, s_pkey, data); + if (err) + goto leave; + } +#endif /* Put the hash into a sexp */ if (algo == GCRY_PK_EDDSA) err = do_encode_eddsa (gcry_pk_get_nbits (s_skey), data, datalen, diff --git a/common/Makefile.am b/common/Makefile.am index d5ab038..5e7ac35 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -99,6 +99,9 @@ common_sources = \ compliance.c compliance.h \ pkscreening.c pkscreening.h +if GPG_USE_SM2 +common_sources += sm2.c sm2.h +endif if HAVE_W32_SYSTEM common_sources += w32-reg.c w32-cmdline.c diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c index 4930549..767a4e5 100644 --- a/common/openpgp-oid.c +++ b/common/openpgp-oid.c @@ -62,6 +62,9 @@ static struct { { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512 }, { "secp256k1", "1.3.132.0.10", 256 }, +#ifdef GPG_USE_SM2 + { "sm2p256v1", "1.2.156.10197.1.301", 256 }, +#endif { NULL, NULL, 0} }; @@ -92,6 +95,10 @@ static const char oid_cv448[] = { 0x03, 0x2b, 0x65, 0x6f }; /* The OID for Ed448 in OpenPGP format. */ static const char oid_ed448[] = { 0x03, 0x2b, 0x65, 0x71 }; +#ifdef GPG_USE_SM2 +/* The OID for SM2 in OpenPGP format. */ +static const char oid_sm2[] = { 0x08, 0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x82, 0x2d }; +#endif /* A table to store keyalgo strings like "rsa2048 or "ed25519" so that * we do not need to allocate them. This is currently a simple array @@ -381,6 +388,15 @@ openpgp_oidbuf_is_cv448 (const void *buf, size_t len) && !memcmp (buf, oid_cv448, DIM (oid_cv448))); } +#ifdef GPG_USE_SM2 +/* Return true if (BUF,LEN) represents the OID for SM2. */ +static int +openpgp_oidbuf_is_sm2 (const void *buf, size_t len) +{ + return (buf && len == DIM (oid_sm2) + && !memcmp (buf, oid_sm2, DIM (oid_sm2))); +} +#endif /* Return true if the MPI A represents the OID for Curve25519. */ int @@ -426,6 +442,21 @@ openpgp_oid_is_cv448 (gcry_mpi_t a) return openpgp_oidbuf_is_cv448 (buf, (nbits+7)/8); } +#ifdef GPG_USE_SM2 +/* Return true if the MPI A represents the OID for SM2. */ +int +openpgp_oid_is_sm2 (gcry_mpi_t a) +{ + const unsigned char *buf; + unsigned int nbits; + + if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) + return 0; + + buf = gcry_mpi_get_opaque (a, &nbits); + return openpgp_oidbuf_is_sm2 (buf, (nbits+7)/8); +} +#endif /* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL store the bit size of the curve there. Returns NULL for unknown diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h index 6257479..fd7e668 100644 --- a/common/openpgpdefs.h +++ b/common/openpgpdefs.h @@ -184,6 +184,10 @@ typedef enum DIGEST_ALGO_SHA384 = 9, DIGEST_ALGO_SHA512 = 10, DIGEST_ALGO_SHA224 = 11, +#ifdef GPG_USE_SM2 + /* 100-110 Private or Experimental Use */ + DIGEST_ALGO_SM3 = 109, +#endif DIGEST_ALGO_PRIVATE10 = 110 } digest_algo_t; diff --git a/common/sm2.c b/common/sm2.c new file mode 100644 index 0000000..2d34dbb --- /dev/null +++ b/common/sm2.c @@ -0,0 +1,149 @@ +/* openpgp-oids.c - OID helper for OpenPGP + * Copyright (C) 2024 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + */ + +#include "sm2.h" + +const unsigned char zin_default[] = { + 0x00, 0x80, // id length + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, // default id: 1234567812345678 + 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, // sm2 a + 0x28, 0xe9, 0xfa, 0x9e, 0x9d, 0x9f, 0x5e, 0x34, 0x4d, 0x5a, 0x9e, 0x4b, + 0xcf, 0x65, 0x09, 0xa7, 0xf3, 0x97, 0x89, 0xf5, 0x15, 0xab, 0x8f, 0x92, + 0xdd, 0xbc, 0xbd, 0x41, 0x4d, 0x94, 0x0e, 0x93, // sm2 b + 0x32, 0xc4, 0xae, 0x2c, 0x1f, 0x19, 0x81, 0x19, 0x5f, 0x99, 0x04, 0x46, + 0x6a, 0x39, 0xc9, 0x94, 0x8f, 0xe3, 0x0b, 0xbf, 0xf2, 0x66, 0x0b, 0xe1, + 0x71, 0x5a, 0x45, 0x89, 0x33, 0x4c, 0x74, 0xc7, // sm2 x + 0xbc, 0x37, 0x36, 0xa2, 0xf4, 0xf6, 0x77, 0x9c, 0x59, 0xbd, 0xce, 0xe3, + 0x6b, 0x69, 0x21, 0x53, 0xd0, 0xa9, 0x87, 0x7c, 0xc6, 0x2a, 0x47, 0x40, + 0x02, 0xdf, 0x32, 0xe5, 0x21, 0x39, 0xf0, 0xa0 // sm2 y +}; + +static gpg_error_t +calculate_za (gcry_mpi_t pkey, unsigned char *result) +{ + gpg_error_t err; + gcry_md_hd_t md; + unsigned char q[65]; + size_t qlen; + + err = gcry_mpi_print (GCRYMPI_FMT_STD, q, sizeof(q), &qlen, pkey); + if (err) + return err; + + err = gcry_md_open (&md, GCRY_MD_SM3_PGP, 0); + if (err) + return err; + + gcry_md_write (md, zin_default, sizeof(zin_default)); + gcry_md_write (md, q + 1, qlen - 1); + gcry_md_final (md); + memcpy (result, gcry_md_read (md, GCRY_MD_SM3_PGP), 32); + gcry_md_close (md); + + return 0; +} + +gpg_error_t +update_sm2_hash_md (gcry_md_hd_t md, gcry_mpi_t pkey) +{ + gpg_error_t err; + unsigned char za[32]; + unsigned char msg[32]; + + if (!md || !pkey) + return gpg_error (GPG_ERR_INV_VALUE); + + err = calculate_za(pkey, za); + if (err) + return err; + + memcpy(msg, gcry_md_read(md, GCRY_MD_SM3_PGP), 32); + gcry_md_reset(md); + gcry_md_write(md, za, sizeof(za)); + gcry_md_write(md, msg, sizeof(msg)); + gcry_md_final(md); + + return 0; +} + +gpg_error_t +update_sm2_hash_value (unsigned char *msg, size_t msglen, gcry_sexp_t s_pkey, unsigned char *result) +{ + gpg_error_t err; + gcry_sexp_t q_sexp; + gcry_mpi_t q_mpi; + gcry_md_hd_t md; + unsigned char za[32]; + + if(!msg || !s_pkey || !result) + return gpg_error (GPG_ERR_INV_VALUE); + + q_sexp = gcry_sexp_find_token(s_pkey, "q", 0); + if (!q_sexp) + return gpg_error (GPG_ERR_NO_PUBKEY); + + q_mpi = gcry_sexp_nth_mpi (q_sexp, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (q_sexp); + if (!q_mpi) + return gpg_error (GPG_ERR_NO_PUBKEY); + + err = calculate_za (q_mpi, za); + gcry_mpi_release (q_mpi); + if (err) + return err; + + err = gcry_md_open (&md, GCRY_MD_SM3_PGP, 0); + if (err) + return err; + + gcry_md_write (md, za, sizeof(za)); + gcry_md_write (md, msg, msglen); + gcry_md_final (md); + memcpy (result, gcry_md_read (md, GCRY_MD_SM3_PGP), 32); + gcry_md_close (md); + + return 0; +} + +int pkey_is_sm2 (gcry_sexp_t pkey) +{ + const char *curve; + + if (!pkey) + return 0; + + curve = gcry_pk_get_curve (pkey, 0, NULL); + if (curve && !strcmp (curve, "sm2p256v1")) + return 1; + + return 0; +} diff --git a/common/sm2.h b/common/sm2.h new file mode 100644 index 0000000..7cd38d4 --- /dev/null +++ b/common/sm2.h @@ -0,0 +1,24 @@ +/* sm2.h + * Copyright (C) 2024 Free Software Foundation, Inc. + * + * This file is free software; as a special exception the author gives + * unlimited permission to copy and/or distribute it, with or without + * modifications, as long as this notice is preserved. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY, to the extent permitted by law; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +#ifndef GNUPG_COMMON_SM2_H +#define GNUPG_COMMON_SM2_H + +#include <gcrypt.h> +#include <errno.h> +#include <gpg-error.h> + +gpg_error_t update_sm2_hash_md (gcry_md_hd_t md, gcry_mpi_t pkey); +gpg_error_t update_sm2_hash_value (unsigned char *msg, size_t msglen, gcry_sexp_t s_pkey, unsigned char *result); + +#endif /*GNUPG_COMMON_SM2_H*/ diff --git a/common/util.h b/common/util.h index aa24e39..7b5a1d8 100644 --- a/common/util.h +++ b/common/util.h @@ -250,6 +250,9 @@ int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len); int openpgp_oid_is_cv25519 (gcry_mpi_t a); int openpgp_oid_is_cv448 (gcry_mpi_t a); int openpgp_oid_is_ed448 (gcry_mpi_t a); +#ifdef GPG_USE_SM2 +int openpgp_oid_is_sm2 (gcry_mpi_t a); +#endif const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo); const char *openpgp_oid_to_curve (const char *oid, int canon); diff --git a/configure.ac b/configure.ac index e68b779..3cffc4d 100644 --- a/configure.ac +++ b/configure.ac @@ -341,6 +341,16 @@ GNUPG_GPG_DISABLE_ALGO([sha224],[SHA-224 hash]) GNUPG_GPG_DISABLE_ALGO([sha384],[SHA-384 hash]) GNUPG_GPG_DISABLE_ALGO([sha512],[SHA-512 hash]) +AC_ARG_ENABLE([sm2], + [AS_HELP_STRING([--enable-sm2], [Enable SM2 support])], + [enable_sm2=$enableval], + [enable_sm2=no]) + +if test "x$enable_sm2" = "xyes"; then + AC_DEFINE([GPG_USE_SM2], [1], [Define if SM2 support is enabled]) + AM_CONDITIONAL([GPG_USE_SM2], [test "x$enable_sm2" = "xyes"]) + CFLAGS="$CFLAGS -DUSE_SM3_PGP" +fi # Allow disabling of zip support. # This is in general not a good idea because according to rfc4880 OpenPGP diff --git a/g10/keygen.c b/g10/keygen.c index 6ead599..b6c357e 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -2603,6 +2603,9 @@ ask_curve (int *algo, int *subkey_algo, const char *current) { "brainpoolP384r1", NULL, "Brainpool P-384", MY_USE_ECDSADH, 1, 1, 0 }, { "brainpoolP512r1", NULL, "Brainpool P-512", MY_USE_ECDSADH, 1, 1, 0 }, { "secp256k1", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, +#ifdef GPG_USE_SM2 + { "sm2p256v1", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, +#endif }; #undef MY_USE_ECDSADH int idx; diff --git a/g10/misc.c b/g10/misc.c index 2f4b452..7e60131 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -866,6 +866,11 @@ map_md_openpgp_to_gcry (digest_algo_t algo) case DIGEST_ALGO_SHA512: return GCRY_MD_SHA512; #else case DIGEST_ALGO_SHA512: return 0; +#endif +#ifdef GPG_USE_SM2 + case DIGEST_ALGO_SM3: return GCRY_MD_SM3_PGP; +#else + case DIGEST_ALGO_SM3: return 0; #endif default: return 0; } @@ -902,6 +907,9 @@ openpgp_md_algo_name (int algo) case DIGEST_ALGO_SHA384: return "SHA384"; case DIGEST_ALGO_SHA512: return "SHA512"; case DIGEST_ALGO_SHA224: return "SHA224"; +#ifdef GPG_USE_SM2 + case DIGEST_ALGO_SM3: return "SM3"; +#endif } return "?"; } @@ -1291,7 +1299,10 @@ string_to_digest_algo (const char *string) if (!*string || *endptr || openpgp_md_test_algo (val)) val = 0; } - +#ifdef GPG_USE_SM2 + if (val == GCRY_MD_SM3) + val = GCRY_MD_SM3_PGP; +#endif return val; } diff --git a/g10/pkglue.c b/g10/pkglue.c index f183139..497b555 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -297,6 +297,11 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash, { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); +#ifdef GPG_USE_SM2 + else if (openpgp_oid_is_sm2(pkey[0])) + rc = gcry_sexp_build (&s_sig, NULL, + "(sig-val(sm2(r%m)(s%m)))", data[0], data[1]); +#endif else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]); diff --git a/g10/sig-check.c b/g10/sig-check.c index 06329f6..d59de92 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -34,6 +34,9 @@ #include "options.h" #include "pkglue.h" #include "../common/compliance.h" +#ifdef GPG_USE_SM2 +#include "../common/sm2.h" +#endif static int check_signature_end (PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest, @@ -622,6 +625,15 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig, } gcry_md_final( digest ); +#ifdef GPG_USE_SM2 + if (openpgp_oid_is_sm2 (pk->pkey[0])) + { + rc = update_sm2_hash_md (digest, pk->pkey[1]); + if (!rc) + return rc; + } +#endif + /* Convert the digest to an MPI. */ result = encode_md_value (pk, digest, sig->digest_algo ); if (!result) diff --git a/g10/sign.c b/g10/sign.c index 05ab5b7..913edb4 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -671,6 +671,10 @@ hash_for (PKT_public_key *pk) { unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]); +#ifdef GPG_USE_SM2 + if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA && openpgp_oid_is_sm2(pk->pkey[0])) + return DIGEST_ALGO_SM3; +#endif if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA) qbytes = ecdsa_qbits_from_Q (qbytes); qbytes = qbytes/8; @@ -703,7 +707,6 @@ hash_for (PKT_public_key *pk) return prefs->value; } } - return match_dsa_hash(qbytes); } else if (openpgp_card_v1_p (pk)) @@ -1869,8 +1872,15 @@ make_keysig_packet (ctrl_t ctrl, else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) /* Meet DSA requirements. */ digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA) /* Meet ECDSA requirements. */ - digest_algo = match_dsa_hash - (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8); + { +#ifdef GPG_USE_SM2 + if (openpgp_oid_is_sm2(pk->pkey[0])) + digest_algo = DIGEST_ALGO_SM3; + else +#endif + digest_algo = match_dsa_hash + (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8); + } else if (pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) { if (gcry_mpi_get_nbits (pksk->pkey[1]) > 256) diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 636d14a..d4aa70f 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -590,6 +590,9 @@ our_md_test_algo (int algo) case GCRY_MD_SHA384: case GCRY_MD_SHA512: case GCRY_MD_WHIRLPOOL: +#ifdef GPG_USE_SM2 + case GCRY_MD_SM3: +#endif return gcry_md_test_algo (algo); default: return 1; -- 2.43.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