xref: /openbmc/linux/crypto/sm2.c (revision 9d637f8113deef57bbeb141a2c1a4eb00e8c14c4)
1  /* SPDX-License-Identifier: GPL-2.0-or-later */
2  /*
3   * SM2 asymmetric public-key algorithm
4   * as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012 SM2 and
5   * described at https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02
6   *
7   * Copyright (c) 2020, Alibaba Group.
8   * Authors: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
9   */
10  
11  #include <linux/module.h>
12  #include <linux/mpi.h>
13  #include <crypto/internal/akcipher.h>
14  #include <crypto/akcipher.h>
15  #include <crypto/hash.h>
16  #include <crypto/sm3_base.h>
17  #include <crypto/rng.h>
18  #include <crypto/sm2.h>
19  #include "sm2signature.asn1.h"
20  
21  #define MPI_NBYTES(m)   ((mpi_get_nbits(m) + 7) / 8)
22  
23  struct ecc_domain_parms {
24  	const char *desc;           /* Description of the curve.  */
25  	unsigned int nbits;         /* Number of bits.  */
26  	unsigned int fips:1; /* True if this is a FIPS140-2 approved curve */
27  
28  	/* The model describing this curve.  This is mainly used to select
29  	 * the group equation.
30  	 */
31  	enum gcry_mpi_ec_models model;
32  
33  	/* The actual ECC dialect used.  This is used for curve specific
34  	 * optimizations and to select encodings etc.
35  	 */
36  	enum ecc_dialects dialect;
37  
38  	const char *p;              /* The prime defining the field.  */
39  	const char *a, *b;          /* The coefficients.  For Twisted Edwards
40  				     * Curves b is used for d.  For Montgomery
41  				     * Curves (a,b) has ((A-2)/4,B^-1).
42  				     */
43  	const char *n;              /* The order of the base point.  */
44  	const char *g_x, *g_y;      /* Base point.  */
45  	unsigned int h;             /* Cofactor.  */
46  };
47  
48  static const struct ecc_domain_parms sm2_ecp = {
49  	.desc = "sm2p256v1",
50  	.nbits = 256,
51  	.fips = 0,
52  	.model = MPI_EC_WEIERSTRASS,
53  	.dialect = ECC_DIALECT_STANDARD,
54  	.p   = "0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff",
55  	.a   = "0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc",
56  	.b   = "0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93",
57  	.n   = "0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123",
58  	.g_x = "0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7",
59  	.g_y = "0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0",
60  	.h = 1
61  };
62  
63  static int sm2_ec_ctx_init(struct mpi_ec_ctx *ec)
64  {
65  	const struct ecc_domain_parms *ecp = &sm2_ecp;
66  	MPI p, a, b;
67  	MPI x, y;
68  	int rc = -EINVAL;
69  
70  	p = mpi_scanval(ecp->p);
71  	a = mpi_scanval(ecp->a);
72  	b = mpi_scanval(ecp->b);
73  	if (!p || !a || !b)
74  		goto free_p;
75  
76  	x = mpi_scanval(ecp->g_x);
77  	y = mpi_scanval(ecp->g_y);
78  	if (!x || !y)
79  		goto free;
80  
81  	rc = -ENOMEM;
82  	/* mpi_ec_setup_elliptic_curve */
83  	ec->G = mpi_point_new(0);
84  	if (!ec->G)
85  		goto free;
86  
87  	mpi_set(ec->G->x, x);
88  	mpi_set(ec->G->y, y);
89  	mpi_set_ui(ec->G->z, 1);
90  
91  	rc = -EINVAL;
92  	ec->n = mpi_scanval(ecp->n);
93  	if (!ec->n) {
94  		mpi_point_release(ec->G);
95  		goto free;
96  	}
97  
98  	ec->h = ecp->h;
99  	ec->name = ecp->desc;
100  	mpi_ec_init(ec, ecp->model, ecp->dialect, 0, p, a, b);
101  
102  	rc = 0;
103  
104  free:
105  	mpi_free(x);
106  	mpi_free(y);
107  free_p:
108  	mpi_free(p);
109  	mpi_free(a);
110  	mpi_free(b);
111  
112  	return rc;
113  }
114  
115  static void sm2_ec_ctx_deinit(struct mpi_ec_ctx *ec)
116  {
117  	mpi_ec_deinit(ec);
118  
119  	memset(ec, 0, sizeof(*ec));
120  }
121  
122  static int sm2_ec_ctx_reset(struct mpi_ec_ctx *ec)
123  {
124  	sm2_ec_ctx_deinit(ec);
125  	return sm2_ec_ctx_init(ec);
126  }
127  
128  /* RESULT must have been initialized and is set on success to the
129   * point given by VALUE.
130   */
131  static int sm2_ecc_os2ec(MPI_POINT result, MPI value)
132  {
133  	int rc;
134  	size_t n;
135  	const unsigned char *buf;
136  	unsigned char *buf_memory;
137  	MPI x, y;
138  
139  	n = (mpi_get_nbits(value)+7)/8;
140  	buf_memory = kmalloc(n, GFP_KERNEL);
141  	rc = mpi_print(GCRYMPI_FMT_USG, buf_memory, n, &n, value);
142  	if (rc) {
143  		kfree(buf_memory);
144  		return rc;
145  	}
146  	buf = buf_memory;
147  
148  	if (n < 1) {
149  		kfree(buf_memory);
150  		return -EINVAL;
151  	}
152  	if (*buf != 4) {
153  		kfree(buf_memory);
154  		return -EINVAL; /* No support for point compression.  */
155  	}
156  	if (((n-1)%2)) {
157  		kfree(buf_memory);
158  		return -EINVAL;
159  	}
160  	n = (n-1)/2;
161  	x = mpi_read_raw_data(buf + 1, n);
162  	if (!x) {
163  		kfree(buf_memory);
164  		return -ENOMEM;
165  	}
166  	y = mpi_read_raw_data(buf + 1 + n, n);
167  	kfree(buf_memory);
168  	if (!y) {
169  		mpi_free(x);
170  		return -ENOMEM;
171  	}
172  
173  	mpi_normalize(x);
174  	mpi_normalize(y);
175  
176  	mpi_set(result->x, x);
177  	mpi_set(result->y, y);
178  	mpi_set_ui(result->z, 1);
179  
180  	mpi_free(x);
181  	mpi_free(y);
182  
183  	return 0;
184  }
185  
186  struct sm2_signature_ctx {
187  	MPI sig_r;
188  	MPI sig_s;
189  };
190  
191  int sm2_get_signature_r(void *context, size_t hdrlen, unsigned char tag,
192  				const void *value, size_t vlen)
193  {
194  	struct sm2_signature_ctx *sig = context;
195  
196  	if (!value || !vlen)
197  		return -EINVAL;
198  
199  	sig->sig_r = mpi_read_raw_data(value, vlen);
200  	if (!sig->sig_r)
201  		return -ENOMEM;
202  
203  	return 0;
204  }
205  
206  int sm2_get_signature_s(void *context, size_t hdrlen, unsigned char tag,
207  				const void *value, size_t vlen)
208  {
209  	struct sm2_signature_ctx *sig = context;
210  
211  	if (!value || !vlen)
212  		return -EINVAL;
213  
214  	sig->sig_s = mpi_read_raw_data(value, vlen);
215  	if (!sig->sig_s)
216  		return -ENOMEM;
217  
218  	return 0;
219  }
220  
221  static int sm2_z_digest_update(struct shash_desc *desc,
222  			MPI m, unsigned int pbytes)
223  {
224  	static const unsigned char zero[32];
225  	unsigned char *in;
226  	unsigned int inlen;
227  
228  	in = mpi_get_buffer(m, &inlen, NULL);
229  	if (!in)
230  		return -EINVAL;
231  
232  	if (inlen < pbytes) {
233  		/* padding with zero */
234  		crypto_sm3_update(desc, zero, pbytes - inlen);
235  		crypto_sm3_update(desc, in, inlen);
236  	} else if (inlen > pbytes) {
237  		/* skip the starting zero */
238  		crypto_sm3_update(desc, in + inlen - pbytes, pbytes);
239  	} else {
240  		crypto_sm3_update(desc, in, inlen);
241  	}
242  
243  	kfree(in);
244  	return 0;
245  }
246  
247  static int sm2_z_digest_update_point(struct shash_desc *desc,
248  		MPI_POINT point, struct mpi_ec_ctx *ec, unsigned int pbytes)
249  {
250  	MPI x, y;
251  	int ret = -EINVAL;
252  
253  	x = mpi_new(0);
254  	y = mpi_new(0);
255  
256  	if (!mpi_ec_get_affine(x, y, point, ec) &&
257  		!sm2_z_digest_update(desc, x, pbytes) &&
258  		!sm2_z_digest_update(desc, y, pbytes))
259  		ret = 0;
260  
261  	mpi_free(x);
262  	mpi_free(y);
263  	return ret;
264  }
265  
266  int sm2_compute_z_digest(struct crypto_akcipher *tfm,
267  			const unsigned char *id, size_t id_len,
268  			unsigned char dgst[SM3_DIGEST_SIZE])
269  {
270  	struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
271  	uint16_t bits_len;
272  	unsigned char entl[2];
273  	SHASH_DESC_ON_STACK(desc, NULL);
274  	unsigned int pbytes;
275  
276  	if (id_len > (USHRT_MAX / 8) || !ec->Q)
277  		return -EINVAL;
278  
279  	bits_len = (uint16_t)(id_len * 8);
280  	entl[0] = bits_len >> 8;
281  	entl[1] = bits_len & 0xff;
282  
283  	pbytes = MPI_NBYTES(ec->p);
284  
285  	/* ZA = H256(ENTLA | IDA | a | b | xG | yG | xA | yA) */
286  	sm3_base_init(desc);
287  	crypto_sm3_update(desc, entl, 2);
288  	crypto_sm3_update(desc, id, id_len);
289  
290  	if (sm2_z_digest_update(desc, ec->a, pbytes) ||
291  		sm2_z_digest_update(desc, ec->b, pbytes) ||
292  		sm2_z_digest_update_point(desc, ec->G, ec, pbytes) ||
293  		sm2_z_digest_update_point(desc, ec->Q, ec, pbytes))
294  		return -EINVAL;
295  
296  	crypto_sm3_final(desc, dgst);
297  	return 0;
298  }
299  EXPORT_SYMBOL(sm2_compute_z_digest);
300  
301  static int _sm2_verify(struct mpi_ec_ctx *ec, MPI hash, MPI sig_r, MPI sig_s)
302  {
303  	int rc = -EINVAL;
304  	struct gcry_mpi_point sG, tP;
305  	MPI t = NULL;
306  	MPI x1 = NULL, y1 = NULL;
307  
308  	mpi_point_init(&sG);
309  	mpi_point_init(&tP);
310  	x1 = mpi_new(0);
311  	y1 = mpi_new(0);
312  	t = mpi_new(0);
313  
314  	/* r, s in [1, n-1] */
315  	if (mpi_cmp_ui(sig_r, 1) < 0 || mpi_cmp(sig_r, ec->n) > 0 ||
316  		mpi_cmp_ui(sig_s, 1) < 0 || mpi_cmp(sig_s, ec->n) > 0) {
317  		goto leave;
318  	}
319  
320  	/* t = (r + s) % n, t == 0 */
321  	mpi_addm(t, sig_r, sig_s, ec->n);
322  	if (mpi_cmp_ui(t, 0) == 0)
323  		goto leave;
324  
325  	/* sG + tP = (x1, y1) */
326  	rc = -EBADMSG;
327  	mpi_ec_mul_point(&sG, sig_s, ec->G, ec);
328  	mpi_ec_mul_point(&tP, t, ec->Q, ec);
329  	mpi_ec_add_points(&sG, &sG, &tP, ec);
330  	if (mpi_ec_get_affine(x1, y1, &sG, ec))
331  		goto leave;
332  
333  	/* R = (e + x1) % n */
334  	mpi_addm(t, hash, x1, ec->n);
335  
336  	/* check R == r */
337  	rc = -EKEYREJECTED;
338  	if (mpi_cmp(t, sig_r))
339  		goto leave;
340  
341  	rc = 0;
342  
343  leave:
344  	mpi_point_free_parts(&sG);
345  	mpi_point_free_parts(&tP);
346  	mpi_free(x1);
347  	mpi_free(y1);
348  	mpi_free(t);
349  
350  	return rc;
351  }
352  
353  static int sm2_verify(struct akcipher_request *req)
354  {
355  	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
356  	struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
357  	unsigned char *buffer;
358  	struct sm2_signature_ctx sig;
359  	MPI hash;
360  	int ret;
361  
362  	if (unlikely(!ec->Q))
363  		return -EINVAL;
364  
365  	buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL);
366  	if (!buffer)
367  		return -ENOMEM;
368  
369  	sg_pcopy_to_buffer(req->src,
370  		sg_nents_for_len(req->src, req->src_len + req->dst_len),
371  		buffer, req->src_len + req->dst_len, 0);
372  
373  	sig.sig_r = NULL;
374  	sig.sig_s = NULL;
375  	ret = asn1_ber_decoder(&sm2signature_decoder, &sig,
376  				buffer, req->src_len);
377  	if (ret)
378  		goto error;
379  
380  	ret = -ENOMEM;
381  	hash = mpi_read_raw_data(buffer + req->src_len, req->dst_len);
382  	if (!hash)
383  		goto error;
384  
385  	ret = _sm2_verify(ec, hash, sig.sig_r, sig.sig_s);
386  
387  	mpi_free(hash);
388  error:
389  	mpi_free(sig.sig_r);
390  	mpi_free(sig.sig_s);
391  	kfree(buffer);
392  	return ret;
393  }
394  
395  static int sm2_set_pub_key(struct crypto_akcipher *tfm,
396  			const void *key, unsigned int keylen)
397  {
398  	struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
399  	MPI a;
400  	int rc;
401  
402  	rc = sm2_ec_ctx_reset(ec);
403  	if (rc)
404  		return rc;
405  
406  	ec->Q = mpi_point_new(0);
407  	if (!ec->Q)
408  		return -ENOMEM;
409  
410  	/* include the uncompressed flag '0x04' */
411  	rc = -ENOMEM;
412  	a = mpi_read_raw_data(key, keylen);
413  	if (!a)
414  		goto error;
415  
416  	mpi_normalize(a);
417  	rc = sm2_ecc_os2ec(ec->Q, a);
418  	mpi_free(a);
419  	if (rc)
420  		goto error;
421  
422  	return 0;
423  
424  error:
425  	mpi_point_release(ec->Q);
426  	ec->Q = NULL;
427  	return rc;
428  }
429  
430  static unsigned int sm2_max_size(struct crypto_akcipher *tfm)
431  {
432  	/* Unlimited max size */
433  	return PAGE_SIZE;
434  }
435  
436  static int sm2_init_tfm(struct crypto_akcipher *tfm)
437  {
438  	struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
439  
440  	return sm2_ec_ctx_init(ec);
441  }
442  
443  static void sm2_exit_tfm(struct crypto_akcipher *tfm)
444  {
445  	struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
446  
447  	sm2_ec_ctx_deinit(ec);
448  }
449  
450  static struct akcipher_alg sm2 = {
451  	.verify = sm2_verify,
452  	.set_pub_key = sm2_set_pub_key,
453  	.max_size = sm2_max_size,
454  	.init = sm2_init_tfm,
455  	.exit = sm2_exit_tfm,
456  	.base = {
457  		.cra_name = "sm2",
458  		.cra_driver_name = "sm2-generic",
459  		.cra_priority = 100,
460  		.cra_module = THIS_MODULE,
461  		.cra_ctxsize = sizeof(struct mpi_ec_ctx),
462  	},
463  };
464  
465  static int sm2_init(void)
466  {
467  	return crypto_register_akcipher(&sm2);
468  }
469  
470  static void sm2_exit(void)
471  {
472  	crypto_unregister_akcipher(&sm2);
473  }
474  
475  subsys_initcall(sm2_init);
476  module_exit(sm2_exit);
477  
478  MODULE_LICENSE("GPL");
479  MODULE_AUTHOR("Tianjia Zhang <tianjia.zhang@linux.alibaba.com>");
480  MODULE_DESCRIPTION("SM2 generic algorithm");
481  MODULE_ALIAS_CRYPTO("sm2-generic");
482