summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/sm2/sm2_sign.c
diff options
context:
space:
mode:
authortb <>2021-08-18 16:04:32 +0000
committertb <>2021-08-18 16:04:32 +0000
commit27a4a421da356671ca87fff69b8b7340d284659c (patch)
treeff95b8757df3a4b8d97a0f3f19a7c9962ba1076f /src/lib/libcrypto/sm2/sm2_sign.c
parente9cfb6e09338ad2081dfa06cdae4acc1dc0c78d9 (diff)
downloadopenbsd-27a4a421da356671ca87fff69b8b7340d284659c.tar.gz
openbsd-27a4a421da356671ca87fff69b8b7340d284659c.tar.bz2
openbsd-27a4a421da356671ca87fff69b8b7340d284659c.zip
Import initial code for the SM2 cipher
This adds the SM2 algorithm defined in the Chinese standards GB/T 32918.1-2016, GB/T 32918.2-2016, GB/T 32918.3-2016, GB/T 32918.4-2016 and GB/T 32918.5-2017. This is an ISC licensed implementation contributed by Ribose.inc, based on the same code that was contributed to OpenSSL by Jack Lloyd. The port to LibreSSL was done by Ronald Tse and Nickolay Olshevsky. Github PR #105 I made quite a few cleanup passes on this, but more is needed, some of which will happen in-tree before this is linked to the build. ok deraadt inoguchi (a long time ago), jsing
Diffstat (limited to 'src/lib/libcrypto/sm2/sm2_sign.c')
-rw-r--r--src/lib/libcrypto/sm2/sm2_sign.c465
1 files changed, 465 insertions, 0 deletions
diff --git a/src/lib/libcrypto/sm2/sm2_sign.c b/src/lib/libcrypto/sm2/sm2_sign.c
new file mode 100644
index 0000000000..d306658a48
--- /dev/null
+++ b/src/lib/libcrypto/sm2/sm2_sign.c
@@ -0,0 +1,465 @@
1/* $OpenBSD: sm2_sign.c,v 1.1.1.1 2021/08/18 16:04:32 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_lcl.h"
28#include "sm2_locl.h"
29
30static BIGNUM *
31sm2_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
88static ECDSA_SIG *
89sm2_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)) {
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
243static int
244sm2_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
351ECDSA_SIG *
352sm2_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
371int
372sm2_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
391int
392SM2_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
423int
424SM2_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 */