aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorStephan Mueller <smueller@chronox.de>2014-12-25 17:00:06 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2014-12-29 05:37:59 -0500
commit5afdfd22e6ba2260129a2a7113ab0916339c4205 (patch)
treee933e679e4b3e278ec48b73495b4d5843002808e /crypto
parentad202c8c1563da4dda9416ca0ea1e0b94430f759 (diff)
crypto: algif_rng - add random number generator support
This patch adds the random number generator support for AF_ALG. A random number generator's purpose is to generate data without requiring the caller to provide any data. Therefore, the AF_ALG interface handler for RNGs only implements a callback handler for recvmsg. The following parameters provided with a recvmsg are processed by the RNG callback handler: * sock - to resolve the RNG context data structure accessing the RNG instance private to the socket * len - this parameter allows userspace callers to specify how many random bytes the RNG shall produce and return. As the kernel context for the RNG allocates a buffer of 128 bytes to store random numbers before copying them to userspace, the len parameter is checked that it is not larger than 128. If a caller wants more random numbers, a new request for recvmsg shall be made. The size of 128 bytes is chose because of the following considerations: * to increase the memory footprint of the kernel too much (note, that would be 128 bytes per open socket) * 128 is divisible by any typical cryptographic block size an RNG may have * A request for random numbers typically only shall supply small amount of data like for keys or IVs that should only require one invocation of the recvmsg function. Note, during instantiation of the RNG, the code checks whether the RNG implementation requires seeding. If so, the RNG is seeded with output from get_random_bytes. A fully working example using all aspects of the RNG interface is provided at http://www.chronox.de/libkcapi.html Signed-off-by: Stephan Mueller <smueller@chronox.de> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/algif_rng.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c
new file mode 100644
index 000000000000..91c06f5673dd
--- /dev/null
+++ b/crypto/algif_rng.c
@@ -0,0 +1,192 @@
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 <smueller@chronox.de>
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/module.h>
42#include <crypto/rng.h>
43#include <linux/random.h>
44#include <crypto/if_alg.h>
45#include <linux/net.h>
46#include <net/sock.h>
47
48MODULE_LICENSE("GPL");
49MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
50MODULE_DESCRIPTION("User-space interface for random number generators");
51
52struct rng_ctx {
53#define MAXSIZE 128
54 unsigned int len;
55 struct crypto_rng *drng;
56};
57
58static int rng_recvmsg(struct kiocb *unused, struct socket *sock,
59 struct msghdr *msg, size_t len, int flags)
60{
61 struct sock *sk = sock->sk;
62 struct alg_sock *ask = alg_sk(sk);
63 struct rng_ctx *ctx = ask->private;
64 int err = -EFAULT;
65 int genlen = 0;
66 u8 result[MAXSIZE];
67
68 if (len == 0)
69 return 0;
70 if (len > MAXSIZE)
71 len = MAXSIZE;
72
73 /*
74 * although not strictly needed, this is a precaution against coding
75 * errors
76 */
77 memset(result, 0, len);
78
79 /*
80 * The enforcement of a proper seeding of an RNG is done within an
81 * RNG implementation. Some RNGs (DRBG, krng) do not need specific
82 * seeding as they automatically seed. The X9.31 DRNG will return
83 * an error if it was not seeded properly.
84 */
85 genlen = crypto_rng_get_bytes(ctx->drng, result, len);
86 if (genlen < 0)
87 return genlen;
88
89 err = memcpy_to_msg(msg, result, len);
90 memzero_explicit(result, genlen);
91
92 return err ? err : len;
93}
94
95static struct proto_ops algif_rng_ops = {
96 .family = PF_ALG,
97
98 .connect = sock_no_connect,
99 .socketpair = sock_no_socketpair,
100 .getname = sock_no_getname,
101 .ioctl = sock_no_ioctl,
102 .listen = sock_no_listen,
103 .shutdown = sock_no_shutdown,
104 .getsockopt = sock_no_getsockopt,
105 .mmap = sock_no_mmap,
106 .bind = sock_no_bind,
107 .accept = sock_no_accept,
108 .setsockopt = sock_no_setsockopt,
109 .poll = sock_no_poll,
110 .sendmsg = sock_no_sendmsg,
111 .sendpage = sock_no_sendpage,
112
113 .release = af_alg_release,
114 .recvmsg = rng_recvmsg,
115};
116
117static void *rng_bind(const char *name, u32 type, u32 mask)
118{
119 return crypto_alloc_rng(name, type, mask);
120}
121
122static void rng_release(void *private)
123{
124 crypto_free_rng(private);
125}
126
127static void rng_sock_destruct(struct sock *sk)
128{
129 struct alg_sock *ask = alg_sk(sk);
130 struct rng_ctx *ctx = ask->private;
131
132 sock_kfree_s(sk, ctx, ctx->len);
133 af_alg_release_parent(sk);
134}
135
136static int rng_accept_parent(void *private, struct sock *sk)
137{
138 struct rng_ctx *ctx;
139 struct alg_sock *ask = alg_sk(sk);
140 unsigned int len = sizeof(*ctx);
141
142 ctx = sock_kmalloc(sk, len, GFP_KERNEL);
143 if (!ctx)
144 return -ENOMEM;
145
146 ctx->len = len;
147
148 /*
149 * No seeding done at that point -- if multiple accepts are
150 * done on one RNG instance, each resulting FD points to the same
151 * state of the RNG.
152 */
153
154 ctx->drng = private;
155 ask->private = ctx;
156 sk->sk_destruct = rng_sock_destruct;
157
158 return 0;
159}
160
161static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen)
162{
163 /*
164 * Check whether seedlen is of sufficient size is done in RNG
165 * implementations.
166 */
167 return crypto_rng_reset(private, (u8 *)seed, seedlen);
168}
169
170static const struct af_alg_type algif_type_rng = {
171 .bind = rng_bind,
172 .release = rng_release,
173 .accept = rng_accept_parent,
174 .setkey = rng_setkey,
175 .ops = &algif_rng_ops,
176 .name = "rng",
177 .owner = THIS_MODULE
178};
179
180static int __init rng_init(void)
181{
182 return af_alg_register_type(&algif_type_rng);
183}
184
185void __exit rng_exit(void)
186{
187 int err = af_alg_unregister_type(&algif_type_rng);
188 BUG_ON(err);
189}
190
191module_init(rng_init);
192module_exit(rng_exit);