sm2.c (9945B)
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.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 23struct 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 48static 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 63static 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 83 ec->Q = mpi_point_new(0); 84 if (!ec->Q) 85 goto free; 86 87 /* mpi_ec_setup_elliptic_curve */ 88 ec->G = mpi_point_new(0); 89 if (!ec->G) { 90 mpi_point_release(ec->Q); 91 goto free; 92 } 93 94 mpi_set(ec->G->x, x); 95 mpi_set(ec->G->y, y); 96 mpi_set_ui(ec->G->z, 1); 97 98 rc = -EINVAL; 99 ec->n = mpi_scanval(ecp->n); 100 if (!ec->n) { 101 mpi_point_release(ec->Q); 102 mpi_point_release(ec->G); 103 goto free; 104 } 105 106 ec->h = ecp->h; 107 ec->name = ecp->desc; 108 mpi_ec_init(ec, ecp->model, ecp->dialect, 0, p, a, b); 109 110 rc = 0; 111 112free: 113 mpi_free(x); 114 mpi_free(y); 115free_p: 116 mpi_free(p); 117 mpi_free(a); 118 mpi_free(b); 119 120 return rc; 121} 122 123static void sm2_ec_ctx_deinit(struct mpi_ec_ctx *ec) 124{ 125 mpi_ec_deinit(ec); 126 127 memset(ec, 0, sizeof(*ec)); 128} 129 130/* RESULT must have been initialized and is set on success to the 131 * point given by VALUE. 132 */ 133static int sm2_ecc_os2ec(MPI_POINT result, MPI value) 134{ 135 int rc; 136 size_t n; 137 unsigned char *buf; 138 MPI x, y; 139 140 n = MPI_NBYTES(value); 141 buf = kmalloc(n, GFP_KERNEL); 142 if (!buf) 143 return -ENOMEM; 144 145 rc = mpi_print(GCRYMPI_FMT_USG, buf, n, &n, value); 146 if (rc) 147 goto err_freebuf; 148 149 rc = -EINVAL; 150 if (n < 1 || ((n - 1) % 2)) 151 goto err_freebuf; 152 /* No support for point compression */ 153 if (*buf != 0x4) 154 goto err_freebuf; 155 156 rc = -ENOMEM; 157 n = (n - 1) / 2; 158 x = mpi_read_raw_data(buf + 1, n); 159 if (!x) 160 goto err_freebuf; 161 y = mpi_read_raw_data(buf + 1 + n, n); 162 if (!y) 163 goto err_freex; 164 165 mpi_normalize(x); 166 mpi_normalize(y); 167 mpi_set(result->x, x); 168 mpi_set(result->y, y); 169 mpi_set_ui(result->z, 1); 170 171 rc = 0; 172 173 mpi_free(y); 174err_freex: 175 mpi_free(x); 176err_freebuf: 177 kfree(buf); 178 return rc; 179} 180 181struct sm2_signature_ctx { 182 MPI sig_r; 183 MPI sig_s; 184}; 185 186int sm2_get_signature_r(void *context, size_t hdrlen, unsigned char tag, 187 const void *value, size_t vlen) 188{ 189 struct sm2_signature_ctx *sig = context; 190 191 if (!value || !vlen) 192 return -EINVAL; 193 194 sig->sig_r = mpi_read_raw_data(value, vlen); 195 if (!sig->sig_r) 196 return -ENOMEM; 197 198 return 0; 199} 200 201int sm2_get_signature_s(void *context, size_t hdrlen, unsigned char tag, 202 const void *value, size_t vlen) 203{ 204 struct sm2_signature_ctx *sig = context; 205 206 if (!value || !vlen) 207 return -EINVAL; 208 209 sig->sig_s = mpi_read_raw_data(value, vlen); 210 if (!sig->sig_s) 211 return -ENOMEM; 212 213 return 0; 214} 215 216static int sm2_z_digest_update(struct sm3_state *sctx, 217 MPI m, unsigned int pbytes) 218{ 219 static const unsigned char zero[32]; 220 unsigned char *in; 221 unsigned int inlen; 222 223 in = mpi_get_buffer(m, &inlen, NULL); 224 if (!in) 225 return -EINVAL; 226 227 if (inlen < pbytes) { 228 /* padding with zero */ 229 sm3_update(sctx, zero, pbytes - inlen); 230 sm3_update(sctx, in, inlen); 231 } else if (inlen > pbytes) { 232 /* skip the starting zero */ 233 sm3_update(sctx, in + inlen - pbytes, pbytes); 234 } else { 235 sm3_update(sctx, in, inlen); 236 } 237 238 kfree(in); 239 return 0; 240} 241 242static int sm2_z_digest_update_point(struct sm3_state *sctx, 243 MPI_POINT point, struct mpi_ec_ctx *ec, unsigned int pbytes) 244{ 245 MPI x, y; 246 int ret = -EINVAL; 247 248 x = mpi_new(0); 249 y = mpi_new(0); 250 251 if (!mpi_ec_get_affine(x, y, point, ec) && 252 !sm2_z_digest_update(sctx, x, pbytes) && 253 !sm2_z_digest_update(sctx, y, pbytes)) 254 ret = 0; 255 256 mpi_free(x); 257 mpi_free(y); 258 return ret; 259} 260 261int sm2_compute_z_digest(struct crypto_akcipher *tfm, 262 const unsigned char *id, size_t id_len, 263 unsigned char dgst[SM3_DIGEST_SIZE]) 264{ 265 struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); 266 uint16_t bits_len; 267 unsigned char entl[2]; 268 struct sm3_state sctx; 269 unsigned int pbytes; 270 271 if (id_len > (USHRT_MAX / 8) || !ec->Q) 272 return -EINVAL; 273 274 bits_len = (uint16_t)(id_len * 8); 275 entl[0] = bits_len >> 8; 276 entl[1] = bits_len & 0xff; 277 278 pbytes = MPI_NBYTES(ec->p); 279 280 /* ZA = H256(ENTLA | IDA | a | b | xG | yG | xA | yA) */ 281 sm3_init(&sctx); 282 sm3_update(&sctx, entl, 2); 283 sm3_update(&sctx, id, id_len); 284 285 if (sm2_z_digest_update(&sctx, ec->a, pbytes) || 286 sm2_z_digest_update(&sctx, ec->b, pbytes) || 287 sm2_z_digest_update_point(&sctx, ec->G, ec, pbytes) || 288 sm2_z_digest_update_point(&sctx, ec->Q, ec, pbytes)) 289 return -EINVAL; 290 291 sm3_final(&sctx, dgst); 292 return 0; 293} 294EXPORT_SYMBOL(sm2_compute_z_digest); 295 296static int _sm2_verify(struct mpi_ec_ctx *ec, MPI hash, MPI sig_r, MPI sig_s) 297{ 298 int rc = -EINVAL; 299 struct gcry_mpi_point sG, tP; 300 MPI t = NULL; 301 MPI x1 = NULL, y1 = NULL; 302 303 mpi_point_init(&sG); 304 mpi_point_init(&tP); 305 x1 = mpi_new(0); 306 y1 = mpi_new(0); 307 t = mpi_new(0); 308 309 /* r, s in [1, n-1] */ 310 if (mpi_cmp_ui(sig_r, 1) < 0 || mpi_cmp(sig_r, ec->n) > 0 || 311 mpi_cmp_ui(sig_s, 1) < 0 || mpi_cmp(sig_s, ec->n) > 0) { 312 goto leave; 313 } 314 315 /* t = (r + s) % n, t == 0 */ 316 mpi_addm(t, sig_r, sig_s, ec->n); 317 if (mpi_cmp_ui(t, 0) == 0) 318 goto leave; 319 320 /* sG + tP = (x1, y1) */ 321 rc = -EBADMSG; 322 mpi_ec_mul_point(&sG, sig_s, ec->G, ec); 323 mpi_ec_mul_point(&tP, t, ec->Q, ec); 324 mpi_ec_add_points(&sG, &sG, &tP, ec); 325 if (mpi_ec_get_affine(x1, y1, &sG, ec)) 326 goto leave; 327 328 /* R = (e + x1) % n */ 329 mpi_addm(t, hash, x1, ec->n); 330 331 /* check R == r */ 332 rc = -EKEYREJECTED; 333 if (mpi_cmp(t, sig_r)) 334 goto leave; 335 336 rc = 0; 337 338leave: 339 mpi_point_free_parts(&sG); 340 mpi_point_free_parts(&tP); 341 mpi_free(x1); 342 mpi_free(y1); 343 mpi_free(t); 344 345 return rc; 346} 347 348static int sm2_verify(struct akcipher_request *req) 349{ 350 struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); 351 struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); 352 unsigned char *buffer; 353 struct sm2_signature_ctx sig; 354 MPI hash; 355 int ret; 356 357 if (unlikely(!ec->Q)) 358 return -EINVAL; 359 360 buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); 361 if (!buffer) 362 return -ENOMEM; 363 364 sg_pcopy_to_buffer(req->src, 365 sg_nents_for_len(req->src, req->src_len + req->dst_len), 366 buffer, req->src_len + req->dst_len, 0); 367 368 sig.sig_r = NULL; 369 sig.sig_s = NULL; 370 ret = asn1_ber_decoder(&sm2signature_decoder, &sig, 371 buffer, req->src_len); 372 if (ret) 373 goto error; 374 375 ret = -ENOMEM; 376 hash = mpi_read_raw_data(buffer + req->src_len, req->dst_len); 377 if (!hash) 378 goto error; 379 380 ret = _sm2_verify(ec, hash, sig.sig_r, sig.sig_s); 381 382 mpi_free(hash); 383error: 384 mpi_free(sig.sig_r); 385 mpi_free(sig.sig_s); 386 kfree(buffer); 387 return ret; 388} 389 390static int sm2_set_pub_key(struct crypto_akcipher *tfm, 391 const void *key, unsigned int keylen) 392{ 393 struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); 394 MPI a; 395 int rc; 396 397 /* include the uncompressed flag '0x04' */ 398 a = mpi_read_raw_data(key, keylen); 399 if (!a) 400 return -ENOMEM; 401 402 mpi_normalize(a); 403 rc = sm2_ecc_os2ec(ec->Q, a); 404 mpi_free(a); 405 406 return rc; 407} 408 409static unsigned int sm2_max_size(struct crypto_akcipher *tfm) 410{ 411 /* Unlimited max size */ 412 return PAGE_SIZE; 413} 414 415static int sm2_init_tfm(struct crypto_akcipher *tfm) 416{ 417 struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); 418 419 return sm2_ec_ctx_init(ec); 420} 421 422static void sm2_exit_tfm(struct crypto_akcipher *tfm) 423{ 424 struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); 425 426 sm2_ec_ctx_deinit(ec); 427} 428 429static struct akcipher_alg sm2 = { 430 .verify = sm2_verify, 431 .set_pub_key = sm2_set_pub_key, 432 .max_size = sm2_max_size, 433 .init = sm2_init_tfm, 434 .exit = sm2_exit_tfm, 435 .base = { 436 .cra_name = "sm2", 437 .cra_driver_name = "sm2-generic", 438 .cra_priority = 100, 439 .cra_module = THIS_MODULE, 440 .cra_ctxsize = sizeof(struct mpi_ec_ctx), 441 }, 442}; 443 444static int sm2_init(void) 445{ 446 return crypto_register_akcipher(&sm2); 447} 448 449static void sm2_exit(void) 450{ 451 crypto_unregister_akcipher(&sm2); 452} 453 454subsys_initcall(sm2_init); 455module_exit(sm2_exit); 456 457MODULE_LICENSE("GPL"); 458MODULE_AUTHOR("Tianjia Zhang <tianjia.zhang@linux.alibaba.com>"); 459MODULE_DESCRIPTION("SM2 generic algorithm"); 460MODULE_ALIAS_CRYPTO("sm2-generic");