]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - net/ceph/crypto.c
libceph: uninline ceph_crypto_key_destroy()
[mirror_ubuntu-artful-kernel.git] / net / ceph / crypto.c
CommitLineData
8b6e4f2d 1
3d14c5d2 2#include <linux/ceph/ceph_debug.h>
8b6e4f2d
SW
3
4#include <linux/err.h>
5#include <linux/scatterlist.h>
5a0e3ad6 6#include <linux/slab.h>
e59dd982
HX
7#include <crypto/aes.h>
8#include <crypto/skcipher.h>
4b2a58ab 9#include <linux/key-type.h>
8b6e4f2d 10
4b2a58ab 11#include <keys/ceph-type.h>
7c3bec0a 12#include <keys/user-type.h>
3d14c5d2 13#include <linux/ceph/decode.h>
8b6e4f2d 14#include "crypto.h"
8b6e4f2d 15
8323c3aa
TV
16int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
17 const struct ceph_crypto_key *src)
18{
19 memcpy(dst, src, sizeof(struct ceph_crypto_key));
18648256 20 dst->key = kmemdup(src->key, src->len, GFP_NOFS);
8323c3aa
TV
21 if (!dst->key)
22 return -ENOMEM;
8323c3aa
TV
23 return 0;
24}
25
8b6e4f2d
SW
26int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
27{
28 if (*p + sizeof(u16) + sizeof(key->created) +
29 sizeof(u16) + key->len > end)
30 return -ERANGE;
31 ceph_encode_16(p, key->type);
32 ceph_encode_copy(p, &key->created, sizeof(key->created));
33 ceph_encode_16(p, key->len);
34 ceph_encode_copy(p, key->key, key->len);
35 return 0;
36}
37
38int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
39{
40 ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad);
41 key->type = ceph_decode_16(p);
42 ceph_decode_copy(p, &key->created, sizeof(key->created));
43 key->len = ceph_decode_16(p);
44 ceph_decode_need(p, end, key->len, bad);
45 key->key = kmalloc(key->len, GFP_NOFS);
46 if (!key->key)
47 return -ENOMEM;
48 ceph_decode_copy(p, key->key, key->len);
49 return 0;
50
51bad:
52 dout("failed to decode crypto key\n");
53 return -EINVAL;
54}
55
56int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
57{
58 int inlen = strlen(inkey);
59 int blen = inlen * 3 / 4;
60 void *buf, *p;
61 int ret;
62
63 dout("crypto_key_unarmor %s\n", inkey);
64 buf = kmalloc(blen, GFP_NOFS);
65 if (!buf)
66 return -ENOMEM;
67 blen = ceph_unarmor(buf, inkey, inkey+inlen);
68 if (blen < 0) {
69 kfree(buf);
70 return blen;
71 }
72
73 p = buf;
74 ret = ceph_crypto_key_decode(key, &p, p + blen);
75 kfree(buf);
76 if (ret)
77 return ret;
78 dout("crypto_key_unarmor key %p type %d len %d\n", key,
79 key->type, key->len);
80 return 0;
81}
82
6db2304a
ID
83void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
84{
85 if (key) {
86 kfree(key->key);
87 key->key = NULL;
88 }
89}
90
e59dd982 91static struct crypto_skcipher *ceph_crypto_alloc_cipher(void)
8b6e4f2d 92{
e59dd982 93 return crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
8b6e4f2d
SW
94}
95
cbbfe499 96static const u8 *aes_iv = (u8 *)CEPH_AES_IV;
8b6e4f2d 97
aaef3170
ID
98/*
99 * Should be used for buffers allocated with ceph_kvmalloc().
100 * Currently these are encrypt out-buffer (ceph_buffer) and decrypt
101 * in-buffer (msg front).
102 *
103 * Dispose of @sgt with teardown_sgtable().
104 *
105 * @prealloc_sg is to avoid memory allocation inside sg_alloc_table()
106 * in cases where a single sg is sufficient. No attempt to reduce the
107 * number of sgs by squeezing physically contiguous pages together is
108 * made though, for simplicity.
109 */
110static int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
111 const void *buf, unsigned int buf_len)
112{
113 struct scatterlist *sg;
114 const bool is_vmalloc = is_vmalloc_addr(buf);
115 unsigned int off = offset_in_page(buf);
116 unsigned int chunk_cnt = 1;
117 unsigned int chunk_len = PAGE_ALIGN(off + buf_len);
118 int i;
119 int ret;
120
121 if (buf_len == 0) {
122 memset(sgt, 0, sizeof(*sgt));
123 return -EINVAL;
124 }
125
126 if (is_vmalloc) {
127 chunk_cnt = chunk_len >> PAGE_SHIFT;
128 chunk_len = PAGE_SIZE;
129 }
130
131 if (chunk_cnt > 1) {
132 ret = sg_alloc_table(sgt, chunk_cnt, GFP_NOFS);
133 if (ret)
134 return ret;
135 } else {
136 WARN_ON(chunk_cnt != 1);
137 sg_init_table(prealloc_sg, 1);
138 sgt->sgl = prealloc_sg;
139 sgt->nents = sgt->orig_nents = 1;
140 }
141
142 for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
143 struct page *page;
144 unsigned int len = min(chunk_len - off, buf_len);
145
146 if (is_vmalloc)
147 page = vmalloc_to_page(buf);
148 else
149 page = virt_to_page(buf);
150
151 sg_set_page(sg, page, len, off);
152
153 off = 0;
154 buf += len;
155 buf_len -= len;
156 }
157 WARN_ON(buf_len != 0);
158
159 return 0;
160}
161
162static void teardown_sgtable(struct sg_table *sgt)
163{
164 if (sgt->orig_nents > 1)
165 sg_free_table(sgt);
166}
167
a45f795c
ID
168static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt,
169 void *buf, int buf_len, int in_len, int *pout_len)
170{
171 struct crypto_skcipher *tfm = ceph_crypto_alloc_cipher();
172 SKCIPHER_REQUEST_ON_STACK(req, tfm);
173 struct sg_table sgt;
174 struct scatterlist prealloc_sg;
175 char iv[AES_BLOCK_SIZE];
176 int pad_byte = AES_BLOCK_SIZE - (in_len & (AES_BLOCK_SIZE - 1));
177 int crypt_len = encrypt ? in_len + pad_byte : in_len;
178 int ret;
179
180 if (IS_ERR(tfm))
181 return PTR_ERR(tfm);
182
183 WARN_ON(crypt_len > buf_len);
184 if (encrypt)
185 memset(buf + in_len, pad_byte, pad_byte);
186 ret = setup_sgtable(&sgt, &prealloc_sg, buf, crypt_len);
187 if (ret)
188 goto out_tfm;
189
190 crypto_skcipher_setkey((void *)tfm, key->key, key->len);
191 memcpy(iv, aes_iv, AES_BLOCK_SIZE);
192
193 skcipher_request_set_tfm(req, tfm);
194 skcipher_request_set_callback(req, 0, NULL, NULL);
195 skcipher_request_set_crypt(req, sgt.sgl, sgt.sgl, crypt_len, iv);
196
197 /*
198 print_hex_dump(KERN_ERR, "key: ", DUMP_PREFIX_NONE, 16, 1,
199 key->key, key->len, 1);
200 print_hex_dump(KERN_ERR, " in: ", DUMP_PREFIX_NONE, 16, 1,
201 buf, crypt_len, 1);
202 */
203 if (encrypt)
204 ret = crypto_skcipher_encrypt(req);
205 else
206 ret = crypto_skcipher_decrypt(req);
207 skcipher_request_zero(req);
208 if (ret) {
209 pr_err("%s %scrypt failed: %d\n", __func__,
210 encrypt ? "en" : "de", ret);
211 goto out_sgt;
212 }
213 /*
214 print_hex_dump(KERN_ERR, "out: ", DUMP_PREFIX_NONE, 16, 1,
215 buf, crypt_len, 1);
216 */
217
218 if (encrypt) {
219 *pout_len = crypt_len;
220 } else {
221 pad_byte = *(char *)(buf + in_len - 1);
222 if (pad_byte > 0 && pad_byte <= AES_BLOCK_SIZE &&
223 in_len >= pad_byte) {
224 *pout_len = in_len - pad_byte;
225 } else {
226 pr_err("%s got bad padding %d on in_len %d\n",
227 __func__, pad_byte, in_len);
228 ret = -EPERM;
229 goto out_sgt;
230 }
231 }
232
233out_sgt:
234 teardown_sgtable(&sgt);
235out_tfm:
236 crypto_free_skcipher(tfm);
237 return ret;
238}
239
240int ceph_crypt(const struct ceph_crypto_key *key, bool encrypt,
241 void *buf, int buf_len, int in_len, int *pout_len)
242{
243 switch (key->type) {
244 case CEPH_CRYPTO_NONE:
245 *pout_len = in_len;
246 return 0;
247 case CEPH_CRYPTO_AES:
248 return ceph_aes_crypt(key, encrypt, buf, buf_len, in_len,
249 pout_len);
250 default:
251 return -ENOTSUPP;
252 }
253}
254
efa64c09 255static int ceph_key_preparse(struct key_preparsed_payload *prep)
4b2a58ab
TV
256{
257 struct ceph_crypto_key *ckey;
cf7f601c 258 size_t datalen = prep->datalen;
4b2a58ab
TV
259 int ret;
260 void *p;
261
262 ret = -EINVAL;
cf7f601c 263 if (datalen <= 0 || datalen > 32767 || !prep->data)
4b2a58ab
TV
264 goto err;
265
4b2a58ab
TV
266 ret = -ENOMEM;
267 ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
268 if (!ckey)
269 goto err;
270
271 /* TODO ceph_crypto_key_decode should really take const input */
cf7f601c
DH
272 p = (void *)prep->data;
273 ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen);
4b2a58ab
TV
274 if (ret < 0)
275 goto err_ckey;
276
146aa8b1 277 prep->payload.data[0] = ckey;
efa64c09 278 prep->quotalen = datalen;
4b2a58ab
TV
279 return 0;
280
281err_ckey:
282 kfree(ckey);
283err:
284 return ret;
285}
286
efa64c09
DH
287static void ceph_key_free_preparse(struct key_preparsed_payload *prep)
288{
146aa8b1 289 struct ceph_crypto_key *ckey = prep->payload.data[0];
efa64c09
DH
290 ceph_crypto_key_destroy(ckey);
291 kfree(ckey);
292}
293
efa64c09
DH
294static void ceph_key_destroy(struct key *key)
295{
146aa8b1 296 struct ceph_crypto_key *ckey = key->payload.data[0];
4b2a58ab
TV
297
298 ceph_crypto_key_destroy(ckey);
f0666b1a 299 kfree(ckey);
4b2a58ab
TV
300}
301
302struct key_type key_type_ceph = {
303 .name = "ceph",
efa64c09
DH
304 .preparse = ceph_key_preparse,
305 .free_preparse = ceph_key_free_preparse,
306 .instantiate = generic_key_instantiate,
4b2a58ab
TV
307 .destroy = ceph_key_destroy,
308};
309
310int ceph_crypto_init(void) {
311 return register_key_type(&key_type_ceph);
312}
313
314void ceph_crypto_shutdown(void) {
315 unregister_key_type(&key_type_ceph);
316}