Browse Source

Support SM2 certificate verification

Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/8321)
杨洋 5 years ago
parent
commit
8267becb8b

+ 40 - 5
apps/verify.c

@@ -21,7 +21,8 @@
 static int cb(int ok, X509_STORE_CTX *ctx);
 static int check(X509_STORE *ctx, const char *file,
                  STACK_OF(X509) *uchain, STACK_OF(X509) *tchain,
-                 STACK_OF(X509_CRL) *crls, int show_chain);
+                 STACK_OF(X509_CRL) *crls, int show_chain,
+                 unsigned char *sm2id, size_t sm2idlen);
 static int v_verbose = 0, vflags = 0;
 
 typedef enum OPTION_choice {
@@ -29,7 +30,7 @@ typedef enum OPTION_choice {
     OPT_ENGINE, OPT_CAPATH, OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE,
     OPT_UNTRUSTED, OPT_TRUSTED, OPT_CRLFILE, OPT_CRL_DOWNLOAD, OPT_SHOW_CHAIN,
     OPT_V_ENUM, OPT_NAMEOPT,
-    OPT_VERBOSE
+    OPT_VERBOSE, OPT_SM2ID, OPT_SM2HEXID
 } OPTION_CHOICE;
 
 const OPTIONS verify_options[] = {
@@ -56,6 +57,12 @@ const OPTIONS verify_options[] = {
     OPT_V_OPTIONS,
 #ifndef OPENSSL_NO_ENGINE
     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
+#endif
+#ifndef OPENSSL_NO_SM2
+    {"sm2-id", OPT_SM2ID, 's',
+     "Specify an ID string to verify an SM2 certificate"},
+    {"sm2-hex-id", OPT_SM2HEXID, 's',
+     "Specify a hex ID string to verify an SM2 certificate"},
 #endif
     {NULL}
 };
@@ -71,6 +78,8 @@ int verify_main(int argc, char **argv)
     int noCApath = 0, noCAfile = 0;
     int vpmtouched = 0, crl_download = 0, show_chain = 0, i = 0, ret = 1;
     OPTION_CHOICE o;
+    unsigned char *sm2_id = NULL;
+    size_t sm2_idlen = 0;
 
     if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
         goto end;
@@ -158,6 +167,19 @@ int verify_main(int argc, char **argv)
         case OPT_VERBOSE:
             v_verbose = 1;
             break;
+        case OPT_SM2ID:
+            /* we assume the input is not a hex string */
+            sm2_id = (unsigned char *)opt_arg();
+            sm2_idlen = strlen((const char *)sm2_id);
+            break;
+        case OPT_SM2HEXID:
+            /* try to parse the input as hex string first */
+            sm2_id = OPENSSL_hexstr2buf(opt_arg(), (long *)&sm2_idlen);
+            if (sm2_id == NULL) {
+                BIO_printf(bio_err, "Invalid hex string input\n");
+                goto end;
+            }
+            break;
         }
     }
     argc = opt_num_rest();
@@ -183,12 +205,13 @@ int verify_main(int argc, char **argv)
 
     ret = 0;
     if (argc < 1) {
-        if (check(store, NULL, untrusted, trusted, crls, show_chain) != 1)
+        if (check(store, NULL, untrusted, trusted, crls, show_chain,
+                  sm2_id, sm2_idlen) != 1)
             ret = -1;
     } else {
         for (i = 0; i < argc; i++)
             if (check(store, argv[i], untrusted, trusted, crls,
-                      show_chain) != 1)
+                      show_chain, sm2_id, sm2_idlen) != 1)
                 ret = -1;
     }
 
