Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/crypto/algif_rng.c
26131 views
1
/*
2
* algif_rng: User-space interface for random number generators
3
*
4
* This file provides the user-space API for random number generators.
5
*
6
* Copyright (C) 2014, Stephan Mueller <[email protected]>
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, and the entire permission notice in its entirety,
13
* including the disclaimer of warranties.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
* 3. The name of the author may not be used to endorse or promote
18
* products derived from this software without specific prior
19
* written permission.
20
*
21
* ALTERNATIVELY, this product may be distributed under the terms of
22
* the GNU General Public License, in which case the provisions of the GPL2
23
* are required INSTEAD OF the above restrictions. (This clause is
24
* necessary due to a potential bad interaction between the GPL and
25
* the restrictions contained in a BSD-style copyright.)
26
*
27
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
28
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
30
* WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
31
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
33
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
34
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37
* USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
38
* DAMAGE.
39
*/
40
41
#include <linux/capability.h>
42
#include <linux/module.h>
43
#include <crypto/rng.h>
44
#include <linux/random.h>
45
#include <crypto/if_alg.h>
46
#include <linux/net.h>
47
#include <net/sock.h>
48
49
MODULE_LICENSE("GPL");
50
MODULE_AUTHOR("Stephan Mueller <[email protected]>");
51
MODULE_DESCRIPTION("User-space interface for random number generators");
52
53
struct rng_ctx {
54
#define MAXSIZE 128
55
unsigned int len;
56
struct crypto_rng *drng;
57
u8 *addtl;
58
size_t addtl_len;
59
};
60
61
struct rng_parent_ctx {
62
struct crypto_rng *drng;
63
u8 *entropy;
64
};
65
66
static void rng_reset_addtl(struct rng_ctx *ctx)
67
{
68
kfree_sensitive(ctx->addtl);
69
ctx->addtl = NULL;
70
ctx->addtl_len = 0;
71
}
72
73
static int _rng_recvmsg(struct crypto_rng *drng, struct msghdr *msg, size_t len,
74
u8 *addtl, size_t addtl_len)
75
{
76
int err = 0;
77
int genlen = 0;
78
u8 result[MAXSIZE];
79
80
if (len == 0)
81
return 0;
82
if (len > MAXSIZE)
83
len = MAXSIZE;
84
85
/*
86
* although not strictly needed, this is a precaution against coding
87
* errors
88
*/
89
memset(result, 0, len);
90
91
/*
92
* The enforcement of a proper seeding of an RNG is done within an
93
* RNG implementation. Some RNGs (DRBG, krng) do not need specific
94
* seeding as they automatically seed. The X9.31 DRNG will return
95
* an error if it was not seeded properly.
96
*/
97
genlen = crypto_rng_generate(drng, addtl, addtl_len, result, len);
98
if (genlen < 0)
99
return genlen;
100
101
err = memcpy_to_msg(msg, result, len);
102
memzero_explicit(result, len);
103
104
return err ? err : len;
105
}
106
107
static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
108
int flags)
109
{
110
struct sock *sk = sock->sk;
111
struct alg_sock *ask = alg_sk(sk);
112
struct rng_ctx *ctx = ask->private;
113
114
return _rng_recvmsg(ctx->drng, msg, len, NULL, 0);
115
}
116
117
static int rng_test_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
118
int flags)
119
{
120
struct sock *sk = sock->sk;
121
struct alg_sock *ask = alg_sk(sk);
122
struct rng_ctx *ctx = ask->private;
123
int ret;
124
125
lock_sock(sock->sk);
126
ret = _rng_recvmsg(ctx->drng, msg, len, ctx->addtl, ctx->addtl_len);
127
rng_reset_addtl(ctx);
128
release_sock(sock->sk);
129
130
return ret;
131
}
132
133
static int rng_test_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
134
{
135
int err;
136
struct alg_sock *ask = alg_sk(sock->sk);
137
struct rng_ctx *ctx = ask->private;
138
139
lock_sock(sock->sk);
140
if (len > MAXSIZE) {
141
err = -EMSGSIZE;
142
goto unlock;
143
}
144
145
rng_reset_addtl(ctx);
146
ctx->addtl = kmalloc(len, GFP_KERNEL);
147
if (!ctx->addtl) {
148
err = -ENOMEM;
149
goto unlock;
150
}
151
152
err = memcpy_from_msg(ctx->addtl, msg, len);
153
if (err) {
154
rng_reset_addtl(ctx);
155
goto unlock;
156
}
157
ctx->addtl_len = len;
158
159
unlock:
160
release_sock(sock->sk);
161
return err ? err : len;
162
}
163
164
static struct proto_ops algif_rng_ops = {
165
.family = PF_ALG,
166
167
.connect = sock_no_connect,
168
.socketpair = sock_no_socketpair,
169
.getname = sock_no_getname,
170
.ioctl = sock_no_ioctl,
171
.listen = sock_no_listen,
172
.shutdown = sock_no_shutdown,
173
.mmap = sock_no_mmap,
174
.bind = sock_no_bind,
175
.accept = sock_no_accept,
176
.sendmsg = sock_no_sendmsg,
177
178
.release = af_alg_release,
179
.recvmsg = rng_recvmsg,
180
};
181
182
static struct proto_ops __maybe_unused algif_rng_test_ops = {
183
.family = PF_ALG,
184
185
.connect = sock_no_connect,
186
.socketpair = sock_no_socketpair,
187
.getname = sock_no_getname,
188
.ioctl = sock_no_ioctl,
189
.listen = sock_no_listen,
190
.shutdown = sock_no_shutdown,
191
.mmap = sock_no_mmap,
192
.bind = sock_no_bind,
193
.accept = sock_no_accept,
194
195
.release = af_alg_release,
196
.recvmsg = rng_test_recvmsg,
197
.sendmsg = rng_test_sendmsg,
198
};
199
200
static void *rng_bind(const char *name, u32 type, u32 mask)
201
{
202
struct rng_parent_ctx *pctx;
203
struct crypto_rng *rng;
204
205
pctx = kzalloc(sizeof(*pctx), GFP_KERNEL);
206
if (!pctx)
207
return ERR_PTR(-ENOMEM);
208
209
rng = crypto_alloc_rng(name, type, mask);
210
if (IS_ERR(rng)) {
211
kfree(pctx);
212
return ERR_CAST(rng);
213
}
214
215
pctx->drng = rng;
216
return pctx;
217
}
218
219
static void rng_release(void *private)
220
{
221
struct rng_parent_ctx *pctx = private;
222
223
if (unlikely(!pctx))
224
return;
225
crypto_free_rng(pctx->drng);
226
kfree_sensitive(pctx->entropy);
227
kfree_sensitive(pctx);
228
}
229
230
static void rng_sock_destruct(struct sock *sk)
231
{
232
struct alg_sock *ask = alg_sk(sk);
233
struct rng_ctx *ctx = ask->private;
234
235
rng_reset_addtl(ctx);
236
sock_kfree_s(sk, ctx, ctx->len);
237
af_alg_release_parent(sk);
238
}
239
240
static int rng_accept_parent(void *private, struct sock *sk)
241
{
242
struct rng_ctx *ctx;
243
struct rng_parent_ctx *pctx = private;
244
struct alg_sock *ask = alg_sk(sk);
245
unsigned int len = sizeof(*ctx);
246
247
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
248
if (!ctx)
249
return -ENOMEM;
250
251
ctx->len = len;
252
ctx->addtl = NULL;
253
ctx->addtl_len = 0;
254
255
/*
256
* No seeding done at that point -- if multiple accepts are
257
* done on one RNG instance, each resulting FD points to the same
258
* state of the RNG.
259
*/
260
261
ctx->drng = pctx->drng;
262
ask->private = ctx;
263
sk->sk_destruct = rng_sock_destruct;
264
265
/*
266
* Non NULL pctx->entropy means that CAVP test has been initiated on
267
* this socket, replace proto_ops algif_rng_ops with algif_rng_test_ops.
268
*/
269
if (IS_ENABLED(CONFIG_CRYPTO_USER_API_RNG_CAVP) && pctx->entropy)
270
sk->sk_socket->ops = &algif_rng_test_ops;
271
272
return 0;
273
}
274
275
static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen)
276
{
277
struct rng_parent_ctx *pctx = private;
278
/*
279
* Check whether seedlen is of sufficient size is done in RNG
280
* implementations.
281
*/
282
return crypto_rng_reset(pctx->drng, seed, seedlen);
283
}
284
285
static int __maybe_unused rng_setentropy(void *private, sockptr_t entropy,
286
unsigned int len)
287
{
288
struct rng_parent_ctx *pctx = private;
289
u8 *kentropy = NULL;
290
291
if (!capable(CAP_SYS_ADMIN))
292
return -EACCES;
293
294
if (pctx->entropy)
295
return -EINVAL;
296
297
if (len > MAXSIZE)
298
return -EMSGSIZE;
299
300
if (len) {
301
kentropy = memdup_sockptr(entropy, len);
302
if (IS_ERR(kentropy))
303
return PTR_ERR(kentropy);
304
}
305
306
crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len);
307
/*
308
* Since rng doesn't perform any memory management for the entropy
309
* buffer, save kentropy pointer to pctx now to free it after use.
310
*/
311
pctx->entropy = kentropy;
312
return 0;
313
}
314
315
static const struct af_alg_type algif_type_rng = {
316
.bind = rng_bind,
317
.release = rng_release,
318
.accept = rng_accept_parent,
319
.setkey = rng_setkey,
320
#ifdef CONFIG_CRYPTO_USER_API_RNG_CAVP
321
.setentropy = rng_setentropy,
322
#endif
323
.ops = &algif_rng_ops,
324
.name = "rng",
325
.owner = THIS_MODULE
326
};
327
328
static int __init rng_init(void)
329
{
330
return af_alg_register_type(&algif_type_rng);
331
}
332
333
static void __exit rng_exit(void)
334
{
335
int err = af_alg_unregister_type(&algif_type_rng);
336
BUG_ON(err);
337
}
338
339
module_init(rng_init);
340
module_exit(rng_exit);
341
342