summaryrefslogtreecommitdiff
path: root/crypto/ecdsa-p1363.c
blob: eaae7214d69bca60a1743b298e737c8563790182 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// SPDX-License-Identifier: GPL-2.0
/*
 * ECDSA P1363 signature encoding
 *
 * Copyright (c) 2024 Intel Corporation
 */

#include <linux/err.h>
#include <linux/module.h>
#include <crypto/algapi.h>
#include <crypto/sig.h>
#include <crypto/internal/ecc.h>
#include <crypto/internal/sig.h>

struct ecdsa_p1363_ctx {
	struct crypto_sig *child;
};

static int ecdsa_p1363_verify(struct crypto_sig *tfm,
			      const void *src, unsigned int slen,
			      const void *digest, unsigned int dlen)
{
	struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm);
	unsigned int keylen = crypto_sig_keysize(ctx->child);
	unsigned int ndigits = DIV_ROUND_UP(keylen, sizeof(u64));
	struct ecdsa_raw_sig sig;

	if (slen != 2 * keylen)
		return -EINVAL;

	ecc_digits_from_bytes(src, keylen, sig.r, ndigits);
	ecc_digits_from_bytes(src + keylen, keylen, sig.s, ndigits);

	return crypto_sig_verify(ctx->child, &sig, sizeof(sig), digest, dlen);
}

static unsigned int ecdsa_p1363_key_size(struct crypto_sig *tfm)
{
	struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm);

	return crypto_sig_keysize(ctx->child);
}

static unsigned int ecdsa_p1363_max_size(struct crypto_sig *tfm)
{
	struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm);

	return 2 * crypto_sig_keysize(ctx->child);
}

static unsigned int ecdsa_p1363_digest_size(struct crypto_sig *tfm)
{
	struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm);

	return crypto_sig_digestsize(ctx->child);
}

static int ecdsa_p1363_set_pub_key(struct crypto_sig *tfm,
				   const void *key, unsigned int keylen)
{
	struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm);

	return crypto_sig_set_pubkey(ctx->child, key, keylen);
}

static int ecdsa_p1363_init_tfm(struct crypto_sig *tfm)
{
	struct sig_instance *inst = sig_alg_instance(tfm);
	struct crypto_sig_spawn *spawn = sig_instance_ctx(inst);
	struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm);
	struct crypto_sig *child_tfm;

	child_tfm = crypto_spawn_sig(spawn);
	if (IS_ERR(child_tfm))
		return PTR_ERR(child_tfm);

	ctx->child = child_tfm;

	return 0;
}

static void ecdsa_p1363_exit_tfm(struct crypto_sig *tfm)
{
	struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm);

	crypto_free_sig(ctx->child);
}

static void ecdsa_p1363_free(struct sig_instance *inst)
{
	struct crypto_sig_spawn *spawn = sig_instance_ctx(inst);

	crypto_drop_sig(spawn);
	kfree(inst);
}

static int ecdsa_p1363_create(struct crypto_template *tmpl, struct rtattr **tb)
{
	struct crypto_sig_spawn *spawn;
	struct sig_instance *inst;
	struct sig_alg *ecdsa_alg;
	u32 mask;
	int err;

	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SIG, &mask);
	if (err)
		return err;

	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
	if (!inst)
		return -ENOMEM;

	spawn = sig_instance_ctx(inst);

	err = crypto_grab_sig(spawn, sig_crypto_instance(inst),
			      crypto_attr_alg_name(tb[1]), 0, mask);
	if (err)
		goto err_free_inst;

	ecdsa_alg = crypto_spawn_sig_alg(spawn);

	err = -EINVAL;
	if (strncmp(ecdsa_alg->base.cra_name, "ecdsa", 5) != 0)
		goto err_free_inst;

	err = crypto_inst_setname(sig_crypto_instance(inst), tmpl->name,
				  &ecdsa_alg->base);
	if (err)
		goto err_free_inst;

	inst->alg.base.cra_priority = ecdsa_alg->base.cra_priority;
	inst->alg.base.cra_ctxsize = sizeof(struct ecdsa_p1363_ctx);

	inst->alg.init = ecdsa_p1363_init_tfm;
	inst->alg.exit = ecdsa_p1363_exit_tfm;

	inst->alg.verify = ecdsa_p1363_verify;
	inst->alg.key_size = ecdsa_p1363_key_size;
	inst->alg.max_size = ecdsa_p1363_max_size;
	inst->alg.digest_size = ecdsa_p1363_digest_size;
	inst->alg.set_pub_key = ecdsa_p1363_set_pub_key;

	inst->free = ecdsa_p1363_free;

	err = sig_register_instance(tmpl, inst);
	if (err) {
err_free_inst:
		ecdsa_p1363_free(inst);
	}
	return err;
}

struct crypto_template ecdsa_p1363_tmpl = {
	.name = "p1363",
	.create = ecdsa_p1363_create,
	.module = THIS_MODULE,
};

MODULE_ALIAS_CRYPTO("p1363");