]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
ec0994e4 | 2 | |
3d14c5d2 | 3 | #include <linux/ceph/ceph_debug.h> |
ec0994e4 SW |
4 | |
5 | #include <linux/err.h> | |
6 | #include <linux/module.h> | |
7 | #include <linux/random.h> | |
5a0e3ad6 | 8 | #include <linux/slab.h> |
ec0994e4 | 9 | |
3d14c5d2 YS |
10 | #include <linux/ceph/decode.h> |
11 | #include <linux/ceph/auth.h> | |
cc255c76 | 12 | #include <linux/ceph/ceph_features.h> |
a51983e4 | 13 | #include <linux/ceph/libceph.h> |
33d07337 | 14 | #include <linux/ceph/messenger.h> |
3d14c5d2 YS |
15 | |
16 | #include "crypto.h" | |
ec0994e4 SW |
17 | #include "auth_x.h" |
18 | #include "auth_x_protocol.h" | |
ec0994e4 | 19 | |
ec0994e4 SW |
20 | static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed); |
21 | ||
22 | static int ceph_x_is_authenticated(struct ceph_auth_client *ac) | |
23 | { | |
24 | struct ceph_x_info *xi = ac->private; | |
f79e25b0 ID |
25 | int missing; |
26 | int need; /* missing + need renewal */ | |
ec0994e4 SW |
27 | |
28 | ceph_x_validate_tickets(ac, &need); | |
f79e25b0 ID |
29 | missing = ac->want_keys & ~xi->have_keys; |
30 | WARN_ON((need & missing) != missing); | |
31 | dout("%s want 0x%x have 0x%x missing 0x%x -> %d\n", __func__, | |
32 | ac->want_keys, xi->have_keys, missing, !missing); | |
33 | return !missing; | |
ec0994e4 SW |
34 | } |
35 | ||
a41359fa SW |
36 | static int ceph_x_should_authenticate(struct ceph_auth_client *ac) |
37 | { | |
38 | struct ceph_x_info *xi = ac->private; | |
39 | int need; | |
40 | ||
41 | ceph_x_validate_tickets(ac, &need); | |
f79e25b0 ID |
42 | dout("%s want 0x%x have 0x%x need 0x%x -> %d\n", __func__, |
43 | ac->want_keys, xi->have_keys, need, !!need); | |
44 | return !!need; | |
a41359fa SW |
45 | } |
46 | ||
55d9cc83 ID |
47 | static int ceph_x_encrypt_offset(void) |
48 | { | |
49 | return sizeof(u32) + sizeof(struct ceph_x_encrypt_header); | |
50 | } | |
51 | ||
807c86e2 SW |
52 | static int ceph_x_encrypt_buflen(int ilen) |
53 | { | |
55d9cc83 | 54 | return ceph_x_encrypt_offset() + ilen + 16; |
807c86e2 SW |
55 | } |
56 | ||
d03857c6 ID |
57 | static int ceph_x_encrypt(struct ceph_crypto_key *secret, void *buf, |
58 | int buf_len, int plaintext_len) | |
ec0994e4 | 59 | { |
d03857c6 ID |
60 | struct ceph_x_encrypt_header *hdr = buf + sizeof(u32); |
61 | int ciphertext_len; | |
ec0994e4 SW |
62 | int ret; |
63 | ||
d03857c6 ID |
64 | hdr->struct_v = 1; |
65 | hdr->magic = cpu_to_le64(CEPHX_ENC_MAGIC); | |
66 | ||
67 | ret = ceph_crypt(secret, true, buf + sizeof(u32), buf_len - sizeof(u32), | |
68 | plaintext_len + sizeof(struct ceph_x_encrypt_header), | |
69 | &ciphertext_len); | |
ec0994e4 SW |
70 | if (ret) |
71 | return ret; | |
d03857c6 ID |
72 | |
73 | ceph_encode_32(&buf, ciphertext_len); | |
74 | return sizeof(u32) + ciphertext_len; | |
ec0994e4 SW |
75 | } |
76 | ||
c571fe24 ID |
77 | static int __ceph_x_decrypt(struct ceph_crypto_key *secret, void *p, |
78 | int ciphertext_len) | |
79 | { | |
80 | struct ceph_x_encrypt_header *hdr = p; | |
81 | int plaintext_len; | |
82 | int ret; | |
83 | ||
84 | ret = ceph_crypt(secret, false, p, ciphertext_len, ciphertext_len, | |
85 | &plaintext_len); | |
86 | if (ret) | |
87 | return ret; | |
88 | ||
89 | if (le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC) { | |
90 | pr_err("%s bad magic\n", __func__); | |
91 | return -EINVAL; | |
92 | } | |
93 | ||
94 | return plaintext_len - sizeof(*hdr); | |
95 | } | |
96 | ||
e15fd0a1 | 97 | static int ceph_x_decrypt(struct ceph_crypto_key *secret, void **p, void *end) |
ec0994e4 | 98 | { |
c571fe24 | 99 | int ciphertext_len; |
e15fd0a1 | 100 | int ret; |
ec0994e4 | 101 | |
e15fd0a1 ID |
102 | ceph_decode_32_safe(p, end, ciphertext_len, e_inval); |
103 | ceph_decode_need(p, end, ciphertext_len, e_inval); | |
c27a3e4d | 104 | |
c571fe24 ID |
105 | ret = __ceph_x_decrypt(secret, *p, ciphertext_len); |
106 | if (ret < 0) | |
ec0994e4 | 107 | return ret; |
e15fd0a1 | 108 | |
e15fd0a1 | 109 | *p += ciphertext_len; |
c571fe24 | 110 | return ret; |
e15fd0a1 ID |
111 | |
112 | e_inval: | |
113 | return -EINVAL; | |
ec0994e4 SW |
114 | } |
115 | ||
116 | /* | |
117 | * get existing (or insert new) ticket handler | |
118 | */ | |
cd84db6e YS |
119 | static struct ceph_x_ticket_handler * |
120 | get_ticket_handler(struct ceph_auth_client *ac, int service) | |
ec0994e4 SW |
121 | { |
122 | struct ceph_x_ticket_handler *th; | |
123 | struct ceph_x_info *xi = ac->private; | |
124 | struct rb_node *parent = NULL, **p = &xi->ticket_handlers.rb_node; | |
125 | ||
126 | while (*p) { | |
127 | parent = *p; | |
128 | th = rb_entry(parent, struct ceph_x_ticket_handler, node); | |
129 | if (service < th->service) | |
130 | p = &(*p)->rb_left; | |
131 | else if (service > th->service) | |
132 | p = &(*p)->rb_right; | |
133 | else | |
134 | return th; | |
135 | } | |
136 | ||
137 | /* add it */ | |
138 | th = kzalloc(sizeof(*th), GFP_NOFS); | |
139 | if (!th) | |
140 | return ERR_PTR(-ENOMEM); | |
141 | th->service = service; | |
142 | rb_link_node(&th->node, parent, p); | |
143 | rb_insert_color(&th->node, &xi->ticket_handlers); | |
144 | return th; | |
145 | } | |
146 | ||
147 | static void remove_ticket_handler(struct ceph_auth_client *ac, | |
148 | struct ceph_x_ticket_handler *th) | |
149 | { | |
150 | struct ceph_x_info *xi = ac->private; | |
151 | ||
152 | dout("remove_ticket_handler %p %d\n", th, th->service); | |
153 | rb_erase(&th->node, &xi->ticket_handlers); | |
154 | ceph_crypto_key_destroy(&th->session_key); | |
155 | if (th->ticket_blob) | |
156 | ceph_buffer_put(th->ticket_blob); | |
157 | kfree(th); | |
158 | } | |
159 | ||
597cda35 ID |
160 | static int process_one_ticket(struct ceph_auth_client *ac, |
161 | struct ceph_crypto_key *secret, | |
c27a3e4d | 162 | void **p, void *end) |
597cda35 ID |
163 | { |
164 | struct ceph_x_info *xi = ac->private; | |
165 | int type; | |
166 | u8 tkt_struct_v, blob_struct_v; | |
167 | struct ceph_x_ticket_handler *th; | |
168 | void *dp, *dend; | |
169 | int dlen; | |
170 | char is_enc; | |
473bd2d7 | 171 | struct timespec64 validity; |
597cda35 | 172 | void *tp, *tpend; |
e9226d7c | 173 | void **ptp; |
b51456a6 | 174 | struct ceph_crypto_key new_session_key = { 0 }; |
597cda35 | 175 | struct ceph_buffer *new_ticket_blob; |
473bd2d7 | 176 | time64_t new_expires, new_renew_after; |
597cda35 ID |
177 | u64 new_secret_id; |
178 | int ret; | |
179 | ||
180 | ceph_decode_need(p, end, sizeof(u32) + 1, bad); | |
181 | ||
182 | type = ceph_decode_32(p); | |
183 | dout(" ticket type %d %s\n", type, ceph_entity_type_name(type)); | |
184 | ||
185 | tkt_struct_v = ceph_decode_8(p); | |
186 | if (tkt_struct_v != 1) | |
187 | goto bad; | |
188 | ||
189 | th = get_ticket_handler(ac, type); | |
190 | if (IS_ERR(th)) { | |
191 | ret = PTR_ERR(th); | |
192 | goto out; | |
193 | } | |
194 | ||
195 | /* blob for me */ | |
e15fd0a1 ID |
196 | dp = *p + ceph_x_encrypt_offset(); |
197 | ret = ceph_x_decrypt(secret, p, end); | |
198 | if (ret < 0) | |
597cda35 | 199 | goto out; |
e15fd0a1 ID |
200 | dout(" decrypted %d bytes\n", ret); |
201 | dend = dp + ret; | |
597cda35 | 202 | |
6610fff2 | 203 | ceph_decode_8_safe(&dp, dend, tkt_struct_v, bad); |
597cda35 ID |
204 | if (tkt_struct_v != 1) |
205 | goto bad; | |
206 | ||
597cda35 ID |
207 | ret = ceph_crypto_key_decode(&new_session_key, &dp, dend); |
208 | if (ret) | |
209 | goto out; | |
210 | ||
6610fff2 | 211 | ceph_decode_need(&dp, dend, sizeof(struct ceph_timespec), bad); |
473bd2d7 | 212 | ceph_decode_timespec64(&validity, dp); |
f6cdb292 | 213 | dp += sizeof(struct ceph_timespec); |
473bd2d7 | 214 | new_expires = ktime_get_real_seconds() + validity.tv_sec; |
597cda35 | 215 | new_renew_after = new_expires - (validity.tv_sec / 4); |
473bd2d7 | 216 | dout(" expires=%llu renew_after=%llu\n", new_expires, |
597cda35 ID |
217 | new_renew_after); |
218 | ||
219 | /* ticket blob for service */ | |
220 | ceph_decode_8_safe(p, end, is_enc, bad); | |
597cda35 ID |
221 | if (is_enc) { |
222 | /* encrypted */ | |
e15fd0a1 ID |
223 | tp = *p + ceph_x_encrypt_offset(); |
224 | ret = ceph_x_decrypt(&th->session_key, p, end); | |
225 | if (ret < 0) | |
597cda35 | 226 | goto out; |
e15fd0a1 | 227 | dout(" encrypted ticket, decrypted %d bytes\n", ret); |
e9226d7c | 228 | ptp = &tp; |
e15fd0a1 | 229 | tpend = tp + ret; |
597cda35 ID |
230 | } else { |
231 | /* unencrypted */ | |
e9226d7c ID |
232 | ptp = p; |
233 | tpend = end; | |
597cda35 | 234 | } |
e9226d7c | 235 | ceph_decode_32_safe(ptp, tpend, dlen, bad); |
597cda35 | 236 | dout(" ticket blob is %d bytes\n", dlen); |
e9226d7c ID |
237 | ceph_decode_need(ptp, tpend, 1 + sizeof(u64), bad); |
238 | blob_struct_v = ceph_decode_8(ptp); | |
d18a1247 ID |
239 | if (blob_struct_v != 1) |
240 | goto bad; | |
241 | ||
e9226d7c ID |
242 | new_secret_id = ceph_decode_64(ptp); |
243 | ret = ceph_decode_buffer(&new_ticket_blob, ptp, tpend); | |
597cda35 ID |
244 | if (ret) |
245 | goto out; | |
246 | ||
247 | /* all is well, update our ticket */ | |
248 | ceph_crypto_key_destroy(&th->session_key); | |
249 | if (th->ticket_blob) | |
250 | ceph_buffer_put(th->ticket_blob); | |
251 | th->session_key = new_session_key; | |
252 | th->ticket_blob = new_ticket_blob; | |
597cda35 ID |
253 | th->secret_id = new_secret_id; |
254 | th->expires = new_expires; | |
255 | th->renew_after = new_renew_after; | |
6abe097d | 256 | th->have_key = true; |
597cda35 ID |
257 | dout(" got ticket service %d (%s) secret_id %lld len %d\n", |
258 | type, ceph_entity_type_name(type), th->secret_id, | |
259 | (int)th->ticket_blob->vec.iov_len); | |
260 | xi->have_keys |= th->service; | |
b51456a6 | 261 | return 0; |
597cda35 ID |
262 | |
263 | bad: | |
264 | ret = -EINVAL; | |
b51456a6 ID |
265 | out: |
266 | ceph_crypto_key_destroy(&new_session_key); | |
267 | return ret; | |
597cda35 ID |
268 | } |
269 | ||
ec0994e4 SW |
270 | static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, |
271 | struct ceph_crypto_key *secret, | |
285ea34f | 272 | void **p, void *end) |
ec0994e4 | 273 | { |
b736b3d9 | 274 | u8 reply_struct_v; |
597cda35 ID |
275 | u32 num; |
276 | int ret; | |
ec0994e4 | 277 | |
285ea34f | 278 | ceph_decode_8_safe(p, end, reply_struct_v, bad); |
b736b3d9 | 279 | if (reply_struct_v != 1) |
597cda35 | 280 | return -EINVAL; |
ec0994e4 | 281 | |
285ea34f | 282 | ceph_decode_32_safe(p, end, num, bad); |
597cda35 | 283 | dout("%d tickets\n", num); |
ec0994e4 | 284 | |
597cda35 | 285 | while (num--) { |
285ea34f | 286 | ret = process_one_ticket(ac, secret, p, end); |
ec0994e4 | 287 | if (ret) |
c27a3e4d | 288 | return ret; |
ec0994e4 SW |
289 | } |
290 | ||
c27a3e4d | 291 | return 0; |
ec0994e4 SW |
292 | |
293 | bad: | |
c27a3e4d | 294 | return -EINVAL; |
ec0994e4 SW |
295 | } |
296 | ||
149cac4a ID |
297 | /* |
298 | * Encode and encrypt the second part (ceph_x_authorize_b) of the | |
299 | * authorizer. The first part (ceph_x_authorize_a) should already be | |
300 | * encoded. | |
301 | */ | |
6daca13d ID |
302 | static int encrypt_authorizer(struct ceph_x_authorizer *au, |
303 | u64 *server_challenge) | |
149cac4a ID |
304 | { |
305 | struct ceph_x_authorize_a *msg_a; | |
306 | struct ceph_x_authorize_b *msg_b; | |
307 | void *p, *end; | |
308 | int ret; | |
309 | ||
310 | msg_a = au->buf->vec.iov_base; | |
311 | WARN_ON(msg_a->ticket_blob.secret_id != cpu_to_le64(au->secret_id)); | |
312 | p = (void *)(msg_a + 1) + le32_to_cpu(msg_a->ticket_blob.blob_len); | |
313 | end = au->buf->vec.iov_base + au->buf->vec.iov_len; | |
314 | ||
315 | msg_b = p + ceph_x_encrypt_offset(); | |
6daca13d | 316 | msg_b->struct_v = 2; |
149cac4a | 317 | msg_b->nonce = cpu_to_le64(au->nonce); |
6daca13d ID |
318 | if (server_challenge) { |
319 | msg_b->have_challenge = 1; | |
320 | msg_b->server_challenge_plus_one = | |
321 | cpu_to_le64(*server_challenge + 1); | |
322 | } else { | |
323 | msg_b->have_challenge = 0; | |
324 | msg_b->server_challenge_plus_one = 0; | |
325 | } | |
149cac4a ID |
326 | |
327 | ret = ceph_x_encrypt(&au->session_key, p, end - p, sizeof(*msg_b)); | |
328 | if (ret < 0) | |
329 | return ret; | |
330 | ||
331 | p += ret; | |
6daca13d ID |
332 | if (server_challenge) { |
333 | WARN_ON(p != end); | |
334 | } else { | |
335 | WARN_ON(p > end); | |
336 | au->buf->vec.iov_len = p - au->buf->vec.iov_base; | |
337 | } | |
149cac4a ID |
338 | |
339 | return 0; | |
340 | } | |
341 | ||
cbf99a11 ID |
342 | static void ceph_x_authorizer_cleanup(struct ceph_x_authorizer *au) |
343 | { | |
344 | ceph_crypto_key_destroy(&au->session_key); | |
345 | if (au->buf) { | |
346 | ceph_buffer_put(au->buf); | |
347 | au->buf = NULL; | |
348 | } | |
349 | } | |
350 | ||
ec0994e4 SW |
351 | static int ceph_x_build_authorizer(struct ceph_auth_client *ac, |
352 | struct ceph_x_ticket_handler *th, | |
353 | struct ceph_x_authorizer *au) | |
354 | { | |
807c86e2 | 355 | int maxlen; |
ec0994e4 | 356 | struct ceph_x_authorize_a *msg_a; |
d03857c6 | 357 | struct ceph_x_authorize_b *msg_b; |
ec0994e4 SW |
358 | int ret; |
359 | int ticket_blob_len = | |
360 | (th->ticket_blob ? th->ticket_blob->vec.iov_len : 0); | |
361 | ||
362 | dout("build_authorizer for %s %p\n", | |
363 | ceph_entity_type_name(th->service), au); | |
364 | ||
ae385eaf YZ |
365 | ceph_crypto_key_destroy(&au->session_key); |
366 | ret = ceph_crypto_key_clone(&au->session_key, &th->session_key); | |
367 | if (ret) | |
cbf99a11 | 368 | goto out_au; |
ae385eaf | 369 | |
36721ece | 370 | maxlen = sizeof(*msg_a) + ticket_blob_len + |
d03857c6 | 371 | ceph_x_encrypt_buflen(sizeof(*msg_b)); |
807c86e2 SW |
372 | dout(" need len %d\n", maxlen); |
373 | if (au->buf && au->buf->alloc_len < maxlen) { | |
ec0994e4 SW |
374 | ceph_buffer_put(au->buf); |
375 | au->buf = NULL; | |
376 | } | |
377 | if (!au->buf) { | |
807c86e2 | 378 | au->buf = ceph_buffer_new(maxlen, GFP_NOFS); |
ae385eaf | 379 | if (!au->buf) { |
cbf99a11 ID |
380 | ret = -ENOMEM; |
381 | goto out_au; | |
ae385eaf | 382 | } |
ec0994e4 SW |
383 | } |
384 | au->service = th->service; | |
f79e25b0 | 385 | WARN_ON(!th->secret_id); |
0bed9b5c | 386 | au->secret_id = th->secret_id; |
ec0994e4 SW |
387 | |
388 | msg_a = au->buf->vec.iov_base; | |
389 | msg_a->struct_v = 1; | |
390 | msg_a->global_id = cpu_to_le64(ac->global_id); | |
391 | msg_a->service_id = cpu_to_le32(th->service); | |
392 | msg_a->ticket_blob.struct_v = 1; | |
393 | msg_a->ticket_blob.secret_id = cpu_to_le64(th->secret_id); | |
394 | msg_a->ticket_blob.blob_len = cpu_to_le32(ticket_blob_len); | |
395 | if (ticket_blob_len) { | |
396 | memcpy(msg_a->ticket_blob.blob, th->ticket_blob->vec.iov_base, | |
397 | th->ticket_blob->vec.iov_len); | |
398 | } | |
399 | dout(" th %p secret_id %lld %lld\n", th, th->secret_id, | |
400 | le64_to_cpu(msg_a->ticket_blob.secret_id)); | |
401 | ||
ec0994e4 | 402 | get_random_bytes(&au->nonce, sizeof(au->nonce)); |
6daca13d | 403 | ret = encrypt_authorizer(au, NULL); |
149cac4a ID |
404 | if (ret) { |
405 | pr_err("failed to encrypt authorizer: %d", ret); | |
cbf99a11 | 406 | goto out_au; |
149cac4a | 407 | } |
36721ece | 408 | |
ec0994e4 SW |
409 | dout(" built authorizer nonce %llx len %d\n", au->nonce, |
410 | (int)au->buf->vec.iov_len); | |
411 | return 0; | |
412 | ||
cbf99a11 ID |
413 | out_au: |
414 | ceph_x_authorizer_cleanup(au); | |
ec0994e4 SW |
415 | return ret; |
416 | } | |
417 | ||
418 | static int ceph_x_encode_ticket(struct ceph_x_ticket_handler *th, | |
419 | void **p, void *end) | |
420 | { | |
421 | ceph_decode_need(p, end, 1 + sizeof(u64), bad); | |
422 | ceph_encode_8(p, 1); | |
423 | ceph_encode_64(p, th->secret_id); | |
424 | if (th->ticket_blob) { | |
425 | const char *buf = th->ticket_blob->vec.iov_base; | |
426 | u32 len = th->ticket_blob->vec.iov_len; | |
427 | ||
428 | ceph_encode_32_safe(p, end, len, bad); | |
429 | ceph_encode_copy_safe(p, end, buf, len, bad); | |
430 | } else { | |
431 | ceph_encode_32_safe(p, end, 0, bad); | |
432 | } | |
433 | ||
434 | return 0; | |
435 | bad: | |
436 | return -ERANGE; | |
437 | } | |
438 | ||
6abe097d ID |
439 | static bool need_key(struct ceph_x_ticket_handler *th) |
440 | { | |
441 | if (!th->have_key) | |
442 | return true; | |
443 | ||
473bd2d7 | 444 | return ktime_get_real_seconds() >= th->renew_after; |
6abe097d ID |
445 | } |
446 | ||
447 | static bool have_key(struct ceph_x_ticket_handler *th) | |
448 | { | |
f79e25b0 ID |
449 | if (th->have_key && ktime_get_real_seconds() >= th->expires) { |
450 | dout("ticket %d (%s) secret_id %llu expired\n", th->service, | |
451 | ceph_entity_type_name(th->service), th->secret_id); | |
452 | th->have_key = false; | |
6abe097d ID |
453 | } |
454 | ||
455 | return th->have_key; | |
456 | } | |
457 | ||
ec0994e4 SW |
458 | static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed) |
459 | { | |
460 | int want = ac->want_keys; | |
461 | struct ceph_x_info *xi = ac->private; | |
462 | int service; | |
463 | ||
464 | *pneed = ac->want_keys & ~(xi->have_keys); | |
465 | ||
466 | for (service = 1; service <= want; service <<= 1) { | |
467 | struct ceph_x_ticket_handler *th; | |
468 | ||
469 | if (!(ac->want_keys & service)) | |
470 | continue; | |
471 | ||
472 | if (*pneed & service) | |
473 | continue; | |
474 | ||
475 | th = get_ticket_handler(ac, service); | |
b545787d | 476 | if (IS_ERR(th)) { |
ec0994e4 SW |
477 | *pneed |= service; |
478 | continue; | |
479 | } | |
480 | ||
6abe097d | 481 | if (need_key(th)) |
ec0994e4 | 482 | *pneed |= service; |
6abe097d | 483 | if (!have_key(th)) |
ec0994e4 SW |
484 | xi->have_keys &= ~service; |
485 | } | |
486 | } | |
487 | ||
ec0994e4 SW |
488 | static int ceph_x_build_request(struct ceph_auth_client *ac, |
489 | void *buf, void *end) | |
490 | { | |
491 | struct ceph_x_info *xi = ac->private; | |
492 | int need; | |
493 | struct ceph_x_request_header *head = buf; | |
6610fff2 | 494 | void *p; |
ec0994e4 SW |
495 | int ret; |
496 | struct ceph_x_ticket_handler *th = | |
497 | get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH); | |
498 | ||
b545787d DC |
499 | if (IS_ERR(th)) |
500 | return PTR_ERR(th); | |
501 | ||
ec0994e4 | 502 | ceph_x_validate_tickets(ac, &need); |
f79e25b0 ID |
503 | dout("%s want 0x%x have 0x%x need 0x%x\n", __func__, ac->want_keys, |
504 | xi->have_keys, need); | |
ec0994e4 SW |
505 | |
506 | if (need & CEPH_ENTITY_TYPE_AUTH) { | |
507 | struct ceph_x_authenticate *auth = (void *)(head + 1); | |
d03857c6 ID |
508 | void *enc_buf = xi->auth_authorizer.enc_buf; |
509 | struct ceph_x_challenge_blob *blob = enc_buf + | |
510 | ceph_x_encrypt_offset(); | |
ec0994e4 SW |
511 | u64 *u; |
512 | ||
6610fff2 | 513 | p = auth + 1; |
ec0994e4 SW |
514 | if (p > end) |
515 | return -ERANGE; | |
516 | ||
517 | dout(" get_auth_session_key\n"); | |
518 | head->op = cpu_to_le16(CEPHX_GET_AUTH_SESSION_KEY); | |
519 | ||
520 | /* encrypt and hash */ | |
521 | get_random_bytes(&auth->client_challenge, sizeof(u64)); | |
d03857c6 ID |
522 | blob->client_challenge = auth->client_challenge; |
523 | blob->server_challenge = cpu_to_le64(xi->server_challenge); | |
524 | ret = ceph_x_encrypt(&xi->secret, enc_buf, CEPHX_AU_ENC_BUF_LEN, | |
525 | sizeof(*blob)); | |
ec0994e4 SW |
526 | if (ret < 0) |
527 | return ret; | |
528 | ||
7807dafd | 529 | auth->struct_v = 3; /* nautilus+ */ |
ec0994e4 | 530 | auth->key = 0; |
d03857c6 | 531 | for (u = (u64 *)enc_buf; u + 1 <= (u64 *)(enc_buf + ret); u++) |
cd84db6e | 532 | auth->key ^= *(__le64 *)u; |
ec0994e4 SW |
533 | dout(" server_challenge %llx client_challenge %llx key %llx\n", |
534 | xi->server_challenge, le64_to_cpu(auth->client_challenge), | |
535 | le64_to_cpu(auth->key)); | |
536 | ||
537 | /* now encode the old ticket if exists */ | |
538 | ret = ceph_x_encode_ticket(th, &p, end); | |
539 | if (ret < 0) | |
540 | return ret; | |
541 | ||
285ea34f ID |
542 | /* nautilus+: request service tickets at the same time */ |
543 | need = ac->want_keys & ~CEPH_ENTITY_TYPE_AUTH; | |
544 | WARN_ON(!need); | |
545 | ceph_encode_32_safe(&p, end, need, e_range); | |
ec0994e4 SW |
546 | return p - buf; |
547 | } | |
548 | ||
549 | if (need) { | |
6610fff2 | 550 | dout(" get_principal_session_key\n"); |
ec0994e4 SW |
551 | ret = ceph_x_build_authorizer(ac, th, &xi->auth_authorizer); |
552 | if (ret) | |
553 | return ret; | |
ec0994e4 | 554 | |
6610fff2 ID |
555 | p = buf; |
556 | ceph_encode_16_safe(&p, end, CEPHX_GET_PRINCIPAL_SESSION_KEY, | |
557 | e_range); | |
558 | ceph_encode_copy_safe(&p, end, | |
559 | xi->auth_authorizer.buf->vec.iov_base, | |
560 | xi->auth_authorizer.buf->vec.iov_len, e_range); | |
561 | ceph_encode_8_safe(&p, end, 1, e_range); | |
562 | ceph_encode_32_safe(&p, end, need, e_range); | |
ec0994e4 SW |
563 | return p - buf; |
564 | } | |
565 | ||
566 | return 0; | |
6610fff2 ID |
567 | |
568 | e_range: | |
569 | return -ERANGE; | |
ec0994e4 SW |
570 | } |
571 | ||
10f42b3e ID |
572 | static int decode_con_secret(void **p, void *end, u8 *con_secret, |
573 | int *con_secret_len) | |
574 | { | |
575 | int len; | |
576 | ||
577 | ceph_decode_32_safe(p, end, len, bad); | |
578 | ceph_decode_need(p, end, len, bad); | |
579 | ||
580 | dout("%s len %d\n", __func__, len); | |
581 | if (con_secret) { | |
582 | if (len > CEPH_MAX_CON_SECRET_LEN) { | |
583 | pr_err("connection secret too big %d\n", len); | |
584 | goto bad_memzero; | |
585 | } | |
586 | memcpy(con_secret, *p, len); | |
587 | *con_secret_len = len; | |
588 | } | |
589 | memzero_explicit(*p, len); | |
590 | *p += len; | |
591 | return 0; | |
592 | ||
593 | bad_memzero: | |
594 | memzero_explicit(*p, len); | |
595 | bad: | |
596 | pr_err("failed to decode connection secret\n"); | |
597 | return -EINVAL; | |
598 | } | |
599 | ||
03af4c7b | 600 | static int handle_auth_session_key(struct ceph_auth_client *ac, u64 global_id, |
285ea34f ID |
601 | void **p, void *end, |
602 | u8 *session_key, int *session_key_len, | |
603 | u8 *con_secret, int *con_secret_len) | |
604 | { | |
605 | struct ceph_x_info *xi = ac->private; | |
606 | struct ceph_x_ticket_handler *th; | |
607 | void *dp, *dend; | |
608 | int len; | |
609 | int ret; | |
610 | ||
611 | /* AUTH ticket */ | |
612 | ret = ceph_x_proc_ticket_reply(ac, &xi->secret, p, end); | |
613 | if (ret) | |
614 | return ret; | |
615 | ||
03af4c7b | 616 | ceph_auth_set_global_id(ac, global_id); |
285ea34f ID |
617 | if (*p == end) { |
618 | /* pre-nautilus (or didn't request service tickets!) */ | |
619 | WARN_ON(session_key || con_secret); | |
620 | return 0; | |
621 | } | |
622 | ||
623 | th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH); | |
624 | if (IS_ERR(th)) | |
625 | return PTR_ERR(th); | |
626 | ||
627 | if (session_key) { | |
628 | memcpy(session_key, th->session_key.key, th->session_key.len); | |
629 | *session_key_len = th->session_key.len; | |
630 | } | |
631 | ||
632 | /* connection secret */ | |
633 | ceph_decode_32_safe(p, end, len, e_inval); | |
634 | dout("%s connection secret blob len %d\n", __func__, len); | |
635 | if (len > 0) { | |
636 | dp = *p + ceph_x_encrypt_offset(); | |
637 | ret = ceph_x_decrypt(&th->session_key, p, *p + len); | |
638 | if (ret < 0) | |
639 | return ret; | |
640 | ||
641 | dout("%s decrypted %d bytes\n", __func__, ret); | |
642 | dend = dp + ret; | |
643 | ||
10f42b3e ID |
644 | ret = decode_con_secret(&dp, dend, con_secret, con_secret_len); |
645 | if (ret) | |
646 | return ret; | |
285ea34f ID |
647 | } |
648 | ||
649 | /* service tickets */ | |
650 | ceph_decode_32_safe(p, end, len, e_inval); | |
651 | dout("%s service tickets blob len %d\n", __func__, len); | |
652 | if (len > 0) { | |
653 | ret = ceph_x_proc_ticket_reply(ac, &th->session_key, | |
654 | p, *p + len); | |
655 | if (ret) | |
656 | return ret; | |
657 | } | |
658 | ||
659 | return 0; | |
660 | ||
661 | e_inval: | |
662 | return -EINVAL; | |
663 | } | |
664 | ||
03af4c7b | 665 | static int ceph_x_handle_reply(struct ceph_auth_client *ac, u64 global_id, |
285ea34f ID |
666 | void *buf, void *end, |
667 | u8 *session_key, int *session_key_len, | |
668 | u8 *con_secret, int *con_secret_len) | |
ec0994e4 SW |
669 | { |
670 | struct ceph_x_info *xi = ac->private; | |
ec0994e4 SW |
671 | struct ceph_x_ticket_handler *th; |
672 | int len = end - buf; | |
3c0d0894 | 673 | int result; |
6610fff2 | 674 | void *p; |
ec0994e4 SW |
675 | int op; |
676 | int ret; | |
677 | ||
ec0994e4 SW |
678 | if (xi->starting) { |
679 | /* it's a hello */ | |
680 | struct ceph_x_server_challenge *sc = buf; | |
681 | ||
682 | if (len != sizeof(*sc)) | |
683 | return -EINVAL; | |
684 | xi->server_challenge = le64_to_cpu(sc->server_challenge); | |
685 | dout("handle_reply got server challenge %llx\n", | |
686 | xi->server_challenge); | |
687 | xi->starting = false; | |
688 | xi->have_keys &= ~CEPH_ENTITY_TYPE_AUTH; | |
689 | return -EAGAIN; | |
690 | } | |
691 | ||
6610fff2 ID |
692 | p = buf; |
693 | ceph_decode_16_safe(&p, end, op, e_inval); | |
694 | ceph_decode_32_safe(&p, end, result, e_inval); | |
ec0994e4 SW |
695 | dout("handle_reply op %d result %d\n", op, result); |
696 | switch (op) { | |
697 | case CEPHX_GET_AUTH_SESSION_KEY: | |
285ea34f | 698 | /* AUTH ticket + [connection secret] + service tickets */ |
03af4c7b ID |
699 | ret = handle_auth_session_key(ac, global_id, &p, end, |
700 | session_key, session_key_len, | |
701 | con_secret, con_secret_len); | |
ec0994e4 SW |
702 | break; |
703 | ||
704 | case CEPHX_GET_PRINCIPAL_SESSION_KEY: | |
705 | th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH); | |
b545787d DC |
706 | if (IS_ERR(th)) |
707 | return PTR_ERR(th); | |
6610fff2 | 708 | |
285ea34f ID |
709 | /* service tickets */ |
710 | ret = ceph_x_proc_ticket_reply(ac, &th->session_key, &p, end); | |
ec0994e4 SW |
711 | break; |
712 | ||
713 | default: | |
714 | return -EINVAL; | |
715 | } | |
716 | if (ret) | |
717 | return ret; | |
718 | if (ac->want_keys == xi->have_keys) | |
719 | return 0; | |
720 | return -EAGAIN; | |
6610fff2 ID |
721 | |
722 | e_inval: | |
723 | return -EINVAL; | |
ec0994e4 SW |
724 | } |
725 | ||
6c1ea260 ID |
726 | static void ceph_x_destroy_authorizer(struct ceph_authorizer *a) |
727 | { | |
728 | struct ceph_x_authorizer *au = (void *)a; | |
729 | ||
730 | ceph_x_authorizer_cleanup(au); | |
731 | kfree(au); | |
732 | } | |
733 | ||
ec0994e4 SW |
734 | static int ceph_x_create_authorizer( |
735 | struct ceph_auth_client *ac, int peer_type, | |
74f1869f | 736 | struct ceph_auth_handshake *auth) |
ec0994e4 SW |
737 | { |
738 | struct ceph_x_authorizer *au; | |
739 | struct ceph_x_ticket_handler *th; | |
740 | int ret; | |
741 | ||
742 | th = get_ticket_handler(ac, peer_type); | |
743 | if (IS_ERR(th)) | |
744 | return PTR_ERR(th); | |
745 | ||
746 | au = kzalloc(sizeof(*au), GFP_NOFS); | |
747 | if (!au) | |
748 | return -ENOMEM; | |
749 | ||
6c1ea260 ID |
750 | au->base.destroy = ceph_x_destroy_authorizer; |
751 | ||
ec0994e4 SW |
752 | ret = ceph_x_build_authorizer(ac, th, au); |
753 | if (ret) { | |
754 | kfree(au); | |
755 | return ret; | |
756 | } | |
757 | ||
74f1869f AE |
758 | auth->authorizer = (struct ceph_authorizer *) au; |
759 | auth->authorizer_buf = au->buf->vec.iov_base; | |
760 | auth->authorizer_buf_len = au->buf->vec.iov_len; | |
7882a26d ID |
761 | auth->authorizer_reply_buf = au->enc_buf; |
762 | auth->authorizer_reply_buf_len = CEPHX_AU_ENC_BUF_LEN; | |
33d07337 YZ |
763 | auth->sign_message = ac->ops->sign_message; |
764 | auth->check_message_signature = ac->ops->check_message_signature; | |
74f1869f | 765 | |
ec0994e4 SW |
766 | return 0; |
767 | } | |
768 | ||
0bed9b5c SW |
769 | static int ceph_x_update_authorizer( |
770 | struct ceph_auth_client *ac, int peer_type, | |
771 | struct ceph_auth_handshake *auth) | |
772 | { | |
773 | struct ceph_x_authorizer *au; | |
774 | struct ceph_x_ticket_handler *th; | |
0bed9b5c SW |
775 | |
776 | th = get_ticket_handler(ac, peer_type); | |
777 | if (IS_ERR(th)) | |
778 | return PTR_ERR(th); | |
779 | ||
780 | au = (struct ceph_x_authorizer *)auth->authorizer; | |
781 | if (au->secret_id < th->secret_id) { | |
782 | dout("ceph_x_update_authorizer service %u secret %llu < %llu\n", | |
783 | au->service, au->secret_id, th->secret_id); | |
784 | return ceph_x_build_authorizer(ac, th, au); | |
785 | } | |
786 | return 0; | |
787 | } | |
788 | ||
285ea34f ID |
789 | /* |
790 | * CephXAuthorizeChallenge | |
791 | */ | |
792 | static int decrypt_authorizer_challenge(struct ceph_crypto_key *secret, | |
793 | void *challenge, int challenge_len, | |
794 | u64 *server_challenge) | |
6daca13d | 795 | { |
285ea34f | 796 | void *dp, *dend; |
6daca13d ID |
797 | int ret; |
798 | ||
799 | /* no leading len */ | |
285ea34f | 800 | ret = __ceph_x_decrypt(secret, challenge, challenge_len); |
6daca13d ID |
801 | if (ret < 0) |
802 | return ret; | |
6daca13d | 803 | |
285ea34f ID |
804 | dout("%s decrypted %d bytes\n", __func__, ret); |
805 | dp = challenge + sizeof(struct ceph_x_encrypt_header); | |
806 | dend = dp + ret; | |
807 | ||
808 | ceph_decode_skip_8(&dp, dend, e_inval); /* struct_v */ | |
809 | ceph_decode_64_safe(&dp, dend, *server_challenge, e_inval); | |
810 | dout("%s server_challenge %llu\n", __func__, *server_challenge); | |
6daca13d | 811 | return 0; |
285ea34f ID |
812 | |
813 | e_inval: | |
814 | return -EINVAL; | |
6daca13d ID |
815 | } |
816 | ||
817 | static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac, | |
818 | struct ceph_authorizer *a, | |
285ea34f | 819 | void *challenge, int challenge_len) |
6daca13d ID |
820 | { |
821 | struct ceph_x_authorizer *au = (void *)a; | |
822 | u64 server_challenge; | |
823 | int ret; | |
824 | ||
285ea34f ID |
825 | ret = decrypt_authorizer_challenge(&au->session_key, challenge, |
826 | challenge_len, &server_challenge); | |
6daca13d ID |
827 | if (ret) { |
828 | pr_err("failed to decrypt authorize challenge: %d", ret); | |
829 | return ret; | |
830 | } | |
831 | ||
832 | ret = encrypt_authorizer(au, &server_challenge); | |
833 | if (ret) { | |
834 | pr_err("failed to encrypt authorizer w/ challenge: %d", ret); | |
835 | return ret; | |
836 | } | |
837 | ||
838 | return 0; | |
839 | } | |
840 | ||
285ea34f ID |
841 | /* |
842 | * CephXAuthorizeReply | |
843 | */ | |
844 | static int decrypt_authorizer_reply(struct ceph_crypto_key *secret, | |
845 | void **p, void *end, u64 *nonce_plus_one, | |
846 | u8 *con_secret, int *con_secret_len) | |
847 | { | |
848 | void *dp, *dend; | |
849 | u8 struct_v; | |
285ea34f ID |
850 | int ret; |
851 | ||
852 | dp = *p + ceph_x_encrypt_offset(); | |
853 | ret = ceph_x_decrypt(secret, p, end); | |
854 | if (ret < 0) | |
855 | return ret; | |
856 | ||
857 | dout("%s decrypted %d bytes\n", __func__, ret); | |
858 | dend = dp + ret; | |
859 | ||
860 | ceph_decode_8_safe(&dp, dend, struct_v, e_inval); | |
861 | ceph_decode_64_safe(&dp, dend, *nonce_plus_one, e_inval); | |
862 | dout("%s nonce_plus_one %llu\n", __func__, *nonce_plus_one); | |
863 | if (struct_v >= 2) { | |
10f42b3e ID |
864 | ret = decode_con_secret(&dp, dend, con_secret, con_secret_len); |
865 | if (ret) | |
866 | return ret; | |
285ea34f ID |
867 | } |
868 | ||
869 | return 0; | |
870 | ||
871 | e_inval: | |
872 | return -EINVAL; | |
873 | } | |
874 | ||
ec0994e4 | 875 | static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac, |
285ea34f ID |
876 | struct ceph_authorizer *a, |
877 | void *reply, int reply_len, | |
878 | u8 *session_key, int *session_key_len, | |
879 | u8 *con_secret, int *con_secret_len) | |
ec0994e4 SW |
880 | { |
881 | struct ceph_x_authorizer *au = (void *)a; | |
285ea34f | 882 | u64 nonce_plus_one; |
e15fd0a1 | 883 | int ret; |
ec0994e4 | 884 | |
285ea34f ID |
885 | if (session_key) { |
886 | memcpy(session_key, au->session_key.key, au->session_key.len); | |
887 | *session_key_len = au->session_key.len; | |
888 | } | |
889 | ||
890 | ret = decrypt_authorizer_reply(&au->session_key, &reply, | |
891 | reply + reply_len, &nonce_plus_one, | |
892 | con_secret, con_secret_len); | |
893 | if (ret) | |
ec0994e4 | 894 | return ret; |
285ea34f ID |
895 | |
896 | if (nonce_plus_one != au->nonce + 1) { | |
897 | pr_err("failed to authenticate server\n"); | |
898 | return -EPERM; | |
f1d10e04 | 899 | } |
ec0994e4 | 900 | |
285ea34f | 901 | return 0; |
ec0994e4 SW |
902 | } |
903 | ||
ec0994e4 SW |
904 | static void ceph_x_reset(struct ceph_auth_client *ac) |
905 | { | |
906 | struct ceph_x_info *xi = ac->private; | |
907 | ||
908 | dout("reset\n"); | |
909 | xi->starting = true; | |
910 | xi->server_challenge = 0; | |
911 | } | |
912 | ||
913 | static void ceph_x_destroy(struct ceph_auth_client *ac) | |
914 | { | |
915 | struct ceph_x_info *xi = ac->private; | |
916 | struct rb_node *p; | |
917 | ||
918 | dout("ceph_x_destroy %p\n", ac); | |
919 | ceph_crypto_key_destroy(&xi->secret); | |
920 | ||
921 | while ((p = rb_first(&xi->ticket_handlers)) != NULL) { | |
922 | struct ceph_x_ticket_handler *th = | |
923 | rb_entry(p, struct ceph_x_ticket_handler, node); | |
924 | remove_ticket_handler(ac, th); | |
925 | } | |
926 | ||
cbf99a11 | 927 | ceph_x_authorizer_cleanup(&xi->auth_authorizer); |
22b1de06 | 928 | |
ec0994e4 SW |
929 | kfree(ac->private); |
930 | ac->private = NULL; | |
931 | } | |
932 | ||
187d131d | 933 | static void invalidate_ticket(struct ceph_auth_client *ac, int peer_type) |
ec0994e4 SW |
934 | { |
935 | struct ceph_x_ticket_handler *th; | |
936 | ||
937 | th = get_ticket_handler(ac, peer_type); | |
f79e25b0 ID |
938 | if (IS_ERR(th)) |
939 | return; | |
940 | ||
941 | if (th->have_key) { | |
942 | dout("ticket %d (%s) secret_id %llu invalidated\n", | |
943 | th->service, ceph_entity_type_name(th->service), | |
944 | th->secret_id); | |
6abe097d | 945 | th->have_key = false; |
f79e25b0 | 946 | } |
ec0994e4 SW |
947 | } |
948 | ||
187d131d ID |
949 | static void ceph_x_invalidate_authorizer(struct ceph_auth_client *ac, |
950 | int peer_type) | |
951 | { | |
952 | /* | |
953 | * We are to invalidate a service ticket in the hopes of | |
954 | * getting a new, hopefully more valid, one. But, we won't get | |
955 | * it unless our AUTH ticket is good, so invalidate AUTH ticket | |
956 | * as well, just in case. | |
957 | */ | |
958 | invalidate_ticket(ac, peer_type); | |
959 | invalidate_ticket(ac, CEPH_ENTITY_TYPE_AUTH); | |
960 | } | |
961 | ||
4eb4517c ID |
962 | static int calc_signature(struct ceph_x_authorizer *au, struct ceph_msg *msg, |
963 | __le64 *psig) | |
33d07337 | 964 | { |
d03857c6 | 965 | void *enc_buf = au->enc_buf; |
4eb4517c ID |
966 | int ret; |
967 | ||
cc255c76 ID |
968 | if (!CEPH_HAVE_FEATURE(msg->con->peer_features, CEPHX_V2)) { |
969 | struct { | |
970 | __le32 len; | |
971 | __le32 header_crc; | |
972 | __le32 front_crc; | |
973 | __le32 middle_crc; | |
974 | __le32 data_crc; | |
975 | } __packed *sigblock = enc_buf + ceph_x_encrypt_offset(); | |
976 | ||
977 | sigblock->len = cpu_to_le32(4*sizeof(u32)); | |
978 | sigblock->header_crc = msg->hdr.crc; | |
979 | sigblock->front_crc = msg->footer.front_crc; | |
980 | sigblock->middle_crc = msg->footer.middle_crc; | |
981 | sigblock->data_crc = msg->footer.data_crc; | |
982 | ||
983 | ret = ceph_x_encrypt(&au->session_key, enc_buf, | |
984 | CEPHX_AU_ENC_BUF_LEN, sizeof(*sigblock)); | |
985 | if (ret < 0) | |
986 | return ret; | |
987 | ||
988 | *psig = *(__le64 *)(enc_buf + sizeof(u32)); | |
989 | } else { | |
990 | struct { | |
991 | __le32 header_crc; | |
992 | __le32 front_crc; | |
993 | __le32 front_len; | |
994 | __le32 middle_crc; | |
995 | __le32 middle_len; | |
996 | __le32 data_crc; | |
997 | __le32 data_len; | |
998 | __le32 seq_lower_word; | |
999 | } __packed *sigblock = enc_buf; | |
1000 | struct { | |
1001 | __le64 a, b, c, d; | |
1002 | } __packed *penc = enc_buf; | |
1003 | int ciphertext_len; | |
1004 | ||
1005 | sigblock->header_crc = msg->hdr.crc; | |
1006 | sigblock->front_crc = msg->footer.front_crc; | |
1007 | sigblock->front_len = msg->hdr.front_len; | |
1008 | sigblock->middle_crc = msg->footer.middle_crc; | |
1009 | sigblock->middle_len = msg->hdr.middle_len; | |
1010 | sigblock->data_crc = msg->footer.data_crc; | |
1011 | sigblock->data_len = msg->hdr.data_len; | |
1012 | sigblock->seq_lower_word = *(__le32 *)&msg->hdr.seq; | |
1013 | ||
1014 | /* no leading len, no ceph_x_encrypt_header */ | |
1015 | ret = ceph_crypt(&au->session_key, true, enc_buf, | |
1016 | CEPHX_AU_ENC_BUF_LEN, sizeof(*sigblock), | |
1017 | &ciphertext_len); | |
1018 | if (ret) | |
1019 | return ret; | |
1020 | ||
1021 | *psig = penc->a ^ penc->b ^ penc->c ^ penc->d; | |
1022 | } | |
4eb4517c | 1023 | |
33d07337 YZ |
1024 | return 0; |
1025 | } | |
1026 | ||
1027 | static int ceph_x_sign_message(struct ceph_auth_handshake *auth, | |
1028 | struct ceph_msg *msg) | |
1029 | { | |
4eb4517c | 1030 | __le64 sig; |
33d07337 | 1031 | int ret; |
4199b8ee | 1032 | |
a51983e4 ID |
1033 | if (ceph_test_opt(from_msgr(msg->con->msgr), NOMSGSIGN)) |
1034 | return 0; | |
1035 | ||
4eb4517c ID |
1036 | ret = calc_signature((struct ceph_x_authorizer *)auth->authorizer, |
1037 | msg, &sig); | |
1038 | if (ret) | |
33d07337 | 1039 | return ret; |
4eb4517c ID |
1040 | |
1041 | msg->footer.sig = sig; | |
33d07337 YZ |
1042 | msg->footer.flags |= CEPH_MSG_FOOTER_SIGNED; |
1043 | return 0; | |
1044 | } | |
1045 | ||
1046 | static int ceph_x_check_message_signature(struct ceph_auth_handshake *auth, | |
1047 | struct ceph_msg *msg) | |
1048 | { | |
1049 | __le64 sig_check; | |
1050 | int ret; | |
1051 | ||
a51983e4 ID |
1052 | if (ceph_test_opt(from_msgr(msg->con->msgr), NOMSGSIGN)) |
1053 | return 0; | |
1054 | ||
4eb4517c ID |
1055 | ret = calc_signature((struct ceph_x_authorizer *)auth->authorizer, |
1056 | msg, &sig_check); | |
1057 | if (ret) | |
33d07337 YZ |
1058 | return ret; |
1059 | if (sig_check == msg->footer.sig) | |
1060 | return 0; | |
1061 | if (msg->footer.flags & CEPH_MSG_FOOTER_SIGNED) | |
1062 | dout("ceph_x_check_message_signature %p has signature %llx " | |
1063 | "expect %llx\n", msg, msg->footer.sig, sig_check); | |
1064 | else | |
1065 | dout("ceph_x_check_message_signature %p sender did not set " | |
1066 | "CEPH_MSG_FOOTER_SIGNED\n", msg); | |
1067 | return -EBADMSG; | |
1068 | } | |
ec0994e4 SW |
1069 | |
1070 | static const struct ceph_auth_client_ops ceph_x_ops = { | |
1071 | .is_authenticated = ceph_x_is_authenticated, | |
a41359fa | 1072 | .should_authenticate = ceph_x_should_authenticate, |
ec0994e4 SW |
1073 | .build_request = ceph_x_build_request, |
1074 | .handle_reply = ceph_x_handle_reply, | |
1075 | .create_authorizer = ceph_x_create_authorizer, | |
0bed9b5c | 1076 | .update_authorizer = ceph_x_update_authorizer, |
6daca13d | 1077 | .add_authorizer_challenge = ceph_x_add_authorizer_challenge, |
ec0994e4 | 1078 | .verify_authorizer_reply = ceph_x_verify_authorizer_reply, |
ec0994e4 SW |
1079 | .invalidate_authorizer = ceph_x_invalidate_authorizer, |
1080 | .reset = ceph_x_reset, | |
1081 | .destroy = ceph_x_destroy, | |
33d07337 YZ |
1082 | .sign_message = ceph_x_sign_message, |
1083 | .check_message_signature = ceph_x_check_message_signature, | |
ec0994e4 SW |
1084 | }; |
1085 | ||
1086 | ||
1087 | int ceph_x_init(struct ceph_auth_client *ac) | |
1088 | { | |
1089 | struct ceph_x_info *xi; | |
1090 | int ret; | |
1091 | ||
1092 | dout("ceph_x_init %p\n", ac); | |
b0930f8d | 1093 | ret = -ENOMEM; |
ec0994e4 SW |
1094 | xi = kzalloc(sizeof(*xi), GFP_NOFS); |
1095 | if (!xi) | |
b0930f8d | 1096 | goto out; |
ec0994e4 | 1097 | |
ec0994e4 | 1098 | ret = -EINVAL; |
8323c3aa | 1099 | if (!ac->key) { |
ec0994e4 | 1100 | pr_err("no secret set (for auth_x protocol)\n"); |
b0930f8d | 1101 | goto out_nomem; |
ec0994e4 SW |
1102 | } |
1103 | ||
8323c3aa TV |
1104 | ret = ceph_crypto_key_clone(&xi->secret, ac->key); |
1105 | if (ret < 0) { | |
1106 | pr_err("cannot clone key: %d\n", ret); | |
b0930f8d | 1107 | goto out_nomem; |
8323c3aa | 1108 | } |
ec0994e4 SW |
1109 | |
1110 | xi->starting = true; | |
1111 | xi->ticket_handlers = RB_ROOT; | |
1112 | ||
1113 | ac->protocol = CEPH_AUTH_CEPHX; | |
1114 | ac->private = xi; | |
1115 | ac->ops = &ceph_x_ops; | |
1116 | return 0; | |
1117 | ||
b0930f8d | 1118 | out_nomem: |
ec0994e4 | 1119 | kfree(xi); |
b0930f8d | 1120 | out: |
ec0994e4 SW |
1121 | return ret; |
1122 | } |