18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2021 IBM Corporation 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <crypto/internal/akcipher.h> 88c2ecf20Sopenharmony_ci#include <crypto/akcipher.h> 98c2ecf20Sopenharmony_ci#include <crypto/ecdh.h> 108c2ecf20Sopenharmony_ci#include <linux/asn1_decoder.h> 118c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "ecc.h" 148c2ecf20Sopenharmony_ci#include "ecdsasignature.asn1.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistruct ecc_ctx { 178c2ecf20Sopenharmony_ci unsigned int curve_id; 188c2ecf20Sopenharmony_ci const struct ecc_curve *curve; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci bool pub_key_set; 218c2ecf20Sopenharmony_ci u64 x[ECC_MAX_DIGITS]; /* pub key x and y coordinates */ 228c2ecf20Sopenharmony_ci u64 y[ECC_MAX_DIGITS]; 238c2ecf20Sopenharmony_ci struct ecc_point pub_key; 248c2ecf20Sopenharmony_ci}; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct ecdsa_signature_ctx { 278c2ecf20Sopenharmony_ci const struct ecc_curve *curve; 288c2ecf20Sopenharmony_ci u64 r[ECC_MAX_DIGITS]; 298c2ecf20Sopenharmony_ci u64 s[ECC_MAX_DIGITS]; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Get the r and s components of a signature from the X509 certificate. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_cistatic int ecdsa_get_signature_rs(u64 *dest, size_t hdrlen, unsigned char tag, 368c2ecf20Sopenharmony_ci const void *value, size_t vlen, unsigned int ndigits) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci size_t keylen = ndigits * sizeof(u64); 398c2ecf20Sopenharmony_ci ssize_t diff = vlen - keylen; 408c2ecf20Sopenharmony_ci const char *d = value; 418c2ecf20Sopenharmony_ci u8 rs[ECC_MAX_BYTES]; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (!value || !vlen) 448c2ecf20Sopenharmony_ci return -EINVAL; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* diff = 0: 'value' has exacly the right size 478c2ecf20Sopenharmony_ci * diff > 0: 'value' has too many bytes; one leading zero is allowed that 488c2ecf20Sopenharmony_ci * makes the value a positive integer; error on more 498c2ecf20Sopenharmony_ci * diff < 0: 'value' is missing leading zeros, which we add 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci if (diff > 0) { 528c2ecf20Sopenharmony_ci /* skip over leading zeros that make 'value' a positive int */ 538c2ecf20Sopenharmony_ci if (*d == 0) { 548c2ecf20Sopenharmony_ci vlen -= 1; 558c2ecf20Sopenharmony_ci diff--; 568c2ecf20Sopenharmony_ci d++; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci if (diff) 598c2ecf20Sopenharmony_ci return -EINVAL; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci if (-diff >= keylen) 628c2ecf20Sopenharmony_ci return -EINVAL; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (diff) { 658c2ecf20Sopenharmony_ci /* leading zeros not given in 'value' */ 668c2ecf20Sopenharmony_ci memset(rs, 0, -diff); 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci memcpy(&rs[-diff], d, vlen); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ecc_swap_digits((u64 *)rs, dest, ndigits); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ciint ecdsa_get_signature_r(void *context, size_t hdrlen, unsigned char tag, 778c2ecf20Sopenharmony_ci const void *value, size_t vlen) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct ecdsa_signature_ctx *sig = context; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return ecdsa_get_signature_rs(sig->r, hdrlen, tag, value, vlen, 828c2ecf20Sopenharmony_ci sig->curve->g.ndigits); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ciint ecdsa_get_signature_s(void *context, size_t hdrlen, unsigned char tag, 868c2ecf20Sopenharmony_ci const void *value, size_t vlen) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct ecdsa_signature_ctx *sig = context; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return ecdsa_get_signature_rs(sig->s, hdrlen, tag, value, vlen, 918c2ecf20Sopenharmony_ci sig->curve->g.ndigits); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int _ecdsa_verify(struct ecc_ctx *ctx, const u64 *hash, const u64 *r, const u64 *s) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci const struct ecc_curve *curve = ctx->curve; 978c2ecf20Sopenharmony_ci unsigned int ndigits = curve->g.ndigits; 988c2ecf20Sopenharmony_ci u64 s1[ECC_MAX_DIGITS]; 998c2ecf20Sopenharmony_ci u64 u1[ECC_MAX_DIGITS]; 1008c2ecf20Sopenharmony_ci u64 u2[ECC_MAX_DIGITS]; 1018c2ecf20Sopenharmony_ci u64 x1[ECC_MAX_DIGITS]; 1028c2ecf20Sopenharmony_ci u64 y1[ECC_MAX_DIGITS]; 1038c2ecf20Sopenharmony_ci struct ecc_point res = ECC_POINT_INIT(x1, y1, ndigits); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* 0 < r < n and 0 < s < n */ 1068c2ecf20Sopenharmony_ci if (vli_is_zero(r, ndigits) || vli_cmp(r, curve->n, ndigits) >= 0 || 1078c2ecf20Sopenharmony_ci vli_is_zero(s, ndigits) || vli_cmp(s, curve->n, ndigits) >= 0) 1088c2ecf20Sopenharmony_ci return -EBADMSG; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* hash is given */ 1118c2ecf20Sopenharmony_ci pr_devel("hash : %016llx %016llx ... %016llx\n", 1128c2ecf20Sopenharmony_ci hash[ndigits - 1], hash[ndigits - 2], hash[0]); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* s1 = (s^-1) mod n */ 1158c2ecf20Sopenharmony_ci vli_mod_inv(s1, s, curve->n, ndigits); 1168c2ecf20Sopenharmony_ci /* u1 = (hash * s1) mod n */ 1178c2ecf20Sopenharmony_ci vli_mod_mult_slow(u1, hash, s1, curve->n, ndigits); 1188c2ecf20Sopenharmony_ci /* u2 = (r * s1) mod n */ 1198c2ecf20Sopenharmony_ci vli_mod_mult_slow(u2, r, s1, curve->n, ndigits); 1208c2ecf20Sopenharmony_ci /* res = u1*G + u2 * pub_key */ 1218c2ecf20Sopenharmony_ci ecc_point_mult_shamir(&res, u1, &curve->g, u2, &ctx->pub_key, curve); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* res.x = res.x mod n (if res.x > order) */ 1248c2ecf20Sopenharmony_ci if (unlikely(vli_cmp(res.x, curve->n, ndigits) == 1)) 1258c2ecf20Sopenharmony_ci /* faster alternative for NIST p384, p256 & p192 */ 1268c2ecf20Sopenharmony_ci vli_sub(res.x, res.x, curve->n, ndigits); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (!vli_cmp(res.x, r, ndigits)) 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return -EKEYREJECTED; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* 1358c2ecf20Sopenharmony_ci * Verify an ECDSA signature. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_cistatic int ecdsa_verify(struct akcipher_request *req) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); 1408c2ecf20Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 1418c2ecf20Sopenharmony_ci size_t keylen = ctx->curve->g.ndigits * sizeof(u64); 1428c2ecf20Sopenharmony_ci struct ecdsa_signature_ctx sig_ctx = { 1438c2ecf20Sopenharmony_ci .curve = ctx->curve, 1448c2ecf20Sopenharmony_ci }; 1458c2ecf20Sopenharmony_ci u8 rawhash[ECC_MAX_BYTES]; 1468c2ecf20Sopenharmony_ci u64 hash[ECC_MAX_DIGITS]; 1478c2ecf20Sopenharmony_ci unsigned char *buffer; 1488c2ecf20Sopenharmony_ci ssize_t diff; 1498c2ecf20Sopenharmony_ci int ret; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (unlikely(!ctx->pub_key_set)) 1528c2ecf20Sopenharmony_ci return -EINVAL; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); 1558c2ecf20Sopenharmony_ci if (!buffer) 1568c2ecf20Sopenharmony_ci return -ENOMEM; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci sg_pcopy_to_buffer(req->src, 1598c2ecf20Sopenharmony_ci sg_nents_for_len(req->src, req->src_len + req->dst_len), 1608c2ecf20Sopenharmony_ci buffer, req->src_len + req->dst_len, 0); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ret = asn1_ber_decoder(&ecdsasignature_decoder, &sig_ctx, 1638c2ecf20Sopenharmony_ci buffer, req->src_len); 1648c2ecf20Sopenharmony_ci if (ret < 0) 1658c2ecf20Sopenharmony_ci goto error; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* if the hash is shorter then we will add leading zeros to fit to ndigits */ 1688c2ecf20Sopenharmony_ci diff = keylen - req->dst_len; 1698c2ecf20Sopenharmony_ci if (diff >= 0) { 1708c2ecf20Sopenharmony_ci if (diff) 1718c2ecf20Sopenharmony_ci memset(rawhash, 0, diff); 1728c2ecf20Sopenharmony_ci memcpy(&rawhash[diff], buffer + req->src_len, req->dst_len); 1738c2ecf20Sopenharmony_ci } else if (diff < 0) { 1748c2ecf20Sopenharmony_ci /* given hash is longer, we take the left-most bytes */ 1758c2ecf20Sopenharmony_ci memcpy(&rawhash, buffer + req->src_len, keylen); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci ecc_swap_digits((u64 *)rawhash, hash, ctx->curve->g.ndigits); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ret = _ecdsa_verify(ctx, hash, sig_ctx.r, sig_ctx.s); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cierror: 1838c2ecf20Sopenharmony_ci kfree(buffer); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return ret; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int ecdsa_ecc_ctx_init(struct ecc_ctx *ctx, unsigned int curve_id) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci ctx->curve_id = curve_id; 1918c2ecf20Sopenharmony_ci ctx->curve = ecc_get_curve(curve_id); 1928c2ecf20Sopenharmony_ci if (!ctx->curve) 1938c2ecf20Sopenharmony_ci return -EINVAL; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic void ecdsa_ecc_ctx_deinit(struct ecc_ctx *ctx) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci ctx->pub_key_set = false; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int ecdsa_ecc_ctx_reset(struct ecc_ctx *ctx) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci unsigned int curve_id = ctx->curve_id; 2078c2ecf20Sopenharmony_ci int ret; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ecdsa_ecc_ctx_deinit(ctx); 2108c2ecf20Sopenharmony_ci ret = ecdsa_ecc_ctx_init(ctx, curve_id); 2118c2ecf20Sopenharmony_ci if (ret == 0) 2128c2ecf20Sopenharmony_ci ctx->pub_key = ECC_POINT_INIT(ctx->x, ctx->y, 2138c2ecf20Sopenharmony_ci ctx->curve->g.ndigits); 2148c2ecf20Sopenharmony_ci return ret; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/* 2188c2ecf20Sopenharmony_ci * Set the public key given the raw uncompressed key data from an X509 2198c2ecf20Sopenharmony_ci * certificate. The key data contain the concatenated X and Y coordinates of 2208c2ecf20Sopenharmony_ci * the public key. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_cistatic int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 2258c2ecf20Sopenharmony_ci const unsigned char *d = key; 2268c2ecf20Sopenharmony_ci const u64 *digits = (const u64 *)&d[1]; 2278c2ecf20Sopenharmony_ci unsigned int ndigits; 2288c2ecf20Sopenharmony_ci int ret; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci ret = ecdsa_ecc_ctx_reset(ctx); 2318c2ecf20Sopenharmony_ci if (ret < 0) 2328c2ecf20Sopenharmony_ci return ret; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (keylen < 1 || (((keylen - 1) >> 1) % sizeof(u64)) != 0) 2358c2ecf20Sopenharmony_ci return -EINVAL; 2368c2ecf20Sopenharmony_ci /* we only accept uncompressed format indicated by '4' */ 2378c2ecf20Sopenharmony_ci if (d[0] != 4) 2388c2ecf20Sopenharmony_ci return -EINVAL; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci keylen--; 2418c2ecf20Sopenharmony_ci ndigits = (keylen >> 1) / sizeof(u64); 2428c2ecf20Sopenharmony_ci if (ndigits != ctx->curve->g.ndigits) 2438c2ecf20Sopenharmony_ci return -EINVAL; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci ecc_swap_digits(digits, ctx->pub_key.x, ndigits); 2468c2ecf20Sopenharmony_ci ecc_swap_digits(&digits[ndigits], ctx->pub_key.y, ndigits); 2478c2ecf20Sopenharmony_ci ret = ecc_is_pubkey_valid_full(ctx->curve, &ctx->pub_key); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci ctx->pub_key_set = ret == 0; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return ret; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void ecdsa_exit_tfm(struct crypto_akcipher *tfm) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci ecdsa_ecc_ctx_deinit(ctx); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic unsigned int ecdsa_max_size(struct crypto_akcipher *tfm) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return ctx->pub_key.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic int ecdsa_nist_p384_init_tfm(struct crypto_akcipher *tfm) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P384); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic struct akcipher_alg ecdsa_nist_p384 = { 2768c2ecf20Sopenharmony_ci .verify = ecdsa_verify, 2778c2ecf20Sopenharmony_ci .set_pub_key = ecdsa_set_pub_key, 2788c2ecf20Sopenharmony_ci .max_size = ecdsa_max_size, 2798c2ecf20Sopenharmony_ci .init = ecdsa_nist_p384_init_tfm, 2808c2ecf20Sopenharmony_ci .exit = ecdsa_exit_tfm, 2818c2ecf20Sopenharmony_ci .base = { 2828c2ecf20Sopenharmony_ci .cra_name = "ecdsa-nist-p384", 2838c2ecf20Sopenharmony_ci .cra_driver_name = "ecdsa-nist-p384-generic", 2848c2ecf20Sopenharmony_ci .cra_priority = 100, 2858c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 2868c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct ecc_ctx), 2878c2ecf20Sopenharmony_ci }, 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int ecdsa_nist_p256_init_tfm(struct crypto_akcipher *tfm) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P256); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic struct akcipher_alg ecdsa_nist_p256 = { 2988c2ecf20Sopenharmony_ci .verify = ecdsa_verify, 2998c2ecf20Sopenharmony_ci .set_pub_key = ecdsa_set_pub_key, 3008c2ecf20Sopenharmony_ci .max_size = ecdsa_max_size, 3018c2ecf20Sopenharmony_ci .init = ecdsa_nist_p256_init_tfm, 3028c2ecf20Sopenharmony_ci .exit = ecdsa_exit_tfm, 3038c2ecf20Sopenharmony_ci .base = { 3048c2ecf20Sopenharmony_ci .cra_name = "ecdsa-nist-p256", 3058c2ecf20Sopenharmony_ci .cra_driver_name = "ecdsa-nist-p256-generic", 3068c2ecf20Sopenharmony_ci .cra_priority = 100, 3078c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 3088c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct ecc_ctx), 3098c2ecf20Sopenharmony_ci }, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic int ecdsa_nist_p192_init_tfm(struct crypto_akcipher *tfm) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P192); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic struct akcipher_alg ecdsa_nist_p192 = { 3208c2ecf20Sopenharmony_ci .verify = ecdsa_verify, 3218c2ecf20Sopenharmony_ci .set_pub_key = ecdsa_set_pub_key, 3228c2ecf20Sopenharmony_ci .max_size = ecdsa_max_size, 3238c2ecf20Sopenharmony_ci .init = ecdsa_nist_p192_init_tfm, 3248c2ecf20Sopenharmony_ci .exit = ecdsa_exit_tfm, 3258c2ecf20Sopenharmony_ci .base = { 3268c2ecf20Sopenharmony_ci .cra_name = "ecdsa-nist-p192", 3278c2ecf20Sopenharmony_ci .cra_driver_name = "ecdsa-nist-p192-generic", 3288c2ecf20Sopenharmony_ci .cra_priority = 100, 3298c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 3308c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct ecc_ctx), 3318c2ecf20Sopenharmony_ci }, 3328c2ecf20Sopenharmony_ci}; 3338c2ecf20Sopenharmony_cistatic bool ecdsa_nist_p192_registered; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int ecdsa_init(void) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci int ret; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* NIST p192 may not be available in FIPS mode */ 3408c2ecf20Sopenharmony_ci ret = crypto_register_akcipher(&ecdsa_nist_p192); 3418c2ecf20Sopenharmony_ci ecdsa_nist_p192_registered = ret == 0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci ret = crypto_register_akcipher(&ecdsa_nist_p256); 3448c2ecf20Sopenharmony_ci if (ret) 3458c2ecf20Sopenharmony_ci goto nist_p256_error; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci ret = crypto_register_akcipher(&ecdsa_nist_p384); 3488c2ecf20Sopenharmony_ci if (ret) 3498c2ecf20Sopenharmony_ci goto nist_p384_error; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cinist_p384_error: 3548c2ecf20Sopenharmony_ci crypto_unregister_akcipher(&ecdsa_nist_p256); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cinist_p256_error: 3578c2ecf20Sopenharmony_ci if (ecdsa_nist_p192_registered) 3588c2ecf20Sopenharmony_ci crypto_unregister_akcipher(&ecdsa_nist_p192); 3598c2ecf20Sopenharmony_ci return ret; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic void ecdsa_exit(void) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci if (ecdsa_nist_p192_registered) 3658c2ecf20Sopenharmony_ci crypto_unregister_akcipher(&ecdsa_nist_p192); 3668c2ecf20Sopenharmony_ci crypto_unregister_akcipher(&ecdsa_nist_p256); 3678c2ecf20Sopenharmony_ci crypto_unregister_akcipher(&ecdsa_nist_p384); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cisubsys_initcall(ecdsa_init); 3718c2ecf20Sopenharmony_cimodule_exit(ecdsa_exit); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stefan Berger <stefanb@linux.ibm.com>"); 3758c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ECDSA generic algorithm"); 3768c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("ecdsa-generic"); 377