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