Commit | Line | Data |
---|---|---|
ca7fb100 DH |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* RxRPC key management | |
3 | * | |
4 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
5 | * Written by David Howells (dhowells@redhat.com) | |
6 | * | |
7 | * RxRPC keys should have a description of describing their purpose: | |
8 | * "afs@CAMBRIDGE.REDHAT.COM> | |
9 | */ | |
10 | ||
11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
12 | ||
13 | #include <crypto/skcipher.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/net.h> | |
16 | #include <linux/skbuff.h> | |
17 | #include <linux/key-type.h> | |
18 | #include <linux/ctype.h> | |
19 | #include <linux/slab.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 | ||
26 | static int rxrpc_vet_description_s(const char *); | |
27 | static int rxrpc_preparse_s(struct key_preparsed_payload *); | |
28 | static void rxrpc_free_preparse_s(struct key_preparsed_payload *); | |
29 | static void rxrpc_destroy_s(struct key *); | |
30 | static void rxrpc_describe_s(const struct key *, struct seq_file *); | |
31 | ||
32 | /* | |
12da59fc DH |
33 | * rxrpc server keys take "<serviceId>:<securityIndex>[:<sec-specific>]" as the |
34 | * description and the key material as the payload. | |
ca7fb100 DH |
35 | */ |
36 | struct key_type key_type_rxrpc_s = { | |
37 | .name = "rxrpc_s", | |
38 | .flags = KEY_TYPE_NET_DOMAIN, | |
39 | .vet_description = rxrpc_vet_description_s, | |
40 | .preparse = rxrpc_preparse_s, | |
41 | .free_preparse = rxrpc_free_preparse_s, | |
42 | .instantiate = generic_key_instantiate, | |
43 | .destroy = rxrpc_destroy_s, | |
44 | .describe = rxrpc_describe_s, | |
45 | }; | |
46 | ||
47 | /* | |
12da59fc | 48 | * Vet the description for an RxRPC server key. |
ca7fb100 DH |
49 | */ |
50 | static int rxrpc_vet_description_s(const char *desc) | |
51 | { | |
12da59fc | 52 | unsigned long service, sec_class; |
ca7fb100 DH |
53 | char *p; |
54 | ||
12da59fc DH |
55 | service = simple_strtoul(desc, &p, 10); |
56 | if (*p != ':' || service > 65535) | |
ca7fb100 | 57 | return -EINVAL; |
12da59fc DH |
58 | sec_class = simple_strtoul(p + 1, &p, 10); |
59 | if ((*p && *p != ':') || sec_class < 1 || sec_class > 255) | |
ca7fb100 DH |
60 | return -EINVAL; |
61 | return 0; | |
62 | } | |
63 | ||
64 | /* | |
65 | * Preparse a server secret key. | |
ca7fb100 DH |
66 | */ |
67 | static int rxrpc_preparse_s(struct key_preparsed_payload *prep) | |
68 | { | |
12da59fc DH |
69 | const struct rxrpc_security *sec; |
70 | unsigned int service, sec_class; | |
71 | int n; | |
ca7fb100 DH |
72 | |
73 | _enter("%zu", prep->datalen); | |
74 | ||
12da59fc | 75 | if (!prep->orig_description) |
ca7fb100 DH |
76 | return -EINVAL; |
77 | ||
12da59fc DH |
78 | if (sscanf(prep->orig_description, "%u:%u%n", &service, &sec_class, &n) != 2) |
79 | return -EINVAL; | |
ca7fb100 | 80 | |
12da59fc DH |
81 | sec = rxrpc_security_lookup(sec_class); |
82 | if (!sec) | |
83 | return -ENOPKG; | |
ca7fb100 | 84 | |
12da59fc | 85 | prep->payload.data[1] = (struct rxrpc_security *)sec; |
ca7fb100 | 86 | |
ff8376ad XH |
87 | if (!sec->preparse_server_key) |
88 | return -EINVAL; | |
89 | ||
12da59fc | 90 | return sec->preparse_server_key(prep); |
ca7fb100 DH |
91 | } |
92 | ||
93 | static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep) | |
94 | { | |
12da59fc DH |
95 | const struct rxrpc_security *sec = prep->payload.data[1]; |
96 | ||
ff8376ad | 97 | if (sec && sec->free_preparse_server_key) |
12da59fc | 98 | sec->free_preparse_server_key(prep); |
ca7fb100 DH |
99 | } |
100 | ||
101 | static void rxrpc_destroy_s(struct key *key) | |
102 | { | |
12da59fc DH |
103 | const struct rxrpc_security *sec = key->payload.data[1]; |
104 | ||
ff8376ad | 105 | if (sec && sec->destroy_server_key) |
12da59fc | 106 | sec->destroy_server_key(key); |
ca7fb100 DH |
107 | } |
108 | ||
109 | static void rxrpc_describe_s(const struct key *key, struct seq_file *m) | |
110 | { | |
d5953f65 DH |
111 | const struct rxrpc_security *sec = key->payload.data[1]; |
112 | ||
ca7fb100 | 113 | seq_puts(m, key->description); |
d5953f65 DH |
114 | if (sec && sec->describe_server_key) |
115 | sec->describe_server_key(key, m); | |
ca7fb100 DH |
116 | } |
117 | ||
118 | /* | |
119 | * grab the security keyring for a server socket | |
120 | */ | |
121 | int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen) | |
122 | { | |
123 | struct key *key; | |
124 | char *description; | |
125 | ||
126 | _enter(""); | |
127 | ||
128 | if (optlen <= 0 || optlen > PAGE_SIZE - 1) | |
129 | return -EINVAL; | |
130 | ||
131 | description = memdup_sockptr_nul(optval, optlen); | |
132 | if (IS_ERR(description)) | |
133 | return PTR_ERR(description); | |
134 | ||
135 | key = request_key(&key_type_keyring, description, NULL); | |
136 | if (IS_ERR(key)) { | |
137 | kfree(description); | |
138 | _leave(" = %ld", PTR_ERR(key)); | |
139 | return PTR_ERR(key); | |
140 | } | |
141 | ||
142 | rx->securities = key; | |
143 | kfree(description); | |
144 | _leave(" = 0 [key %x]", key->serial); | |
145 | return 0; | |
146 | } | |
75bfdbf2 DH |
147 | |
148 | /** | |
149 | * rxrpc_sock_set_security_keyring - Set the security keyring for a kernel service | |
150 | * @sk: The socket to set the keyring on | |
151 | * @keyring: The keyring to set | |
152 | * | |
153 | * Set the server security keyring on an rxrpc socket. This is used to provide | |
154 | * the encryption keys for a kernel service. | |
155 | */ | |
156 | int rxrpc_sock_set_security_keyring(struct sock *sk, struct key *keyring) | |
157 | { | |
158 | struct rxrpc_sock *rx = rxrpc_sk(sk); | |
159 | int ret = 0; | |
160 | ||
161 | lock_sock(sk); | |
162 | if (rx->securities) | |
163 | ret = -EINVAL; | |
164 | else if (rx->sk.sk_state != RXRPC_UNBOUND) | |
165 | ret = -EISCONN; | |
166 | else | |
167 | rx->securities = key_get(keyring); | |
168 | release_sock(sk); | |
169 | return ret; | |
170 | } | |
171 | EXPORT_SYMBOL(rxrpc_sock_set_security_keyring); |