xref: /openbsd/lib/libcrypto/sm2/sm2_sign.c (revision d415bd75)
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 *
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 *
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
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 *
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
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
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
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