Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
+ *) Support SM2 signing and verification schemes with X509 certificate.
+ [Paul Yang]
+
*) Use SHA256 as the default digest for TS query in the ts app.
[Tomas Mraz]
const char *enddate,
long days, int batch, const char *ext_sect, CONF *conf,
int verbose, unsigned long certopt, unsigned long nameopt,
- int default_op, int ext_copy, int selfsign);
+ int default_op, int ext_copy, int selfsign,
+ unsigned char *sm2_id, size_t sm2idlen);
static int certify_cert(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509,
const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
STACK_OF(CONF_VALUE) *policy, CA_DB *db,
OPT_INFILES, OPT_SS_CERT, OPT_SPKAC, OPT_REVOKE, OPT_VALID,
OPT_EXTENSIONS, OPT_EXTFILE, OPT_STATUS, OPT_UPDATEDB, OPT_CRLEXTS,
OPT_RAND_SERIAL,
- OPT_R_ENUM,
+ OPT_R_ENUM, OPT_SM2ID, OPT_SM2HEXID,
/* Do not change the order here; see related case statements below */
OPT_CRL_REASON, OPT_CRL_HOLD, OPT_CRL_COMPROMISE, OPT_CRL_CA_COMPROMISE
} OPTION_CHOICE;
OPT_R_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 request"},
+ {"sm2-hex-id", OPT_SM2HEXID, 's',
+ "Specify a hex ID string to verify an SM2 certificate request"},
#endif
{NULL}
};
REVINFO_TYPE rev_type = REV_NONE;
X509_REVOKED *r = NULL;
OPTION_CHOICE o;
+ unsigned char *sm2_id = NULL;
+ size_t sm2_idlen = 0;
+ int sm2_free = 0;
prog = opt_init(argc, argv, ca_options);
while ((o = opt_next()) != OPT_EOF) {
case OPT_ENGINE:
e = setup_engine(opt_arg(), 0);
break;
+ case OPT_SM2ID:
+ /* we assume the input is not a hex string */
+ if (sm2_id != NULL) {
+ BIO_printf(bio_err,
+ "Use one of the options 'sm2-hex-id' or 'sm2-id'\n");
+ goto end;
+ }
+ 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 */
+ if (sm2_id != NULL) {
+ BIO_printf(bio_err,
+ "Use one of the options 'sm2-hex-id' or 'sm2-id'\n");
+ goto end;
+ }
+ sm2_free = 1;
+ 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;
}
}
end_of_options:
j = certify(&x, infile, pkey, x509p, dgst, sigopts, attribs, db,
serial, subj, chtype, multirdn, email_dn, startdate,
enddate, days, batch, extensions, conf, verbose,
- certopt, get_nameopt(), default_op, ext_copy, selfsign);
+ certopt, get_nameopt(), default_op, ext_copy, selfsign,
+ sm2_id, sm2_idlen);
if (j < 0)
goto end;
if (j > 0) {
j = certify(&x, argv[i], pkey, x509p, dgst, sigopts, attribs, db,
serial, subj, chtype, multirdn, email_dn, startdate,
enddate, days, batch, extensions, conf, verbose,
- certopt, get_nameopt(), default_op, ext_copy, selfsign);
+ certopt, get_nameopt(), default_op, ext_copy, selfsign,
+ sm2_id, sm2_idlen);
if (j < 0)
goto end;
if (j > 0) {
ret = 0;
end:
+ if (sm2_free)
+ OPENSSL_free(sm2_id);
if (ret)
ERR_print_errors(bio_err);
BIO_free_all(Sout);
const char *enddate,
long days, int batch, const char *ext_sect, CONF *lconf,
int verbose, unsigned long certopt, unsigned long nameopt,
- int default_op, int ext_copy, int selfsign)
+ int default_op, int ext_copy, int selfsign,
+ unsigned char *sm2id, size_t sm2idlen)
{
X509_REQ *req = NULL;
BIO *in = NULL;
BIO_printf(bio_err, "error unpacking public key\n");
goto end;
}
+ if (sm2id != NULL) {
+#ifndef OPENSSL_NO_SM2
+ ASN1_OCTET_STRING *v;
+
+ v = ASN1_OCTET_STRING_new();
+ if (v == NULL) {
+ BIO_printf(bio_err, "error: SM2 ID allocation failed\n");
+ goto end;
+ }
+
+ if (!ASN1_OCTET_STRING_set(v, sm2id, sm2idlen)) {
+ BIO_printf(bio_err, "error: setting SM2 ID failed\n");
+ ASN1_OCTET_STRING_free(v);
+ goto end;
+ }
+
+ X509_REQ_set0_sm2_id(req, v);
+#endif
+ }
i = X509_REQ_verify(req, pktmp);
pktmp = NULL;
if (i < 0) {
OPT_VERIFY, OPT_NODES, OPT_NOOUT, OPT_VERBOSE, OPT_UTF8,
OPT_NAMEOPT, OPT_REQOPT, OPT_SUBJ, OPT_SUBJECT, OPT_TEXT, OPT_X509,
OPT_MULTIVALUE_RDN, OPT_DAYS, OPT_SET_SERIAL, OPT_ADDEXT, OPT_EXTENSIONS,
- OPT_REQEXTS, OPT_PRECERT, OPT_MD,
+ OPT_REQEXTS, OPT_PRECERT, OPT_MD, OPT_SM2ID, OPT_SM2HEXID,
OPT_R_ENUM
} OPTION_CHOICE;
{"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
{"keygen_engine", OPT_KEYGEN_ENGINE, 's',
"Specify engine to be used for key generation operations"},
+#endif
+#ifndef OPENSSL_NO_SM2
+ {"sm2-id", OPT_SM2ID, 's',
+ "Specify an ID string to verify an SM2 certificate request"},
+ {"sm2-hex-id", OPT_SM2HEXID, 's',
+ "Specify a hex ID string to verify an SM2 certificate request"},
#endif
{NULL}
};
int nodes = 0, newhdr = 0, subject = 0, pubkey = 0, precert = 0;
long newkey = -1;
unsigned long chtype = MBSTRING_ASC, reqflag = 0;
+ unsigned char *sm2_id = NULL;
+ size_t sm2_idlen = 0;
+ int sm2_free = 0;
#ifndef OPENSSL_NO_DES
cipher = EVP_des_ede3_cbc();
goto opthelp;
digest = md_alg;
break;
+ case OPT_SM2ID:
+ if (sm2_id != NULL) {
+ BIO_printf(bio_err,
+ "Use one of the options 'sm2-hex-id' or 'sm2-id'\n");
+ goto end;
+ }
+ sm2_id = (unsigned char *)opt_arg();
+ sm2_idlen = strlen((const char *)sm2_id);
+ break;
+ case OPT_SM2HEXID:
+ if (sm2_id != NULL) {
+ BIO_printf(bio_err,
+ "Use one of the options 'sm2-hex-id' or 'sm2-id'\n");
+ goto end;
+ }
+ /* try to parse the input as hex string first */
+ sm2_free = 1;
+ 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();
goto end;
}
+ if (sm2_id != NULL) {
+#ifndef OPENSSL_NO_SM2
+ ASN1_OCTET_STRING *v;
+
+ v = ASN1_OCTET_STRING_new();
+ if (v == NULL) {
+ BIO_printf(bio_err, "error: SM2 ID allocation failed\n");
+ goto end;
+ }
+
+ if (!ASN1_OCTET_STRING_set(v, sm2_id, sm2_idlen)) {
+ BIO_printf(bio_err, "error: setting SM2 ID failed\n");
+ ASN1_OCTET_STRING_free(v);
+ goto end;
+ }
+
+ X509_REQ_set0_sm2_id(req, v);
+#endif
+ }
+
i = X509_REQ_verify(req, tpubkey);
if (i < 0) {
}
ret = 0;
end:
+ if (sm2_free)
+ OPENSSL_free(sm2_id);
if (ret) {
ERR_print_errors(bio_err);
}
return 1;
}
+#ifndef OPENSSL_NO_SM2
+static int ec_pkey_is_sm2(EVP_PKEY *pkey)
+{
+ EC_KEY *eckey = NULL;
+ const EC_GROUP *group = NULL;
+
+ if (EVP_PKEY_id(pkey) == EVP_PKEY_SM2)
+ return 1;
+ if (EVP_PKEY_id(pkey) == EVP_PKEY_EC
+ && (eckey = EVP_PKEY_get0_EC_KEY(pkey)) != NULL
+ && (group = EC_KEY_get0_group(eckey)) != NULL
+ && EC_GROUP_get_curve_name(group) == NID_sm2)
+ return 1;
+ return 0;
+}
+#endif
+
static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey,
const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts)
{
EVP_PKEY_CTX *pkctx = NULL;
- int i, def_nid;
+#ifndef OPENSSL_NO_SM2
+ EVP_PKEY_CTX *pctx = NULL;
+#endif
+ int i, def_nid, ret = 0;
if (ctx == NULL)
- return 0;
+ goto err;
+#ifndef OPENSSL_NO_SM2
+ if (ec_pkey_is_sm2(pkey)) {
+ /* initialize some SM2-specific code */
+ if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) {
+ BIO_printf(bio_err, "Internal error.\n");
+ goto err;
+ }
+ pctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (pctx == NULL) {
+ BIO_printf(bio_err, "memory allocation failure.\n");
+ goto err;
+ }
+ /* set SM2 ID from sig options before calling the real init routine */
+ for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) {
+ char *sigopt = sk_OPENSSL_STRING_value(sigopts, i);
+ if (pkey_ctrl_string(pctx, sigopt) <= 0) {
+ BIO_printf(bio_err, "parameter error \"%s\"\n", sigopt);
+ ERR_print_errors(bio_err);
+ goto err;
+ }
+ }
+ EVP_MD_CTX_set_pkey_ctx(ctx, pctx);
+ }
+#endif
/*
* EVP_PKEY_get_default_digest_nid() returns 2 if the digest is mandatory
* for this algorithm.
md = NULL;
}
if (!EVP_DigestSignInit(ctx, &pkctx, md, NULL, pkey))
- return 0;
+ goto err;
for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) {
char *sigopt = sk_OPENSSL_STRING_value(sigopts, i);
if (pkey_ctrl_string(pkctx, sigopt) <= 0) {
BIO_printf(bio_err, "parameter error \"%s\"\n", sigopt);
ERR_print_errors(bio_err);
- return 0;
+ goto err;
}
}
- return 1;
+
+ ret = 1;
+ err:
+#ifndef OPENSSL_NO_SM2
+ if (!ret)
+ EVP_PKEY_CTX_free(pctx);
+#endif
+ return ret;
}
int do_X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md,
{
int rv;
EVP_MD_CTX *mctx = EVP_MD_CTX_new();
+#ifndef OPENSSL_NO_SM2
+ EVP_PKEY_CTX *pctx = NULL;
+#endif
rv = do_sign_init(mctx, pkey, md, sigopts);
if (rv > 0)
rv = X509_sign_ctx(x, mctx);
+#ifndef OPENSSL_NO_SM2
+ /* only in SM2 case we need to free the pctx explicitly */
+ if (ec_pkey_is_sm2(pkey)) {
+ pctx = EVP_MD_CTX_pkey_ctx(mctx);
+ EVP_PKEY_CTX_free(pctx);
+ }
+#endif
EVP_MD_CTX_free(mctx);
return rv > 0 ? 1 : 0;
}
{
int rv;
EVP_MD_CTX *mctx = EVP_MD_CTX_new();
+#ifndef OPENSSL_NO_SM2
+ EVP_PKEY_CTX *pctx = NULL;
+#endif
+
rv = do_sign_init(mctx, pkey, md, sigopts);
if (rv > 0)
rv = X509_REQ_sign_ctx(x, mctx);
+#ifndef OPENSSL_NO_SM2
+ /* only in SM2 case we need to free the pctx explicitly */
+ if (ec_pkey_is_sm2(pkey)) {
+ pctx = EVP_MD_CTX_pkey_ctx(mctx);
+ EVP_PKEY_CTX_free(pctx);
+ }
+#endif
EVP_MD_CTX_free(mctx);
return rv > 0 ? 1 : 0;
}
{
int rv;
EVP_MD_CTX *mctx = EVP_MD_CTX_new();
+#ifndef OPENSSL_NO_SM2
+ EVP_PKEY_CTX *pctx = NULL;
+#endif
+
rv = do_sign_init(mctx, pkey, md, sigopts);
if (rv > 0)
rv = X509_CRL_sign_ctx(x, mctx);
+#ifndef OPENSSL_NO_SM2
+ /* only in SM2 case we need to free the pctx explicitly */
+ if (ec_pkey_is_sm2(pkey)) {
+ pctx = EVP_MD_CTX_pkey_ctx(mctx);
+ EVP_PKEY_CTX_free(pctx);
+ }
+#endif
EVP_MD_CTX_free(mctx);
return rv > 0 ? 1 : 0;
}
unsigned char *buf_in = NULL, *buf_out = NULL;
size_t inl = 0, outl = 0, outll = 0;
int signid, paramtype, buf_len = 0;
- int rv;
+ int rv, pkey_id;
type = EVP_MD_CTX_md(ctx);
pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx));
ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, ASN1_R_CONTEXT_NOT_INITIALISED);
goto err;
}
- if (!OBJ_find_sigid_by_algs(&signid,
- EVP_MD_nid(type),
- pkey->ameth->pkey_id)) {
+
+ pkey_id =
+#ifndef OPENSSL_NO_SM2
+ EVP_PKEY_id(pkey) == NID_sm2 ? NID_sm2 :
+#endif
+ pkey->ameth->pkey_id;
+
+ if (!OBJ_find_sigid_by_algs(&signid, EVP_MD_nid(type), pkey_id)) {
ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX,
ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
goto err;
EVP_MD_type((const EVP_MD *)p2) != NID_sha3_224 &&
EVP_MD_type((const EVP_MD *)p2) != NID_sha3_256 &&
EVP_MD_type((const EVP_MD *)p2) != NID_sha3_384 &&
- EVP_MD_type((const EVP_MD *)p2) != NID_sha3_512) {
+ EVP_MD_type((const EVP_MD *)p2) != NID_sha3_512 &&
+ EVP_MD_type((const EVP_MD *)p2) != NID_sm3) {
ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_DIGEST_TYPE);
return 0;
}
X509_F_BY_FILE_CTRL:101:by_file_ctrl
X509_F_CHECK_NAME_CONSTRAINTS:149:check_name_constraints
X509_F_CHECK_POLICY:145:check_policy
+X509_F_COMMON_VERIFY_SM2:165:common_verify_sm2
X509_F_DANE_I2D:107:dane_i2d
X509_F_DIR_CTRL:102:dir_ctrl
X509_F_GET_CERT_BY_SUBJECT:103:get_cert_by_subject
X509_F_X509_REQ_PRINT_EX:121:X509_REQ_print_ex
X509_F_X509_REQ_PRINT_FP:122:X509_REQ_print_fp
X509_F_X509_REQ_TO_X509:123:X509_REQ_to_X509
+X509_F_X509_REQ_VERIFY:163:X509_REQ_verify
+X509_F_X509_REQ_VERIFY_SM2:164:x509_req_verify_sm2
X509_F_X509_STORE_ADD_CERT:124:X509_STORE_add_cert
X509_F_X509_STORE_ADD_CRL:125:X509_STORE_add_crl
X509_F_X509_STORE_ADD_LOOKUP:157:X509_STORE_add_lookup
ASN1_BIT_STRING *signature; /* signature */
CRYPTO_REF_COUNT references;
CRYPTO_RWLOCK *lock;
+# ifndef OPENSSL_NO_SM2
+ ASN1_OCTET_STRING *sm2_id;
+# endif
};
struct X509_crl_info_st {
{ERR_PACK(ERR_LIB_X509, X509_F_CHECK_NAME_CONSTRAINTS, 0),
"check_name_constraints"},
{ERR_PACK(ERR_LIB_X509, X509_F_CHECK_POLICY, 0), "check_policy"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_COMMON_VERIFY_SM2, 0), "common_verify_sm2"},
{ERR_PACK(ERR_LIB_X509, X509_F_DANE_I2D, 0), "dane_i2d"},
{ERR_PACK(ERR_LIB_X509, X509_F_DIR_CTRL, 0), "dir_ctrl"},
{ERR_PACK(ERR_LIB_X509, X509_F_GET_CERT_BY_SUBJECT, 0),
{ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_PRINT_EX, 0), "X509_REQ_print_ex"},
{ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_PRINT_FP, 0), "X509_REQ_print_fp"},
{ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_TO_X509, 0), "X509_REQ_to_X509"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_VERIFY, 0), "X509_REQ_verify"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_VERIFY_SM2, 0),
+ "x509_req_verify_sm2"},
{ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_ADD_CERT, 0),
"X509_STORE_add_cert"},
{ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_ADD_CRL, 0),
# include "internal/asn1_int.h"
# include "internal/evp_int.h"
-static int x509_verify_sm2(X509 *x, EVP_PKEY *pkey, int mdnid, int pknid)
+static int common_verify_sm2(void *data, EVP_PKEY *pkey,
+ int mdnid, int pknid, int req)
{
+ X509 *x = NULL;
+ X509_REQ *r = NULL;
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);
+ ASN1_BIT_STRING *signature = NULL;
+ ASN1_OCTET_STRING *sm2_id = NULL;
+ ASN1_VALUE *tbv = NULL;
if (type == NULL) {
- X509err(X509_F_X509_VERIFY_SM2,
+ X509err(X509_F_COMMON_VERIFY_SM2,
ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
goto err;
}
if (pkey == NULL) {
- X509err(X509_F_X509_VERIFY_SM2, ERR_R_PASSED_NULL_PARAMETER);
+ X509err(X509_F_COMMON_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);
+ if (req == 1) {
+ r = (X509_REQ *)data;
+ signature = r->signature;
+ sm2_id = r->sm2_id;
+ tbv = (ASN1_VALUE *)&r->req_info;
+ } else {
+ x = (X509 *)data;
+ signature = &x->signature;
+ sm2_id = x->sm2_id;
+ tbv = (ASN1_VALUE *)&x->cert_info;
+ }
+
+ if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) {
+ X509err(X509_F_COMMON_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);
+ X509err(X509_F_COMMON_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);
+ X509err(X509_F_COMMON_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);
+ X509err(X509_F_COMMON_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);
+ X509err(X509_F_COMMON_VERIFY_SM2, ERR_R_EVP_LIB);
ret = 0;
goto err;
}
/* NOTE: we tolerate no actual ID, to provide maximum flexibility */
- if (x->sm2_id != NULL
- && 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);
+ if (sm2_id != NULL
+ && EVP_PKEY_CTX_set1_id(pctx, sm2_id->data, sm2_id->length) != 1) {
+ X509err(X509_F_COMMON_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);
+ X509err(X509_F_COMMON_VERIFY_SM2, ERR_R_EVP_LIB);
ret = 0;
goto err;
}
- inl = ASN1_item_i2d((ASN1_VALUE *)&x->cert_info, &buf_in,
+ inl = ASN1_item_i2d(tbv, &buf_in,
+ req == 1 ?
+ ASN1_ITEM_rptr(X509_REQ_INFO) :
ASN1_ITEM_rptr(X509_CINF));
if (inl <= 0) {
- X509err(X509_F_X509_VERIFY_SM2, ERR_R_INTERNAL_ERROR);
+ X509err(X509_F_COMMON_VERIFY_SM2, ERR_R_INTERNAL_ERROR);
goto err;
}
if (buf_in == NULL) {
- X509err(X509_F_X509_VERIFY_SM2, ERR_R_MALLOC_FAILURE);
+ X509err(X509_F_COMMON_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);
+ ret = EVP_DigestVerify(ctx, signature->data,
+ (size_t)signature->length, buf_in, inl);
if (ret <= 0) {
- X509err(X509_F_X509_VERIFY_SM2, ERR_R_EVP_LIB);
+ X509err(X509_F_COMMON_VERIFY_SM2, ERR_R_EVP_LIB);
goto err;
}
ret = 1;
EVP_PKEY_CTX_free(pctx);
return ret;
}
+
+static int x509_verify_sm2(X509 *x, EVP_PKEY *pkey, int mdnid, int pknid)
+{
+ return common_verify_sm2(x, pkey, mdnid, pknid, 0);
+}
+
+static int x509_req_verify_sm2(X509_REQ *x, EVP_PKEY *pkey,
+ int mdnid, int pknid)
+{
+ return common_verify_sm2(x, pkey, mdnid, pknid, 1);
+}
+
#endif
int X509_verify(X509 *a, EVP_PKEY *r)
int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r)
{
+#ifndef OPENSSL_NO_SM2
+ int mdnid, pknid;
+
+ /* 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_REQ_VERIFY, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
+ return 0;
+ }
+
+ if (pknid == NID_sm2)
+ return x509_req_verify_sm2(a, r, mdnid, pknid);
+#endif
+
return (ASN1_item_verify(ASN1_ITEM_rptr(X509_REQ_INFO),
&a->sig_alg, a->signature, &a->req_info, r));
}
return 1;
}
+static int req_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg)
+{
+#ifndef OPENSSL_NO_SM2
+ X509_REQ *ret = (X509_REQ *)*pval;
+
+ switch (operation) {
+ case ASN1_OP_D2I_PRE:
+ ASN1_OCTET_STRING_free(ret->sm2_id);
+ /* fall thru */
+ case ASN1_OP_NEW_POST:
+ ret->sm2_id = NULL;
+ break;
+
+ case ASN1_OP_FREE_POST:
+ ASN1_OCTET_STRING_free(ret->sm2_id);
+ break;
+ }
+#endif
+
+ return 1;
+}
+
ASN1_SEQUENCE_enc(X509_REQ_INFO, enc, rinf_cb) = {
ASN1_SIMPLE(X509_REQ_INFO, version, ASN1_INTEGER),
ASN1_SIMPLE(X509_REQ_INFO, subject, X509_NAME),
IMPLEMENT_ASN1_FUNCTIONS(X509_REQ_INFO)
-ASN1_SEQUENCE_ref(X509_REQ, 0) = {
+ASN1_SEQUENCE_ref(X509_REQ, req_cb) = {
ASN1_EMBED(X509_REQ, req_info, X509_REQ_INFO),
ASN1_EMBED(X509_REQ, sig_alg, X509_ALGOR),
ASN1_SIMPLE(X509_REQ, signature, ASN1_BIT_STRING)
IMPLEMENT_ASN1_FUNCTIONS(X509_REQ)
IMPLEMENT_ASN1_DUP_FUNCTION(X509_REQ)
+
+#ifndef OPENSSL_NO_SM2
+void X509_REQ_set0_sm2_id(X509_REQ *x, ASN1_OCTET_STRING *sm2_id)
+{
+ ASN1_OCTET_STRING_free(x->sm2_id);
+ x->sm2_id = sm2_id;
+}
+
+ASN1_OCTET_STRING *X509_REQ_get0_sm2_id(X509_REQ *x)
+{
+ return x->sm2_id;
+}
+#endif
sk_IPAddressFamily_pop_free(ret->rfc3779_addr, IPAddressFamily_free);
ASIdentifiers_free(ret->rfc3779_asid);
#endif
+#ifndef OPENSSL_NO_SM2
+ ASN1_OCTET_STRING_free(ret->sm2_id);
+#endif
/* fall thru */
[B<-multivalue-rdn>]
[B<-rand file...>]
[B<-writerand file>]
+[B<-sm2-id string>]
+[B<-sm2-hex-id hex-string>]
=head1 DESCRIPTION
Writes random data to the specified I<file> upon exit.
This can be used with a subsequent B<-rand> flag.
+=item B<-sm2-id>
+
+Specify the ID string to use when verifying an SM2 certificate. The ID string is
+required by the SM2 signature algorithm for signing and verification.
+
+=item B<-sm2-hex-id>
+
+Specify a binary ID string to use when signing or verifying using an SM2
+certificate. The argument for this option is string of hexadecimal digits.
+
=back
=head1 CRL OPTIONS
openssl ca -in req.pem -out newcert.pem
+Sign an SM2 certificate request:
+
+ openssl ca -in sm2.csr -out sm2.crt -md sm3 -sigopt "sm2_id:1234567812345678" -sm2-id "1234567812345678"
+
Sign a certificate request, using CA extensions:
openssl ca -in req.pem -extensions v3_ca -out newcert.pem
[B<-batch>]
[B<-verbose>]
[B<-engine id>]
+[B<-sm2-id string>]
+[B<-sm2-hex-id hex-string>]
=head1 DESCRIPTION
Specifies an engine (by its unique B<id> string) which would be used
for key generation operations.
+=item B<-sm2-id>
+
+Specify the ID string to use when verifying an SM2 certificate. The ID string is
+required by the SM2 signature algorithm for signing and verification.
+
+=item B<-sm2-hex-id>
+
+Specify a binary ID string to use when signing or verifying using an SM2
+certificate. The argument for this option is string of hexadecimal digits.
+
=back
=head1 CONFIGURATION FILE FORMAT
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out req.pem
+Create an SM2 private key and then generate a certificate request from it:
+
+ openssl ecparam -genkey -name SM2 -out sm2.key
+ openssl req -new -key sm2.key -out sm2.csr -sm3 -sigopt "sm2_id:1234567812345678"
+
+Examine and verify an SM2 certificate request:
+
+ openssl req -verify -in sm2.csr -sm3 -sm2-id 1234567812345678
+
Example of a file pointed to by the B<oid_file> option:
1.2.3.4 shortName A longer Name
=head1 NAME
-X509_get0_sm2_id, X509_set0_sm2_id - get or set SM2 ID for certificate operations
+X509_get0_sm2_id, X509_set0_sm2_id,
+X509_REQ_get0_sm2_id, X509_REQ_set0_sm2_id
+- get or set SM2 ID for certificate operations
=head1 SYNOPSIS
ASN1_OCTET_STRING *X509_get0_sm2_id(X509 *x);
void X509_set0_sm2_id(X509 *x, ASN1_OCTET_STRING *sm2_id);
+ ASN1_OCTET_STRING *X509_REQ_get0_sm2_id(X509_REQ *x);
+ void X509_REQ_set0_sm2_id(X509_REQ *x, ASN1_OCTET_STRING *sm2_id);
=head1 DESCRIPTION
and therefore the value that has been passed in should not be freed by the
caller after this function has been called.
+X509_REQ_get0_sm2_id() and X509_REQ_set0_sm2_id() have the same functionality
+as X509_get0_sm2_id() and X509_set0_sm2_id() except that they deal with
+B<X509_REQ> objects instead of B<X509>.
+
=head1 NOTES
SM2 signature algorithm requires an ID value when generating and verifying a
=head1 RETURN VALUES
-X509_set0_sm2_id() does not return a value.
+X509_set0_sm2_id() and X509_REQ_set0_sm2_id() do not return a value.
=head1 SEE ALSO
# ifndef OPENSSL_NO_SM2
void X509_set0_sm2_id(X509 *x, ASN1_OCTET_STRING *sm2_id);
ASN1_OCTET_STRING *X509_get0_sm2_id(X509 *x);
+void X509_REQ_set0_sm2_id(X509_REQ *x, ASN1_OCTET_STRING *sm2_id);
+ASN1_OCTET_STRING *X509_REQ_get0_sm2_id(X509_REQ *x);
# endif
int X509_trusted(const X509 *x);
# define X509_F_BY_FILE_CTRL 101
# define X509_F_CHECK_NAME_CONSTRAINTS 149
# define X509_F_CHECK_POLICY 145
+# define X509_F_COMMON_VERIFY_SM2 165
# define X509_F_DANE_I2D 107
# define X509_F_DIR_CTRL 102
# define X509_F_GET_CERT_BY_SUBJECT 103
# define X509_F_X509_REQ_PRINT_EX 121
# define X509_F_X509_REQ_PRINT_FP 122
# define X509_F_X509_REQ_TO_X509 123
+# define X509_F_X509_REQ_VERIFY 163
+# define X509_F_X509_REQ_VERIFY_SM2 164
# define X509_F_X509_STORE_ADD_CERT 124
# define X509_F_X509_STORE_ADD_CRL 125
# define X509_F_X509_STORE_ADD_LOOKUP 157
--- /dev/null
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBMTCB1wIBADB1MQswCQYDVQQGEwJDTjERMA8GA1UECAwITGlhb25pbmcxETAP
+BgNVBAcMCFNoZW55YW5nMQwwCgYDVQQKDANUZXQxDDAKBgNVBAsMA1RldDELMAkG
+A1UEAwwCb28xFzAVBgkqhkiG9w0BCQEWCG9vQG9vLm9vMFkwEwYHKoZIzj0CAQYI
+KoEcz1UBgi0DQgAE1NjdOpldcjTkuZpdGDNyHAnhK9cB2RZ7jAmFzt7jgEs9OHSg
+rb3crjz+qGZfqyJ5AyZulQ7gdARzb1H55jvw5qAAMAoGCCqBHM9VAYN1A0kAMEYC
+IQCacUXA8kyTTDwEm89Yz9qjsbfd8/N32lnzKxuKCcXJwQIhAIpugCbfeWuPxUQO
+7AvQS3yxBp1yn0FbTT2XVSyYy6To
+-----END CERTIFICATE REQUEST-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICJDCCAcqgAwIBAgIJAOlkpDpSrmVbMAoGCCqBHM9VAYN1MGgxCzAJBgNVBAYT
+AkNOMQswCQYDVQQIDAJMTjERMA8GA1UEBwwIU2hlbnlhbmcxETAPBgNVBAoMCFRl
+c3QgT3JnMRAwDgYDVQQLDAdUZXN0IE9VMRQwEgYDVQQDDAtUZXN0IFNNMiBDQTAe
+Fw0xOTAyMTkwNzA1NDhaFw0yMzAzMzAwNzA1NDhaMGgxCzAJBgNVBAYTAkNOMQsw
+CQYDVQQIDAJMTjERMA8GA1UEBwwIU2hlbnlhbmcxETAPBgNVBAoMCFRlc3QgT3Jn
+MRAwDgYDVQQLDAdUZXN0IE9VMRQwEgYDVQQDDAtUZXN0IFNNMiBDQTBZMBMGByqG
+SM49AgEGCCqBHM9VAYItA0IABHRYnqErofBdXPptvvO7+BSVJxcpHuTGnZ+UPrbU
+5kVEUMaUnNOeMJZl/vRGimZCm/AkReJmRfnb15ESHR+ssp6jXTBbMB0GA1UdDgQW
+BBTFjcWu/zJgSZ5SKUlU5Vx4/0W5dDAfBgNVHSMEGDAWgBTFjcWu/zJgSZ5SKUlU
+5Vx4/0W5dDAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjAKBggqgRzPVQGDdQNI
+ADBFAiEAs6byi1nSQtFELOw/2tQIv5AEsZFR5MJ/oB2ztXzs2LYCIEfIw4xlUH6X
+YFhs4RnIa0K9Ng1ebsGPrifYkudwBIk3
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQglktdVbLA5tyXMc+9
+KV4ikyDaFZNnXqfNAzUVqTlqn8GhRANCAAR0WJ6hK6HwXVz6bb7zu/gUlScXKR7k
+xp2flD621OZFRFDGlJzTnjCWZf70RopmQpvwJEXiZkX529eREh0frLKe
+-----END PRIVATE KEY-----
setup("test_req");
-plan tests => 9;
+plan tests => 10;
require_ok(srctop_file('test','recipes','tconversion.pl'));
"Verifying signature on request");
};
+subtest "generating SM2 certificate requests" => sub {
+ plan tests => 2;
+
+ SKIP: {
+ skip "SM2 is not supported by this OpenSSL build", 2
+ if disabled("sm2");
+ ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"),
+ "-new", "-key", srctop_file("test", "certs", "sm2.key"),
+ "-sigopt", "sm2_id:1234567812345678",
+ "-out", "testreq.pem", "-sm3"])),
+ "Generating SM2 certificate request");
+
+ ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"),
+ "-verify", "-in", "testreq.pem", "-noout",
+ "-sm2-id", "1234567812345678", "-sm3"])),
+ "Verifying signature on SM2 certificate request");
+ }
+};
+
my @openssl_args = ("req", "-config", srctop_file("apps", "openssl.cnf"));
run_conversion('req conversions',
ok(run(test(["verify_extra_test",
srctop_file("test", "certs", "roots.pem"),
srctop_file("test", "certs", "untrusted.pem"),
- srctop_file("test", "certs", "bad.pem")])));
+ srctop_file("test", "certs", "bad.pem"),
+ srctop_file("test", "certs", "sm2-csr.pem")])));
rmtree("demoCA", { safe => 0 });
-plan tests => 5;
+plan tests => 6;
SKIP: {
$ENV{OPENSSL_CONFIG} = '-config "'.srctop_file("test", "CAss.cnf").'"';
skip "failed creating CA structure", 4
'creating new pre-certificate');
}
+SKIP: {
+ skip "SM2 is not supported by this OpenSSL build", 1
+ if disabled("sm2");
+
+ is(yes(cmdstr(app(["openssl", "ca", "-config",
+ srctop_file("test", "CAss.cnf"),
+ "-in", srctop_file("test", "certs", "sm2-csr.pem"),
+ "-out", "sm2-test.crt",
+ "-sigopt", "sm2_id:1234567812345678",
+ "-sm2-id", "1234567812345678",
+ "-md", "sm3",
+ "-cert", srctop_file("test", "certs", "sm2-root.crt"),
+ "-keyfile", srctop_file("test", "certs", "sm2-root.key")]))),
+ 0,
+ "Signing SM2 certificate request");
+}
rmtree("demoCA", { safe => 0 });
-unlink "newcert.pem", "newreq.pem", "newkey.pem";
+unlink "newcert.pem", "newreq.pem", "newkey.pem", "sm2-test.crt";
sub yes {
static const char *roots_f;
static const char *untrusted_f;
static const char *bad_f;
+static const char *req_f;
static STACK_OF(X509) *load_certs_from_file(const char *filename)
{
BIO_free(bio);
return ret;
}
+
+static int test_req_sm2_id(void)
+{
+ /* we only need an X509_REQ structure, no matter if it's a real SM2 cert */
+ X509_REQ *x = NULL;
+ BIO *bio = NULL;
+ int ret = 0;
+ ASN1_OCTET_STRING *v = NULL, *v2 = NULL;
+ char *sm2id = "this is an ID";
+
+ bio = BIO_new_file(req_f, "r");
+ if (bio == NULL)
+ goto err;
+
+ x = PEM_read_bio_X509_REQ(bio, NULL, 0, NULL);
+ if (x == NULL)
+ goto err;
+
+ v = ASN1_OCTET_STRING_new();
+ if (v == NULL)
+ goto err;
+
+ if (!ASN1_OCTET_STRING_set(v, (unsigned char *)sm2id, (int)strlen(sm2id))) {
+ ASN1_OCTET_STRING_free(v);
+ goto err;
+ }
+
+ X509_REQ_set0_sm2_id(x, v);
+
+ v2 = X509_REQ_get0_sm2_id(x);
+ if (!TEST_ptr(v2)
+ || !TEST_int_eq(ASN1_OCTET_STRING_cmp(v, v2), 0))
+ goto err;
+
+ ret = 1;
+ err:
+ X509_REQ_free(x);
+ BIO_free(bio);
+ return ret;
+}
#endif
int setup_tests(void)
{
if (!TEST_ptr(roots_f = test_get_argument(0))
|| !TEST_ptr(untrusted_f = test_get_argument(1))
- || !TEST_ptr(bad_f = test_get_argument(2)))
+ || !TEST_ptr(bad_f = test_get_argument(2))
+ || !TEST_ptr(req_f = test_get_argument(3)))
return 0;
ADD_TEST(test_alt_chains_cert_forgery);
ADD_TEST(test_store_ctx);
#ifndef OPENSSL_NO_SM2
ADD_TEST(test_sm2_id);
+ ADD_TEST(test_req_sm2_id);
#endif
return 1;
}
BN_CTX_secure_new_ex 4778 3_0_0 EXIST::FUNCTION:
OPENSSL_thread_stop_ex 4779 3_0_0 EXIST::FUNCTION:
OSSL_PARAM_locate_const 4780 3_0_0 EXIST::FUNCTION:
+X509_REQ_set0_sm2_id 4781 3_0_0 EXIST::FUNCTION:SM2
+X509_REQ_get0_sm2_id 4782 3_0_0 EXIST::FUNCTION:SM2