|
1 /*- |
|
2 * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. |
|
3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. |
|
4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * a) Redistributions of source code must retain the above copyright notice, |
|
10 * this list of conditions and the following disclaimer. |
|
11 * |
|
12 * b) Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in |
|
14 * the documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * c) Neither the name of Cisco Systems, Inc. nor the names of its |
|
17 * contributors may be used to endorse or promote products derived |
|
18 * from this software without specific prior written permission. |
|
19 * |
|
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
|
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
|
30 * THE POSSIBILITY OF SUCH DAMAGE. |
|
31 */ |
|
32 |
|
33 #ifdef __FreeBSD__ |
|
34 #include <sys/cdefs.h> |
|
35 __FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.c 257804 2013-11-07 18:50:11Z tuexen $"); |
|
36 #endif |
|
37 |
|
38 #include <netinet/sctp_os.h> |
|
39 #include <netinet/sctp.h> |
|
40 #include <netinet/sctp_header.h> |
|
41 #include <netinet/sctp_pcb.h> |
|
42 #include <netinet/sctp_var.h> |
|
43 #include <netinet/sctp_sysctl.h> |
|
44 #include <netinet/sctputil.h> |
|
45 #include <netinet/sctp_indata.h> |
|
46 #include <netinet/sctp_output.h> |
|
47 #include <netinet/sctp_auth.h> |
|
48 |
|
49 #ifdef SCTP_DEBUG |
|
50 #define SCTP_AUTH_DEBUG (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_AUTH1) |
|
51 #define SCTP_AUTH_DEBUG2 (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_AUTH2) |
|
52 #endif /* SCTP_DEBUG */ |
|
53 |
|
54 |
|
55 void |
|
56 sctp_clear_chunklist(sctp_auth_chklist_t *chklist) |
|
57 { |
|
58 bzero(chklist, sizeof(*chklist)); |
|
59 /* chklist->num_chunks = 0; */ |
|
60 } |
|
61 |
|
62 sctp_auth_chklist_t * |
|
63 sctp_alloc_chunklist(void) |
|
64 { |
|
65 sctp_auth_chklist_t *chklist; |
|
66 |
|
67 SCTP_MALLOC(chklist, sctp_auth_chklist_t *, sizeof(*chklist), |
|
68 SCTP_M_AUTH_CL); |
|
69 if (chklist == NULL) { |
|
70 SCTPDBG(SCTP_DEBUG_AUTH1, "sctp_alloc_chunklist: failed to get memory!\n"); |
|
71 } else { |
|
72 sctp_clear_chunklist(chklist); |
|
73 } |
|
74 return (chklist); |
|
75 } |
|
76 |
|
77 void |
|
78 sctp_free_chunklist(sctp_auth_chklist_t *list) |
|
79 { |
|
80 if (list != NULL) |
|
81 SCTP_FREE(list, SCTP_M_AUTH_CL); |
|
82 } |
|
83 |
|
84 sctp_auth_chklist_t * |
|
85 sctp_copy_chunklist(sctp_auth_chklist_t *list) |
|
86 { |
|
87 sctp_auth_chklist_t *new_list; |
|
88 |
|
89 if (list == NULL) |
|
90 return (NULL); |
|
91 |
|
92 /* get a new list */ |
|
93 new_list = sctp_alloc_chunklist(); |
|
94 if (new_list == NULL) |
|
95 return (NULL); |
|
96 /* copy it */ |
|
97 bcopy(list, new_list, sizeof(*new_list)); |
|
98 |
|
99 return (new_list); |
|
100 } |
|
101 |
|
102 |
|
103 /* |
|
104 * add a chunk to the required chunks list |
|
105 */ |
|
106 int |
|
107 sctp_auth_add_chunk(uint8_t chunk, sctp_auth_chklist_t *list) |
|
108 { |
|
109 if (list == NULL) |
|
110 return (-1); |
|
111 |
|
112 /* is chunk restricted? */ |
|
113 if ((chunk == SCTP_INITIATION) || |
|
114 (chunk == SCTP_INITIATION_ACK) || |
|
115 (chunk == SCTP_SHUTDOWN_COMPLETE) || |
|
116 (chunk == SCTP_AUTHENTICATION)) { |
|
117 return (-1); |
|
118 } |
|
119 if (list->chunks[chunk] == 0) { |
|
120 list->chunks[chunk] = 1; |
|
121 list->num_chunks++; |
|
122 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
123 "SCTP: added chunk %u (0x%02x) to Auth list\n", |
|
124 chunk, chunk); |
|
125 } |
|
126 return (0); |
|
127 } |
|
128 |
|
129 /* |
|
130 * delete a chunk from the required chunks list |
|
131 */ |
|
132 int |
|
133 sctp_auth_delete_chunk(uint8_t chunk, sctp_auth_chklist_t *list) |
|
134 { |
|
135 if (list == NULL) |
|
136 return (-1); |
|
137 |
|
138 /* is chunk restricted? */ |
|
139 if ((chunk == SCTP_ASCONF) || |
|
140 (chunk == SCTP_ASCONF_ACK)) { |
|
141 return (-1); |
|
142 } |
|
143 if (list->chunks[chunk] == 1) { |
|
144 list->chunks[chunk] = 0; |
|
145 list->num_chunks--; |
|
146 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
147 "SCTP: deleted chunk %u (0x%02x) from Auth list\n", |
|
148 chunk, chunk); |
|
149 } |
|
150 return (0); |
|
151 } |
|
152 |
|
153 size_t |
|
154 sctp_auth_get_chklist_size(const sctp_auth_chklist_t *list) |
|
155 { |
|
156 if (list == NULL) |
|
157 return (0); |
|
158 else |
|
159 return (list->num_chunks); |
|
160 } |
|
161 |
|
162 /* |
|
163 * set the default list of chunks requiring AUTH |
|
164 */ |
|
165 void |
|
166 sctp_auth_set_default_chunks(sctp_auth_chklist_t *list) |
|
167 { |
|
168 (void)sctp_auth_add_chunk(SCTP_ASCONF, list); |
|
169 (void)sctp_auth_add_chunk(SCTP_ASCONF_ACK, list); |
|
170 } |
|
171 |
|
172 /* |
|
173 * return the current number and list of required chunks caller must |
|
174 * guarantee ptr has space for up to 256 bytes |
|
175 */ |
|
176 int |
|
177 sctp_serialize_auth_chunks(const sctp_auth_chklist_t *list, uint8_t *ptr) |
|
178 { |
|
179 int i, count = 0; |
|
180 |
|
181 if (list == NULL) |
|
182 return (0); |
|
183 |
|
184 for (i = 0; i < 256; i++) { |
|
185 if (list->chunks[i] != 0) { |
|
186 *ptr++ = i; |
|
187 count++; |
|
188 } |
|
189 } |
|
190 return (count); |
|
191 } |
|
192 |
|
193 int |
|
194 sctp_pack_auth_chunks(const sctp_auth_chklist_t *list, uint8_t *ptr) |
|
195 { |
|
196 int i, size = 0; |
|
197 |
|
198 if (list == NULL) |
|
199 return (0); |
|
200 |
|
201 if (list->num_chunks <= 32) { |
|
202 /* just list them, one byte each */ |
|
203 for (i = 0; i < 256; i++) { |
|
204 if (list->chunks[i] != 0) { |
|
205 *ptr++ = i; |
|
206 size++; |
|
207 } |
|
208 } |
|
209 } else { |
|
210 int index, offset; |
|
211 |
|
212 /* pack into a 32 byte bitfield */ |
|
213 for (i = 0; i < 256; i++) { |
|
214 if (list->chunks[i] != 0) { |
|
215 index = i / 8; |
|
216 offset = i % 8; |
|
217 ptr[index] |= (1 << offset); |
|
218 } |
|
219 } |
|
220 size = 32; |
|
221 } |
|
222 return (size); |
|
223 } |
|
224 |
|
225 int |
|
226 sctp_unpack_auth_chunks(const uint8_t *ptr, uint8_t num_chunks, |
|
227 sctp_auth_chklist_t *list) |
|
228 { |
|
229 int i; |
|
230 int size; |
|
231 |
|
232 if (list == NULL) |
|
233 return (0); |
|
234 |
|
235 if (num_chunks <= 32) { |
|
236 /* just pull them, one byte each */ |
|
237 for (i = 0; i < num_chunks; i++) { |
|
238 (void)sctp_auth_add_chunk(*ptr++, list); |
|
239 } |
|
240 size = num_chunks; |
|
241 } else { |
|
242 int index, offset; |
|
243 |
|
244 /* unpack from a 32 byte bitfield */ |
|
245 for (index = 0; index < 32; index++) { |
|
246 for (offset = 0; offset < 8; offset++) { |
|
247 if (ptr[index] & (1 << offset)) { |
|
248 (void)sctp_auth_add_chunk((index * 8) + offset, list); |
|
249 } |
|
250 } |
|
251 } |
|
252 size = 32; |
|
253 } |
|
254 return (size); |
|
255 } |
|
256 |
|
257 |
|
258 /* |
|
259 * allocate structure space for a key of length keylen |
|
260 */ |
|
261 sctp_key_t * |
|
262 sctp_alloc_key(uint32_t keylen) |
|
263 { |
|
264 sctp_key_t *new_key; |
|
265 |
|
266 SCTP_MALLOC(new_key, sctp_key_t *, sizeof(*new_key) + keylen, |
|
267 SCTP_M_AUTH_KY); |
|
268 if (new_key == NULL) { |
|
269 /* out of memory */ |
|
270 return (NULL); |
|
271 } |
|
272 new_key->keylen = keylen; |
|
273 return (new_key); |
|
274 } |
|
275 |
|
276 void |
|
277 sctp_free_key(sctp_key_t *key) |
|
278 { |
|
279 if (key != NULL) |
|
280 SCTP_FREE(key,SCTP_M_AUTH_KY); |
|
281 } |
|
282 |
|
283 void |
|
284 sctp_print_key(sctp_key_t *key, const char *str) |
|
285 { |
|
286 uint32_t i; |
|
287 |
|
288 if (key == NULL) { |
|
289 SCTP_PRINTF("%s: [Null key]\n", str); |
|
290 return; |
|
291 } |
|
292 SCTP_PRINTF("%s: len %u, ", str, key->keylen); |
|
293 if (key->keylen) { |
|
294 for (i = 0; i < key->keylen; i++) |
|
295 SCTP_PRINTF("%02x", key->key[i]); |
|
296 SCTP_PRINTF("\n"); |
|
297 } else { |
|
298 SCTP_PRINTF("[Null key]\n"); |
|
299 } |
|
300 } |
|
301 |
|
302 void |
|
303 sctp_show_key(sctp_key_t *key, const char *str) |
|
304 { |
|
305 uint32_t i; |
|
306 |
|
307 if (key == NULL) { |
|
308 SCTP_PRINTF("%s: [Null key]\n", str); |
|
309 return; |
|
310 } |
|
311 SCTP_PRINTF("%s: len %u, ", str, key->keylen); |
|
312 if (key->keylen) { |
|
313 for (i = 0; i < key->keylen; i++) |
|
314 SCTP_PRINTF("%02x", key->key[i]); |
|
315 SCTP_PRINTF("\n"); |
|
316 } else { |
|
317 SCTP_PRINTF("[Null key]\n"); |
|
318 } |
|
319 } |
|
320 |
|
321 static uint32_t |
|
322 sctp_get_keylen(sctp_key_t *key) |
|
323 { |
|
324 if (key != NULL) |
|
325 return (key->keylen); |
|
326 else |
|
327 return (0); |
|
328 } |
|
329 |
|
330 /* |
|
331 * generate a new random key of length 'keylen' |
|
332 */ |
|
333 sctp_key_t * |
|
334 sctp_generate_random_key(uint32_t keylen) |
|
335 { |
|
336 sctp_key_t *new_key; |
|
337 |
|
338 new_key = sctp_alloc_key(keylen); |
|
339 if (new_key == NULL) { |
|
340 /* out of memory */ |
|
341 return (NULL); |
|
342 } |
|
343 SCTP_READ_RANDOM(new_key->key, keylen); |
|
344 new_key->keylen = keylen; |
|
345 return (new_key); |
|
346 } |
|
347 |
|
348 sctp_key_t * |
|
349 sctp_set_key(uint8_t *key, uint32_t keylen) |
|
350 { |
|
351 sctp_key_t *new_key; |
|
352 |
|
353 new_key = sctp_alloc_key(keylen); |
|
354 if (new_key == NULL) { |
|
355 /* out of memory */ |
|
356 return (NULL); |
|
357 } |
|
358 bcopy(key, new_key->key, keylen); |
|
359 return (new_key); |
|
360 } |
|
361 |
|
362 /*- |
|
363 * given two keys of variable size, compute which key is "larger/smaller" |
|
364 * returns: 1 if key1 > key2 |
|
365 * -1 if key1 < key2 |
|
366 * 0 if key1 = key2 |
|
367 */ |
|
368 static int |
|
369 sctp_compare_key(sctp_key_t *key1, sctp_key_t *key2) |
|
370 { |
|
371 uint32_t maxlen; |
|
372 uint32_t i; |
|
373 uint32_t key1len, key2len; |
|
374 uint8_t *key_1, *key_2; |
|
375 uint8_t val1, val2; |
|
376 |
|
377 /* sanity/length check */ |
|
378 key1len = sctp_get_keylen(key1); |
|
379 key2len = sctp_get_keylen(key2); |
|
380 if ((key1len == 0) && (key2len == 0)) |
|
381 return (0); |
|
382 else if (key1len == 0) |
|
383 return (-1); |
|
384 else if (key2len == 0) |
|
385 return (1); |
|
386 |
|
387 if (key1len < key2len) { |
|
388 maxlen = key2len; |
|
389 } else { |
|
390 maxlen = key1len; |
|
391 } |
|
392 key_1 = key1->key; |
|
393 key_2 = key2->key; |
|
394 /* check for numeric equality */ |
|
395 for (i = 0; i < maxlen; i++) { |
|
396 /* left-pad with zeros */ |
|
397 val1 = (i < (maxlen - key1len)) ? 0 : *(key_1++); |
|
398 val2 = (i < (maxlen - key2len)) ? 0 : *(key_2++); |
|
399 if (val1 > val2) { |
|
400 return (1); |
|
401 } else if (val1 < val2) { |
|
402 return (-1); |
|
403 } |
|
404 } |
|
405 /* keys are equal value, so check lengths */ |
|
406 if (key1len == key2len) |
|
407 return (0); |
|
408 else if (key1len < key2len) |
|
409 return (-1); |
|
410 else |
|
411 return (1); |
|
412 } |
|
413 |
|
414 /* |
|
415 * generate the concatenated keying material based on the two keys and the |
|
416 * shared key (if available). draft-ietf-tsvwg-auth specifies the specific |
|
417 * order for concatenation |
|
418 */ |
|
419 sctp_key_t * |
|
420 sctp_compute_hashkey(sctp_key_t *key1, sctp_key_t *key2, sctp_key_t *shared) |
|
421 { |
|
422 uint32_t keylen; |
|
423 sctp_key_t *new_key; |
|
424 uint8_t *key_ptr; |
|
425 |
|
426 keylen = sctp_get_keylen(key1) + sctp_get_keylen(key2) + |
|
427 sctp_get_keylen(shared); |
|
428 |
|
429 if (keylen > 0) { |
|
430 /* get space for the new key */ |
|
431 new_key = sctp_alloc_key(keylen); |
|
432 if (new_key == NULL) { |
|
433 /* out of memory */ |
|
434 return (NULL); |
|
435 } |
|
436 new_key->keylen = keylen; |
|
437 key_ptr = new_key->key; |
|
438 } else { |
|
439 /* all keys empty/null?! */ |
|
440 return (NULL); |
|
441 } |
|
442 |
|
443 /* concatenate the keys */ |
|
444 if (sctp_compare_key(key1, key2) <= 0) { |
|
445 /* key is shared + key1 + key2 */ |
|
446 if (sctp_get_keylen(shared)) { |
|
447 bcopy(shared->key, key_ptr, shared->keylen); |
|
448 key_ptr += shared->keylen; |
|
449 } |
|
450 if (sctp_get_keylen(key1)) { |
|
451 bcopy(key1->key, key_ptr, key1->keylen); |
|
452 key_ptr += key1->keylen; |
|
453 } |
|
454 if (sctp_get_keylen(key2)) { |
|
455 bcopy(key2->key, key_ptr, key2->keylen); |
|
456 } |
|
457 } else { |
|
458 /* key is shared + key2 + key1 */ |
|
459 if (sctp_get_keylen(shared)) { |
|
460 bcopy(shared->key, key_ptr, shared->keylen); |
|
461 key_ptr += shared->keylen; |
|
462 } |
|
463 if (sctp_get_keylen(key2)) { |
|
464 bcopy(key2->key, key_ptr, key2->keylen); |
|
465 key_ptr += key2->keylen; |
|
466 } |
|
467 if (sctp_get_keylen(key1)) { |
|
468 bcopy(key1->key, key_ptr, key1->keylen); |
|
469 } |
|
470 } |
|
471 return (new_key); |
|
472 } |
|
473 |
|
474 |
|
475 sctp_sharedkey_t * |
|
476 sctp_alloc_sharedkey(void) |
|
477 { |
|
478 sctp_sharedkey_t *new_key; |
|
479 |
|
480 SCTP_MALLOC(new_key, sctp_sharedkey_t *, sizeof(*new_key), |
|
481 SCTP_M_AUTH_KY); |
|
482 if (new_key == NULL) { |
|
483 /* out of memory */ |
|
484 return (NULL); |
|
485 } |
|
486 new_key->keyid = 0; |
|
487 new_key->key = NULL; |
|
488 new_key->refcount = 1; |
|
489 new_key->deactivated = 0; |
|
490 return (new_key); |
|
491 } |
|
492 |
|
493 void |
|
494 sctp_free_sharedkey(sctp_sharedkey_t *skey) |
|
495 { |
|
496 if (skey == NULL) |
|
497 return; |
|
498 |
|
499 if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&skey->refcount)) { |
|
500 if (skey->key != NULL) |
|
501 sctp_free_key(skey->key); |
|
502 SCTP_FREE(skey, SCTP_M_AUTH_KY); |
|
503 } |
|
504 } |
|
505 |
|
506 sctp_sharedkey_t * |
|
507 sctp_find_sharedkey(struct sctp_keyhead *shared_keys, uint16_t key_id) |
|
508 { |
|
509 sctp_sharedkey_t *skey; |
|
510 |
|
511 LIST_FOREACH(skey, shared_keys, next) { |
|
512 if (skey->keyid == key_id) |
|
513 return (skey); |
|
514 } |
|
515 return (NULL); |
|
516 } |
|
517 |
|
518 int |
|
519 sctp_insert_sharedkey(struct sctp_keyhead *shared_keys, |
|
520 sctp_sharedkey_t *new_skey) |
|
521 { |
|
522 sctp_sharedkey_t *skey; |
|
523 |
|
524 if ((shared_keys == NULL) || (new_skey == NULL)) |
|
525 return (EINVAL); |
|
526 |
|
527 /* insert into an empty list? */ |
|
528 if (LIST_EMPTY(shared_keys)) { |
|
529 LIST_INSERT_HEAD(shared_keys, new_skey, next); |
|
530 return (0); |
|
531 } |
|
532 /* insert into the existing list, ordered by key id */ |
|
533 LIST_FOREACH(skey, shared_keys, next) { |
|
534 if (new_skey->keyid < skey->keyid) { |
|
535 /* insert it before here */ |
|
536 LIST_INSERT_BEFORE(skey, new_skey, next); |
|
537 return (0); |
|
538 } else if (new_skey->keyid == skey->keyid) { |
|
539 /* replace the existing key */ |
|
540 /* verify this key *can* be replaced */ |
|
541 if ((skey->deactivated) && (skey->refcount > 1)) { |
|
542 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
543 "can't replace shared key id %u\n", |
|
544 new_skey->keyid); |
|
545 return (EBUSY); |
|
546 } |
|
547 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
548 "replacing shared key id %u\n", |
|
549 new_skey->keyid); |
|
550 LIST_INSERT_BEFORE(skey, new_skey, next); |
|
551 LIST_REMOVE(skey, next); |
|
552 sctp_free_sharedkey(skey); |
|
553 return (0); |
|
554 } |
|
555 if (LIST_NEXT(skey, next) == NULL) { |
|
556 /* belongs at the end of the list */ |
|
557 LIST_INSERT_AFTER(skey, new_skey, next); |
|
558 return (0); |
|
559 } |
|
560 } |
|
561 /* shouldn't reach here */ |
|
562 return (0); |
|
563 } |
|
564 |
|
565 void |
|
566 sctp_auth_key_acquire(struct sctp_tcb *stcb, uint16_t key_id) |
|
567 { |
|
568 sctp_sharedkey_t *skey; |
|
569 |
|
570 /* find the shared key */ |
|
571 skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, key_id); |
|
572 |
|
573 /* bump the ref count */ |
|
574 if (skey) { |
|
575 atomic_add_int(&skey->refcount, 1); |
|
576 SCTPDBG(SCTP_DEBUG_AUTH2, |
|
577 "%s: stcb %p key %u refcount acquire to %d\n", |
|
578 __FUNCTION__, (void *)stcb, key_id, skey->refcount); |
|
579 } |
|
580 } |
|
581 |
|
582 void |
|
583 sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t key_id, int so_locked |
|
584 #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) |
|
585 SCTP_UNUSED |
|
586 #endif |
|
587 ) |
|
588 { |
|
589 sctp_sharedkey_t *skey; |
|
590 |
|
591 /* find the shared key */ |
|
592 skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, key_id); |
|
593 |
|
594 /* decrement the ref count */ |
|
595 if (skey) { |
|
596 sctp_free_sharedkey(skey); |
|
597 SCTPDBG(SCTP_DEBUG_AUTH2, |
|
598 "%s: stcb %p key %u refcount release to %d\n", |
|
599 __FUNCTION__, (void *)stcb, key_id, skey->refcount); |
|
600 |
|
601 /* see if a notification should be generated */ |
|
602 if ((skey->refcount <= 1) && (skey->deactivated)) { |
|
603 /* notify ULP that key is no longer used */ |
|
604 sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb, |
|
605 key_id, 0, so_locked); |
|
606 SCTPDBG(SCTP_DEBUG_AUTH2, |
|
607 "%s: stcb %p key %u no longer used, %d\n", |
|
608 __FUNCTION__, (void *)stcb, key_id, skey->refcount); |
|
609 } |
|
610 } |
|
611 } |
|
612 |
|
613 static sctp_sharedkey_t * |
|
614 sctp_copy_sharedkey(const sctp_sharedkey_t *skey) |
|
615 { |
|
616 sctp_sharedkey_t *new_skey; |
|
617 |
|
618 if (skey == NULL) |
|
619 return (NULL); |
|
620 new_skey = sctp_alloc_sharedkey(); |
|
621 if (new_skey == NULL) |
|
622 return (NULL); |
|
623 if (skey->key != NULL) |
|
624 new_skey->key = sctp_set_key(skey->key->key, skey->key->keylen); |
|
625 else |
|
626 new_skey->key = NULL; |
|
627 new_skey->keyid = skey->keyid; |
|
628 return (new_skey); |
|
629 } |
|
630 |
|
631 int |
|
632 sctp_copy_skeylist(const struct sctp_keyhead *src, struct sctp_keyhead *dest) |
|
633 { |
|
634 sctp_sharedkey_t *skey, *new_skey; |
|
635 int count = 0; |
|
636 |
|
637 if ((src == NULL) || (dest == NULL)) |
|
638 return (0); |
|
639 LIST_FOREACH(skey, src, next) { |
|
640 new_skey = sctp_copy_sharedkey(skey); |
|
641 if (new_skey != NULL) { |
|
642 (void)sctp_insert_sharedkey(dest, new_skey); |
|
643 count++; |
|
644 } |
|
645 } |
|
646 return (count); |
|
647 } |
|
648 |
|
649 |
|
650 sctp_hmaclist_t * |
|
651 sctp_alloc_hmaclist(uint8_t num_hmacs) |
|
652 { |
|
653 sctp_hmaclist_t *new_list; |
|
654 int alloc_size; |
|
655 |
|
656 alloc_size = sizeof(*new_list) + num_hmacs * sizeof(new_list->hmac[0]); |
|
657 SCTP_MALLOC(new_list, sctp_hmaclist_t *, alloc_size, |
|
658 SCTP_M_AUTH_HL); |
|
659 if (new_list == NULL) { |
|
660 /* out of memory */ |
|
661 return (NULL); |
|
662 } |
|
663 new_list->max_algo = num_hmacs; |
|
664 new_list->num_algo = 0; |
|
665 return (new_list); |
|
666 } |
|
667 |
|
668 void |
|
669 sctp_free_hmaclist(sctp_hmaclist_t *list) |
|
670 { |
|
671 if (list != NULL) { |
|
672 SCTP_FREE(list,SCTP_M_AUTH_HL); |
|
673 list = NULL; |
|
674 } |
|
675 } |
|
676 |
|
677 int |
|
678 sctp_auth_add_hmacid(sctp_hmaclist_t *list, uint16_t hmac_id) |
|
679 { |
|
680 int i; |
|
681 if (list == NULL) |
|
682 return (-1); |
|
683 if (list->num_algo == list->max_algo) { |
|
684 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
685 "SCTP: HMAC id list full, ignoring add %u\n", hmac_id); |
|
686 return (-1); |
|
687 } |
|
688 #if defined(SCTP_SUPPORT_HMAC_SHA256) |
|
689 if ((hmac_id != SCTP_AUTH_HMAC_ID_SHA1) && |
|
690 (hmac_id != SCTP_AUTH_HMAC_ID_SHA256)) { |
|
691 #else |
|
692 if (hmac_id != SCTP_AUTH_HMAC_ID_SHA1) { |
|
693 #endif |
|
694 return (-1); |
|
695 } |
|
696 /* Now is it already in the list */ |
|
697 for (i = 0; i < list->num_algo; i++) { |
|
698 if (list->hmac[i] == hmac_id) { |
|
699 /* already in list */ |
|
700 return (-1); |
|
701 } |
|
702 } |
|
703 SCTPDBG(SCTP_DEBUG_AUTH1, "SCTP: add HMAC id %u to list\n", hmac_id); |
|
704 list->hmac[list->num_algo++] = hmac_id; |
|
705 return (0); |
|
706 } |
|
707 |
|
708 sctp_hmaclist_t * |
|
709 sctp_copy_hmaclist(sctp_hmaclist_t *list) |
|
710 { |
|
711 sctp_hmaclist_t *new_list; |
|
712 int i; |
|
713 |
|
714 if (list == NULL) |
|
715 return (NULL); |
|
716 /* get a new list */ |
|
717 new_list = sctp_alloc_hmaclist(list->max_algo); |
|
718 if (new_list == NULL) |
|
719 return (NULL); |
|
720 /* copy it */ |
|
721 new_list->max_algo = list->max_algo; |
|
722 new_list->num_algo = list->num_algo; |
|
723 for (i = 0; i < list->num_algo; i++) |
|
724 new_list->hmac[i] = list->hmac[i]; |
|
725 return (new_list); |
|
726 } |
|
727 |
|
728 sctp_hmaclist_t * |
|
729 sctp_default_supported_hmaclist(void) |
|
730 { |
|
731 sctp_hmaclist_t *new_list; |
|
732 |
|
733 #if defined(SCTP_SUPPORT_HMAC_SHA256) |
|
734 new_list = sctp_alloc_hmaclist(2); |
|
735 #else |
|
736 new_list = sctp_alloc_hmaclist(1); |
|
737 #endif |
|
738 if (new_list == NULL) |
|
739 return (NULL); |
|
740 #if defined(SCTP_SUPPORT_HMAC_SHA256) |
|
741 /* We prefer SHA256, so list it first */ |
|
742 (void)sctp_auth_add_hmacid(new_list, SCTP_AUTH_HMAC_ID_SHA256); |
|
743 #endif |
|
744 (void)sctp_auth_add_hmacid(new_list, SCTP_AUTH_HMAC_ID_SHA1); |
|
745 return (new_list); |
|
746 } |
|
747 |
|
748 /*- |
|
749 * HMAC algos are listed in priority/preference order |
|
750 * find the best HMAC id to use for the peer based on local support |
|
751 */ |
|
752 uint16_t |
|
753 sctp_negotiate_hmacid(sctp_hmaclist_t *peer, sctp_hmaclist_t *local) |
|
754 { |
|
755 int i, j; |
|
756 |
|
757 if ((local == NULL) || (peer == NULL)) |
|
758 return (SCTP_AUTH_HMAC_ID_RSVD); |
|
759 |
|
760 for (i = 0; i < peer->num_algo; i++) { |
|
761 for (j = 0; j < local->num_algo; j++) { |
|
762 if (peer->hmac[i] == local->hmac[j]) { |
|
763 /* found the "best" one */ |
|
764 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
765 "SCTP: negotiated peer HMAC id %u\n", |
|
766 peer->hmac[i]); |
|
767 return (peer->hmac[i]); |
|
768 } |
|
769 } |
|
770 } |
|
771 /* didn't find one! */ |
|
772 return (SCTP_AUTH_HMAC_ID_RSVD); |
|
773 } |
|
774 |
|
775 /*- |
|
776 * serialize the HMAC algo list and return space used |
|
777 * caller must guarantee ptr has appropriate space |
|
778 */ |
|
779 int |
|
780 sctp_serialize_hmaclist(sctp_hmaclist_t *list, uint8_t *ptr) |
|
781 { |
|
782 int i; |
|
783 uint16_t hmac_id; |
|
784 |
|
785 if (list == NULL) |
|
786 return (0); |
|
787 |
|
788 for (i = 0; i < list->num_algo; i++) { |
|
789 hmac_id = htons(list->hmac[i]); |
|
790 bcopy(&hmac_id, ptr, sizeof(hmac_id)); |
|
791 ptr += sizeof(hmac_id); |
|
792 } |
|
793 return (list->num_algo * sizeof(hmac_id)); |
|
794 } |
|
795 |
|
796 int |
|
797 sctp_verify_hmac_param (struct sctp_auth_hmac_algo *hmacs, uint32_t num_hmacs) |
|
798 { |
|
799 uint32_t i; |
|
800 |
|
801 for (i = 0; i < num_hmacs; i++) { |
|
802 if (ntohs(hmacs->hmac_ids[i]) == SCTP_AUTH_HMAC_ID_SHA1) { |
|
803 return (0); |
|
804 } |
|
805 } |
|
806 return (-1); |
|
807 } |
|
808 |
|
809 sctp_authinfo_t * |
|
810 sctp_alloc_authinfo(void) |
|
811 { |
|
812 sctp_authinfo_t *new_authinfo; |
|
813 |
|
814 SCTP_MALLOC(new_authinfo, sctp_authinfo_t *, sizeof(*new_authinfo), |
|
815 SCTP_M_AUTH_IF); |
|
816 |
|
817 if (new_authinfo == NULL) { |
|
818 /* out of memory */ |
|
819 return (NULL); |
|
820 } |
|
821 bzero(new_authinfo, sizeof(*new_authinfo)); |
|
822 return (new_authinfo); |
|
823 } |
|
824 |
|
825 void |
|
826 sctp_free_authinfo(sctp_authinfo_t *authinfo) |
|
827 { |
|
828 if (authinfo == NULL) |
|
829 return; |
|
830 |
|
831 if (authinfo->random != NULL) |
|
832 sctp_free_key(authinfo->random); |
|
833 if (authinfo->peer_random != NULL) |
|
834 sctp_free_key(authinfo->peer_random); |
|
835 if (authinfo->assoc_key != NULL) |
|
836 sctp_free_key(authinfo->assoc_key); |
|
837 if (authinfo->recv_key != NULL) |
|
838 sctp_free_key(authinfo->recv_key); |
|
839 |
|
840 /* We are NOT dynamically allocating authinfo's right now... */ |
|
841 /* SCTP_FREE(authinfo, SCTP_M_AUTH_??); */ |
|
842 } |
|
843 |
|
844 |
|
845 uint32_t |
|
846 sctp_get_auth_chunk_len(uint16_t hmac_algo) |
|
847 { |
|
848 int size; |
|
849 |
|
850 size = sizeof(struct sctp_auth_chunk) + sctp_get_hmac_digest_len(hmac_algo); |
|
851 return (SCTP_SIZE32(size)); |
|
852 } |
|
853 |
|
854 uint32_t |
|
855 sctp_get_hmac_digest_len(uint16_t hmac_algo) |
|
856 { |
|
857 switch (hmac_algo) { |
|
858 case SCTP_AUTH_HMAC_ID_SHA1: |
|
859 return (SCTP_AUTH_DIGEST_LEN_SHA1); |
|
860 #if defined(SCTP_SUPPORT_HMAC_SHA256) |
|
861 case SCTP_AUTH_HMAC_ID_SHA256: |
|
862 return (SCTP_AUTH_DIGEST_LEN_SHA256); |
|
863 #endif |
|
864 default: |
|
865 /* unknown HMAC algorithm: can't do anything */ |
|
866 return (0); |
|
867 } /* end switch */ |
|
868 } |
|
869 |
|
870 static inline int |
|
871 sctp_get_hmac_block_len(uint16_t hmac_algo) |
|
872 { |
|
873 switch (hmac_algo) { |
|
874 case SCTP_AUTH_HMAC_ID_SHA1: |
|
875 return (64); |
|
876 #if defined(SCTP_SUPPORT_HMAC_SHA256) |
|
877 case SCTP_AUTH_HMAC_ID_SHA256: |
|
878 return (64); |
|
879 #endif |
|
880 case SCTP_AUTH_HMAC_ID_RSVD: |
|
881 default: |
|
882 /* unknown HMAC algorithm: can't do anything */ |
|
883 return (0); |
|
884 } /* end switch */ |
|
885 } |
|
886 |
|
887 #if defined(__Userspace__) |
|
888 /* __Userspace__ SHA1_Init is defined in libcrypto.a (libssl-dev on Ubuntu) */ |
|
889 #endif |
|
890 static void |
|
891 sctp_hmac_init(uint16_t hmac_algo, sctp_hash_context_t *ctx) |
|
892 { |
|
893 switch (hmac_algo) { |
|
894 case SCTP_AUTH_HMAC_ID_SHA1: |
|
895 SCTP_SHA1_INIT(&ctx->sha1); |
|
896 break; |
|
897 #if defined(SCTP_SUPPORT_HMAC_SHA256) |
|
898 case SCTP_AUTH_HMAC_ID_SHA256: |
|
899 SCTP_SHA256_INIT(&ctx->sha256); |
|
900 break; |
|
901 #endif |
|
902 case SCTP_AUTH_HMAC_ID_RSVD: |
|
903 default: |
|
904 /* unknown HMAC algorithm: can't do anything */ |
|
905 return; |
|
906 } /* end switch */ |
|
907 } |
|
908 |
|
909 static void |
|
910 sctp_hmac_update(uint16_t hmac_algo, sctp_hash_context_t *ctx, |
|
911 uint8_t *text, uint32_t textlen) |
|
912 { |
|
913 switch (hmac_algo) { |
|
914 case SCTP_AUTH_HMAC_ID_SHA1: |
|
915 SCTP_SHA1_UPDATE(&ctx->sha1, text, textlen); |
|
916 break; |
|
917 #if defined(SCTP_SUPPORT_HMAC_SHA256) |
|
918 case SCTP_AUTH_HMAC_ID_SHA256: |
|
919 SCTP_SHA256_UPDATE(&ctx->sha256, text, textlen); |
|
920 break; |
|
921 #endif |
|
922 case SCTP_AUTH_HMAC_ID_RSVD: |
|
923 default: |
|
924 /* unknown HMAC algorithm: can't do anything */ |
|
925 return; |
|
926 } /* end switch */ |
|
927 } |
|
928 |
|
929 static void |
|
930 sctp_hmac_final(uint16_t hmac_algo, sctp_hash_context_t *ctx, |
|
931 uint8_t *digest) |
|
932 { |
|
933 switch (hmac_algo) { |
|
934 case SCTP_AUTH_HMAC_ID_SHA1: |
|
935 SCTP_SHA1_FINAL(digest, &ctx->sha1); |
|
936 break; |
|
937 #if defined(SCTP_SUPPORT_HMAC_SHA256) |
|
938 case SCTP_AUTH_HMAC_ID_SHA256: |
|
939 SCTP_SHA256_FINAL(digest, &ctx->sha256); |
|
940 break; |
|
941 #endif |
|
942 case SCTP_AUTH_HMAC_ID_RSVD: |
|
943 default: |
|
944 /* unknown HMAC algorithm: can't do anything */ |
|
945 return; |
|
946 } /* end switch */ |
|
947 } |
|
948 |
|
949 /*- |
|
950 * Keyed-Hashing for Message Authentication: FIPS 198 (RFC 2104) |
|
951 * |
|
952 * Compute the HMAC digest using the desired hash key, text, and HMAC |
|
953 * algorithm. Resulting digest is placed in 'digest' and digest length |
|
954 * is returned, if the HMAC was performed. |
|
955 * |
|
956 * WARNING: it is up to the caller to supply sufficient space to hold the |
|
957 * resultant digest. |
|
958 */ |
|
959 uint32_t |
|
960 sctp_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen, |
|
961 uint8_t *text, uint32_t textlen, uint8_t *digest) |
|
962 { |
|
963 uint32_t digestlen; |
|
964 uint32_t blocklen; |
|
965 sctp_hash_context_t ctx; |
|
966 uint8_t ipad[128], opad[128]; /* keyed hash inner/outer pads */ |
|
967 uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX]; |
|
968 uint32_t i; |
|
969 |
|
970 /* sanity check the material and length */ |
|
971 if ((key == NULL) || (keylen == 0) || (text == NULL) || |
|
972 (textlen == 0) || (digest == NULL)) { |
|
973 /* can't do HMAC with empty key or text or digest store */ |
|
974 return (0); |
|
975 } |
|
976 /* validate the hmac algo and get the digest length */ |
|
977 digestlen = sctp_get_hmac_digest_len(hmac_algo); |
|
978 if (digestlen == 0) |
|
979 return (0); |
|
980 |
|
981 /* hash the key if it is longer than the hash block size */ |
|
982 blocklen = sctp_get_hmac_block_len(hmac_algo); |
|
983 if (keylen > blocklen) { |
|
984 sctp_hmac_init(hmac_algo, &ctx); |
|
985 sctp_hmac_update(hmac_algo, &ctx, key, keylen); |
|
986 sctp_hmac_final(hmac_algo, &ctx, temp); |
|
987 /* set the hashed key as the key */ |
|
988 keylen = digestlen; |
|
989 key = temp; |
|
990 } |
|
991 /* initialize the inner/outer pads with the key and "append" zeroes */ |
|
992 bzero(ipad, blocklen); |
|
993 bzero(opad, blocklen); |
|
994 bcopy(key, ipad, keylen); |
|
995 bcopy(key, opad, keylen); |
|
996 |
|
997 /* XOR the key with ipad and opad values */ |
|
998 for (i = 0; i < blocklen; i++) { |
|
999 ipad[i] ^= 0x36; |
|
1000 opad[i] ^= 0x5c; |
|
1001 } |
|
1002 |
|
1003 /* perform inner hash */ |
|
1004 sctp_hmac_init(hmac_algo, &ctx); |
|
1005 sctp_hmac_update(hmac_algo, &ctx, ipad, blocklen); |
|
1006 sctp_hmac_update(hmac_algo, &ctx, text, textlen); |
|
1007 sctp_hmac_final(hmac_algo, &ctx, temp); |
|
1008 |
|
1009 /* perform outer hash */ |
|
1010 sctp_hmac_init(hmac_algo, &ctx); |
|
1011 sctp_hmac_update(hmac_algo, &ctx, opad, blocklen); |
|
1012 sctp_hmac_update(hmac_algo, &ctx, temp, digestlen); |
|
1013 sctp_hmac_final(hmac_algo, &ctx, digest); |
|
1014 |
|
1015 return (digestlen); |
|
1016 } |
|
1017 |
|
1018 /* mbuf version */ |
|
1019 uint32_t |
|
1020 sctp_hmac_m(uint16_t hmac_algo, uint8_t *key, uint32_t keylen, |
|
1021 struct mbuf *m, uint32_t m_offset, uint8_t *digest, uint32_t trailer) |
|
1022 { |
|
1023 uint32_t digestlen; |
|
1024 uint32_t blocklen; |
|
1025 sctp_hash_context_t ctx; |
|
1026 uint8_t ipad[128], opad[128]; /* keyed hash inner/outer pads */ |
|
1027 uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX]; |
|
1028 uint32_t i; |
|
1029 struct mbuf *m_tmp; |
|
1030 |
|
1031 /* sanity check the material and length */ |
|
1032 if ((key == NULL) || (keylen == 0) || (m == NULL) || (digest == NULL)) { |
|
1033 /* can't do HMAC with empty key or text or digest store */ |
|
1034 return (0); |
|
1035 } |
|
1036 /* validate the hmac algo and get the digest length */ |
|
1037 digestlen = sctp_get_hmac_digest_len(hmac_algo); |
|
1038 if (digestlen == 0) |
|
1039 return (0); |
|
1040 |
|
1041 /* hash the key if it is longer than the hash block size */ |
|
1042 blocklen = sctp_get_hmac_block_len(hmac_algo); |
|
1043 if (keylen > blocklen) { |
|
1044 sctp_hmac_init(hmac_algo, &ctx); |
|
1045 sctp_hmac_update(hmac_algo, &ctx, key, keylen); |
|
1046 sctp_hmac_final(hmac_algo, &ctx, temp); |
|
1047 /* set the hashed key as the key */ |
|
1048 keylen = digestlen; |
|
1049 key = temp; |
|
1050 } |
|
1051 /* initialize the inner/outer pads with the key and "append" zeroes */ |
|
1052 bzero(ipad, blocklen); |
|
1053 bzero(opad, blocklen); |
|
1054 bcopy(key, ipad, keylen); |
|
1055 bcopy(key, opad, keylen); |
|
1056 |
|
1057 /* XOR the key with ipad and opad values */ |
|
1058 for (i = 0; i < blocklen; i++) { |
|
1059 ipad[i] ^= 0x36; |
|
1060 opad[i] ^= 0x5c; |
|
1061 } |
|
1062 |
|
1063 /* perform inner hash */ |
|
1064 sctp_hmac_init(hmac_algo, &ctx); |
|
1065 sctp_hmac_update(hmac_algo, &ctx, ipad, blocklen); |
|
1066 /* find the correct starting mbuf and offset (get start of text) */ |
|
1067 m_tmp = m; |
|
1068 while ((m_tmp != NULL) && (m_offset >= (uint32_t) SCTP_BUF_LEN(m_tmp))) { |
|
1069 m_offset -= SCTP_BUF_LEN(m_tmp); |
|
1070 m_tmp = SCTP_BUF_NEXT(m_tmp); |
|
1071 } |
|
1072 /* now use the rest of the mbuf chain for the text */ |
|
1073 while (m_tmp != NULL) { |
|
1074 if ((SCTP_BUF_NEXT(m_tmp) == NULL) && trailer) { |
|
1075 sctp_hmac_update(hmac_algo, &ctx, mtod(m_tmp, uint8_t *) + m_offset, |
|
1076 SCTP_BUF_LEN(m_tmp) - (trailer+m_offset)); |
|
1077 } else { |
|
1078 sctp_hmac_update(hmac_algo, &ctx, mtod(m_tmp, uint8_t *) + m_offset, |
|
1079 SCTP_BUF_LEN(m_tmp) - m_offset); |
|
1080 } |
|
1081 |
|
1082 /* clear the offset since it's only for the first mbuf */ |
|
1083 m_offset = 0; |
|
1084 m_tmp = SCTP_BUF_NEXT(m_tmp); |
|
1085 } |
|
1086 sctp_hmac_final(hmac_algo, &ctx, temp); |
|
1087 |
|
1088 /* perform outer hash */ |
|
1089 sctp_hmac_init(hmac_algo, &ctx); |
|
1090 sctp_hmac_update(hmac_algo, &ctx, opad, blocklen); |
|
1091 sctp_hmac_update(hmac_algo, &ctx, temp, digestlen); |
|
1092 sctp_hmac_final(hmac_algo, &ctx, digest); |
|
1093 |
|
1094 return (digestlen); |
|
1095 } |
|
1096 |
|
1097 /*- |
|
1098 * verify the HMAC digest using the desired hash key, text, and HMAC |
|
1099 * algorithm. |
|
1100 * Returns -1 on error, 0 on success. |
|
1101 */ |
|
1102 int |
|
1103 sctp_verify_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen, |
|
1104 uint8_t *text, uint32_t textlen, |
|
1105 uint8_t *digest, uint32_t digestlen) |
|
1106 { |
|
1107 uint32_t len; |
|
1108 uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX]; |
|
1109 |
|
1110 /* sanity check the material and length */ |
|
1111 if ((key == NULL) || (keylen == 0) || |
|
1112 (text == NULL) || (textlen == 0) || (digest == NULL)) { |
|
1113 /* can't do HMAC with empty key or text or digest */ |
|
1114 return (-1); |
|
1115 } |
|
1116 len = sctp_get_hmac_digest_len(hmac_algo); |
|
1117 if ((len == 0) || (digestlen != len)) |
|
1118 return (-1); |
|
1119 |
|
1120 /* compute the expected hash */ |
|
1121 if (sctp_hmac(hmac_algo, key, keylen, text, textlen, temp) != len) |
|
1122 return (-1); |
|
1123 |
|
1124 if (memcmp(digest, temp, digestlen) != 0) |
|
1125 return (-1); |
|
1126 else |
|
1127 return (0); |
|
1128 } |
|
1129 |
|
1130 |
|
1131 /* |
|
1132 * computes the requested HMAC using a key struct (which may be modified if |
|
1133 * the keylen exceeds the HMAC block len). |
|
1134 */ |
|
1135 uint32_t |
|
1136 sctp_compute_hmac(uint16_t hmac_algo, sctp_key_t *key, uint8_t *text, |
|
1137 uint32_t textlen, uint8_t *digest) |
|
1138 { |
|
1139 uint32_t digestlen; |
|
1140 uint32_t blocklen; |
|
1141 sctp_hash_context_t ctx; |
|
1142 uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX]; |
|
1143 |
|
1144 /* sanity check */ |
|
1145 if ((key == NULL) || (text == NULL) || (textlen == 0) || |
|
1146 (digest == NULL)) { |
|
1147 /* can't do HMAC with empty key or text or digest store */ |
|
1148 return (0); |
|
1149 } |
|
1150 /* validate the hmac algo and get the digest length */ |
|
1151 digestlen = sctp_get_hmac_digest_len(hmac_algo); |
|
1152 if (digestlen == 0) |
|
1153 return (0); |
|
1154 |
|
1155 /* hash the key if it is longer than the hash block size */ |
|
1156 blocklen = sctp_get_hmac_block_len(hmac_algo); |
|
1157 if (key->keylen > blocklen) { |
|
1158 sctp_hmac_init(hmac_algo, &ctx); |
|
1159 sctp_hmac_update(hmac_algo, &ctx, key->key, key->keylen); |
|
1160 sctp_hmac_final(hmac_algo, &ctx, temp); |
|
1161 /* save the hashed key as the new key */ |
|
1162 key->keylen = digestlen; |
|
1163 bcopy(temp, key->key, key->keylen); |
|
1164 } |
|
1165 return (sctp_hmac(hmac_algo, key->key, key->keylen, text, textlen, |
|
1166 digest)); |
|
1167 } |
|
1168 |
|
1169 /* mbuf version */ |
|
1170 uint32_t |
|
1171 sctp_compute_hmac_m(uint16_t hmac_algo, sctp_key_t *key, struct mbuf *m, |
|
1172 uint32_t m_offset, uint8_t *digest) |
|
1173 { |
|
1174 uint32_t digestlen; |
|
1175 uint32_t blocklen; |
|
1176 sctp_hash_context_t ctx; |
|
1177 uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX]; |
|
1178 |
|
1179 /* sanity check */ |
|
1180 if ((key == NULL) || (m == NULL) || (digest == NULL)) { |
|
1181 /* can't do HMAC with empty key or text or digest store */ |
|
1182 return (0); |
|
1183 } |
|
1184 /* validate the hmac algo and get the digest length */ |
|
1185 digestlen = sctp_get_hmac_digest_len(hmac_algo); |
|
1186 if (digestlen == 0) |
|
1187 return (0); |
|
1188 |
|
1189 /* hash the key if it is longer than the hash block size */ |
|
1190 blocklen = sctp_get_hmac_block_len(hmac_algo); |
|
1191 if (key->keylen > blocklen) { |
|
1192 sctp_hmac_init(hmac_algo, &ctx); |
|
1193 sctp_hmac_update(hmac_algo, &ctx, key->key, key->keylen); |
|
1194 sctp_hmac_final(hmac_algo, &ctx, temp); |
|
1195 /* save the hashed key as the new key */ |
|
1196 key->keylen = digestlen; |
|
1197 bcopy(temp, key->key, key->keylen); |
|
1198 } |
|
1199 return (sctp_hmac_m(hmac_algo, key->key, key->keylen, m, m_offset, digest, 0)); |
|
1200 } |
|
1201 |
|
1202 int |
|
1203 sctp_auth_is_supported_hmac(sctp_hmaclist_t *list, uint16_t id) |
|
1204 { |
|
1205 int i; |
|
1206 |
|
1207 if ((list == NULL) || (id == SCTP_AUTH_HMAC_ID_RSVD)) |
|
1208 return (0); |
|
1209 |
|
1210 for (i = 0; i < list->num_algo; i++) |
|
1211 if (list->hmac[i] == id) |
|
1212 return (1); |
|
1213 |
|
1214 /* not in the list */ |
|
1215 return (0); |
|
1216 } |
|
1217 |
|
1218 |
|
1219 /*- |
|
1220 * clear any cached key(s) if they match the given key id on an association. |
|
1221 * the cached key(s) will be recomputed and re-cached at next use. |
|
1222 * ASSUMES TCB_LOCK is already held |
|
1223 */ |
|
1224 void |
|
1225 sctp_clear_cachedkeys(struct sctp_tcb *stcb, uint16_t keyid) |
|
1226 { |
|
1227 if (stcb == NULL) |
|
1228 return; |
|
1229 |
|
1230 if (keyid == stcb->asoc.authinfo.assoc_keyid) { |
|
1231 sctp_free_key(stcb->asoc.authinfo.assoc_key); |
|
1232 stcb->asoc.authinfo.assoc_key = NULL; |
|
1233 } |
|
1234 if (keyid == stcb->asoc.authinfo.recv_keyid) { |
|
1235 sctp_free_key(stcb->asoc.authinfo.recv_key); |
|
1236 stcb->asoc.authinfo.recv_key = NULL; |
|
1237 } |
|
1238 } |
|
1239 |
|
1240 /*- |
|
1241 * clear any cached key(s) if they match the given key id for all assocs on |
|
1242 * an endpoint. |
|
1243 * ASSUMES INP_WLOCK is already held |
|
1244 */ |
|
1245 void |
|
1246 sctp_clear_cachedkeys_ep(struct sctp_inpcb *inp, uint16_t keyid) |
|
1247 { |
|
1248 struct sctp_tcb *stcb; |
|
1249 |
|
1250 if (inp == NULL) |
|
1251 return; |
|
1252 |
|
1253 /* clear the cached keys on all assocs on this instance */ |
|
1254 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
1255 SCTP_TCB_LOCK(stcb); |
|
1256 sctp_clear_cachedkeys(stcb, keyid); |
|
1257 SCTP_TCB_UNLOCK(stcb); |
|
1258 } |
|
1259 } |
|
1260 |
|
1261 /*- |
|
1262 * delete a shared key from an association |
|
1263 * ASSUMES TCB_LOCK is already held |
|
1264 */ |
|
1265 int |
|
1266 sctp_delete_sharedkey(struct sctp_tcb *stcb, uint16_t keyid) |
|
1267 { |
|
1268 sctp_sharedkey_t *skey; |
|
1269 |
|
1270 if (stcb == NULL) |
|
1271 return (-1); |
|
1272 |
|
1273 /* is the keyid the assoc active sending key */ |
|
1274 if (keyid == stcb->asoc.authinfo.active_keyid) |
|
1275 return (-1); |
|
1276 |
|
1277 /* does the key exist? */ |
|
1278 skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid); |
|
1279 if (skey == NULL) |
|
1280 return (-1); |
|
1281 |
|
1282 /* are there other refcount holders on the key? */ |
|
1283 if (skey->refcount > 1) |
|
1284 return (-1); |
|
1285 |
|
1286 /* remove it */ |
|
1287 LIST_REMOVE(skey, next); |
|
1288 sctp_free_sharedkey(skey); /* frees skey->key as well */ |
|
1289 |
|
1290 /* clear any cached keys */ |
|
1291 sctp_clear_cachedkeys(stcb, keyid); |
|
1292 return (0); |
|
1293 } |
|
1294 |
|
1295 /*- |
|
1296 * deletes a shared key from the endpoint |
|
1297 * ASSUMES INP_WLOCK is already held |
|
1298 */ |
|
1299 int |
|
1300 sctp_delete_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid) |
|
1301 { |
|
1302 sctp_sharedkey_t *skey; |
|
1303 |
|
1304 if (inp == NULL) |
|
1305 return (-1); |
|
1306 |
|
1307 /* is the keyid the active sending key on the endpoint */ |
|
1308 if (keyid == inp->sctp_ep.default_keyid) |
|
1309 return (-1); |
|
1310 |
|
1311 /* does the key exist? */ |
|
1312 skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid); |
|
1313 if (skey == NULL) |
|
1314 return (-1); |
|
1315 |
|
1316 /* endpoint keys are not refcounted */ |
|
1317 |
|
1318 /* remove it */ |
|
1319 LIST_REMOVE(skey, next); |
|
1320 sctp_free_sharedkey(skey); /* frees skey->key as well */ |
|
1321 |
|
1322 /* clear any cached keys */ |
|
1323 sctp_clear_cachedkeys_ep(inp, keyid); |
|
1324 return (0); |
|
1325 } |
|
1326 |
|
1327 /*- |
|
1328 * set the active key on an association |
|
1329 * ASSUMES TCB_LOCK is already held |
|
1330 */ |
|
1331 int |
|
1332 sctp_auth_setactivekey(struct sctp_tcb *stcb, uint16_t keyid) |
|
1333 { |
|
1334 sctp_sharedkey_t *skey = NULL; |
|
1335 |
|
1336 /* find the key on the assoc */ |
|
1337 skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid); |
|
1338 if (skey == NULL) { |
|
1339 /* that key doesn't exist */ |
|
1340 return (-1); |
|
1341 } |
|
1342 if ((skey->deactivated) && (skey->refcount > 1)) { |
|
1343 /* can't reactivate a deactivated key with other refcounts */ |
|
1344 return (-1); |
|
1345 } |
|
1346 |
|
1347 /* set the (new) active key */ |
|
1348 stcb->asoc.authinfo.active_keyid = keyid; |
|
1349 /* reset the deactivated flag */ |
|
1350 skey->deactivated = 0; |
|
1351 |
|
1352 return (0); |
|
1353 } |
|
1354 |
|
1355 /*- |
|
1356 * set the active key on an endpoint |
|
1357 * ASSUMES INP_WLOCK is already held |
|
1358 */ |
|
1359 int |
|
1360 sctp_auth_setactivekey_ep(struct sctp_inpcb *inp, uint16_t keyid) |
|
1361 { |
|
1362 sctp_sharedkey_t *skey; |
|
1363 |
|
1364 /* find the key */ |
|
1365 skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid); |
|
1366 if (skey == NULL) { |
|
1367 /* that key doesn't exist */ |
|
1368 return (-1); |
|
1369 } |
|
1370 inp->sctp_ep.default_keyid = keyid; |
|
1371 return (0); |
|
1372 } |
|
1373 |
|
1374 /*- |
|
1375 * deactivates a shared key from the association |
|
1376 * ASSUMES INP_WLOCK is already held |
|
1377 */ |
|
1378 int |
|
1379 sctp_deact_sharedkey(struct sctp_tcb *stcb, uint16_t keyid) |
|
1380 { |
|
1381 sctp_sharedkey_t *skey; |
|
1382 |
|
1383 if (stcb == NULL) |
|
1384 return (-1); |
|
1385 |
|
1386 /* is the keyid the assoc active sending key */ |
|
1387 if (keyid == stcb->asoc.authinfo.active_keyid) |
|
1388 return (-1); |
|
1389 |
|
1390 /* does the key exist? */ |
|
1391 skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid); |
|
1392 if (skey == NULL) |
|
1393 return (-1); |
|
1394 |
|
1395 /* are there other refcount holders on the key? */ |
|
1396 if (skey->refcount == 1) { |
|
1397 /* no other users, send a notification for this key */ |
|
1398 sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb, keyid, 0, |
|
1399 SCTP_SO_LOCKED); |
|
1400 } |
|
1401 |
|
1402 /* mark the key as deactivated */ |
|
1403 skey->deactivated = 1; |
|
1404 |
|
1405 return (0); |
|
1406 } |
|
1407 |
|
1408 /*- |
|
1409 * deactivates a shared key from the endpoint |
|
1410 * ASSUMES INP_WLOCK is already held |
|
1411 */ |
|
1412 int |
|
1413 sctp_deact_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid) |
|
1414 { |
|
1415 sctp_sharedkey_t *skey; |
|
1416 |
|
1417 if (inp == NULL) |
|
1418 return (-1); |
|
1419 |
|
1420 /* is the keyid the active sending key on the endpoint */ |
|
1421 if (keyid == inp->sctp_ep.default_keyid) |
|
1422 return (-1); |
|
1423 |
|
1424 /* does the key exist? */ |
|
1425 skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid); |
|
1426 if (skey == NULL) |
|
1427 return (-1); |
|
1428 |
|
1429 /* endpoint keys are not refcounted */ |
|
1430 |
|
1431 /* remove it */ |
|
1432 LIST_REMOVE(skey, next); |
|
1433 sctp_free_sharedkey(skey); /* frees skey->key as well */ |
|
1434 |
|
1435 return (0); |
|
1436 } |
|
1437 |
|
1438 /* |
|
1439 * get local authentication parameters from cookie (from INIT-ACK) |
|
1440 */ |
|
1441 void |
|
1442 sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, |
|
1443 uint32_t offset, uint32_t length) |
|
1444 { |
|
1445 struct sctp_paramhdr *phdr, tmp_param; |
|
1446 uint16_t plen, ptype; |
|
1447 uint8_t random_store[SCTP_PARAM_BUFFER_SIZE]; |
|
1448 struct sctp_auth_random *p_random = NULL; |
|
1449 uint16_t random_len = 0; |
|
1450 uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE]; |
|
1451 struct sctp_auth_hmac_algo *hmacs = NULL; |
|
1452 uint16_t hmacs_len = 0; |
|
1453 uint8_t chunks_store[SCTP_PARAM_BUFFER_SIZE]; |
|
1454 struct sctp_auth_chunk_list *chunks = NULL; |
|
1455 uint16_t num_chunks = 0; |
|
1456 sctp_key_t *new_key; |
|
1457 uint32_t keylen; |
|
1458 |
|
1459 /* convert to upper bound */ |
|
1460 length += offset; |
|
1461 |
|
1462 phdr = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, |
|
1463 sizeof(struct sctp_paramhdr), (uint8_t *)&tmp_param); |
|
1464 while (phdr != NULL) { |
|
1465 ptype = ntohs(phdr->param_type); |
|
1466 plen = ntohs(phdr->param_length); |
|
1467 |
|
1468 if ((plen == 0) || (offset + plen > length)) |
|
1469 break; |
|
1470 |
|
1471 if (ptype == SCTP_RANDOM) { |
|
1472 if (plen > sizeof(random_store)) |
|
1473 break; |
|
1474 phdr = sctp_get_next_param(m, offset, |
|
1475 (struct sctp_paramhdr *)random_store, min(plen, sizeof(random_store))); |
|
1476 if (phdr == NULL) |
|
1477 return; |
|
1478 /* save the random and length for the key */ |
|
1479 p_random = (struct sctp_auth_random *)phdr; |
|
1480 random_len = plen - sizeof(*p_random); |
|
1481 } else if (ptype == SCTP_HMAC_LIST) { |
|
1482 int num_hmacs; |
|
1483 int i; |
|
1484 |
|
1485 if (plen > sizeof(hmacs_store)) |
|
1486 break; |
|
1487 phdr = sctp_get_next_param(m, offset, |
|
1488 (struct sctp_paramhdr *)hmacs_store, min(plen,sizeof(hmacs_store))); |
|
1489 if (phdr == NULL) |
|
1490 return; |
|
1491 /* save the hmacs list and num for the key */ |
|
1492 hmacs = (struct sctp_auth_hmac_algo *)phdr; |
|
1493 hmacs_len = plen - sizeof(*hmacs); |
|
1494 num_hmacs = hmacs_len / sizeof(hmacs->hmac_ids[0]); |
|
1495 if (stcb->asoc.local_hmacs != NULL) |
|
1496 sctp_free_hmaclist(stcb->asoc.local_hmacs); |
|
1497 stcb->asoc.local_hmacs = sctp_alloc_hmaclist(num_hmacs); |
|
1498 if (stcb->asoc.local_hmacs != NULL) { |
|
1499 for (i = 0; i < num_hmacs; i++) { |
|
1500 (void)sctp_auth_add_hmacid(stcb->asoc.local_hmacs, |
|
1501 ntohs(hmacs->hmac_ids[i])); |
|
1502 } |
|
1503 } |
|
1504 } else if (ptype == SCTP_CHUNK_LIST) { |
|
1505 int i; |
|
1506 |
|
1507 if (plen > sizeof(chunks_store)) |
|
1508 break; |
|
1509 phdr = sctp_get_next_param(m, offset, |
|
1510 (struct sctp_paramhdr *)chunks_store, min(plen,sizeof(chunks_store))); |
|
1511 if (phdr == NULL) |
|
1512 return; |
|
1513 chunks = (struct sctp_auth_chunk_list *)phdr; |
|
1514 num_chunks = plen - sizeof(*chunks); |
|
1515 /* save chunks list and num for the key */ |
|
1516 if (stcb->asoc.local_auth_chunks != NULL) |
|
1517 sctp_clear_chunklist(stcb->asoc.local_auth_chunks); |
|
1518 else |
|
1519 stcb->asoc.local_auth_chunks = sctp_alloc_chunklist(); |
|
1520 for (i = 0; i < num_chunks; i++) { |
|
1521 (void)sctp_auth_add_chunk(chunks->chunk_types[i], |
|
1522 stcb->asoc.local_auth_chunks); |
|
1523 } |
|
1524 } |
|
1525 /* get next parameter */ |
|
1526 offset += SCTP_SIZE32(plen); |
|
1527 if (offset + sizeof(struct sctp_paramhdr) > length) |
|
1528 break; |
|
1529 phdr = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), |
|
1530 (uint8_t *)&tmp_param); |
|
1531 } |
|
1532 /* concatenate the full random key */ |
|
1533 keylen = sizeof(*p_random) + random_len + sizeof(*hmacs) + hmacs_len; |
|
1534 if (chunks != NULL) { |
|
1535 keylen += sizeof(*chunks) + num_chunks; |
|
1536 } |
|
1537 new_key = sctp_alloc_key(keylen); |
|
1538 if (new_key != NULL) { |
|
1539 /* copy in the RANDOM */ |
|
1540 if (p_random != NULL) { |
|
1541 keylen = sizeof(*p_random) + random_len; |
|
1542 bcopy(p_random, new_key->key, keylen); |
|
1543 } |
|
1544 /* append in the AUTH chunks */ |
|
1545 if (chunks != NULL) { |
|
1546 bcopy(chunks, new_key->key + keylen, |
|
1547 sizeof(*chunks) + num_chunks); |
|
1548 keylen += sizeof(*chunks) + num_chunks; |
|
1549 } |
|
1550 /* append in the HMACs */ |
|
1551 if (hmacs != NULL) { |
|
1552 bcopy(hmacs, new_key->key + keylen, |
|
1553 sizeof(*hmacs) + hmacs_len); |
|
1554 } |
|
1555 } |
|
1556 if (stcb->asoc.authinfo.random != NULL) |
|
1557 sctp_free_key(stcb->asoc.authinfo.random); |
|
1558 stcb->asoc.authinfo.random = new_key; |
|
1559 stcb->asoc.authinfo.random_len = random_len; |
|
1560 sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.assoc_keyid); |
|
1561 sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.recv_keyid); |
|
1562 |
|
1563 /* negotiate what HMAC to use for the peer */ |
|
1564 stcb->asoc.peer_hmac_id = sctp_negotiate_hmacid(stcb->asoc.peer_hmacs, |
|
1565 stcb->asoc.local_hmacs); |
|
1566 |
|
1567 /* copy defaults from the endpoint */ |
|
1568 /* FIX ME: put in cookie? */ |
|
1569 stcb->asoc.authinfo.active_keyid = stcb->sctp_ep->sctp_ep.default_keyid; |
|
1570 /* copy out the shared key list (by reference) from the endpoint */ |
|
1571 (void)sctp_copy_skeylist(&stcb->sctp_ep->sctp_ep.shared_keys, |
|
1572 &stcb->asoc.shared_keys); |
|
1573 } |
|
1574 |
|
1575 /* |
|
1576 * compute and fill in the HMAC digest for a packet |
|
1577 */ |
|
1578 void |
|
1579 sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset, |
|
1580 struct sctp_auth_chunk *auth, struct sctp_tcb *stcb, uint16_t keyid) |
|
1581 { |
|
1582 uint32_t digestlen; |
|
1583 sctp_sharedkey_t *skey; |
|
1584 sctp_key_t *key; |
|
1585 |
|
1586 if ((stcb == NULL) || (auth == NULL)) |
|
1587 return; |
|
1588 |
|
1589 /* zero the digest + chunk padding */ |
|
1590 digestlen = sctp_get_hmac_digest_len(stcb->asoc.peer_hmac_id); |
|
1591 bzero(auth->hmac, SCTP_SIZE32(digestlen)); |
|
1592 |
|
1593 /* is the desired key cached? */ |
|
1594 if ((keyid != stcb->asoc.authinfo.assoc_keyid) || |
|
1595 (stcb->asoc.authinfo.assoc_key == NULL)) { |
|
1596 if (stcb->asoc.authinfo.assoc_key != NULL) { |
|
1597 /* free the old cached key */ |
|
1598 sctp_free_key(stcb->asoc.authinfo.assoc_key); |
|
1599 } |
|
1600 skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid); |
|
1601 /* the only way skey is NULL is if null key id 0 is used */ |
|
1602 if (skey != NULL) |
|
1603 key = skey->key; |
|
1604 else |
|
1605 key = NULL; |
|
1606 /* compute a new assoc key and cache it */ |
|
1607 stcb->asoc.authinfo.assoc_key = |
|
1608 sctp_compute_hashkey(stcb->asoc.authinfo.random, |
|
1609 stcb->asoc.authinfo.peer_random, key); |
|
1610 stcb->asoc.authinfo.assoc_keyid = keyid; |
|
1611 SCTPDBG(SCTP_DEBUG_AUTH1, "caching key id %u\n", |
|
1612 stcb->asoc.authinfo.assoc_keyid); |
|
1613 #ifdef SCTP_DEBUG |
|
1614 if (SCTP_AUTH_DEBUG) |
|
1615 sctp_print_key(stcb->asoc.authinfo.assoc_key, |
|
1616 "Assoc Key"); |
|
1617 #endif |
|
1618 } |
|
1619 |
|
1620 /* set in the active key id */ |
|
1621 auth->shared_key_id = htons(keyid); |
|
1622 |
|
1623 /* compute and fill in the digest */ |
|
1624 (void)sctp_compute_hmac_m(stcb->asoc.peer_hmac_id, stcb->asoc.authinfo.assoc_key, |
|
1625 m, auth_offset, auth->hmac); |
|
1626 } |
|
1627 |
|
1628 |
|
1629 static void |
|
1630 sctp_bzero_m(struct mbuf *m, uint32_t m_offset, uint32_t size) |
|
1631 { |
|
1632 struct mbuf *m_tmp; |
|
1633 uint8_t *data; |
|
1634 |
|
1635 /* sanity check */ |
|
1636 if (m == NULL) |
|
1637 return; |
|
1638 |
|
1639 /* find the correct starting mbuf and offset (get start position) */ |
|
1640 m_tmp = m; |
|
1641 while ((m_tmp != NULL) && (m_offset >= (uint32_t) SCTP_BUF_LEN(m_tmp))) { |
|
1642 m_offset -= SCTP_BUF_LEN(m_tmp); |
|
1643 m_tmp = SCTP_BUF_NEXT(m_tmp); |
|
1644 } |
|
1645 /* now use the rest of the mbuf chain */ |
|
1646 while ((m_tmp != NULL) && (size > 0)) { |
|
1647 data = mtod(m_tmp, uint8_t *) + m_offset; |
|
1648 if (size > (uint32_t) SCTP_BUF_LEN(m_tmp)) { |
|
1649 bzero(data, SCTP_BUF_LEN(m_tmp)); |
|
1650 size -= SCTP_BUF_LEN(m_tmp); |
|
1651 } else { |
|
1652 bzero(data, size); |
|
1653 size = 0; |
|
1654 } |
|
1655 /* clear the offset since it's only for the first mbuf */ |
|
1656 m_offset = 0; |
|
1657 m_tmp = SCTP_BUF_NEXT(m_tmp); |
|
1658 } |
|
1659 } |
|
1660 |
|
1661 /*- |
|
1662 * process the incoming Authentication chunk |
|
1663 * return codes: |
|
1664 * -1 on any authentication error |
|
1665 * 0 on authentication verification |
|
1666 */ |
|
1667 int |
|
1668 sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth, |
|
1669 struct mbuf *m, uint32_t offset) |
|
1670 { |
|
1671 uint16_t chunklen; |
|
1672 uint16_t shared_key_id; |
|
1673 uint16_t hmac_id; |
|
1674 sctp_sharedkey_t *skey; |
|
1675 uint32_t digestlen; |
|
1676 uint8_t digest[SCTP_AUTH_DIGEST_LEN_MAX]; |
|
1677 uint8_t computed_digest[SCTP_AUTH_DIGEST_LEN_MAX]; |
|
1678 |
|
1679 /* auth is checked for NULL by caller */ |
|
1680 chunklen = ntohs(auth->ch.chunk_length); |
|
1681 if (chunklen < sizeof(*auth)) { |
|
1682 SCTP_STAT_INCR(sctps_recvauthfailed); |
|
1683 return (-1); |
|
1684 } |
|
1685 SCTP_STAT_INCR(sctps_recvauth); |
|
1686 |
|
1687 /* get the auth params */ |
|
1688 shared_key_id = ntohs(auth->shared_key_id); |
|
1689 hmac_id = ntohs(auth->hmac_id); |
|
1690 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
1691 "SCTP AUTH Chunk: shared key %u, HMAC id %u\n", |
|
1692 shared_key_id, hmac_id); |
|
1693 |
|
1694 /* is the indicated HMAC supported? */ |
|
1695 if (!sctp_auth_is_supported_hmac(stcb->asoc.local_hmacs, hmac_id)) { |
|
1696 struct mbuf *m_err; |
|
1697 struct sctp_auth_invalid_hmac *err; |
|
1698 |
|
1699 SCTP_STAT_INCR(sctps_recvivalhmacid); |
|
1700 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
1701 "SCTP Auth: unsupported HMAC id %u\n", |
|
1702 hmac_id); |
|
1703 /* |
|
1704 * report this in an Error Chunk: Unsupported HMAC |
|
1705 * Identifier |
|
1706 */ |
|
1707 m_err = sctp_get_mbuf_for_msg(sizeof(*err), 0, M_NOWAIT, |
|
1708 1, MT_HEADER); |
|
1709 if (m_err != NULL) { |
|
1710 /* pre-reserve some space */ |
|
1711 SCTP_BUF_RESV_UF(m_err, sizeof(struct sctp_chunkhdr)); |
|
1712 /* fill in the error */ |
|
1713 err = mtod(m_err, struct sctp_auth_invalid_hmac *); |
|
1714 bzero(err, sizeof(*err)); |
|
1715 err->ph.param_type = htons(SCTP_CAUSE_UNSUPPORTED_HMACID); |
|
1716 err->ph.param_length = htons(sizeof(*err)); |
|
1717 err->hmac_id = ntohs(hmac_id); |
|
1718 SCTP_BUF_LEN(m_err) = sizeof(*err); |
|
1719 /* queue it */ |
|
1720 sctp_queue_op_err(stcb, m_err); |
|
1721 } |
|
1722 return (-1); |
|
1723 } |
|
1724 /* get the indicated shared key, if available */ |
|
1725 if ((stcb->asoc.authinfo.recv_key == NULL) || |
|
1726 (stcb->asoc.authinfo.recv_keyid != shared_key_id)) { |
|
1727 /* find the shared key on the assoc first */ |
|
1728 skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, |
|
1729 shared_key_id); |
|
1730 /* if the shared key isn't found, discard the chunk */ |
|
1731 if (skey == NULL) { |
|
1732 SCTP_STAT_INCR(sctps_recvivalkeyid); |
|
1733 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
1734 "SCTP Auth: unknown key id %u\n", |
|
1735 shared_key_id); |
|
1736 return (-1); |
|
1737 } |
|
1738 /* generate a notification if this is a new key id */ |
|
1739 if (stcb->asoc.authinfo.recv_keyid != shared_key_id) |
|
1740 /* |
|
1741 * sctp_ulp_notify(SCTP_NOTIFY_AUTH_NEW_KEY, stcb, |
|
1742 * shared_key_id, (void |
|
1743 * *)stcb->asoc.authinfo.recv_keyid); |
|
1744 */ |
|
1745 sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, |
|
1746 shared_key_id, stcb->asoc.authinfo.recv_keyid, |
|
1747 SCTP_SO_NOT_LOCKED); |
|
1748 /* compute a new recv assoc key and cache it */ |
|
1749 if (stcb->asoc.authinfo.recv_key != NULL) |
|
1750 sctp_free_key(stcb->asoc.authinfo.recv_key); |
|
1751 stcb->asoc.authinfo.recv_key = |
|
1752 sctp_compute_hashkey(stcb->asoc.authinfo.random, |
|
1753 stcb->asoc.authinfo.peer_random, skey->key); |
|
1754 stcb->asoc.authinfo.recv_keyid = shared_key_id; |
|
1755 #ifdef SCTP_DEBUG |
|
1756 if (SCTP_AUTH_DEBUG) |
|
1757 sctp_print_key(stcb->asoc.authinfo.recv_key, "Recv Key"); |
|
1758 #endif |
|
1759 } |
|
1760 /* validate the digest length */ |
|
1761 digestlen = sctp_get_hmac_digest_len(hmac_id); |
|
1762 if (chunklen < (sizeof(*auth) + digestlen)) { |
|
1763 /* invalid digest length */ |
|
1764 SCTP_STAT_INCR(sctps_recvauthfailed); |
|
1765 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
1766 "SCTP Auth: chunk too short for HMAC\n"); |
|
1767 return (-1); |
|
1768 } |
|
1769 /* save a copy of the digest, zero the pseudo header, and validate */ |
|
1770 bcopy(auth->hmac, digest, digestlen); |
|
1771 sctp_bzero_m(m, offset + sizeof(*auth), SCTP_SIZE32(digestlen)); |
|
1772 (void)sctp_compute_hmac_m(hmac_id, stcb->asoc.authinfo.recv_key, |
|
1773 m, offset, computed_digest); |
|
1774 |
|
1775 /* compare the computed digest with the one in the AUTH chunk */ |
|
1776 if (memcmp(digest, computed_digest, digestlen) != 0) { |
|
1777 SCTP_STAT_INCR(sctps_recvauthfailed); |
|
1778 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
1779 "SCTP Auth: HMAC digest check failed\n"); |
|
1780 return (-1); |
|
1781 } |
|
1782 return (0); |
|
1783 } |
|
1784 |
|
1785 /* |
|
1786 * Generate NOTIFICATION |
|
1787 */ |
|
1788 void |
|
1789 sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication, |
|
1790 uint16_t keyid, uint16_t alt_keyid, int so_locked |
|
1791 #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) |
|
1792 SCTP_UNUSED |
|
1793 #endif |
|
1794 ) |
|
1795 { |
|
1796 struct mbuf *m_notify; |
|
1797 struct sctp_authkey_event *auth; |
|
1798 struct sctp_queued_to_read *control; |
|
1799 |
|
1800 if ((stcb == NULL) || |
|
1801 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || |
|
1802 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || |
|
1803 (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) |
|
1804 ) { |
|
1805 /* If the socket is gone we are out of here */ |
|
1806 return; |
|
1807 } |
|
1808 |
|
1809 if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_AUTHEVNT)) |
|
1810 /* event not enabled */ |
|
1811 return; |
|
1812 |
|
1813 m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_authkey_event), |
|
1814 0, M_NOWAIT, 1, MT_HEADER); |
|
1815 if (m_notify == NULL) |
|
1816 /* no space left */ |
|
1817 return; |
|
1818 |
|
1819 SCTP_BUF_LEN(m_notify) = 0; |
|
1820 auth = mtod(m_notify, struct sctp_authkey_event *); |
|
1821 auth->auth_type = SCTP_AUTHENTICATION_EVENT; |
|
1822 auth->auth_flags = 0; |
|
1823 auth->auth_length = sizeof(*auth); |
|
1824 auth->auth_keynumber = keyid; |
|
1825 auth->auth_altkeynumber = alt_keyid; |
|
1826 auth->auth_indication = indication; |
|
1827 auth->auth_assoc_id = sctp_get_associd(stcb); |
|
1828 |
|
1829 SCTP_BUF_LEN(m_notify) = sizeof(*auth); |
|
1830 SCTP_BUF_NEXT(m_notify) = NULL; |
|
1831 |
|
1832 /* append to socket */ |
|
1833 control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, |
|
1834 0, 0, stcb->asoc.context, 0, 0, 0, m_notify); |
|
1835 if (control == NULL) { |
|
1836 /* no memory */ |
|
1837 sctp_m_freem(m_notify); |
|
1838 return; |
|
1839 } |
|
1840 control->spec_flags = M_NOTIFICATION; |
|
1841 control->length = SCTP_BUF_LEN(m_notify); |
|
1842 /* not that we need this */ |
|
1843 control->tail_mbuf = m_notify; |
|
1844 sctp_add_to_readq(stcb->sctp_ep, stcb, control, |
|
1845 &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); |
|
1846 } |
|
1847 |
|
1848 |
|
1849 /*- |
|
1850 * validates the AUTHentication related parameters in an INIT/INIT-ACK |
|
1851 * Note: currently only used for INIT as INIT-ACK is handled inline |
|
1852 * with sctp_load_addresses_from_init() |
|
1853 */ |
|
1854 int |
|
1855 sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit) |
|
1856 { |
|
1857 struct sctp_paramhdr *phdr, parm_buf; |
|
1858 uint16_t ptype, plen; |
|
1859 int peer_supports_asconf = 0; |
|
1860 int peer_supports_auth = 0; |
|
1861 int got_random = 0, got_hmacs = 0, got_chklist = 0; |
|
1862 uint8_t saw_asconf = 0; |
|
1863 uint8_t saw_asconf_ack = 0; |
|
1864 |
|
1865 /* go through each of the params. */ |
|
1866 phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf)); |
|
1867 while (phdr) { |
|
1868 ptype = ntohs(phdr->param_type); |
|
1869 plen = ntohs(phdr->param_length); |
|
1870 |
|
1871 if (offset + plen > limit) { |
|
1872 break; |
|
1873 } |
|
1874 if (plen < sizeof(struct sctp_paramhdr)) { |
|
1875 break; |
|
1876 } |
|
1877 if (ptype == SCTP_SUPPORTED_CHUNK_EXT) { |
|
1878 /* A supported extension chunk */ |
|
1879 struct sctp_supported_chunk_types_param *pr_supported; |
|
1880 uint8_t local_store[SCTP_PARAM_BUFFER_SIZE]; |
|
1881 int num_ent, i; |
|
1882 |
|
1883 phdr = sctp_get_next_param(m, offset, |
|
1884 (struct sctp_paramhdr *)&local_store, min(plen,sizeof(local_store))); |
|
1885 if (phdr == NULL) { |
|
1886 return (-1); |
|
1887 } |
|
1888 pr_supported = (struct sctp_supported_chunk_types_param *)phdr; |
|
1889 num_ent = plen - sizeof(struct sctp_paramhdr); |
|
1890 for (i = 0; i < num_ent; i++) { |
|
1891 switch (pr_supported->chunk_types[i]) { |
|
1892 case SCTP_ASCONF: |
|
1893 case SCTP_ASCONF_ACK: |
|
1894 peer_supports_asconf = 1; |
|
1895 break; |
|
1896 default: |
|
1897 /* one we don't care about */ |
|
1898 break; |
|
1899 } |
|
1900 } |
|
1901 } else if (ptype == SCTP_RANDOM) { |
|
1902 got_random = 1; |
|
1903 /* enforce the random length */ |
|
1904 if (plen != (sizeof(struct sctp_auth_random) + |
|
1905 SCTP_AUTH_RANDOM_SIZE_REQUIRED)) { |
|
1906 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
1907 "SCTP: invalid RANDOM len\n"); |
|
1908 return (-1); |
|
1909 } |
|
1910 } else if (ptype == SCTP_HMAC_LIST) { |
|
1911 uint8_t store[SCTP_PARAM_BUFFER_SIZE]; |
|
1912 struct sctp_auth_hmac_algo *hmacs; |
|
1913 int num_hmacs; |
|
1914 |
|
1915 if (plen > sizeof(store)) |
|
1916 break; |
|
1917 phdr = sctp_get_next_param(m, offset, |
|
1918 (struct sctp_paramhdr *)store, min(plen,sizeof(store))); |
|
1919 if (phdr == NULL) |
|
1920 return (-1); |
|
1921 hmacs = (struct sctp_auth_hmac_algo *)phdr; |
|
1922 num_hmacs = (plen - sizeof(*hmacs)) / |
|
1923 sizeof(hmacs->hmac_ids[0]); |
|
1924 /* validate the hmac list */ |
|
1925 if (sctp_verify_hmac_param(hmacs, num_hmacs)) { |
|
1926 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
1927 "SCTP: invalid HMAC param\n"); |
|
1928 return (-1); |
|
1929 } |
|
1930 got_hmacs = 1; |
|
1931 } else if (ptype == SCTP_CHUNK_LIST) { |
|
1932 int i, num_chunks; |
|
1933 uint8_t chunks_store[SCTP_SMALL_CHUNK_STORE]; |
|
1934 /* did the peer send a non-empty chunk list? */ |
|
1935 struct sctp_auth_chunk_list *chunks = NULL; |
|
1936 phdr = sctp_get_next_param(m, offset, |
|
1937 (struct sctp_paramhdr *)chunks_store, |
|
1938 min(plen,sizeof(chunks_store))); |
|
1939 if (phdr == NULL) |
|
1940 return (-1); |
|
1941 |
|
1942 /*- |
|
1943 * Flip through the list and mark that the |
|
1944 * peer supports asconf/asconf_ack. |
|
1945 */ |
|
1946 chunks = (struct sctp_auth_chunk_list *)phdr; |
|
1947 num_chunks = plen - sizeof(*chunks); |
|
1948 for (i = 0; i < num_chunks; i++) { |
|
1949 /* record asconf/asconf-ack if listed */ |
|
1950 if (chunks->chunk_types[i] == SCTP_ASCONF) |
|
1951 saw_asconf = 1; |
|
1952 if (chunks->chunk_types[i] == SCTP_ASCONF_ACK) |
|
1953 saw_asconf_ack = 1; |
|
1954 |
|
1955 } |
|
1956 if (num_chunks) |
|
1957 got_chklist = 1; |
|
1958 } |
|
1959 |
|
1960 offset += SCTP_SIZE32(plen); |
|
1961 if (offset >= limit) { |
|
1962 break; |
|
1963 } |
|
1964 phdr = sctp_get_next_param(m, offset, &parm_buf, |
|
1965 sizeof(parm_buf)); |
|
1966 } |
|
1967 /* validate authentication required parameters */ |
|
1968 if (got_random && got_hmacs) { |
|
1969 peer_supports_auth = 1; |
|
1970 } else { |
|
1971 peer_supports_auth = 0; |
|
1972 } |
|
1973 if (!peer_supports_auth && got_chklist) { |
|
1974 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
1975 "SCTP: peer sent chunk list w/o AUTH\n"); |
|
1976 return (-1); |
|
1977 } |
|
1978 if (!SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk) && peer_supports_asconf && |
|
1979 !peer_supports_auth) { |
|
1980 SCTPDBG(SCTP_DEBUG_AUTH1, |
|
1981 "SCTP: peer supports ASCONF but not AUTH\n"); |
|
1982 return (-1); |
|
1983 } else if ((peer_supports_asconf) && (peer_supports_auth) && |
|
1984 ((saw_asconf == 0) || (saw_asconf_ack == 0))) { |
|
1985 return (-2); |
|
1986 } |
|
1987 return (0); |
|
1988 } |
|
1989 |
|
1990 void |
|
1991 sctp_initialize_auth_params(struct sctp_inpcb *inp, struct sctp_tcb *stcb) |
|
1992 { |
|
1993 uint16_t chunks_len = 0; |
|
1994 uint16_t hmacs_len = 0; |
|
1995 uint16_t random_len = SCTP_AUTH_RANDOM_SIZE_DEFAULT; |
|
1996 sctp_key_t *new_key; |
|
1997 uint16_t keylen; |
|
1998 |
|
1999 /* initialize hmac list from endpoint */ |
|
2000 stcb->asoc.local_hmacs = sctp_copy_hmaclist(inp->sctp_ep.local_hmacs); |
|
2001 if (stcb->asoc.local_hmacs != NULL) { |
|
2002 hmacs_len = stcb->asoc.local_hmacs->num_algo * |
|
2003 sizeof(stcb->asoc.local_hmacs->hmac[0]); |
|
2004 } |
|
2005 /* initialize auth chunks list from endpoint */ |
|
2006 stcb->asoc.local_auth_chunks = |
|
2007 sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks); |
|
2008 if (stcb->asoc.local_auth_chunks != NULL) { |
|
2009 int i; |
|
2010 for (i = 0; i < 256; i++) { |
|
2011 if (stcb->asoc.local_auth_chunks->chunks[i]) |
|
2012 chunks_len++; |
|
2013 } |
|
2014 } |
|
2015 /* copy defaults from the endpoint */ |
|
2016 stcb->asoc.authinfo.active_keyid = inp->sctp_ep.default_keyid; |
|
2017 |
|
2018 /* copy out the shared key list (by reference) from the endpoint */ |
|
2019 (void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys, |
|
2020 &stcb->asoc.shared_keys); |
|
2021 |
|
2022 /* now set the concatenated key (random + chunks + hmacs) */ |
|
2023 /* key includes parameter headers */ |
|
2024 keylen = (3 * sizeof(struct sctp_paramhdr)) + random_len + chunks_len + |
|
2025 hmacs_len; |
|
2026 new_key = sctp_alloc_key(keylen); |
|
2027 if (new_key != NULL) { |
|
2028 struct sctp_paramhdr *ph; |
|
2029 int plen; |
|
2030 /* generate and copy in the RANDOM */ |
|
2031 ph = (struct sctp_paramhdr *)new_key->key; |
|
2032 ph->param_type = htons(SCTP_RANDOM); |
|
2033 plen = sizeof(*ph) + random_len; |
|
2034 ph->param_length = htons(plen); |
|
2035 SCTP_READ_RANDOM(new_key->key + sizeof(*ph), random_len); |
|
2036 keylen = plen; |
|
2037 |
|
2038 /* append in the AUTH chunks */ |
|
2039 /* NOTE: currently we always have chunks to list */ |
|
2040 ph = (struct sctp_paramhdr *)(new_key->key + keylen); |
|
2041 ph->param_type = htons(SCTP_CHUNK_LIST); |
|
2042 plen = sizeof(*ph) + chunks_len; |
|
2043 ph->param_length = htons(plen); |
|
2044 keylen += sizeof(*ph); |
|
2045 if (stcb->asoc.local_auth_chunks) { |
|
2046 int i; |
|
2047 for (i = 0; i < 256; i++) { |
|
2048 if (stcb->asoc.local_auth_chunks->chunks[i]) |
|
2049 new_key->key[keylen++] = i; |
|
2050 } |
|
2051 } |
|
2052 |
|
2053 /* append in the HMACs */ |
|
2054 ph = (struct sctp_paramhdr *)(new_key->key + keylen); |
|
2055 ph->param_type = htons(SCTP_HMAC_LIST); |
|
2056 plen = sizeof(*ph) + hmacs_len; |
|
2057 ph->param_length = htons(plen); |
|
2058 keylen += sizeof(*ph); |
|
2059 (void)sctp_serialize_hmaclist(stcb->asoc.local_hmacs, |
|
2060 new_key->key + keylen); |
|
2061 } |
|
2062 if (stcb->asoc.authinfo.random != NULL) |
|
2063 sctp_free_key(stcb->asoc.authinfo.random); |
|
2064 stcb->asoc.authinfo.random = new_key; |
|
2065 stcb->asoc.authinfo.random_len = random_len; |
|
2066 } |
|
2067 |
|
2068 |
|
2069 #ifdef SCTP_HMAC_TEST |
|
2070 /* |
|
2071 * HMAC and key concatenation tests |
|
2072 */ |
|
2073 static void |
|
2074 sctp_print_digest(uint8_t *digest, uint32_t digestlen, const char *str) |
|
2075 { |
|
2076 uint32_t i; |
|
2077 |
|
2078 SCTP_PRINTF("\n%s: 0x", str); |
|
2079 if (digest == NULL) |
|
2080 return; |
|
2081 |
|
2082 for (i = 0; i < digestlen; i++) |
|
2083 SCTP_PRINTF("%02x", digest[i]); |
|
2084 } |
|
2085 |
|
2086 static int |
|
2087 sctp_test_hmac(const char *str, uint16_t hmac_id, uint8_t *key, |
|
2088 uint32_t keylen, uint8_t *text, uint32_t textlen, |
|
2089 uint8_t *digest, uint32_t digestlen) |
|
2090 { |
|
2091 uint8_t computed_digest[SCTP_AUTH_DIGEST_LEN_MAX]; |
|
2092 |
|
2093 SCTP_PRINTF("\n%s:", str); |
|
2094 sctp_hmac(hmac_id, key, keylen, text, textlen, computed_digest); |
|
2095 sctp_print_digest(digest, digestlen, "Expected digest"); |
|
2096 sctp_print_digest(computed_digest, digestlen, "Computed digest"); |
|
2097 if (memcmp(digest, computed_digest, digestlen) != 0) { |
|
2098 SCTP_PRINTF("\nFAILED"); |
|
2099 return (-1); |
|
2100 } else { |
|
2101 SCTP_PRINTF("\nPASSED"); |
|
2102 return (0); |
|
2103 } |
|
2104 } |
|
2105 |
|
2106 |
|
2107 /* |
|
2108 * RFC 2202: HMAC-SHA1 test cases |
|
2109 */ |
|
2110 void |
|
2111 sctp_test_hmac_sha1(void) |
|
2112 { |
|
2113 uint8_t *digest; |
|
2114 uint8_t key[128]; |
|
2115 uint32_t keylen; |
|
2116 uint8_t text[128]; |
|
2117 uint32_t textlen; |
|
2118 uint32_t digestlen = 20; |
|
2119 int failed = 0; |
|
2120 |
|
2121 /*- |
|
2122 * test_case = 1 |
|
2123 * key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b |
|
2124 * key_len = 20 |
|
2125 * data = "Hi There" |
|
2126 * data_len = 8 |
|
2127 * digest = 0xb617318655057264e28bc0b6fb378c8ef146be00 |
|
2128 */ |
|
2129 keylen = 20; |
|
2130 memset(key, 0x0b, keylen); |
|
2131 textlen = 8; |
|
2132 strcpy(text, "Hi There"); |
|
2133 digest = "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00"; |
|
2134 if (sctp_test_hmac("SHA1 test case 1", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, |
|
2135 text, textlen, digest, digestlen) < 0) |
|
2136 failed++; |
|
2137 |
|
2138 /*- |
|
2139 * test_case = 2 |
|
2140 * key = "Jefe" |
|
2141 * key_len = 4 |
|
2142 * data = "what do ya want for nothing?" |
|
2143 * data_len = 28 |
|
2144 * digest = 0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79 |
|
2145 */ |
|
2146 keylen = 4; |
|
2147 strcpy(key, "Jefe"); |
|
2148 textlen = 28; |
|
2149 strcpy(text, "what do ya want for nothing?"); |
|
2150 digest = "\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79"; |
|
2151 if (sctp_test_hmac("SHA1 test case 2", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, |
|
2152 text, textlen, digest, digestlen) < 0) |
|
2153 failed++; |
|
2154 |
|
2155 /*- |
|
2156 * test_case = 3 |
|
2157 * key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
|
2158 * key_len = 20 |
|
2159 * data = 0xdd repeated 50 times |
|
2160 * data_len = 50 |
|
2161 * digest = 0x125d7342b9ac11cd91a39af48aa17b4f63f175d3 |
|
2162 */ |
|
2163 keylen = 20; |
|
2164 memset(key, 0xaa, keylen); |
|
2165 textlen = 50; |
|
2166 memset(text, 0xdd, textlen); |
|
2167 digest = "\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3"; |
|
2168 if (sctp_test_hmac("SHA1 test case 3", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, |
|
2169 text, textlen, digest, digestlen) < 0) |
|
2170 failed++; |
|
2171 |
|
2172 /*- |
|
2173 * test_case = 4 |
|
2174 * key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819 |
|
2175 * key_len = 25 |
|
2176 * data = 0xcd repeated 50 times |
|
2177 * data_len = 50 |
|
2178 * digest = 0x4c9007f4026250c6bc8414f9bf50c86c2d7235da |
|
2179 */ |
|
2180 keylen = 25; |
|
2181 memcpy(key, "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", keylen); |
|
2182 textlen = 50; |
|
2183 memset(text, 0xcd, textlen); |
|
2184 digest = "\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda"; |
|
2185 if (sctp_test_hmac("SHA1 test case 4", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, |
|
2186 text, textlen, digest, digestlen) < 0) |
|
2187 failed++; |
|
2188 |
|
2189 /*- |
|
2190 * test_case = 5 |
|
2191 * key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c |
|
2192 * key_len = 20 |
|
2193 * data = "Test With Truncation" |
|
2194 * data_len = 20 |
|
2195 * digest = 0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04 |
|
2196 * digest-96 = 0x4c1a03424b55e07fe7f27be1 |
|
2197 */ |
|
2198 keylen = 20; |
|
2199 memset(key, 0x0c, keylen); |
|
2200 textlen = 20; |
|
2201 strcpy(text, "Test With Truncation"); |
|
2202 digest = "\x4c\x1a\x03\x42\x4b\x55\xe0\x7f\xe7\xf2\x7b\xe1\xd5\x8b\xb9\x32\x4a\x9a\x5a\x04"; |
|
2203 if (sctp_test_hmac("SHA1 test case 5", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, |
|
2204 text, textlen, digest, digestlen) < 0) |
|
2205 failed++; |
|
2206 |
|
2207 /*- |
|
2208 * test_case = 6 |
|
2209 * key = 0xaa repeated 80 times |
|
2210 * key_len = 80 |
|
2211 * data = "Test Using Larger Than Block-Size Key - Hash Key First" |
|
2212 * data_len = 54 |
|
2213 * digest = 0xaa4ae5e15272d00e95705637ce8a3b55ed402112 |
|
2214 */ |
|
2215 keylen = 80; |
|
2216 memset(key, 0xaa, keylen); |
|
2217 textlen = 54; |
|
2218 strcpy(text, "Test Using Larger Than Block-Size Key - Hash Key First"); |
|
2219 digest = "\xaa\x4a\xe5\xe1\x52\x72\xd0\x0e\x95\x70\x56\x37\xce\x8a\x3b\x55\xed\x40\x21\x12"; |
|
2220 if (sctp_test_hmac("SHA1 test case 6", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, |
|
2221 text, textlen, digest, digestlen) < 0) |
|
2222 failed++; |
|
2223 |
|
2224 /*- |
|
2225 * test_case = 7 |
|
2226 * key = 0xaa repeated 80 times |
|
2227 * key_len = 80 |
|
2228 * data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" |
|
2229 * data_len = 73 |
|
2230 * digest = 0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91 |
|
2231 */ |
|
2232 keylen = 80; |
|
2233 memset(key, 0xaa, keylen); |
|
2234 textlen = 73; |
|
2235 strcpy(text, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"); |
|
2236 digest = "\xe8\xe9\x9d\x0f\x45\x23\x7d\x78\x6d\x6b\xba\xa7\x96\x5c\x78\x08\xbb\xff\x1a\x91"; |
|
2237 if (sctp_test_hmac("SHA1 test case 7", SCTP_AUTH_HMAC_ID_SHA1, key, keylen, |
|
2238 text, textlen, digest, digestlen) < 0) |
|
2239 failed++; |
|
2240 |
|
2241 /* done with all tests */ |
|
2242 if (failed) |
|
2243 SCTP_PRINTF("\nSHA1 test results: %d cases failed", failed); |
|
2244 else |
|
2245 SCTP_PRINTF("\nSHA1 test results: all test cases passed"); |
|
2246 } |
|
2247 |
|
2248 /* |
|
2249 * test assoc key concatenation |
|
2250 */ |
|
2251 static int |
|
2252 sctp_test_key_concatenation(sctp_key_t *key1, sctp_key_t *key2, |
|
2253 sctp_key_t *expected_key) |
|
2254 { |
|
2255 sctp_key_t *key; |
|
2256 int ret_val; |
|
2257 |
|
2258 sctp_show_key(key1, "\nkey1"); |
|
2259 sctp_show_key(key2, "\nkey2"); |
|
2260 key = sctp_compute_hashkey(key1, key2, NULL); |
|
2261 sctp_show_key(expected_key, "\nExpected"); |
|
2262 sctp_show_key(key, "\nComputed"); |
|
2263 if (memcmp(key, expected_key, expected_key->keylen) != 0) { |
|
2264 SCTP_PRINTF("\nFAILED"); |
|
2265 ret_val = -1; |
|
2266 } else { |
|
2267 SCTP_PRINTF("\nPASSED"); |
|
2268 ret_val = 0; |
|
2269 } |
|
2270 sctp_free_key(key1); |
|
2271 sctp_free_key(key2); |
|
2272 sctp_free_key(expected_key); |
|
2273 sctp_free_key(key); |
|
2274 return (ret_val); |
|
2275 } |
|
2276 |
|
2277 |
|
2278 void |
|
2279 sctp_test_authkey(void) |
|
2280 { |
|
2281 sctp_key_t *key1, *key2, *expected_key; |
|
2282 int failed = 0; |
|
2283 |
|
2284 /* test case 1 */ |
|
2285 key1 = sctp_set_key("\x01\x01\x01\x01", 4); |
|
2286 key2 = sctp_set_key("\x01\x02\x03\x04", 4); |
|
2287 expected_key = sctp_set_key("\x01\x01\x01\x01\x01\x02\x03\x04", 8); |
|
2288 if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) |
|
2289 failed++; |
|
2290 |
|
2291 /* test case 2 */ |
|
2292 key1 = sctp_set_key("\x00\x00\x00\x01", 4); |
|
2293 key2 = sctp_set_key("\x02", 1); |
|
2294 expected_key = sctp_set_key("\x00\x00\x00\x01\x02", 5); |
|
2295 if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) |
|
2296 failed++; |
|
2297 |
|
2298 /* test case 3 */ |
|
2299 key1 = sctp_set_key("\x01", 1); |
|
2300 key2 = sctp_set_key("\x00\x00\x00\x02", 4); |
|
2301 expected_key = sctp_set_key("\x01\x00\x00\x00\x02", 5); |
|
2302 if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) |
|
2303 failed++; |
|
2304 |
|
2305 /* test case 4 */ |
|
2306 key1 = sctp_set_key("\x00\x00\x00\x01", 4); |
|
2307 key2 = sctp_set_key("\x01", 1); |
|
2308 expected_key = sctp_set_key("\x01\x00\x00\x00\x01", 5); |
|
2309 if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) |
|
2310 failed++; |
|
2311 |
|
2312 /* test case 5 */ |
|
2313 key1 = sctp_set_key("\x01", 1); |
|
2314 key2 = sctp_set_key("\x00\x00\x00\x01", 4); |
|
2315 expected_key = sctp_set_key("\x01\x00\x00\x00\x01", 5); |
|
2316 if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) |
|
2317 failed++; |
|
2318 |
|
2319 /* test case 6 */ |
|
2320 key1 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07", 11); |
|
2321 key2 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x08", 11); |
|
2322 expected_key = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x08", 22); |
|
2323 if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) |
|
2324 failed++; |
|
2325 |
|
2326 /* test case 7 */ |
|
2327 key1 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x08", 11); |
|
2328 key2 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07", 11); |
|
2329 expected_key = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x08", 22); |
|
2330 if (sctp_test_key_concatenation(key1, key2, expected_key) < 0) |
|
2331 failed++; |
|
2332 |
|
2333 /* done with all tests */ |
|
2334 if (failed) |
|
2335 SCTP_PRINTF("\nKey concatenation test results: %d cases failed", failed); |
|
2336 else |
|
2337 SCTP_PRINTF("\nKey concatenation test results: all test cases passed"); |
|
2338 } |
|
2339 |
|
2340 |
|
2341 #if defined(STANDALONE_HMAC_TEST) |
|
2342 int |
|
2343 main(void) |
|
2344 { |
|
2345 sctp_test_hmac_sha1(); |
|
2346 sctp_test_authkey(); |
|
2347 } |
|
2348 |
|
2349 #endif /* STANDALONE_HMAC_TEST */ |
|
2350 |
|
2351 #endif /* SCTP_HMAC_TEST */ |