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