1*6ddee6b2Stb /* $OpenBSD: sm2_sign.c,v 1.4 2023/07/05 17:36:19 tb Exp $ */
251892d90Stb /*
351892d90Stb * Copyright (c) 2017, 2019 Ribose Inc
451892d90Stb *
551892d90Stb * Permission to use, copy, modify, and/or distribute this software for any
651892d90Stb * purpose with or without fee is hereby granted, provided that the above
751892d90Stb * copyright notice and this permission notice appear in all copies.
851892d90Stb *
951892d90Stb * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1051892d90Stb * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1151892d90Stb * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1251892d90Stb * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1351892d90Stb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1451892d90Stb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1551892d90Stb * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1651892d90Stb */
1751892d90Stb
1851892d90Stb #ifndef OPENSSL_NO_SM2
1951892d90Stb
2051892d90Stb #include <string.h>
2151892d90Stb
2251892d90Stb #include <openssl/sm2.h>
2351892d90Stb #include <openssl/evp.h>
2451892d90Stb #include <openssl/err.h>
2551892d90Stb #include <openssl/bn.h>
2651892d90Stb
27c9675a23Stb #include "bn_local.h"
28c9675a23Stb #include "sm2_local.h"
2951892d90Stb
3051892d90Stb static BIGNUM *
sm2_compute_msg_hash(const EVP_MD * digest,const EC_KEY * key,const uint8_t * uid,size_t uid_len,const uint8_t * msg,size_t msg_len)3151892d90Stb sm2_compute_msg_hash(const EVP_MD *digest, const EC_KEY *key,
3251892d90Stb const uint8_t *uid, size_t uid_len, const uint8_t *msg, size_t msg_len)
3351892d90Stb {
3451892d90Stb EVP_MD_CTX *hash;
3551892d90Stb BIGNUM *e = NULL;
3651892d90Stb int md_size;
3751892d90Stb uint8_t *za = NULL;
3851892d90Stb
3951892d90Stb if ((hash = EVP_MD_CTX_new()) == NULL) {
4051892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
4151892d90Stb goto err;
4251892d90Stb }
4351892d90Stb
4451892d90Stb if ((md_size = EVP_MD_size(digest)) < 0) {
4551892d90Stb SM2error(SM2_R_INVALID_DIGEST);
4651892d90Stb goto err;
4751892d90Stb }
4851892d90Stb
4951892d90Stb if ((za = calloc(1, md_size)) == NULL) {
5051892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
5151892d90Stb goto err;
5251892d90Stb }
5351892d90Stb
5451892d90Stb if (!sm2_compute_userid_digest(za, digest, uid, uid_len, key)) {
5551892d90Stb SM2error(SM2_R_DIGEST_FAILURE);
5651892d90Stb goto err;
5751892d90Stb }
5851892d90Stb
5951892d90Stb if (!EVP_DigestInit(hash, digest)) {
6051892d90Stb SM2error(ERR_R_EVP_LIB);
6151892d90Stb goto err;
6251892d90Stb }
6351892d90Stb
6451892d90Stb if (!EVP_DigestUpdate(hash, za, md_size)) {
6551892d90Stb SM2error(ERR_R_EVP_LIB);
6651892d90Stb goto err;
6751892d90Stb }
6851892d90Stb
6951892d90Stb if (!EVP_DigestUpdate(hash, msg, msg_len)) {
7051892d90Stb SM2error(ERR_R_EVP_LIB);
7151892d90Stb goto err;
7251892d90Stb }
7351892d90Stb
7451892d90Stb /* reuse za buffer to hold H(ZA || M) */
7551892d90Stb if (!EVP_DigestFinal(hash, za, NULL)) {
7651892d90Stb SM2error(ERR_R_EVP_LIB);
7751892d90Stb goto err;
7851892d90Stb }
7951892d90Stb
8051892d90Stb e = BN_bin2bn(za, md_size, NULL);
8151892d90Stb
8251892d90Stb err:
8351892d90Stb free(za);
8451892d90Stb EVP_MD_CTX_free(hash);
8551892d90Stb return e;
8651892d90Stb }
8751892d90Stb
8851892d90Stb static ECDSA_SIG *
sm2_sig_gen(const EC_KEY * key,const BIGNUM * e)8951892d90Stb sm2_sig_gen(const EC_KEY *key, const BIGNUM *e)
9051892d90Stb {
9151892d90Stb ECDSA_SIG *sig = NULL;
9251892d90Stb const EC_GROUP *group;
9351892d90Stb EC_POINT *kG = NULL;
9451892d90Stb BN_CTX *ctx = NULL;
9551892d90Stb const BIGNUM *dA;
9651892d90Stb BIGNUM *order = NULL, *r = NULL, *s = NULL;
9751892d90Stb BIGNUM *k, *rk, *tmp, *x1;
9851892d90Stb
9951892d90Stb if ((dA = EC_KEY_get0_private_key(key)) == NULL) {
10051892d90Stb SM2error(SM2_R_INVALID_FIELD);
10151892d90Stb goto err;
10251892d90Stb }
10351892d90Stb
10451892d90Stb if ((group = EC_KEY_get0_group(key)) == NULL) {
10551892d90Stb SM2error(SM2_R_INVALID_FIELD);
10651892d90Stb goto err;
10751892d90Stb }
10851892d90Stb
10951892d90Stb if ((order = BN_new()) == NULL) {
11051892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
11151892d90Stb goto err;
11251892d90Stb }
11351892d90Stb
11451892d90Stb if (!EC_GROUP_get_order(group, order, NULL)) {
11551892d90Stb SM2error(ERR_R_EC_LIB);
11651892d90Stb goto err;
11751892d90Stb }
11851892d90Stb
11951892d90Stb if ((kG = EC_POINT_new(group)) == NULL) {
12051892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
12151892d90Stb goto err;
12251892d90Stb }
12351892d90Stb
12451892d90Stb if ((ctx = BN_CTX_new()) == NULL) {
12551892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
12651892d90Stb goto err;
12751892d90Stb }
12851892d90Stb
12951892d90Stb BN_CTX_start(ctx);
13051892d90Stb
13151892d90Stb if ((k = BN_CTX_get(ctx)) == NULL) {
13251892d90Stb SM2error(ERR_R_BN_LIB);
13351892d90Stb goto err;
13451892d90Stb }
13551892d90Stb if ((rk = BN_CTX_get(ctx)) == NULL) {
13651892d90Stb SM2error(ERR_R_BN_LIB);
13751892d90Stb goto err;
13851892d90Stb }
13951892d90Stb if ((x1 = BN_CTX_get(ctx)) == NULL) {
14051892d90Stb SM2error(ERR_R_BN_LIB);
14151892d90Stb goto err;
14251892d90Stb }
14351892d90Stb if ((tmp = BN_CTX_get(ctx)) == NULL) {
14451892d90Stb SM2error(ERR_R_BN_LIB);
14551892d90Stb goto err;
14651892d90Stb }
14751892d90Stb
14851892d90Stb /* r and s are returned as part of sig, so they can't be part of ctx. */
14951892d90Stb if ((r = BN_new()) == NULL) {
15051892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
15151892d90Stb goto err;
15251892d90Stb }
15351892d90Stb if ((s = BN_new()) == NULL) {
15451892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
15551892d90Stb goto err;
15651892d90Stb }
15751892d90Stb
15851892d90Stb for (;;) {
15951892d90Stb if (!BN_rand_range(k, order)) {
16051892d90Stb SM2error(SM2_R_RANDOM_NUMBER_GENERATION_FAILED);
16151892d90Stb goto err;
16251892d90Stb }
16351892d90Stb
16451892d90Stb if (!EC_POINT_mul(group, kG, k, NULL, NULL, ctx)) {
16551892d90Stb SM2error(ERR_R_EC_LIB);
16651892d90Stb goto err;
16751892d90Stb }
16851892d90Stb
16951892d90Stb if (!EC_POINT_get_affine_coordinates(group, kG, x1, NULL,
17051892d90Stb ctx)) {
17151892d90Stb SM2error(ERR_R_EC_LIB);
17251892d90Stb goto err;
17351892d90Stb }
17451892d90Stb
17551892d90Stb if (!BN_mod_add(r, e, x1, order, ctx)) {
17651892d90Stb SM2error(ERR_R_BN_LIB);
17751892d90Stb goto err;
17851892d90Stb }
17951892d90Stb
18051892d90Stb /* try again if r == 0 or r + k == n */
18151892d90Stb if (BN_is_zero(r))
18251892d90Stb continue;
18351892d90Stb
18451892d90Stb if (!BN_add(rk, r, k)) {
18551892d90Stb SM2error(ERR_R_BN_LIB);
18651892d90Stb goto err;
18751892d90Stb }
18851892d90Stb
18951892d90Stb if (BN_cmp(rk, order) == 0)
19051892d90Stb continue;
19151892d90Stb
19251892d90Stb if (!BN_add(s, dA, BN_value_one())) {
19351892d90Stb SM2error(ERR_R_BN_LIB);
19451892d90Stb goto err;
19551892d90Stb }
19651892d90Stb
197cb26bec3Sinoguchi if (BN_mod_inverse_ct(s, s, order, ctx) == NULL) {
19851892d90Stb SM2error(ERR_R_BN_LIB);
19951892d90Stb goto err;
20051892d90Stb }
20151892d90Stb
20251892d90Stb if (!BN_mod_mul(tmp, dA, r, order, ctx)) {
20351892d90Stb SM2error(ERR_R_BN_LIB);
20451892d90Stb goto err;
20551892d90Stb }
20651892d90Stb
20751892d90Stb if (!BN_sub(tmp, k, tmp)) {
20851892d90Stb SM2error(ERR_R_BN_LIB);
20951892d90Stb goto err;
21051892d90Stb }
21151892d90Stb
21251892d90Stb if (!BN_mod_mul(s, s, tmp, order, ctx)) {
21351892d90Stb SM2error(ERR_R_BN_LIB);
21451892d90Stb goto err;
21551892d90Stb }
21651892d90Stb
21751892d90Stb if ((sig = ECDSA_SIG_new()) == NULL) {
21851892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
21951892d90Stb goto err;
22051892d90Stb }
22151892d90Stb
22251892d90Stb /* sig takes ownership of r and s */
22351892d90Stb if (!ECDSA_SIG_set0(sig, r, s)) {
22451892d90Stb SM2error(ERR_R_INTERNAL_ERROR);
22551892d90Stb goto err;
22651892d90Stb }
22751892d90Stb break;
22851892d90Stb }
22951892d90Stb
23051892d90Stb err:
23151892d90Stb if (sig == NULL) {
23251892d90Stb BN_free(r);
23351892d90Stb BN_free(s);
23451892d90Stb }
23551892d90Stb
23651892d90Stb BN_free(order);
23751892d90Stb BN_CTX_end(ctx);
23851892d90Stb BN_CTX_free(ctx);
23951892d90Stb EC_POINT_free(kG);
24051892d90Stb return sig;
24151892d90Stb }
24251892d90Stb
24351892d90Stb static int
sm2_sig_verify(const EC_KEY * key,const ECDSA_SIG * sig,const BIGNUM * e)24451892d90Stb sm2_sig_verify(const EC_KEY *key, const ECDSA_SIG *sig, const BIGNUM *e)
24551892d90Stb {
24651892d90Stb const EC_GROUP *group;
24751892d90Stb EC_POINT *pt = NULL;
24851892d90Stb const BIGNUM *r = NULL, *s = NULL;
24951892d90Stb BN_CTX *ctx = NULL;
25051892d90Stb BIGNUM *order, *t, *x1;
25151892d90Stb int ret = 0;
25251892d90Stb
25351892d90Stb if ((group = EC_KEY_get0_group(key)) == NULL) {
25451892d90Stb SM2error(SM2_R_INVALID_FIELD);
25551892d90Stb goto err;
25651892d90Stb }
25751892d90Stb
25851892d90Stb if ((ctx = BN_CTX_new()) == NULL) {
25951892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
26051892d90Stb goto err;
26151892d90Stb }
26251892d90Stb
26351892d90Stb BN_CTX_start(ctx);
26451892d90Stb
26551892d90Stb if ((order = BN_CTX_get(ctx)) == NULL) {
26651892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
26751892d90Stb goto err;
26851892d90Stb }
26951892d90Stb
27051892d90Stb if (!EC_GROUP_get_order(group, order, NULL)) {
27151892d90Stb SM2error(ERR_R_EC_LIB);
27251892d90Stb goto err;
27351892d90Stb }
27451892d90Stb
27551892d90Stb if ((pt = EC_POINT_new(group)) == NULL) {
27651892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
27751892d90Stb goto err;
27851892d90Stb }
27951892d90Stb
28051892d90Stb if ((t = BN_CTX_get(ctx)) == NULL) {
28151892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
28251892d90Stb goto err;
28351892d90Stb }
28451892d90Stb if ((x1 = BN_CTX_get(ctx)) == NULL) {
28551892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
28651892d90Stb goto err;
28751892d90Stb }
28851892d90Stb
28951892d90Stb /*
29051892d90Stb * Section 5.3.1 in https://tools.ietf.org/html/draft-shen-sm2-ecdsa-00
29151892d90Stb *
29251892d90Stb * B1: verify that r' is in [1, n-1]
29351892d90Stb * B2: verify that s' is in [1, n-1]
29451892d90Stb * B3: set M' ~= ZA || M'
29551892d90Stb * B4: calculate e' = Hv(M'~)
29651892d90Stb * B5: verify that t = r' + s' (mod n) is not zero
29751892d90Stb * B6: calculate the point (x1', y1') = [s']G + [t]PA
29851892d90Stb * B7: verify that r' == e' + x1' (mod n)
29951892d90Stb */
30051892d90Stb
30151892d90Stb ECDSA_SIG_get0(sig, &r, &s);
30251892d90Stb
30351892d90Stb /* B1: verify that r' is in [1, n-1] */
30451892d90Stb if (BN_cmp(r, BN_value_one()) < 0 || BN_cmp(order, r) <= 0) {
30551892d90Stb SM2error(SM2_R_BAD_SIGNATURE);
30651892d90Stb goto err;
30751892d90Stb }
30851892d90Stb
30951892d90Stb /* B2: verify that s' is in [1, n-1] */
31051892d90Stb if (BN_cmp(s, BN_value_one()) < 0 || BN_cmp(order, s) <= 0) {
31151892d90Stb SM2error(SM2_R_BAD_SIGNATURE);
31251892d90Stb goto err;
31351892d90Stb }
31451892d90Stb
31551892d90Stb /* B5: verify that t = r + s is not zero */
31651892d90Stb if (!BN_mod_add(t, r, s, order, ctx)) {
31751892d90Stb SM2error(ERR_R_BN_LIB);
31851892d90Stb goto err;
31951892d90Stb }
32051892d90Stb if (BN_is_zero(t)) {
32151892d90Stb SM2error(SM2_R_BAD_SIGNATURE);
32251892d90Stb goto err;
32351892d90Stb }
32451892d90Stb
32551892d90Stb /* B6: calculate pt = (x1', y1') = [s']G + [t]PA */
32651892d90Stb if (!EC_POINT_mul(group, pt, s, EC_KEY_get0_public_key(key), t, ctx)) {
32751892d90Stb SM2error(ERR_R_EC_LIB);
32851892d90Stb goto err;
32951892d90Stb }
33051892d90Stb
33151892d90Stb if (!EC_POINT_get_affine_coordinates(group, pt, x1, NULL, ctx)) {
33251892d90Stb SM2error(ERR_R_EC_LIB);
33351892d90Stb goto err;
33451892d90Stb }
33551892d90Stb
33651892d90Stb /* B7: verify that r' == e' + x1' (mod n) */
33751892d90Stb if (!BN_mod_add(t, e, x1, order, ctx)) {
33851892d90Stb SM2error(ERR_R_BN_LIB);
33951892d90Stb goto err;
34051892d90Stb }
34151892d90Stb if (BN_cmp(r, t) == 0)
34251892d90Stb ret = 1;
34351892d90Stb
34451892d90Stb err:
34551892d90Stb EC_POINT_free(pt);
34651892d90Stb BN_CTX_end(ctx);
34751892d90Stb BN_CTX_free(ctx);
34851892d90Stb return ret;
34951892d90Stb }
35051892d90Stb
35151892d90Stb ECDSA_SIG *
sm2_do_sign(const EC_KEY * key,const EVP_MD * digest,const uint8_t * uid,size_t uid_len,const uint8_t * msg,size_t msg_len)35251892d90Stb sm2_do_sign(const EC_KEY *key, const EVP_MD *digest, const uint8_t *uid,
35351892d90Stb size_t uid_len, const uint8_t *msg, size_t msg_len)
35451892d90Stb {
35551892d90Stb ECDSA_SIG *sig = NULL;
35651892d90Stb BIGNUM *e;
35751892d90Stb
35851892d90Stb e = sm2_compute_msg_hash(digest, key, uid, uid_len, msg, msg_len);
35951892d90Stb if (e == NULL) {
36051892d90Stb SM2error(SM2_R_DIGEST_FAILURE);
36151892d90Stb goto err;
36251892d90Stb }
36351892d90Stb
36451892d90Stb sig = sm2_sig_gen(key, e);
36551892d90Stb
36651892d90Stb err:
36751892d90Stb BN_free(e);
36851892d90Stb return sig;
36951892d90Stb }
37051892d90Stb
37151892d90Stb int
sm2_do_verify(const EC_KEY * key,const EVP_MD * digest,const ECDSA_SIG * sig,const uint8_t * uid,size_t uid_len,const uint8_t * msg,size_t msg_len)37251892d90Stb sm2_do_verify(const EC_KEY *key, const EVP_MD *digest, const ECDSA_SIG *sig,
37351892d90Stb const uint8_t *uid, size_t uid_len, const uint8_t *msg, size_t msg_len)
37451892d90Stb {
37551892d90Stb BIGNUM *e;
37651892d90Stb int ret = -1;
37751892d90Stb
37851892d90Stb e = sm2_compute_msg_hash(digest, key, uid, uid_len, msg, msg_len);
37951892d90Stb if (e == NULL) {
38051892d90Stb SM2error(SM2_R_DIGEST_FAILURE);
38151892d90Stb goto err;
38251892d90Stb }
38351892d90Stb
38451892d90Stb ret = sm2_sig_verify(key, sig, e);
38551892d90Stb
38651892d90Stb err:
38751892d90Stb BN_free(e);
38851892d90Stb return ret;
38951892d90Stb }
39051892d90Stb
39151892d90Stb int
SM2_sign(const unsigned char * dgst,int dgstlen,unsigned char * sig,unsigned int * siglen,EC_KEY * eckey)39251892d90Stb SM2_sign(const unsigned char *dgst, int dgstlen, unsigned char *sig,
39351892d90Stb unsigned int *siglen, EC_KEY *eckey)
39451892d90Stb {
39551892d90Stb BIGNUM *e;
39651892d90Stb ECDSA_SIG *s = NULL;
39751892d90Stb int outlen = 0;
39851892d90Stb int ret = -1;
39951892d90Stb
40051892d90Stb if ((e = BN_bin2bn(dgst, dgstlen, NULL)) == NULL) {
40151892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
40251892d90Stb goto err;
40351892d90Stb }
40451892d90Stb
40551892d90Stb if ((s = sm2_sig_gen(eckey, e)) == NULL) {
40651892d90Stb goto err;
40751892d90Stb }
40851892d90Stb
40951892d90Stb if ((outlen = i2d_ECDSA_SIG(s, &sig)) < 0) {
41051892d90Stb SM2error(SM2_R_ASN1_ERROR);
41151892d90Stb goto err;
41251892d90Stb }
41351892d90Stb
41451892d90Stb *siglen = outlen;
41551892d90Stb ret = 1;
41651892d90Stb
41751892d90Stb err:
41851892d90Stb ECDSA_SIG_free(s);
41951892d90Stb BN_free(e);
42051892d90Stb return ret;
42151892d90Stb }
42251892d90Stb
42351892d90Stb int
SM2_verify(const unsigned char * dgst,int dgstlen,const unsigned char * sig,int sig_len,EC_KEY * eckey)42451892d90Stb SM2_verify(const unsigned char *dgst, int dgstlen, const unsigned char *sig,
42551892d90Stb int sig_len, EC_KEY *eckey)
42651892d90Stb {
42751892d90Stb ECDSA_SIG *s;
42851892d90Stb BIGNUM *e = NULL;
42951892d90Stb const unsigned char *p = sig;
43051892d90Stb unsigned char *der = NULL;
43151892d90Stb int derlen = -1;
43251892d90Stb int ret = -1;
43351892d90Stb
43451892d90Stb if ((s = ECDSA_SIG_new()) == NULL) {
43551892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
43651892d90Stb goto err;
43751892d90Stb }
43851892d90Stb
43951892d90Stb if (d2i_ECDSA_SIG(&s, &p, sig_len) == NULL) {
44051892d90Stb SM2error(SM2_R_INVALID_ENCODING);
44151892d90Stb goto err;
44251892d90Stb }
44351892d90Stb
44451892d90Stb /* Ensure signature uses DER and doesn't have trailing garbage */
44551892d90Stb derlen = i2d_ECDSA_SIG(s, &der);
44651892d90Stb if (derlen != sig_len || memcmp(sig, der, derlen) != 0) {
44751892d90Stb SM2error(SM2_R_INVALID_ENCODING);
44851892d90Stb goto err;
44951892d90Stb }
45051892d90Stb
45151892d90Stb if ((e = BN_bin2bn(dgst, dgstlen, NULL)) == NULL) {
45251892d90Stb SM2error(ERR_R_BN_LIB);
45351892d90Stb goto err;
45451892d90Stb }
45551892d90Stb
45651892d90Stb ret = sm2_sig_verify(eckey, s, e);
45751892d90Stb
45851892d90Stb err:
45951892d90Stb free(der);
46051892d90Stb BN_free(e);
46151892d90Stb ECDSA_SIG_free(s);
46251892d90Stb return ret;
46351892d90Stb }
46451892d90Stb
46551892d90Stb #endif /* OPENSSL_NO_SM2 */
466