162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2021 IBM Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <crypto/internal/akcipher.h> 862306a36Sopenharmony_ci#include <crypto/internal/ecc.h> 962306a36Sopenharmony_ci#include <crypto/akcipher.h> 1062306a36Sopenharmony_ci#include <crypto/ecdh.h> 1162306a36Sopenharmony_ci#include <linux/asn1_decoder.h> 1262306a36Sopenharmony_ci#include <linux/scatterlist.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "ecdsasignature.asn1.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct ecc_ctx { 1762306a36Sopenharmony_ci unsigned int curve_id; 1862306a36Sopenharmony_ci const struct ecc_curve *curve; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci bool pub_key_set; 2162306a36Sopenharmony_ci u64 x[ECC_MAX_DIGITS]; /* pub key x and y coordinates */ 2262306a36Sopenharmony_ci u64 y[ECC_MAX_DIGITS]; 2362306a36Sopenharmony_ci struct ecc_point pub_key; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct ecdsa_signature_ctx { 2762306a36Sopenharmony_ci const struct ecc_curve *curve; 2862306a36Sopenharmony_ci u64 r[ECC_MAX_DIGITS]; 2962306a36Sopenharmony_ci u64 s[ECC_MAX_DIGITS]; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * Get the r and s components of a signature from the X509 certificate. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cistatic int ecdsa_get_signature_rs(u64 *dest, size_t hdrlen, unsigned char tag, 3662306a36Sopenharmony_ci const void *value, size_t vlen, unsigned int ndigits) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci size_t keylen = ndigits * sizeof(u64); 3962306a36Sopenharmony_ci ssize_t diff = vlen - keylen; 4062306a36Sopenharmony_ci const char *d = value; 4162306a36Sopenharmony_ci u8 rs[ECC_MAX_BYTES]; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!value || !vlen) 4462306a36Sopenharmony_ci return -EINVAL; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* diff = 0: 'value' has exacly the right size 4762306a36Sopenharmony_ci * diff > 0: 'value' has too many bytes; one leading zero is allowed that 4862306a36Sopenharmony_ci * makes the value a positive integer; error on more 4962306a36Sopenharmony_ci * diff < 0: 'value' is missing leading zeros, which we add 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci if (diff > 0) { 5262306a36Sopenharmony_ci /* skip over leading zeros that make 'value' a positive int */ 5362306a36Sopenharmony_ci if (*d == 0) { 5462306a36Sopenharmony_ci vlen -= 1; 5562306a36Sopenharmony_ci diff--; 5662306a36Sopenharmony_ci d++; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci if (diff) 5962306a36Sopenharmony_ci return -EINVAL; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci if (-diff >= keylen) 6262306a36Sopenharmony_ci return -EINVAL; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (diff) { 6562306a36Sopenharmony_ci /* leading zeros not given in 'value' */ 6662306a36Sopenharmony_ci memset(rs, 0, -diff); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci memcpy(&rs[-diff], d, vlen); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci ecc_swap_digits((u64 *)rs, dest, ndigits); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciint ecdsa_get_signature_r(void *context, size_t hdrlen, unsigned char tag, 7762306a36Sopenharmony_ci const void *value, size_t vlen) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct ecdsa_signature_ctx *sig = context; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return ecdsa_get_signature_rs(sig->r, hdrlen, tag, value, vlen, 8262306a36Sopenharmony_ci sig->curve->g.ndigits); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ciint ecdsa_get_signature_s(void *context, size_t hdrlen, unsigned char tag, 8662306a36Sopenharmony_ci const void *value, size_t vlen) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct ecdsa_signature_ctx *sig = context; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return ecdsa_get_signature_rs(sig->s, hdrlen, tag, value, vlen, 9162306a36Sopenharmony_ci sig->curve->g.ndigits); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int _ecdsa_verify(struct ecc_ctx *ctx, const u64 *hash, const u64 *r, const u64 *s) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci const struct ecc_curve *curve = ctx->curve; 9762306a36Sopenharmony_ci unsigned int ndigits = curve->g.ndigits; 9862306a36Sopenharmony_ci u64 s1[ECC_MAX_DIGITS]; 9962306a36Sopenharmony_ci u64 u1[ECC_MAX_DIGITS]; 10062306a36Sopenharmony_ci u64 u2[ECC_MAX_DIGITS]; 10162306a36Sopenharmony_ci u64 x1[ECC_MAX_DIGITS]; 10262306a36Sopenharmony_ci u64 y1[ECC_MAX_DIGITS]; 10362306a36Sopenharmony_ci struct ecc_point res = ECC_POINT_INIT(x1, y1, ndigits); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* 0 < r < n and 0 < s < n */ 10662306a36Sopenharmony_ci if (vli_is_zero(r, ndigits) || vli_cmp(r, curve->n, ndigits) >= 0 || 10762306a36Sopenharmony_ci vli_is_zero(s, ndigits) || vli_cmp(s, curve->n, ndigits) >= 0) 10862306a36Sopenharmony_ci return -EBADMSG; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* hash is given */ 11162306a36Sopenharmony_ci pr_devel("hash : %016llx %016llx ... %016llx\n", 11262306a36Sopenharmony_ci hash[ndigits - 1], hash[ndigits - 2], hash[0]); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* s1 = (s^-1) mod n */ 11562306a36Sopenharmony_ci vli_mod_inv(s1, s, curve->n, ndigits); 11662306a36Sopenharmony_ci /* u1 = (hash * s1) mod n */ 11762306a36Sopenharmony_ci vli_mod_mult_slow(u1, hash, s1, curve->n, ndigits); 11862306a36Sopenharmony_ci /* u2 = (r * s1) mod n */ 11962306a36Sopenharmony_ci vli_mod_mult_slow(u2, r, s1, curve->n, ndigits); 12062306a36Sopenharmony_ci /* res = u1*G + u2 * pub_key */ 12162306a36Sopenharmony_ci ecc_point_mult_shamir(&res, u1, &curve->g, u2, &ctx->pub_key, curve); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* res.x = res.x mod n (if res.x > order) */ 12462306a36Sopenharmony_ci if (unlikely(vli_cmp(res.x, curve->n, ndigits) == 1)) 12562306a36Sopenharmony_ci /* faster alternative for NIST p384, p256 & p192 */ 12662306a36Sopenharmony_ci vli_sub(res.x, res.x, curve->n, ndigits); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (!vli_cmp(res.x, r, ndigits)) 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return -EKEYREJECTED; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* 13562306a36Sopenharmony_ci * Verify an ECDSA signature. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_cistatic int ecdsa_verify(struct akcipher_request *req) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); 14062306a36Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 14162306a36Sopenharmony_ci size_t keylen = ctx->curve->g.ndigits * sizeof(u64); 14262306a36Sopenharmony_ci struct ecdsa_signature_ctx sig_ctx = { 14362306a36Sopenharmony_ci .curve = ctx->curve, 14462306a36Sopenharmony_ci }; 14562306a36Sopenharmony_ci u8 rawhash[ECC_MAX_BYTES]; 14662306a36Sopenharmony_ci u64 hash[ECC_MAX_DIGITS]; 14762306a36Sopenharmony_ci unsigned char *buffer; 14862306a36Sopenharmony_ci ssize_t diff; 14962306a36Sopenharmony_ci int ret; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (unlikely(!ctx->pub_key_set)) 15262306a36Sopenharmony_ci return -EINVAL; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); 15562306a36Sopenharmony_ci if (!buffer) 15662306a36Sopenharmony_ci return -ENOMEM; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci sg_pcopy_to_buffer(req->src, 15962306a36Sopenharmony_ci sg_nents_for_len(req->src, req->src_len + req->dst_len), 16062306a36Sopenharmony_ci buffer, req->src_len + req->dst_len, 0); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci ret = asn1_ber_decoder(&ecdsasignature_decoder, &sig_ctx, 16362306a36Sopenharmony_ci buffer, req->src_len); 16462306a36Sopenharmony_ci if (ret < 0) 16562306a36Sopenharmony_ci goto error; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* if the hash is shorter then we will add leading zeros to fit to ndigits */ 16862306a36Sopenharmony_ci diff = keylen - req->dst_len; 16962306a36Sopenharmony_ci if (diff >= 0) { 17062306a36Sopenharmony_ci if (diff) 17162306a36Sopenharmony_ci memset(rawhash, 0, diff); 17262306a36Sopenharmony_ci memcpy(&rawhash[diff], buffer + req->src_len, req->dst_len); 17362306a36Sopenharmony_ci } else if (diff < 0) { 17462306a36Sopenharmony_ci /* given hash is longer, we take the left-most bytes */ 17562306a36Sopenharmony_ci memcpy(&rawhash, buffer + req->src_len, keylen); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci ecc_swap_digits((u64 *)rawhash, hash, ctx->curve->g.ndigits); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ret = _ecdsa_verify(ctx, hash, sig_ctx.r, sig_ctx.s); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cierror: 18362306a36Sopenharmony_ci kfree(buffer); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return ret; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int ecdsa_ecc_ctx_init(struct ecc_ctx *ctx, unsigned int curve_id) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci ctx->curve_id = curve_id; 19162306a36Sopenharmony_ci ctx->curve = ecc_get_curve(curve_id); 19262306a36Sopenharmony_ci if (!ctx->curve) 19362306a36Sopenharmony_ci return -EINVAL; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void ecdsa_ecc_ctx_deinit(struct ecc_ctx *ctx) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci ctx->pub_key_set = false; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int ecdsa_ecc_ctx_reset(struct ecc_ctx *ctx) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci unsigned int curve_id = ctx->curve_id; 20762306a36Sopenharmony_ci int ret; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci ecdsa_ecc_ctx_deinit(ctx); 21062306a36Sopenharmony_ci ret = ecdsa_ecc_ctx_init(ctx, curve_id); 21162306a36Sopenharmony_ci if (ret == 0) 21262306a36Sopenharmony_ci ctx->pub_key = ECC_POINT_INIT(ctx->x, ctx->y, 21362306a36Sopenharmony_ci ctx->curve->g.ndigits); 21462306a36Sopenharmony_ci return ret; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* 21862306a36Sopenharmony_ci * Set the public key given the raw uncompressed key data from an X509 21962306a36Sopenharmony_ci * certificate. The key data contain the concatenated X and Y coordinates of 22062306a36Sopenharmony_ci * the public key. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_cistatic int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 22562306a36Sopenharmony_ci const unsigned char *d = key; 22662306a36Sopenharmony_ci const u64 *digits = (const u64 *)&d[1]; 22762306a36Sopenharmony_ci unsigned int ndigits; 22862306a36Sopenharmony_ci int ret; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci ret = ecdsa_ecc_ctx_reset(ctx); 23162306a36Sopenharmony_ci if (ret < 0) 23262306a36Sopenharmony_ci return ret; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (keylen < 1 || (((keylen - 1) >> 1) % sizeof(u64)) != 0) 23562306a36Sopenharmony_ci return -EINVAL; 23662306a36Sopenharmony_ci /* we only accept uncompressed format indicated by '4' */ 23762306a36Sopenharmony_ci if (d[0] != 4) 23862306a36Sopenharmony_ci return -EINVAL; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci keylen--; 24162306a36Sopenharmony_ci ndigits = (keylen >> 1) / sizeof(u64); 24262306a36Sopenharmony_ci if (ndigits != ctx->curve->g.ndigits) 24362306a36Sopenharmony_ci return -EINVAL; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci ecc_swap_digits(digits, ctx->pub_key.x, ndigits); 24662306a36Sopenharmony_ci ecc_swap_digits(&digits[ndigits], ctx->pub_key.y, ndigits); 24762306a36Sopenharmony_ci ret = ecc_is_pubkey_valid_full(ctx->curve, &ctx->pub_key); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci ctx->pub_key_set = ret == 0; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return ret; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic void ecdsa_exit_tfm(struct crypto_akcipher *tfm) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci ecdsa_ecc_ctx_deinit(ctx); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic unsigned int ecdsa_max_size(struct crypto_akcipher *tfm) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return ctx->pub_key.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int ecdsa_nist_p384_init_tfm(struct crypto_akcipher *tfm) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P384); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic struct akcipher_alg ecdsa_nist_p384 = { 27662306a36Sopenharmony_ci .verify = ecdsa_verify, 27762306a36Sopenharmony_ci .set_pub_key = ecdsa_set_pub_key, 27862306a36Sopenharmony_ci .max_size = ecdsa_max_size, 27962306a36Sopenharmony_ci .init = ecdsa_nist_p384_init_tfm, 28062306a36Sopenharmony_ci .exit = ecdsa_exit_tfm, 28162306a36Sopenharmony_ci .base = { 28262306a36Sopenharmony_ci .cra_name = "ecdsa-nist-p384", 28362306a36Sopenharmony_ci .cra_driver_name = "ecdsa-nist-p384-generic", 28462306a36Sopenharmony_ci .cra_priority = 100, 28562306a36Sopenharmony_ci .cra_module = THIS_MODULE, 28662306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct ecc_ctx), 28762306a36Sopenharmony_ci }, 28862306a36Sopenharmony_ci}; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic int ecdsa_nist_p256_init_tfm(struct crypto_akcipher *tfm) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P256); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic struct akcipher_alg ecdsa_nist_p256 = { 29862306a36Sopenharmony_ci .verify = ecdsa_verify, 29962306a36Sopenharmony_ci .set_pub_key = ecdsa_set_pub_key, 30062306a36Sopenharmony_ci .max_size = ecdsa_max_size, 30162306a36Sopenharmony_ci .init = ecdsa_nist_p256_init_tfm, 30262306a36Sopenharmony_ci .exit = ecdsa_exit_tfm, 30362306a36Sopenharmony_ci .base = { 30462306a36Sopenharmony_ci .cra_name = "ecdsa-nist-p256", 30562306a36Sopenharmony_ci .cra_driver_name = "ecdsa-nist-p256-generic", 30662306a36Sopenharmony_ci .cra_priority = 100, 30762306a36Sopenharmony_ci .cra_module = THIS_MODULE, 30862306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct ecc_ctx), 30962306a36Sopenharmony_ci }, 31062306a36Sopenharmony_ci}; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic int ecdsa_nist_p192_init_tfm(struct crypto_akcipher *tfm) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P192); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic struct akcipher_alg ecdsa_nist_p192 = { 32062306a36Sopenharmony_ci .verify = ecdsa_verify, 32162306a36Sopenharmony_ci .set_pub_key = ecdsa_set_pub_key, 32262306a36Sopenharmony_ci .max_size = ecdsa_max_size, 32362306a36Sopenharmony_ci .init = ecdsa_nist_p192_init_tfm, 32462306a36Sopenharmony_ci .exit = ecdsa_exit_tfm, 32562306a36Sopenharmony_ci .base = { 32662306a36Sopenharmony_ci .cra_name = "ecdsa-nist-p192", 32762306a36Sopenharmony_ci .cra_driver_name = "ecdsa-nist-p192-generic", 32862306a36Sopenharmony_ci .cra_priority = 100, 32962306a36Sopenharmony_ci .cra_module = THIS_MODULE, 33062306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct ecc_ctx), 33162306a36Sopenharmony_ci }, 33262306a36Sopenharmony_ci}; 33362306a36Sopenharmony_cistatic bool ecdsa_nist_p192_registered; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int __init ecdsa_init(void) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci int ret; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* NIST p192 may not be available in FIPS mode */ 34062306a36Sopenharmony_ci ret = crypto_register_akcipher(&ecdsa_nist_p192); 34162306a36Sopenharmony_ci ecdsa_nist_p192_registered = ret == 0; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci ret = crypto_register_akcipher(&ecdsa_nist_p256); 34462306a36Sopenharmony_ci if (ret) 34562306a36Sopenharmony_ci goto nist_p256_error; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci ret = crypto_register_akcipher(&ecdsa_nist_p384); 34862306a36Sopenharmony_ci if (ret) 34962306a36Sopenharmony_ci goto nist_p384_error; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return 0; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cinist_p384_error: 35462306a36Sopenharmony_ci crypto_unregister_akcipher(&ecdsa_nist_p256); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cinist_p256_error: 35762306a36Sopenharmony_ci if (ecdsa_nist_p192_registered) 35862306a36Sopenharmony_ci crypto_unregister_akcipher(&ecdsa_nist_p192); 35962306a36Sopenharmony_ci return ret; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void __exit ecdsa_exit(void) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci if (ecdsa_nist_p192_registered) 36562306a36Sopenharmony_ci crypto_unregister_akcipher(&ecdsa_nist_p192); 36662306a36Sopenharmony_ci crypto_unregister_akcipher(&ecdsa_nist_p256); 36762306a36Sopenharmony_ci crypto_unregister_akcipher(&ecdsa_nist_p384); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cisubsys_initcall(ecdsa_init); 37162306a36Sopenharmony_cimodule_exit(ecdsa_exit); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 37462306a36Sopenharmony_ciMODULE_AUTHOR("Stefan Berger <stefanb@linux.ibm.com>"); 37562306a36Sopenharmony_ciMODULE_DESCRIPTION("ECDSA generic algorithm"); 37662306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("ecdsa-generic"); 377