1 /* $OpenBSD: sm2_sign.c,v 1.4 2023/07/05 17:36:19 tb Exp $ */
2 /*
3 * Copyright (c) 2017, 2019 Ribose Inc
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #ifndef OPENSSL_NO_SM2
19
20 #include <string.h>
21
22 #include <openssl/sm2.h>
23 #include <openssl/evp.h>
24 #include <openssl/err.h>
25 #include <openssl/bn.h>
26
27 #include "bn_local.h"
28 #include "sm2_local.h"
29
30 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)31 sm2_compute_msg_hash(const EVP_MD *digest, const EC_KEY *key,
32 const uint8_t *uid, size_t uid_len, const uint8_t *msg, size_t msg_len)
33 {
34 EVP_MD_CTX *hash;
35 BIGNUM *e = NULL;
36 int md_size;
37 uint8_t *za = NULL;
38
39 if ((hash = EVP_MD_CTX_new()) == NULL) {
40 SM2error(ERR_R_MALLOC_FAILURE);
41 goto err;
42 }
43
44 if ((md_size = EVP_MD_size(digest)) < 0) {
45 SM2error(SM2_R_INVALID_DIGEST);
46 goto err;
47 }
48
49 if ((za = calloc(1, md_size)) == NULL) {
50 SM2error(ERR_R_MALLOC_FAILURE);
51 goto err;
52 }
53
54 if (!sm2_compute_userid_digest(za, digest, uid, uid_len, key)) {
55 SM2error(SM2_R_DIGEST_FAILURE);
56 goto err;
57 }
58
59 if (!EVP_DigestInit(hash, digest)) {
60 SM2error(ERR_R_EVP_LIB);
61 goto err;
62 }
63
64 if (!EVP_DigestUpdate(hash, za, md_size)) {
65 SM2error(ERR_R_EVP_LIB);
66 goto err;
67 }
68
69 if (!EVP_DigestUpdate(hash, msg, msg_len)) {
70 SM2error(ERR_R_EVP_LIB);
71 goto err;
72 }
73
74 /* reuse za buffer to hold H(ZA || M) */
75 if (!EVP_DigestFinal(hash, za, NULL)) {
76 SM2error(ERR_R_EVP_LIB);
77 goto err;
78 }
79
80 e = BN_bin2bn(za, md_size, NULL);
81
82 err:
83 free(za);
84 EVP_MD_CTX_free(hash);
85 return e;
86 }
87
88 static ECDSA_SIG *
sm2_sig_gen(const EC_KEY * key,const BIGNUM * e)89 sm2_sig_gen(const EC_KEY *key, const BIGNUM *e)
90 {
91 ECDSA_SIG *sig = NULL;
92 const EC_GROUP *group;
93 EC_POINT *kG = NULL;
94 BN_CTX *ctx = NULL;
95 const BIGNUM *dA;
96 BIGNUM *order = NULL, *r = NULL, *s = NULL;
97 BIGNUM *k, *rk, *tmp, *x1;
98
99 if ((dA = EC_KEY_get0_private_key(key)) == NULL) {
100 SM2error(SM2_R_INVALID_FIELD);
101 goto err;
102 }
103
104 if ((group = EC_KEY_get0_group(key)) == NULL) {
105 SM2error(SM2_R_INVALID_FIELD);
106 goto err;
107 }
108
109 if ((order = BN_new()) == NULL) {
110 SM2error(ERR_R_MALLOC_FAILURE);
111 goto err;
112 }
113
114 if (!EC_GROUP_get_order(group, order, NULL)) {
115 SM2error(ERR_R_EC_LIB);
116 goto err;
117 }
118
119 if ((kG = EC_POINT_new(group)) == NULL) {
120 SM2error(ERR_R_MALLOC_FAILURE);
121 goto err;
122 }
123
124 if ((ctx = BN_CTX_new()) == NULL) {
125 SM2error(ERR_R_MALLOC_FAILURE);
126 goto err;
127 }
128
129 BN_CTX_start(ctx);
130
131 if ((k = BN_CTX_get(ctx)) == NULL) {
132 SM2error(ERR_R_BN_LIB);
133 goto err;
134 }
135 if ((rk = BN_CTX_get(ctx)) == NULL) {
136 SM2error(ERR_R_BN_LIB);
137 goto err;
138 }
139 if ((x1 = BN_CTX_get(ctx)) == NULL) {
140 SM2error(ERR_R_BN_LIB);
141 goto err;
142 }
143 if ((tmp = BN_CTX_get(ctx)) == NULL) {
144 SM2error(ERR_R_BN_LIB);
145 goto err;
146 }
147
148 /* r and s are returned as part of sig, so they can't be part of ctx. */
149 if ((r = BN_new()) == NULL) {
150 SM2error(ERR_R_MALLOC_FAILURE);
151 goto err;
152 }
153 if ((s = BN_new()) == NULL) {
154 SM2error(ERR_R_MALLOC_FAILURE);
155 goto err;
156 }
157
158 for (;;) {
159 if (!BN_rand_range(k, order)) {
160 SM2error(SM2_R_RANDOM_NUMBER_GENERATION_FAILED);
161 goto err;
162 }
163
164 if (!EC_POINT_mul(group, kG, k, NULL, NULL, ctx)) {
165 SM2error(ERR_R_EC_LIB);
166 goto err;
167 }
168
169 if (!EC_POINT_get_affine_coordinates(group, kG, x1, NULL,
170 ctx)) {
171 SM2error(ERR_R_EC_LIB);
172 goto err;
173 }
174
175 if (!BN_mod_add(r, e, x1, order, ctx)) {
176 SM2error(ERR_R_BN_LIB);
177 goto err;
178 }
179
180 /* try again if r == 0 or r + k == n */
181 if (BN_is_zero(r))
182 continue;
183
184 if (!BN_add(rk, r, k)) {
185 SM2error(ERR_R_BN_LIB);
186 goto err;
187 }
188
189 if (BN_cmp(rk, order) == 0)
190 continue;
191
192 if (!BN_add(s, dA, BN_value_one())) {
193 SM2error(ERR_R_BN_LIB);
194 goto err;
195 }
196
197 if (BN_mod_inverse_ct(s, s, order, ctx) == NULL) {
198 SM2error(ERR_R_BN_LIB);
199 goto err;
200 }
201
202 if (!BN_mod_mul(tmp, dA, r, order, ctx)) {
203 SM2error(ERR_R_BN_LIB);
204 goto err;
205 }
206
207 if (!BN_sub(tmp, k, tmp)) {
208 SM2error(ERR_R_BN_LIB);
209 goto err;
210 }
211
212 if (!BN_mod_mul(s, s, tmp, order, ctx)) {
213 SM2error(ERR_R_BN_LIB);
214 goto err;
215 }
216
217 if ((sig = ECDSA_SIG_new()) == NULL) {
218 SM2error(ERR_R_MALLOC_FAILURE);
219 goto err;
220 }
221
222 /* sig takes ownership of r and s */
223 if (!ECDSA_SIG_set0(sig, r, s)) {
224 SM2error(ERR_R_INTERNAL_ERROR);
225 goto err;
226 }
227 break;
228 }
229
230 err:
231 if (sig == NULL) {
232 BN_free(r);
233 BN_free(s);
234 }
235
236 BN_free(order);
237 BN_CTX_end(ctx);
238 BN_CTX_free(ctx);
239 EC_POINT_free(kG);
240 return sig;
241 }
242
243 static int
sm2_sig_verify(const EC_KEY * key,const ECDSA_SIG * sig,const BIGNUM * e)244 sm2_sig_verify(const EC_KEY *key, const ECDSA_SIG *sig, const BIGNUM *e)
245 {
246 const EC_GROUP *group;
247 EC_POINT *pt = NULL;
248 const BIGNUM *r = NULL, *s = NULL;
249 BN_CTX *ctx = NULL;
250 BIGNUM *order, *t, *x1;
251 int ret = 0;
252
253 if ((group = EC_KEY_get0_group(key)) == NULL) {
254 SM2error(SM2_R_INVALID_FIELD);
255 goto err;
256 }
257
258 if ((ctx = BN_CTX_new()) == NULL) {
259 SM2error(ERR_R_MALLOC_FAILURE);
260 goto err;
261 }
262
263 BN_CTX_start(ctx);
264
265 if ((order = BN_CTX_get(ctx)) == NULL) {
266 SM2error(ERR_R_MALLOC_FAILURE);
267 goto err;
268 }
269
270 if (!EC_GROUP_get_order(group, order, NULL)) {
271 SM2error(ERR_R_EC_LIB);
272 goto err;
273 }
274
275 if ((pt = EC_POINT_new(group)) == NULL) {
276 SM2error(ERR_R_MALLOC_FAILURE);
277 goto err;
278 }
279
280 if ((t = BN_CTX_get(ctx)) == NULL) {
281 SM2error(ERR_R_MALLOC_FAILURE);
282 goto err;
283 }
284 if ((x1 = BN_CTX_get(ctx)) == NULL) {
285 SM2error(ERR_R_MALLOC_FAILURE);
286 goto err;
287 }
288
289 /*
290 * Section 5.3.1 in https://tools.ietf.org/html/draft-shen-sm2-ecdsa-00
291 *
292 * B1: verify that r' is in [1, n-1]
293 * B2: verify that s' is in [1, n-1]
294 * B3: set M' ~= ZA || M'
295 * B4: calculate e' = Hv(M'~)
296 * B5: verify that t = r' + s' (mod n) is not zero
297 * B6: calculate the point (x1', y1') = [s']G + [t]PA
298 * B7: verify that r' == e' + x1' (mod n)
299 */
300
301 ECDSA_SIG_get0(sig, &r, &s);
302
303 /* B1: verify that r' is in [1, n-1] */
304 if (BN_cmp(r, BN_value_one()) < 0 || BN_cmp(order, r) <= 0) {
305 SM2error(SM2_R_BAD_SIGNATURE);
306 goto err;
307 }
308
309 /* B2: verify that s' is in [1, n-1] */
310 if (BN_cmp(s, BN_value_one()) < 0 || BN_cmp(order, s) <= 0) {
311 SM2error(SM2_R_BAD_SIGNATURE);
312 goto err;
313 }
314
315 /* B5: verify that t = r + s is not zero */
316 if (!BN_mod_add(t, r, s, order, ctx)) {
317 SM2error(ERR_R_BN_LIB);
318 goto err;
319 }
320 if (BN_is_zero(t)) {
321 SM2error(SM2_R_BAD_SIGNATURE);
322 goto err;
323 }
324
325 /* B6: calculate pt = (x1', y1') = [s']G + [t]PA */
326 if (!EC_POINT_mul(group, pt, s, EC_KEY_get0_public_key(key), t, ctx)) {
327 SM2error(ERR_R_EC_LIB);
328 goto err;
329 }
330
331 if (!EC_POINT_get_affine_coordinates(group, pt, x1, NULL, ctx)) {
332 SM2error(ERR_R_EC_LIB);
333 goto err;
334 }
335
336 /* B7: verify that r' == e' + x1' (mod n) */
337 if (!BN_mod_add(t, e, x1, order, ctx)) {
338 SM2error(ERR_R_BN_LIB);
339 goto err;
340 }
341 if (BN_cmp(r, t) == 0)
342 ret = 1;
343
344 err:
345 EC_POINT_free(pt);
346 BN_CTX_end(ctx);
347 BN_CTX_free(ctx);
348 return ret;
349 }
350
351 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)352 sm2_do_sign(const EC_KEY *key, const EVP_MD *digest, const uint8_t *uid,
353 size_t uid_len, const uint8_t *msg, size_t msg_len)
354 {
355 ECDSA_SIG *sig = NULL;
356 BIGNUM *e;
357
358 e = sm2_compute_msg_hash(digest, key, uid, uid_len, msg, msg_len);
359 if (e == NULL) {
360 SM2error(SM2_R_DIGEST_FAILURE);
361 goto err;
362 }
363
364 sig = sm2_sig_gen(key, e);
365
366 err:
367 BN_free(e);
368 return sig;
369 }
370
371 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)372 sm2_do_verify(const EC_KEY *key, const EVP_MD *digest, const ECDSA_SIG *sig,
373 const uint8_t *uid, size_t uid_len, const uint8_t *msg, size_t msg_len)
374 {
375 BIGNUM *e;
376 int ret = -1;
377
378 e = sm2_compute_msg_hash(digest, key, uid, uid_len, msg, msg_len);
379 if (e == NULL) {
380 SM2error(SM2_R_DIGEST_FAILURE);
381 goto err;
382 }
383
384 ret = sm2_sig_verify(key, sig, e);
385
386 err:
387 BN_free(e);
388 return ret;
389 }
390
391 int
SM2_sign(const unsigned char * dgst,int dgstlen,unsigned char * sig,unsigned int * siglen,EC_KEY * eckey)392 SM2_sign(const unsigned char *dgst, int dgstlen, unsigned char *sig,
393 unsigned int *siglen, EC_KEY *eckey)
394 {
395 BIGNUM *e;
396 ECDSA_SIG *s = NULL;
397 int outlen = 0;
398 int ret = -1;
399
400 if ((e = BN_bin2bn(dgst, dgstlen, NULL)) == NULL) {
401 SM2error(ERR_R_MALLOC_FAILURE);
402 goto err;
403 }
404
405 if ((s = sm2_sig_gen(eckey, e)) == NULL) {
406 goto err;
407 }
408
409 if ((outlen = i2d_ECDSA_SIG(s, &sig)) < 0) {
410 SM2error(SM2_R_ASN1_ERROR);
411 goto err;
412 }
413
414 *siglen = outlen;
415 ret = 1;
416
417 err:
418 ECDSA_SIG_free(s);
419 BN_free(e);
420 return ret;
421 }
422
423 int
SM2_verify(const unsigned char * dgst,int dgstlen,const unsigned char * sig,int sig_len,EC_KEY * eckey)424 SM2_verify(const unsigned char *dgst, int dgstlen, const unsigned char *sig,
425 int sig_len, EC_KEY *eckey)
426 {
427 ECDSA_SIG *s;
428 BIGNUM *e = NULL;
429 const unsigned char *p = sig;
430 unsigned char *der = NULL;
431 int derlen = -1;
432 int ret = -1;
433
434 if ((s = ECDSA_SIG_new()) == NULL) {
435 SM2error(ERR_R_MALLOC_FAILURE);
436 goto err;
437 }
438
439 if (d2i_ECDSA_SIG(&s, &p, sig_len) == NULL) {
440 SM2error(SM2_R_INVALID_ENCODING);
441 goto err;
442 }
443
444 /* Ensure signature uses DER and doesn't have trailing garbage */
445 derlen = i2d_ECDSA_SIG(s, &der);
446 if (derlen != sig_len || memcmp(sig, der, derlen) != 0) {
447 SM2error(SM2_R_INVALID_ENCODING);
448 goto err;
449 }
450
451 if ((e = BN_bin2bn(dgst, dgstlen, NULL)) == NULL) {
452 SM2error(ERR_R_BN_LIB);
453 goto err;
454 }
455
456 ret = sm2_sig_verify(eckey, s, e);
457
458 err:
459 free(der);
460 BN_free(e);
461 ECDSA_SIG_free(s);
462 return ret;
463 }
464
465 #endif /* OPENSSL_NO_SM2 */
466