18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SM2 asymmetric public-key algorithm 48c2ecf20Sopenharmony_ci * as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012 SM2 and 58c2ecf20Sopenharmony_ci * described at https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2020, Alibaba Group. 88c2ecf20Sopenharmony_ci * Authors: Tianjia Zhang <tianjia.zhang@linux.alibaba.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/mpi.h> 138c2ecf20Sopenharmony_ci#include <crypto/internal/akcipher.h> 148c2ecf20Sopenharmony_ci#include <crypto/akcipher.h> 158c2ecf20Sopenharmony_ci#include <crypto/hash.h> 168c2ecf20Sopenharmony_ci#include <crypto/sm3_base.h> 178c2ecf20Sopenharmony_ci#include <crypto/rng.h> 188c2ecf20Sopenharmony_ci#include <crypto/sm2.h> 198c2ecf20Sopenharmony_ci#include "sm2signature.asn1.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define MPI_NBYTES(m) ((mpi_get_nbits(m) + 7) / 8) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct ecc_domain_parms { 248c2ecf20Sopenharmony_ci const char *desc; /* Description of the curve. */ 258c2ecf20Sopenharmony_ci unsigned int nbits; /* Number of bits. */ 268c2ecf20Sopenharmony_ci unsigned int fips:1; /* True if this is a FIPS140-2 approved curve */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci /* The model describing this curve. This is mainly used to select 298c2ecf20Sopenharmony_ci * the group equation. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci enum gcry_mpi_ec_models model; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* The actual ECC dialect used. This is used for curve specific 348c2ecf20Sopenharmony_ci * optimizations and to select encodings etc. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci enum ecc_dialects dialect; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci const char *p; /* The prime defining the field. */ 398c2ecf20Sopenharmony_ci const char *a, *b; /* The coefficients. For Twisted Edwards 408c2ecf20Sopenharmony_ci * Curves b is used for d. For Montgomery 418c2ecf20Sopenharmony_ci * Curves (a,b) has ((A-2)/4,B^-1). 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci const char *n; /* The order of the base point. */ 448c2ecf20Sopenharmony_ci const char *g_x, *g_y; /* Base point. */ 458c2ecf20Sopenharmony_ci unsigned int h; /* Cofactor. */ 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic const struct ecc_domain_parms sm2_ecp = { 498c2ecf20Sopenharmony_ci .desc = "sm2p256v1", 508c2ecf20Sopenharmony_ci .nbits = 256, 518c2ecf20Sopenharmony_ci .fips = 0, 528c2ecf20Sopenharmony_ci .model = MPI_EC_WEIERSTRASS, 538c2ecf20Sopenharmony_ci .dialect = ECC_DIALECT_STANDARD, 548c2ecf20Sopenharmony_ci .p = "0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff", 558c2ecf20Sopenharmony_ci .a = "0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc", 568c2ecf20Sopenharmony_ci .b = "0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93", 578c2ecf20Sopenharmony_ci .n = "0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123", 588c2ecf20Sopenharmony_ci .g_x = "0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", 598c2ecf20Sopenharmony_ci .g_y = "0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", 608c2ecf20Sopenharmony_ci .h = 1 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int sm2_ec_ctx_init(struct mpi_ec_ctx *ec) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci const struct ecc_domain_parms *ecp = &sm2_ecp; 668c2ecf20Sopenharmony_ci MPI p, a, b; 678c2ecf20Sopenharmony_ci MPI x, y; 688c2ecf20Sopenharmony_ci int rc = -EINVAL; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci p = mpi_scanval(ecp->p); 718c2ecf20Sopenharmony_ci a = mpi_scanval(ecp->a); 728c2ecf20Sopenharmony_ci b = mpi_scanval(ecp->b); 738c2ecf20Sopenharmony_ci if (!p || !a || !b) 748c2ecf20Sopenharmony_ci goto free_p; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci x = mpi_scanval(ecp->g_x); 778c2ecf20Sopenharmony_ci y = mpi_scanval(ecp->g_y); 788c2ecf20Sopenharmony_ci if (!x || !y) 798c2ecf20Sopenharmony_ci goto free; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci rc = -ENOMEM; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci ec->Q = mpi_point_new(0); 848c2ecf20Sopenharmony_ci if (!ec->Q) 858c2ecf20Sopenharmony_ci goto free; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* mpi_ec_setup_elliptic_curve */ 888c2ecf20Sopenharmony_ci ec->G = mpi_point_new(0); 898c2ecf20Sopenharmony_ci if (!ec->G) { 908c2ecf20Sopenharmony_ci mpi_point_release(ec->Q); 918c2ecf20Sopenharmony_ci goto free; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci mpi_set(ec->G->x, x); 958c2ecf20Sopenharmony_ci mpi_set(ec->G->y, y); 968c2ecf20Sopenharmony_ci mpi_set_ui(ec->G->z, 1); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci rc = -EINVAL; 998c2ecf20Sopenharmony_ci ec->n = mpi_scanval(ecp->n); 1008c2ecf20Sopenharmony_ci if (!ec->n) { 1018c2ecf20Sopenharmony_ci mpi_point_release(ec->Q); 1028c2ecf20Sopenharmony_ci mpi_point_release(ec->G); 1038c2ecf20Sopenharmony_ci goto free; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci ec->h = ecp->h; 1078c2ecf20Sopenharmony_ci ec->name = ecp->desc; 1088c2ecf20Sopenharmony_ci mpi_ec_init(ec, ecp->model, ecp->dialect, 0, p, a, b); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci rc = 0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cifree: 1138c2ecf20Sopenharmony_ci mpi_free(x); 1148c2ecf20Sopenharmony_ci mpi_free(y); 1158c2ecf20Sopenharmony_cifree_p: 1168c2ecf20Sopenharmony_ci mpi_free(p); 1178c2ecf20Sopenharmony_ci mpi_free(a); 1188c2ecf20Sopenharmony_ci mpi_free(b); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return rc; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void sm2_ec_ctx_deinit(struct mpi_ec_ctx *ec) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci mpi_ec_deinit(ec); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci memset(ec, 0, sizeof(*ec)); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* RESULT must have been initialized and is set on success to the 1318c2ecf20Sopenharmony_ci * point given by VALUE. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic int sm2_ecc_os2ec(MPI_POINT result, MPI value) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci int rc; 1368c2ecf20Sopenharmony_ci size_t n; 1378c2ecf20Sopenharmony_ci unsigned char *buf; 1388c2ecf20Sopenharmony_ci MPI x, y; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci n = MPI_NBYTES(value); 1418c2ecf20Sopenharmony_ci buf = kmalloc(n, GFP_KERNEL); 1428c2ecf20Sopenharmony_ci if (!buf) 1438c2ecf20Sopenharmony_ci return -ENOMEM; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci rc = mpi_print(GCRYMPI_FMT_USG, buf, n, &n, value); 1468c2ecf20Sopenharmony_ci if (rc) 1478c2ecf20Sopenharmony_ci goto err_freebuf; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci rc = -EINVAL; 1508c2ecf20Sopenharmony_ci if (n < 1 || ((n - 1) % 2)) 1518c2ecf20Sopenharmony_ci goto err_freebuf; 1528c2ecf20Sopenharmony_ci /* No support for point compression */ 1538c2ecf20Sopenharmony_ci if (*buf != 0x4) 1548c2ecf20Sopenharmony_ci goto err_freebuf; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci rc = -ENOMEM; 1578c2ecf20Sopenharmony_ci n = (n - 1) / 2; 1588c2ecf20Sopenharmony_ci x = mpi_read_raw_data(buf + 1, n); 1598c2ecf20Sopenharmony_ci if (!x) 1608c2ecf20Sopenharmony_ci goto err_freebuf; 1618c2ecf20Sopenharmony_ci y = mpi_read_raw_data(buf + 1 + n, n); 1628c2ecf20Sopenharmony_ci if (!y) 1638c2ecf20Sopenharmony_ci goto err_freex; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci mpi_normalize(x); 1668c2ecf20Sopenharmony_ci mpi_normalize(y); 1678c2ecf20Sopenharmony_ci mpi_set(result->x, x); 1688c2ecf20Sopenharmony_ci mpi_set(result->y, y); 1698c2ecf20Sopenharmony_ci mpi_set_ui(result->z, 1); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci rc = 0; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci mpi_free(y); 1748c2ecf20Sopenharmony_cierr_freex: 1758c2ecf20Sopenharmony_ci mpi_free(x); 1768c2ecf20Sopenharmony_cierr_freebuf: 1778c2ecf20Sopenharmony_ci kfree(buf); 1788c2ecf20Sopenharmony_ci return rc; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistruct sm2_signature_ctx { 1828c2ecf20Sopenharmony_ci MPI sig_r; 1838c2ecf20Sopenharmony_ci MPI sig_s; 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ciint sm2_get_signature_r(void *context, size_t hdrlen, unsigned char tag, 1878c2ecf20Sopenharmony_ci const void *value, size_t vlen) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct sm2_signature_ctx *sig = context; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (!value || !vlen) 1928c2ecf20Sopenharmony_ci return -EINVAL; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci sig->sig_r = mpi_read_raw_data(value, vlen); 1958c2ecf20Sopenharmony_ci if (!sig->sig_r) 1968c2ecf20Sopenharmony_ci return -ENOMEM; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ciint sm2_get_signature_s(void *context, size_t hdrlen, unsigned char tag, 2028c2ecf20Sopenharmony_ci const void *value, size_t vlen) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct sm2_signature_ctx *sig = context; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (!value || !vlen) 2078c2ecf20Sopenharmony_ci return -EINVAL; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci sig->sig_s = mpi_read_raw_data(value, vlen); 2108c2ecf20Sopenharmony_ci if (!sig->sig_s) 2118c2ecf20Sopenharmony_ci return -ENOMEM; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int sm2_z_digest_update(struct shash_desc *desc, 2178c2ecf20Sopenharmony_ci MPI m, unsigned int pbytes) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci static const unsigned char zero[32]; 2208c2ecf20Sopenharmony_ci unsigned char *in; 2218c2ecf20Sopenharmony_ci unsigned int inlen; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci in = mpi_get_buffer(m, &inlen, NULL); 2248c2ecf20Sopenharmony_ci if (!in) 2258c2ecf20Sopenharmony_ci return -EINVAL; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (inlen < pbytes) { 2288c2ecf20Sopenharmony_ci /* padding with zero */ 2298c2ecf20Sopenharmony_ci crypto_sm3_update(desc, zero, pbytes - inlen); 2308c2ecf20Sopenharmony_ci crypto_sm3_update(desc, in, inlen); 2318c2ecf20Sopenharmony_ci } else if (inlen > pbytes) { 2328c2ecf20Sopenharmony_ci /* skip the starting zero */ 2338c2ecf20Sopenharmony_ci crypto_sm3_update(desc, in + inlen - pbytes, pbytes); 2348c2ecf20Sopenharmony_ci } else { 2358c2ecf20Sopenharmony_ci crypto_sm3_update(desc, in, inlen); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci kfree(in); 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int sm2_z_digest_update_point(struct shash_desc *desc, 2438c2ecf20Sopenharmony_ci MPI_POINT point, struct mpi_ec_ctx *ec, unsigned int pbytes) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci MPI x, y; 2468c2ecf20Sopenharmony_ci int ret = -EINVAL; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci x = mpi_new(0); 2498c2ecf20Sopenharmony_ci y = mpi_new(0); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (!mpi_ec_get_affine(x, y, point, ec) && 2528c2ecf20Sopenharmony_ci !sm2_z_digest_update(desc, x, pbytes) && 2538c2ecf20Sopenharmony_ci !sm2_z_digest_update(desc, y, pbytes)) 2548c2ecf20Sopenharmony_ci ret = 0; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci mpi_free(x); 2578c2ecf20Sopenharmony_ci mpi_free(y); 2588c2ecf20Sopenharmony_ci return ret; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ciint sm2_compute_z_digest(struct crypto_akcipher *tfm, 2628c2ecf20Sopenharmony_ci const unsigned char *id, size_t id_len, 2638c2ecf20Sopenharmony_ci unsigned char dgst[SM3_DIGEST_SIZE]) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); 2668c2ecf20Sopenharmony_ci uint16_t bits_len; 2678c2ecf20Sopenharmony_ci unsigned char entl[2]; 2688c2ecf20Sopenharmony_ci SHASH_DESC_ON_STACK(desc, NULL); 2698c2ecf20Sopenharmony_ci unsigned int pbytes; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (id_len > (USHRT_MAX / 8) || !ec->Q) 2728c2ecf20Sopenharmony_ci return -EINVAL; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci bits_len = (uint16_t)(id_len * 8); 2758c2ecf20Sopenharmony_ci entl[0] = bits_len >> 8; 2768c2ecf20Sopenharmony_ci entl[1] = bits_len & 0xff; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci pbytes = MPI_NBYTES(ec->p); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* ZA = H256(ENTLA | IDA | a | b | xG | yG | xA | yA) */ 2818c2ecf20Sopenharmony_ci sm3_base_init(desc); 2828c2ecf20Sopenharmony_ci crypto_sm3_update(desc, entl, 2); 2838c2ecf20Sopenharmony_ci crypto_sm3_update(desc, id, id_len); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (sm2_z_digest_update(desc, ec->a, pbytes) || 2868c2ecf20Sopenharmony_ci sm2_z_digest_update(desc, ec->b, pbytes) || 2878c2ecf20Sopenharmony_ci sm2_z_digest_update_point(desc, ec->G, ec, pbytes) || 2888c2ecf20Sopenharmony_ci sm2_z_digest_update_point(desc, ec->Q, ec, pbytes)) 2898c2ecf20Sopenharmony_ci return -EINVAL; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci crypto_sm3_final(desc, dgst); 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sm2_compute_z_digest); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int _sm2_verify(struct mpi_ec_ctx *ec, MPI hash, MPI sig_r, MPI sig_s) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci int rc = -EINVAL; 2998c2ecf20Sopenharmony_ci struct gcry_mpi_point sG, tP; 3008c2ecf20Sopenharmony_ci MPI t = NULL; 3018c2ecf20Sopenharmony_ci MPI x1 = NULL, y1 = NULL; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci mpi_point_init(&sG); 3048c2ecf20Sopenharmony_ci mpi_point_init(&tP); 3058c2ecf20Sopenharmony_ci x1 = mpi_new(0); 3068c2ecf20Sopenharmony_ci y1 = mpi_new(0); 3078c2ecf20Sopenharmony_ci t = mpi_new(0); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* r, s in [1, n-1] */ 3108c2ecf20Sopenharmony_ci if (mpi_cmp_ui(sig_r, 1) < 0 || mpi_cmp(sig_r, ec->n) > 0 || 3118c2ecf20Sopenharmony_ci mpi_cmp_ui(sig_s, 1) < 0 || mpi_cmp(sig_s, ec->n) > 0) { 3128c2ecf20Sopenharmony_ci goto leave; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* t = (r + s) % n, t == 0 */ 3168c2ecf20Sopenharmony_ci mpi_addm(t, sig_r, sig_s, ec->n); 3178c2ecf20Sopenharmony_ci if (mpi_cmp_ui(t, 0) == 0) 3188c2ecf20Sopenharmony_ci goto leave; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* sG + tP = (x1, y1) */ 3218c2ecf20Sopenharmony_ci rc = -EBADMSG; 3228c2ecf20Sopenharmony_ci mpi_ec_mul_point(&sG, sig_s, ec->G, ec); 3238c2ecf20Sopenharmony_ci mpi_ec_mul_point(&tP, t, ec->Q, ec); 3248c2ecf20Sopenharmony_ci mpi_ec_add_points(&sG, &sG, &tP, ec); 3258c2ecf20Sopenharmony_ci if (mpi_ec_get_affine(x1, y1, &sG, ec)) 3268c2ecf20Sopenharmony_ci goto leave; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* R = (e + x1) % n */ 3298c2ecf20Sopenharmony_ci mpi_addm(t, hash, x1, ec->n); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* check R == r */ 3328c2ecf20Sopenharmony_ci rc = -EKEYREJECTED; 3338c2ecf20Sopenharmony_ci if (mpi_cmp(t, sig_r)) 3348c2ecf20Sopenharmony_ci goto leave; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci rc = 0; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cileave: 3398c2ecf20Sopenharmony_ci mpi_point_free_parts(&sG); 3408c2ecf20Sopenharmony_ci mpi_point_free_parts(&tP); 3418c2ecf20Sopenharmony_ci mpi_free(x1); 3428c2ecf20Sopenharmony_ci mpi_free(y1); 3438c2ecf20Sopenharmony_ci mpi_free(t); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return rc; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int sm2_verify(struct akcipher_request *req) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); 3518c2ecf20Sopenharmony_ci struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); 3528c2ecf20Sopenharmony_ci unsigned char *buffer; 3538c2ecf20Sopenharmony_ci struct sm2_signature_ctx sig; 3548c2ecf20Sopenharmony_ci MPI hash; 3558c2ecf20Sopenharmony_ci int ret; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (unlikely(!ec->Q)) 3588c2ecf20Sopenharmony_ci return -EINVAL; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); 3618c2ecf20Sopenharmony_ci if (!buffer) 3628c2ecf20Sopenharmony_ci return -ENOMEM; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci sg_pcopy_to_buffer(req->src, 3658c2ecf20Sopenharmony_ci sg_nents_for_len(req->src, req->src_len + req->dst_len), 3668c2ecf20Sopenharmony_ci buffer, req->src_len + req->dst_len, 0); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci sig.sig_r = NULL; 3698c2ecf20Sopenharmony_ci sig.sig_s = NULL; 3708c2ecf20Sopenharmony_ci ret = asn1_ber_decoder(&sm2signature_decoder, &sig, 3718c2ecf20Sopenharmony_ci buffer, req->src_len); 3728c2ecf20Sopenharmony_ci if (ret) 3738c2ecf20Sopenharmony_ci goto error; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ret = -ENOMEM; 3768c2ecf20Sopenharmony_ci hash = mpi_read_raw_data(buffer + req->src_len, req->dst_len); 3778c2ecf20Sopenharmony_ci if (!hash) 3788c2ecf20Sopenharmony_ci goto error; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ret = _sm2_verify(ec, hash, sig.sig_r, sig.sig_s); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci mpi_free(hash); 3838c2ecf20Sopenharmony_cierror: 3848c2ecf20Sopenharmony_ci mpi_free(sig.sig_r); 3858c2ecf20Sopenharmony_ci mpi_free(sig.sig_s); 3868c2ecf20Sopenharmony_ci kfree(buffer); 3878c2ecf20Sopenharmony_ci return ret; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int sm2_set_pub_key(struct crypto_akcipher *tfm, 3918c2ecf20Sopenharmony_ci const void *key, unsigned int keylen) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); 3948c2ecf20Sopenharmony_ci MPI a; 3958c2ecf20Sopenharmony_ci int rc; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* include the uncompressed flag '0x04' */ 3988c2ecf20Sopenharmony_ci a = mpi_read_raw_data(key, keylen); 3998c2ecf20Sopenharmony_ci if (!a) 4008c2ecf20Sopenharmony_ci return -ENOMEM; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci mpi_normalize(a); 4038c2ecf20Sopenharmony_ci rc = sm2_ecc_os2ec(ec->Q, a); 4048c2ecf20Sopenharmony_ci mpi_free(a); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return rc; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic unsigned int sm2_max_size(struct crypto_akcipher *tfm) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci /* Unlimited max size */ 4128c2ecf20Sopenharmony_ci return PAGE_SIZE; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int sm2_init_tfm(struct crypto_akcipher *tfm) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return sm2_ec_ctx_init(ec); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic void sm2_exit_tfm(struct crypto_akcipher *tfm) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci sm2_ec_ctx_deinit(ec); 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic struct akcipher_alg sm2 = { 4308c2ecf20Sopenharmony_ci .verify = sm2_verify, 4318c2ecf20Sopenharmony_ci .set_pub_key = sm2_set_pub_key, 4328c2ecf20Sopenharmony_ci .max_size = sm2_max_size, 4338c2ecf20Sopenharmony_ci .init = sm2_init_tfm, 4348c2ecf20Sopenharmony_ci .exit = sm2_exit_tfm, 4358c2ecf20Sopenharmony_ci .base = { 4368c2ecf20Sopenharmony_ci .cra_name = "sm2", 4378c2ecf20Sopenharmony_ci .cra_driver_name = "sm2-generic", 4388c2ecf20Sopenharmony_ci .cra_priority = 100, 4398c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 4408c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct mpi_ec_ctx), 4418c2ecf20Sopenharmony_ci }, 4428c2ecf20Sopenharmony_ci}; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int sm2_init(void) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci return crypto_register_akcipher(&sm2); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic void sm2_exit(void) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci crypto_unregister_akcipher(&sm2); 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cisubsys_initcall(sm2_init); 4558c2ecf20Sopenharmony_cimodule_exit(sm2_exit); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4588c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tianjia Zhang <tianjia.zhang@linux.alibaba.com>"); 4598c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SM2 generic algorithm"); 4608c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("sm2-generic"); 461