From cdc0126ea3473c963027457b742d219faf464124 Mon Sep 17 00:00:00 2001 From: Huiyue Xu Date: Mon, 18 Sep 2023 15:19:55 +0800 Subject: [PATCH] Support SM2 cert and TLCP Signed-off-by: Huiyue Xu --- CHANGES | 3 + Configure | 7 +- apps/ca.c | 68 +- apps/pkeyutl.c | 171 +++- apps/req.c | 167 +++- apps/s_client.c | 60 +- apps/verify.c | 81 +- apps/x509.c | 4 + crypto/asn1/a_sign.c | 13 +- crypto/ec/ec_pmeth.c | 3 +- crypto/err/openssl.txt | 35 +- crypto/evp/p_lib.c | 18 + crypto/objects/obj_dat.h | 18 +- crypto/objects/obj_mac.num | 1 + crypto/objects/obj_xref.h | 2 + crypto/objects/obj_xref.txt | 2 + crypto/objects/objects.txt | 2 + crypto/pkcs7/pk7_doit.c | 23 +- crypto/sm2/build.info | 2 +- crypto/sm2/sm2_err.c | 4 +- crypto/sm2/sm2_kep.c | 254 ++++++ crypto/sm2/sm2_pmeth.c | 27 + crypto/x509/x509_err.c | 6 + crypto/x509/x_all.c | 158 ++++ crypto/x509/x_req.c | 38 +- crypto/x509/x_x509.c | 22 + doc/man1/ca.pod | 16 + doc/man1/pkeyutl.pod | 52 ++ doc/man1/req.pod | 21 + doc/man1/s_client.pod | 9 + doc/man1/verify.pod | 14 + doc/man3/EVP_PKEY_set1_RSA.pod | 9 +- doc/man3/SSL_CTX_new.pod | 19 +- doc/man3/SSL_CTX_set_options.pod | 4 +- doc/man3/SSL_CTX_use_certificate.pod | 56 +- doc/man3/X509_get0_sm2_id.pod | 55 ++ doc/man7/ssl.pod | 40 + fuzz/oids.txt | 1 + include/crypto/sm2.h | 2 + include/crypto/sm2err.h | 12 +- include/crypto/x509.h | 8 +- include/openssl/evp.h | 4 + include/openssl/obj_mac.h | 5 + include/openssl/sm2.h | 31 + include/openssl/ssl.h | 71 ++ include/openssl/sslerr.h | 33 +- include/openssl/tls1.h | 20 + include/openssl/x509.h | 11 + include/openssl/x509err.h | 7 +- ssl/methods.c | 36 + ssl/record/ssl3_record.c | 4 + ssl/s3_lib.c | 126 +++ ssl/ssl_asn1.c | 3 +- ssl/ssl_cert.c | 20 +- ssl/ssl_cert_table.h | 6 +- ssl/ssl_ciph.c | 46 +- ssl/ssl_err.c | 54 +- ssl/ssl_lib.c | 81 +- ssl/ssl_local.h | 69 +- ssl/ssl_rsa.c | 542 +++++++++++++ ssl/ssl_sess.c | 3 + ssl/ssl_stat.c | 28 + ssl/statem/extensions.c | 6 +- ssl/statem/extensions_clnt.c | 3 + ssl/statem/extensions_srvr.c | 6 +- ssl/statem/statem.c | 4 + ssl/statem/statem_clnt.c | 434 ++++++++++ ssl/statem/statem_lib.c | 182 ++++- ssl/statem/statem_srvr.c | 445 ++++++++++- ssl/t1_enc.c | 84 ++ ssl/t1_lib.c | 132 +++- test/build.info | 6 +- test/certs/sm2-ca-cert.pem | 14 + test/certs/sm2-csr.pem | 9 + test/certs/sm2-root.crt | 14 + test/certs/sm2-root.key | 5 + test/certs/sm2.key | 5 + test/certs/sm2.pem | 14 + test/ciphername_test.c | 3 + test/recipes/20-test_pkeyutl.t | 41 + test/recipes/25-test_req.t | 41 +- test/recipes/25-test_verify.t | 14 +- test/recipes/80-test_ca.t | 20 +- test/recipes/85-test_tlcp.t | 34 + .../85-test_tlcp_data/ecdsa-client-cert.pem | 12 + .../85-test_tlcp_data/ecdsa-client-key.pem | 5 + .../85-test_tlcp_data/ecdsa-root-cert.pem | 14 + .../85-test_tlcp_data/ecdsa-server-cert.pem | 12 + .../85-test_tlcp_data/ecdsa-server-key.pem | 5 + .../85-test_tlcp_data/sm2-client-enc-cert.pem | 12 + .../85-test_tlcp_data/sm2-client-enc-key.pem | 5 + .../85-test_tlcp_data/sm2-client-sig-cert.pem | 12 + .../85-test_tlcp_data/sm2-client-sig-key.pem | 5 + .../85-test_tlcp_data/sm2-root-cert.pem | 14 + .../85-test_tlcp_data/sm2-server-enc-cert.pem | 12 + .../85-test_tlcp_data/sm2-server-enc-key.pem | 5 + .../85-test_tlcp_data/sm2-server-sig-cert.pem | 12 + .../85-test_tlcp_data/sm2-server-sig-key.pem | 5 + test/sm2_internal_test.c | 111 +++ test/tlcptest.c | 746 ++++++++++++++++++ test/verify_extra_test.c | 90 +++ util/libcrypto.num | 6 + util/libssl.num | 17 + 103 files changed, 5214 insertions(+), 109 deletions(-) create mode 100644 crypto/sm2/sm2_kep.c create mode 100644 doc/man3/X509_get0_sm2_id.pod create mode 100644 include/openssl/sm2.h create mode 100644 test/certs/sm2-ca-cert.pem create mode 100644 test/certs/sm2-csr.pem create mode 100644 test/certs/sm2-root.crt create mode 100644 test/certs/sm2-root.key create mode 100644 test/certs/sm2.key create mode 100644 test/certs/sm2.pem create mode 100644 test/recipes/20-test_pkeyutl.t create mode 100644 test/recipes/85-test_tlcp.t create mode 100644 test/recipes/85-test_tlcp_data/ecdsa-client-cert.pem create mode 100644 test/recipes/85-test_tlcp_data/ecdsa-client-key.pem create mode 100644 test/recipes/85-test_tlcp_data/ecdsa-root-cert.pem create mode 100644 test/recipes/85-test_tlcp_data/ecdsa-server-cert.pem create mode 100644 test/recipes/85-test_tlcp_data/ecdsa-server-key.pem create mode 100644 test/recipes/85-test_tlcp_data/sm2-client-enc-cert.pem create mode 100644 test/recipes/85-test_tlcp_data/sm2-client-enc-key.pem create mode 100644 test/recipes/85-test_tlcp_data/sm2-client-sig-cert.pem create mode 100644 test/recipes/85-test_tlcp_data/sm2-client-sig-key.pem create mode 100644 test/recipes/85-test_tlcp_data/sm2-root-cert.pem create mode 100644 test/recipes/85-test_tlcp_data/sm2-server-enc-cert.pem create mode 100644 test/recipes/85-test_tlcp_data/sm2-server-enc-key.pem create mode 100644 test/recipes/85-test_tlcp_data/sm2-server-sig-cert.pem create mode 100644 test/recipes/85-test_tlcp_data/sm2-server-sig-key.pem create mode 100644 test/tlcptest.c diff --git a/CHANGES b/CHANGES index ce9046f8f2..08e97ba61a 100644 --- a/CHANGES +++ b/CHANGES @@ -339,6 +339,9 @@ Changes between 1.1.1l and 1.1.1m [14 Dec 2021] + *) Support SM2 signing and verification schemes with X509 certificate. + [Paul Yang] + *) Avoid loading of a dynamic engine twice. [Bernd Edlinger] diff --git a/Configure b/Configure index f7f1919b22..972cca7993 100755 --- a/Configure +++ b/Configure @@ -425,6 +425,7 @@ my @disablables = ( "stdio", "tests", "threads", + "tlcp", "tls", "ts", "ubsan", @@ -469,6 +470,7 @@ our %disabled = ( # "what" => "comment" "ssl-trace" => "default", "ssl3" => "default", "ssl3-method" => "default", + "tlcp" => "default", "ubsan" => "default", "unit-test" => "default", "weak-ssl-ciphers" => "default", @@ -512,8 +514,9 @@ my @disable_cascades = ( "apps" => [ "tests" ], "tests" => [ "external-tests" ], "comp" => [ "zlib" ], - "ec" => [ "tls1_3", "sm2" ], - "sm3" => [ "sm2" ], + "ec" => [ "tls1_3", "sm2", "tlcp" ], + "sm3" => [ "sm2", "tlcp" ], + "sm2" => [ "tlcp" ], sub { !$disabled{"unit-test"} } => [ "heartbeats" ], sub { !$disabled{"msan"} } => [ "asm" ], diff --git a/apps/ca.c b/apps/ca.c index ea375ca0b1..901c17bb88 100755 --- a/apps/ca.c +++ b/apps/ca.c @@ -96,7 +96,8 @@ static int certify(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, 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, @@ -147,7 +148,7 @@ typedef enum OPTION_choice { 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; @@ -217,6 +218,12 @@ const OPTIONS ca_options[] = { 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} }; @@ -262,6 +269,9 @@ int ca_main(int argc, char **argv) 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) { @@ -425,6 +435,30 @@ opthelp: 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: @@ -914,7 +948,8 @@ 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) { @@ -933,7 +968,8 @@ end_of_options: 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) { @@ -1232,6 +1268,8 @@ end_of_options: ret = 0; end: + if (sm2_free) + OPENSSL_free(sm2_id); if (ret) ERR_print_errors(bio_err); BIO_free_all(Sout); @@ -1270,7 +1308,8 @@ static int certify(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, 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; @@ -1302,6 +1341,25 @@ static int certify(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, 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) { diff --git a/apps/pkeyutl.c b/apps/pkeyutl.c index 831e14dab4..1d3d57be69 100644 --- a/apps/pkeyutl.c +++ b/apps/pkeyutl.c @@ -22,7 +22,7 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, const char *keyfile, int keyform, int key_type, char *passinarg, int pkey_op, ENGINE *e, - const int impl); + const int impl, EVP_PKEY **ppkey); static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file, ENGINE *e); @@ -31,6 +31,11 @@ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op, unsigned char *out, size_t *poutlen, const unsigned char *in, size_t inlen); +static int do_raw_keyop(int pkey_op, EVP_PKEY_CTX *ctx, + const EVP_MD *md, EVP_PKEY *pkey, BIO *in, + unsigned char *sig, int siglen, + unsigned char **out, size_t *poutlen); + typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ENGINE, OPT_ENGINE_IMPL, OPT_IN, OPT_OUT, @@ -38,12 +43,15 @@ typedef enum OPTION_choice { OPT_VERIFY, OPT_VERIFYRECOVER, OPT_REV, OPT_ENCRYPT, OPT_DECRYPT, OPT_DERIVE, OPT_SIGFILE, OPT_INKEY, OPT_PEERKEY, OPT_PASSIN, OPT_PEERFORM, OPT_KEYFORM, OPT_PKEYOPT, OPT_KDF, OPT_KDFLEN, - OPT_R_ENUM + OPT_R_ENUM, OPT_RAWIN, OPT_DIGEST } OPTION_CHOICE; const OPTIONS pkeyutl_options[] = { {"help", OPT_HELP, '-', "Display this summary"}, {"in", OPT_IN, '<', "Input file - default stdin"}, + {"rawin", OPT_RAWIN, '-', "Indicate the input data is in raw form"}, + {"digest", OPT_DIGEST, 's', + "Specify the digest algorithm when signing the raw input data"}, {"out", OPT_OUT, '>', "Output file - default stdout"}, {"pubin", OPT_PUBIN, '-', "Input is a public key"}, {"certin", OPT_CERTIN, '-', "Input is a cert with a public key"}, @@ -80,6 +88,7 @@ int pkeyutl_main(int argc, char **argv) BIO *in = NULL, *out = NULL; ENGINE *e = NULL; EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; char *infile = NULL, *outfile = NULL, *sigfile = NULL, *passinarg = NULL; char hexdump = 0, asn1parse = 0, rev = 0, *prog; unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL; @@ -94,6 +103,8 @@ int pkeyutl_main(int argc, char **argv) const char *kdfalg = NULL; int kdflen = 0; STACK_OF(OPENSSL_STRING) *pkeyopts = NULL; + int rawin = 0; + const EVP_MD *md = NULL; prog = opt_init(argc, argv, pkeyutl_options); while ((o = opt_next()) != OPT_EOF) { @@ -192,12 +203,39 @@ int pkeyutl_main(int argc, char **argv) goto end; } break; + case OPT_RAWIN: + rawin = 1; + break; + case OPT_DIGEST: + if (!opt_md(opt_arg(), &md)) + goto end; + break; } } argc = opt_num_rest(); if (argc != 0) goto opthelp; + if (rawin && pkey_op != EVP_PKEY_OP_SIGN && pkey_op != EVP_PKEY_OP_VERIFY) { + BIO_printf(bio_err, + "%s: -rawin can only be used with -sign or -verify\n", + prog); + goto opthelp; + } + + if (md != NULL && !rawin) { + BIO_printf(bio_err, + "%s: -digest can only be used with -rawin\n", + prog); + goto opthelp; + } + + if (rawin && rev) { + BIO_printf(bio_err, "%s: -rev cannot be used with raw input\n", + prog); + goto opthelp; + } + if (kdfalg != NULL) { if (kdflen == 0) { BIO_printf(bio_err, @@ -214,7 +252,7 @@ int pkeyutl_main(int argc, char **argv) goto opthelp; } ctx = init_ctx(kdfalg, &keysize, inkey, keyform, key_type, - passinarg, pkey_op, e, engine_impl); + passinarg, pkey_op, e, engine_impl, &pkey); if (ctx == NULL) { BIO_printf(bio_err, "%s: Error initializing context\n", prog); ERR_print_errors(bio_err); @@ -277,7 +315,8 @@ int pkeyutl_main(int argc, char **argv) } } - if (in != NULL) { + /* Raw input data is handled elsewhere */ + if (in != NULL && !rawin) { /* Read the input data */ buf_inlen = bio_to_mem(&buf_in, keysize * 10, in); if (buf_inlen < 0) { @@ -296,8 +335,9 @@ int pkeyutl_main(int argc, char **argv) } } - /* Sanity check the input */ - if (buf_inlen > EVP_MAX_MD_SIZE + /* Sanity check the input if the input is not raw */ + if (!rawin + && buf_inlen > EVP_MAX_MD_SIZE && (pkey_op == EVP_PKEY_OP_SIGN || pkey_op == EVP_PKEY_OP_VERIFY)) { BIO_printf(bio_err, @@ -306,8 +346,13 @@ int pkeyutl_main(int argc, char **argv) } if (pkey_op == EVP_PKEY_OP_VERIFY) { - rv = EVP_PKEY_verify(ctx, sig, (size_t)siglen, - buf_in, (size_t)buf_inlen); + if (rawin) { + rv = do_raw_keyop(pkey_op, ctx, md, pkey, in, sig, siglen, + NULL, 0); + } else { + rv = EVP_PKEY_verify(ctx, sig, (size_t)siglen, + buf_in, (size_t)buf_inlen); + } if (rv == 1) { BIO_puts(out, "Signature Verified Successfully\n"); ret = 0; @@ -320,14 +365,20 @@ int pkeyutl_main(int argc, char **argv) buf_outlen = kdflen; rv = 1; } else { - rv = do_keyop(ctx, pkey_op, NULL, (size_t *)&buf_outlen, - buf_in, (size_t)buf_inlen); - } - if (rv > 0 && buf_outlen != 0) { - buf_out = app_malloc(buf_outlen, "buffer output"); - rv = do_keyop(ctx, pkey_op, - buf_out, (size_t *)&buf_outlen, - buf_in, (size_t)buf_inlen); + if (rawin) { + /* rawin allocates the buffer in do_raw_keyop() */ + rv = do_raw_keyop(pkey_op, ctx, md, pkey, in, NULL, 0, + &buf_out, (size_t *)&buf_outlen); + } else { + rv = do_keyop(ctx, pkey_op, NULL, (size_t *)&buf_outlen, + buf_in, (size_t)buf_inlen); + if (rv > 0 && buf_outlen != 0) { + buf_out = app_malloc(buf_outlen, "buffer output"); + rv = do_keyop(ctx, pkey_op, + buf_out, (size_t *)&buf_outlen, + buf_in, (size_t)buf_inlen); + } + } } if (rv <= 0) { if (pkey_op != EVP_PKEY_OP_DERIVE) { @@ -364,7 +415,7 @@ int pkeyutl_main(int argc, char **argv) static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, const char *keyfile, int keyform, int key_type, char *passinarg, int pkey_op, ENGINE *e, - const int engine_impl) + const int engine_impl, EVP_PKEY **ppkey) { EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; @@ -424,8 +475,26 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, } else { if (pkey == NULL) goto end; + +#ifndef OPENSSL_NO_EC + /* SM2 needs a special treatment */ + if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) { + EC_KEY *eckey = NULL; + const EC_GROUP *group = NULL; + int nid; + + if ((eckey = EVP_PKEY_get0_EC_KEY(pkey)) == NULL + || (group = EC_KEY_get0_group(eckey)) == NULL + || (nid = EC_GROUP_get_curve_name(group)) == 0) + goto end; + if (nid == NID_sm2) + EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2); + } +#endif *pkeysize = EVP_PKEY_size(pkey); ctx = EVP_PKEY_CTX_new(pkey, impl); + if (ppkey != NULL) + *ppkey = pkey; EVP_PKEY_free(pkey); } @@ -522,3 +591,71 @@ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op, } return rv; } + +#define TBUF_MAXSIZE 2048 + +static int do_raw_keyop(int pkey_op, EVP_PKEY_CTX *ctx, + const EVP_MD *md, EVP_PKEY *pkey, BIO *in, + unsigned char *sig, int siglen, + unsigned char **out, size_t *poutlen) +{ + int rv = 0; + EVP_MD_CTX *mctx = NULL; + unsigned char tbuf[TBUF_MAXSIZE]; + int tbuf_len = 0; + + if ((mctx = EVP_MD_CTX_new()) == NULL) { + BIO_printf(bio_err, "Error: out of memory\n"); + return rv; + } + EVP_MD_CTX_set_pkey_ctx(mctx, ctx); + + switch(pkey_op) { + case EVP_PKEY_OP_VERIFY: + if (EVP_DigestVerifyInit(mctx, NULL, md, NULL, pkey) != 1) + goto end; + for (;;) { + tbuf_len = BIO_read(in, tbuf, TBUF_MAXSIZE); + if (tbuf_len == 0) + break; + if (tbuf_len < 0) { + BIO_printf(bio_err, "Error reading raw input data\n"); + goto end; + } + rv = EVP_DigestVerifyUpdate(mctx, tbuf, (size_t)tbuf_len); + if (rv != 1) { + BIO_printf(bio_err, "Error verifying raw input data\n"); + goto end; + } + } + rv = EVP_DigestVerifyFinal(mctx, sig, (size_t)siglen); + break; + case EVP_PKEY_OP_SIGN: + if (EVP_DigestSignInit(mctx, NULL, md, NULL, pkey) != 1) + goto end; + for (;;) { + tbuf_len = BIO_read(in, tbuf, TBUF_MAXSIZE); + if (tbuf_len == 0) + break; + if (tbuf_len < 0) { + BIO_printf(bio_err, "Error reading raw input data\n"); + goto end; + } + rv = EVP_DigestSignUpdate(mctx, tbuf, (size_t)tbuf_len); + if (rv != 1) { + BIO_printf(bio_err, "Error signing raw input data\n"); + goto end; + } + } + rv = EVP_DigestSignFinal(mctx, NULL, poutlen); + if (rv == 1 && out != NULL) { + *out = app_malloc(*poutlen, "buffer output"); + rv = EVP_DigestSignFinal(mctx, *out, poutlen); + } + break; + } + + end: + EVP_MD_CTX_free(mctx); + return rv; +} diff --git a/apps/req.c b/apps/req.c index a603907cd5..95dd0e4ec0 100644 --- a/apps/req.c +++ b/apps/req.c @@ -90,7 +90,7 @@ typedef enum OPTION_choice { 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; @@ -145,6 +145,12 @@ const OPTIONS req_options[] = { {"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} }; @@ -242,6 +248,9 @@ int req_main(int argc, char **argv) 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(); @@ -417,6 +426,29 @@ int req_main(int argc, char **argv) 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(); @@ -849,6 +881,26 @@ int req_main(int argc, char **argv) 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) { @@ -957,6 +1009,8 @@ int req_main(int argc, char **argv) } ret = 0; end: + if (sm2_free) + OPENSSL_free(sm2_id); if (ret) { ERR_print_errors(bio_err); } @@ -1611,14 +1665,58 @@ static int genpkey_cb(EVP_PKEY_CTX *ctx) 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. @@ -1629,16 +1727,23 @@ static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey, 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, @@ -1646,10 +1751,24 @@ 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) + 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 do_sign_init() fails, pctx is already freed in it + */ + 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; } @@ -1659,9 +1778,24 @@ int do_X509_REQ_sign(X509_REQ *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) + 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 do_sign_init() fails, pctx is already freed in it + */ + 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; } @@ -1671,9 +1805,24 @@ int do_X509_CRL_sign(X509_CRL *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) + 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 do_sign_init() fails, no need to double free pctx + */ + 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; } diff --git a/apps/s_client.c b/apps/s_client.c index 00effc8037..22859d0181 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -578,6 +578,7 @@ typedef enum OPTION_choice { OPT_SRPUSER, OPT_SRPPASS, OPT_SRP_STRENGTH, OPT_SRP_LATEUSER, OPT_SRP_MOREGROUPS, #endif + OPT_TLCP, OPT_DCERT, OPT_DKEY, OPT_DPASS, OPT_SSL3, OPT_SSL_CONFIG, OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1, OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_KEYFORM, OPT_PASS, @@ -738,6 +739,12 @@ const OPTIONS s_client_options[] = { #ifndef OPENSSL_NO_TLS1_3 {"tls1_3", OPT_TLS1_3, '-', "Just use TLSv1.3"}, #endif +#ifndef OPENSSL_NO_TCLP + {"tlcp", OPT_TLCP, '-', "Just use TLCP"}, + {"dcert", OPT_DCERT, '<', "Encryption certificate file to use (usually for TLCP)"}, + {"dkey", OPT_DKEY, '<', "Encryption private key file to use (usually for TLCP)"}, + {"dpass", OPT_DPASS, 's', "Encryption private key file pass phrase source"}, +#endif #ifndef OPENSSL_NO_DTLS {"dtls", OPT_DTLS, '-', "Use any version of DTLS"}, {"timeout", OPT_TIMEOUT, '-', @@ -836,7 +843,7 @@ static const OPT_PAIR services[] = { #define IS_PROT_FLAG(o) \ (o == OPT_SSL3 || o == OPT_TLS1 || o == OPT_TLS1_1 || o == OPT_TLS1_2 \ - || o == OPT_TLS1_3 || o == OPT_DTLS || o == OPT_DTLS1 || o == OPT_DTLS1_2) + || o == OPT_TLS1_3 || o == OPT_DTLS || o == OPT_DTLS1 || o == OPT_DTLS1_2 || o == OPT_TLCP) /* Free |*dest| and optionally set it to a copy of |source|. */ static void freeandcopy(char **dest, const char *source) @@ -983,6 +990,10 @@ int s_client_main(int argc, char **argv) #ifndef OPENSSL_NO_SCTP int sctp_label_bug = 0; #endif + char *s_dcert_file = NULL, *s_dkey_file = NULL; + char *dpassarg = NULL, *dpass = NULL; + X509 *s_dcert = NULL; + EVP_PKEY *s_dkey = NULL; FD_ZERO(&readfds); FD_ZERO(&writefds); @@ -1319,6 +1330,14 @@ int s_client_main(int argc, char **argv) socket_type = SOCK_STREAM; #ifndef OPENSSL_NO_DTLS isdtls = 0; +#endif + break; + case OPT_TLCP: + min_version = TLCP_VERSION; + max_version = TLCP_VERSION; + socket_type = SOCK_STREAM; +#ifndef OPENSSL_NO_DTLS + isdtls = 0; #endif break; case OPT_DTLS: @@ -1382,6 +1401,15 @@ int s_client_main(int argc, char **argv) case OPT_KEY: key_file = opt_arg(); break; + case OPT_DCERT: + s_dcert_file = opt_arg(); + break; + case OPT_DPASS: + dpassarg = opt_arg(); + break; + case OPT_DKEY: + s_dkey_file = opt_arg(); + break; case OPT_RECONNECT: reconnect = 5; break; @@ -1660,7 +1688,7 @@ int s_client_main(int argc, char **argv) next_proto.data = NULL; #endif - if (!app_passwd(passarg, NULL, &pass, NULL)) { + if (!app_passwd(passarg, dpassarg, &pass, &dpass)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } @@ -1691,6 +1719,26 @@ int s_client_main(int argc, char **argv) goto end; } + if (s_dcert_file != NULL) { + if (s_dkey_file == NULL) + s_dkey_file = s_dcert_file; + + s_dkey = load_key(s_dkey_file, key_format, 0, dpass, e, + "Encrypt certificate private key file"); + if (s_dkey == NULL) { + ERR_print_errors(bio_err); + goto end; + } + + s_dcert = load_cert(s_dcert_file, key_format, + "Encrypt server certificate file"); + + if (s_dcert == NULL) { + ERR_print_errors(bio_err); + goto end; + } + } + if (crl_file != NULL) { X509_CRL *crl; crl = load_crl(crl_file, crl_format); @@ -1942,6 +1990,11 @@ int s_client_main(int argc, char **argv) if (!set_cert_key_stuff(ctx, cert, key, chain, build_chain)) goto end; + + if (s_dcert != NULL) { + if (!set_cert_key_stuff(ctx, s_dcert, s_dkey, chain, build_chain)) + goto end; + } if (!noservername) { tlsextcbp.biodebug = bio_err; @@ -3156,6 +3209,9 @@ int s_client_main(int argc, char **argv) EVP_PKEY_free(key); sk_X509_pop_free(chain, X509_free); OPENSSL_free(pass); + X509_free(s_dcert); + EVP_PKEY_free(s_dkey); + OPENSSL_free(dpass); #ifndef OPENSSL_NO_SRP OPENSSL_free(srp_arg.srppassin); #endif diff --git a/apps/verify.c b/apps/verify.c index 1f93856060..900056731c 100644 --- a/apps/verify.c +++ b/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,9 @@ 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; + int sm2_free = 0; if ((vpm = X509_VERIFY_PARAM_new()) == NULL) goto end; @@ -158,6 +168,20 @@ 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_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(); @@ -183,16 +207,19 @@ 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; } end: + if (sm2_free) + OPENSSL_free(sm2_id); X509_VERIFY_PARAM_free(vpm); X509_STORE_free(store); sk_X509_pop_free(untrusted, X509_free); @@ -204,7 +231,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,18 +244,39 @@ 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 = 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_set0_sm2_id(x, v); +#endif + } + csc = X509_STORE_CTX_new(); if (csc == NULL) { - printf("error %s: X.509 store context allocation failed\n", - (file == NULL) ? "stdin" : file); + BIO_printf(bio_err, "error %s: X.509 store context allocation failed\n", + (file == NULL) ? "stdin" : file); goto end; } X509_STORE_set_flags(ctx, vflags); if (!X509_STORE_CTX_init(csc, ctx, x, uchain)) { X509_STORE_CTX_free(csc); - printf("error %s: X.509 store context initialization failed\n", - (file == NULL) ? "stdin" : file); + BIO_printf(bio_err, + "error %s: X.509 store context initialization failed\n", + (file == NULL) ? "stdin" : file); goto end; } if (tchain != NULL) @@ -236,28 +285,30 @@ static int check(X509_STORE *ctx, const char *file, X509_STORE_CTX_set0_crls(csc, crls); i = X509_verify_cert(csc); if (i > 0 && X509_STORE_CTX_get_error(csc) == X509_V_OK) { - printf("%s: OK\n", (file == NULL) ? "stdin" : file); + BIO_printf(bio_out, "%s: OK\n", (file == NULL) ? "stdin" : file); ret = 1; if (show_chain) { int j; chain = X509_STORE_CTX_get1_chain(csc); num_untrusted = X509_STORE_CTX_get_num_untrusted(csc); - printf("Chain:\n"); + BIO_printf(bio_out, "Chain:\n"); for (j = 0; j < sk_X509_num(chain); j++) { X509 *cert = sk_X509_value(chain, j); - printf("depth=%d: ", j); + BIO_printf(bio_out, "depth=%d: ", j); X509_NAME_print_ex_fp(stdout, X509_get_subject_name(cert), 0, get_nameopt()); if (j < num_untrusted) - printf(" (untrusted)"); - printf("\n"); + BIO_printf(bio_out, " (untrusted)"); + BIO_printf(bio_out, "\n"); } sk_X509_pop_free(chain, X509_free); } } else { - printf("error %s: verification failed\n", (file == NULL) ? "stdin" : file); + BIO_printf(bio_err, + "error %s: verification failed\n", + (file == NULL) ? "stdin" : file); } X509_STORE_CTX_free(csc); diff --git a/apps/x509.c b/apps/x509.c index 8d4bf71a03..2c642110ed 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -1084,6 +1084,10 @@ static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, if (!X509V3_EXT_add_nconf(conf, &ctx, section, x)) goto err; } +#ifndef OPENSSL_NO_SM2 + if (EVP_PKEY_is_sm2(pkey) && !EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) + goto err; +#endif if (!X509_sign(x, pkey, digest)) goto err; return 1; diff --git a/crypto/asn1/a_sign.c b/crypto/asn1/a_sign.c index 72381b6655..c29080b908 100644 --- a/crypto/asn1/a_sign.c +++ b/crypto/asn1/a_sign.c @@ -145,7 +145,7 @@ int ASN1_item_sign_ctx(const ASN1_ITEM *it, 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)); @@ -184,9 +184,14 @@ int ASN1_item_sign_ctx(const ASN1_ITEM *it, 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; diff --git a/crypto/ec/ec_pmeth.c b/crypto/ec/ec_pmeth.c index 64d2cc93a6..a63fd707f9 100644 --- a/crypto/ec/ec_pmeth.c +++ b/crypto/ec/ec_pmeth.c @@ -327,7 +327,8 @@ static int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) 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; } diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index c0a3cd720b..c111822eac 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1103,6 +1103,7 @@ SM2_F_PKEY_SM2_CTRL_STR:110:pkey_sm2_ctrl_str SM2_F_PKEY_SM2_DIGEST_CUSTOM:114:pkey_sm2_digest_custom SM2_F_PKEY_SM2_INIT:111:pkey_sm2_init SM2_F_PKEY_SM2_SIGN:112:pkey_sm2_sign +SM2_F_SM2_COMPUTE_KEY:116:SM2_compute_key SM2_F_SM2_COMPUTE_MSG_HASH:100:sm2_compute_msg_hash SM2_F_SM2_COMPUTE_USERID_DIGEST:101:sm2_compute_userid_digest SM2_F_SM2_COMPUTE_Z_DIGEST:113:sm2_compute_z_digest @@ -1185,7 +1186,7 @@ SSL_F_OSSL_STATEM_SERVER_CONSTRUCT_MESSAGE:431:* SSL_F_OSSL_STATEM_SERVER_POST_PROCESS_MESSAGE:601:\ ossl_statem_server_post_process_message SSL_F_OSSL_STATEM_SERVER_POST_WORK:602:ossl_statem_server_post_work -SSL_F_OSSL_STATEM_SERVER_PRE_WORK:640: +SSL_F_OSSL_STATEM_SERVER_PRE_WORK:640:ossl_statem_server_pre_work SSL_F_OSSL_STATEM_SERVER_PROCESS_MESSAGE:603:ossl_statem_server_process_message SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION:418:ossl_statem_server_read_transition SSL_F_OSSL_STATEM_SERVER_WRITE_TRANSITION:604:\ @@ -1271,6 +1272,10 @@ SSL_F_SSL_CTX_SET_TLSEXT_MAX_FRAGMENT_LENGTH:551:\ SSL_F_SSL_CTX_USE_CERTIFICATE:171:SSL_CTX_use_certificate SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1:172:SSL_CTX_use_certificate_ASN1 SSL_F_SSL_CTX_USE_CERTIFICATE_FILE:173:SSL_CTX_use_certificate_file +SSL_F_SSL_CTX_USE_GM_CERTIFICATE:641:SSL_CTX_use_gm_certificate +SSL_F_SSL_CTX_USE_GM_CERTIFICATE_ASN1:642:SSL_CTX_use_gm_certificate_ASN1 +SSL_F_SSL_CTX_USE_GM_PRIVATEKEY:643:SSL_CTX_use_gm_PrivateKey +SSL_F_SSL_CTX_USE_GM_PRIVATEKEY_ASN1:644:SSL_CTX_use_gm_PrivateKey_ASN1 SSL_F_SSL_CTX_USE_PRIVATEKEY:174:SSL_CTX_use_PrivateKey SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1:175:SSL_CTX_use_PrivateKey_ASN1 SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE:176:SSL_CTX_use_PrivateKey_file @@ -1297,7 +1302,9 @@ SSL_F_SSL_GET_SIGN_PKEY:183:* SSL_F_SSL_HANDSHAKE_HASH:560:ssl_handshake_hash SSL_F_SSL_INIT_WBIO_BUFFER:184:ssl_init_wbio_buffer SSL_F_SSL_KEY_UPDATE:515:SSL_key_update +SSL_F_SSL_LOAD_CERT_FILE:645:ssl_load_cert_file SSL_F_SSL_LOAD_CLIENT_CA_FILE:185:SSL_load_client_CA_file +SSL_F_SSL_LOAD_PKEY_FILE:646:ssl_load_pkey_file SSL_F_SSL_LOG_MASTER_SECRET:498:* SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE:499:ssl_log_rsa_client_key_exchange SSL_F_SSL_MODULE_INIT:392:ssl_module_init @@ -1331,11 +1338,14 @@ SSL_F_SSL_SET_CERT_AND_KEY:621:ssl_set_cert_and_key SSL_F_SSL_SET_CIPHER_LIST:271:SSL_set_cipher_list SSL_F_SSL_SET_CT_VALIDATION_CALLBACK:399:SSL_set_ct_validation_callback SSL_F_SSL_SET_FD:192:SSL_set_fd +SSL_F_SSL_SET_GM_CERT_AND_KEY:647:ssl_set_gm_cert_and_key SSL_F_SSL_SET_PKEY:193:ssl_set_pkey SSL_F_SSL_SET_RFD:194:SSL_set_rfd SSL_F_SSL_SET_SESSION:195:SSL_set_session SSL_F_SSL_SET_SESSION_ID_CONTEXT:218:SSL_set_session_id_context SSL_F_SSL_SET_SESSION_TICKET_EXT:294:SSL_set_session_ticket_ext +SSL_F_SSL_SET_SIGN_ENC_CERT:648:ssl_set_sign_enc_cert +SSL_F_SSL_SET_SIGN_ENC_PKEY:649:ssl_set_sign_enc_pkey SSL_F_SSL_SET_TLSEXT_MAX_FRAGMENT_LENGTH:550:SSL_set_tlsext_max_fragment_length SSL_F_SSL_SET_WFD:196:SSL_set_wfd SSL_F_SSL_SHUTDOWN:224:SSL_shutdown @@ -1346,6 +1356,10 @@ SSL_F_SSL_UNDEFINED_VOID_FUNCTION:244:ssl_undefined_void_function SSL_F_SSL_USE_CERTIFICATE:198:SSL_use_certificate SSL_F_SSL_USE_CERTIFICATE_ASN1:199:SSL_use_certificate_ASN1 SSL_F_SSL_USE_CERTIFICATE_FILE:200:SSL_use_certificate_file +SSL_F_SSL_USE_GM_CERTIFICATE:650:SSL_use_gm_certificate +SSL_F_SSL_USE_GM_CERTIFICATE_ASN1:651:SSL_use_gm_certificate_ASN1 +SSL_F_SSL_USE_GM_PRIVATEKEY:652:SSL_use_gm_PrivateKey +SSL_F_SSL_USE_GM_PRIVATEKEY_ASN1:653:SSL_use_gm_PrivateKey_ASN1 SSL_F_SSL_USE_PRIVATEKEY:201:SSL_use_PrivateKey SSL_F_SSL_USE_PRIVATEKEY_ASN1:202:SSL_use_PrivateKey_ASN1 SSL_F_SSL_USE_PRIVATEKEY_FILE:203:SSL_use_PrivateKey_file @@ -1362,6 +1376,20 @@ SSL_F_SSL_WRITE_EARLY_FINISH:527:* SSL_F_SSL_WRITE_EX:433:SSL_write_ex SSL_F_SSL_WRITE_INTERNAL:524:ssl_write_internal SSL_F_STATE_MACHINE:353:state_machine +SSL_F_TLCP_CHOOSE_SIGALG:662:tlcp_choose_sigalg +SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE:663:tlcp_construct_cke_sm2dhe +SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC:658:tlcp_construct_cke_sm2ecc +SSL_F_TLCP_CONSTRUCT_CLIENT_KEY_EXCHANGE:654:tlcp_construct_client_key_exchange +SSL_F_TLCP_CONSTRUCT_SERVER_KEY_EXCHANGE:655:tlcp_construct_server_key_exchange +SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE:664:tlcp_construct_ske_sm2dhe +SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC:659:tlcp_construct_ske_sm2ecc +SSL_F_TLCP_DERIVE:665:tlcp_derive +SSL_F_TLCP_PROCESS_CKE_SM2DHE:666:tlcp_process_cke_sm2dhe +SSL_F_TLCP_PROCESS_CKE_SM2ECC:660:tlcp_process_cke_sm2ecc +SSL_F_TLCP_PROCESS_CLIENT_KEY_EXCHANGE:656:tlcp_process_client_key_exchange +SSL_F_TLCP_PROCESS_KEY_EXCHANGE:657:tlcp_process_key_exchange +SSL_F_TLCP_PROCESS_SKE_SM2DHE:667:tlcp_process_ske_sm2dhe +SSL_F_TLCP_PROCESS_SKE_SM2ECC:661:tlcp_process_ske_sm2ecc SSL_F_TLS12_CHECK_PEER_SIGALG:333:tls12_check_peer_sigalg SSL_F_TLS12_COPY_SIGALGS:533:tls12_copy_sigalgs SSL_F_TLS13_CHANGE_CIPHER_STATE:440:tls13_change_cipher_state @@ -1712,6 +1740,7 @@ X509_F_BUILD_CHAIN:106:build_chain 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 @@ -1756,6 +1785,8 @@ X509_F_X509_REQ_CHECK_PRIVATE_KEY:144:X509_REQ_check_private_key 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 @@ -1767,8 +1798,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:166: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 diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index 1f36cb2164..9e25ae1b6c 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -459,6 +459,24 @@ const unsigned char *EVP_PKEY_get0_siphash(const EVP_PKEY *pkey, size_t *len) } #endif +# ifndef OPENSSL_NO_SM2 +int EVP_PKEY_is_sm2(EVP_PKEY *pkey) +{ + EC_KEY *eckey; + const EC_GROUP *group; + if (pkey == NULL) { + return 0; + } + 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 EVP_PKEY_id(pkey) == EVP_PKEY_SM2; +} +# endif + #ifndef OPENSSL_NO_RSA int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key) { diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h index 36c38d0d22..6d60f87518 100644 --- a/crypto/objects/obj_dat.h +++ b/crypto/objects/obj_dat.h @@ -10,7 +10,7 @@ */ /* Serialized OID's */ -static const unsigned char so[7770] = { +static const unsigned char so[7778] = { 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 */ @@ -1076,7 +1076,8 @@ static const unsigned char so[7770] = { 0x2A,0x85,0x03,0x07,0x01,0x02,0x01,0x01,0x04, /* [ 7736] OBJ_id_tc26_gost_3410_2012_256_paramSetD */ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0C, /* [ 7745] OBJ_hmacWithSHA512_224 */ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0D, /* [ 7753] OBJ_hmacWithSHA512_256 */ - 0x2A,0x81,0x1C,0xCF,0x55,0x01,0x68,0x0A, /* [ 7761] OBJ_sm4_xts */ + 0x2A,0x81,0x1C,0xCF,0x55,0x01,0x83,0x75, /* [ 7761] OBJ_SM2_with_SM3 */ + 0x2A,0x81,0x1C,0xCF,0x55,0x01,0x68,0x0A, /* [ 7769] OBJ_sm4_xts */ }; #define NUM_NID 1197 @@ -2276,11 +2277,11 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = { {"magma-mac", "magma-mac", NID_magma_mac}, {"hmacWithSHA512-224", "hmacWithSHA512-224", NID_hmacWithSHA512_224, 8, &so[7745]}, {"hmacWithSHA512-256", "hmacWithSHA512-256", NID_hmacWithSHA512_256, 8, &so[7753]}, - { NULL, NULL, NID_undef }, - {"SM4-XTS", "sm4-xts", NID_sm4_xts, 8, &so[7761]}, + {"SM2-SM3", "SM2-with-SM3", NID_SM2_with_SM3, 8, &so[7761]}, + {"SM4-XTS", "sm4-xts", NID_sm4_xts, 8, &so[7769]}, }; -#define NUM_SN 1187 +#define NUM_SN 1188 static const unsigned int sn_objs[NUM_SN] = { 364, /* "AD_DVCS" */ 419, /* "AES-128-CBC" */ @@ -2546,6 +2547,7 @@ static const unsigned int sn_objs[NUM_SN] = { 1100, /* "SHAKE128" */ 1101, /* "SHAKE256" */ 1172, /* "SM2" */ + 1195, /* "SM2-SM3" */ 1143, /* "SM3" */ 1134, /* "SM4-CBC" */ 1137, /* "SM4-CFB" */ @@ -3471,7 +3473,7 @@ static const unsigned int sn_objs[NUM_SN] = { 1093, /* "x509ExtAdmission" */ }; -#define NUM_LN 1187 +#define NUM_LN 1188 static const unsigned int ln_objs[NUM_LN] = { 363, /* "AD Time Stamping" */ 405, /* "ANSI X9.62" */ @@ -3627,6 +3629,7 @@ static const unsigned int ln_objs[NUM_LN] = { 1119, /* "RSA-SHA3-512" */ 188, /* "S/MIME" */ 167, /* "S/MIME Capabilities" */ + 1195, /* "SM2-with-SM3" */ 1006, /* "SNILS" */ 387, /* "SNMPv2" */ 1025, /* "SSH Client" */ @@ -4662,7 +4665,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 */ @@ -5132,6 +5135,7 @@ static const unsigned int obj_objs[NUM_OBJ] = { 1196, /* OBJ_sm4_xts 1 2 156 10197 1 104 10 */ 1172, /* OBJ_sm2 1 2 156 10197 1 301 */ 1143, /* OBJ_sm3 1 2 156 10197 1 401 */ + 1195, /* 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 */ diff --git a/crypto/objects/obj_mac.num b/crypto/objects/obj_mac.num index d1de6e1997..0d8ab53467 100644 --- a/crypto/objects/obj_mac.num +++ b/crypto/objects/obj_mac.num @@ -1193,3 +1193,4 @@ magma_mac 1192 hmacWithSHA512_224 1193 hmacWithSHA512_256 1194 sm4_xts 1196 +SM2_with_SM3 1195 diff --git a/crypto/objects/obj_xref.h b/crypto/objects/obj_xref.h index 5ef094bbfd..1acfcdeb18 100644 --- a/crypto/objects/obj_xref.h +++ b/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], }; diff --git a/crypto/objects/obj_xref.txt b/crypto/objects/obj_xref.txt index ca3e74461d..f3dd8ed318 100644 --- a/crypto/objects/obj_xref.txt +++ b/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 diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt index 14495f2ad8..5713fae4b5 100644 --- a/crypto/objects/objects.txt +++ b/crypto/objects/objects.txt @@ -385,6 +385,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 diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c index f63fbc50ea..916a35a5e8 100644 --- a/crypto/pkcs7/pk7_doit.c +++ b/crypto/pkcs7/pk7_doit.c @@ -946,6 +946,9 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, STACK_OF(X509_ATTRIBUTE) *sk; BIO *btmp; EVP_PKEY *pkey; +#ifndef OPENSSL_NO_SM2 + EVP_PKEY_CTX *pctx = NULL; +#endif mdc_tmp = EVP_MD_CTX_new(); if (mdc_tmp == NULL) { @@ -1013,7 +1016,19 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, goto err; } - if (!EVP_VerifyInit_ex(mdc_tmp, EVP_get_digestbynid(md_type), NULL)) + pkey = X509_get0_pubkey(x509); + if (!pkey) { + ret = -1; + goto err; + } + + ret = +#ifndef OPENSSL_NO_SM2 + EVP_PKEY_is_sm2(pkey) ? + EVP_DigestVerifyInit(mdc_tmp, &pctx, EVP_get_digestbynid(md_type), NULL, pkey) : +#endif + EVP_VerifyInit_ex(mdc_tmp, EVP_get_digestbynid(md_type), NULL); + if (!ret) goto err; alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf, @@ -1036,7 +1051,11 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, goto err; } - i = EVP_VerifyFinal(mdc_tmp, os->data, os->length, pkey); + i = +#ifndef OPENSSL_NO_SM2 + EVP_PKEY_is_sm2(pkey) ? EVP_DigestVerifyFinal(mdc_tmp, os->data, os->length) : +#endif + EVP_VerifyFinal(mdc_tmp, os->data, os->length, pkey); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE); ret = -1; diff --git a/crypto/sm2/build.info b/crypto/sm2/build.info index be76d96d31..adaf5f3d09 100644 --- a/crypto/sm2/build.info +++ b/crypto/sm2/build.info @@ -1,5 +1,5 @@ LIBS=../../libcrypto SOURCE[../../libcrypto]=\ - sm2_sign.c sm2_crypt.c sm2_err.c sm2_pmeth.c + sm2_sign.c sm2_crypt.c sm2_err.c sm2_pmeth.c sm2_kep.c diff --git a/crypto/sm2/sm2_err.c b/crypto/sm2/sm2_err.c index e5973e9c71..f5f75cb43c 100644 --- a/crypto/sm2/sm2_err.c +++ b/crypto/sm2/sm2_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-2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -21,6 +21,7 @@ static const ERR_STRING_DATA SM2_str_functs[] = { "pkey_sm2_digest_custom"}, {ERR_PACK(ERR_LIB_SM2, SM2_F_PKEY_SM2_INIT, 0), "pkey_sm2_init"}, {ERR_PACK(ERR_LIB_SM2, SM2_F_PKEY_SM2_SIGN, 0), "pkey_sm2_sign"}, + {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_COMPUTE_KEY, 0), "SM2_compute_key"}, {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_COMPUTE_MSG_HASH, 0), "sm2_compute_msg_hash"}, {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_COMPUTE_USERID_DIGEST, 0), @@ -51,6 +52,7 @@ static const ERR_STRING_DATA SM2_str_reasons[] = { {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_INVALID_ENCODING), "invalid encoding"}, {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_INVALID_FIELD), "invalid field"}, {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_NO_PARAMETERS_SET), "no parameters set"}, + {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_NO_PRIVATE_VALUE), "no private value"}, {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_USER_ID_TOO_LARGE), "user id too large"}, {0, NULL} }; diff --git a/crypto/sm2/sm2_kep.c b/crypto/sm2/sm2_kep.c new file mode 100644 index 0000000000..a7bd6817aa --- /dev/null +++ b/crypto/sm2/sm2_kep.c @@ -0,0 +1,254 @@ +/* + * Copyright 2019 The BabaSSL Project Authors. All Rights Reserved. + */ + +#include "internal/cryptlib.h" +#include +#include +#include +#include "crypto/sm2.h" +#include "crypto/ec.h" /* ecdh_KDF_X9_63() */ +#include "crypto/sm2err.h" + + +#ifndef OPENSSL_NO_SM2 +int SM2_compute_key(void *out, size_t outlen, int server, + const char *peer_uid, int peer_uid_len, + const char *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; + size_t elemet_len, idx; + + if (outlen > INT_MAX) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (peer_pub_key == NULL || self_eckey == NULL) { + SM2err(SM2_F_SM2_COMPUTE_KEY, SM2_R_NO_PRIVATE_VALUE); + goto err; + } + + priv_key = EC_KEY_get0_private_key(self_eckey); + if (priv_key == NULL) { + SM2err(SM2_F_SM2_COMPUTE_KEY, SM2_R_NO_PRIVATE_VALUE); + goto err; + } + + if (peer_ecdhe_key == NULL || self_ecdhe_key == NULL) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_PASSED_NULL_PARAMETER); + 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 == NULL || Rp == NULL || r == NULL) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE); + goto err; + } + + BN_CTX_start(ctx); + Xs = BN_CTX_get(ctx); + Xp = BN_CTX_get(ctx); + h = BN_CTX_get(ctx); + t = BN_CTX_get(ctx); + two_power_w = BN_CTX_get(ctx); + order = BN_CTX_get(ctx); + + if (order == NULL) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE); + goto err; + } + + group = EC_KEY_get0_group(self_eckey); + + if (!EC_GROUP_get_order(group, order, ctx) + || !EC_GROUP_get_cofactor(group, h, ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE); + goto err; + } + + w = (BN_num_bits(order) + 1) / 2 - 1; + if (!BN_lshift(two_power_w, BN_value_one(), w)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB); + goto err; + } + + /*Third: Caculate -- X = 2 ^ w + (x & (2 ^ w - 1)) = 2 ^ w + (x mod 2 ^ w)*/ + UorV = EC_POINT_new(group); + if (UorV == NULL) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE); + goto err; + } + + /*Test peer public key On curve*/ + if (!EC_POINT_is_on_curve(group, Rp, ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB); + 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)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB); + goto err; + } + + if (!EC_POINT_get_affine_coordinates_GFp(group, Rp, Xp, NULL, ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB); + goto err; + } + } + + /*x mod 2 ^ w*/ + /*Caculate Self x*/ + if (!BN_nnmod(Xs, Xs, two_power_w, ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB); + goto err; + } + + if (!BN_add(Xs, Xs, two_power_w)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB); + goto err; + } + + /*Caculate Peer x*/ + if (!BN_nnmod(Xp, Xp, two_power_w, ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB); + goto err; + } + + if (!BN_add(Xp, Xp, two_power_w)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB); + goto err; + } + + /*Forth: Caculate t*/ + if (!BN_mod_mul(t, Xs, r, order, ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB); + goto err; + } + + if (!BN_mod_add(t, t, priv_key, order, ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB); + goto err; + } + + /*Fifth: Caculate V or U*/ + if (!BN_mul(t, t, h, ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB); + goto err; + } + + /* [x]R */ + if (!EC_POINT_mul(group, UorV, NULL, Rp, Xp, ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB); + goto err; + } + + /* P + [x]R */ + if (!EC_POINT_add(group, UorV, UorV, + EC_KEY_get0_public_key(peer_pub_key), ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB); + goto err; + } + + if (!EC_POINT_mul(group, UorV, NULL, UorV, t, ctx)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB); + goto err; + } + + if (EC_POINT_is_at_infinity(group, UorV)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB); + goto err; + } + + /*Sixth: Caculate Key -- Need Xuorv, Yuorv, Zc, Zs, klen*/ + + 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_zalloc(buflen + 10); + if (buf == NULL) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE); + goto err; + } + + /*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) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB); + goto err; + } + + len = EVP_MD_size(md); + + /* Z_A || Z_B, server is initiator(Z_A), client is responder(Z_B) */ + if (server) { + if (!sm2_compute_z_digest((uint8_t *)(buf + idx), md, + (const uint8_t *)self_uid, + self_uid_len, self_eckey)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_INTERNAL_ERROR); + goto err; + } + + idx += len; + } + + if (!sm2_compute_z_digest((uint8_t *)(buf + idx), md, + (const uint8_t *)peer_uid, peer_uid_len, + peer_pub_key)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_INTERNAL_ERROR); + goto err; + } + idx += len; + + if (!server) { + if (!sm2_compute_z_digest((uint8_t *)(buf + idx), md, + (const uint8_t *)self_uid, + self_uid_len, self_eckey)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_INTERNAL_ERROR); + goto err; + } + idx += len; + } + + if (!ecdh_KDF_X9_63(out, outlen, (const unsigned char *)(buf + 1), idx - 1, + NULL, 0, md)) { + SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = outlen; + + err: + EC_POINT_free(UorV); + OPENSSL_free(buf); + if (ctx != NULL) + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + return ret; +} + +#endif diff --git a/crypto/sm2/sm2_pmeth.c b/crypto/sm2/sm2_pmeth.c index 0e722b910b..53cdbe9d80 100644 --- a/crypto/sm2/sm2_pmeth.c +++ b/crypto/sm2/sm2_pmeth.c @@ -221,6 +221,7 @@ static int pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) return 1; case EVP_PKEY_CTRL_DIGESTINIT: + case EVP_PKEY_CTRL_PKCS7_SIGN: /* nothing to be inited, this is to suppress the error... */ return 1; @@ -232,6 +233,10 @@ static int pkey_sm2_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) static int pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value) { + uint8_t *hex_id; + long hex_len = 0; + int ret = 0; + if (strcmp(type, "ec_paramgen_curve") == 0) { int nid = NID_undef; @@ -252,6 +257,24 @@ static int pkey_sm2_ctrl_str(EVP_PKEY_CTX *ctx, else return -2; return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc); + } else if (strcmp(type, "sm2_id") == 0) { + return pkey_sm2_ctrl(ctx, EVP_PKEY_CTRL_SET1_ID, + (int)strlen(value), (void *)value); + } else if (strcmp(type, "sm2_hex_id") == 0) { + /* + * TODO(3.0): reconsider the name "sm2_hex_id", OR change + * OSSL_PARAM_construct_from_text() / OSSL_PARAM_allocate_from_text() + * to handle infix "_hex_" + */ + hex_id = OPENSSL_hexstr2buf((const char *)value, &hex_len); + if (hex_id == NULL) { + SM2err(SM2_F_PKEY_SM2_CTRL_STR, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + ret = pkey_sm2_ctrl(ctx, EVP_PKEY_CTRL_SET1_ID, (int)hex_len, + (void *)hex_id); + OPENSSL_free(hex_id); + return ret; } return -2; @@ -265,6 +288,10 @@ static int pkey_sm2_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) const EVP_MD *md = EVP_MD_CTX_md(mctx); int mdlen = EVP_MD_size(md); + if (!smctx->id_set) + (void)pkey_sm2_ctrl(ctx, EVP_PKEY_CTRL_SET1_ID, SM2_DEFAULT_USERID_LEN + , (void *)SM2_DEFAULT_USERID); + if (!smctx->id_set) { /* * An ID value must be set. The specifications are not clear whether a diff --git a/crypto/x509/x509_err.c b/crypto/x509/x509_err.c index bdd1e67cd3..f02793bdc5 100644 --- a/crypto/x509/x509_err.c +++ b/crypto/x509/x509_err.c @@ -20,6 +20,7 @@ static const ERR_STRING_DATA X509_str_functs[] = { {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), @@ -87,6 +88,9 @@ static const ERR_STRING_DATA X509_str_functs[] = { {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), @@ -105,9 +109,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} }; diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c index fcf6b5ba37..efd2d1663f 100644 --- a/crypto/x509/x_all.c +++ b/crypto/x509/x_all.c @@ -19,16 +19,174 @@ #include #include +#ifndef OPENSSL_NO_SM2 + +# include "crypto/asn1.h" +# include "crypto/evp.h" + +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_COMMON_VERIFY_SM2, + ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); + goto err; + } + + if (pkey == NULL) { + X509err(X509_F_COMMON_VERIFY_SM2, ERR_R_PASSED_NULL_PARAMETER); + return -1; + } + + 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_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_COMMON_VERIFY_SM2, ASN1_R_WRONG_PUBLIC_KEY_TYPE); + goto err; + } + + if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) { + 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_COMMON_VERIFY_SM2, ERR_R_EVP_LIB); + ret = 0; + goto err; + } + /* NOTE: we tolerate no actual ID, to provide maximum flexibility */ + 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_COMMON_VERIFY_SM2, ERR_R_EVP_LIB); + ret = 0; + goto err; + } + + 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_COMMON_VERIFY_SM2, ERR_R_INTERNAL_ERROR); + goto err; + } + if (buf_in == NULL) { + X509err(X509_F_COMMON_VERIFY_SM2, ERR_R_MALLOC_FAILURE); + goto err; + } + inll = inl; + + ret = EVP_DigestVerify(ctx, signature->data, + (size_t)signature->length, buf_in, inl); + if (ret <= 0) { + X509err(X509_F_COMMON_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; +} + +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) { +#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)); } 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)); } diff --git a/crypto/x509/x_req.c b/crypto/x509/x_req.c index d2b02f6dae..de4ff2cfed 100644 --- a/crypto/x509/x_req.c +++ b/crypto/x509/x_req.c @@ -45,6 +45,29 @@ static int rinf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, 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), @@ -57,7 +80,7 @@ ASN1_SEQUENCE_enc(X509_REQ_INFO, enc, rinf_cb) = { 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) @@ -66,3 +89,16 @@ ASN1_SEQUENCE_ref(X509_REQ, 0) = { 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 diff --git a/crypto/x509/x_x509.c b/crypto/x509/x_x509.c index 7aa8b77ae7..8c27265874 100644 --- a/crypto/x509/x_x509.c +++ b/crypto/x509/x_x509.c @@ -53,6 +53,9 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, 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 */ @@ -72,6 +75,9 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, #ifndef OPENSSL_NO_RFC3779 ret->rfc3779_addr = NULL; ret->rfc3779_asid = NULL; +#endif +#ifndef OPENSSL_NO_SM2 + ret->sm2_id = NULL; #endif ret->aux = NULL; ret->crldp = NULL; @@ -91,6 +97,9 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, #ifndef OPENSSL_NO_RFC3779 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 break; @@ -245,3 +254,16 @@ int X509_get_signature_nid(const X509 *x) { return OBJ_obj2nid(x->sig_alg.algorithm); } + +#ifndef OPENSSL_NO_SM2 +void X509_set0_sm2_id(X509 *x, ASN1_OCTET_STRING *sm2_id) +{ + ASN1_OCTET_STRING_free(x->sm2_id); + x->sm2_id = sm2_id; +} + +ASN1_OCTET_STRING *X509_get0_sm2_id(X509 *x) +{ + return x->sm2_id; +} +#endif diff --git a/doc/man1/ca.pod b/doc/man1/ca.pod index 4380d869ea..1a6c53e0c2 100644 --- a/doc/man1/ca.pod +++ b/doc/man1/ca.pod @@ -57,6 +57,8 @@ B B [B<-multivalue-rdn>] [B<-rand file...>] [B<-writerand file>] +[B<-sm2-id string>] +[B<-sm2-hex-id hex-string>] =head1 DESCRIPTION @@ -303,6 +305,16 @@ all others. Writes random data to the specified I 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 @@ -600,6 +612,10 @@ Sign a certificate request: 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 diff --git a/doc/man1/pkeyutl.pod b/doc/man1/pkeyutl.pod index f6fd48d5b5..1a742ab358 100644 --- a/doc/man1/pkeyutl.pod +++ b/doc/man1/pkeyutl.pod @@ -10,6 +10,8 @@ pkeyutl - public key algorithm utility B B [B<-help>] [B<-in file>] +[B<-rawin>] +[B<-digest algorithm>] [B<-out file>] [B<-sigfile file>] [B<-inkey file>] @@ -54,6 +56,23 @@ Print out a usage message. This specifies the input filename to read data from or standard input if this option is not specified. +=item B<-rawin> + +This indicates that the input data is raw data, which is not hashed by any +message digest algorithm. The user can specify a digest algorithm by using +the B<-digest> option. This option can only be used with B<-sign> and +B<-verify>. + +=item B<-digest algorithm> + +This specifies the digest algorithm which is used to hash the input data before +signing or verifying it with the input key. This option could be omitted if the +signature algorithm does not require one (for instance, EdDSA). If this option +is omitted but the signature algorithm requires one, a default value will be +used. For signature algorithms like RSA, DSA and ECDSA, SHA-256 will be the +default digest algorithm. For SM2, it will be SM3. If this option is present, +then the B<-rawin> option must be also specified to B. + =item B<-out filename> Specifies the output filename to write to or standard output by @@ -296,6 +315,29 @@ the B<-pkeyopt> B option. The X25519 and X448 algorithms support key derivation only. Currently there are no additional options. +=head1 SM2 + +The SM2 algorithm supports sign, verify, encrypt and decrypt operations. For +the sign and verify operations, SM2 requires an ID string to be passed in. The +following B value is supported: + +=over 4 + +=item B + +This sets the ID string used in SM2 sign or verify operations. While verifying +an SM2 signature, the ID string must be the same one used when signing the data. +Otherwise the verification will fail. + +=item B + +This sets the ID string used in SM2 sign or verify operations. While verifying +an SM2 signature, the ID string must be the same one used when signing the data. +Otherwise the verification will fail. The ID string provided with this option +should be a valid hexadecimal value. + +=back + =head1 EXAMPLES Sign some data using a private key: @@ -329,6 +371,16 @@ Decrypt some data using a private key with OAEP padding using SHA256: openssl pkeyutl -decrypt -in file -inkey key.pem -out secret \ -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 +Sign some data using an L private key and a specific ID: + + openssl pkeyutl -sign -in file -inkey sm2.key -out sig -rawin -digest sm3 \ + -pkeyopt sm2_id:someid + +Verify some data using an L certificate and a specific ID: + + openssl pkeyutl -verify -certin -in file -inkey sm2.cert -sigfile sig \ + -rawin -digest sm3 -pkeyopt sm2_id:someid + =head1 SEE ALSO L, L, L diff --git a/doc/man1/req.pod b/doc/man1/req.pod index 539b843803..e117ec6a92 100644 --- a/doc/man1/req.pod +++ b/doc/man1/req.pod @@ -50,6 +50,8 @@ B B [B<-batch>] [B<-verbose>] [B<-engine id>] +[B<-sm2-id string>] +[B<-sm2-hex-id hex-string>] =head1 DESCRIPTION @@ -339,6 +341,16 @@ for all available algorithms. Specifies an engine (by its unique B string) which would be used for key generation operations. +=item B<-sm2-id> + +Specify the ID string to use when verifying an SM2 certificate request. 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 verifying an SM2 certificate request. The +argument for this option is string of hexadecimal digits. + =back =head1 CONFIGURATION FILE FORMAT @@ -534,6 +546,15 @@ Generate a self signed root certificate: 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 option: 1.2.3.4 shortName A longer Name diff --git a/doc/man1/s_client.pod b/doc/man1/s_client.pod index f1a2c4abdf..8fa82a1df1 100644 --- a/doc/man1/s_client.pod +++ b/doc/man1/s_client.pod @@ -20,8 +20,10 @@ B B [B<-verify depth>] [B<-verify_return_error>] [B<-cert filename>] +[B<-dcert filename>] [B<-certform DER|PEM>] [B<-key filename>] +[B<-dkey filename>] [B<-keyform DER|PEM>] [B<-cert_chain filename>] [B<-build_chain>] @@ -32,6 +34,7 @@ B B [B<-xcertform PEM|DER>] [B<-xkeyform PEM|DER>] [B<-pass arg>] +[B<-dpass arg>] [B<-CApath directory>] [B<-CAfile filename>] [B<-chainCApath directory>] @@ -91,6 +94,7 @@ B B [B<-tls1_1>] [B<-tls1_2>] [B<-tls1_3>] +[B<-tlcp>] [B<-no_ssl3>] [B<-no_tls1>] [B<-no_tls1_1>] @@ -214,6 +218,11 @@ ClientHello message. Cannot be used in conjunction with the B<-servername> or The certificate to use, if one is requested by the server. The default is not to use a certificate. +=item B<-dcert infile>, B<-dkey infile>, B<-dpass val> + +Specify an encryption certificate, private key and passphrase +respectively, usually for TLCP. + =item B<-certform format> The certificate format to use: DER or PEM. PEM is the default. diff --git a/doc/man1/verify.pod b/doc/man1/verify.pod index da2b702482..a6b6b2be80 100644 --- a/doc/man1/verify.pod +++ b/doc/man1/verify.pod @@ -50,6 +50,8 @@ B B [B<-verify_name name>] [B<-x509_strict>] [B<-show_chain>] +[B<-sm2-id string>] +[B<-sm2-hex-id hex-string>] [B<->] [certificates] @@ -319,6 +321,16 @@ Display information about the certificate chain that has been built (if successful). Certificates in the chain that came from the untrusted list will be flagged as "untrusted". +=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. + =item B<-> Indicates the last option. All arguments following this are assumed to be @@ -774,6 +786,8 @@ The B<-show_chain> option was added in OpenSSL 1.1.0. The B<-issuer_checks> option is deprecated as of OpenSSL 1.1.0 and is silently ignored. +The B<-sm2-id> and B<-sm2-hex-id> options were added in OpenSSL 3.0.0. + =head1 COPYRIGHT Copyright 2000-2020 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man3/EVP_PKEY_set1_RSA.pod b/doc/man3/EVP_PKEY_set1_RSA.pod index d571e58d95..f9ee16df95 100644 --- a/doc/man3/EVP_PKEY_set1_RSA.pod +++ b/doc/man3/EVP_PKEY_set1_RSA.pod @@ -9,7 +9,7 @@ EVP_PKEY_assign_RSA, EVP_PKEY_assign_DSA, EVP_PKEY_assign_DH, EVP_PKEY_assign_EC_KEY, EVP_PKEY_assign_POLY1305, EVP_PKEY_assign_SIPHASH, EVP_PKEY_get0_hmac, EVP_PKEY_get0_poly1305, EVP_PKEY_get0_siphash, EVP_PKEY_type, EVP_PKEY_id, EVP_PKEY_base_id, EVP_PKEY_set_alias_type, -EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions +EVP_PKEY_is_sm2, EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions =head1 SYNOPSIS @@ -45,6 +45,8 @@ EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions int EVP_PKEY_type(int type); int EVP_PKEY_set_alias_type(EVP_PKEY *pkey, int type); + int EVP_PKEY_is_sm2(EVP_PKEY *pkey); + ENGINE *EVP_PKEY_get0_engine(const EVP_PKEY *pkey); int EVP_PKEY_set1_engine(EVP_PKEY *pkey, ENGINE *engine); @@ -93,6 +95,9 @@ EVP_PKEY_set_alias_type() allows modifying a EVP_PKEY to use a different set of algorithms than the default. This is currently used to support SM2 keys, which use an identical encoding to ECDSA. +EVP_PKEY_is_sm2() can be used to determine whether the B is +SM2 curve. + =head1 NOTES In accordance with the OpenSSL naming convention the key obtained @@ -134,6 +139,8 @@ EVP_PKEY_set1_engine() returns 1 for success and 0 for failure. EVP_PKEY_set_alias_type() returns 1 for success and 0 for error. +EVP_PKEY_is_sm2() returns 1 for success and 0 for error. + =head1 EXAMPLES After loading an ECC key, it is possible to convert it to using SM2 diff --git a/doc/man3/SSL_CTX_new.pod b/doc/man3/SSL_CTX_new.pod index a6c036c365..23f93f6c50 100644 --- a/doc/man3/SSL_CTX_new.pod +++ b/doc/man3/SSL_CTX_new.pod @@ -9,7 +9,8 @@ TLSv1_1_method, TLSv1_1_server_method, TLSv1_1_client_method, TLS_method, TLS_server_method, TLS_client_method, SSLv23_method, SSLv23_server_method, SSLv23_client_method, DTLS_method, DTLS_server_method, DTLS_client_method, DTLSv1_method, DTLSv1_server_method, DTLSv1_client_method, -DTLSv1_2_method, DTLSv1_2_server_method, DTLSv1_2_client_method +DTLSv1_2_method, DTLSv1_2_server_method, DTLSv1_2_client_method, +TLCP_method, TLCP_server_method, TLCP_client_method, - create a new SSL_CTX object as framework for TLS/SSL or DTLS enabled functions @@ -68,6 +69,12 @@ functions const SSL_METHOD *DTLSv1_2_client_method(void); #endif + #ifndef OPENSSL_NO_TLCP + const SSL_METHOD *TLCP_method(void); + const SSL_METHOD *TLCP_server_method(void); + const SSL_METHOD *TLCP_client_method(void); + #endif + =head1 DESCRIPTION SSL_CTX_new() creates a new B object as framework to @@ -93,6 +100,8 @@ These are the general-purpose I SSL/TLS methods. The actual protocol version used will be negotiated to the highest version mutually supported by the client and the server. The supported protocols are SSLv3, TLSv1, TLSv1.1, TLSv1.2 and TLSv1.3. +TLS_method() and TLS_server_method() can aslo support TLCP protocol +by using TLCP_client_method(). Applications should use these methods, and avoid the version-specific methods described below, which are deprecated. @@ -141,6 +150,12 @@ These methods are deprecated. These are the version-specific methods for DTLSv1. These methods are deprecated. +=item TLCP_method(), TLCP_server_method(), TLCP_client_method() + +These are the GM version-specific methods for TLCP protocol. +Valid TLCP ciphersuite names are ECDHE-SM4-CBC-SM3 and ECC-SM4-CBC-SM3. +B(argument to Configure) was required. + =back SSL_CTX_new() initializes the list of ciphers, the session cache setting, the @@ -162,7 +177,7 @@ allow newer protocols like TLS 1.0, TLS 1.1, TLS 1.2 or TLS 1.3. The list of protocols available can also be limited using the B, B, B, -B, B and B +B, B, B and B options of the L or L functions, but this approach is not recommended. Clients should avoid creating "holes" in the set of diff --git a/doc/man3/SSL_CTX_set_options.pod b/doc/man3/SSL_CTX_set_options.pod index 969e0366c4..304e966136 100644 --- a/doc/man3/SSL_CTX_set_options.pod +++ b/doc/man3/SSL_CTX_set_options.pod @@ -114,11 +114,11 @@ preferences. When not set, the SSL server will always follow the clients preferences. When set, the SSL/TLS server will choose following its own preferences. -=item SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1, SSL_OP_NO_TLSv1_1, +=item SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1, SSL_OP_NO_TLSv1_1, SSL_OP_NO_TLCP SSL_OP_NO_TLSv1_2, SSL_OP_NO_TLSv1_3, SSL_OP_NO_DTLSv1, SSL_OP_NO_DTLSv1_2 These options turn off the SSLv3, TLSv1, TLSv1.1, TLSv1.2 or TLSv1.3 protocol -versions with TLS or the DTLSv1, DTLSv1.2 versions with DTLS, +versions with TLS or the DTLSv1, DTLSv1.2 versions with DTLS, TLCP respectively. As of OpenSSL 1.1.0, these options are deprecated, use L and diff --git a/doc/man3/SSL_CTX_use_certificate.pod b/doc/man3/SSL_CTX_use_certificate.pod index b065d8f9e5..7a717e7217 100644 --- a/doc/man3/SSL_CTX_use_certificate.pod +++ b/doc/man3/SSL_CTX_use_certificate.pod @@ -12,7 +12,12 @@ SSL_CTX_use_RSAPrivateKey_ASN1, SSL_CTX_use_RSAPrivateKey_file, SSL_use_PrivateKey_file, SSL_use_PrivateKey_ASN1, SSL_use_PrivateKey, SSL_use_RSAPrivateKey, SSL_use_RSAPrivateKey_ASN1, SSL_use_RSAPrivateKey_file, SSL_CTX_check_private_key, SSL_check_private_key, -SSL_CTX_use_cert_and_key, SSL_use_cert_and_key +SSL_CTX_use_cert_and_key, SSL_use_cert_and_key, +SSL_CTX_use_gm_certificate, SSL_CTX_use_gm_certificate_ASN1, SSL_CTX_use_gm_certificate_file, +SSL_use_gm_certificate, SSL_use_gm_certificate_ASN1, SSL_use_gm_certificate_file, +SSL_CTX_use_gm_PrivateKey, SSL_CTX_use_gm_PrivateKey_ASN1, SSL_CTX_use_gm_PrivateKey_file, +SSL_use_gm_PrivateKey, SSL_use_gm_PrivateKey_ASN1, SSL_use_gm_PrivateKey_file, +SSL_CTX_use_gm_cert_and_key, SSL_use_gm_cert_and_key - load certificate and key data =head1 SYNOPSIS @@ -26,6 +31,13 @@ SSL_CTX_use_cert_and_key, SSL_use_cert_and_key int SSL_use_certificate_ASN1(SSL *ssl, unsigned char *d, int len); int SSL_use_certificate_file(SSL *ssl, const char *file, int type); + int SSL_CTX_use_gm_certificate(SSL_CTX *ctx, X509 *x, int usage); + int SSL_CTX_use_gm_certificate_ASN1(SSL_CTX *ctx, int len, unsigned char *d, int usage); + int SSL_CTX_use_gm_certificate_file(SSL_CTX *ctx, const char *file, int type, int usage); + int SSL_use_gm_certificate(SSL *ssl, X509 *x, int usage); + int SSL_use_gm_certificate_ASN1(SSL *ssl, unsigned char *d, int len, int usage); + int SSL_use_gm_certificate_file(SSL *ssl, const char *file, int type, int usage); + int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); int SSL_use_certificate_chain_file(SSL *ssl, const char *file); @@ -43,12 +55,23 @@ SSL_CTX_use_cert_and_key, SSL_use_cert_and_key int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len); int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type); + int SSL_CTX_use_gm_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey, int usage); + int SSL_CTX_use_gm_PrivateKey_ASN1(int pk, SSL_CTX *ctx, unsigned char *d, + long len, int usage); + int SSL_CTX_use_gm_PrivateKey_file(SSL_CTX *ctx, const char *file, int type, int usage); + int SSL_use_gm_PrivateKey(SSL *ssl, EVP_PKEY *pkey, int usage); + int SSL_use_gm_PrivateKey_ASN1(int pk, SSL *ssl, unsigned char *d, long len, int usage); + int SSL_use_gm_PrivateKey_file(SSL *ssl, const char *file, int type, int usage); + int SSL_CTX_check_private_key(const SSL_CTX *ctx); int SSL_check_private_key(const SSL *ssl); int SSL_CTX_use_cert_and_key(SSL_CTX *ctx, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override); int SSL_use_cert_and_key(SSL *ssl, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override); + int SSL_CTX_use_gm_cert_and_key(SSL_CTX *ctx, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override, int usage); + int SSL_use_gm_cert_and_key(SSL *ssl, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override, int usage); + =head1 DESCRIPTION These functions load the certificates and private keys into the SSL_CTX @@ -81,6 +104,21 @@ SSL_use_certificate_file() loads the certificate from B into B. See the NOTES section on why SSL_CTX_use_certificate_chain_file() should be preferred. +SSL_CTX_use_gm_certificate() loads the certificate B into B +and specify B. SSL_use_gm_certificate() loads B into B +and specify B. The B should be SSL_USAGE_SIG or SSL_USAGE_ENC. + +SSL_CTX_use_gm_certificate_ASN1() loads the ASN1 encoded certificate from +the memory location B (with length B) into B and specify B, +SSL_use_gm_certificate_ASN1() loads the ASN1 encoded certificate into B +and specify B. + +SSL_CTX_use_gm_certificate_file() loads the first certificate stored in B +into B and specify B. The formatting B of the certificate must +be specified from the known types SSL_FILETYPE_PEM, SSL_FILETYPE_ASN1. +SSL_use_gm_certificate_file() loads the certificate from B into B +and specify B. + SSL_CTX_use_certificate_chain_file() loads a certificate chain from B into B. The certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server @@ -127,6 +165,22 @@ B to B. SSL_use_PrivateKey_file() adds the first private key found in B to B; SSL_use_RSAPrivateKey_file() adds the first private RSA key found to B. +SSL_CTX_use_gm_PrivateKey() adds B as private key to B and +specify B. SSL_CTX_use_gm_PrivateKey_ASN1() adds the private key of +type B stored at memory location B (length B) to B and +specify B. SSL_CTX_use_gm_PrivateKey_file() adds the first private +key found in B to B. The formatting B of the private key +must be specified from the known types SSL_FILETYPE_PEM, SSL_FILETYPE_ASN1. + +SSL_use_PrivateKey() adds B as private key to B and sprcify B. +SSL_use_gm_PrivateKey_ASN1() adds the private key to B and sprcify B. +SSL_use_gm_PrivateKey_file() adds the first private key found in B to B +and sprcify B. + +SSL_CTX_use_gm_cert_and_key() and SSL_use_gm_cert_and_key() assign the X.509 +certificate B, private key B, and certificate B onto the +corresponding B or B and specify B. + SSL_CTX_check_private_key() checks the consistency of a private key with the corresponding certificate loaded into B. If more than one key/certificate pair (RSA/DSA) is installed, the last item installed will diff --git a/doc/man3/X509_get0_sm2_id.pod b/doc/man3/X509_get0_sm2_id.pod new file mode 100644 index 0000000000..d8a85d7f8b --- /dev/null +++ b/doc/man3/X509_get0_sm2_id.pod @@ -0,0 +1,55 @@ +=pod + +=head1 NAME + +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 + + #include + + 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 + +X509_get0_sm2_id() gets the ID value of an SM2 certificate B by returning an +B object which should not be freed by the caller. + +X509_set0_sm2_id() sets the B value to an SM2 certificate B. Calling +this function transfers the memory management of the value to the X509 object, +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 objects instead of B. + +=head1 NOTES + +SM2 signature algorithm requires an ID value when generating and verifying a +signature. The functions described in this manual provide the user with the +ability to set and retrieve the SM2 ID value. + +=head1 RETURN VALUES + +X509_set0_sm2_id() and X509_REQ_set0_sm2_id() do not return a value. + +=head1 SEE ALSO + +L, L + +=head1 COPYRIGHT + +Copyright 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 +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/doc/man7/ssl.pod b/doc/man7/ssl.pod index d439860b5b..8d7293a545 100644 --- a/doc/man7/ssl.pod +++ b/doc/man7/ssl.pod @@ -183,6 +183,18 @@ Constructor for the SSLv3 SSL_METHOD structure for clients. Constructor for the SSLv3 SSL_METHOD structure for servers. +=item const SSL_METHOD *B(void); + +Constructor for the TLCP SSL_METHOD structure for clients, servers or both. + +=item const SSL_METHOD *B(void); + +Constructor for the TLCP SSL_METHOD structure for clients. + +=item const SSL_METHOD *B(void); + +Constructor for the TLCP SSL_METHOD structure for servers. + =back =head2 Dealing with Ciphers @@ -393,6 +405,12 @@ Use the file path to locate trusted CA certificates. =item int B(SSL_CTX *ctx, const char *file, int type); +=item int B(SSL_CTX *ctx, EVP_PKEY *pkey, int usage); + +=item int B(int type, SSL_CTX *ctx, unsigned char *d, long len, int usage); + +=item int B(SSL_CTX *ctx, const char *file, int type, int usage); + =item int B(SSL_CTX *ctx, X509 *x); =item int B(SSL_CTX *ctx, int len, unsigned char *d); @@ -401,6 +419,14 @@ Use the file path to locate trusted CA certificates. =item int B(SSL_CTX *ctx, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override); +=item int B(SSL_CTX *ctx, X509 *x, int usage); + +=item int B(SSL_CTX *ctx, int len, unsigned char *d, int usage); + +=item int B(SSL_CTX *ctx, const char *file, int type, int usage); + +=item int B(SSL_CTX *ctx, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override, int usage); + =item X509 *B(const SSL_CTX *ctx); =item EVP_PKEY *B(const SSL_CTX *ctx); @@ -704,6 +730,12 @@ Returns the current handshake state. =item int B(SSL *ssl, const char *file, int type); +=item int B(SSL *ssl, EVP_PKEY *pkey, int usage); + +=item int B(int type, SSL *ssl, unsigned char *d, long len, int usage); + +=item int B(SSL *ssl, const char *file, int type, int usage); + =item int B(SSL *ssl, X509 *x); =item int B(SSL *ssl, int len, unsigned char *d); @@ -712,6 +744,14 @@ Returns the current handshake state. =item int B(SSL *ssl, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override); +=item int B(SSL *ssl, X509 *x, int usage); + +=item int B(SSL *ssl, int len, unsigned char *d, int usage); + +=item int B(SSL *ssl, const char *file, int type, int usage); + +=item int B(SSL *ssl, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override, int usage); + =item int B(const SSL *ssl); =item int B(const SSL *ssl); diff --git a/fuzz/oids.txt b/fuzz/oids.txt index a3eaa721a4..1ca19226e6 100644 --- a/fuzz/oids.txt +++ b/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_sm4_xts="\x2A\x81\x1C\xCF\x55\x01\x68\x0A" +OBJ_SM2_with_SM3="\x2A\x81\x1C\xCF\x55\x01\x83\x75" diff --git a/include/crypto/sm2.h b/include/crypto/sm2.h index a7f5548c08..1006b31208 100644 --- a/include/crypto/sm2.h +++ b/include/crypto/sm2.h @@ -16,9 +16,11 @@ # ifndef OPENSSL_NO_SM2 # include +# include /* The default user id as specified in GM/T 0009-2012 */ # define SM2_DEFAULT_USERID "1234567812345678" +# define SM2_DEFAULT_USERID_LEN 16 int sm2_compute_z_digest(uint8_t *out, const EVP_MD *digest, diff --git a/include/crypto/sm2err.h b/include/crypto/sm2err.h index d1c0ee2591..251c4f9fe4 100644 --- a/include/crypto/sm2err.h +++ b/include/crypto/sm2err.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -8,12 +8,10 @@ * https://www.openssl.org/source/license.html */ -#ifndef OSSL_CRYPTO_SM2ERR_H -# define OSSL_CRYPTO_SM2ERR_H +#ifndef HEADER_SM2ERR_H +# define HEADER_SM2ERR_H -# ifndef HEADER_SYMHACKS_H -# include -# endif +# include # include @@ -33,6 +31,7 @@ int ERR_load_SM2_strings(void); # define SM2_F_PKEY_SM2_DIGEST_CUSTOM 114 # define SM2_F_PKEY_SM2_INIT 111 # define SM2_F_PKEY_SM2_SIGN 112 +# define SM2_F_SM2_COMPUTE_KEY 116 # define SM2_F_SM2_COMPUTE_MSG_HASH 100 # define SM2_F_SM2_COMPUTE_USERID_DIGEST 101 # define SM2_F_SM2_COMPUTE_Z_DIGEST 113 @@ -59,6 +58,7 @@ int ERR_load_SM2_strings(void); # define SM2_R_INVALID_ENCODING 104 # define SM2_R_INVALID_FIELD 105 # define SM2_R_NO_PARAMETERS_SET 109 +# define SM2_R_NO_PRIVATE_VALUE 113 # define SM2_R_USER_ID_TOO_LARGE 106 # endif diff --git a/include/crypto/x509.h b/include/crypto/x509.h index 243ea74f6f..a6e812a004 100644 --- a/include/crypto/x509.h +++ b/include/crypto/x509.h @@ -73,6 +73,9 @@ struct X509_req_st { 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 { @@ -177,7 +180,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 @@ -185,6 +188,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 */ ; /* diff --git a/include/openssl/evp.h b/include/openssl/evp.h index d11e5ae12c..c4b9cd3a9f 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1015,6 +1015,10 @@ const unsigned char *EVP_PKEY_get0_poly1305(const EVP_PKEY *pkey, size_t *len); const unsigned char *EVP_PKEY_get0_siphash(const EVP_PKEY *pkey, size_t *len); # endif +# ifndef OPENSSL_NO_SM2 +int EVP_PKEY_is_sm2(EVP_PKEY *pkey); +# endif + # ifndef OPENSSL_NO_RSA struct rsa_st; int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key); diff --git a/include/openssl/obj_mac.h b/include/openssl/obj_mac.h index 9c89f77411..edfc87de89 100644 --- a/include/openssl/obj_mac.h +++ b/include/openssl/obj_mac.h @@ -1179,6 +1179,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 1195 +#define OBJ_SM2_with_SM3 OBJ_sm_scheme,501L + #define LN_hmacWithSHA224 "hmacWithSHA224" #define NID_hmacWithSHA224 798 #define OBJ_hmacWithSHA224 OBJ_rsadsi,2L,8L diff --git a/include/openssl/sm2.h b/include/openssl/sm2.h new file mode 100644 index 0000000000..e74b4052a5 --- /dev/null +++ b/include/openssl/sm2.h @@ -0,0 +1,31 @@ +/* + * Copyright 2022 Huawei Technologies Co., Ltd. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_SM2_H +# define HEADER_SM2_H + +#include "ossl_typ.h" + +# ifdef __cplusplus +extern "C" { +# endif + +# ifndef OPENSSL_NO_SM2 +int SM2_compute_key(void *out, size_t outlen, + int server, const char *peer_uid, int peer_uid_len, + const char *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); +# endif + +# ifdef __cplusplus +} +# endif +#endif diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 9af0c8995e..8d211603ef 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -300,6 +300,11 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx); * Reserved value (until OpenSSL 1.2.0) 0x00000001U * Reserved value (until OpenSSL 1.2.0) 0x00000002U */ +#ifndef OPENSSL_NO_TLCP +/* Use reserved value for the position of enc cert, default is placed at the end */ +# define SSL_OP_ENCCERT_SECOND_POSITION 0x00000002U +#endif + /* Allow initial connection to servers that don't support RI */ # define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004U @@ -383,8 +388,15 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx); # define SSL_OP_NO_DTLSv1 0x04000000U # define SSL_OP_NO_DTLSv1_2 0x08000000U +#ifndef OPENSSL_NO_TLCP +/* Use reserved value for TCLP(GB/T 38636-2020) */ +# define SSL_OP_NO_TLCP 0x00000001U +# define SSL_OP_NO_SSL_MASK (SSL_OP_NO_TLCP|SSL_OP_NO_SSLv3|\ + SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2|SSL_OP_NO_TLSv1_3) +#else # define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv3|\ SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2|SSL_OP_NO_TLSv1_3) +#endif # define SSL_OP_NO_DTLS_MASK (SSL_OP_NO_DTLSv1|SSL_OP_NO_DTLSv1_2) /* Disallow all renegotiation */ @@ -1041,6 +1053,11 @@ typedef enum { TLS_ST_SR_END_OF_EARLY_DATA } OSSL_HANDSHAKE_STATE; +#ifndef OPENSSL_NO_TLCP +# define SSL_USAGE_SIG 0 +# define SSL_USAGE_ENC 1 +#endif + /* * Most of the following state values are no longer used and are defined to be * the closest equivalent value in the current state machine code. Not all @@ -1177,6 +1194,19 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) /* fatal */ # define SSL_AD_INAPPROPRIATE_FALLBACK TLS1_AD_INAPPROPRIATE_FALLBACK # define SSL_AD_NO_APPLICATION_PROTOCOL TLS1_AD_NO_APPLICATION_PROTOCOL + +/* These alert types are for TLCP */ +# define SSL_AD_UNSUPPORTED_SITE2SITE TLCP_AD_UNSUPPORTED_SITE2SITE +/* fatal */ +# define SSL_AD_NO_AREA TLCP_AD_NO_AREA +# define SSL_AD_UNSUPPORTED_AREATYPE TLCP_AD_UNSUPPORTED_AREATYPE +# define SSL_AD_BAD_IBCPARAM TLCP_AD_BAD_IBCPARAM +/* fatal */ +# define SSL_AD_UNSUPPORTED_IBCPARAM TLCP_AD_UNSUPPORTED_IBCPARAM +/* fatal */ +# define SSL_AD_IDENTITY_NEED TLCP_AD_IDENTITY_NEED +/* fatal */ + # define SSL_ERROR_NONE 0 # define SSL_ERROR_SSL 1 # define SSL_ERROR_WANT_READ 2 @@ -1570,9 +1600,20 @@ __owur int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa); __owur int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const unsigned char *d, long len); # endif +# ifndef OPENSSL_NO_TLCP +__owur int SSL_use_gm_PrivateKey(SSL *ssl, EVP_PKEY *pkey, int usage); +__owur int SSL_use_gm_PrivateKey_ASN1(int pk, SSL *ssl, const unsigned char *d, + long len, int usage); +# endif __owur int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey); __owur int SSL_use_PrivateKey_ASN1(int pk, SSL *ssl, const unsigned char *d, long len); +# ifndef OPENSSL_NO_TLCP +__owur int SSL_use_gm_certificate(SSL *ssl, X509 *x, int usage); +__owur int SSL_use_gm_certificate_ASN1(SSL *ssl, const unsigned char *d, int len, int usage); +__owur int SSL_use_gm_cert_and_key(SSL *ssl, X509 *x509, EVP_PKEY *privatekey, + STACK_OF(X509) *chain, int override, int usage); +# endif __owur int SSL_use_certificate(SSL *ssl, X509 *x); __owur int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len); __owur int SSL_use_cert_and_key(SSL *ssl, X509 *x509, EVP_PKEY *privatekey, @@ -1595,6 +1636,11 @@ __owur int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file); __owur int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type); #endif +#ifndef OPENSSL_NO_TLCP +__owur int SSL_use_gm_PrivateKey_file(SSL *ssl, const char *file, int type, int usage); +__owur int SSL_use_gm_certificate_file(SSL *ssl, const char *file, int type, int usage); +#endif + __owur int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type); __owur int SSL_use_certificate_file(SSL *ssl, const char *file, int type); @@ -1602,6 +1648,13 @@ __owur int SSL_use_certificate_file(SSL *ssl, const char *file, int type); __owur int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type); #endif + +#ifndef OPENSSL_NO_TLCP +__owur int SSL_CTX_use_gm_PrivateKey_file(SSL_CTX *ctx, const char *file, + int type, int usage); +__owur int SSL_CTX_use_gm_certificate_file(SSL_CTX *ctx, const char *file, + int type, int usage); +#endif __owur int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type); __owur int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, @@ -1705,6 +1758,18 @@ __owur int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); __owur int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); # endif + +# ifndef OPENSSL_NO_TLCP +__owur int SSL_CTX_use_gm_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey, int usage); +__owur int SSL_CTX_use_gm_PrivateKey_ASN1(int pk, SSL_CTX *ctx, + const unsigned char *d, long len, int usage); +__owur int SSL_CTX_use_gm_certificate(SSL_CTX *ctx, X509 *x, int usage); +__owur int SSL_CTX_use_gm_certificate_ASN1(SSL_CTX *ctx, int len, + const unsigned char *d, int usage); +__owur int SSL_CTX_use_gm_cert_and_key(SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey, + STACK_OF(X509) *chain, int override, int usage); +# endif + __owur int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); __owur int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len); @@ -1883,6 +1948,12 @@ __owur const SSL_METHOD *TLS_method(void); __owur const SSL_METHOD *TLS_server_method(void); __owur const SSL_METHOD *TLS_client_method(void); +#ifndef OPENSSL_NO_TLCP +__owur const SSL_METHOD *TLCP_method(void); +__owur const SSL_METHOD *TLCP_server_method(void); +__owur const SSL_METHOD *TLCP_client_method(void); +#endif + # ifndef OPENSSL_NO_TLS1_METHOD DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_method(void)) /* TLSv1.0 */ DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_server_method(void)) diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index 701d61c6e9..aa5f56a482 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -11,9 +11,7 @@ #ifndef HEADER_SSLERR_H # define HEADER_SSLERR_H -# ifndef HEADER_SYMHACKS_H -# include -# endif +# include # ifdef __cplusplus extern "C" @@ -171,6 +169,10 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_CTX_USE_CERTIFICATE 171 # define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1 172 # define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE 173 +# define SSL_F_SSL_CTX_USE_GM_CERTIFICATE 641 +# define SSL_F_SSL_CTX_USE_GM_CERTIFICATE_ASN1 642 +# define SSL_F_SSL_CTX_USE_GM_PRIVATEKEY 643 +# define SSL_F_SSL_CTX_USE_GM_PRIVATEKEY_ASN1 644 # define SSL_F_SSL_CTX_USE_PRIVATEKEY 174 # define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1 175 # define SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE 176 @@ -197,7 +199,9 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_HANDSHAKE_HASH 560 # define SSL_F_SSL_INIT_WBIO_BUFFER 184 # define SSL_F_SSL_KEY_UPDATE 515 +# define SSL_F_SSL_LOAD_CERT_FILE 645 # define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185 +# define SSL_F_SSL_LOAD_PKEY_FILE 646 # define SSL_F_SSL_LOG_MASTER_SECRET 498 # define SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE 499 # define SSL_F_SSL_MODULE_INIT 392 @@ -231,11 +235,14 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_SET_CIPHER_LIST 271 # define SSL_F_SSL_SET_CT_VALIDATION_CALLBACK 399 # define SSL_F_SSL_SET_FD 192 +# define SSL_F_SSL_SET_GM_CERT_AND_KEY 647 # define SSL_F_SSL_SET_PKEY 193 # define SSL_F_SSL_SET_RFD 194 # define SSL_F_SSL_SET_SESSION 195 # define SSL_F_SSL_SET_SESSION_ID_CONTEXT 218 # define SSL_F_SSL_SET_SESSION_TICKET_EXT 294 +# define SSL_F_SSL_SET_SIGN_ENC_CERT 648 +# define SSL_F_SSL_SET_SIGN_ENC_PKEY 649 # define SSL_F_SSL_SET_TLSEXT_MAX_FRAGMENT_LENGTH 550 # define SSL_F_SSL_SET_WFD 196 # define SSL_F_SSL_SHUTDOWN 224 @@ -246,6 +253,10 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_USE_CERTIFICATE 198 # define SSL_F_SSL_USE_CERTIFICATE_ASN1 199 # define SSL_F_SSL_USE_CERTIFICATE_FILE 200 +# define SSL_F_SSL_USE_GM_CERTIFICATE 650 +# define SSL_F_SSL_USE_GM_CERTIFICATE_ASN1 651 +# define SSL_F_SSL_USE_GM_PRIVATEKEY 652 +# define SSL_F_SSL_USE_GM_PRIVATEKEY_ASN1 653 # define SSL_F_SSL_USE_PRIVATEKEY 201 # define SSL_F_SSL_USE_PRIVATEKEY_ASN1 202 # define SSL_F_SSL_USE_PRIVATEKEY_FILE 203 @@ -262,6 +273,20 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_WRITE_EX 433 # define SSL_F_SSL_WRITE_INTERNAL 524 # define SSL_F_STATE_MACHINE 353 +# define SSL_F_TLCP_CHOOSE_SIGALG 662 +# define SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE 663 +# define SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC 658 +# define SSL_F_TLCP_CONSTRUCT_CLIENT_KEY_EXCHANGE 654 +# define SSL_F_TLCP_CONSTRUCT_SERVER_KEY_EXCHANGE 655 +# define SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE 664 +# define SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC 659 +# define SSL_F_TLCP_DERIVE 665 +# define SSL_F_TLCP_PROCESS_CKE_SM2DHE 666 +# define SSL_F_TLCP_PROCESS_CKE_SM2ECC 660 +# define SSL_F_TLCP_PROCESS_CLIENT_KEY_EXCHANGE 656 +# define SSL_F_TLCP_PROCESS_KEY_EXCHANGE 657 +# define SSL_F_TLCP_PROCESS_SKE_SM2DHE 667 +# define SSL_F_TLCP_PROCESS_SKE_SM2ECC 661 # define SSL_F_TLS12_CHECK_PEER_SIGALG 333 # define SSL_F_TLS12_COPY_SIGALGS 533 # define SSL_F_TLS13_CHANGE_CIPHER_STATE 440 diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index 76d9fda46e..f05382a692 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -24,6 +24,7 @@ extern "C" { # define OPENSSL_TLS_SECURITY_LEVEL 1 # endif +# define TLCP_VERSION 0x0101 # define TLS1_VERSION 0x0301 # define TLS1_1_VERSION 0x0302 # define TLS1_2_VERSION 0x0303 @@ -33,6 +34,9 @@ extern "C" { /* Special value for method supporting multiple versions */ # define TLS_ANY_VERSION 0x10000 +# define TLCP_VERSION_MAJOR 0x01 +# define TLCP_VERSION_MINOR 0x01 + # define TLS1_VERSION_MAJOR 0x03 # define TLS1_VERSION_MINOR 0x01 @@ -73,6 +77,14 @@ extern "C" { # define TLS1_AD_UNKNOWN_PSK_IDENTITY 115/* fatal */ # define TLS1_AD_NO_APPLICATION_PROTOCOL 120 /* fatal */ +/* TLCP(GB/T 38636-2020) alerts */ +# define TLCP_AD_UNSUPPORTED_SITE2SITE 200 /* fatal */ +# define TLCP_AD_NO_AREA 201 +# define TLCP_AD_UNSUPPORTED_AREATYPE 202 +# define TLCP_AD_BAD_IBCPARAM 203 /* fatal */ +# define TLCP_AD_UNSUPPORTED_IBCPARAM 204 /* fatal */ +# define TLCP_AD_IDENTITY_NEED 205 /* fatal */ + /* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */ # define TLSEXT_TYPE_server_name 0 # define TLSEXT_TYPE_max_fragment_length 1 @@ -641,6 +653,10 @@ __owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain) # define TLS1_CK_RSA_PSK_WITH_ARIA_128_GCM_SHA256 0x0300C06E # define TLS1_CK_RSA_PSK_WITH_ARIA_256_GCM_SHA384 0x0300C06F +/* some TLCP ciphersuites from GB/T 38636-2020 */ +# define TLCP_CK_ECDHE_SM2_WITH_SM4_CBC_SM3 0x0300E011 +# define TLCP_CK_ECC_SM2_WITH_SM4_CBC_SM3 0x0300E013 + /* a bundle of RFC standard cipher names, generated from ssl3_ciphers[] */ # define TLS1_RFC_RSA_WITH_AES_128_SHA "TLS_RSA_WITH_AES_128_CBC_SHA" # define TLS1_RFC_DHE_DSS_WITH_AES_128_SHA "TLS_DHE_DSS_WITH_AES_128_CBC_SHA" @@ -1127,6 +1143,10 @@ __owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain) # define TLS1_TXT_RSA_PSK_WITH_ARIA_128_GCM_SHA256 "RSA-PSK-ARIA128-GCM-SHA256" # define TLS1_TXT_RSA_PSK_WITH_ARIA_256_GCM_SHA384 "RSA-PSK-ARIA256-GCM-SHA384" +/* some TLCP ciphersuites from GB/T 38636-2020 */ +# define TLCP_TXT_ECDHE_SM2_WITH_SM4_CBC_SM3 "ECDHE-SM4-CBC-SM3" +# define TLCP_TXT_ECC_SM2_WITH_SM4_CBC_SM3 "ECC-SM4-CBC-SM3" + # define TLS_CT_RSA_SIGN 1 # define TLS_CT_DSS_SIGN 2 # define TLS_CT_RSA_FIXED_DH 3 diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 3ff86ec7b5..f6e82f181a 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -55,6 +55,10 @@ extern "C" { # define X509v3_KU_ENCIPHER_ONLY 0x0001 # define X509v3_KU_DECIPHER_ONLY 0x8000 # define X509v3_KU_UNDEF 0xffff +/* For TLCP sm2 certificates */ +# define X509v3_KU_SM2_SIGN (X509v3_KU_DIGITAL_SIGNATURE | X509v3_KU_NON_REPUDIATION) +# define X509v3_KU_SM2_ENC_ENCIPHERMENT (X509v3_KU_KEY_ENCIPHERMENT | X509v3_KU_DATA_ENCIPHERMENT) +# define X509v3_KU_SM2_ENC_CIPHER_ONLY (X509v3_KU_ENCIPHER_ONLY | X509v3_KU_DECIPHER_ONLY) struct X509_algor_st { ASN1_OBJECT *algorithm; @@ -573,6 +577,13 @@ void X509_get0_signature(const ASN1_BIT_STRING **psig, const X509_ALGOR **palg, const X509 *x); int X509_get_signature_nid(const X509 *x); +# 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); int X509_alias_set1(X509 *x, const unsigned char *name, int len); int X509_keyid_set1(X509 *x, const unsigned char *id, int len); diff --git a/include/openssl/x509err.h b/include/openssl/x509err.h index cd08673f8f..1e51e047d6 100644 --- a/include/openssl/x509err.h +++ b/include/openssl/x509err.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -26,6 +26,7 @@ int ERR_load_X509_strings(void); # 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 @@ -70,6 +71,8 @@ int ERR_load_X509_strings(void); # 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 @@ -81,8 +84,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 166 # 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. diff --git a/ssl/methods.c b/ssl/methods.c index c5e8898364..2a6cd73ca0 100644 --- a/ssl/methods.c +++ b/ssl/methods.c @@ -109,6 +109,25 @@ IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1, IMPLEMENT_ssl3_meth_func(sslv3_client_method, ssl_undefined_function, ossl_statem_connect) #endif +/*- + * TLCP methods + */ +#ifndef OPENSSL_NO_TLCP +IMPLEMENT_tls_meth_func(TLCP_VERSION, 0, SSL_OP_NO_TLCP, + tlcp_method, + ossl_statem_accept, + ossl_statem_connect, TLCP_enc_data) + +IMPLEMENT_tls_meth_func(TLCP_VERSION, 0, SSL_OP_NO_TLCP, + tlcp_server_method, + ossl_statem_accept, + ssl_undefined_function, TLCP_enc_data) + +IMPLEMENT_tls_meth_func(TLCP_VERSION, 0, SSL_OP_NO_TLCP, + tlcp_client_method, + ssl_undefined_function, + ossl_statem_connect, TLCP_enc_data) +#endif /*- * DTLS methods */ @@ -207,6 +226,23 @@ const SSL_METHOD *TLSv1_1_client_method(void) } # endif +# ifndef OPENSSL_NO_TLCP +const SSL_METHOD *TLCP_method(void) +{ + return tlcp_method(); +} + +const SSL_METHOD *TLCP_server_method(void) +{ + return tlcp_server_method(); +} + +const SSL_METHOD *TLCP_client_method(void) +{ + return tlcp_client_method(); +} +# endif + # ifndef OPENSSL_NO_TLS1_METHOD const SSL_METHOD *TLSv1_method(void) { diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c index 47c7369ed5..9eb3f90142 100644 --- a/ssl/record/ssl3_record.c +++ b/ssl/record/ssl3_record.c @@ -309,7 +309,11 @@ int ssl3_get_record(SSL *s) return -1; } +#ifndef OPENSSL_NO_TLCP + if ((version >> 8) != SSL3_VERSION_MAJOR && (version != TLCP_VERSION)) { +#else if ((version >> 8) != SSL3_VERSION_MAJOR) { +#endif if (RECORD_LAYER_is_first_record(&s->rlayer)) { /* Go back to start of packet, look at the five bytes * that we have. */ diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 32f9b25710..34cc0c1ad0 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -15,6 +15,8 @@ #include "ssl_local.h" #include #include +#include "include/crypto/sm2.h" +#include #include #include "internal/cryptlib.h" @@ -2667,6 +2669,43 @@ static SSL_CIPHER ssl3_ciphers[] = { }, #endif /* OPENSSL_NO_GOST */ +#ifndef OPENSSL_NO_TLCP + { + 1, + TLCP_TXT_ECDHE_SM2_WITH_SM4_CBC_SM3, + NULL, + TLCP_CK_ECDHE_SM2_WITH_SM4_CBC_SM3, + SSL_kSM2DHE, + SSL_aSM2, + SSL_SM4CBC, + SSL_SM3, + TLCP_VERSION, + TLS1_2_VERSION, + 0, 0, + SSL_HIGH, + SSL_HANDSHAKE_MAC_SM3 | TLS1_PRF_SM3, + 128, + 128, + }, + { + 1, + TLCP_TXT_ECC_SM2_WITH_SM4_CBC_SM3, + NULL, + TLCP_CK_ECC_SM2_WITH_SM4_CBC_SM3, + SSL_kSM2ECC, + SSL_aSM2, + SSL_SM4CBC, + SSL_SM3, + TLCP_VERSION, + TLS1_2_VERSION, + 0, 0, + SSL_HIGH, + SSL_HANDSHAKE_MAC_SM3 | TLS1_PRF_SM3, + 128, + 128, + }, +#endif /* OPENSSL_NO_TLCP */ + #ifndef OPENSSL_NO_IDEA { 1, @@ -4325,6 +4364,20 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, ret = tmp; continue; } +#ifndef OPENSSL_NO_TLCP + /* Prefer ECC-SM4-CBC-SM3 while enabling TLCP */ + if (!(s->options & SSL_OP_NO_TLCP)) { + const SSL_CIPHER *tmp = sk_SSL_CIPHER_value(allow, ii); + + if (tmp->id == TLCP_CK_ECC_SM2_WITH_SM4_CBC_SM3) { + ret = tmp; + break; + } + if (ret == NULL) + ret = tmp; + continue; + } +#endif ret = sk_SSL_CIPHER_value(allow, ii); break; } @@ -4868,3 +4921,76 @@ EVP_PKEY *ssl_dh_to_pkey(DH *dh) return ret; } #endif + +#ifndef OPENSSL_NO_TLCP +int tlcp_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey) +{ + unsigned char *pms; + int pmslen = SSL_MAX_MASTER_KEY_LENGTH; + EC_KEY *tmp_peer_pub_key, *tmp_self_priv_key; + EC_KEY *self_priv_key, *peer_pub_key; + X509 *peer_enc_cert; + int ret; + + if ((tmp_self_priv_key = EVP_PKEY_get0_EC_KEY(privkey)) == NULL + || (tmp_peer_pub_key = EVP_PKEY_get0_EC_KEY(pubkey)) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + if (s->cert->pkeys[SSL_PKEY_SM2_ENC].privatekey == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + if ((self_priv_key = EVP_PKEY_get0_EC_KEY(s->cert->pkeys[SSL_PKEY_SM2_ENC].privatekey)) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE, + ERR_R_EC_LIB); + return 0; + } + + peer_enc_cert = ssl_get_sm2_enc_cert(s, s->session->peer_chain); + if (peer_enc_cert == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + if ((peer_pub_key = EVP_PKEY_get0_EC_KEY(X509_get0_pubkey(peer_enc_cert))) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + pms = OPENSSL_malloc(pmslen); + if (pms == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE, + ERR_R_MALLOC_FAILURE); + return 0; + } + + if (SM2_compute_key(pms, pmslen, s->server, + SM2_DEFAULT_USERID, SM2_DEFAULT_USERID_LEN, + SM2_DEFAULT_USERID, SM2_DEFAULT_USERID_LEN, + tmp_peer_pub_key, tmp_self_priv_key, + peer_pub_key, self_priv_key, + EVP_sm3()) != pmslen) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE, + ERR_R_INTERNAL_ERROR); + OPENSSL_free(pms); + return 0; + } + + if (s->server) { + ret = ssl_generate_master_secret(s, pms, (size_t)pmslen, 1); + } else { + s->s3->tmp.pms = pms; + s->s3->tmp.pmslen = pmslen; + ret = 1; + } + + return ret; +} +#endif diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c index 9264364100..beb3c3bac0 100644 --- a/ssl/ssl_asn1.c +++ b/ssl/ssl_asn1.c @@ -265,7 +265,8 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, if ((as->ssl_version >> 8) != SSL3_VERSION_MAJOR && (as->ssl_version >> 8) != DTLS1_VERSION_MAJOR - && as->ssl_version != DTLS1_BAD_VER) { + && as->ssl_version != DTLS1_BAD_VER + && as->ssl_version != TLCP_VERSION) { SSLerr(SSL_F_D2I_SSL_SESSION, SSL_R_UNSUPPORTED_SSL_VERSION); goto err; } diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index b615e7048d..e52d959df3 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -944,18 +944,31 @@ static int ssl_security_default_callback(const SSL *s, const SSL_CTX *ctx, /* Level 3: forward secure ciphersuites only */ pfs_mask = SSL_kDHE | SSL_kECDHE | SSL_kDHEPSK | SSL_kECDHEPSK; if (level >= 3 && c->min_tls != TLS1_3_VERSION && - !(c->algorithm_mkey & pfs_mask)) +#ifndef OPENSSL_NO_TLCP + !(c->algorithm_mkey & (pfs_mask | SSL_kSM2DHE))) +#else + !(c->algorithm_mkey & pfs_mask)) +#endif return 0; break; } case SSL_SECOP_VERSION: if (!SSL_IS_DTLS(s)) { +#ifndef OPENSSL_NO_TLCP + /* SSLv3 not allowed at level 2 */ + if (nid <= SSL3_VERSION && nid != TLCP_VERSION && level >= 2) + return 0; + /* TLS v1.1 and above only for level 3 */ + if (nid <= TLS1_VERSION && nid != TLCP_VERSION && level >= 3) + return 0; +#else /* SSLv3 not allowed at level 2 */ if (nid <= SSL3_VERSION && level >= 2) return 0; /* TLS v1.1 and above only for level 3 */ if (nid <= TLS1_VERSION && level >= 3) return 0; +#endif /* TLS v1.2 only for level 4 and above */ if (nid <= TLS1_1_VERSION && level >= 4) return 0; @@ -1010,6 +1023,11 @@ const SSL_CERT_LOOKUP *ssl_cert_lookup_by_pkey(const EVP_PKEY *pk, size_t *pidx) { int nid = EVP_PKEY_id(pk); size_t tmpidx; +#ifndef OPENSSL_NO_TLCP + if (EVP_PKEY_is_sm2((EVP_PKEY *)pk)) { + nid = NID_sm2; + } +#endif if (nid == NID_undef) return NULL; diff --git a/ssl/ssl_cert_table.h b/ssl/ssl_cert_table.h index 0c47241c02..1e1864f596 100644 --- a/ssl/ssl_cert_table.h +++ b/ssl/ssl_cert_table.h @@ -19,5 +19,9 @@ static const SSL_CERT_LOOKUP ssl_cert_info [] = { {NID_id_GostR3410_2012_256, SSL_aGOST12}, /* SSL_PKEY_GOST12_256 */ {NID_id_GostR3410_2012_512, SSL_aGOST12}, /* SSL_PKEY_GOST12_512 */ {EVP_PKEY_ED25519, SSL_aECDSA}, /* SSL_PKEY_ED25519 */ - {EVP_PKEY_ED448, SSL_aECDSA} /* SSL_PKEY_ED448 */ + {EVP_PKEY_ED448, SSL_aECDSA}, /* SSL_PKEY_ED448 */ +#ifndef OPENSSL_NO_TLCP + {EVP_PKEY_SM2, SSL_aSM2}, /* SSL_PKEY_SM2_SIGN */ + {EVP_PKEY_SM2, SSL_aSM2} /* SSL_PKEY_SM2_ENC */ +#endif }; diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index a3ca5294be..fe1a48e8d1 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -43,7 +43,12 @@ #define SSL_ENC_CHACHA_IDX 19 #define SSL_ENC_ARIA128GCM_IDX 20 #define SSL_ENC_ARIA256GCM_IDX 21 +#ifndef OPENSSL_NO_TLCP +#define SSL_ENC_SM4CBC_IDX 22 +#define SSL_ENC_NUM_IDX 23 +#else #define SSL_ENC_NUM_IDX 22 +#endif /* NB: make sure indices in these tables match values above */ @@ -76,6 +81,9 @@ static const ssl_cipher_table ssl_cipher_table_cipher[SSL_ENC_NUM_IDX] = { {SSL_CHACHA20POLY1305, NID_chacha20_poly1305}, /* SSL_ENC_CHACHA_IDX 19 */ {SSL_ARIA128GCM, NID_aria_128_gcm}, /* SSL_ENC_ARIA128GCM_IDX 20 */ {SSL_ARIA256GCM, NID_aria_256_gcm}, /* SSL_ENC_ARIA256GCM_IDX 21 */ +#ifndef OPENSSL_NO_TLCP + {SSL_SM4CBC, NID_sm4_cbc}, /* SSL_ENC_SM4CBC_IDX 22*/ +#endif }; static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX]; @@ -110,11 +118,17 @@ static const ssl_cipher_table ssl_cipher_table_mac[SSL_MD_NUM_IDX] = { {SSL_GOST12_512, NID_id_GostR3411_2012_512}, /* SSL_MD_GOST12_512_IDX 8 */ {0, NID_md5_sha1}, /* SSL_MD_MD5_SHA1_IDX 9 */ {0, NID_sha224}, /* SSL_MD_SHA224_IDX 10 */ - {0, NID_sha512} /* SSL_MD_SHA512_IDX 11 */ + {0, NID_sha512}, /* SSL_MD_SHA512_IDX 11 */ +#ifndef OPENSSL_NO_TLCP + {SSL_SM3, NID_sm3} /* SSL_MD_SM3_IDX 12 */ +#endif }; static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#ifndef OPENSSL_NO_TLCP + NULL +#endif }; /* *INDENT-OFF* */ @@ -172,7 +186,10 @@ static int ssl_mac_pkey_id[SSL_MD_NUM_IDX] = { /* GOST2012_512 */ EVP_PKEY_HMAC, /* MD5/SHA1, SHA224, SHA512 */ - NID_undef, NID_undef, NID_undef + NID_undef, NID_undef, NID_undef, +#ifndef OPENSSL_NO_TLCP + EVP_PKEY_HMAC +#endif }; static size_t ssl_mac_secret_size[SSL_MD_NUM_IDX]; @@ -1688,6 +1705,14 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len) case SSL_kANY: kx = "any"; break; +#ifndef OPENSSL_NO_TLCP + case SSL_kSM2ECC: + kx = "SM2ECC"; + break; + case SSL_kSM2DHE: + kx = "SM2DHE"; + break; +#endif default: kx = "unknown"; } @@ -1721,6 +1746,11 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len) case SSL_aANY: au = "any"; break; +#ifndef OPENSSL_NO_TLCP + case SSL_aSM2: + au = "SM2"; + break; +#endif default: au = "unknown"; break; @@ -1791,6 +1821,11 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len) case SSL_CHACHA20POLY1305: enc = "CHACHA20/POLY1305(256)"; break; +#ifndef OPENSSL_NO_TLCP + case SSL_SM4CBC: + enc = "SM4CBC"; + break; +#endif default: enc = "unknown"; break; @@ -1823,6 +1858,11 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len) case SSL_GOST12_512: mac = "GOST2012"; break; +#ifndef OPENSSL_NO_TLCP + case SSL_SM3: + mac = "SM3"; + break; +#endif default: mac = "unknown"; break; diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 324f2ccbb0..5a7c42a88c 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -113,6 +113,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { "ossl_statem_server_post_process_message"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_POST_WORK, 0), "ossl_statem_server_post_work"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_PRE_WORK, 0), + "ossl_statem_server_pre_work"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_PROCESS_MESSAGE, 0), "ossl_statem_server_process_message"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION, 0), @@ -244,6 +246,14 @@ static const ERR_STRING_DATA SSL_str_functs[] = { "SSL_CTX_use_certificate_ASN1"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, 0), "SSL_CTX_use_certificate_file"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_GM_CERTIFICATE, 0), + "SSL_CTX_use_gm_certificate"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_GM_CERTIFICATE_ASN1, 0), + "SSL_CTX_use_gm_certificate_ASN1"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_GM_PRIVATEKEY, 0), + "SSL_CTX_use_gm_PrivateKey"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_GM_PRIVATEKEY_ASN1, 0), + "SSL_CTX_use_gm_PrivateKey_ASN1"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_PRIVATEKEY, 0), "SSL_CTX_use_PrivateKey"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1, 0), @@ -285,8 +295,10 @@ static const ERR_STRING_DATA SSL_str_functs[] = { {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_INIT_WBIO_BUFFER, 0), "ssl_init_wbio_buffer"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_KEY_UPDATE, 0), "SSL_key_update"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOAD_CERT_FILE, 0), "ssl_load_cert_file"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOAD_CLIENT_CA_FILE, 0), "SSL_load_client_CA_file"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOAD_PKEY_FILE, 0), "ssl_load_pkey_file"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOG_MASTER_SECRET, 0), ""}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE, 0), "ssl_log_rsa_client_key_exchange"}, @@ -331,6 +343,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_CT_VALIDATION_CALLBACK, 0), "SSL_set_ct_validation_callback"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_FD, 0), "SSL_set_fd"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_GM_CERT_AND_KEY, 0), + "ssl_set_gm_cert_and_key"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_PKEY, 0), "ssl_set_pkey"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_RFD, 0), "SSL_set_rfd"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SESSION, 0), "SSL_set_session"}, @@ -338,6 +352,10 @@ static const ERR_STRING_DATA SSL_str_functs[] = { "SSL_set_session_id_context"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SESSION_TICKET_EXT, 0), "SSL_set_session_ticket_ext"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SIGN_ENC_CERT, 0), + "ssl_set_sign_enc_cert"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SIGN_ENC_PKEY, 0), + "ssl_set_sign_enc_pkey"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_TLSEXT_MAX_FRAGMENT_LENGTH, 0), "SSL_set_tlsext_max_fragment_length"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_WFD, 0), "SSL_set_wfd"}, @@ -355,6 +373,14 @@ static const ERR_STRING_DATA SSL_str_functs[] = { "SSL_use_certificate_ASN1"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_CERTIFICATE_FILE, 0), "SSL_use_certificate_file"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_GM_CERTIFICATE, 0), + "SSL_use_gm_certificate"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_GM_CERTIFICATE_ASN1, 0), + "SSL_use_gm_certificate_ASN1"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_GM_PRIVATEKEY, 0), + "SSL_use_gm_PrivateKey"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_GM_PRIVATEKEY_ASN1, 0), + "SSL_use_gm_PrivateKey_ASN1"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_PRIVATEKEY, 0), "SSL_use_PrivateKey"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_PRIVATEKEY_ASN1, 0), "SSL_use_PrivateKey_ASN1"}, @@ -380,6 +406,32 @@ static const ERR_STRING_DATA SSL_str_functs[] = { {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_EX, 0), "SSL_write_ex"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_INTERNAL, 0), "ssl_write_internal"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_STATE_MACHINE, 0), "state_machine"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CHOOSE_SIGALG, 0), "tlcp_choose_sigalg"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, 0), + "tlcp_construct_cke_sm2dhe"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC, 0), + "tlcp_construct_cke_sm2ecc"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_CLIENT_KEY_EXCHANGE, 0), + "tlcp_construct_client_key_exchange"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_SERVER_KEY_EXCHANGE, 0), + "tlcp_construct_server_key_exchange"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, 0), + "tlcp_construct_ske_sm2dhe"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC, 0), + "tlcp_construct_ske_sm2ecc"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_DERIVE, 0), "tlcp_derive"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_CKE_SM2DHE, 0), + "tlcp_process_cke_sm2dhe"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_CKE_SM2ECC, 0), + "tlcp_process_cke_sm2ecc"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_CLIENT_KEY_EXCHANGE, 0), + "tlcp_process_client_key_exchange"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_KEY_EXCHANGE, 0), + "tlcp_process_key_exchange"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_SKE_SM2DHE, 0), + "tlcp_process_ske_sm2dhe"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_SKE_SM2ECC, 0), + "tlcp_process_ske_sm2ecc"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS12_CHECK_PEER_SIGALG, 0), "tls12_check_peer_sigalg"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS12_COPY_SIGALGS, 0), "tls12_copy_sigalgs"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 47adc3211c..618549a2ca 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -560,8 +560,14 @@ static int ssl_check_allowed_versions(int min_version, int max_version) #ifdef OPENSSL_NO_TLS1_3 || (min_version <= TLS1_3_VERSION && TLS1_3_VERSION <= max_version) #endif - ) + ) { +#ifndef OPENSSL_NO_TLCP + if (min_version == TLCP_VERSION || max_version == TLCP_VERSION) { + return 1; + } +#endif return 0; + } } return 1; } @@ -3371,6 +3377,9 @@ void ssl_set_masks(SSL *s) unsigned long mask_k, mask_a; #ifndef OPENSSL_NO_EC int have_ecc_cert, ecdsa_ok; +#endif +#ifndef OPENSSL_NO_TLCP + int tlcp_sm2_sign, tlcp_sm2_enc; #endif if (c == NULL) return; @@ -3386,14 +3395,23 @@ void ssl_set_masks(SSL *s) dsa_sign = pvalid[SSL_PKEY_DSA_SIGN] & CERT_PKEY_VALID; #ifndef OPENSSL_NO_EC have_ecc_cert = pvalid[SSL_PKEY_ECC] & CERT_PKEY_VALID; +#endif +#ifndef OPENSSL_NO_TLCP + tlcp_sm2_sign = ssl_has_cert(s, SSL_PKEY_SM2_SIGN); + tlcp_sm2_enc = ssl_has_cert(s, SSL_PKEY_SM2_ENC); #endif mask_k = 0; mask_a = 0; #ifdef CIPHER_DEBUG +#ifndef OPENSSL_NO_TLCP + fprintf(stderr, "dht=%d re=%d rs=%d ds=%d tss=%d tse=%d\n", + dh_tmp, rsa_enc, rsa_sign, dsa_sign, tlcp_sm2_sign, tlcp_sm2_enc); +#else fprintf(stderr, "dht=%d re=%d rs=%d ds=%d\n", dh_tmp, rsa_enc, rsa_sign, dsa_sign); #endif +#endif #ifndef OPENSSL_NO_GOST if (ssl_has_cert(s, SSL_PKEY_GOST12_512)) { @@ -3463,6 +3481,14 @@ void ssl_set_masks(SSL *s) mask_k |= SSL_kECDHE; #endif +#ifndef OPENSSL_NO_TLCP + if (tlcp_sm2_sign) + mask_a |= SSL_aSM2; + + if (tlcp_sm2_enc) + mask_k |= SSL_kSM2ECC | SSL_kSM2DHE; +#endif + #ifndef OPENSSL_NO_PSK mask_k |= SSL_kPSK; mask_a |= SSL_aPSK; @@ -3793,6 +3819,11 @@ const char *ssl_protocol_to_string(int version) case TLS1_VERSION: return "TLSv1"; +#ifndef OPENSSL_NO_TLCP + case TLCP_VERSION: + return "TLCP"; +#endif + case SSL3_VERSION: return "SSLv3"; @@ -5707,3 +5738,51 @@ void SSL_set_allow_early_data_cb(SSL *s, s->allow_early_data_cb = cb; s->allow_early_data_cb_data = arg; } + +#ifndef OPENSSL_NO_TLCP +int ssl_is_sm2_cert(X509 *x) +{ + return x && EVP_PKEY_is_sm2(X509_get0_pubkey(x)); +} + +int ssl_is_sm2_sign_usage(X509 *x) +{ + return x && (X509_get_extension_flags(x) & EXFLAG_KUSAGE) && + (X509_get_key_usage(x) & X509v3_KU_SM2_SIGN); +} + +int ssl_is_sm2_enc_usage(X509 *x) +{ + return x && (X509_get_extension_flags(x) & EXFLAG_KUSAGE) && + ((X509_get_key_usage(x) & X509v3_KU_SM2_ENC_ENCIPHERMENT) || + ((X509_get_key_usage(x) & X509v3_KU_SM2_ENC_CIPHER_ONLY) && + (X509_get_key_usage(x) & X509v3_KU_KEY_AGREEMENT)) + ); +} + +X509 *ssl_get_sm2_enc_cert(SSL *s, STACK_OF(X509) *chain) +{ + X509 *x; + int i; + + for (i = sk_X509_num(chain) - 1; i >= 0 ; --i) { + x = sk_X509_value(chain, i); + if (ssl_is_sm2_cert(x) && ssl_is_sm2_enc_usage(x)) { + return x; + } + } + return NULL; +} + +int ssl_get_sm2_cert_id(X509 *x, size_t *id) +{ + if (ssl_is_sm2_sign_usage(x) && !ssl_is_sm2_enc_usage(x)) { + *id = SSL_PKEY_SM2_SIGN; + return 1; + } else if (!ssl_is_sm2_sign_usage(x) && ssl_is_sm2_enc_usage(x)) { + *id = SSL_PKEY_SM2_ENC; + return 1; + } + return 0; +} +#endif diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 5c79215423..45b2ada727 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -177,6 +177,13 @@ # define SSL_kECDHEPSK 0x00000080U # define SSL_kDHEPSK 0x00000100U +#ifndef OPENSSL_NO_TLCP +/* TLCP ECC*/ +# define SSL_kSM2ECC 0x00000800U +/* TLCP ECDHE */ +# define SSL_kSM2DHE 0x00001000U +#endif + /* all PSK */ # define SSL_PSK (SSL_kPSK | SSL_kRSAPSK | SSL_kECDHEPSK | SSL_kDHEPSK) @@ -203,9 +210,21 @@ # define SSL_aGOST12 0x00000080U /* Any appropriate signature auth (for TLS 1.3 ciphersuites) */ # define SSL_aANY 0x00000000U + +#ifndef OPENSSL_NO_TLCP +/* SM2 auth */ +# define SSL_aSM2 0x00000100U +#endif + +#ifndef OPENSSL_NO_TLCP +/* All bits requiring a certificate */ +#define SSL_aCERT \ + (SSL_aRSA | SSL_aDSS | SSL_aECDSA | SSL_aGOST01 | SSL_aGOST12 | SSL_aSM2) +#else /* All bits requiring a certificate */ #define SSL_aCERT \ (SSL_aRSA | SSL_aDSS | SSL_aECDSA | SSL_aGOST01 | SSL_aGOST12) +#endif /* Bits for algorithm_enc (symmetric encryption) */ # define SSL_DES 0x00000001U @@ -231,6 +250,10 @@ # define SSL_ARIA128GCM 0x00100000U # define SSL_ARIA256GCM 0x00200000U +#ifndef OPENSSL_NO_TLCP +# define SSL_SM4CBC 0x00800000U +#endif + # define SSL_AESGCM (SSL_AES128GCM | SSL_AES256GCM) # define SSL_AESCCM (SSL_AES128CCM | SSL_AES256CCM | SSL_AES128CCM8 | SSL_AES256CCM8) # define SSL_AES (SSL_AES128|SSL_AES256|SSL_AESGCM|SSL_AESCCM) @@ -253,6 +276,10 @@ # define SSL_GOST89MAC12 0x00000100U # define SSL_GOST12_512 0x00000200U +#ifndef OPENSSL_NO_TLCP +# define SSL_SM3 0x00000400U +#endif + /* * When adding new digest in the ssl_ciph.c and increment SSL_MD_NUM_IDX make * sure to update this constant too @@ -270,8 +297,12 @@ # define SSL_MD_MD5_SHA1_IDX 9 # define SSL_MD_SHA224_IDX 10 # define SSL_MD_SHA512_IDX 11 +#ifndef OPENSSL_NO_TLCP +# define SSL_MD_SM3_IDX 12 +# define SSL_MAX_DIGEST 13 +#else # define SSL_MAX_DIGEST 12 - +#endif /* Bits for algorithm2 (handshake digests and other extra flags) */ /* Bits 0-7 are handshake MAC */ @@ -283,6 +314,9 @@ # define SSL_HANDSHAKE_MAC_GOST12_256 SSL_MD_GOST12_256_IDX # define SSL_HANDSHAKE_MAC_GOST12_512 SSL_MD_GOST12_512_IDX # define SSL_HANDSHAKE_MAC_DEFAULT SSL_HANDSHAKE_MAC_MD5_SHA1 +#ifndef OPENSSL_NO_TLCP +# define SSL_HANDSHAKE_MAC_SM3 SSL_MD_SM3_IDX +#endif /* Bits 8-15 bits are PRF */ # define TLS1_PRF_DGST_SHIFT 8 @@ -293,6 +327,9 @@ # define TLS1_PRF_GOST12_256 (SSL_MD_GOST12_256_IDX << TLS1_PRF_DGST_SHIFT) # define TLS1_PRF_GOST12_512 (SSL_MD_GOST12_512_IDX << TLS1_PRF_DGST_SHIFT) # define TLS1_PRF (SSL_MD_MD5_SHA1_IDX << TLS1_PRF_DGST_SHIFT) +#ifndef OPENSSL_NO_TLCP +# define TLS1_PRF_SM3 (SSL_MD_SM3_IDX << TLS1_PRF_DGST_SHIFT) +#endif /* * Stream MAC for GOST ciphersuites from cryptopro draft (currently this also @@ -318,6 +355,8 @@ /* Check if an SSL structure is using DTLS */ # define SSL_IS_DTLS(s) (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) +# define SSL_IS_TLCP(s) (s->version == TLCP_VERSION) + /* Check if we are using TLSv1.3 */ # define SSL_IS_TLS13(s) (!SSL_IS_DTLS(s) \ && (s)->method->version >= TLS1_3_VERSION \ @@ -383,7 +422,13 @@ # define SSL_PKEY_GOST12_512 6 # define SSL_PKEY_ED25519 7 # define SSL_PKEY_ED448 8 +#ifndef OPENSSL_NO_TLCP +# define SSL_PKEY_SM2_SIGN 9 +# define SSL_PKEY_SM2_ENC 10 +# define SSL_PKEY_NUM 11 +#else # define SSL_PKEY_NUM 9 +#endif /*- * SSL_kRSA <- RSA_ENC @@ -2026,6 +2071,9 @@ typedef enum downgrade_en { #define TLSEXT_SIGALG_ecdsa_secp521r1_sha512 0x0603 #define TLSEXT_SIGALG_ecdsa_sha224 0x0303 #define TLSEXT_SIGALG_ecdsa_sha1 0x0203 +#ifndef OPENSSL_NO_TLCP +#define TLSEXT_SIGALG_sm2dsa_sm3 0x0708 +#endif #define TLSEXT_SIGALG_rsa_pss_rsae_sha256 0x0804 #define TLSEXT_SIGALG_rsa_pss_rsae_sha384 0x0805 #define TLSEXT_SIGALG_rsa_pss_rsae_sha512 0x0806 @@ -2095,6 +2143,18 @@ __owur const SSL_METHOD *dtls_bad_ver_client_method(void); __owur const SSL_METHOD *dtlsv1_2_method(void); __owur const SSL_METHOD *dtlsv1_2_server_method(void); __owur const SSL_METHOD *dtlsv1_2_client_method(void); +# ifndef OPENSSL_NO_TLCP +__owur const SSL_METHOD *tlcp_method(void); +__owur const SSL_METHOD *tlcp_server_method(void); +__owur const SSL_METHOD *tlcp_client_method(void); + +/* TLCP helper functions */ +__owur int ssl_is_sm2_cert(X509 *x); +__owur int ssl_is_sm2_sign_usage(X509 *x); +__owur int ssl_is_sm2_enc_usage(X509 *x); +__owur X509 *ssl_get_sm2_enc_cert(SSL *s, STACK_OF(X509) *chain); +__owur int ssl_get_sm2_cert_id(X509 *x, size_t *id); +# endif extern const SSL3_ENC_METHOD TLSv1_enc_data; extern const SSL3_ENC_METHOD TLSv1_1_enc_data; @@ -2103,6 +2163,9 @@ extern const SSL3_ENC_METHOD TLSv1_3_enc_data; extern const SSL3_ENC_METHOD SSLv3_enc_data; extern const SSL3_ENC_METHOD DTLSv1_enc_data; extern const SSL3_ENC_METHOD DTLSv1_2_enc_data; +# ifndef OPENSSL_NO_TLCP +extern const SSL3_ENC_METHOD TLCP_enc_data; +# endif /* * Flags for SSL methods @@ -2331,6 +2394,7 @@ __owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen, __owur EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm); __owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int genmaster); +__owur int tlcp_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey); __owur EVP_PKEY *ssl_dh_to_pkey(DH *dh); __owur unsigned int ssl_get_max_send_fragment(const SSL *ssl); __owur unsigned int ssl_get_split_send_fragment(const SSL *ssl); @@ -2502,6 +2566,9 @@ __owur int tls13_export_keying_material_early(SSL *s, unsigned char *out, __owur int tls1_alert_code(int code); __owur int tls13_alert_code(int code); __owur int ssl3_alert_code(int code); +# ifndef OPENSSL_NO_TLCP +__owur int tlcp_alert_code(int code); +# endif # ifndef OPENSSL_NO_EC __owur int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s); diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index 2df07bea67..5797a4c764 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -19,6 +19,15 @@ static int ssl_set_cert(CERT *c, X509 *x509); static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey); +#ifndef OPENSSL_NO_TLCP +#include + +static int ssl_set_sign_enc_pkey(CERT *c, EVP_PKEY *pkey, size_t id); +static int ssl_set_sign_enc_cert(CERT *c, X509 *x, size_t id); +static int ssl_load_pkey_file(SSL *ssl, SSL_CTX *ctx, const char *file, int type, EVP_PKEY **pkey); +static int ssl_load_cert_file(SSL *ssl, SSL_CTX *ctx, const char *file, int type, X509 **x); +#endif + #define SYNTHV1CONTEXT (SSL_EXT_TLS1_2_AND_BELOW_ONLY \ | SSL_EXT_CLIENT_HELLO \ | SSL_EXT_TLS1_2_SERVER_HELLO \ @@ -97,6 +106,99 @@ int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len) return ret; } +#ifndef OPENSSL_NO_TLCP +static int ssl_load_cert_file(SSL *ssl, SSL_CTX *ctx, const char *file, int type, X509 **x) +{ + int j; + BIO *in; + int ret = 0; + *x = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL) { + SSLerr(SSL_F_SSL_LOAD_CERT_FILE, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + SSLerr(SSL_F_SSL_LOAD_CERT_FILE, ERR_R_SYS_LIB); + goto end; + } + if (type == SSL_FILETYPE_ASN1) { + j = ERR_R_ASN1_LIB; + *x = d2i_X509_bio(in, NULL); + } else if (type == SSL_FILETYPE_PEM) { + j = ERR_R_PEM_LIB; + pem_password_cb *cb = (ssl != NULL) ? ssl->default_passwd_callback : + ctx->default_passwd_callback; + void *userdata = (ssl != NULL) ? ssl->default_passwd_callback_userdata : + ctx->default_passwd_callback_userdata; + *x = PEM_read_bio_X509(in, NULL, cb, userdata); + } else { + SSLerr(SSL_F_SSL_LOAD_CERT_FILE, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + + if (*x == NULL) { + SSLerr(SSL_F_SSL_LOAD_CERT_FILE, j); + goto end; + } + ret = 1; +end: + BIO_free(in); + return ret; +} + +int SSL_use_gm_certificate(SSL *ssl, X509 *x, int usage) +{ + int rv; + if (x == NULL) { + SSLerr(SSL_F_SSL_USE_GM_CERTIFICATE, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + rv = ssl_security_cert(ssl, NULL, x, 0, 1); + if (rv != 1) { + SSLerr(SSL_F_SSL_USE_GM_CERTIFICATE, rv); + return 0; + } + if (usage == SSL_USAGE_SIG) { + return ssl_set_sign_enc_cert(ssl->cert, x, SSL_PKEY_SM2_SIGN); + } else if (usage == SSL_USAGE_ENC) { + return ssl_set_sign_enc_cert(ssl->cert, x, SSL_PKEY_SM2_ENC); + } + SSLerr(SSL_F_SSL_USE_GM_CERTIFICATE, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; +} + +int SSL_use_gm_certificate_ASN1(SSL *ssl, const unsigned char *d, int len, int usage) +{ + X509 *x; + int ret; + + x = d2i_X509(NULL, &d, (long)len); + if (x == NULL) { + SSLerr(SSL_F_SSL_USE_GM_CERTIFICATE_ASN1, ERR_R_ASN1_LIB); + return 0; + } + + ret = SSL_use_gm_certificate(ssl, x, usage); + X509_free(x); + return ret; +} + +int SSL_use_gm_certificate_file(SSL *ssl, const char *file, int type, int usage) +{ + int ret; + X509 *x = NULL; + ret = ssl_load_cert_file(ssl, NULL, file, type, &x); + if (ret == 1) { + ret = SSL_use_gm_certificate(ssl, x, usage); + } + X509_free(x); + return ret; +} +#endif + #ifndef OPENSSL_NO_RSA int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { @@ -162,6 +264,50 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) return 1; } +#ifndef OPENSSL_NO_TLCP +int ssl_set_sign_enc_pkey(CERT *c, EVP_PKEY *pkey, size_t id) +{ + if (id != SSL_PKEY_SM2_SIGN && id != SSL_PKEY_SM2_ENC) { + SSLerr(SSL_F_SSL_SET_SIGN_ENC_PKEY, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + if (EVP_PKEY_is_sm2(pkey) == 0) { + SSLerr(SSL_F_SSL_SET_SIGN_ENC_PKEY, SSL_R_UNKNOWN_PKEY_TYPE); + return 0; + } + + if (c->pkeys[id].x509 != NULL) { + EVP_PKEY *pktmp; + pktmp = X509_get0_pubkey(c->pkeys[id].x509); + if (pktmp == NULL) { + SSLerr(SSL_F_SSL_SET_SIGN_ENC_PKEY, ERR_R_MALLOC_FAILURE); + return 0; + } + /* + * The return code from EVP_PKEY_copy_parameters is deliberately + * ignored. Some EVP_PKEY types cannot do this. + */ + EVP_PKEY_copy_parameters(pktmp, pkey); + ERR_clear_error(); + + if (!X509_check_private_key(c->pkeys[id].x509, pkey)) { + X509_free(c->pkeys[id].x509); + c->pkeys[id].x509 = NULL; + return 0; + } + } + + EVP_PKEY_free(c->pkeys[id].privatekey); + EVP_PKEY_up_ref(pkey); + c->pkeys[id].privatekey = pkey; + if (id != SSL_PKEY_SM2_ENC) { + c->key = &(c->pkeys[id]); + } + return 1; +} +#endif + #ifndef OPENSSL_NO_RSA int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) { @@ -228,6 +374,17 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER); return 0; } +#ifndef OPENSSL_NO_TLCP + if (EVP_PKEY_is_sm2(pkey)) { + if (X509_check_private_key(ssl->cert->pkeys[SSL_PKEY_SM2_SIGN].x509, pkey)) { + return ssl_set_sign_enc_pkey(ssl->cert, pkey, SSL_PKEY_SM2_SIGN); + } else if (X509_check_private_key(ssl->cert->pkeys[SSL_PKEY_SM2_ENC].x509, pkey)) { + return ssl_set_sign_enc_pkey(ssl->cert, pkey, SSL_PKEY_SM2_ENC); + } + SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } +#endif ret = ssl_set_pkey(ssl->cert, pkey); return ret; } @@ -289,6 +446,94 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, return ret; } +#ifndef OPENSSL_NO_TLCP +static int ssl_load_pkey_file(SSL *ssl, SSL_CTX *ctx, const char *file, int type, EVP_PKEY **pkey) +{ + int j, ret = 0; + BIO *in; + *pkey = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL) { + SSLerr(SSL_F_SSL_LOAD_PKEY_FILE, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + SSLerr(SSL_F_SSL_LOAD_PKEY_FILE, ERR_R_SYS_LIB); + goto end; + } + if (type == SSL_FILETYPE_PEM) { + j = ERR_R_PEM_LIB; + pem_password_cb *cb = (ssl != NULL) ? ssl->default_passwd_callback : + ctx->default_passwd_callback; + void *userdata = (ssl != NULL) ? ssl->default_passwd_callback_userdata : + ctx->default_passwd_callback_userdata; + *pkey = PEM_read_bio_PrivateKey(in, NULL, cb, userdata); + } else if (type == SSL_FILETYPE_ASN1) { + j = ERR_R_ASN1_LIB; + *pkey = d2i_PrivateKey_bio(in, NULL); + } else { + SSLerr(SSL_F_SSL_LOAD_PKEY_FILE, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + if (*pkey == NULL) { + SSLerr(SSL_F_SSL_LOAD_PKEY_FILE, j); + goto end; + } + ret = 1; +end: + BIO_free(in); + return ret; +} + +int SSL_use_gm_PrivateKey(SSL *ssl, EVP_PKEY *pkey, int usage) +{ + if (pkey == NULL) { + SSLerr(SSL_F_SSL_USE_GM_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (usage == SSL_USAGE_SIG) { + return ssl_set_sign_enc_pkey(ssl->cert, pkey, SSL_PKEY_SM2_SIGN); + } else if (usage == SSL_USAGE_ENC) { + return ssl_set_sign_enc_pkey(ssl->cert, pkey, SSL_PKEY_SM2_ENC); + } + SSLerr(SSL_F_SSL_USE_GM_PRIVATEKEY, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; +} + +int SSL_use_gm_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, + long len, int usage) +{ + int ret; + const unsigned char *p; + EVP_PKEY *pkey; + + p = d; + if ((pkey = d2i_PrivateKey(type, NULL, &p, (long)len)) == NULL) { + SSLerr(SSL_F_SSL_USE_GM_PRIVATEKEY_ASN1, ERR_R_ASN1_LIB); + return 0; + } + + ret = SSL_use_gm_PrivateKey(ssl, pkey, usage); + EVP_PKEY_free(pkey); + return ret; +} + +int SSL_use_gm_PrivateKey_file(SSL *ssl, const char *file, int type, int usage) +{ + int ret; + EVP_PKEY *pkey = NULL; + + ret = ssl_load_pkey_file(ssl, NULL, file, type, &pkey); + if (ret == 1) { + ret = SSL_use_gm_PrivateKey(ssl, pkey, usage); + } + EVP_PKEY_free(pkey); + return ret; +} +#endif + int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { int rv; @@ -319,6 +564,12 @@ static int ssl_set_cert(CERT *c, X509 *x) SSLerr(SSL_F_SSL_SET_CERT, SSL_R_UNKNOWN_CERTIFICATE_TYPE); return 0; } +#ifndef OPENSSL_NO_TLCP + if (i == SSL_PKEY_SM2_SIGN && !ssl_get_sm2_cert_id(x, &i)) { + SSLerr(SSL_F_SSL_SET_CERT, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + return 0; + } +#endif #ifndef OPENSSL_NO_EC if (i == SSL_PKEY_ECC && !EC_KEY_can_sign(EVP_PKEY_get0_EC_KEY(pkey))) { SSLerr(SSL_F_SSL_SET_CERT, SSL_R_ECC_CERT_NOT_FOR_SIGNING); @@ -349,7 +600,13 @@ static int ssl_set_cert(CERT *c, X509 *x) X509_free(c->pkeys[i].x509); X509_up_ref(x); c->pkeys[i].x509 = x; +#ifndef OPENSSL_NO_TLCP + if (i != SSL_PKEY_SM2_ENC) { + c->key = &(c->pkeys[i]); + } +#else c->key = &(c->pkeys[i]); +#endif return 1; } @@ -411,6 +668,109 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d) return ret; } +#ifndef OPENSSL_NO_TLCP +static int ssl_set_sign_enc_cert(CERT *c, X509 *x, size_t id) +{ + EVP_PKEY *pkey; + + pkey = X509_get0_pubkey(x); + if (pkey == NULL) { + SSLerr(SSL_F_SSL_SET_SIGN_ENC_CERT, SSL_R_X509_LIB); + return 0; + } + + if (ssl_is_sm2_cert(x) == 0 || + (id == SSL_PKEY_SM2_ENC && !ssl_is_sm2_enc_usage(x)) || + (id == SSL_PKEY_SM2_SIGN && !ssl_is_sm2_sign_usage(x))) { + SSLerr(SSL_F_SSL_SET_SIGN_ENC_CERT, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + return 0; + } + + if (id == SSL_PKEY_SM2_SIGN && !EC_KEY_can_sign(EVP_PKEY_get0_EC_KEY(pkey))) { + SSLerr(SSL_F_SSL_SET_SIGN_ENC_CERT, SSL_R_ECC_CERT_NOT_FOR_SIGNING); + return 0; + } + + if (c->pkeys[id].privatekey != NULL) { + /* + * The return code from EVP_PKEY_copy_parameters is deliberately + * ignored. Some EVP_PKEY types cannot do this. + */ + EVP_PKEY_copy_parameters(pkey, c->pkeys[id].privatekey); + ERR_clear_error(); + + if (!X509_check_private_key(x, c->pkeys[id].privatekey)) { + /* + * don't fail for a cert/key mismatch, just free current private + * key (when switching to a different cert & key, first this + * function should be used, then ssl_set_pkey + */ + EVP_PKEY_free(c->pkeys[id].privatekey); + c->pkeys[id].privatekey = NULL; + /* clear error queue */ + ERR_clear_error(); + } + } + + X509_free(c->pkeys[id].x509); + X509_up_ref(x); + c->pkeys[id].x509 = x; + if (id != SSL_PKEY_SM2_ENC) { + c->key = &(c->pkeys[id]); + } + return 1; +} + +int SSL_CTX_use_gm_certificate(SSL_CTX *ctx, X509 *x, int usage) +{ + int rv; + if (x == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_GM_CERTIFICATE, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + rv = ssl_security_cert(NULL, ctx, x, 0, 1); + if (rv != 1) { + SSLerr(SSL_F_SSL_CTX_USE_GM_CERTIFICATE, rv); + return 0; + } + if (usage == SSL_USAGE_SIG) { + return ssl_set_sign_enc_cert(ctx->cert, x, SSL_PKEY_SM2_SIGN); + } else if (usage == SSL_USAGE_ENC) { + return ssl_set_sign_enc_cert(ctx->cert, x, SSL_PKEY_SM2_ENC); + } + SSLerr(SSL_F_SSL_CTX_USE_GM_CERTIFICATE, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; +} + +int SSL_CTX_use_gm_certificate_file(SSL_CTX *ctx, const char *file, int type, int usage) +{ + int ret; + X509 *x = NULL; + ret = ssl_load_cert_file(NULL, ctx, file, type, &x); + if (ret == 1) { + ret = SSL_CTX_use_gm_certificate(ctx, x, usage); + } + X509_free(x); + return ret; +} + +int SSL_CTX_use_gm_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d, int usage) +{ + X509 *x; + int ret; + + x = d2i_X509(NULL, &d, (long)len); + if (x == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_GM_CERTIFICATE_ASN1, ERR_R_ASN1_LIB); + return 0; + } + + ret = SSL_CTX_use_gm_certificate(ctx, x, usage); + X509_free(x); + return ret; +} +#endif + #ifndef OPENSSL_NO_RSA int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) { @@ -502,6 +862,17 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER); return 0; } +#ifndef OPENSSL_NO_TLCP + if (EVP_PKEY_is_sm2(pkey)) { + if (X509_check_private_key(ctx->cert->pkeys[SSL_PKEY_SM2_SIGN].x509, pkey)) { + return ssl_set_sign_enc_pkey(ctx->cert, pkey, SSL_PKEY_SM2_SIGN); + } else if (X509_check_private_key(ctx->cert->pkeys[SSL_PKEY_SM2_ENC].x509, pkey)) { + return ssl_set_sign_enc_pkey(ctx->cert, pkey, SSL_PKEY_SM2_ENC); + } + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } +#endif return ssl_set_pkey(ctx->cert, pkey); } @@ -562,6 +933,54 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, return ret; } +#ifndef OPENSSL_NO_TLCP +int SSL_CTX_use_gm_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey, int usage) +{ + if (pkey == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_GM_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (usage == SSL_USAGE_SIG) { + return ssl_set_sign_enc_pkey(ctx->cert, pkey, SSL_PKEY_SM2_SIGN); + } else if (usage == SSL_USAGE_ENC) { + return ssl_set_sign_enc_pkey(ctx->cert, pkey, SSL_PKEY_SM2_ENC); + } + SSLerr(SSL_F_SSL_CTX_USE_GM_PRIVATEKEY, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; +} + +int SSL_CTX_use_gm_PrivateKey_file(SSL_CTX *ctx, const char *file, int type, int usage) +{ + int ret; + EVP_PKEY *pkey = NULL; + + ret = ssl_load_pkey_file(NULL, ctx, file, type, &pkey); + if (ret == 1) { + ret = SSL_CTX_use_gm_PrivateKey(ctx, pkey, usage); + } + EVP_PKEY_free(pkey); + return ret; +} + +int SSL_CTX_use_gm_PrivateKey_ASN1(int type, SSL_CTX *ctx, + const unsigned char *d, long len, int usage) +{ + int ret; + const unsigned char *p; + EVP_PKEY *pkey; + + p = d; + if ((pkey = d2i_PrivateKey(type, NULL, &p, (long)len)) == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_GM_PRIVATEKEY_ASN1, ERR_R_ASN1_LIB); + return 0; + } + + ret = SSL_CTX_use_gm_PrivateKey(ctx, pkey, usage); + EVP_PKEY_free(pkey); + return ret; +} +#endif + /* * Read a file that contains our certificate in "PEM" format, possibly * followed by a sequence of CA certificates that should be sent to the peer @@ -1112,6 +1531,12 @@ static int ssl_set_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *pr SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_UNKNOWN_CERTIFICATE_TYPE); goto out; } +#ifndef OPENSSL_NO_TLCP + if (i == SSL_PKEY_SM2_SIGN && !ssl_get_sm2_cert_id(x509, &i)) { + SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + return 0; + } +#endif if (!override && (c->pkeys[i].x509 != NULL || c->pkeys[i].privatekey != NULL @@ -1140,7 +1565,13 @@ static int ssl_set_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *pr EVP_PKEY_up_ref(privatekey); c->pkeys[i].privatekey = privatekey; +#ifndef OPENSSL_NO_TLCP + if (i != SSL_PKEY_SM2_ENC) { + c->key = &(c->pkeys[i]); + } +#else c->key = &(c->pkeys[i]); +#endif ret = 1; out: @@ -1159,3 +1590,114 @@ int SSL_CTX_use_cert_and_key(SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey, { return ssl_set_cert_and_key(NULL, ctx, x509, privatekey, chain, override); } + +#ifndef OPENSSL_NO_TLCP +static int ssl_set_gm_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey, + STACK_OF(X509) *chain, int override, int usage) +{ + int ret = 0; + size_t id; + int j; + int rv; + CERT *c = ssl != NULL ? ssl->cert : ctx->cert; + STACK_OF(X509) *dup_chain = NULL; + EVP_PKEY *pubkey = NULL; + + /* Do all security checks before anything else */ + rv = ssl_security_cert(ssl, ctx, x509, 0, 1); + if (rv != 1) { + SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, rv); + goto out; + } + for (j = 0; j < sk_X509_num(chain); j++) { + rv = ssl_security_cert(ssl, ctx, sk_X509_value(chain, j), 0, 0); + if (rv != 1) { + SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, rv); + goto out; + } + } + + pubkey = X509_get_pubkey(x509); /* bumps reference */ + if (pubkey == NULL) + goto out; + if (privatekey == NULL) { + privatekey = pubkey; + } else { + /* For RSA, which has no parameters, missing returns 0 */ + if (EVP_PKEY_missing_parameters(privatekey)) { + if (EVP_PKEY_missing_parameters(pubkey)) { + /* nobody has parameters? - error */ + SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, SSL_R_MISSING_PARAMETERS); + goto out; + } else { + /* copy to privatekey from pubkey */ + EVP_PKEY_copy_parameters(privatekey, pubkey); + } + } else if (EVP_PKEY_missing_parameters(pubkey)) { + /* copy to pubkey from privatekey */ + EVP_PKEY_copy_parameters(pubkey, privatekey); + } /* else both have parameters */ + + /* check that key <-> cert match */ + if (EVP_PKEY_cmp(pubkey, privatekey) != 1) { + SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, SSL_R_PRIVATE_KEY_MISMATCH); + goto out; + } + } + if (usage == SSL_USAGE_SIG) { + id = SSL_PKEY_SM2_SIGN; + } else if (usage == SSL_USAGE_ENC) { + id = SSL_PKEY_SM2_ENC; + } else { + SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, ERR_R_PASSED_INVALID_ARGUMENT); + goto out; + } + + if (!override && (c->pkeys[id].x509 != NULL + || c->pkeys[id].privatekey != NULL + || c->pkeys[id].chain != NULL)) { + /* No override, and something already there */ + SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, SSL_R_NOT_REPLACING_CERTIFICATE); + goto out; + } + + if (chain != NULL) { + dup_chain = X509_chain_up_ref(chain); + if (dup_chain == NULL) { + SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, ERR_R_MALLOC_FAILURE); + goto out; + } + } + + sk_X509_pop_free(c->pkeys[id].chain, X509_free); + c->pkeys[id].chain = dup_chain; + + X509_free(c->pkeys[id].x509); + X509_up_ref(x509); + c->pkeys[id].x509 = x509; + + EVP_PKEY_free(c->pkeys[id].privatekey); + EVP_PKEY_up_ref(privatekey); + c->pkeys[id].privatekey = privatekey; + if (id != SSL_PKEY_SM2_ENC) { + c->key = &(c->pkeys[id]); + } + ret = 1; + out: + EVP_PKEY_free(pubkey); + return ret; +} + +int SSL_use_gm_cert_and_key(SSL *ssl, X509 *x509, EVP_PKEY *privatekey, + STACK_OF(X509) *chain, int override, int usage) +{ + return ssl_set_gm_cert_and_key(ssl, NULL, x509, privatekey, chain, override, usage); +} + +int SSL_CTX_use_gm_cert_and_key(SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey, + STACK_OF(X509) *chain, int override, int usage) +{ + return ssl_set_gm_cert_and_key(NULL, ctx, x509, privatekey, chain, override, usage); +} +#endif + diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 68d1737ac5..1b4c85b60c 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -286,6 +286,9 @@ int ssl_generate_session_id(SSL *s, SSL_SESSION *ss) GEN_SESSION_CB cb = def_generate_session_id; switch (s->version) { +#ifndef OPENSSL_NO_TLCP + case TLCP_VERSION: +#endif case SSL3_VERSION: case TLS1_VERSION: case TLS1_1_VERSION: diff --git a/ssl/ssl_stat.c b/ssl/ssl_stat.c index ca51c0331c..1750bdb2c5 100644 --- a/ssl/ssl_stat.c +++ b/ssl/ssl_stat.c @@ -312,6 +312,20 @@ const char *SSL_alert_desc_string(int value) return "BH"; case TLS1_AD_UNKNOWN_PSK_IDENTITY: return "UP"; +#ifndef OPENSSL_NO_TLCP + case TLCP_AD_UNSUPPORTED_SITE2SITE: + return "U2"; + case TLCP_AD_NO_AREA: + return "NA"; + case TLCP_AD_UNSUPPORTED_AREATYPE: + return "AT"; + case TLCP_AD_BAD_IBCPARAM: + return "BI"; + case TLCP_AD_UNSUPPORTED_IBCPARAM: + return "UI"; + case TLCP_AD_IDENTITY_NEED: + return "IN"; +#endif default: return "UK"; } @@ -382,6 +396,20 @@ const char *SSL_alert_desc_string_long(int value) return "unknown PSK identity"; case TLS1_AD_NO_APPLICATION_PROTOCOL: return "no application protocol"; +#ifndef OPENSSL_NO_TLCP + case TLCP_AD_UNSUPPORTED_SITE2SITE: + return "unsupported site2site"; + case TLCP_AD_NO_AREA: + return "no area"; + case TLCP_AD_UNSUPPORTED_AREATYPE: + return "unsupported areatype"; + case TLCP_AD_BAD_IBCPARAM: + return "bad ibcparam"; + case TLCP_AD_UNSUPPORTED_IBCPARAM: + return "unsupported ibcparam"; + case TLCP_AD_IDENTITY_NEED: + return "identity need"; +#endif default: return "unknown"; } diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 0f39275baa..a03b6cd1a6 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -1056,7 +1056,11 @@ static int final_ec_pt_formats(SSL *s, unsigned int context, int sent) && s->ext.ecpointformats_len > 0 && s->ext.peer_ecpointformats != NULL && s->ext.peer_ecpointformats_len > 0 - && ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))) { + && ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA) +#ifndef OPENSSL_NO_TLCP + || (alg_k & SSL_kSM2DHE) || (alg_a & SSL_aSM2) +#endif + )) { /* we are using an ECC cipher */ size_t i; unsigned char *list = s->ext.peer_ecpointformats; diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 1cbaefa9f1..c641ae7351 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -134,6 +134,9 @@ static int use_ecc(SSL *s) alg_a = c->algorithm_auth; if ((alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) || (alg_a & SSL_aECDSA) +#ifndef OPENSSL_NO_TLCP + || (alg_k & SSL_kSM2DHE) || (alg_a & SSL_aSM2) +#endif || c->min_tls >= TLS1_3_VERSION) { ret = 1; break; diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 47541101db..775d9a7444 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1385,7 +1385,11 @@ EXT_RETURN tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, { unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; - int using_ecc = ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) + int using_ecc = ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA) +#ifndef OPENSSL_NO_TLCP + || (alg_k & SSL_kSM2DHE) || (alg_a & SSL_aSM2) +#endif + ) && (s->ext.peer_ecpointformats != NULL); const unsigned char *plist; size_t plistlen; diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index 20f5bd584e..d1fc2ccea6 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -361,7 +361,11 @@ static int state_machine(SSL *s, int server) goto end; } } else { +#ifndef OPENSSL_NO_TLCP + if ((s->version >> 8) != SSL3_VERSION_MAJOR && s->version != TLCP_VERSION) { +#else if ((s->version >> 8) != SSL3_VERSION_MAJOR) { +#endif SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR); goto end; diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index d19c44e8d9..ccb266bded 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -61,6 +61,10 @@ static int key_exchange_expected(SSL *s) { long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s)) + return 1; +#endif /* * Can't skip server key exchange if this is an ephemeral * ciphersuite or for SRP @@ -2257,8 +2261,277 @@ static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey) #endif } +#ifndef OPENSSL_NO_TLCP +static int tlcp_process_ske_sm2ecc(SSL *s, PACKET *pkt) +{ + EVP_MD_CTX *md_ctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + unsigned char *encbuf = NULL; + unsigned char *tbs = NULL; + + PACKET signature; + X509 *peer_sign_cert; + X509 *peer_enc_cert; + EVP_PKEY *peer_sign_pkey; + const EVP_MD *md; + unsigned char *tmp; + int rv, ebuflen, tbslen; + + rv = 0; + peer_sign_cert = s->session->peer; + peer_enc_cert = ssl_get_sm2_enc_cert(s, s->session->peer_chain); + if (peer_sign_cert == NULL || peer_enc_cert == NULL + || !ssl_is_sm2_cert(peer_sign_cert) + || !ssl_is_sm2_sign_usage(peer_sign_cert)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2ECC, ERR_R_INTERNAL_ERROR); + goto err; + } + + peer_sign_pkey = X509_get0_pubkey(peer_sign_cert); + if (!EVP_PKEY_set_alias_type(peer_sign_pkey, EVP_PKEY_SM2)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + /* Get the signature algorithm according to the peer sign key */ + if (SSL_USE_SIGALGS(s)) { + unsigned int sigalg; + + if (!PACKET_get_net_2(pkt, &sigalg)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC, + SSL_R_LENGTH_TOO_SHORT); + goto err; + } + if (tls12_check_peer_sigalg(s, sigalg, peer_sign_pkey) <=0) { + /* SSLfatal() already called */ + goto err; + } + } else if (!tls1_set_peer_legacy_sigalg(s, peer_sign_pkey)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + if (!tls1_lookup_md(s->s3->tmp.peer_sigalg, &md) + || EVP_PKEY_size(peer_sign_pkey) < 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!PACKET_get_length_prefixed_2(pkt, &signature) + || PACKET_remaining(pkt) != 0 + || PACKET_remaining(&signature) > (size_t)EVP_PKEY_size(peer_sign_pkey)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC, + SSL_R_LENGTH_MISMATCH); + goto err; + } + + ebuflen = i2d_X509(peer_enc_cert, NULL); + if (ebuflen < 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC, + ERR_R_BUF_LIB); + goto err; + } + + md_ctx = EVP_MD_CTX_new(); + encbuf = OPENSSL_malloc(ebuflen + 3); + if (md_ctx == NULL || encbuf == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC, + ERR_R_MALLOC_FAILURE); + goto err; + } + /* Encode the DER encoding of an X509 structure, reserve 3 bytes for length */ + tmp = encbuf; + l2n3(ebuflen, tmp); + ebuflen = i2d_X509(peer_enc_cert, &tmp); + if (ebuflen < 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC, + ERR_R_BUF_LIB); + goto err; + } + ebuflen += 3; + + if (EVP_DigestVerifyInit(md_ctx, &pctx, md, NULL, peer_sign_pkey) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC, + ERR_R_EVP_LIB); + goto err; + } + + tbslen = construct_key_exchange_tbs(s, &tbs, encbuf, ebuflen); + if (tbslen == 0) { + goto err; + } + + rv = EVP_DigestVerify(md_ctx, PACKET_data(&signature), + PACKET_remaining(&signature), tbs, tbslen); + if (rv <= 0) { + SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC, + SSL_R_BAD_SIGNATURE); + } +err: + OPENSSL_free(encbuf); + OPENSSL_free(tbs); + EVP_MD_CTX_free(md_ctx); + return rv; +} + +static int tlcp_process_ske_sm2dhe(SSL *s, PACKET *pkt) +{ + unsigned char *ecparams; + int ecparams_len; + PACKET pt_encoded; + PACKET signature; + EVP_PKEY *pkey; + EVP_PKEY_CTX *pctx; + EVP_PKEY_CTX *verify_ctx; + EVP_MD_CTX *md_ctx = NULL; + char *id = "1234567812345678"; + int ret = 0; + int max_sig_len; + + if(!PACKET_get_bytes(pkt, (const unsigned char**)&ecparams, 3) + || !PACKET_get_length_prefixed_1(pkt, &pt_encoded) + || !PACKET_get_length_prefixed_2(pkt, &signature) + ) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, SSL_R_LENGTH_TOO_SHORT); + return 0; + } + + if (PACKET_remaining(pkt) != 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, SSL_R_LENGTH_TOO_LONG); + return 0; + } + + // generate tmp pkey s->s3->peer_tmp with peer pub key + if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (EVP_PKEY_paramgen_init(pctx) <= 0 + || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_sm2) <= 0 + || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_EVP_LIB); + goto end; + } + + if (s->s3->peer_tmp == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_INTERNAL_ERROR); + goto end; + } + + if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp, + PACKET_data(&pt_encoded), PACKET_remaining(&pt_encoded))) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, SSL_R_BAD_ECPOINT); + goto end; + } + + // verify the msg using peer sign cert's pubkey + if ((pkey = X509_get0_pubkey(s->session->peer)) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_INTERNAL_ERROR); + goto end; + } + + max_sig_len = EVP_PKEY_size(pkey); + if (PACKET_remaining(&signature) > (size_t)max_sig_len) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, SSL_R_LENGTH_TOO_LONG); + goto end; + } + + if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_EVP_LIB); + goto end; + } + + if ((md_ctx = EVP_MD_CTX_new()) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_MALLOC_FAILURE); + goto end; + } + + if (EVP_DigestVerifyInit(md_ctx, &verify_ctx, EVP_sm3(), NULL, pkey) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_EVP_LIB); + goto end; + } + + if (EVP_PKEY_CTX_set1_id(verify_ctx, id, strlen(id)) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_EVP_LIB); + goto end; + } + + ecparams_len = PACKET_data(&pt_encoded) + PACKET_remaining(&pt_encoded) - ecparams; + if (EVP_DigestVerifyUpdate(md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestVerifyUpdate(md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestVerifyUpdate(md_ctx, ecparams, ecparams_len) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_EVP_LIB); + goto end; + } + + if (EVP_DigestVerifyFinal(md_ctx, + PACKET_data(&signature), PACKET_remaining(&signature)) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_SKE_SM2DHE, SSL_R_BAD_SIGNATURE); + goto end; + } + + ret = 1; + +end: + EVP_PKEY_CTX_free(pctx); + EVP_MD_CTX_free(md_ctx); + + return ret; +} + +static MSG_PROCESS_RETURN tlcp_process_key_exchange(SSL *s, PACKET *pkt) +{ + unsigned long alg_k; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + if (alg_k & SSL_kSM2ECC) { + if (!tlcp_process_ske_sm2ecc(s, pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + } else if (alg_k & SSL_kSM2DHE) { + if (!tlcp_process_ske_sm2dhe(s, pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + } else { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + return MSG_PROCESS_CONTINUE_READING; +err: + return MSG_PROCESS_ERROR; +} +#endif + MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt) { +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s)) + return tlcp_process_key_exchange(s, pkt); +#endif long alg_k; EVP_PKEY *pkey = NULL; EVP_MD_CTX *md_ctx = NULL; @@ -3320,8 +3593,169 @@ static int tls_construct_cke_srp(SSL *s, WPACKET *pkt) #endif } +#ifndef OPENSSL_NO_TLCP +static int tlcp_construct_cke_sm2ecc(SSL *s, WPACKET *pkt) +{ + unsigned char *encdata = NULL; + EVP_PKEY_CTX *pctx = NULL; + unsigned char *pms = NULL; + size_t pmslen = 0; + + X509 *peer_enc_cert; + EVP_PKEY *peer_enc_pkey; + size_t enclen; + + peer_enc_cert = ssl_get_sm2_enc_cert(s, s->session->peer_chain); + peer_enc_pkey = X509_get0_pubkey(peer_enc_cert); + if (peer_enc_cert == NULL || peer_enc_pkey == NULL + || !EVP_PKEY_set_alias_type(peer_enc_pkey, EVP_PKEY_SM2)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC, ERR_R_INTERNAL_ERROR); + goto err; + } + + pmslen = SSL_MAX_MASTER_KEY_LENGTH; + pms = OPENSSL_malloc(pmslen); + if (pms == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC, + ERR_R_MALLOC_FAILURE); + goto err; + } + + pms[0] = s->client_version >> 8; + pms[1] = s->client_version & 0xff; + if (RAND_bytes(pms + 2, (int)(pmslen - 2)) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!WPACKET_start_sub_packet_u16(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + /* Encrypt premaster secret { client_version, random[46] }*/ + pctx = EVP_PKEY_CTX_new(peer_enc_pkey, NULL); + if (pctx == NULL || EVP_PKEY_encrypt_init(pctx) <= 0 + || EVP_PKEY_encrypt(pctx, NULL, &enclen, pms, pmslen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC, + ERR_R_EVP_LIB); + goto err; + } + if (!WPACKET_reserve_bytes(pkt, enclen, &encdata) + || EVP_PKEY_encrypt(pctx, encdata, &enclen, pms, pmslen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC, + ERR_R_EVP_LIB); + goto err; + } + pkt->written += enclen; + pkt->curr += enclen; + EVP_PKEY_CTX_free(pctx); + pctx = NULL; + + if (!WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + + s->s3->tmp.pms = pms; + s->s3->tmp.pmslen = pmslen; + + return 1; +err: + OPENSSL_clear_free(pms, pmslen); + EVP_PKEY_CTX_free(pctx); + return 0; +} + +static int tlcp_construct_cke_sm2dhe(SSL *s, WPACKET *pkt) +{ + EVP_PKEY *skey, *ckey; + unsigned char * pt_encoded = NULL; + int pt_encoded_len; + int ret = 0; + + if ((skey = s->s3->peer_tmp) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!WPACKET_put_bytes_u8(pkt, NAMED_CURVE_TYPE) + || !WPACKET_put_bytes_u8(pkt, 0) + || !WPACKET_put_bytes_u8(pkt, 41)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_INTERNAL_ERROR); + return 0; + } + + if ((ckey = ssl_generate_pkey(skey)) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_INTERNAL_ERROR); + return 0; + } + + if ((pt_encoded_len = EVP_PKEY_get1_tls_encodedpoint(ckey, &pt_encoded)) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_EC_LIB); + goto end; + } + + if (!WPACKET_sub_memcpy_u8(pkt, pt_encoded, pt_encoded_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_INTERNAL_ERROR); + goto end; + } + + if (!tlcp_derive(s, ckey, skey)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_INTERNAL_ERROR); + goto end; + } + + ret = 1; + +end: + EVP_PKEY_free(ckey); + if (pt_encoded) { + OPENSSL_free(pt_encoded); + } + + return ret; +} + +static int tlcp_construct_client_key_exchange(SSL *s, WPACKET *pkt) +{ + unsigned long alg_k; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + if (alg_k & SSL_kSM2ECC) { + if (!tlcp_construct_cke_sm2ecc(s, pkt)) + goto err; + } else if (alg_k & SSL_kSM2DHE) { + if (!tlcp_construct_cke_sm2dhe(s, pkt)) + goto err; + } else { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + return 1; +err: + return 0; +} +#endif + int tls_construct_client_key_exchange(SSL *s, WPACKET *pkt) { +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s)) + return tlcp_construct_client_key_exchange(s, pkt); +#endif unsigned long alg_k; alg_k = s->s3->tmp.new_cipher->algorithm_mkey; diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 695caab3d6..777a474692 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -227,6 +227,29 @@ static int get_cert_verify_tbs_data(SSL *s, unsigned char *tls13tbs, return 1; } +#ifndef OPENSSL_NO_TLCP +static int get_tbs_hash_data(void *hdata, size_t hdatalen, unsigned char *out, size_t *outlen) +{ + EVP_MD_CTX *md_ctx; + int rv = 0; + + md_ctx = EVP_MD_CTX_new(); + if (md_ctx == NULL) + goto err; + + // TLCP is only used SM3 + if (!EVP_DigestInit(md_ctx, EVP_sm3()) + || !EVP_DigestUpdate(md_ctx, (const void *)hdata, hdatalen) + || !EVP_DigestFinal(md_ctx, out, (unsigned int *)outlen)) { + goto err; + } + rv = 1; +err: + EVP_MD_CTX_free(md_ctx); + return rv; +} +#endif + int tls_construct_cert_verify(SSL *s, WPACKET *pkt) { EVP_PKEY *pkey = NULL; @@ -238,6 +261,9 @@ int tls_construct_cert_verify(SSL *s, WPACKET *pkt) unsigned char *sig = NULL; unsigned char tls13tbs[TLS13_TBS_PREAMBLE_SIZE + EVP_MAX_MD_SIZE]; const SIGALG_LOOKUP *lu = s->s3->tmp.sigalg; +#ifndef OPENSSL_NO_TLCP + unsigned char out[EVP_MAX_MD_SIZE] = {0}; +#endif if (lu == NULL || s->s3->tmp.cert == NULL) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY, @@ -251,6 +277,15 @@ int tls_construct_cert_verify(SSL *s, WPACKET *pkt) ERR_R_INTERNAL_ERROR); goto err; } +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s) && EVP_PKEY_is_sm2(pkey)) { + if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY, + ERR_R_INTERNAL_ERROR); + goto err; + } + } +#endif mctx = EVP_MD_CTX_new(); if (mctx == NULL) { @@ -264,7 +299,17 @@ int tls_construct_cert_verify(SSL *s, WPACKET *pkt) /* SSLfatal() already called */ goto err; } - +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s)) { + if (!get_tbs_hash_data(hdata, hdatalen, out, &hdatalen)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY, + ERR_R_INTERNAL_ERROR); + goto err; + } + /* Use new hash data for sign */ + hdata = out; + } +#endif if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_INTERNAL_ERROR); @@ -359,6 +404,9 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt) unsigned char tls13tbs[TLS13_TBS_PREAMBLE_SIZE + EVP_MAX_MD_SIZE]; EVP_MD_CTX *mctx = EVP_MD_CTX_new(); EVP_PKEY_CTX *pctx = NULL; +#ifndef OPENSSL_NO_TLCP + unsigned char out[EVP_MAX_MD_SIZE] = {0}; +#endif if (mctx == NULL) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY, @@ -373,6 +421,15 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt) ERR_R_INTERNAL_ERROR); goto err; } +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s) && EVP_PKEY_is_sm2(pkey)) { + if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY, + ERR_R_INTERNAL_ERROR); + goto err; + } + } +#endif if (ssl_cert_lookup_by_pkey(pkey, NULL) == NULL) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_CERT_VERIFY, @@ -448,6 +505,17 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt) /* SSLfatal() already called */ goto err; } +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s)) { + if (!get_tbs_hash_data(hdata, hdatalen, out, &hdatalen)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY, + ERR_R_INTERNAL_ERROR); + goto err; + } + /* Use new hash data for verify */ + hdata = out; + } +#endif #ifdef SSL_DEBUG fprintf(stderr, "Using client verify alg %s\n", @@ -907,6 +975,60 @@ static int ssl_add_cert_to_wpacket(SSL *s, WPACKET *pkt, X509 *x, int chain) return 1; } +#ifndef OPENSSL_NO_TLCP +static int ssl_add_sm2_cert_for_tlcp(SSL *s, STACK_OF(X509) *chain, WPACKET *pkt, X509 *sign_cert) +{ + CERT_PKEY *enc_cpk; + X509 *x; + int i = 0; + int idx = 0; + int count; + X509 *enc_cert; + + enc_cpk = &s->cert->pkeys[SSL_PKEY_SM2_ENC]; + // server must have enc cert + if (s->server && (enc_cpk == NULL || enc_cpk->x509 == NULL)) + return 0; + + enc_cert = enc_cpk->x509; + + if (sign_cert != NULL) { + if (!ssl_add_cert_to_wpacket(s, pkt, sign_cert, idx++)) { + return 0; + } + } else { + if (!ssl_add_cert_to_wpacket(s, pkt, sk_X509_value(chain, i++), idx++)) { + return 0; + } + } + + // enc cert put the second position + if (enc_cert != NULL && (s->options & SSL_OP_ENCCERT_SECOND_POSITION)) { + if (!ssl_add_cert_to_wpacket(s, pkt, enc_cert, idx++)) { + return 0; + } + enc_cert = NULL; + } + + count = sk_X509_num(chain); + for (; i < count; i++) { + x = sk_X509_value(chain, i); + if (!ssl_add_cert_to_wpacket(s, pkt, x, idx++)) { + return 0; + } + } + + // enc cert in the last position + if (enc_cert) { + if (!ssl_add_cert_to_wpacket(s, pkt, enc_cpk->x509, idx++)) { + return 0; + } + } + + return 1; +} +#endif + /* Add certificate chain to provided WPACKET */ static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk) { @@ -972,6 +1094,14 @@ static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk) SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ADD_CERT_CHAIN, i); return 0; } +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s)) { + if (!ssl_add_sm2_cert_for_tlcp(s, chain, pkt, NULL)) { + X509_STORE_CTX_free(xs_ctx); + return 0; + } + } else { +#endif chain_count = sk_X509_num(chain); for (i = 0; i < chain_count; i++) { x = sk_X509_value(chain, i); @@ -982,6 +1112,9 @@ static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk) return 0; } } +#ifndef OPENSSL_NO_TLCP + } +#endif X509_STORE_CTX_free(xs_ctx); } else { i = ssl_security_cert_chain(s, extra_certs, x, 0); @@ -989,6 +1122,11 @@ static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk) SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ADD_CERT_CHAIN, i); return 0; } +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s)) { + return ssl_add_sm2_cert_for_tlcp(s, extra_certs, pkt, x); + } else { +#endif if (!ssl_add_cert_to_wpacket(s, pkt, x, 0)) { /* SSLfatal() already called */ return 0; @@ -1000,6 +1138,9 @@ static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk) return 0; } } +#ifndef OPENSSL_NO_TLCP + } +#endif } return 1; } @@ -1444,6 +1585,9 @@ static const version_info tls_version_table[] = { #else {TLS1_VERSION, NULL, NULL}, #endif +#ifndef OPENSSL_NO_TLCP + {TLCP_VERSION, tlcp_client_method, tlcp_server_method}, +#endif #ifndef OPENSSL_NO_SSL3 {SSL3_VERSION, sslv3_client_method, sslv3_server_method}, #else @@ -1596,7 +1740,10 @@ int ssl_version_supported(const SSL *s, int version, const SSL_METHOD **meth) } for (vent = table; - vent->version != 0 && version_cmp(s, version, vent->version) <= 0; +#ifndef OPENSSL_NO_TLCP + ((version == SSL3_VERSION) && (vent->version == TLCP_VERSION)) || +#endif + (vent->version != 0 && version_cmp(s, version, vent->version) <= 0); ++vent) { if (vent->cmeth != NULL && version_cmp(s, version, vent->version) == 0 @@ -1675,8 +1822,11 @@ int ssl_set_version_bound(int method_version, int version, int *bound) *bound = version; return 1; } - +#ifndef OPENSSL_NO_TLCP + valid_tls = version >= TLCP_VERSION && version <= TLS_MAX_VERSION; +#else valid_tls = version >= SSL3_VERSION && version <= TLS_MAX_VERSION; +#endif valid_dtls = DTLS_VERSION_LE(version, DTLS_MAX_VERSION) && DTLS_VERSION_GE(version, DTLS1_BAD_VER); @@ -1868,6 +2018,9 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd) const SSL_METHOD *method; if (vent->smeth == NULL || +#ifndef OPENSSL_NO_TLCP + ((client_version != TLCP_VERSION) && (vent->version == TLCP_VERSION)) || +#endif version_cmp(s, client_version, vent->version) < 0) continue; method = vent->smeth(); @@ -2097,6 +2250,11 @@ int ssl_get_min_max_version(const SSL *s, int *min_version, int *max_version, * A table entry with a NULL client method is still a hole in the * "version capability" vector. */ +#ifndef OPENSSL_NO_TLCP + if (vent->version == TLCP_VERSION) { + continue; + } +#endif if (vent->cmeth == NULL) { hole = 1; tmp_real_max = 0; @@ -2120,7 +2278,23 @@ int ssl_get_min_max_version(const SSL *s, int *min_version, int *max_version, hole = 0; } } - +#ifndef OPENSSL_NO_TLCP + if (version == 0 && s->method->version == TLS_ANY_VERSION) { + /* + * enable tlcp condition (when only sslv3 version, dont choose tlcp): + * 1. version is TLS_ANY_VERSION, and all tls/ssl protocol disabled + * 2. max version > sslv3 or max version == tlcp_version + * 3. s->options not set SSL_OP_NO_TLCP + */ + if ((s->max_proto_version > SSL3_VERSION + || s->max_proto_version == TLCP_VERSION + || s->max_proto_version == 0) + && (s->options & SSL_OP_NO_TLCP) == 0) { + *min_version = *max_version = TLCP_VERSION; + return 0; + } + } +#endif *max_version = version; /* Fail if everything is disabled */ diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 43f77a5899..1b3b8002ee 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -325,6 +325,11 @@ static int send_server_key_exchange(SSL *s) { unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; +#ifndef OPENSSL_NO_TLCP + /* TLCP: send ServerKeyExchange */ + if (SSL_IS_TLCP(s)) + return 1; +#endif /* * only send a ServerKeyExchange if DH or fortezza but we have a * sign only certificate PSK: may send PSK identity hints For @@ -2356,7 +2361,17 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst) } } #endif - +#ifndef OPENSSL_NO_TLCP + /* + * As described by TLCP, when using ecdhe algorithm, + * client is required to send a certificate, + * so we set VEERFY_PEER mode. + */ + if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSM2DHE) { + SSL_set_verify(s, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT + | SSL_VERIFY_CLIENT_ONCE, NULL); + } +#endif return WORK_FINISHED_STOP; err: return WORK_ERROR; @@ -2485,8 +2500,270 @@ int tls_construct_server_done(SSL *s, WPACKET *pkt) return 1; } +#ifndef OPENSSL_NO_TLCP +static int tlcp_construct_ske_sm2ecc(SSL *s, WPACKET *pkt) +{ + EVP_MD_CTX *md_ctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + unsigned char *encbuf = NULL; + unsigned char *tbs = NULL; + + const SIGALG_LOOKUP *lu; + EVP_PKEY *sign_pkey; + X509 *enc_cert; + const EVP_MD *md; + unsigned char *sigbytes1, *sigbytes2, *tmp; + size_t siglen, tbslen; + int rv, ebuflen; + + rv = 0; + lu = s->s3->tmp.sigalg; + sign_pkey = s->cert->pkeys[SSL_PKEY_SM2_SIGN].privatekey; + enc_cert = s->cert->pkeys[SSL_PKEY_SM2_ENC].x509; + + if (lu == NULL || sign_pkey == NULL || enc_cert == NULL + || !tls1_lookup_md(lu, &md)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!EVP_PKEY_is_sm2(sign_pkey) + || !EVP_PKEY_set_alias_type(sign_pkey, EVP_PKEY_SM2)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + + /* send signature algorithm */ + if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + + ebuflen = i2d_X509(enc_cert, NULL); + if (ebuflen < 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC, + ERR_R_BUF_LIB); + goto err; + } + + md_ctx = EVP_MD_CTX_new(); + encbuf = OPENSSL_malloc(ebuflen + 3); + if (md_ctx == NULL || encbuf == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC, + ERR_R_MALLOC_FAILURE); + goto err; + } + /* Encode the DER encoding of an X509 structure, reserve 3 bytes for length */ + tmp = encbuf; + l2n3(ebuflen, tmp); + ebuflen = i2d_X509(enc_cert, &tmp); + if (ebuflen < 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC, + ERR_R_BUF_LIB); + goto err; + } + ebuflen += 3; + + siglen = EVP_PKEY_size(sign_pkey); + if (!WPACKET_sub_reserve_bytes_u16(pkt, siglen, &sigbytes1) + || EVP_DigestSignInit(md_ctx, &pctx, md, NULL, sign_pkey) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + /* + * As described by TLCP, client_random, server_random and encryption + * certificate are signed. + */ + tbslen = construct_key_exchange_tbs(s, &tbs, encbuf, ebuflen); + if (tbslen == 0) { + goto err; + } + + rv = EVP_DigestSign(md_ctx, sigbytes1, &siglen, tbs, tbslen); + + if (rv <= 0 || !WPACKET_sub_allocate_bytes_u16(pkt, siglen, &sigbytes2) + || sigbytes1 != sigbytes2) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } +err: + OPENSSL_free(encbuf); + OPENSSL_free(tbs); + EVP_MD_CTX_free(md_ctx); + return rv; +} + +static int tlcp_construct_ske_sm2dhe(SSL *s, WPACKET *pkt) +{ + EVP_PKEY_CTX *ctx; + EVP_PKEY *pkey; + EVP_MD_CTX *md_ctx = NULL; + unsigned char *pt; + int ptLen; + char *id = "1234567812345678"; + unsigned char *ecparam; + size_t ecparam_len = 0; + int ret = 0; + size_t siglen; + unsigned char *sig; + + ecparam = WPACKET_get_curr(pkt); + + // ECParam: NameCurved, curvedtype {NameCurved(3), curveid(41, rfc8898 defined, but this msg is ignored) + if (!WPACKET_put_bytes_u8(pkt, NAMED_CURVE_TYPE) + || !WPACKET_put_bytes_u8(pkt, 0) + || !WPACKET_put_bytes_u8(pkt, 41)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + pkey = s->cert->pkeys[SSL_PKEY_SM2_SIGN].privatekey; + if (pkey == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + if (s->s3->tmp.pkey != NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + return 0; + } + s->s3->tmp.pkey = ssl_generate_pkey_group(s, 41); + if (s->s3->tmp.pkey == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + ptLen = EVP_PKEY_get1_tls_encodedpoint(s->s3->tmp.pkey, &pt); + if (ptLen == 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_EC_LIB); + return 0; + } + + if (!WPACKET_sub_memcpy_u8(pkt, pt, ptLen)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + OPENSSL_free(pt); + return 0; + } + OPENSSL_free(pt); + ecparam_len = WPACKET_get_curr(pkt) - ecparam; + + if (!EVP_PKEY_is_sm2(pkey) || !EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_EC_LIB); + goto err; + } + + md_ctx = EVP_MD_CTX_new(); + if (md_ctx == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_MALLOC_FAILURE); + return 0; + } + + if (EVP_DigestSignInit(md_ctx, &ctx, EVP_sm3(), NULL, pkey) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (EVP_PKEY_CTX_set1_id(ctx, id, strlen(id)) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_EC_LIB); + return 0; + } + + if (EVP_DigestSignUpdate(md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestSignUpdate(md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestSignUpdate(md_ctx, ecparam, ecparam_len) <= 0 + ) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_EVP_LIB); + goto err; + } + + if ((siglen = EVP_PKEY_size(pkey)) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!WPACKET_sub_reserve_bytes_u16(pkt, siglen, &sig)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (EVP_DigestSignFinal(md_ctx, sig, &siglen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + SSL_R_SIGNATURE_ALGORITHMS_ERROR); + goto err; + } + + unsigned char* sig2 = NULL; + if (!WPACKET_sub_allocate_bytes_u16(pkt, siglen, &sig2) || sig != sig2) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = 1; + +err: + EVP_MD_CTX_free(md_ctx); + if (!ret && s->s3->tmp.pkey) { + EVP_PKEY_free(s->s3->tmp.pkey); + s->s3->tmp.pkey = NULL; + } + + return ret; +} + +static int tlcp_construct_server_key_exchange(SSL *s, WPACKET *pkt) +{ + unsigned long alg_k; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + if (alg_k & SSL_kSM2ECC) { + if (!tlcp_construct_ske_sm2ecc(s, pkt)) + goto err; + } else if (alg_k & SSL_kSM2DHE) { + if (!tlcp_construct_ske_sm2dhe(s, pkt)) + goto err; + } else { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + return 1; +err: + return 0; +} +#endif + int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt) { +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s)) + return tlcp_construct_server_key_exchange(s, pkt); +#endif #ifndef OPENSSL_NO_DH EVP_PKEY *pkdh = NULL; #endif @@ -3455,8 +3732,174 @@ static int tls_process_cke_gost(SSL *s, PACKET *pkt) #endif } +#ifndef OPENSSL_NO_TLCP +static int tlcp_process_cke_sm2ecc(SSL *s, PACKET *pkt) +{ + EVP_PKEY_CTX *pctx = NULL; + int ret = 0; + + unsigned char premaster_secret[SSL_MAX_MASTER_KEY_LENGTH]; + EVP_PKEY *enc_prv_pkey; + PACKET enc_premaster; + size_t decrypt_len; + + enc_prv_pkey = s->cert->pkeys[SSL_PKEY_SM2_ENC].privatekey; + if (enc_prv_pkey == NULL || !EVP_PKEY_is_sm2(enc_prv_pkey) + || !EVP_PKEY_set_alias_type(enc_prv_pkey, EVP_PKEY_SM2)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC, + SSL_R_NO_PRIVATE_KEY_ASSIGNED); + return 0; + } + + if (!PACKET_get_length_prefixed_2(pkt, &enc_premaster) + || PACKET_remaining(pkt) != 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC, + SSL_R_LENGTH_MISMATCH); + return 0; + } + + pctx = EVP_PKEY_CTX_new(enc_prv_pkey, NULL); + if (pctx == NULL || EVP_PKEY_decrypt_init(pctx) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC, + ERR_R_EVP_LIB); + goto err; + } + + /* Decrypt premaster secret { client_version, random[46] }*/ + decrypt_len = sizeof(premaster_secret); + if (EVP_PKEY_decrypt(pctx, premaster_secret, &decrypt_len, + PACKET_data(&enc_premaster), PACKET_remaining(&enc_premaster)) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC, + ERR_R_EVP_LIB); + goto err; + } + if (decrypt_len != SSL_MAX_MASTER_KEY_LENGTH) { + SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC, + SSL_R_DECRYPTION_FAILED); + goto err; + } + + /* Check client version */ + if (constant_time_eq_8(premaster_secret[0], (unsigned)(s->client_version >> 8)) == 0 || + constant_time_eq_8(premaster_secret[1], (unsigned)(s->client_version & 0xff)) == 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!ssl_generate_master_secret(s, premaster_secret, + sizeof(premaster_secret), 0)) { + /* SSLfatal() already called */ + goto err; + } + + ret = 1; + err: + OPENSSL_cleanse(premaster_secret, sizeof(premaster_secret)); + EVP_PKEY_CTX_free(pctx); + return ret; +} + +static int tlcp_process_cke_sm2dhe(SSL *s, PACKET *pkt) +{ + int ret = 0; + const unsigned char *ecparams; + PACKET pt_encoded; + EVP_PKEY *skey; + EVP_PKEY *ckey = NULL; + + if ((skey = s->s3->tmp.pkey) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!PACKET_get_bytes(pkt, &ecparams, 3)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE, + SSL_R_LENGTH_TOO_SHORT); + goto end; + } + + if (!PACKET_get_length_prefixed_1(pkt, &pt_encoded)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE, + SSL_R_LENGTH_TOO_SHORT); + goto end; + } + + if (PACKET_remaining(pkt) != 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE, + SSL_R_LENGTH_TOO_LONG); + goto end; + } + + if ((ckey = EVP_PKEY_new()) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE, + ERR_R_MALLOC_FAILURE); + goto end; + } + + if (EVP_PKEY_copy_parameters(ckey, skey) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + goto end; + } + + if (EVP_PKEY_set1_tls_encodedpoint(ckey, + PACKET_data(&pt_encoded), PACKET_remaining(&pt_encoded)) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE, + ERR_R_EC_LIB); + goto end; + } + + if (!tlcp_derive(s, skey, ckey)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE, + ERR_R_INTERNAL_ERROR); + goto end; + } + + ret = 1; + +end: + EVP_PKEY_free(ckey); + EVP_PKEY_free(skey); + s->s3->tmp.pkey = NULL; + + return ret; +} + +static MSG_PROCESS_RETURN tlcp_process_client_key_exchange(SSL *s, PACKET *pkt) +{ + unsigned long alg_k; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + if (alg_k & SSL_kSM2ECC) { + if (!tlcp_process_cke_sm2ecc(s, pkt)) { + goto err; + } + } else if (alg_k & SSL_kSM2DHE) { + if (!tlcp_process_cke_sm2dhe(s, pkt)) { + goto err; + } + } else { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLCP_PROCESS_CLIENT_KEY_EXCHANGE, + SSL_R_UNKNOWN_CIPHER_TYPE); + goto err; + } + + return MSG_PROCESS_CONTINUE_PROCESSING; +err: + return MSG_PROCESS_ERROR; +} +#endif + MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt) { +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s)) + return tlcp_process_client_key_exchange(s, pkt); +#endif unsigned long alg_k; alg_k = s->s3->tmp.new_cipher->algorithm_mkey; diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index f8e53d4efc..6196cb04ae 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -678,3 +678,87 @@ int tls1_alert_code(int code) return -1; } } + +#ifndef OPENSSL_NO_TLCP +int tlcp_alert_code(int code) +{ + switch (code) { + case SSL_AD_CLOSE_NOTIFY: + return (SSL3_AD_CLOSE_NOTIFY); + case SSL_AD_UNEXPECTED_MESSAGE: + return (SSL3_AD_UNEXPECTED_MESSAGE); + case SSL_AD_BAD_RECORD_MAC: + return (SSL3_AD_BAD_RECORD_MAC); + case SSL_AD_DECRYPTION_FAILED: + return (TLS1_AD_DECRYPTION_FAILED); + case SSL_AD_RECORD_OVERFLOW: + return (TLS1_AD_RECORD_OVERFLOW); + case SSL_AD_DECOMPRESSION_FAILURE: + return (SSL3_AD_DECOMPRESSION_FAILURE); + case SSL_AD_HANDSHAKE_FAILURE: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_BAD_CERTIFICATE: + return (SSL3_AD_BAD_CERTIFICATE); + case SSL_AD_UNSUPPORTED_CERTIFICATE: + return (SSL3_AD_UNSUPPORTED_CERTIFICATE); + case SSL_AD_CERTIFICATE_REVOKED: + return (SSL3_AD_CERTIFICATE_REVOKED); + case SSL_AD_CERTIFICATE_EXPIRED: + return (SSL3_AD_CERTIFICATE_EXPIRED); + case SSL_AD_CERTIFICATE_UNKNOWN: + return (SSL3_AD_CERTIFICATE_UNKNOWN); + case SSL_AD_ILLEGAL_PARAMETER: + return (SSL3_AD_ILLEGAL_PARAMETER); + case SSL_AD_UNKNOWN_CA: + return (TLS1_AD_UNKNOWN_CA); + case SSL_AD_ACCESS_DENIED: + return (TLS1_AD_ACCESS_DENIED); + case SSL_AD_DECODE_ERROR: + return (TLS1_AD_DECODE_ERROR); + case SSL_AD_DECRYPT_ERROR: + return (TLS1_AD_DECRYPT_ERROR); + case SSL_AD_EXPORT_RESTRICTION: + return (TLS1_AD_EXPORT_RESTRICTION); + case SSL_AD_PROTOCOL_VERSION: + return (TLS1_AD_PROTOCOL_VERSION); + case SSL_AD_INSUFFICIENT_SECURITY: + return (TLS1_AD_INSUFFICIENT_SECURITY); + case SSL_AD_INTERNAL_ERROR: + return (TLS1_AD_INTERNAL_ERROR); + case SSL_AD_USER_CANCELLED: + return (TLS1_AD_USER_CANCELLED); + case SSL_AD_NO_RENEGOTIATION: + return (TLS1_AD_NO_RENEGOTIATION); + case SSL_AD_UNSUPPORTED_EXTENSION: + return (TLS1_AD_UNSUPPORTED_EXTENSION); + case SSL_AD_CERTIFICATE_UNOBTAINABLE: + return (TLS1_AD_CERTIFICATE_UNOBTAINABLE); + case SSL_AD_UNRECOGNIZED_NAME: + return (TLS1_AD_UNRECOGNIZED_NAME); + case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + return (TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE); + case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: + return (TLS1_AD_BAD_CERTIFICATE_HASH_VALUE); + case SSL_AD_INAPPROPRIATE_FALLBACK: + return (TLS1_AD_INAPPROPRIATE_FALLBACK); + case SSL_AD_NO_APPLICATION_PROTOCOL: + return (TLS1_AD_NO_APPLICATION_PROTOCOL); + case SSL_AD_CERTIFICATE_REQUIRED: + return (SSL_AD_HANDSHAKE_FAILURE); + case SSL_AD_UNSUPPORTED_SITE2SITE: + return (TLCP_AD_UNSUPPORTED_SITE2SITE); + case SSL_AD_NO_AREA: + return (TLCP_AD_NO_AREA); + case SSL_AD_UNSUPPORTED_AREATYPE: + return (TLCP_AD_UNSUPPORTED_AREATYPE); + case SSL_AD_BAD_IBCPARAM: + return (TLCP_AD_BAD_IBCPARAM); + case SSL_AD_UNSUPPORTED_IBCPARAM: + return (TLCP_AD_UNSUPPORTED_IBCPARAM); + case SSL_AD_IDENTITY_NEED: + return (TLCP_AD_IDENTITY_NEED); + default: + return (-1); + } +} +#endif diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 5f657f888e..9fd51a8a2f 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -93,6 +93,25 @@ SSL3_ENC_METHOD const TLSv1_3_enc_data = { ssl3_handshake_write }; +#ifndef OPENSSL_NO_TLCP +SSL3_ENC_METHOD const TLCP_enc_data = { + tls1_enc, + tls1_mac, + tls1_setup_key_block, + tls1_generate_master_secret, + tls1_change_cipher_state, + tls1_final_finish_mac, + TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE, + TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE, + tlcp_alert_code, + tls1_export_keying_material, + SSL_ENC_FLAG_EXPLICIT_IV, + ssl3_set_handshake_header, + tls_close_construct_packet, + ssl3_handshake_write +}; +#endif + long tls1_default_timeout(void) { /* @@ -169,6 +188,9 @@ static const TLS_GROUP_INFO nid_list[] = { {NID_brainpoolP512r1, 256, TLS_CURVE_PRIME}, /* brainpool512r1 (28) */ {EVP_PKEY_X25519, 128, TLS_CURVE_CUSTOM}, /* X25519 (29) */ {EVP_PKEY_X448, 224, TLS_CURVE_CUSTOM}, /* X448 (30) */ +#ifndef OPENSSL_NO_TLCP + [40] = {EVP_PKEY_SM2, 128, TLS_CURVE_PRIME} /* sm2 (41) */ +#endif }; static const unsigned char ecformats_default[] = { @@ -184,6 +206,9 @@ static const uint16_t eccurves_default[] = { 30, /* X448 (30) */ 25, /* secp521r1 (25) */ 24, /* secp384r1 (24) */ +#ifndef OPENSSL_NO_TLCP + 41, /* sm2 (41) */ +#endif }; static const uint16_t suiteb_curves[] = { @@ -258,6 +283,12 @@ int tls_curve_allowed(SSL *s, uint16_t curve, int op) if (cinfo->flags & TLS_CURVE_CHAR2) return 0; # endif +#ifndef OPENSSL_NO_TLCP + // SM2 is only allowed in TLCP + if (s->version != TLCP_VERSION && cinfo->nid == NID_sm2) { + return 0; + } +#endif ctmp[0] = curve >> 8; ctmp[1] = curve & 0xff; return ssl_security(s, op, cinfo->secbits, cinfo->nid, (void *)ctmp); @@ -545,6 +576,10 @@ void tls1_get_formatlist(SSL *s, const unsigned char **pformats, /* For Suite B we don't support char2 fields */ if (tls1_suiteb(s)) *num_formats = sizeof(ecformats_default) - 1; +#ifndef OPENSSL_NO_TLCP + else if (SSL_IS_TLCP(s)) // TLCP version only support uncompressed + *num_formats = sizeof(ecformats_default) - 2; +#endif else *num_formats = sizeof(ecformats_default); } @@ -637,6 +672,9 @@ static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md) /* Default sigalg schemes */ static const uint16_t tls12_sigalgs[] = { #ifndef OPENSSL_NO_EC +#ifndef OPENSSL_NO_TLCP + TLSEXT_SIGALG_sm2dsa_sm3, +#endif TLSEXT_SIGALG_ecdsa_secp256r1_sha256, TLSEXT_SIGALG_ecdsa_secp384r1_sha384, TLSEXT_SIGALG_ecdsa_secp521r1_sha512, @@ -685,6 +723,11 @@ static const uint16_t suiteb_sigalgs[] = { static const SIGALG_LOOKUP sigalg_lookup_tbl[] = { #ifndef OPENSSL_NO_EC +#ifndef OPENSSL_NO_TLCP + {"sm2dsa_sm3", TLSEXT_SIGALG_sm2dsa_sm3, + NID_sm3, SSL_MD_SM3_IDX, EVP_PKEY_SM2, SSL_PKEY_SM2_SIGN, + NID_SM2_with_SM3, NID_sm2}, +#endif {"ecdsa_secp256r1_sha256", TLSEXT_SIGALG_ecdsa_secp256r1_sha256, NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_EC, SSL_PKEY_ECC, NID_ecdsa_with_SHA256, NID_X9_62_prime256v1}, @@ -794,6 +837,10 @@ static const uint16_t tls_default_sigalg[] = { TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512, /* SSL_PKEY_GOST12_512 */ 0, /* SSL_PKEY_ED25519 */ 0, /* SSL_PKEY_ED448 */ +#ifndef OPENSSL_NO_TLCP + TLSEXT_SIGALG_sm2dsa_sm3, /* SSL_PKEY_SM2_SIGN */ + 0, /* SSL_PKEY_SM2_ENC */ +#endif }; /* Lookup TLS signature algorithm */ @@ -981,7 +1028,7 @@ int tls_check_sigalg_curve(const SSL *s, int curve) if (lu == NULL) continue; - if (lu->sig == EVP_PKEY_EC + if ((lu->sig == EVP_PKEY_EC || lu->sig == EVP_PKEY_SM2) && lu->curve != NID_undef && curve == lu->curve) return 1; @@ -1053,6 +1100,9 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey) if (lu == NULL || (SSL_IS_TLS13(s) && (lu->hash == NID_sha1 || lu->hash == NID_sha224)) || (pkeyid != lu->sig +#ifndef OPENSSL_NO_TCLP + && (lu->sig != EVP_PKEY_SM2) +#endif && (lu->sig != EVP_PKEY_RSA_PSS || pkeyid != EVP_PKEY_RSA))) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE); @@ -1197,6 +1247,13 @@ int ssl_set_client_disabled(SSL *s) s->s3->tmp.mask_a |= SSL_aSRP; s->s3->tmp.mask_k |= SSL_kSRP; } +#endif +#ifndef OPENSSL_NO_TLCP + /* TLCP ciphersuites will be disabled while using other protocols */ + if (s->version != TLCP_VERSION) { + s->s3->tmp.mask_a |= SSL_aSM2; + s->s3->tmp.mask_k |= SSL_kSM2ECC | SSL_kSM2DHE; + } #endif return 1; } @@ -1317,7 +1374,11 @@ SSL_TICKET_STATUS tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, * (e.g. TLSv1.3) behave as if no ticket present to permit stateful * resumption. */ +#ifndef OPENSSL_NO_TLCP + if ((s->version <= SSL3_VERSION && s->version != TLCP_VERSION) || !tls_use_ticket(s)) +#else if (s->version <= SSL3_VERSION || !tls_use_ticket(s)) +#endif return SSL_TICKET_NONE; ticketext = &hello->pre_proc_exts[TLSEXT_IDX_session_ticket]; @@ -1595,6 +1656,13 @@ static int tls12_sigalg_allowed(const SSL *s, int op, const SIGALG_LOOKUP *lu) unsigned char sigalgstr[2]; int secbits; +#ifndef OPENSSL_NO_TLCP + // SM2 is only allowed in TLCP + if (s->version != TLCP_VERSION && lu != NULL && lu->sig == EVP_PKEY_SM2) { + return 0; + } +#endif + /* See if sigalgs is recognised and if hash is enabled */ if (!tls1_lookup_md(lu, NULL)) return 0; @@ -2426,6 +2494,10 @@ void tls1_set_cert_validity(SSL *s) tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST12_512); tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ED25519); tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ED448); +#ifndef OPENSSL_NO_TLCP + tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_SM2_ENC); + tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_SM2_SIGN); +#endif } /* User level utility function to check a chain is suitable */ @@ -2732,6 +2804,57 @@ static const SIGALG_LOOKUP *find_sig_alg(SSL *s, X509 *x, EVP_PKEY *pkey) return lu; } +#ifndef OPENSSL_NO_TLCP +static int tlcp_choose_sigalg(SSL *s, int fatalerrs) +{ + int sig_idx; + const SIGALG_LOOKUP *lu = NULL; + + // sever must used sm2dsa cert for signature + if (s->server) { + s->cert->key = &(s->cert->pkeys[SSL_PKEY_SM2_SIGN]); + } + + sig_idx = s->cert->key - s->cert->pkeys; + + // check cert is existed + if (!ssl_has_cert(s, sig_idx)) { + if (!fatalerrs) + return 1; + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CHOOSE_SIGALG, + ERR_R_INTERNAL_ERROR); + return 0; + } + + // only support sm2dsa cert now + switch(sig_idx) { + case SSL_PKEY_ECC: + if (!EVP_PKEY_is_sm2(s->cert->key->privatekey)) + break; + lu = tls1_lookup_sigalg(TLSEXT_SIGALG_sm2dsa_sm3); + break; + case SSL_PKEY_SM2_SIGN: + lu = tls1_lookup_sigalg(TLSEXT_SIGALG_sm2dsa_sm3); + break; + default: + lu = NULL; + } + + if (lu == NULL) { + if (!fatalerrs) + return 1; + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CHOOSE_SIGALG, + ERR_R_INTERNAL_ERROR); + return 0; + } + + s->s3->tmp.cert = &s->cert->pkeys[sig_idx]; + s->cert->key = s->s3->tmp.cert; + s->s3->tmp.sigalg = lu; + return 1; +} +#endif + /* * Choose an appropriate signature algorithm based on available certificates * Sets chosen certificate and signature algorithm. @@ -2751,6 +2874,12 @@ int tls_choose_sigalg(SSL *s, int fatalerrs) s->s3->tmp.cert = NULL; s->s3->tmp.sigalg = NULL; +#ifndef OPENSSL_NO_TLCP + if (SSL_IS_TLCP(s)) { + return tlcp_choose_sigalg(s, fatalerrs); + } +#endif + if (SSL_IS_TLS13(s)) { lu = find_sig_alg(s, NULL, NULL); if (lu == NULL) { @@ -2764,6 +2893,7 @@ int tls_choose_sigalg(SSL *s, int fatalerrs) /* If ciphersuite doesn't require a cert nothing to do */ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aCERT)) return 1; + if (!s->server && !ssl_has_cert(s, s->cert->key - s->cert->pkeys)) return 1; diff --git a/test/build.info b/test/build.info index 6357a7f2fe..dcd4989d4e 100644 --- a/test/build.info +++ b/test/build.info @@ -51,7 +51,7 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN recordlentest drbgtest drbg_cavs_test sslbuffertest \ time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \ servername_test ocspapitest rsa_mp_test fatalerrtest tls13ccstest \ - sysdefaulttest errtest ssl_ctx_test gosttest + sysdefaulttest errtest ssl_ctx_test gosttest tlcptest SOURCE[versions]=versions.c INCLUDE[versions]=../include @@ -320,6 +320,10 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN INCLUDE[dtlstest]=../include DEPEND[dtlstest]=../libcrypto ../libssl libtestutil.a + SOURCE[tlcptest]=tlcptest.c ssltestlib.c + INCLUDE[tlcptest]=.. ../include + DEPEND[tlcptest]=../libcrypto ../libssl libtestutil.a + SOURCE[sslcorrupttest]=sslcorrupttest.c ssltestlib.c INCLUDE[sslcorrupttest]=../include DEPEND[sslcorrupttest]=../libcrypto ../libssl libtestutil.a diff --git a/test/certs/sm2-ca-cert.pem b/test/certs/sm2-ca-cert.pem new file mode 100644 index 0000000000..70ce71e430 --- /dev/null +++ b/test/certs/sm2-ca-cert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICJzCCAcygAwIBAgIJAOlkpDpSrmVbMAoGCCqBHM9VAYN1MGgxCzAJBgNVBAYT +AkNOMQswCQYDVQQIDAJMTjERMA8GA1UEBwwIU2hlbnlhbmcxETAPBgNVBAoMCFRl +c3QgT3JnMRAwDgYDVQQLDAdUZXN0IE9VMRQwEgYDVQQDDAtUZXN0IFNNMiBDQTAg +Fw0yMjA2MDIxNTQ5MzlaGA8yMTIyMDUwOTE1NDkzOVowaDELMAkGA1UEBhMCQ04x +CzAJBgNVBAgMAkxOMREwDwYDVQQHDAhTaGVueWFuZzERMA8GA1UECgwIVGVzdCBP +cmcxEDAOBgNVBAsMB1Rlc3QgT1UxFDASBgNVBAMMC1Rlc3QgU00yIENBMFkwEwYH +KoZIzj0CAQYIKoEcz1UBgi0DQgAEdFieoSuh8F1c+m2+87v4FJUnFyke5Madn5Q+ +ttTmRURQxpSc054wlmX+9EaKZkKb8CRF4mZF+dvXkRIdH6yynqNdMFswHQYDVR0O +BBYEFMWNxa7/MmBJnlIpSVTlXHj/Rbl0MB8GA1UdIwQYMBaAFMWNxa7/MmBJnlIp +SVTlXHj/Rbl0MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoGCCqBHM9VAYN1 +A0kAMEYCIQC3c2TkO6Lyxt5GNZqoZNuMEphjL9K7W1TsX6mHzlhHDwIhAICXy2XC +WsTzdrMZUXLtrDDFOq+3FaD4pe1HP2LZFNpu +-----END CERTIFICATE----- diff --git a/test/certs/sm2-csr.pem b/test/certs/sm2-csr.pem new file mode 100644 index 0000000000..a6dcca8742 --- /dev/null +++ b/test/certs/sm2-csr.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBMTCB1wIBADB1MQswCQYDVQQGEwJDTjERMA8GA1UECAwITGlhb25pbmcxETAP +BgNVBAcMCFNoZW55YW5nMQwwCgYDVQQKDANUZXQxDDAKBgNVBAsMA1RldDELMAkG +A1UEAwwCb28xFzAVBgkqhkiG9w0BCQEWCG9vQG9vLm9vMFkwEwYHKoZIzj0CAQYI +KoEcz1UBgi0DQgAE1NjdOpldcjTkuZpdGDNyHAnhK9cB2RZ7jAmFzt7jgEs9OHSg +rb3crjz+qGZfqyJ5AyZulQ7gdARzb1H55jvw5qAAMAoGCCqBHM9VAYN1A0kAMEYC +IQCacUXA8kyTTDwEm89Yz9qjsbfd8/N32lnzKxuKCcXJwQIhAIpugCbfeWuPxUQO +7AvQS3yxBp1yn0FbTT2XVSyYy6To +-----END CERTIFICATE REQUEST----- diff --git a/test/certs/sm2-root.crt b/test/certs/sm2-root.crt new file mode 100644 index 0000000000..70ce71e430 --- /dev/null +++ b/test/certs/sm2-root.crt @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICJzCCAcygAwIBAgIJAOlkpDpSrmVbMAoGCCqBHM9VAYN1MGgxCzAJBgNVBAYT +AkNOMQswCQYDVQQIDAJMTjERMA8GA1UEBwwIU2hlbnlhbmcxETAPBgNVBAoMCFRl +c3QgT3JnMRAwDgYDVQQLDAdUZXN0IE9VMRQwEgYDVQQDDAtUZXN0IFNNMiBDQTAg +Fw0yMjA2MDIxNTQ5MzlaGA8yMTIyMDUwOTE1NDkzOVowaDELMAkGA1UEBhMCQ04x +CzAJBgNVBAgMAkxOMREwDwYDVQQHDAhTaGVueWFuZzERMA8GA1UECgwIVGVzdCBP +cmcxEDAOBgNVBAsMB1Rlc3QgT1UxFDASBgNVBAMMC1Rlc3QgU00yIENBMFkwEwYH +KoZIzj0CAQYIKoEcz1UBgi0DQgAEdFieoSuh8F1c+m2+87v4FJUnFyke5Madn5Q+ +ttTmRURQxpSc054wlmX+9EaKZkKb8CRF4mZF+dvXkRIdH6yynqNdMFswHQYDVR0O +BBYEFMWNxa7/MmBJnlIpSVTlXHj/Rbl0MB8GA1UdIwQYMBaAFMWNxa7/MmBJnlIp +SVTlXHj/Rbl0MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoGCCqBHM9VAYN1 +A0kAMEYCIQC3c2TkO6Lyxt5GNZqoZNuMEphjL9K7W1TsX6mHzlhHDwIhAICXy2XC +WsTzdrMZUXLtrDDFOq+3FaD4pe1HP2LZFNpu +-----END CERTIFICATE----- diff --git a/test/certs/sm2-root.key b/test/certs/sm2-root.key new file mode 100644 index 0000000000..4bda65b5e6 --- /dev/null +++ b/test/certs/sm2-root.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQglktdVbLA5tyXMc+9 +KV4ikyDaFZNnXqfNAzUVqTlqn8GhRANCAAR0WJ6hK6HwXVz6bb7zu/gUlScXKR7k +xp2flD621OZFRFDGlJzTnjCWZf70RopmQpvwJEXiZkX529eREh0frLKe +-----END PRIVATE KEY----- diff --git a/test/certs/sm2.key b/test/certs/sm2.key new file mode 100644 index 0000000000..1efd3643b6 --- /dev/null +++ b/test/certs/sm2.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgSKhk+4xGyDI+IS2H +WVfFPDxh1qv5+wtrddaIsGNXGZihRANCAAQwqeNkWp7fiu1KZnuDkAucpM8piEzE +TL1ymrcrOBvv8mhNNkeb20asbWgFQI2zOrSM99/sXGn9rM2/usM/Mlca +-----END PRIVATE KEY----- diff --git a/test/certs/sm2.pem b/test/certs/sm2.pem new file mode 100644 index 0000000000..daf12926af --- /dev/null +++ b/test/certs/sm2.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICNDCCAdugAwIBAgIUOMbsiFLCy2BCPtfHQSdG4R1+3BowCgYIKoEcz1UBg3Uw +aDELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkxOMREwDwYDVQQHDAhTaGVueWFuZzER +MA8GA1UECgwIVGVzdCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFDASBgNVBAMMC1Rl +c3QgU00yIENBMCAXDTIyMDYwMjE1NTU0OFoYDzIxMjIwNTA5MTU1NTQ4WjBvMQsw +CQYDVQQGEwJDTjELMAkGA1UECAwCTE4xETAPBgNVBAcMCFNoZW55YW5nMREwDwYD +VQQKDAhUZXN0IE9yZzEQMA4GA1UECwwHVGVzdCBPVTEbMBkGA1UEAwwSVGVzdCBT +TTIgU2lnbiBDZXJ0MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEMKnjZFqe34rt +SmZ7g5ALnKTPKYhMxEy9cpq3Kzgb7/JoTTZHm9tGrG1oBUCNszq0jPff7Fxp/azN +v7rDPzJXGqNaMFgwCQYDVR0TBAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFNPl +u8JjXkhQPiJ5bYrrq+voqBUlMB8GA1UdIwQYMBaAFMWNxa7/MmBJnlIpSVTlXHj/ +Rbl0MAoGCCqBHM9VAYN1A0cAMEQCIG3gG1D7T7ltn6Gz1UksBZahgBE6jmkQ9Sp9 +/3aY5trlAiB5adxiK0avV0LEKfbzTdff9skoZpd7vje1QTW0l0HaGg== +-----END CERTIFICATE----- diff --git a/test/ciphername_test.c b/test/ciphername_test.c index 303e28f50f..5c9edf4e91 100644 --- a/test/ciphername_test.c +++ b/test/ciphername_test.c @@ -434,6 +434,9 @@ static int test_cipher_name(void) if ((id == 0xFF85) || (id == 0xFF87)) /* skip GOST2012-GOST8912-GOST891 and GOST2012-NULL-GOST12 */ continue; + if ((id == 0xE011) || (id == 0xE013)) + /* skip ECDHE_SM2_WITH_SM4_CBC_SM3 and ECC_SM2_WITH_SM4_CBC_SM3 */ + continue; p = SSL_CIPHER_standard_name(c); q = get_std_name_by_id(id); if (!TEST_ptr(p)) { diff --git a/test/recipes/20-test_pkeyutl.t b/test/recipes/20-test_pkeyutl.t new file mode 100644 index 0000000000..a36d41e78b --- /dev/null +++ b/test/recipes/20-test_pkeyutl.t @@ -0,0 +1,41 @@ +#! /usr/bin/env perl +# Copyright 2018 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 +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; +use warnings; + +use File::Spec; +use OpenSSL::Test qw/:DEFAULT srctop_file/; +use OpenSSL::Test::Utils; + +setup("test_pkeyutl"); + +plan tests => 2; + +# For the tests below we use the cert itself as the TBS file + +SKIP: { + skip "Skipping tests that require EC, SM2 or SM3", 2 + if disabled("ec") || disabled("sm2") || disabled("sm3"); + + # SM2 + ok(run(app(([ 'openssl', 'pkeyutl', '-sign', + '-in', srctop_file('test', 'certs', 'sm2.pem'), + '-inkey', srctop_file('test', 'certs', 'sm2.key'), + '-out', 'signature.dat', '-rawin', + '-digest', 'sm3', '-pkeyopt', 'sm2_id:someid']))), + "Sign a piece of data using SM2"); + ok(run(app(([ 'openssl', 'pkeyutl', '-verify', '-certin', + '-in', srctop_file('test', 'certs', 'sm2.pem'), + '-inkey', srctop_file('test', 'certs', 'sm2.pem'), + '-sigfile', 'signature.dat', '-rawin', + '-digest', 'sm3', '-pkeyopt', 'sm2_id:someid']))), + "Verify an SM2 signature against a piece of data"); +} + +unlink 'signature.dat'; diff --git a/test/recipes/25-test_req.t b/test/recipes/25-test_req.t index 383120c234..2b0c08c796 100644 --- a/test/recipes/25-test_req.t +++ b/test/recipes/25-test_req.t @@ -15,7 +15,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_req"); -plan tests => 14; +plan tests => 15; require_ok(srctop_file('test','recipes','tconversion.pl')); @@ -181,6 +181,43 @@ subtest "generating certificate requests" => sub { "Verifying signature on request"); }; +subtest "generating SM2 certificate requests" => sub { + plan tests => 5; + + SKIP: { + skip "SM2 is not supported by this OpenSSL build", 5 + 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"); + + # Use default sm2 id + ok(run(app(["openssl", "x509", "-req", "-extfile", srctop_file("test", "CAss.cnf"), + "-extensions", "v3_ca", "-sm3", "-days", "365", + "-in", "testreq.pem", "-signkey", srctop_file("test", "certs", "sm2.key"), + "-out", "testsign.pem"])), + "Signing SM2 certificate request"); + + ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"), + "-new", "-key", srctop_file("test", "certs", "sm2.key"), + "-sigopt", "sm2_hex_id:DEADBEEF", + "-out", "testreq.pem", "-sm3"])), + "Generating SM2 certificate request with hex id"); + + ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"), + "-verify", "-in", "testreq.pem", "-noout", + "-sm2-hex-id", "DEADBEEF", "-sm3"])), + "Verifying signature on SM2 certificate request"); + } +}; + my @openssl_args = ("req", "-config", srctop_file("apps", "openssl.cnf")); run_conversion('req conversions', @@ -188,7 +225,7 @@ run_conversion('req conversions', run_conversion('req conversions -- testreq2', srctop_file("test", "testreq2.pem")); -unlink "testkey.pem", "testreq.pem", "testreq_withattrs_pem.pem", "testreq_withattrs_der.pem"; +unlink "testkey.pem", "testreq.pem", "testreq_withattrs_pem.pem", "testreq_withattrs_der.pem", "testsign.pem"; sub run_conversion { my $title = shift; diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t index 0084dd234d..cb0f87368f 100644 --- a/test/recipes/25-test_verify.t +++ b/test/recipes/25-test_verify.t @@ -27,7 +27,7 @@ sub verify { run(app([@args])); } -plan tests => 148; +plan tests => 150; # Canonical success ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]), @@ -410,6 +410,18 @@ SKIP: { } +SKIP: { + skip "SM2 is not supported by this OpenSSL build", 2 + if disabled("sm2"); + + # Test '-sm2-id' and '-sm2-hex-id' option + ok(verify("sm2", "any", ["sm2-ca-cert"], [], "-sm2-id", "1234567812345678"), + "SM2 ID test"); + ok(verify("sm2", "any", ["sm2-ca-cert"], [], "-sm2-hex-id", + "31323334353637383132333435363738"), + "SM2 hex ID test"); +} + # Certificate Policies ok(verify("ee-cert-policies", "sslserver", ["root-cert"], ["ca-pol-cert"], "-policy_check", "-policy", "1.3.6.1.4.1.16604.998855.1", diff --git a/test/recipes/80-test_ca.t b/test/recipes/80-test_ca.t index 557777e191..92557cfe96 100644 --- a/test/recipes/80-test_ca.t +++ b/test/recipes/80-test_ca.t @@ -23,7 +23,7 @@ my $std_openssl_cnf = 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 @@ -51,9 +51,25 @@ plan tests => 5; '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 { diff --git a/test/recipes/85-test_tlcp.t b/test/recipes/85-test_tlcp.t new file mode 100644 index 0000000000..eb87123091 --- /dev/null +++ b/test/recipes/85-test_tlcp.t @@ -0,0 +1,34 @@ +#! /usr/bin/env perl +# Copyright 2022 Huawei Technologies Co., Ltd. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use OpenSSL::Test::Utils; +use OpenSSL::Test qw/:DEFAULT data_file/; + +setup("test_tlcp"); + +plan skip_all => "TLCP is not supported by this OpenSSL build" + if disabled("tlcp"); + +plan tests => 1; + +ok(run(test(["tlcptest", + data_file("sm2-root-cert.pem"), # 0 + data_file("sm2-server-sig-cert.pem"), # 1 + data_file("sm2-server-sig-key.pem"), # 2 + data_file("sm2-server-enc-cert.pem"), # 3 + data_file("sm2-server-enc-key.pem"), # 4 + data_file("sm2-client-sig-cert.pem"), # 5 + data_file("sm2-client-sig-key.pem"), # 6 + data_file("sm2-client-enc-cert.pem"), # 7 + data_file("sm2-client-enc-key.pem"), # 8 + data_file("ecdsa-root-cert.pem"), # 9 + data_file("ecdsa-server-cert.pem"), # 10 + data_file("ecdsa-server-key.pem"), # 11 + data_file("ecdsa-client-cert.pem"), # 12 + data_file("ecdsa-client-key.pem") # 13 + ]))); \ No newline at end of file diff --git a/test/recipes/85-test_tlcp_data/ecdsa-client-cert.pem b/test/recipes/85-test_tlcp_data/ecdsa-client-cert.pem new file mode 100644 index 0000000000..4f41232cb0 --- /dev/null +++ b/test/recipes/85-test_tlcp_data/ecdsa-client-cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2zCCAYGgAwIBAgIUIxUR+f5s2IPkP5kd86umC0jtOy0wCgYIKoZIzj0EAwIw +YDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz +dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxGDAWBgNVBAMMD1Rlc3QgQ0EgKEVDRFNB +KTAeFw0yMjA1MTkwOTI3MTVaFw0yNjA2MjcwOTI3MTVaMF8xCzAJBgNVBAYTAkNO +MRIwEAYDVQQIDAlHdWFuZ2RvbmcxETAPBgNVBAoMCFRlc3QgT3JnMRAwDgYDVQQL +DAdUZXN0IE9VMRcwFQYDVQQDDA5jbGllbnQgKEVDRFNBKTBZMBMGByqGSM49AgEG +CCqGSM49AwEHA0IABJg2jl8qqQkLHwcqKC+gu8SWpDNHl8x2xSlsNkS8hm2edlsJ +5QHfMPw7b138CmEE2FEtMqCtpRtsQnb5JRcxfTajGjAYMAkGA1UdEwQCMAAwCwYD +VR0PBAQDAgbAMAoGCCqGSM49BAMCA0gAMEUCICBPe4rSKQdIWdB3u8EZ9+AR6Slu +wsqdPm8p2mE409x4AiEAx513RsVDYohfejrvJmEL9ELIHmqTHjX+WjTjfMR/qrY= +-----END CERTIFICATE----- diff --git a/test/recipes/85-test_tlcp_data/ecdsa-client-key.pem b/test/recipes/85-test_tlcp_data/ecdsa-client-key.pem new file mode 100644 index 0000000000..8a356ba137 --- /dev/null +++ b/test/recipes/85-test_tlcp_data/ecdsa-client-key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgj/hA8kscmW1VDMMn +jWDNu/JrGrZ5Xr1kH0Q61zpRhIShRANCAASYNo5fKqkJCx8HKigvoLvElqQzR5fM +dsUpbDZEvIZtnnZbCeUB3zD8O29d/AphBNhRLTKgraUbbEJ2+SUXMX02 +-----END PRIVATE KEY----- diff --git a/test/recipes/85-test_tlcp_data/ecdsa-root-cert.pem b/test/recipes/85-test_tlcp_data/ecdsa-root-cert.pem new file mode 100644 index 0000000000..80d8c06081 --- /dev/null +++ b/test/recipes/85-test_tlcp_data/ecdsa-root-cert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICHzCCAcWgAwIBAgIUcxkoWsrQfKvdPzNFeZt9sUACCv8wCgYIKoZIzj0EAwIw +YDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz +dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxGDAWBgNVBAMMD1Rlc3QgQ0EgKEVDRFNB +KTAeFw0yMjA1MTkwOTI3MTVaFw0yNjA2MjcwOTI3MTVaMGAxCzAJBgNVBAYTAkNO +MRIwEAYDVQQIDAlHdWFuZ2RvbmcxETAPBgNVBAoMCFRlc3QgT3JnMRAwDgYDVQQL +DAdUZXN0IE9VMRgwFgYDVQQDDA9UZXN0IENBIChFQ0RTQSkwWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAAQb8M+p/ywfaaLb6y5jP/6essKMw+HBYIzluA8JpAyuSEag +hiiIegi/fJA9tONUKGGQrE92gFIjsyrGvwPnYqF1o10wWzAdBgNVHQ4EFgQU+BnE +9UFgm03egYusuG7wtBeF12kwHwYDVR0jBBgwFoAU+BnE9UFgm03egYusuG7wtBeF +12kwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCgYIKoZIzj0EAwIDSAAwRQIh +AO3LVs9OBinihB4W22ju3zoqfXTtHGdF0d9nbHbZEYqdAiAum1ZhMbtyWo/3YLDR +2DqMuw5al5FbOlCIwrMbqcL+qQ== +-----END CERTIFICATE----- diff --git a/test/recipes/85-test_tlcp_data/ecdsa-server-cert.pem b/test/recipes/85-test_tlcp_data/ecdsa-server-cert.pem new file mode 100644 index 0000000000..7e0d8d798f --- /dev/null +++ b/test/recipes/85-test_tlcp_data/ecdsa-server-cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2zCCAYGgAwIBAgIUIxUR+f5s2IPkP5kd86umC0jtOywwCgYIKoZIzj0EAwIw +YDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz +dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxGDAWBgNVBAMMD1Rlc3QgQ0EgKEVDRFNB +KTAeFw0yMjA1MTkwOTI3MTVaFw0yNjA2MjcwOTI3MTVaMF8xCzAJBgNVBAYTAkNO +MRIwEAYDVQQIDAlHdWFuZ2RvbmcxETAPBgNVBAoMCFRlc3QgT3JnMRAwDgYDVQQL +DAdUZXN0IE9VMRcwFQYDVQQDDA5zZXJ2ZXIgKEVDRFNBKTBZMBMGByqGSM49AgEG +CCqGSM49AwEHA0IABAAmT2rADtfh1M/AW6n3cgLm2kEq/StWWcFDQ/AmTz54nFMp +9AHt7xAqnizKl2UcdzUcDbhyBeNwjZ+80Eavvx2jGjAYMAkGA1UdEwQCMAAwCwYD +VR0PBAQDAgbAMAoGCCqGSM49BAMCA0gAMEUCIQC70m1KUdKAsLI8zq78azjV2r/Z +Oc6vwXfAqLKgF7EhtQIgYvh0XrMU9ETKKbfHORqJK+BD9DmFnAkxNpc9KVmN/D8= +-----END CERTIFICATE----- diff --git a/test/recipes/85-test_tlcp_data/ecdsa-server-key.pem b/test/recipes/85-test_tlcp_data/ecdsa-server-key.pem new file mode 100644 index 0000000000..9d9af8d29b --- /dev/null +++ b/test/recipes/85-test_tlcp_data/ecdsa-server-key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgqMLQcziYtVwg+30u +MvCIb3bYAfxAazvxQ8I69Jtml9uhRANCAAQAJk9qwA7X4dTPwFup93IC5tpBKv0r +VlnBQ0PwJk8+eJxTKfQB7e8QKp4sypdlHHc1HA24cgXjcI2fvNBGr78d +-----END PRIVATE KEY----- diff --git a/test/recipes/85-test_tlcp_data/sm2-client-enc-cert.pem b/test/recipes/85-test_tlcp_data/sm2-client-enc-cert.pem new file mode 100644 index 0000000000..4a3e3f0165 --- /dev/null +++ b/test/recipes/85-test_tlcp_data/sm2-client-enc-cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2DCCAYCgAwIBAgIUMsQnTMiHshN4IOMc/ydgCOWB3WQwCgYIKoEcz1UBg3Uw +XjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz +dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFjAUBgNVBAMMDVRlc3QgQ0EgKFNNMikw +HhcNMjIwNTE5MDkyNzEwWhcNMjYwNjI3MDkyNzEwWjBgMQswCQYDVQQGEwJDTjES +MBAGA1UECAwJR3Vhbmdkb25nMREwDwYDVQQKDAhUZXN0IE9yZzEQMA4GA1UECwwH +VGVzdCBPVTEYMBYGA1UEAwwPY2xpZW50IGVuYyhTTTIpMFkwEwYHKoZIzj0CAQYI +KoEcz1UBgi0DQgAEsjxuZnSYi2M2iL4vUqHFdegJqxALkFxq+XiA/C8vQSMOCDaz +8ZH1XrCwU3kMShiQyNM8AkjufKgCOGSB3B58qKMaMBgwCQYDVR0TBAIwADALBgNV +HQ8EBAMCAzgwCgYIKoEcz1UBg3UDRgAwQwIgcwaVeJ3pa/WUuR28r9+tGRg2EIEO +IOlzRUlo6mwqcDACHxugAc0CFsB1dUWLOJuwJtpYsEmNpNHwLzxa16cfW3w= +-----END CERTIFICATE----- diff --git a/test/recipes/85-test_tlcp_data/sm2-client-enc-key.pem b/test/recipes/85-test_tlcp_data/sm2-client-enc-key.pem new file mode 100644 index 0000000000..7a039915a9 --- /dev/null +++ b/test/recipes/85-test_tlcp_data/sm2-client-enc-key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQg5xwdNhYtjBcZ5YEd +VNu5609rYpePHUZUlQvlAJIqMB2hRANCAASyPG5mdJiLYzaIvi9SocV16AmrEAuQ +XGr5eID8Ly9BIw4INrPxkfVesLBTeQxKGJDI0zwCSO58qAI4ZIHcHnyo +-----END PRIVATE KEY----- diff --git a/test/recipes/85-test_tlcp_data/sm2-client-sig-cert.pem b/test/recipes/85-test_tlcp_data/sm2-client-sig-cert.pem new file mode 100644 index 0000000000..ce539a6fdf --- /dev/null +++ b/test/recipes/85-test_tlcp_data/sm2-client-sig-cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB3DCCAYKgAwIBAgIUMsQnTMiHshN4IOMc/ydgCOWB3WMwCgYIKoEcz1UBg3Uw +XjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz +dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFjAUBgNVBAMMDVRlc3QgQ0EgKFNNMikw +HhcNMjIwNTE5MDkyNzEwWhcNMjYwNjI3MDkyNzEwWjBiMQswCQYDVQQGEwJDTjES +MBAGA1UECAwJR3Vhbmdkb25nMREwDwYDVQQKDAhUZXN0IE9yZzEQMA4GA1UECwwH +VGVzdCBPVTEaMBgGA1UEAwwRY2xpZW50IHNpZ24gKFNNMikwWTATBgcqhkjOPQIB +BggqgRzPVQGCLQNCAAQDr0xTp4anFz8UHoMWyAWq/yYpiXdysF1dvciTvgET7CAA +PydlOnKQw2K1NguwiecT4/XCpZMmbvhthMcCsyywoxowGDAJBgNVHRMEAjAAMAsG +A1UdDwQEAwIGwDAKBggqgRzPVQGDdQNIADBFAiEA1pxw3tMJ6epz6r/wonHMWBE/ +3MBbRIsOq9xxhOhqhyECIBR0V+O51j3gsuDwSqSU81rYLXPaE0RGuhbdWOHi4bII +-----END CERTIFICATE----- diff --git a/test/recipes/85-test_tlcp_data/sm2-client-sig-key.pem b/test/recipes/85-test_tlcp_data/sm2-client-sig-key.pem new file mode 100644 index 0000000000..d2c537d811 --- /dev/null +++ b/test/recipes/85-test_tlcp_data/sm2-client-sig-key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQg0x2USJzgAonYJeiQ +VkBw/u6/uo6B9M88YVL3A1OmorKhRANCAAQDr0xTp4anFz8UHoMWyAWq/yYpiXdy +sF1dvciTvgET7CAAPydlOnKQw2K1NguwiecT4/XCpZMmbvhthMcCsyyw +-----END PRIVATE KEY----- diff --git a/test/recipes/85-test_tlcp_data/sm2-root-cert.pem b/test/recipes/85-test_tlcp_data/sm2-root-cert.pem new file mode 100644 index 0000000000..a20df8c123 --- /dev/null +++ b/test/recipes/85-test_tlcp_data/sm2-root-cert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICGjCCAcGgAwIBAgIUV3TWPlV09Vqm5/FpSqR7ryeGrfEwCgYIKoEcz1UBg3Uw +XjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz +dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFjAUBgNVBAMMDVRlc3QgQ0EgKFNNMikw +HhcNMjIwNTE5MDkyNzEwWhcNMjYwNjI3MDkyNzEwWjBeMQswCQYDVQQGEwJDTjES +MBAGA1UECAwJR3Vhbmdkb25nMREwDwYDVQQKDAhUZXN0IE9yZzEQMA4GA1UECwwH +VGVzdCBPVTEWMBQGA1UEAwwNVGVzdCBDQSAoU00yKTBZMBMGByqGSM49AgEGCCqB +HM9VAYItA0IABHsTJfkk1NiaYrPidOIQHCGWBs77fKEhXoG1uONGTfHEDhhhA3EX +QZBL9cVO//farVmKF9ipYR9GA4pk0wHtGEKjXTBbMB0GA1UdDgQWBBQ9YT+D7/Cv +3KqG4b9YxuWOSbMRRzAfBgNVHSMEGDAWgBQ9YT+D7/Cv3KqG4b9YxuWOSbMRRzAM +BgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjAKBggqgRzPVQGDdQNHADBEAiAOJ4al +v3c1AHBohqZQkAAZsY9+LSH/3/e3C4Q4jQsDUQIgUDJFXbXSUrsMoKFmkvHONmz+ +9zGXND9ctJ1Dineo9dI= +-----END CERTIFICATE----- diff --git a/test/recipes/85-test_tlcp_data/sm2-server-enc-cert.pem b/test/recipes/85-test_tlcp_data/sm2-server-enc-cert.pem new file mode 100644 index 0000000000..c7a5ef2dbb --- /dev/null +++ b/test/recipes/85-test_tlcp_data/sm2-server-enc-cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2jCCAYGgAwIBAgIUMsQnTMiHshN4IOMc/ydgCOWB3WIwCgYIKoEcz1UBg3Uw +XjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz +dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFjAUBgNVBAMMDVRlc3QgQ0EgKFNNMikw +HhcNMjIwNTE5MDkyNzEwWhcNMjYwNjI3MDkyNzEwWjBhMQswCQYDVQQGEwJDTjES +MBAGA1UECAwJR3Vhbmdkb25nMREwDwYDVQQKDAhUZXN0IE9yZzEQMA4GA1UECwwH +VGVzdCBPVTEZMBcGA1UEAwwQc2VydmVyIGVuYyAoU00yKTBZMBMGByqGSM49AgEG +CCqBHM9VAYItA0IABCWsJ/Vs/68DYkqIgoTdE8zoOA86UMHLASZriw+AF0lbmiOD +dngO7RvDd55OOAmFK6sY7d+vzsIeMNQus4YLkc2jGjAYMAkGA1UdEwQCMAAwCwYD +VR0PBAQDAgM4MAoGCCqBHM9VAYN1A0cAMEQCICZgP6OiaVyAbYTX5yJpiwusEvDU +bMB/+hpnNA0ors3zAiB4EkZEBWZkd0su+umAXpO44IYaDvUumPSaGZLBbg7m1w== +-----END CERTIFICATE----- diff --git a/test/recipes/85-test_tlcp_data/sm2-server-enc-key.pem b/test/recipes/85-test_tlcp_data/sm2-server-enc-key.pem new file mode 100644 index 0000000000..ae509ec2c7 --- /dev/null +++ b/test/recipes/85-test_tlcp_data/sm2-server-enc-key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgE32DrOaCm3ai/cPZ +/9nnxJoCH171qVL7ignjIrMBGdGhRANCAAQlrCf1bP+vA2JKiIKE3RPM6DgPOlDB +ywEma4sPgBdJW5ojg3Z4Du0bw3eeTjgJhSurGO3fr87CHjDULrOGC5HN +-----END PRIVATE KEY----- diff --git a/test/recipes/85-test_tlcp_data/sm2-server-sig-cert.pem b/test/recipes/85-test_tlcp_data/sm2-server-sig-cert.pem new file mode 100644 index 0000000000..8238badc37 --- /dev/null +++ b/test/recipes/85-test_tlcp_data/sm2-server-sig-cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2zCCAYKgAwIBAgIUMsQnTMiHshN4IOMc/ydgCOWB3WEwCgYIKoEcz1UBg3Uw +XjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz +dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFjAUBgNVBAMMDVRlc3QgQ0EgKFNNMikw +HhcNMjIwNTE5MDkyNzEwWhcNMjYwNjI3MDkyNzEwWjBiMQswCQYDVQQGEwJDTjES +MBAGA1UECAwJR3Vhbmdkb25nMREwDwYDVQQKDAhUZXN0IE9yZzEQMA4GA1UECwwH +VGVzdCBPVTEaMBgGA1UEAwwRc2VydmVyIHNpZ24gKFNNMikwWTATBgcqhkjOPQIB +BggqgRzPVQGCLQNCAAQgP2f+HnNb6BWCGscITDpf53BwVvpj3gxrlHz05Po3i2IA +qyL5yL2VE+bqTrxCFpQOHupjW3f5Bkihv7IUW/zMoxowGDAJBgNVHRMEAjAAMAsG +A1UdDwQEAwIGwDAKBggqgRzPVQGDdQNHADBEAiA63GVhHaDzcVJ9DMLK/53wQZvg +HR+tj4MCBtb6F9hL9QIgbojf0R49GnO6VYHHUx0fe+4+2DfAcMdVIutOmbpRc60= +-----END CERTIFICATE----- diff --git a/test/recipes/85-test_tlcp_data/sm2-server-sig-key.pem b/test/recipes/85-test_tlcp_data/sm2-server-sig-key.pem new file mode 100644 index 0000000000..f7fa712004 --- /dev/null +++ b/test/recipes/85-test_tlcp_data/sm2-server-sig-key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgr9nuyaNIE7aSQw/I +sc7JhizpuCPUNKBF9zZy1on8BHShRANCAAQgP2f+HnNb6BWCGscITDpf53BwVvpj +3gxrlHz05Po3i2IAqyL5yL2VE+bqTrxCFpQOHupjW3f5Bkihv7IUW/zM +-----END PRIVATE KEY----- diff --git a/test/sm2_internal_test.c b/test/sm2_internal_test.c index 4951cd3e30..0ab84b2d9a 100644 --- a/test/sm2_internal_test.c +++ b/test/sm2_internal_test.c @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include "testutil.h" #ifndef OPENSSL_NO_SM2 @@ -404,6 +406,114 @@ static int sm2_sig_test(void) return testresult; } +static EC_KEY* create_EC_key(EC_GROUP *group, const char *prv_hex, const char *x_hex, const char *y_hex) +{ + BIGNUM *prv = NULL; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + EC_KEY *key = NULL; + + if (!TEST_true(BN_hex2bn(&prv, prv_hex)) + || !TEST_true(BN_hex2bn(&x, x_hex)) + || !TEST_true(BN_hex2bn(&y, y_hex))) + goto err; + + if (!TEST_ptr(key = EC_KEY_new()) + || !TEST_true(EC_KEY_set_group(key, group)) + || !TEST_true(EC_KEY_set_private_key(key, prv)) + || !TEST_true(EC_KEY_set_public_key_affine_coordinates(key, x, y))) { + EC_KEY_free(key); + key = NULL; + } + +err: + BN_free(prv); + BN_free(x); + BN_free(y); + + return key; +} + +static int sm2_key_exchange_test(void) +{ + const char *userA = "ALICE123@YAHOO.COM"; + const char *userB = "BILL456@YAHOO.COM"; + const char *privA_hex = "6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEE"; + const char *pubA_x_hex = "3099093BF3C137D8FCBBCDF4A2AE50F3B0F216C3122D79425FE03A45DBFE1655"; + const char *pubA_y_hex = "3DF79E8DAC1CF0ECBAA2F2B49D51A4B387F2EFAF482339086A27A8E05BAED98B"; + const char *privB_hex = "5E35D7D3F3C54DBAC72E61819E730B019A84208CA3A35E4C2E353DFCCB2A3B53"; + const char *pubB_x_hex = "245493D446C38D8CC0F118374690E7DF633A8A4BFB3329B5ECE604B2B4F37F43"; + const char *pubB_y_hex = "53C0869F4B9E17773DE68FEC45E14904E0DEA45BF6CECF9918C85EA047C60A4C"; + const char *ra = "83A2C9C8B96E5AF70BD480B472409A9A327257F1EBB73F5B073354B248668563"; + const char *x1 = "6CB5633816F4DD560B1DEC458310CBCC6856C09505324A6D23150C408F162BF0"; + const char *y1 = "0D6FCF62F1036C0A1B6DACCF57399223A65F7D7BF2D9637E5BBBEB857961BF1A"; + const char *rb = "33FE21940342161C55619C4A0C060293D543C80AF19748CE176D83477DE71C80"; + const char *x2 = "1799B2A2C778295300D9A2325C686129B8F2B5337B3DCF4514E8BBC19D900EE5"; + const char *y2 = "54C9288C82733EFDF7808AE7F27D0E732F7C73A7D9AC98B7D8740A91D0DB3CF4"; + + EC_KEY *keyA = NULL; + EC_KEY *keyB = NULL; + EC_KEY *keyRa = NULL; + EC_KEY *keyRb = NULL; + + unsigned char Ka[16]; + unsigned char Kb[16]; + unsigned char K[] = {0x55, 0xB0, 0xAC, 0x62, 0xA6, 0xB9, 0x27, 0xBA, 0x23, 0x70, 0x38, 0x32, 0xC8, 0x53, 0xDE, 0xD4}; + + int ret = 0; + + EC_GROUP *test_group = + create_EC_group + ("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", + "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", + "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", + "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", + "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", + "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", + "1"); + + if (!TEST_ptr(keyA = create_EC_key(test_group, privA_hex, pubA_x_hex, pubA_y_hex)) + || !TEST_ptr(keyB = create_EC_key(test_group, privB_hex, pubB_x_hex, pubB_y_hex))) + goto done; + + if (!TEST_ptr(keyRa = create_EC_key(test_group, ra, x1, y1)) + || !TEST_ptr(keyRb = create_EC_key(test_group, rb, x2, y2))) + goto done; + + ret = SM2_compute_key(Ka, sizeof(Ka), 1, + userB, strlen(userB), userA, strlen(userA), + keyRb, keyRa, + keyB, keyA, + EVP_sm3()); + if (!TEST_int_eq(ret, sizeof(Ka))) { + ret = 0; + goto done; + } + + ret = SM2_compute_key(Kb, sizeof(Kb), 0, + userA, strlen(userA), userB, strlen(userB), + keyRa, keyRb, + keyA, keyB, + EVP_sm3()); + if (!TEST_int_eq(ret, sizeof(Kb))) { + ret = 0; + goto done; + } + + if (!TEST_mem_eq(Ka, sizeof(Ka), K, sizeof(K)) + || !TEST_mem_eq(Kb, sizeof(Kb), K, sizeof(K))) + ret = 0; + +done: + EC_KEY_free(keyA); + EC_KEY_free(keyB); + EC_KEY_free(keyRa); + EC_KEY_free(keyRb); + EC_GROUP_free(test_group); + + return ret; +} + #endif int setup_tests(void) @@ -413,6 +523,7 @@ int setup_tests(void) #else ADD_TEST(sm2_crypt_test); ADD_TEST(sm2_sig_test); + ADD_TEST(sm2_key_exchange_test); #endif return 1; } diff --git a/test/tlcptest.c b/test/tlcptest.c new file mode 100644 index 0000000000..b508f3f6e6 --- /dev/null +++ b/test/tlcptest.c @@ -0,0 +1,746 @@ +/* + * Copyright 2022 Huawei Technologies Co., Ltd. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include + +#include "internal/nelem.h" +#include "ssltestlib.h" +#include "testutil.h" + +#ifndef OPENSSL_NO_TLCP + +typedef enum { + IDX_SM2_ROOT_CERT = 0, + IDX_SM2_SERVER_SIG_CERT, + IDX_SM2_SERVER_SIG_KEY, + IDX_SM2_SERVER_ENC_CERT, + IDX_SM2_SERVER_ENC_KEY, + IDX_SM2_CLIENT_SIG_CERT, + IDX_SM2_CLIENT_SIG_KEY, + IDX_SM2_CLIENT_ENC_CERT, + IDX_SM2_CLIENT_ENC_KEY, + IDX_ECDSA_ROOT_CERT, + IDX_ECDSA_SERVER_CERT, + IDX_ECDSA_SERVER_KEY, + IDX_ECDSA_CLIENT_CERT, + IDX_ECDSA_CLIENT_KEY, + IDX_MAX +} TEST_FILES_IDX; + +#define OPTION_IS_CA 0x00000001U +#define OPTION_IS_CERT 0x00000002U +#define OPTION_IS_KEY 0x00000004U +#define OPTION_USE_NEWAPI 0x00000008U +#define OPTION_USE_EXTRA 0x00000010U +#define OPTION_IS_SIG 0x00000020U +#define OPTION_IS_ENC 0x00000040U + +typedef struct { + TEST_FILES_IDX idx; + int flag; +} LOAD_OPTION; + +typedef struct { + const char *method_name; + const char *sid_ctx; + int verify_mode; + int ssl_options; + int set_version; + LOAD_OPTION load_options[IDX_MAX]; +} SSL_CTX_OPTION; +typedef struct { + const char *case_name; + SSL_CTX_OPTION server; + SSL_CTX_OPTION client; + const char *ciphersuite; + const char *expected_version; + const char *expected_cipher; + int regenotiate; + int reuse_session; +} TLCP_TEST_CASE; + +static const TLCP_TEST_CASE tlcp_test_cases[] = { + { "test_ecc_and_cert_position", + { + "TLS_server", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + "ECC-SM4-CBC-SM3", + "TLCP", + "ECC-SM4-CBC-SM3", + 0, 0 + }, + { "test_extra_cert", + { + "TLS_server", NULL, SSL_VERIFY_NONE, 0, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA | OPTION_USE_EXTRA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLCP_client", NULL, SSL_VERIFY_NONE, 0, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA | OPTION_USE_EXTRA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + "ECC-SM4-CBC-SM3", + "TLCP", + "ECC-SM4-CBC-SM3", + 0, 0 + }, + { "test_ssl_op_no", + { + "TLS_server", NULL, SSL_VERIFY_PEER, SSL_OP_NO_TLSv1_3 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1 | SSL_OP_NO_SSLv3, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLS_client", NULL, SSL_VERIFY_PEER, SSL_OP_NO_TLSv1_3 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1 | SSL_OP_NO_SSLv3, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + "ECC-SM4-CBC-SM3", + "TLCP", + "ECC-SM4-CBC-SM3", + 0, 0 + }, + { "test_set_version_bound", + { + "TLCP_server", NULL, SSL_VERIFY_PEER, 0, TLCP_VERSION, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLS_client", NULL, SSL_VERIFY_PEER, 0, TLCP_VERSION, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + NULL, + "TLCP", + "ECC-SM4-CBC-SM3", + 0, 0 + }, + { "test_use_old_api_and_other_certs", + { + "TLS_server", NULL, SSL_VERIFY_PEER, 0, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_IS_ENC | OPTION_IS_KEY }, + {IDX_ECDSA_ROOT_CERT, OPTION_IS_CA}, + {IDX_ECDSA_SERVER_CERT, OPTION_IS_CERT}, + {IDX_ECDSA_SERVER_KEY, OPTION_IS_KEY} + } + }, + { + "TLCP_client", NULL, SSL_VERIFY_PEER, 0, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_IS_ENC | OPTION_IS_KEY }, + {IDX_ECDSA_ROOT_CERT, OPTION_IS_CA}, + {IDX_ECDSA_CLIENT_CERT, OPTION_IS_CERT}, + {IDX_ECDSA_CLIENT_KEY, OPTION_IS_KEY} + } + }, + NULL, + "TLCP", + "ECC-SM4-CBC-SM3", + 0, 0 + }, + { "test_sm2dhe_and_cert_position", + { + "TLS_server", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + "ECDHE-SM4-CBC-SM3", + "TLCP", + "ECDHE-SM4-CBC-SM3", + 0, 0 + }, + { "test_ecc_regenotiate", + { + "TLS_server", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + "ECC-SM4-CBC-SM3", + "TLCP", + "ECC-SM4-CBC-SM3", + 1, 0 + }, + { "test_sm2dhe_regenotiate", + { + "TLS_server", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + "ECDHE-SM4-CBC-SM3", + "TLCP", + "ECDHE-SM4-CBC-SM3", + 1, 0 + }, + { "test_ecc_reused_sessionid", + { + "TLS_server", "TEST", SSL_VERIFY_PEER, SSL_OP_NO_TICKET | SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_NO_TICKET | SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + "ECC-SM4-CBC-SM3", + "TLCP", + "ECC-SM4-CBC-SM3", + 0, 1 + }, + { "test_sm2dhe_reused_sessionid", + { + "TLS_server", "TEST", SSL_VERIFY_PEER, SSL_OP_NO_TICKET | SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_NO_TICKET | SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + "ECDHE-SM4-CBC-SM3", + "TLCP", + "ECDHE-SM4-CBC-SM3", + 0, 1 + }, + { "test_ecc_reused_ticket", + { + "TLS_server", NULL, SSL_VERIFY_NONE, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLCP_client", NULL, SSL_VERIFY_NONE, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + "ECC-SM4-CBC-SM3", + "TLCP", + "ECC-SM4-CBC-SM3", + 0, 1 + }, + { "test_sm2dhe_reused_ticket", + { + "TLS_server", NULL, SSL_VERIFY_NONE, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + { + "TLCP_client", NULL, SSL_VERIFY_NONE, SSL_OP_ENCCERT_SECOND_POSITION, 0, + { + {IDX_SM2_ROOT_CERT, OPTION_IS_CA}, + {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY }, + {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT }, + {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY } + } + }, + "ECDHE-SM4-CBC-SM3", + "TLCP", + "ECDHE-SM4-CBC-SM3", + 0, 1 + }, +}; + +static const char *test_files[IDX_MAX]; + +static X509 *PEM_file_to_X509(const char *file) +{ + BIO *in; + X509 *x = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL || BIO_read_filename(in, file) <= 0) + goto err; + + x = PEM_read_bio_X509(in, NULL, NULL, NULL); +err: + BIO_free(in); + return x; +} + +static EVP_PKEY *PEM_file_to_PrivateKey(const char *file) +{ + BIO *in; + EVP_PKEY *pkey = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL || BIO_read_filename(in, file) <= 0) + goto err; + + pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); +err: + BIO_free(in); + return pkey; +} + +static int use_extra_cert_file(SSL_CTX *ctx, const char *file) +{ + X509 *x; + + x = PEM_file_to_X509(file); + + if (x == NULL) + return 0; + + if (!SSL_CTX_add_extra_chain_cert(ctx, x)) { + X509_free(x); + return 0; + } + return 1; +} + +static int load_test_file_by_option(SSL_CTX *ctx, LOAD_OPTION opt) +{ + int usage = -1; + if (opt.idx >= IDX_MAX) + return 0; + + if (opt.flag & OPTION_IS_CA) { + return (opt.flag & OPTION_USE_EXTRA) + ? use_extra_cert_file(ctx, test_files[opt.idx]) + : SSL_CTX_load_verify_locations(ctx, test_files[opt.idx], NULL); + } + + if (opt.flag & OPTION_IS_SIG) { + usage = SSL_USAGE_SIG; + } else if (opt.flag & OPTION_IS_ENC) { + usage = SSL_USAGE_ENC; + } + + if (opt.flag & OPTION_IS_CERT) { + return (opt.flag & OPTION_USE_NEWAPI) + ? SSL_CTX_use_gm_certificate_file(ctx, test_files[opt.idx], SSL_FILETYPE_PEM, usage) + : SSL_CTX_use_certificate_file(ctx, test_files[opt.idx], SSL_FILETYPE_PEM); + } else if (opt.flag & OPTION_IS_KEY){ + return (opt.flag & OPTION_USE_NEWAPI) + ? SSL_CTX_use_gm_PrivateKey_file(ctx, test_files[opt.idx], SSL_FILETYPE_PEM, usage) + : SSL_CTX_use_PrivateKey_file(ctx, test_files[opt.idx], SSL_FILETYPE_PEM); + } + return 1; +} + +static int load_test_files(SSL_CTX *ctx, LOAD_OPTION *opt, size_t optlen) +{ + size_t i; + for (i = 0; i < optlen; ++i) { + if (!load_test_file_by_option(ctx, opt[i])) { + return 0; + } + } + return 1; +} + +static SSL_CTX *SSL_CTX_create_by_option(const SSL_CTX_OPTION *opt) +{ + SSL_CTX *ctx = NULL; + if (opt == NULL) + return NULL; + + if (strcmp(opt->method_name, "TLS_server") == 0) { + ctx = SSL_CTX_new(TLS_server_method()); + } else if (strcmp(opt->method_name, "TLS_client") == 0) { + ctx = SSL_CTX_new(TLS_client_method()); + } else if (strcmp(opt->method_name, "TLCP_server") == 0) { + ctx = SSL_CTX_new(TLCP_server_method()); + } else if (strcmp(opt->method_name, "TLCP_client") == 0) { + ctx = SSL_CTX_new(TLCP_client_method()); + } + if (ctx == NULL) + return NULL; + + SSL_CTX_set_verify(ctx, opt->verify_mode, NULL); + SSL_CTX_set_options(ctx, opt->ssl_options); + SSL_CTX_set_min_proto_version(ctx, opt->set_version); + SSL_CTX_set_max_proto_version(ctx, opt->set_version); + + if (opt->sid_ctx + && SSL_CTX_set_session_id_context(ctx, (unsigned char*)opt->sid_ctx, strlen(opt->sid_ctx)) != 1) { + SSL_CTX_free(ctx); + return NULL; + } + + if (!load_test_files(ctx, (LOAD_OPTION *)opt->load_options, OSSL_NELEM(opt->load_options))) { + SSL_CTX_free(ctx); + return NULL; + } + return ctx; +} + +static int test_tlcp_regenotiate(SSL *server_ssl, SSL *client_ssl) +{ + SSL_SESSION *sess_pre; + SSL_SESSION *sess_post; + + if (!TEST_ptr(sess_pre = SSL_get0_session(server_ssl))) + return 0; + + if (!TEST_int_eq(SSL_renegotiate(client_ssl), 1) + || !TEST_int_eq(SSL_renegotiate_pending(client_ssl), 1)) + return 0; + + for (int i = 0; i < 3; i++) { + unsigned char buf; + size_t readbytes; + int ret = SSL_read_ex(client_ssl, &buf, sizeof(buf), &readbytes); + if ((ret > 0 && !TEST_ulong_eq(readbytes, 0)) + || (ret <= 0 && !TEST_int_eq(SSL_get_error(client_ssl, 0), SSL_ERROR_WANT_READ))) { + return 0; + } + + ret = SSL_read_ex(server_ssl, &buf, sizeof(buf), &readbytes); + if ((ret > 0 && !TEST_ulong_eq(readbytes, 0)) + || (ret <= 0 && SSL_get_error(server_ssl, 0) != SSL_ERROR_WANT_READ)) { + if (!strcmp("ECDHE-SM4-CBC-SM3", SSL_CIPHER_get_name(SSL_get_current_cipher(client_ssl)))) + return 1; + return 0; + } + } + + if (!TEST_false(SSL_renegotiate_pending(client_ssl)) + || !TEST_int_eq(SSL_session_reused(client_ssl), 0) + || !TEST_int_eq(SSL_session_reused(server_ssl), 0) + || !TEST_ptr(sess_post = SSL_get0_session(server_ssl)) + || !TEST_ptr_ne(sess_pre, sess_post)) + return 0; + + return 1; +} + +static int test_tlcp_reuse_session(SSL **p_server_ssl, SSL **p_client_ssl) +{ + int ret = 0; + SSL *server_ssl = *p_server_ssl; + SSL *client_ssl = *p_client_ssl; + SSL_CTX *server_ctx; + SSL_CTX *client_ctx; + SSL_SESSION *sess_pre; + SSL_SESSION *sess_post; + SSL_SESSION *sess; + const unsigned char *sess_pre_id; + unsigned int sess_pre_id_len; + const unsigned char *sess_post_id; + unsigned int sess_post_id_len; + const char *ciph_name = SSL_CIPHER_get_name(SSL_get_current_cipher(client_ssl)); + + if (!TEST_ptr(server_ctx = SSL_get_SSL_CTX(server_ssl)) + || !TEST_ptr(client_ctx = SSL_get_SSL_CTX(client_ssl))) + return 0; + + if (!TEST_ptr(sess_pre = SSL_get0_session(server_ssl))) + return 0; + + if (!TEST_ptr(sess = SSL_get1_session(client_ssl))) + return 0; + + shutdown_ssl_connection(server_ssl, client_ssl); + *p_server_ssl = NULL; + *p_client_ssl = NULL; + + if (!TEST_int_eq(create_ssl_objects(server_ctx, client_ctx, p_server_ssl, p_client_ssl, NULL, NULL), 1)) + goto out; + + server_ssl = *p_server_ssl; + client_ssl = *p_client_ssl; + + if (!TEST_int_eq(SSL_set_session(client_ssl, sess), 1)) + goto out; + + if (!TEST_int_eq(create_ssl_connection(server_ssl, client_ssl, SSL_ERROR_NONE), 1)) + goto out; + + if (!TEST_int_eq(SSL_session_reused(client_ssl), 1) + || !TEST_int_eq(SSL_session_reused(server_ssl), 1)) + goto out; + + if (!TEST_ptr(sess_post = SSL_get0_session(server_ssl)) + || !TEST_str_eq(ciph_name, SSL_CIPHER_get_name(SSL_get_current_cipher(client_ssl)))) + goto out; + + if ((SSL_get_options(client_ssl) & SSL_OP_NO_TICKET) && (SSL_get_options(server_ssl) & SSL_OP_NO_TICKET) + && !TEST_ptr_eq(sess_pre, sess_post)) + goto out; + + sess_post_id = SSL_SESSION_get_id(sess_post, &sess_post_id_len); + sess_pre_id = SSL_SESSION_get_id(sess, &sess_pre_id_len); + + if (!TEST_mem_eq(sess_pre_id, sess_pre_id_len, sess_post_id, sess_post_id_len)) + goto out; + + ret = 1; + +out: + SSL_SESSION_free(sess); + + return ret; +} + +static int test_tlcp_ciphersuites(int idx) +{ + int result = 0; + SSL_CTX *server_ctx = NULL; + SSL_CTX *client_ctx = NULL; + SSL *server_ssl = NULL; + SSL *client_ssl = NULL; + const TLCP_TEST_CASE *case_ptr; + + case_ptr = &tlcp_test_cases[idx]; + if (!TEST_ptr(server_ctx = SSL_CTX_create_by_option(&case_ptr->server)) + || !TEST_ptr(client_ctx = SSL_CTX_create_by_option(&case_ptr->client))) + goto err; + + if (case_ptr->ciphersuite != NULL && + !TEST_int_eq(SSL_CTX_set_cipher_list(client_ctx, case_ptr->ciphersuite), 1)) + goto err; + + if (!TEST_int_eq(create_ssl_objects(server_ctx, client_ctx + , &server_ssl, &client_ssl, NULL, NULL), 1)) + goto err; + + if (!TEST_int_eq(create_ssl_connection(server_ssl, client_ssl, SSL_ERROR_NONE), 1)) + goto err; + + if (case_ptr->expected_version != NULL && + !TEST_str_eq(SSL_get_version(client_ssl), case_ptr->expected_version)) + goto err; + + if (case_ptr->expected_cipher && + !TEST_str_eq(SSL_get_cipher(client_ssl), case_ptr->expected_cipher)) + goto err; + + if (case_ptr->regenotiate + && !TEST_int_eq(test_tlcp_regenotiate(server_ssl, client_ssl), 1)) + goto err; + + if (case_ptr->reuse_session + && !TEST_int_eq(test_tlcp_reuse_session(&server_ssl, &client_ssl), 1)) + goto err; + + result = 1; +err: + if (server_ssl != NULL) + SSL_shutdown(server_ssl); + if (client_ssl != NULL) + SSL_shutdown(client_ssl); + SSL_free(server_ssl); + SSL_free(client_ssl); + SSL_CTX_free(server_ctx); + SSL_CTX_free(client_ctx); + return result; +} + +static int test_use_certs_and_keys(void) +{ + SSL_CTX *ctx = NULL; + SSL *ssl = NULL; + X509 *x = NULL; + EVP_PKEY *pkey = NULL; + int result = 0; + + ctx = SSL_CTX_new(TLCP_method()); + if (ctx == NULL) + goto err; + + ssl = SSL_new(ctx); + if (ssl == NULL) + goto err; + + if (!TEST_int_ne(SSL_use_gm_certificate_file(ssl, test_files[IDX_ECDSA_SERVER_CERT], + SSL_FILETYPE_PEM, SSL_USAGE_SIG), 1) + || !TEST_int_ne(SSL_use_gm_PrivateKey_file(ssl, test_files[IDX_ECDSA_CLIENT_KEY], + SSL_FILETYPE_PEM, SSL_USAGE_SIG), 1)) { + goto err; + } + + if (!TEST_int_eq(SSL_use_certificate_file(ssl, test_files[IDX_SM2_SERVER_SIG_CERT], + SSL_FILETYPE_PEM), 1) + || !TEST_int_eq(SSL_use_gm_PrivateKey_file(ssl, test_files[IDX_SM2_SERVER_SIG_KEY], + SSL_FILETYPE_PEM, SSL_USAGE_SIG), 1) + || !TEST_int_eq(SSL_use_gm_certificate_file(ssl, test_files[IDX_SM2_SERVER_ENC_CERT], + SSL_FILETYPE_PEM, SSL_USAGE_ENC), 1) + || !TEST_int_eq(SSL_use_PrivateKey_file(ssl, test_files[IDX_SM2_SERVER_ENC_KEY], + SSL_FILETYPE_PEM), 1)){ + goto err; + } + + if (!TEST_ptr(x = PEM_file_to_X509(test_files[IDX_SM2_CLIENT_SIG_CERT])) + || !TEST_ptr(pkey = PEM_file_to_PrivateKey(test_files[IDX_SM2_CLIENT_SIG_KEY])) + || !TEST_int_eq(SSL_use_gm_cert_and_key(ssl, x, pkey, NULL, 1, SSL_USAGE_SIG), 1)) { + goto err; + } + result = 1; +err: + X509_free(x); + + EVP_PKEY_free(pkey); + SSL_free(ssl); + SSL_CTX_free(ctx); + return result; +} + +#endif + +int setup_tests(void) +{ +#ifndef OPENSSL_NO_TLCP + int argc; + + for (argc = 0; argc < IDX_MAX; ++argc) { + if (!TEST_ptr(test_files[argc] = test_get_argument(argc))) { + return 0; + } + } + + ADD_ALL_TESTS(test_tlcp_ciphersuites, OSSL_NELEM(tlcp_test_cases)); + ADD_TEST(test_use_certs_and_keys); +#endif + return 1; +} diff --git a/test/verify_extra_test.c b/test/verify_extra_test.c index b6bffde91e..cc00abf720 100644 --- a/test/verify_extra_test.c +++ b/test/verify_extra_test.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -24,6 +25,7 @@ static char *good_f = NULL; static char *sroot_cert = NULL; static char *ca_cert = NULL; static char *ee_cert = NULL; +static char *req_f = NULL; static X509 *load_cert_pem(const char *file) { @@ -304,6 +306,88 @@ static int test_purpose_any(void) return do_test_purpose(X509_PURPOSE_ANY, 1); } +#ifndef OPENSSL_NO_SM2 +static int test_sm2_id(void) +{ + /* we only need an X509 structure, no matter if it's a real SM2 cert */ + X509 *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(bad_f, "r"); + if (bio == NULL) + goto err; + + x = PEM_read_bio_X509(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_set0_sm2_id(x, v); + + v2 = X509_get0_sm2_id(x); + if (!TEST_ptr(v2) + || !TEST_int_eq(ASN1_OCTET_STRING_cmp(v, v2), 0)) + goto err; + + ret = 1; + err: + X509_free(x); + 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(certs_dir = test_get_argument(0))) { @@ -315,6 +399,7 @@ int setup_tests(void) || !TEST_ptr(untrusted_f = test_mk_file_path(certs_dir, "untrusted.pem")) || !TEST_ptr(bad_f = test_mk_file_path(certs_dir, "bad.pem")) || !TEST_ptr(good_f = test_mk_file_path(certs_dir, "rootCA.pem")) + || !TEST_ptr(req_f = test_mk_file_path(certs_dir, "sm2-csr.pem")) || !TEST_ptr(sroot_cert = test_mk_file_path(certs_dir, "sroot-cert.pem")) || !TEST_ptr(ca_cert = test_mk_file_path(certs_dir, "ca-cert.pem")) || !TEST_ptr(ee_cert = test_mk_file_path(certs_dir, "ee-cert.pem"))) @@ -324,6 +409,10 @@ int setup_tests(void) ADD_TEST(test_store_ctx); ADD_TEST(test_self_signed_good); ADD_TEST(test_self_signed_bad); +#ifndef OPENSSL_NO_SM2 + ADD_TEST(test_sm2_id); + ADD_TEST(test_req_sm2_id); +#endif ADD_TEST(test_purpose_ssl_client); ADD_TEST(test_purpose_ssl_server); ADD_TEST(test_purpose_any); @@ -339,6 +428,7 @@ void cleanup_tests(void) OPENSSL_free(untrusted_f); OPENSSL_free(bad_f); OPENSSL_free(good_f); + OPENSSL_free(req_f); OPENSSL_free(sroot_cert); OPENSSL_free(ca_cert); OPENSSL_free(ee_cert); diff --git a/util/libcrypto.num b/util/libcrypto.num index 797dac999e..d4e3011793 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4593,3 +4593,9 @@ X509_REQ_set1_signature_algo 4546 1_1_1h EXIST::FUNCTION: EC_KEY_decoded_from_explicit_params 4547 1_1_1h EXIST::FUNCTION:EC EVP_sm4_xts 4548 1_1_1x EXIST::FUNCTION:SM4 CRYPTO_xts128gb_encrypt 4549 1_1_1x EXIST::FUNCTION: +X509_set0_sm2_id 4550 1_1_1x EXIST::FUNCTION:SM2 +X509_get0_sm2_id 4551 1_1_1x EXIST::FUNCTION:SM2 +X509_REQ_get0_sm2_id 4552 1_1_1x EXIST::FUNCTION:SM2 +X509_REQ_set0_sm2_id 4553 1_1_1x EXIST::FUNCTION:SM2 +EVP_PKEY_is_sm2 4554 1_1_1x EXIST::FUNCTION:SM2 +SM2_compute_key 4555 1_1_1x EXIST::FUNCTION:SM2 diff --git a/util/libssl.num b/util/libssl.num index 297522c363..f120bed625 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -498,3 +498,20 @@ SSL_CTX_get_recv_max_early_data 498 1_1_1 EXIST::FUNCTION: SSL_CTX_set_recv_max_early_data 499 1_1_1 EXIST::FUNCTION: SSL_CTX_set_post_handshake_auth 500 1_1_1 EXIST::FUNCTION: SSL_get_signature_type_nid 501 1_1_1a EXIST::FUNCTION: +SSL_use_gm_PrivateKey 502 1_1_1m EXIST::FUNCTION:TLCP +SSL_CTX_use_gm_certificate_file 503 1_1_1m EXIST::FUNCTION:TLCP +SSL_CTX_use_gm_certificate 504 1_1_1m EXIST::FUNCTION:TLCP +SSL_use_gm_certificate_file 505 1_1_1m EXIST::FUNCTION:TLCP +SSL_CTX_use_gm_certificate_ASN1 506 1_1_1m EXIST::FUNCTION:TLCP +SSL_use_gm_PrivateKey_file 507 1_1_1m EXIST::FUNCTION:TLCP +TLCP_method 508 1_1_1m EXIST::FUNCTION:TLCP +SSL_CTX_use_gm_PrivateKey_file 509 1_1_1m EXIST::FUNCTION:TLCP +SSL_use_gm_PrivateKey_ASN1 510 1_1_1m EXIST::FUNCTION:TLCP +TLCP_client_method 511 1_1_1m EXIST::FUNCTION:TLCP +SSL_CTX_use_gm_cert_and_key 512 1_1_1m EXIST::FUNCTION:TLCP +SSL_CTX_use_gm_PrivateKey 513 1_1_1m EXIST::FUNCTION:TLCP +TLCP_server_method 514 1_1_1m EXIST::FUNCTION:TLCP +SSL_use_gm_cert_and_key 515 1_1_1m EXIST::FUNCTION:TLCP +SSL_use_gm_certificate 516 1_1_1m EXIST::FUNCTION:TLCP +SSL_use_gm_certificate_ASN1 517 1_1_1m EXIST::FUNCTION:TLCP +SSL_CTX_use_gm_PrivateKey_ASN1 518 1_1_1m EXIST::FUNCTION:TLCP -- Gitee