aboutsummaryrefslogtreecommitdiffstats
path: root/net/rxrpc/ar-key.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2007-04-26 18:48:28 -0400
committerDavid S. Miller <davem@davemloft.net>2007-04-26 18:48:28 -0400
commit17926a79320afa9b95df6b977b40cca6d8713cea (patch)
tree5cedff43b69520ad17b86783d3752053686ec99c /net/rxrpc/ar-key.c
parente19dff1fdd99a25819af74cf0710e147fff4fd3a (diff)
[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both
Provide AF_RXRPC sockets that can be used to talk to AFS servers, or serve answers to AFS clients. KerberosIV security is fully supported. The patches and some example test programs can be found in: http://people.redhat.com/~dhowells/rxrpc/ This will eventually replace the old implementation of kernel-only RxRPC currently resident in net/rxrpc/. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rxrpc/ar-key.c')
-rw-r--r--net/rxrpc/ar-key.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
new file mode 100644
index 000000000000..7e049ff6ae60
--- /dev/null
+++ b/net/rxrpc/ar-key.c
@@ -0,0 +1,334 @@
1/* RxRPC key management
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * RxRPC keys should have a description of describing their purpose:
12 * "afs@CAMBRIDGE.REDHAT.COM>
13 */
14
15#include <linux/module.h>
16#include <linux/net.h>
17#include <linux/skbuff.h>
18#include <linux/key.h>
19#include <linux/crypto.h>
20#include <net/sock.h>
21#include <net/af_rxrpc.h>
22#include <keys/rxrpc-type.h>
23#include <keys/user-type.h>
24#include "ar-internal.h"
25
26static int rxrpc_instantiate(struct key *, const void *, size_t);
27static int rxrpc_instantiate_s(struct key *, const void *, size_t);
28static void rxrpc_destroy(struct key *);
29static void rxrpc_destroy_s(struct key *);
30static void rxrpc_describe(const struct key *, struct seq_file *);
31
32/*
33 * rxrpc defined keys take an arbitrary string as the description and an
34 * arbitrary blob of data as the payload
35 */
36struct key_type key_type_rxrpc = {
37 .name = "rxrpc",
38 .instantiate = rxrpc_instantiate,
39 .match = user_match,
40 .destroy = rxrpc_destroy,
41 .describe = rxrpc_describe,
42};
43
44EXPORT_SYMBOL(key_type_rxrpc);
45
46/*
47 * rxrpc server defined keys take "<serviceId>:<securityIndex>" as the
48 * description and an 8-byte decryption key as the payload
49 */
50struct key_type key_type_rxrpc_s = {
51 .name = "rxrpc_s",
52 .instantiate = rxrpc_instantiate_s,
53 .match = user_match,
54 .destroy = rxrpc_destroy_s,
55 .describe = rxrpc_describe,
56};
57
58/*
59 * instantiate an rxrpc defined key
60 * data should be of the form:
61 * OFFSET LEN CONTENT
62 * 0 4 key interface version number
63 * 4 2 security index (type)
64 * 6 2 ticket length
65 * 8 4 key expiry time (time_t)
66 * 12 4 kvno
67 * 16 8 session key
68 * 24 [len] ticket
69 *
70 * if no data is provided, then a no-security key is made
71 */
72static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
73{
74 const struct rxkad_key *tsec;
75 struct rxrpc_key_payload *upayload;
76 size_t plen;
77 u32 kver;
78 int ret;
79
80 _enter("{%x},,%zu", key_serial(key), datalen);
81
82 /* handle a no-security key */
83 if (!data && datalen == 0)
84 return 0;
85
86 /* get the key interface version number */
87 ret = -EINVAL;
88 if (datalen <= 4 || !data)
89 goto error;
90 memcpy(&kver, data, sizeof(kver));
91 data += sizeof(kver);
92 datalen -= sizeof(kver);
93
94 _debug("KEY I/F VERSION: %u", kver);
95
96 ret = -EKEYREJECTED;
97 if (kver != 1)
98 goto error;
99
100 /* deal with a version 1 key */
101 ret = -EINVAL;
102 if (datalen < sizeof(*tsec))
103 goto error;
104
105 tsec = data;
106 if (datalen != sizeof(*tsec) + tsec->ticket_len)
107 goto error;
108
109 _debug("SCIX: %u", tsec->security_index);
110 _debug("TLEN: %u", tsec->ticket_len);
111 _debug("EXPY: %x", tsec->expiry);
112 _debug("KVNO: %u", tsec->kvno);
113 _debug("SKEY: %02x%02x%02x%02x%02x%02x%02x%02x",
114 tsec->session_key[0], tsec->session_key[1],
115 tsec->session_key[2], tsec->session_key[3],
116 tsec->session_key[4], tsec->session_key[5],
117 tsec->session_key[6], tsec->session_key[7]);
118 if (tsec->ticket_len >= 8)
119 _debug("TCKT: %02x%02x%02x%02x%02x%02x%02x%02x",
120 tsec->ticket[0], tsec->ticket[1],
121 tsec->ticket[2], tsec->ticket[3],
122 tsec->ticket[4], tsec->ticket[5],
123 tsec->ticket[6], tsec->ticket[7]);
124
125 ret = -EPROTONOSUPPORT;
126 if (tsec->security_index != 2)
127 goto error;
128
129 key->type_data.x[0] = tsec->security_index;
130
131 plen = sizeof(*upayload) + tsec->ticket_len;
132 ret = key_payload_reserve(key, plen);
133 if (ret < 0)
134 goto error;
135
136 ret = -ENOMEM;
137 upayload = kmalloc(plen, GFP_KERNEL);
138 if (!upayload)
139 goto error;
140
141 /* attach the data */
142 memcpy(&upayload->k, tsec, sizeof(*tsec));
143 memcpy(&upayload->k.ticket, (void *)tsec + sizeof(*tsec),
144 tsec->ticket_len);
145 key->payload.data = upayload;
146 key->expiry = tsec->expiry;
147 ret = 0;
148
149error:
150 return ret;
151}
152
153/*
154 * instantiate a server secret key
155 * data should be a pointer to the 8-byte secret key
156 */
157static int rxrpc_instantiate_s(struct key *key, const void *data,
158 size_t datalen)
159{
160 struct crypto_blkcipher *ci;
161
162 _enter("{%x},,%zu", key_serial(key), datalen);
163
164 if (datalen != 8)
165 return -EINVAL;
166
167 memcpy(&key->type_data, data, 8);
168
169 ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
170 if (IS_ERR(ci)) {
171 _leave(" = %ld", PTR_ERR(ci));
172 return PTR_ERR(ci);
173 }
174
175 if (crypto_blkcipher_setkey(ci, data, 8) < 0)
176 BUG();
177
178 key->payload.data = ci;
179 _leave(" = 0");
180 return 0;
181}
182
183/*
184 * dispose of the data dangling from the corpse of a rxrpc key
185 */
186static void rxrpc_destroy(struct key *key)
187{
188 kfree(key->payload.data);
189}
190
191/*
192 * dispose of the data dangling from the corpse of a rxrpc key
193 */
194static void rxrpc_destroy_s(struct key *key)
195{
196 if (key->payload.data) {
197 crypto_free_blkcipher(key->payload.data);
198 key->payload.data = NULL;
199 }
200}
201
202/*
203 * describe the rxrpc key
204 */
205static void rxrpc_describe(const struct key *key, struct seq_file *m)
206{
207 seq_puts(m, key->description);
208}
209
210/*
211 * grab the security key for a socket
212 */
213int rxrpc_request_key(struct rxrpc_sock *rx, char __user *optval, int optlen)
214{
215 struct key *key;
216 char *description;
217
218 _enter("");
219
220 if (optlen <= 0 || optlen > PAGE_SIZE - 1)
221 return -EINVAL;
222
223 description = kmalloc(optlen + 1, GFP_KERNEL);
224 if (!description)
225 return -ENOMEM;
226
227 if (copy_from_user(description, optval, optlen)) {
228 kfree(description);
229 return -EFAULT;
230 }
231 description[optlen] = 0;
232
233 key = request_key(&key_type_rxrpc, description, NULL);
234 if (IS_ERR(key)) {
235 kfree(description);
236 _leave(" = %ld", PTR_ERR(key));
237 return PTR_ERR(key);
238 }
239
240 rx->key = key;
241 kfree(description);
242 _leave(" = 0 [key %x]", key->serial);
243 return 0;
244}
245
246/*
247 * grab the security keyring for a server socket
248 */
249int rxrpc_server_keyring(struct rxrpc_sock *rx, char __user *optval,
250 int optlen)
251{
252 struct key *key;
253 char *description;
254
255 _enter("");
256
257 if (optlen <= 0 || optlen > PAGE_SIZE - 1)
258 return -EINVAL;
259
260 description = kmalloc(optlen + 1, GFP_KERNEL);
261 if (!description)
262 return -ENOMEM;
263
264 if (copy_from_user(description, optval, optlen)) {
265 kfree(description);
266 return -EFAULT;
267 }
268 description[optlen] = 0;
269
270 key = request_key(&key_type_keyring, description, NULL);
271 if (IS_ERR(key)) {
272 kfree(description);
273 _leave(" = %ld", PTR_ERR(key));
274 return PTR_ERR(key);
275 }
276
277 rx->securities = key;
278 kfree(description);
279 _leave(" = 0 [key %x]", key->serial);
280 return 0;
281}
282
283/*
284 * generate a server data key
285 */
286int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
287 const void *session_key,
288 time_t expiry,
289 u32 kvno)
290{
291 struct key *key;
292 int ret;
293
294 struct {
295 u32 kver;
296 struct rxkad_key tsec;
297 } data;
298
299 _enter("");
300
301 key = key_alloc(&key_type_rxrpc, "x", 0, 0, current, 0,
302 KEY_ALLOC_NOT_IN_QUOTA);
303 if (IS_ERR(key)) {
304 _leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
305 return -ENOMEM;
306 }
307
308 _debug("key %d", key_serial(key));
309
310 data.kver = 1;
311 data.tsec.security_index = 2;
312 data.tsec.ticket_len = 0;
313 data.tsec.expiry = expiry;
314 data.tsec.kvno = 0;
315
316 memcpy(&data.tsec.session_key, session_key,
317 sizeof(data.tsec.session_key));
318
319 ret = key_instantiate_and_link(key, &data, sizeof(data), NULL, NULL);
320 if (ret < 0)
321 goto error;
322
323 conn->key = key;
324 _leave(" = 0 [%d]", key_serial(key));
325 return 0;
326
327error:
328 key_revoke(key);
329 key_put(key);
330 _leave(" = -ENOMEM [ins %d]", ret);
331 return -ENOMEM;
332}
333
334EXPORT_SYMBOL(rxrpc_get_server_data_key);