@@ -204,7 +227,8 @@ int verify_main(int argc, char **argv)
 
 static int check(X509_STORE *ctx, const char *file,
                  STACK_OF(X509) *uchain, STACK_OF(X509) *tchain,
-                 STACK_OF(X509_CRL) *crls, int show_chain)
+                 STACK_OF(X509_CRL) *crls, int show_chain,
+                 unsigned char *sm2id, size_t sm2idlen)
 {
     X509 *x = NULL;
     int i = 0, ret = 0;
@@ -216,6 +240,17 @@ static int check(X509_STORE *ctx, const char *file,
     if (x == NULL)
         goto end;
 
+    if (sm2id != NULL) {
+#ifndef OPENSSL_NO_SM2
+        ASN1_OCTET_STRING v;
+
+        v.data = sm2id;
+        v.length = sm2idlen;
+
+        X509_set_sm2_id(x, &v);
+#endif
+    }
+
     csc = X509_STORE_CTX_new();
     if (csc == NULL) {
         printf("error %s: X.509 store context allocation failed\n",

+ 1 - 2
crypto/asn1/a_verify.c

@@ -94,7 +94,7 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
     int mdnid, pknid;
     size_t inll = 0;
 
-    if (!pkey) {
+    if (pkey == NULL) {
         ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_PASSED_NULL_PARAMETER);
         return -1;
     }
@@ -150,7 +150,6 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
             ret = 0;
             goto err;
         }
-
     }
 
     inl = ASN1_item_i2d(asn, &buf_in, it);

+ 2 - 0
crypto/err/openssl.txt

@@ -1834,8 +1834,10 @@ X509_F_X509_STORE_NEW:158:X509_STORE_new
 X509_F_X509_TO_X509_REQ:126:X509_to_X509_REQ
 X509_F_X509_TRUST_ADD:133:X509_TRUST_add
 X509_F_X509_TRUST_SET:141:X509_TRUST_set
+X509_F_X509_VERIFY:161:X509_verify
 X509_F_X509_VERIFY_CERT:127:X509_verify_cert
 X509_F_X509_VERIFY_PARAM_NEW:159:X509_VERIFY_PARAM_new
+X509_F_X509_VERIFY_SM2:162:x509_verify_sm2
 
 #Reason codes
 ASN1_R_ADDING_OBJECT:171:adding object

+ 4 - 1
crypto/include/internal/x509_int.h

@@ -175,7 +175,7 @@ struct x509_st {
     STACK_OF(DIST_POINT) *crldp;
     STACK_OF(GENERAL_NAME) *altname;
     NAME_CONSTRAINTS *nc;
-#ifndef OPENSSL_NO_RFC3779
+# ifndef OPENSSL_NO_RFC3779
     STACK_OF(IPAddressFamily) *rfc3779_addr;
     struct ASIdentifiers_st *rfc3779_asid;
 # endif
@@ -183,6 +183,9 @@ struct x509_st {
     X509_CERT_AUX *aux;
     CRYPTO_RWLOCK *lock;
     volatile int ex_cached;
+# ifndef OPENSSL_NO_SM2
+    ASN1_OCTET_STRING sm2_id;
+# endif
 } /* X509 */ ;
 
 /*

+ 10 - 5
crypto/objects/obj_dat.h

@@ -10,7 +10,7 @@
  */
 
 /* Serialized OID's */
-static const unsigned char so[7767] = {
+static const unsigned char so[7775] = {
     0x2A,0x86,0x48,0x86,0xF7,0x0D,                 /* [    0] OBJ_rsadsi */
     0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,            /* [    6] OBJ_pkcs */
     0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x02,       /* [   13] OBJ_md2 */
@@ -1077,9 +1077,10 @@ static const unsigned char so[7767] = {
     0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0C,       /* [ 7745] OBJ_hmacWithSHA512_224 */
     0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0D,       /* [ 7753] OBJ_hmacWithSHA512_256 */
     0x28,0xCC,0x45,0x03,0x04,                      /* [ 7761] OBJ_gmac */
+    0x2A,0x81,0x1C,0xCF,0x55,0x01,0x83,0x75,       /* [ 7766] OBJ_SM2_with_SM3 */
 };
 
-#define NUM_NID 1204
+#define NUM_NID 1205
 static const ASN1_OBJECT nid_objs[NUM_NID] = {
     {"UNDEF", "undefined", NID_undef},
     {"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]},
@@ -2285,9 +2286,10 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = {
     {"BLAKE2BMAC", "blake2bmac", NID_blake2bmac},
     {"BLAKE2SMAC", "blake2smac", NID_blake2smac},
     {"SSHKDF", "sshkdf", NID_sshkdf},
+    {"SM2-SM3", "SM2-with-SM3", NID_SM2_with_SM3, 8, &so[7766]},
 };
 
-#define NUM_SN 1195
+#define NUM_SN 1196
 static const unsigned int sn_objs[NUM_SN] = {
      364,    /* "AD_DVCS" */
      419,    /* "AES-128-CBC" */
@@ -2561,6 +2563,7 @@ static const unsigned int sn_objs[NUM_SN] = {
     1100,    /* "SHAKE128" */
     1101,    /* "SHAKE256" */
     1172,    /* "SM2" */
+    1204,    /* "SM2-SM3" */
     1143,    /* "SM3" */
     1134,    /* "SM4-CBC" */
     1137,    /* "SM4-CFB" */
@@ -3486,7 +3489,7 @@ static const unsigned int sn_objs[NUM_SN] = {
     1093,    /* "x509ExtAdmission" */
 };
 
-#define NUM_LN 1195
+#define NUM_LN 1196
 static const unsigned int ln_objs[NUM_LN] = {
      363,    /* "AD Time Stamping" */
      405,    /* "ANSI X9.62" */
@@ -3642,6 +3645,7 @@ static const unsigned int ln_objs[NUM_LN] = {
     1119,    /* "RSA-SHA3-512" */
      188,    /* "S/MIME" */
      167,    /* "S/MIME Capabilities" */
+    1204,    /* "SM2-with-SM3" */
     1006,    /* "SNILS" */
      387,    /* "SNMPv2" */
     1025,    /* "SSH Client" */
@@ -4685,7 +4689,7 @@ static const unsigned int ln_objs[NUM_LN] = {
      125,    /* "zlib compression" */
 };
 
-#define NUM_OBJ 1072
+#define NUM_OBJ 1073
 static const unsigned int obj_objs[NUM_OBJ] = {
        0,    /* OBJ_undef                        0 */
      181,    /* OBJ_iso                          1 */
@@ -5155,6 +5159,7 @@ static const unsigned int obj_objs[NUM_OBJ] = {
     1139,    /* OBJ_sm4_ctr                      1 2 156 10197 1 104 7 */
     1172,    /* OBJ_sm2                          1 2 156 10197 1 301 */
     1143,    /* OBJ_sm3                          1 2 156 10197 1 401 */
+    1204,    /* OBJ_SM2_with_SM3                 1 2 156 10197 1 501 */
     1144,    /* OBJ_sm3WithRSAEncryption         1 2 156 10197 1 504 */
      776,    /* OBJ_seed_ecb                     1 2 410 200004 1 3 */
      777,    /* OBJ_seed_cbc                     1 2 410 200004 1 4 */

+ 1 - 0
crypto/objects/obj_mac.num

@@ -1201,3 +1201,4 @@ aes_256_siv		1200
 blake2bmac		1201
 blake2smac		1202
 sshkdf		1203
+SM2_with_SM3		1204

+ 2 - 0
crypto/objects/obj_xref.h

@@ -79,6 +79,7 @@ static const nid_triple sigoid_srt[] = {
     {NID_RSA_SHA3_256, NID_sha3_256, NID_rsaEncryption},
     {NID_RSA_SHA3_384, NID_sha3_384, NID_rsaEncryption},
     {NID_RSA_SHA3_512, NID_sha3_512, NID_rsaEncryption},
+    {NID_SM2_with_SM3, NID_sm3, NID_sm2},
 };
 
 static const nid_triple *const sigoid_srt_xref[] = {
@@ -125,4 +126,5 @@ static const nid_triple *const sigoid_srt_xref[] = {
     &sigoid_srt[45],
     &sigoid_srt[46],
     &sigoid_srt[47],
+    &sigoid_srt[48],
 };

+ 2 - 0
crypto/objects/obj_xref.txt

@@ -64,3 +64,5 @@ dhSinglePass_cofactorDH_sha224kdf_scheme	sha224	dh_cofactor_kdf
 dhSinglePass_cofactorDH_sha256kdf_scheme	sha256	dh_cofactor_kdf
 dhSinglePass_cofactorDH_sha384kdf_scheme	sha384	dh_cofactor_kdf
 dhSinglePass_cofactorDH_sha512kdf_scheme	sha512	dh_cofactor_kdf
+
+SM2_with_SM3		sm3	sm2

+ 2 - 0
crypto/objects/objects.txt

@@ -394,6 +394,8 @@ sm-scheme 301           : SM2                   : sm2
 sm-scheme 401           : SM3                   : sm3
 sm-scheme 504           : RSA-SM3		: sm3WithRSAEncryption
 
+sm-scheme 501           : SM2-SM3               : SM2-with-SM3
+
 # From RFC4231
 rsadsi 2 8		:			: hmacWithSHA224
 rsadsi 2 9		:			: hmacWithSHA256

+ 4 - 0
crypto/sm2/sm2_pmeth.c

@@ -220,6 +220,10 @@ static int pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
         *(size_t *)p2 = smctx->id_len;
         return 1;
 
+    case EVP_PKEY_CTRL_DIGESTINIT:
+        /* nothing to be inited, this is to suppress the error... */
+        return 1;
+
     default:
         return -2;
     }

+ 3 - 1
crypto/x509/x509_err.c

@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -104,9 +104,11 @@ static const ERR_STRING_DATA X509_str_functs[] = {
     {ERR_PACK(ERR_LIB_X509, X509_F_X509_TO_X509_REQ, 0), "X509_to_X509_REQ"},
     {ERR_PACK(ERR_LIB_X509, X509_F_X509_TRUST_ADD, 0), "X509_TRUST_add"},
     {ERR_PACK(ERR_LIB_X509, X509_F_X509_TRUST_SET, 0), "X509_TRUST_set"},
+    {ERR_PACK(ERR_LIB_X509, X509_F_X509_VERIFY, 0), "X509_verify"},
     {ERR_PACK(ERR_LIB_X509, X509_F_X509_VERIFY_CERT, 0), "X509_verify_cert"},
     {ERR_PACK(ERR_LIB_X509, X509_F_X509_VERIFY_PARAM_NEW, 0),
      "X509_VERIFY_PARAM_new"},
+    {ERR_PACK(ERR_LIB_X509, X509_F_X509_VERIFY_SM2, 0), "x509_verify_sm2"},
     {0, NULL}
 };
 

+ 110 - 0
crypto/x509/x_all.c

@@ -19,10 +19,120 @@
 #include <openssl/dsa.h>
 #include <openssl/x509v3.h>
 
+#ifndef OPENSSL_NO_SM2
+
+# include "internal/asn1_int.h"
+# include "internal/evp_int.h"
+
+static int x509_verify_sm2(X509 *x, EVP_PKEY *pkey, int mdnid, int pknid)
+{
+    EVP_MD_CTX *ctx = NULL;
+    unsigned char *buf_in = NULL;
+    int ret = -1, inl = 0;
+    size_t inll = 0;
+    EVP_PKEY_CTX *pctx = NULL;
+    const EVP_MD *type = EVP_get_digestbynid(mdnid);
+
+    if (type == NULL) {
+        X509err(X509_F_X509_VERIFY_SM2,
+                ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
+        goto err;
+    }
+
+    if (pkey == NULL) {
+        X509err(X509_F_X509_VERIFY_SM2, ERR_R_PASSED_NULL_PARAMETER);
+        return -1;
+    }
+
+    if (x->signature.type == V_ASN1_BIT_STRING && x->signature.flags & 0x7) {
+        X509err(X509_F_X509_VERIFY_SM2, ASN1_R_INVALID_BIT_STRING_BITS_LEFT);
+        return -1;
+    }
+
+    ctx = EVP_MD_CTX_new();
+    if (ctx == NULL) {
+        X509err(X509_F_X509_VERIFY_SM2, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    /* Check public key OID matches public key type */
+    if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id) {
+        X509err(X509_F_X509_VERIFY_SM2, ASN1_R_WRONG_PUBLIC_KEY_TYPE);
+        goto err;
+    }
+
+    if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) {
+        X509err(X509_F_X509_VERIFY_SM2, ERR_R_EVP_LIB);
+        ret = 0;
+        goto err;
+    }
+    pctx = EVP_PKEY_CTX_new(pkey, NULL);
+    if (pctx == NULL) {
+        X509err(X509_F_X509_VERIFY_SM2, ERR_R_EVP_LIB);
+        ret = 0;
+        goto err;
+    }
+    if (EVP_PKEY_CTX_set1_id(pctx, x->sm2_id.data, x->sm2_id.length) != 1) {
+        X509err(X509_F_X509_VERIFY_SM2, ERR_R_EVP_LIB);
+        ret = 0;
+        goto err;
+    }
+    EVP_MD_CTX_set_pkey_ctx(ctx, pctx);
+
+    if (!EVP_DigestVerifyInit(ctx, NULL, type, NULL, pkey)) {
+        X509err(X509_F_X509_VERIFY_SM2, ERR_R_EVP_LIB);
+        ret = 0;
+        goto err;
+    }
+
+    inl = ASN1_item_i2d((ASN1_VALUE *)&x->cert_info, &buf_in,
+                        ASN1_ITEM_rptr(X509_CINF));
+    if (inl <= 0) {
+        X509err(X509_F_X509_VERIFY_SM2, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    if (buf_in == NULL) {
+        X509err(X509_F_X509_VERIFY_SM2, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    inll = inl;
+
+    ret = EVP_DigestVerify(ctx, x->signature.data,
+                           (size_t)x->signature.length, buf_in, inl);
+    if (ret <= 0) {
+        X509err(X509_F_X509_VERIFY_SM2, ERR_R_EVP_LIB);
+        goto err;
+    }
+    ret = 1;
+ err:
+    OPENSSL_clear_free(buf_in, inll);
+    EVP_MD_CTX_free(ctx);
+    EVP_PKEY_CTX_free(pctx);
+    return ret;
+}
+#endif
+
 int X509_verify(X509 *a, EVP_PKEY *r)
 {
+#ifndef OPENSSL_NO_SM2
+    int mdnid, pknid;
+#endif
+
     if (X509_ALGOR_cmp(&a->sig_alg, &a->cert_info.signature))
         return 0;
+
+#ifndef OPENSSL_NO_SM2
+    /* Convert signature OID into digest and public key OIDs */
+    if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->sig_alg.algorithm),
+                             &mdnid, &pknid)) {
+        X509err(X509_F_X509_VERIFY, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
+        return 0;
+    }
+
+    if (pknid == NID_sm2)
+        return x509_verify_sm2(a, r, mdnid, pknid);
+#endif
+
     return (ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF), &a->sig_alg,
                              &a->signature, &a->cert_info, r));
 }

+ 12 - 0
crypto/x509/x_x509.c

@@ -244,3 +244,15 @@ int X509_get_signature_nid(const X509 *x)
 {
     return OBJ_obj2nid(x->sig_alg.algorithm);
 }
+
+#ifndef OPENSSL_NO_SM2
+void X509_set_sm2_id(X509 *x, ASN1_OCTET_STRING *sm2_id)
+{
+    x->sm2_id = *sm2_id;
+}
+
+ASN1_OCTET_STRING *X509_get0_sm2_id(X509 *x)
+{
+    return &x->sm2_id;
+}
+#endif

+ 1 - 0
fuzz/oids.txt

@@ -1064,3 +1064,4 @@ OBJ_id_tc26_gost_3410_2012_256_paramSetD="\x2A\x85\x03\x07\x01\x02\x01\x01\x04"
 OBJ_hmacWithSHA512_224="\x2A\x86\x48\x86\xF7\x0D\x02\x0C"
 OBJ_hmacWithSHA512_256="\x2A\x86\x48\x86\xF7\x0D\x02\x0D"
 OBJ_gmac="\x28\xCC\x45\x03\x04"
+OBJ_SM2_with_SM3="\x2A\x81\x1C\xCF\x55\x01\x83\x75"

+ 5 - 0
include/openssl/obj_mac.h

@@ -1200,6 +1200,11 @@
 #define NID_sm3WithRSAEncryption                1144
 #define OBJ_sm3WithRSAEncryption                OBJ_sm_scheme,504L
 
+#define SN_SM2_with_SM3         "SM2-SM3"
+#define LN_SM2_with_SM3         "SM2-with-SM3"
+#define NID_SM2_with_SM3                1204
+#define OBJ_SM2_with_SM3                OBJ_sm_scheme,501L
+
 #define LN_hmacWithSHA224               "hmacWithSHA224"
 #define NID_hmacWithSHA224              798
 #define OBJ_hmacWithSHA224              OBJ_rsadsi,2L,8L

+ 3 - 0
include/openssl/x509.h

@@ -566,6 +566,9 @@ void X509_get0_signature(const ASN1_BIT_STRING **psig,
                          const X509_ALGOR **palg, const X509 *x);
 int X509_get_signature_nid(const X509 *x);
 
+void X509_set_sm2_id(X509 *x, ASN1_OCTET_STRING *sm2_id);
+ASN1_OCTET_STRING *X509_get0_sm2_id(X509 *x);
+
 int X509_trusted(const X509 *x);
 int X509_alias_set1(X509 *x, const unsigned char *name, int len);
 int X509_keyid_set1(X509 *x, const unsigned char *id, int len);

+ 2 - 0
include/openssl/x509err.h

@@ -82,8 +82,10 @@ int ERR_load_X509_strings(void);
 # define X509_F_X509_TO_X509_REQ                          126
 # define X509_F_X509_TRUST_ADD                            133
 # define X509_F_X509_TRUST_SET                            141
+# define X509_F_X509_VERIFY                               161
 # define X509_F_X509_VERIFY_CERT                          127
 # define X509_F_X509_VERIFY_PARAM_NEW                     159
+# define X509_F_X509_VERIFY_SM2                           162
 
 /*
  * X509 reason codes.

+ 2 - 0
util/libcrypto.num

@@ -4788,3 +4788,5 @@ OSSL_PARAM_get_utf8_ptr                 4735	3_0_0	EXIST::FUNCTION:
 OSSL_PARAM_set_utf8_ptr                 4736	3_0_0	EXIST::FUNCTION:
 OSSL_PARAM_get_octet_ptr                4737	3_0_0	EXIST::FUNCTION:
 OSSL_PARAM_set_octet_ptr                4738	3_0_0	EXIST::FUNCTION:
+X509_set_sm2_id                         4739	3_0_0	EXIST::FUNCTION:
+X509_get0_sm2_id                        4740	3_0_0	EXIST::FUNCTION: