1163953Srrs/*-
2185694Srrs * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4235828Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5163953Srrs *
6163953Srrs * Redistribution and use in source and binary forms, with or without
7163953Srrs * modification, are permitted provided that the following conditions are met:
8163953Srrs *
9163953Srrs * a) Redistributions of source code must retain the above copyright notice,
10228653Stuexen *    this list of conditions and the following disclaimer.
11163953Srrs *
12163953Srrs * b) Redistributions in binary form must reproduce the above copyright
13163953Srrs *    notice, this list of conditions and the following disclaimer in
14228653Stuexen *    the documentation and/or other materials provided with the distribution.
15163953Srrs *
16163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
17163953Srrs *    contributors may be used to endorse or promote products derived
18163953Srrs *    from this software without specific prior written permission.
19163953Srrs *
20163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30163953Srrs * THE POSSIBILITY OF SUCH DAMAGE.
31163953Srrs */
32163953Srrs
33163953Srrs#include <sys/cdefs.h>
34163953Srrs__FBSDID("$FreeBSD$");
35163953Srrs
36163953Srrs#include <netinet/sctp_os.h>
37163953Srrs#include <netinet/sctp.h>
38163953Srrs#include <netinet/sctp_header.h>
39163953Srrs#include <netinet/sctp_pcb.h>
40163953Srrs#include <netinet/sctp_var.h>
41167598Srrs#include <netinet/sctp_sysctl.h>
42163953Srrs#include <netinet/sctputil.h>
43163953Srrs#include <netinet/sctp_indata.h>
44163953Srrs#include <netinet/sctp_output.h>
45163953Srrs#include <netinet/sctp_auth.h>
46163953Srrs
47163953Srrs#ifdef SCTP_DEBUG
48179783Srrs#define SCTP_AUTH_DEBUG		(SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_AUTH1)
49179783Srrs#define SCTP_AUTH_DEBUG2	(SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_AUTH2)
50163953Srrs#endif				/* SCTP_DEBUG */
51163953Srrs
52163953Srrs
53170806Srrsvoid
54163953Srrssctp_clear_chunklist(sctp_auth_chklist_t * chklist)
55163953Srrs{
56163953Srrs	bzero(chklist, sizeof(*chklist));
57163953Srrs	/* chklist->num_chunks = 0; */
58163953Srrs}
59163953Srrs
60163953Srrssctp_auth_chklist_t *
61163953Srrssctp_alloc_chunklist(void)
62163953Srrs{
63163953Srrs	sctp_auth_chklist_t *chklist;
64163953Srrs
65163953Srrs	SCTP_MALLOC(chklist, sctp_auth_chklist_t *, sizeof(*chklist),
66170091Srrs	    SCTP_M_AUTH_CL);
67163953Srrs	if (chklist == NULL) {
68169420Srrs		SCTPDBG(SCTP_DEBUG_AUTH1, "sctp_alloc_chunklist: failed to get memory!\n");
69163953Srrs	} else {
70163953Srrs		sctp_clear_chunklist(chklist);
71163953Srrs	}
72163953Srrs	return (chklist);
73163953Srrs}
74163953Srrs
75163953Srrsvoid
76163953Srrssctp_free_chunklist(sctp_auth_chklist_t * list)
77163953Srrs{
78163953Srrs	if (list != NULL)
79170091Srrs		SCTP_FREE(list, SCTP_M_AUTH_CL);
80163953Srrs}
81163953Srrs
82163953Srrssctp_auth_chklist_t *
83163953Srrssctp_copy_chunklist(sctp_auth_chklist_t * list)
84163953Srrs{
85163953Srrs	sctp_auth_chklist_t *new_list;
86163953Srrs
87163953Srrs	if (list == NULL)
88163953Srrs		return (NULL);
89163953Srrs
90163953Srrs	/* get a new list */
91163953Srrs	new_list = sctp_alloc_chunklist();
92163953Srrs	if (new_list == NULL)
93163953Srrs		return (NULL);
94163953Srrs	/* copy it */
95163953Srrs	bcopy(list, new_list, sizeof(*new_list));
96163953Srrs
97163953Srrs	return (new_list);
98163953Srrs}
99163953Srrs
100163953Srrs
101163953Srrs/*
102163953Srrs * add a chunk to the required chunks list
103163953Srrs */
104163953Srrsint
105163953Srrssctp_auth_add_chunk(uint8_t chunk, sctp_auth_chklist_t * list)
106163953Srrs{
107163953Srrs	if (list == NULL)
108163953Srrs		return (-1);
109163953Srrs
110163953Srrs	/* is chunk restricted? */
111163953Srrs	if ((chunk == SCTP_INITIATION) ||
112163953Srrs	    (chunk == SCTP_INITIATION_ACK) ||
113163953Srrs	    (chunk == SCTP_SHUTDOWN_COMPLETE) ||
114163953Srrs	    (chunk == SCTP_AUTHENTICATION)) {
115163953Srrs		return (-1);
116163953Srrs	}
117163953Srrs	if (list->chunks[chunk] == 0) {
118163953Srrs		list->chunks[chunk] = 1;
119163953Srrs		list->num_chunks++;
120169420Srrs		SCTPDBG(SCTP_DEBUG_AUTH1,
121169420Srrs		    "SCTP: added chunk %u (0x%02x) to Auth list\n",
122169420Srrs		    chunk, chunk);
123163953Srrs	}
124163953Srrs	return (0);
125163953Srrs}
126163953Srrs
127163953Srrs/*
128163953Srrs * delete a chunk from the required chunks list
129163953Srrs */
130163953Srrsint
131163953Srrssctp_auth_delete_chunk(uint8_t chunk, sctp_auth_chklist_t * list)
132163953Srrs{
133163953Srrs	if (list == NULL)
134163953Srrs		return (-1);
135163953Srrs
136163953Srrs	if (list->chunks[chunk] == 1) {
137163953Srrs		list->chunks[chunk] = 0;
138163953Srrs		list->num_chunks--;
139169420Srrs		SCTPDBG(SCTP_DEBUG_AUTH1,
140169420Srrs		    "SCTP: deleted chunk %u (0x%02x) from Auth list\n",
141169420Srrs		    chunk, chunk);
142163953Srrs	}
143163953Srrs	return (0);
144163953Srrs}
145163953Srrs
146170806Srrssize_t
147163953Srrssctp_auth_get_chklist_size(const sctp_auth_chklist_t * list)
148163953Srrs{
149163953Srrs	if (list == NULL)
150163953Srrs		return (0);
151163953Srrs	else
152163953Srrs		return (list->num_chunks);
153163953Srrs}
154163953Srrs
155163953Srrs/*
156163953Srrs * return the current number and list of required chunks caller must
157163953Srrs * guarantee ptr has space for up to 256 bytes
158163953Srrs */
159163953Srrsint
160163953Srrssctp_serialize_auth_chunks(const sctp_auth_chklist_t * list, uint8_t * ptr)
161163953Srrs{
162163953Srrs	int i, count = 0;
163163953Srrs
164163953Srrs	if (list == NULL)
165163953Srrs		return (0);
166163953Srrs
167163953Srrs	for (i = 0; i < 256; i++) {
168163953Srrs		if (list->chunks[i] != 0) {
169163953Srrs			*ptr++ = i;
170163953Srrs			count++;
171163953Srrs		}
172163953Srrs	}
173163953Srrs	return (count);
174163953Srrs}
175163953Srrs
176163953Srrsint
177163953Srrssctp_pack_auth_chunks(const sctp_auth_chklist_t * list, uint8_t * ptr)
178163953Srrs{
179163953Srrs	int i, size = 0;
180163953Srrs
181163953Srrs	if (list == NULL)
182163953Srrs		return (0);
183163953Srrs
184163953Srrs	if (list->num_chunks <= 32) {
185163953Srrs		/* just list them, one byte each */
186163953Srrs		for (i = 0; i < 256; i++) {
187163953Srrs			if (list->chunks[i] != 0) {
188163953Srrs				*ptr++ = i;
189163953Srrs				size++;
190163953Srrs			}
191163953Srrs		}
192163953Srrs	} else {
193163953Srrs		int index, offset;
194163953Srrs
195163953Srrs		/* pack into a 32 byte bitfield */
196163953Srrs		for (i = 0; i < 256; i++) {
197163953Srrs			if (list->chunks[i] != 0) {
198163953Srrs				index = i / 8;
199163953Srrs				offset = i % 8;
200163953Srrs				ptr[index] |= (1 << offset);
201163953Srrs			}
202163953Srrs		}
203163953Srrs		size = 32;
204163953Srrs	}
205163953Srrs	return (size);
206163953Srrs}
207163953Srrs
208163953Srrsint
209163953Srrssctp_unpack_auth_chunks(const uint8_t * ptr, uint8_t num_chunks,
210163953Srrs    sctp_auth_chklist_t * list)
211163953Srrs{
212163953Srrs	int i;
213163953Srrs	int size;
214163953Srrs
215163953Srrs	if (list == NULL)
216163953Srrs		return (0);
217163953Srrs
218163953Srrs	if (num_chunks <= 32) {
219163953Srrs		/* just pull them, one byte each */
220163953Srrs		for (i = 0; i < num_chunks; i++) {
221169378Srrs			(void)sctp_auth_add_chunk(*ptr++, list);
222163953Srrs		}
223163953Srrs		size = num_chunks;
224163953Srrs	} else {
225163953Srrs		int index, offset;
226163953Srrs
227163953Srrs		/* unpack from a 32 byte bitfield */
228163953Srrs		for (index = 0; index < 32; index++) {
229163953Srrs			for (offset = 0; offset < 8; offset++) {
230163953Srrs				if (ptr[index] & (1 << offset)) {
231169378Srrs					(void)sctp_auth_add_chunk((index * 8) + offset, list);
232163953Srrs				}
233163953Srrs			}
234163953Srrs		}
235163953Srrs		size = 32;
236163953Srrs	}
237163953Srrs	return (size);
238163953Srrs}
239163953Srrs
240163953Srrs
241163953Srrs/*
242163953Srrs * allocate structure space for a key of length keylen
243163953Srrs */
244163953Srrssctp_key_t *
245163953Srrssctp_alloc_key(uint32_t keylen)
246163953Srrs{
247163953Srrs	sctp_key_t *new_key;
248163953Srrs
249163953Srrs	SCTP_MALLOC(new_key, sctp_key_t *, sizeof(*new_key) + keylen,
250170091Srrs	    SCTP_M_AUTH_KY);
251163953Srrs	if (new_key == NULL) {
252163953Srrs		/* out of memory */
253163953Srrs		return (NULL);
254163953Srrs	}
255163953Srrs	new_key->keylen = keylen;
256163953Srrs	return (new_key);
257163953Srrs}
258163953Srrs
259163953Srrsvoid
260163953Srrssctp_free_key(sctp_key_t * key)
261163953Srrs{
262163953Srrs	if (key != NULL)
263170091Srrs		SCTP_FREE(key, SCTP_M_AUTH_KY);
264163953Srrs}
265163953Srrs
266163953Srrsvoid
267163953Srrssctp_print_key(sctp_key_t * key, const char *str)
268163953Srrs{
269163953Srrs	uint32_t i;
270163953Srrs
271163953Srrs	if (key == NULL) {
272234995Stuexen		SCTP_PRINTF("%s: [Null key]\n", str);
273163953Srrs		return;
274163953Srrs	}
275234995Stuexen	SCTP_PRINTF("%s: len %u, ", str, key->keylen);
276163953Srrs	if (key->keylen) {
277163953Srrs		for (i = 0; i < key->keylen; i++)
278234995Stuexen			SCTP_PRINTF("%02x", key->key[i]);
279234995Stuexen		SCTP_PRINTF("\n");
280163953Srrs	} else {
281234995Stuexen		SCTP_PRINTF("[Null key]\n");
282163953Srrs	}
283163953Srrs}
284163953Srrs
285163953Srrsvoid
286163953Srrssctp_show_key(sctp_key_t * key, const char *str)
287163953Srrs{
288163953Srrs	uint32_t i;
289163953Srrs
290163953Srrs	if (key == NULL) {
291234995Stuexen		SCTP_PRINTF("%s: [Null key]\n", str);
292163953Srrs		return;
293163953Srrs	}
294234995Stuexen	SCTP_PRINTF("%s: len %u, ", str, key->keylen);
295163953Srrs	if (key->keylen) {
296163953Srrs		for (i = 0; i < key->keylen; i++)
297234995Stuexen			SCTP_PRINTF("%02x", key->key[i]);
298234995Stuexen		SCTP_PRINTF("\n");
299163953Srrs	} else {
300234995Stuexen		SCTP_PRINTF("[Null key]\n");
301163953Srrs	}
302163953Srrs}
303163953Srrs
304170806Srrsstatic uint32_t
305163953Srrssctp_get_keylen(sctp_key_t * key)
306163953Srrs{
307163953Srrs	if (key != NULL)
308163953Srrs		return (key->keylen);
309163953Srrs	else
310163953Srrs		return (0);
311163953Srrs}
312163953Srrs
313163953Srrs/*
314163953Srrs * generate a new random key of length 'keylen'
315163953Srrs */
316163953Srrssctp_key_t *
317163953Srrssctp_generate_random_key(uint32_t keylen)
318163953Srrs{
319163953Srrs	sctp_key_t *new_key;
320163953Srrs
321163953Srrs	new_key = sctp_alloc_key(keylen);
322163953Srrs	if (new_key == NULL) {
323163953Srrs		/* out of memory */
324163953Srrs		return (NULL);
325163953Srrs	}
326165647Srrs	SCTP_READ_RANDOM(new_key->key, keylen);
327163953Srrs	new_key->keylen = keylen;
328163953Srrs	return (new_key);
329163953Srrs}
330163953Srrs
331163953Srrssctp_key_t *
332163953Srrssctp_set_key(uint8_t * key, uint32_t keylen)
333163953Srrs{
334163953Srrs	sctp_key_t *new_key;
335163953Srrs
336163953Srrs	new_key = sctp_alloc_key(keylen);
337163953Srrs	if (new_key == NULL) {
338163953Srrs		/* out of memory */
339163953Srrs		return (NULL);
340163953Srrs	}
341163953Srrs	bcopy(key, new_key->key, keylen);
342163953Srrs	return (new_key);
343163953Srrs}
344163953Srrs
345185694Srrs/*-
346163953Srrs * given two keys of variable size, compute which key is "larger/smaller"
347185694Srrs * returns:  1 if key1 > key2
348185694Srrs *          -1 if key1 < key2
349185694Srrs *           0 if key1 = key2
350163953Srrs */
351163953Srrsstatic int
352163953Srrssctp_compare_key(sctp_key_t * key1, sctp_key_t * key2)
353163953Srrs{
354163953Srrs	uint32_t maxlen;
355163953Srrs	uint32_t i;
356163953Srrs	uint32_t key1len, key2len;
357163953Srrs	uint8_t *key_1, *key_2;
358258454Stuexen	uint8_t val1, val2;
359163953Srrs
360163953Srrs	/* sanity/length check */
361163953Srrs	key1len = sctp_get_keylen(key1);
362163953Srrs	key2len = sctp_get_keylen(key2);
363163953Srrs	if ((key1len == 0) && (key2len == 0))
364163953Srrs		return (0);
365163953Srrs	else if (key1len == 0)
366163953Srrs		return (-1);
367163953Srrs	else if (key2len == 0)
368163953Srrs		return (1);
369163953Srrs
370258454Stuexen	if (key1len < key2len) {
371258454Stuexen		maxlen = key2len;
372163953Srrs	} else {
373163953Srrs		maxlen = key1len;
374163953Srrs	}
375258454Stuexen	key_1 = key1->key;
376258454Stuexen	key_2 = key2->key;
377258454Stuexen	/* check for numeric equality */
378163953Srrs	for (i = 0; i < maxlen; i++) {
379258454Stuexen		/* left-pad with zeros */
380258454Stuexen		val1 = (i < (maxlen - key1len)) ? 0 : *(key_1++);
381258454Stuexen		val2 = (i < (maxlen - key2len)) ? 0 : *(key_2++);
382258454Stuexen		if (val1 > val2) {
383163953Srrs			return (1);
384258454Stuexen		} else if (val1 < val2) {
385163953Srrs			return (-1);
386258454Stuexen		}
387163953Srrs	}
388163953Srrs	/* keys are equal value, so check lengths */
389163953Srrs	if (key1len == key2len)
390163953Srrs		return (0);
391163953Srrs	else if (key1len < key2len)
392163953Srrs		return (-1);
393163953Srrs	else
394163953Srrs		return (1);
395163953Srrs}
396163953Srrs
397163953Srrs/*
398163953Srrs * generate the concatenated keying material based on the two keys and the
399163953Srrs * shared key (if available). draft-ietf-tsvwg-auth specifies the specific
400163953Srrs * order for concatenation
401163953Srrs */
402163953Srrssctp_key_t *
403163953Srrssctp_compute_hashkey(sctp_key_t * key1, sctp_key_t * key2, sctp_key_t * shared)
404163953Srrs{
405163953Srrs	uint32_t keylen;
406163953Srrs	sctp_key_t *new_key;
407163953Srrs	uint8_t *key_ptr;
408163953Srrs
409163953Srrs	keylen = sctp_get_keylen(key1) + sctp_get_keylen(key2) +
410163953Srrs	    sctp_get_keylen(shared);
411163953Srrs
412163953Srrs	if (keylen > 0) {
413163953Srrs		/* get space for the new key */
414163953Srrs		new_key = sctp_alloc_key(keylen);
415163953Srrs		if (new_key == NULL) {
416163953Srrs			/* out of memory */
417163953Srrs			return (NULL);
418163953Srrs		}
419163953Srrs		new_key->keylen = keylen;
420163953Srrs		key_ptr = new_key->key;
421163953Srrs	} else {
422163953Srrs		/* all keys empty/null?! */
423163953Srrs		return (NULL);
424163953Srrs	}
425163953Srrs
426163953Srrs	/* concatenate the keys */
427163953Srrs	if (sctp_compare_key(key1, key2) <= 0) {
428171990Srrs		/* key is shared + key1 + key2 */
429171990Srrs		if (sctp_get_keylen(shared)) {
430171990Srrs			bcopy(shared->key, key_ptr, shared->keylen);
431171990Srrs			key_ptr += shared->keylen;
432171990Srrs		}
433171990Srrs		if (sctp_get_keylen(key1)) {
434171990Srrs			bcopy(key1->key, key_ptr, key1->keylen);
435171990Srrs			key_ptr += key1->keylen;
436171990Srrs		}
437171990Srrs		if (sctp_get_keylen(key2)) {
438171990Srrs			bcopy(key2->key, key_ptr, key2->keylen);
439171990Srrs		}
440163953Srrs	} else {
441171990Srrs		/* key is shared + key2 + key1 */
442171990Srrs		if (sctp_get_keylen(shared)) {
443171990Srrs			bcopy(shared->key, key_ptr, shared->keylen);
444171990Srrs			key_ptr += shared->keylen;
445171990Srrs		}
446171990Srrs		if (sctp_get_keylen(key2)) {
447171990Srrs			bcopy(key2->key, key_ptr, key2->keylen);
448171990Srrs			key_ptr += key2->keylen;
449171990Srrs		}
450171990Srrs		if (sctp_get_keylen(key1)) {
451171990Srrs			bcopy(key1->key, key_ptr, key1->keylen);
452171990Srrs		}
453163953Srrs	}
454163953Srrs	return (new_key);
455163953Srrs}
456163953Srrs
457163953Srrs
458163953Srrssctp_sharedkey_t *
459163953Srrssctp_alloc_sharedkey(void)
460163953Srrs{
461163953Srrs	sctp_sharedkey_t *new_key;
462163953Srrs
463163953Srrs	SCTP_MALLOC(new_key, sctp_sharedkey_t *, sizeof(*new_key),
464170091Srrs	    SCTP_M_AUTH_KY);
465163953Srrs	if (new_key == NULL) {
466163953Srrs		/* out of memory */
467163953Srrs		return (NULL);
468163953Srrs	}
469163953Srrs	new_key->keyid = 0;
470163953Srrs	new_key->key = NULL;
471185694Srrs	new_key->refcount = 1;
472185694Srrs	new_key->deactivated = 0;
473163953Srrs	return (new_key);
474163953Srrs}
475163953Srrs
476163953Srrsvoid
477163953Srrssctp_free_sharedkey(sctp_sharedkey_t * skey)
478163953Srrs{
479185694Srrs	if (skey == NULL)
480185694Srrs		return;
481185694Srrs
482185694Srrs	if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&skey->refcount)) {
483163953Srrs		if (skey->key != NULL)
484163953Srrs			sctp_free_key(skey->key);
485170091Srrs		SCTP_FREE(skey, SCTP_M_AUTH_KY);
486163953Srrs	}
487163953Srrs}
488163953Srrs
489163953Srrssctp_sharedkey_t *
490163953Srrssctp_find_sharedkey(struct sctp_keyhead *shared_keys, uint16_t key_id)
491163953Srrs{
492163953Srrs	sctp_sharedkey_t *skey;
493163953Srrs
494163953Srrs	LIST_FOREACH(skey, shared_keys, next) {
495163953Srrs		if (skey->keyid == key_id)
496163953Srrs			return (skey);
497163953Srrs	}
498163953Srrs	return (NULL);
499163953Srrs}
500163953Srrs
501185694Srrsint
502163953Srrssctp_insert_sharedkey(struct sctp_keyhead *shared_keys,
503163953Srrs    sctp_sharedkey_t * new_skey)
504163953Srrs{
505163953Srrs	sctp_sharedkey_t *skey;
506163953Srrs
507163953Srrs	if ((shared_keys == NULL) || (new_skey == NULL))
508185694Srrs		return (EINVAL);
509163953Srrs
510163953Srrs	/* insert into an empty list? */
511199437Stuexen	if (LIST_EMPTY(shared_keys)) {
512163953Srrs		LIST_INSERT_HEAD(shared_keys, new_skey, next);
513185694Srrs		return (0);
514163953Srrs	}
515163953Srrs	/* insert into the existing list, ordered by key id */
516163953Srrs	LIST_FOREACH(skey, shared_keys, next) {
517163953Srrs		if (new_skey->keyid < skey->keyid) {
518163953Srrs			/* insert it before here */
519163953Srrs			LIST_INSERT_BEFORE(skey, new_skey, next);
520185694Srrs			return (0);
521163953Srrs		} else if (new_skey->keyid == skey->keyid) {
522163953Srrs			/* replace the existing key */
523185694Srrs			/* verify this key *can* be replaced */
524185694Srrs			if ((skey->deactivated) && (skey->refcount > 1)) {
525185694Srrs				SCTPDBG(SCTP_DEBUG_AUTH1,
526185694Srrs				    "can't replace shared key id %u\n",
527185694Srrs				    new_skey->keyid);
528185694Srrs				return (EBUSY);
529185694Srrs			}
530169420Srrs			SCTPDBG(SCTP_DEBUG_AUTH1,
531169420Srrs			    "replacing shared key id %u\n",
532169420Srrs			    new_skey->keyid);
533163953Srrs			LIST_INSERT_BEFORE(skey, new_skey, next);
534163953Srrs			LIST_REMOVE(skey, next);
535163953Srrs			sctp_free_sharedkey(skey);
536185694Srrs			return (0);
537163953Srrs		}
538163953Srrs		if (LIST_NEXT(skey, next) == NULL) {
539163953Srrs			/* belongs at the end of the list */
540163953Srrs			LIST_INSERT_AFTER(skey, new_skey, next);
541185694Srrs			return (0);
542163953Srrs		}
543163953Srrs	}
544185694Srrs	/* shouldn't reach here */
545185694Srrs	return (0);
546163953Srrs}
547163953Srrs
548185694Srrsvoid
549185694Srrssctp_auth_key_acquire(struct sctp_tcb *stcb, uint16_t key_id)
550185694Srrs{
551185694Srrs	sctp_sharedkey_t *skey;
552185694Srrs
553185694Srrs	/* find the shared key */
554185694Srrs	skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, key_id);
555185694Srrs
556185694Srrs	/* bump the ref count */
557185694Srrs	if (skey) {
558185694Srrs		atomic_add_int(&skey->refcount, 1);
559185694Srrs		SCTPDBG(SCTP_DEBUG_AUTH2,
560185694Srrs		    "%s: stcb %p key %u refcount acquire to %d\n",
561240148Stuexen		    __FUNCTION__, (void *)stcb, key_id, skey->refcount);
562185694Srrs	}
563185694Srrs}
564185694Srrs
565185694Srrsvoid
566221627Stuexensctp_auth_key_release(struct sctp_tcb *stcb, uint16_t key_id, int so_locked
567221627Stuexen#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
568221627Stuexen    SCTP_UNUSED
569221627Stuexen#endif
570221627Stuexen)
571185694Srrs{
572185694Srrs	sctp_sharedkey_t *skey;
573185694Srrs
574185694Srrs	/* find the shared key */
575185694Srrs	skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, key_id);
576185694Srrs
577185694Srrs	/* decrement the ref count */
578185694Srrs	if (skey) {
579185694Srrs		sctp_free_sharedkey(skey);
580185694Srrs		SCTPDBG(SCTP_DEBUG_AUTH2,
581185694Srrs		    "%s: stcb %p key %u refcount release to %d\n",
582240148Stuexen		    __FUNCTION__, (void *)stcb, key_id, skey->refcount);
583185694Srrs
584185694Srrs		/* see if a notification should be generated */
585185694Srrs		if ((skey->refcount <= 1) && (skey->deactivated)) {
586185694Srrs			/* notify ULP that key is no longer used */
587185694Srrs			sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb,
588221627Stuexen			    key_id, 0, so_locked);
589185694Srrs			SCTPDBG(SCTP_DEBUG_AUTH2,
590185694Srrs			    "%s: stcb %p key %u no longer used, %d\n",
591240148Stuexen			    __FUNCTION__, (void *)stcb, key_id, skey->refcount);
592185694Srrs		}
593185694Srrs	}
594185694Srrs}
595185694Srrs
596163953Srrsstatic sctp_sharedkey_t *
597163953Srrssctp_copy_sharedkey(const sctp_sharedkey_t * skey)
598163953Srrs{
599163953Srrs	sctp_sharedkey_t *new_skey;
600163953Srrs
601163953Srrs	if (skey == NULL)
602163953Srrs		return (NULL);
603163953Srrs	new_skey = sctp_alloc_sharedkey();
604163953Srrs	if (new_skey == NULL)
605163953Srrs		return (NULL);
606163953Srrs	if (skey->key != NULL)
607163953Srrs		new_skey->key = sctp_set_key(skey->key->key, skey->key->keylen);
608163953Srrs	else
609163953Srrs		new_skey->key = NULL;
610163953Srrs	new_skey->keyid = skey->keyid;
611163953Srrs	return (new_skey);
612163953Srrs}
613163953Srrs
614163953Srrsint
615163953Srrssctp_copy_skeylist(const struct sctp_keyhead *src, struct sctp_keyhead *dest)
616163953Srrs{
617163953Srrs	sctp_sharedkey_t *skey, *new_skey;
618163953Srrs	int count = 0;
619163953Srrs
620163953Srrs	if ((src == NULL) || (dest == NULL))
621163953Srrs		return (0);
622163953Srrs	LIST_FOREACH(skey, src, next) {
623163953Srrs		new_skey = sctp_copy_sharedkey(skey);
624163953Srrs		if (new_skey != NULL) {
625185694Srrs			(void)sctp_insert_sharedkey(dest, new_skey);
626163953Srrs			count++;
627163953Srrs		}
628163953Srrs	}
629163953Srrs	return (count);
630163953Srrs}
631163953Srrs
632163953Srrs
633163953Srrssctp_hmaclist_t *
634271750Stuexensctp_alloc_hmaclist(uint16_t num_hmacs)
635163953Srrs{
636163953Srrs	sctp_hmaclist_t *new_list;
637163953Srrs	int alloc_size;
638163953Srrs
639163953Srrs	alloc_size = sizeof(*new_list) + num_hmacs * sizeof(new_list->hmac[0]);
640163953Srrs	SCTP_MALLOC(new_list, sctp_hmaclist_t *, alloc_size,
641170091Srrs	    SCTP_M_AUTH_HL);
642163953Srrs	if (new_list == NULL) {
643163953Srrs		/* out of memory */
644163953Srrs		return (NULL);
645163953Srrs	}
646163953Srrs	new_list->max_algo = num_hmacs;
647163953Srrs	new_list->num_algo = 0;
648163953Srrs	return (new_list);
649163953Srrs}
650163953Srrs
651163953Srrsvoid
652163953Srrssctp_free_hmaclist(sctp_hmaclist_t * list)
653163953Srrs{
654163953Srrs	if (list != NULL) {
655170091Srrs		SCTP_FREE(list, SCTP_M_AUTH_HL);
656163953Srrs		list = NULL;
657163953Srrs	}
658163953Srrs}
659163953Srrs
660163953Srrsint
661163953Srrssctp_auth_add_hmacid(sctp_hmaclist_t * list, uint16_t hmac_id)
662163953Srrs{
663170056Srrs	int i;
664170056Srrs
665163953Srrs	if (list == NULL)
666163953Srrs		return (-1);
667163953Srrs	if (list->num_algo == list->max_algo) {
668169420Srrs		SCTPDBG(SCTP_DEBUG_AUTH1,
669169420Srrs		    "SCTP: HMAC id list full, ignoring add %u\n", hmac_id);
670163953Srrs		return (-1);
671163953Srrs	}
672163953Srrs	if ((hmac_id != SCTP_AUTH_HMAC_ID_SHA1) &&
673255160Stuexen	    (hmac_id != SCTP_AUTH_HMAC_ID_SHA256)) {
674163953Srrs		return (-1);
675163953Srrs	}
676170056Srrs	/* Now is it already in the list */
677170056Srrs	for (i = 0; i < list->num_algo; i++) {
678170056Srrs		if (list->hmac[i] == hmac_id) {
679170056Srrs			/* already in list */
680170056Srrs			return (-1);
681170056Srrs		}
682170056Srrs	}
683169420Srrs	SCTPDBG(SCTP_DEBUG_AUTH1, "SCTP: add HMAC id %u to list\n", hmac_id);
684163953Srrs	list->hmac[list->num_algo++] = hmac_id;
685163953Srrs	return (0);
686163953Srrs}
687163953Srrs
688163953Srrssctp_hmaclist_t *
689163953Srrssctp_copy_hmaclist(sctp_hmaclist_t * list)
690163953Srrs{
691163953Srrs	sctp_hmaclist_t *new_list;
692163953Srrs	int i;
693163953Srrs
694163953Srrs	if (list == NULL)
695163953Srrs		return (NULL);
696163953Srrs	/* get a new list */
697163953Srrs	new_list = sctp_alloc_hmaclist(list->max_algo);
698163953Srrs	if (new_list == NULL)
699163953Srrs		return (NULL);
700163953Srrs	/* copy it */
701163953Srrs	new_list->max_algo = list->max_algo;
702163953Srrs	new_list->num_algo = list->num_algo;
703163953Srrs	for (i = 0; i < list->num_algo; i++)
704163953Srrs		new_list->hmac[i] = list->hmac[i];
705163953Srrs	return (new_list);
706163953Srrs}
707163953Srrs
708163953Srrssctp_hmaclist_t *
709163953Srrssctp_default_supported_hmaclist(void)
710163953Srrs{
711163953Srrs	sctp_hmaclist_t *new_list;
712163953Srrs
713163953Srrs	new_list = sctp_alloc_hmaclist(2);
714163953Srrs	if (new_list == NULL)
715163953Srrs		return (NULL);
716255160Stuexen	/* We prefer SHA256, so list it first */
717255160Stuexen	(void)sctp_auth_add_hmacid(new_list, SCTP_AUTH_HMAC_ID_SHA256);
718169378Srrs	(void)sctp_auth_add_hmacid(new_list, SCTP_AUTH_HMAC_ID_SHA1);
719163953Srrs	return (new_list);
720163953Srrs}
721163953Srrs
722185694Srrs/*-
723185694Srrs * HMAC algos are listed in priority/preference order
724185694Srrs * find the best HMAC id to use for the peer based on local support
725163953Srrs */
726163953Srrsuint16_t
727163953Srrssctp_negotiate_hmacid(sctp_hmaclist_t * peer, sctp_hmaclist_t * local)
728163953Srrs{
729163953Srrs	int i, j;
730163953Srrs
731163953Srrs	if ((local == NULL) || (peer == NULL))
732163953Srrs		return (SCTP_AUTH_HMAC_ID_RSVD);
733163953Srrs
734163953Srrs	for (i = 0; i < peer->num_algo; i++) {
735163953Srrs		for (j = 0; j < local->num_algo; j++) {
736163953Srrs			if (peer->hmac[i] == local->hmac[j]) {
737163953Srrs				/* found the "best" one */
738169420Srrs				SCTPDBG(SCTP_DEBUG_AUTH1,
739169420Srrs				    "SCTP: negotiated peer HMAC id %u\n",
740169420Srrs				    peer->hmac[i]);
741163953Srrs				return (peer->hmac[i]);
742163953Srrs			}
743163953Srrs		}
744163953Srrs	}
745163953Srrs	/* didn't find one! */
746163953Srrs	return (SCTP_AUTH_HMAC_ID_RSVD);
747163953Srrs}
748163953Srrs
749185694Srrs/*-
750185694Srrs * serialize the HMAC algo list and return space used
751185694Srrs * caller must guarantee ptr has appropriate space
752163953Srrs */
753163953Srrsint
754163953Srrssctp_serialize_hmaclist(sctp_hmaclist_t * list, uint8_t * ptr)
755163953Srrs{
756163953Srrs	int i;
757163953Srrs	uint16_t hmac_id;
758163953Srrs
759163953Srrs	if (list == NULL)
760163953Srrs		return (0);
761163953Srrs
762163953Srrs	for (i = 0; i < list->num_algo; i++) {
763163953Srrs		hmac_id = htons(list->hmac[i]);
764163953Srrs		bcopy(&hmac_id, ptr, sizeof(hmac_id));
765163953Srrs		ptr += sizeof(hmac_id);
766163953Srrs	}
767163953Srrs	return (list->num_algo * sizeof(hmac_id));
768163953Srrs}
769163953Srrs
770163953Srrsint
771163953Srrssctp_verify_hmac_param(struct sctp_auth_hmac_algo *hmacs, uint32_t num_hmacs)
772163953Srrs{
773163953Srrs	uint32_t i;
774163953Srrs
775163953Srrs	for (i = 0; i < num_hmacs; i++) {
776255160Stuexen		if (ntohs(hmacs->hmac_ids[i]) == SCTP_AUTH_HMAC_ID_SHA1) {
777255160Stuexen			return (0);
778255160Stuexen		}
779163953Srrs	}
780255160Stuexen	return (-1);
781163953Srrs}
782163953Srrs
783163953Srrssctp_authinfo_t *
784163953Srrssctp_alloc_authinfo(void)
785163953Srrs{
786163953Srrs	sctp_authinfo_t *new_authinfo;
787163953Srrs
788163953Srrs	SCTP_MALLOC(new_authinfo, sctp_authinfo_t *, sizeof(*new_authinfo),
789170091Srrs	    SCTP_M_AUTH_IF);
790170091Srrs
791163953Srrs	if (new_authinfo == NULL) {
792163953Srrs		/* out of memory */
793163953Srrs		return (NULL);
794163953Srrs	}
795171943Srrs	bzero(new_authinfo, sizeof(*new_authinfo));
796163953Srrs	return (new_authinfo);
797163953Srrs}
798163953Srrs
799163953Srrsvoid
800163953Srrssctp_free_authinfo(sctp_authinfo_t * authinfo)
801163953Srrs{
802163953Srrs	if (authinfo == NULL)
803163953Srrs		return;
804163953Srrs
805163953Srrs	if (authinfo->random != NULL)
806163953Srrs		sctp_free_key(authinfo->random);
807163953Srrs	if (authinfo->peer_random != NULL)
808163953Srrs		sctp_free_key(authinfo->peer_random);
809163953Srrs	if (authinfo->assoc_key != NULL)
810163953Srrs		sctp_free_key(authinfo->assoc_key);
811163953Srrs	if (authinfo->recv_key != NULL)
812163953Srrs		sctp_free_key(authinfo->recv_key);
813163953Srrs
814163953Srrs	/* We are NOT dynamically allocating authinfo's right now... */
815170091Srrs	/* SCTP_FREE(authinfo, SCTP_M_AUTH_??); */
816163953Srrs}
817163953Srrs
818163953Srrs
819170806Srrsuint32_t
820163953Srrssctp_get_auth_chunk_len(uint16_t hmac_algo)
821163953Srrs{
822163953Srrs	int size;
823163953Srrs
824163953Srrs	size = sizeof(struct sctp_auth_chunk) + sctp_get_hmac_digest_len(hmac_algo);
825163953Srrs	return (SCTP_SIZE32(size));
826163953Srrs}
827163953Srrs
828163953Srrsuint32_t
829163953Srrssctp_get_hmac_digest_len(uint16_t hmac_algo)
830163953Srrs{
831163953Srrs	switch (hmac_algo) {
832163953Srrs	case SCTP_AUTH_HMAC_ID_SHA1:
833163953Srrs		return (SCTP_AUTH_DIGEST_LEN_SHA1);
834163953Srrs	case SCTP_AUTH_HMAC_ID_SHA256:
835163953Srrs		return (SCTP_AUTH_DIGEST_LEN_SHA256);
836163953Srrs	default:
837163953Srrs		/* unknown HMAC algorithm: can't do anything */
838163953Srrs		return (0);
839163953Srrs	}			/* end switch */
840163953Srrs}
841163953Srrs
842163953Srrsstatic inline int
843163953Srrssctp_get_hmac_block_len(uint16_t hmac_algo)
844163953Srrs{
845163953Srrs	switch (hmac_algo) {
846208856Srrs	case SCTP_AUTH_HMAC_ID_SHA1:
847163953Srrs		return (64);
848163953Srrs	case SCTP_AUTH_HMAC_ID_SHA256:
849163953Srrs		return (64);
850163953Srrs	case SCTP_AUTH_HMAC_ID_RSVD:
851163953Srrs	default:
852163953Srrs		/* unknown HMAC algorithm: can't do anything */
853163953Srrs		return (0);
854163953Srrs	}			/* end switch */
855163953Srrs}
856163953Srrs
857163953Srrsstatic void
858163953Srrssctp_hmac_init(uint16_t hmac_algo, sctp_hash_context_t * ctx)
859163953Srrs{
860163953Srrs	switch (hmac_algo) {
861208856Srrs	case SCTP_AUTH_HMAC_ID_SHA1:
862255160Stuexen		SCTP_SHA1_INIT(&ctx->sha1);
863163953Srrs		break;
864163953Srrs	case SCTP_AUTH_HMAC_ID_SHA256:
865255160Stuexen		SCTP_SHA256_INIT(&ctx->sha256);
866163953Srrs		break;
867163953Srrs	case SCTP_AUTH_HMAC_ID_RSVD:
868163953Srrs	default:
869163953Srrs		/* unknown HMAC algorithm: can't do anything */
870163953Srrs		return;
871163953Srrs	}			/* end switch */
872163953Srrs}
873163953Srrs
874163953Srrsstatic void
875163953Srrssctp_hmac_update(uint16_t hmac_algo, sctp_hash_context_t * ctx,
876166675Srrs    uint8_t * text, uint32_t textlen)
877163953Srrs{
878163953Srrs	switch (hmac_algo) {
879208856Srrs	case SCTP_AUTH_HMAC_ID_SHA1:
880255160Stuexen		SCTP_SHA1_UPDATE(&ctx->sha1, text, textlen);
881163953Srrs		break;
882163953Srrs	case SCTP_AUTH_HMAC_ID_SHA256:
883255160Stuexen		SCTP_SHA256_UPDATE(&ctx->sha256, text, textlen);
884163953Srrs		break;
885163953Srrs	case SCTP_AUTH_HMAC_ID_RSVD:
886163953Srrs	default:
887163953Srrs		/* unknown HMAC algorithm: can't do anything */
888163953Srrs		return;
889163953Srrs	}			/* end switch */
890163953Srrs}
891163953Srrs
892163953Srrsstatic void
893163953Srrssctp_hmac_final(uint16_t hmac_algo, sctp_hash_context_t * ctx,
894163953Srrs    uint8_t * digest)
895163953Srrs{
896163953Srrs	switch (hmac_algo) {
897208856Srrs	case SCTP_AUTH_HMAC_ID_SHA1:
898255160Stuexen		SCTP_SHA1_FINAL(digest, &ctx->sha1);
899163953Srrs		break;
900163953Srrs	case SCTP_AUTH_HMAC_ID_SHA256:
901255160Stuexen		SCTP_SHA256_FINAL(digest, &ctx->sha256);
902163953Srrs		break;
903163953Srrs	case SCTP_AUTH_HMAC_ID_RSVD:
904163953Srrs	default:
905163953Srrs		/* unknown HMAC algorithm: can't do anything */
906163953Srrs		return;
907163953Srrs	}			/* end switch */
908163953Srrs}
909163953Srrs
910185694Srrs/*-
911163953Srrs * Keyed-Hashing for Message Authentication: FIPS 198 (RFC 2104)
912163953Srrs *
913163953Srrs * Compute the HMAC digest using the desired hash key, text, and HMAC
914163953Srrs * algorithm.  Resulting digest is placed in 'digest' and digest length
915163953Srrs * is returned, if the HMAC was performed.
916163953Srrs *
917163953Srrs * WARNING: it is up to the caller to supply sufficient space to hold the
918163953Srrs * resultant digest.
919163953Srrs */
920163953Srrsuint32_t
921163953Srrssctp_hmac(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
922166675Srrs    uint8_t * text, uint32_t textlen, uint8_t * digest)
923163953Srrs{
924163953Srrs	uint32_t digestlen;
925163953Srrs	uint32_t blocklen;
926163953Srrs	sctp_hash_context_t ctx;
927163953Srrs	uint8_t ipad[128], opad[128];	/* keyed hash inner/outer pads */
928163953Srrs	uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
929163953Srrs	uint32_t i;
930163953Srrs
931163953Srrs	/* sanity check the material and length */
932163953Srrs	if ((key == NULL) || (keylen == 0) || (text == NULL) ||
933163953Srrs	    (textlen == 0) || (digest == NULL)) {
934163953Srrs		/* can't do HMAC with empty key or text or digest store */
935163953Srrs		return (0);
936163953Srrs	}
937163953Srrs	/* validate the hmac algo and get the digest length */
938163953Srrs	digestlen = sctp_get_hmac_digest_len(hmac_algo);
939163953Srrs	if (digestlen == 0)
940163953Srrs		return (0);
941163953Srrs
942163953Srrs	/* hash the key if it is longer than the hash block size */
943163953Srrs	blocklen = sctp_get_hmac_block_len(hmac_algo);
944163953Srrs	if (keylen > blocklen) {
945163953Srrs		sctp_hmac_init(hmac_algo, &ctx);
946163953Srrs		sctp_hmac_update(hmac_algo, &ctx, key, keylen);
947163953Srrs		sctp_hmac_final(hmac_algo, &ctx, temp);
948163953Srrs		/* set the hashed key as the key */
949163953Srrs		keylen = digestlen;
950163953Srrs		key = temp;
951163953Srrs	}
952163953Srrs	/* initialize the inner/outer pads with the key and "append" zeroes */
953163953Srrs	bzero(ipad, blocklen);
954163953Srrs	bzero(opad, blocklen);
955163953Srrs	bcopy(key, ipad, keylen);
956163953Srrs	bcopy(key, opad, keylen);
957163953Srrs
958163953Srrs	/* XOR the key with ipad and opad values */
959163953Srrs	for (i = 0; i < blocklen; i++) {
960163953Srrs		ipad[i] ^= 0x36;
961163953Srrs		opad[i] ^= 0x5c;
962163953Srrs	}
963163953Srrs
964163953Srrs	/* perform inner hash */
965163953Srrs	sctp_hmac_init(hmac_algo, &ctx);
966163953Srrs	sctp_hmac_update(hmac_algo, &ctx, ipad, blocklen);
967163953Srrs	sctp_hmac_update(hmac_algo, &ctx, text, textlen);
968163953Srrs	sctp_hmac_final(hmac_algo, &ctx, temp);
969163953Srrs
970163953Srrs	/* perform outer hash */
971163953Srrs	sctp_hmac_init(hmac_algo, &ctx);
972163953Srrs	sctp_hmac_update(hmac_algo, &ctx, opad, blocklen);
973163953Srrs	sctp_hmac_update(hmac_algo, &ctx, temp, digestlen);
974163953Srrs	sctp_hmac_final(hmac_algo, &ctx, digest);
975163953Srrs
976163953Srrs	return (digestlen);
977163953Srrs}
978163953Srrs
979163953Srrs/* mbuf version */
980163953Srrsuint32_t
981163953Srrssctp_hmac_m(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
982170462Srrs    struct mbuf *m, uint32_t m_offset, uint8_t * digest, uint32_t trailer)
983163953Srrs{
984163953Srrs	uint32_t digestlen;
985163953Srrs	uint32_t blocklen;
986163953Srrs	sctp_hash_context_t ctx;
987163953Srrs	uint8_t ipad[128], opad[128];	/* keyed hash inner/outer pads */
988163953Srrs	uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
989163953Srrs	uint32_t i;
990163953Srrs	struct mbuf *m_tmp;
991163953Srrs
992163953Srrs	/* sanity check the material and length */
993163953Srrs	if ((key == NULL) || (keylen == 0) || (m == NULL) || (digest == NULL)) {
994163953Srrs		/* can't do HMAC with empty key or text or digest store */
995163953Srrs		return (0);
996163953Srrs	}
997163953Srrs	/* validate the hmac algo and get the digest length */
998163953Srrs	digestlen = sctp_get_hmac_digest_len(hmac_algo);
999163953Srrs	if (digestlen == 0)
1000163953Srrs		return (0);
1001163953Srrs
1002163953Srrs	/* hash the key if it is longer than the hash block size */
1003163953Srrs	blocklen = sctp_get_hmac_block_len(hmac_algo);
1004163953Srrs	if (keylen > blocklen) {
1005163953Srrs		sctp_hmac_init(hmac_algo, &ctx);
1006163953Srrs		sctp_hmac_update(hmac_algo, &ctx, key, keylen);
1007163953Srrs		sctp_hmac_final(hmac_algo, &ctx, temp);
1008163953Srrs		/* set the hashed key as the key */
1009163953Srrs		keylen = digestlen;
1010163953Srrs		key = temp;
1011163953Srrs	}
1012163953Srrs	/* initialize the inner/outer pads with the key and "append" zeroes */
1013163953Srrs	bzero(ipad, blocklen);
1014163953Srrs	bzero(opad, blocklen);
1015163953Srrs	bcopy(key, ipad, keylen);
1016163953Srrs	bcopy(key, opad, keylen);
1017163953Srrs
1018163953Srrs	/* XOR the key with ipad and opad values */
1019163953Srrs	for (i = 0; i < blocklen; i++) {
1020163953Srrs		ipad[i] ^= 0x36;
1021163953Srrs		opad[i] ^= 0x5c;
1022163953Srrs	}
1023163953Srrs
1024163953Srrs	/* perform inner hash */
1025163953Srrs	sctp_hmac_init(hmac_algo, &ctx);
1026163953Srrs	sctp_hmac_update(hmac_algo, &ctx, ipad, blocklen);
1027163953Srrs	/* find the correct starting mbuf and offset (get start of text) */
1028163953Srrs	m_tmp = m;
1029165647Srrs	while ((m_tmp != NULL) && (m_offset >= (uint32_t) SCTP_BUF_LEN(m_tmp))) {
1030165647Srrs		m_offset -= SCTP_BUF_LEN(m_tmp);
1031165647Srrs		m_tmp = SCTP_BUF_NEXT(m_tmp);
1032163953Srrs	}
1033163953Srrs	/* now use the rest of the mbuf chain for the text */
1034163953Srrs	while (m_tmp != NULL) {
1035170462Srrs		if ((SCTP_BUF_NEXT(m_tmp) == NULL) && trailer) {
1036170462Srrs			sctp_hmac_update(hmac_algo, &ctx, mtod(m_tmp, uint8_t *) + m_offset,
1037170462Srrs			    SCTP_BUF_LEN(m_tmp) - (trailer + m_offset));
1038170462Srrs		} else {
1039170462Srrs			sctp_hmac_update(hmac_algo, &ctx, mtod(m_tmp, uint8_t *) + m_offset,
1040170462Srrs			    SCTP_BUF_LEN(m_tmp) - m_offset);
1041170462Srrs		}
1042165647Srrs
1043163953Srrs		/* clear the offset since it's only for the first mbuf */
1044163953Srrs		m_offset = 0;
1045165647Srrs		m_tmp = SCTP_BUF_NEXT(m_tmp);
1046163953Srrs	}
1047163953Srrs	sctp_hmac_final(hmac_algo, &ctx, temp);
1048163953Srrs
1049163953Srrs	/* perform outer hash */
1050163953Srrs	sctp_hmac_init(hmac_algo, &ctx);
1051163953Srrs	sctp_hmac_update(hmac_algo, &ctx, opad, blocklen);
1052163953Srrs	sctp_hmac_update(hmac_algo, &ctx, temp, digestlen);
1053163953Srrs	sctp_hmac_final(hmac_algo, &ctx, digest);
1054163953Srrs
1055163953Srrs	return (digestlen);
1056163953Srrs}
1057163953Srrs
1058185694Srrs/*-
1059163953Srrs * verify the HMAC digest using the desired hash key, text, and HMAC
1060185694Srrs * algorithm.
1061185694Srrs * Returns -1 on error, 0 on success.
1062163953Srrs */
1063163953Srrsint
1064163953Srrssctp_verify_hmac(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
1065166675Srrs    uint8_t * text, uint32_t textlen,
1066163953Srrs    uint8_t * digest, uint32_t digestlen)
1067163953Srrs{
1068163953Srrs	uint32_t len;
1069163953Srrs	uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
1070163953Srrs
1071163953Srrs	/* sanity check the material and length */
1072163953Srrs	if ((key == NULL) || (keylen == 0) ||
1073163953Srrs	    (text == NULL) || (textlen == 0) || (digest == NULL)) {
1074163953Srrs		/* can't do HMAC with empty key or text or digest */
1075163953Srrs		return (-1);
1076163953Srrs	}
1077163953Srrs	len = sctp_get_hmac_digest_len(hmac_algo);
1078163953Srrs	if ((len == 0) || (digestlen != len))
1079163953Srrs		return (-1);
1080163953Srrs
1081163953Srrs	/* compute the expected hash */
1082163953Srrs	if (sctp_hmac(hmac_algo, key, keylen, text, textlen, temp) != len)
1083163953Srrs		return (-1);
1084163953Srrs
1085163953Srrs	if (memcmp(digest, temp, digestlen) != 0)
1086163953Srrs		return (-1);
1087163953Srrs	else
1088163953Srrs		return (0);
1089163953Srrs}
1090163953Srrs
1091163953Srrs
1092163953Srrs/*
1093163953Srrs * computes the requested HMAC using a key struct (which may be modified if
1094163953Srrs * the keylen exceeds the HMAC block len).
1095163953Srrs */
1096163953Srrsuint32_t
1097166675Srrssctp_compute_hmac(uint16_t hmac_algo, sctp_key_t * key, uint8_t * text,
1098163953Srrs    uint32_t textlen, uint8_t * digest)
1099163953Srrs{
1100163953Srrs	uint32_t digestlen;
1101163953Srrs	uint32_t blocklen;
1102163953Srrs	sctp_hash_context_t ctx;
1103163953Srrs	uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
1104163953Srrs
1105163953Srrs	/* sanity check */
1106163953Srrs	if ((key == NULL) || (text == NULL) || (textlen == 0) ||
1107163953Srrs	    (digest == NULL)) {
1108163953Srrs		/* can't do HMAC with empty key or text or digest store */
1109163953Srrs		return (0);
1110163953Srrs	}
1111163953Srrs	/* validate the hmac algo and get the digest length */
1112163953Srrs	digestlen = sctp_get_hmac_digest_len(hmac_algo);
1113163953Srrs	if (digestlen == 0)
1114163953Srrs		return (0);
1115163953Srrs
1116163953Srrs	/* hash the key if it is longer than the hash block size */
1117163953Srrs	blocklen = sctp_get_hmac_block_len(hmac_algo);
1118163953Srrs	if (key->keylen > blocklen) {
1119163953Srrs		sctp_hmac_init(hmac_algo, &ctx);
1120163953Srrs		sctp_hmac_update(hmac_algo, &ctx, key->key, key->keylen);
1121163953Srrs		sctp_hmac_final(hmac_algo, &ctx, temp);
1122163953Srrs		/* save the hashed key as the new key */
1123163953Srrs		key->keylen = digestlen;
1124163953Srrs		bcopy(temp, key->key, key->keylen);
1125163953Srrs	}
1126163953Srrs	return (sctp_hmac(hmac_algo, key->key, key->keylen, text, textlen,
1127163953Srrs	    digest));
1128163953Srrs}
1129163953Srrs
1130163953Srrs/* mbuf version */
1131163953Srrsuint32_t
1132163953Srrssctp_compute_hmac_m(uint16_t hmac_algo, sctp_key_t * key, struct mbuf *m,
1133163953Srrs    uint32_t m_offset, uint8_t * digest)
1134163953Srrs{
1135163953Srrs	uint32_t digestlen;
1136163953Srrs	uint32_t blocklen;
1137163953Srrs	sctp_hash_context_t ctx;
1138163953Srrs	uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
1139163953Srrs
1140163953Srrs	/* sanity check */
1141163953Srrs	if ((key == NULL) || (m == NULL) || (digest == NULL)) {
1142163953Srrs		/* can't do HMAC with empty key or text or digest store */
1143163953Srrs		return (0);
1144163953Srrs	}
1145163953Srrs	/* validate the hmac algo and get the digest length */
1146163953Srrs	digestlen = sctp_get_hmac_digest_len(hmac_algo);
1147163953Srrs	if (digestlen == 0)
1148163953Srrs		return (0);
1149163953Srrs
1150163953Srrs	/* hash the key if it is longer than the hash block size */
1151163953Srrs	blocklen = sctp_get_hmac_block_len(hmac_algo);
1152163953Srrs	if (key->keylen > blocklen) {
1153163953Srrs		sctp_hmac_init(hmac_algo, &ctx);
1154163953Srrs		sctp_hmac_update(hmac_algo, &ctx, key->key, key->keylen);
1155163953Srrs		sctp_hmac_final(hmac_algo, &ctx, temp);
1156163953Srrs		/* save the hashed key as the new key */
1157163953Srrs		key->keylen = digestlen;
1158163953Srrs		bcopy(temp, key->key, key->keylen);
1159163953Srrs	}
1160170462Srrs	return (sctp_hmac_m(hmac_algo, key->key, key->keylen, m, m_offset, digest, 0));
1161163953Srrs}
1162163953Srrs
1163163953Srrsint
1164163953Srrssctp_auth_is_supported_hmac(sctp_hmaclist_t * list, uint16_t id)
1165163953Srrs{
1166163953Srrs	int i;
1167163953Srrs
1168163953Srrs	if ((list == NULL) || (id == SCTP_AUTH_HMAC_ID_RSVD))
1169163953Srrs		return (0);
1170163953Srrs
1171163953Srrs	for (i = 0; i < list->num_algo; i++)
1172163953Srrs		if (list->hmac[i] == id)
1173163953Srrs			return (1);
1174163953Srrs
1175163953Srrs	/* not in the list */
1176163953Srrs	return (0);
1177163953Srrs}
1178163953Srrs
1179163953Srrs
1180185694Srrs/*-
1181185694Srrs * clear any cached key(s) if they match the given key id on an association.
1182185694Srrs * the cached key(s) will be recomputed and re-cached at next use.
1183185694Srrs * ASSUMES TCB_LOCK is already held
1184163953Srrs */
1185163953Srrsvoid
1186163953Srrssctp_clear_cachedkeys(struct sctp_tcb *stcb, uint16_t keyid)
1187163953Srrs{
1188163953Srrs	if (stcb == NULL)
1189163953Srrs		return;
1190163953Srrs
1191163953Srrs	if (keyid == stcb->asoc.authinfo.assoc_keyid) {
1192163953Srrs		sctp_free_key(stcb->asoc.authinfo.assoc_key);
1193163953Srrs		stcb->asoc.authinfo.assoc_key = NULL;
1194163953Srrs	}
1195163953Srrs	if (keyid == stcb->asoc.authinfo.recv_keyid) {
1196163953Srrs		sctp_free_key(stcb->asoc.authinfo.recv_key);
1197163953Srrs		stcb->asoc.authinfo.recv_key = NULL;
1198163953Srrs	}
1199163953Srrs}
1200163953Srrs
1201185694Srrs/*-
1202163953Srrs * clear any cached key(s) if they match the given key id for all assocs on
1203185694Srrs * an endpoint.
1204185694Srrs * ASSUMES INP_WLOCK is already held
1205163953Srrs */
1206163953Srrsvoid
1207163953Srrssctp_clear_cachedkeys_ep(struct sctp_inpcb *inp, uint16_t keyid)
1208163953Srrs{
1209163953Srrs	struct sctp_tcb *stcb;
1210163953Srrs
1211163953Srrs	if (inp == NULL)
1212163953Srrs		return;
1213163953Srrs
1214163953Srrs	/* clear the cached keys on all assocs on this instance */
1215163953Srrs	LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1216163953Srrs		SCTP_TCB_LOCK(stcb);
1217163953Srrs		sctp_clear_cachedkeys(stcb, keyid);
1218163953Srrs		SCTP_TCB_UNLOCK(stcb);
1219163953Srrs	}
1220163953Srrs}
1221163953Srrs
1222185694Srrs/*-
1223185694Srrs * delete a shared key from an association
1224185694Srrs * ASSUMES TCB_LOCK is already held
1225163953Srrs */
1226163953Srrsint
1227163953Srrssctp_delete_sharedkey(struct sctp_tcb *stcb, uint16_t keyid)
1228163953Srrs{
1229163953Srrs	sctp_sharedkey_t *skey;
1230163953Srrs
1231163953Srrs	if (stcb == NULL)
1232163953Srrs		return (-1);
1233163953Srrs
1234163953Srrs	/* is the keyid the assoc active sending key */
1235185694Srrs	if (keyid == stcb->asoc.authinfo.active_keyid)
1236163953Srrs		return (-1);
1237163953Srrs
1238163953Srrs	/* does the key exist? */
1239163953Srrs	skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
1240163953Srrs	if (skey == NULL)
1241163953Srrs		return (-1);
1242163953Srrs
1243185694Srrs	/* are there other refcount holders on the key? */
1244185694Srrs	if (skey->refcount > 1)
1245185694Srrs		return (-1);
1246185694Srrs
1247163953Srrs	/* remove it */
1248163953Srrs	LIST_REMOVE(skey, next);
1249163953Srrs	sctp_free_sharedkey(skey);	/* frees skey->key as well */
1250163953Srrs
1251163953Srrs	/* clear any cached keys */
1252163953Srrs	sctp_clear_cachedkeys(stcb, keyid);
1253163953Srrs	return (0);
1254163953Srrs}
1255163953Srrs
1256185694Srrs/*-
1257185694Srrs * deletes a shared key from the endpoint
1258185694Srrs * ASSUMES INP_WLOCK is already held
1259163953Srrs */
1260163953Srrsint
1261163953Srrssctp_delete_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid)
1262163953Srrs{
1263163953Srrs	sctp_sharedkey_t *skey;
1264163953Srrs
1265163953Srrs	if (inp == NULL)
1266163953Srrs		return (-1);
1267163953Srrs
1268185694Srrs	/* is the keyid the active sending key on the endpoint */
1269163953Srrs	if (keyid == inp->sctp_ep.default_keyid)
1270163953Srrs		return (-1);
1271163953Srrs
1272163953Srrs	/* does the key exist? */
1273163953Srrs	skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid);
1274163953Srrs	if (skey == NULL)
1275163953Srrs		return (-1);
1276163953Srrs
1277185694Srrs	/* endpoint keys are not refcounted */
1278185694Srrs
1279163953Srrs	/* remove it */
1280163953Srrs	LIST_REMOVE(skey, next);
1281163953Srrs	sctp_free_sharedkey(skey);	/* frees skey->key as well */
1282163953Srrs
1283163953Srrs	/* clear any cached keys */
1284163953Srrs	sctp_clear_cachedkeys_ep(inp, keyid);
1285163953Srrs	return (0);
1286163953Srrs}
1287163953Srrs
1288185694Srrs/*-
1289185694Srrs * set the active key on an association
1290185694Srrs * ASSUMES TCB_LOCK is already held
1291163953Srrs */
1292163953Srrsint
1293163953Srrssctp_auth_setactivekey(struct sctp_tcb *stcb, uint16_t keyid)
1294163953Srrs{
1295163953Srrs	sctp_sharedkey_t *skey = NULL;
1296163953Srrs
1297163953Srrs	/* find the key on the assoc */
1298163953Srrs	skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
1299163953Srrs	if (skey == NULL) {
1300163953Srrs		/* that key doesn't exist */
1301163953Srrs		return (-1);
1302163953Srrs	}
1303185694Srrs	if ((skey->deactivated) && (skey->refcount > 1)) {
1304185694Srrs		/* can't reactivate a deactivated key with other refcounts */
1305185694Srrs		return (-1);
1306185694Srrs	}
1307185694Srrs	/* set the (new) active key */
1308185694Srrs	stcb->asoc.authinfo.active_keyid = keyid;
1309185694Srrs	/* reset the deactivated flag */
1310185694Srrs	skey->deactivated = 0;
1311163953Srrs
1312163953Srrs	return (0);
1313163953Srrs}
1314163953Srrs
1315185694Srrs/*-
1316185694Srrs * set the active key on an endpoint
1317185694Srrs * ASSUMES INP_WLOCK is already held
1318163953Srrs */
1319163953Srrsint
1320163953Srrssctp_auth_setactivekey_ep(struct sctp_inpcb *inp, uint16_t keyid)
1321163953Srrs{
1322163953Srrs	sctp_sharedkey_t *skey;
1323163953Srrs
1324163953Srrs	/* find the key */
1325163953Srrs	skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid);
1326163953Srrs	if (skey == NULL) {
1327163953Srrs		/* that key doesn't exist */
1328163953Srrs		return (-1);
1329163953Srrs	}
1330163953Srrs	inp->sctp_ep.default_keyid = keyid;
1331163953Srrs	return (0);
1332163953Srrs}
1333163953Srrs
1334185694Srrs/*-
1335185694Srrs * deactivates a shared key from the association
1336185694Srrs * ASSUMES INP_WLOCK is already held
1337185694Srrs */
1338185694Srrsint
1339185694Srrssctp_deact_sharedkey(struct sctp_tcb *stcb, uint16_t keyid)
1340185694Srrs{
1341185694Srrs	sctp_sharedkey_t *skey;
1342185694Srrs
1343185694Srrs	if (stcb == NULL)
1344185694Srrs		return (-1);
1345185694Srrs
1346185694Srrs	/* is the keyid the assoc active sending key */
1347185694Srrs	if (keyid == stcb->asoc.authinfo.active_keyid)
1348185694Srrs		return (-1);
1349185694Srrs
1350185694Srrs	/* does the key exist? */
1351185694Srrs	skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
1352185694Srrs	if (skey == NULL)
1353185694Srrs		return (-1);
1354185694Srrs
1355185694Srrs	/* are there other refcount holders on the key? */
1356185694Srrs	if (skey->refcount == 1) {
1357185694Srrs		/* no other users, send a notification for this key */
1358185694Srrs		sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb, keyid, 0,
1359185694Srrs		    SCTP_SO_LOCKED);
1360185694Srrs	}
1361185694Srrs	/* mark the key as deactivated */
1362185694Srrs	skey->deactivated = 1;
1363185694Srrs
1364185694Srrs	return (0);
1365185694Srrs}
1366185694Srrs
1367185694Srrs/*-
1368185694Srrs * deactivates a shared key from the endpoint
1369185694Srrs * ASSUMES INP_WLOCK is already held
1370185694Srrs */
1371185694Srrsint
1372185694Srrssctp_deact_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid)
1373185694Srrs{
1374185694Srrs	sctp_sharedkey_t *skey;
1375185694Srrs
1376185694Srrs	if (inp == NULL)
1377185694Srrs		return (-1);
1378185694Srrs
1379185694Srrs	/* is the keyid the active sending key on the endpoint */
1380185694Srrs	if (keyid == inp->sctp_ep.default_keyid)
1381185694Srrs		return (-1);
1382185694Srrs
1383185694Srrs	/* does the key exist? */
1384185694Srrs	skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid);
1385185694Srrs	if (skey == NULL)
1386185694Srrs		return (-1);
1387185694Srrs
1388185694Srrs	/* endpoint keys are not refcounted */
1389185694Srrs
1390185694Srrs	/* remove it */
1391185694Srrs	LIST_REMOVE(skey, next);
1392185694Srrs	sctp_free_sharedkey(skey);	/* frees skey->key as well */
1393185694Srrs
1394185694Srrs	return (0);
1395185694Srrs}
1396185694Srrs
1397163953Srrs/*
1398163953Srrs * get local authentication parameters from cookie (from INIT-ACK)
1399163953Srrs */
1400163953Srrsvoid
1401163953Srrssctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
1402163953Srrs    uint32_t offset, uint32_t length)
1403163953Srrs{
1404163953Srrs	struct sctp_paramhdr *phdr, tmp_param;
1405163953Srrs	uint16_t plen, ptype;
1406166675Srrs	uint8_t random_store[SCTP_PARAM_BUFFER_SIZE];
1407168124Srrs	struct sctp_auth_random *p_random = NULL;
1408163953Srrs	uint16_t random_len = 0;
1409166675Srrs	uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE];
1410163953Srrs	struct sctp_auth_hmac_algo *hmacs = NULL;
1411163953Srrs	uint16_t hmacs_len = 0;
1412166675Srrs	uint8_t chunks_store[SCTP_PARAM_BUFFER_SIZE];
1413163953Srrs	struct sctp_auth_chunk_list *chunks = NULL;
1414163953Srrs	uint16_t num_chunks = 0;
1415163953Srrs	sctp_key_t *new_key;
1416163953Srrs	uint32_t keylen;
1417163953Srrs
1418163953Srrs	/* convert to upper bound */
1419163953Srrs	length += offset;
1420163953Srrs
1421163953Srrs	phdr = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
1422163953Srrs	    sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
1423163953Srrs	while (phdr != NULL) {
1424163953Srrs		ptype = ntohs(phdr->param_type);
1425163953Srrs		plen = ntohs(phdr->param_length);
1426163953Srrs
1427163953Srrs		if ((plen == 0) || (offset + plen > length))
1428163953Srrs			break;
1429163953Srrs
1430163953Srrs		if (ptype == SCTP_RANDOM) {
1431166675Srrs			if (plen > sizeof(random_store))
1432163953Srrs				break;
1433163953Srrs			phdr = sctp_get_next_param(m, offset,
1434169208Srrs			    (struct sctp_paramhdr *)random_store, min(plen, sizeof(random_store)));
1435163953Srrs			if (phdr == NULL)
1436163953Srrs				return;
1437163953Srrs			/* save the random and length for the key */
1438168124Srrs			p_random = (struct sctp_auth_random *)phdr;
1439168124Srrs			random_len = plen - sizeof(*p_random);
1440163953Srrs		} else if (ptype == SCTP_HMAC_LIST) {
1441271750Stuexen			uint16_t num_hmacs;
1442271750Stuexen			uint16_t i;
1443163953Srrs
1444166675Srrs			if (plen > sizeof(hmacs_store))
1445163953Srrs				break;
1446163953Srrs			phdr = sctp_get_next_param(m, offset,
1447169208Srrs			    (struct sctp_paramhdr *)hmacs_store, min(plen, sizeof(hmacs_store)));
1448163953Srrs			if (phdr == NULL)
1449163953Srrs				return;
1450163953Srrs			/* save the hmacs list and num for the key */
1451163953Srrs			hmacs = (struct sctp_auth_hmac_algo *)phdr;
1452163953Srrs			hmacs_len = plen - sizeof(*hmacs);
1453163953Srrs			num_hmacs = hmacs_len / sizeof(hmacs->hmac_ids[0]);
1454163953Srrs			if (stcb->asoc.local_hmacs != NULL)
1455163953Srrs				sctp_free_hmaclist(stcb->asoc.local_hmacs);
1456163953Srrs			stcb->asoc.local_hmacs = sctp_alloc_hmaclist(num_hmacs);
1457163953Srrs			if (stcb->asoc.local_hmacs != NULL) {
1458163953Srrs				for (i = 0; i < num_hmacs; i++) {
1459169378Srrs					(void)sctp_auth_add_hmacid(stcb->asoc.local_hmacs,
1460163953Srrs					    ntohs(hmacs->hmac_ids[i]));
1461163953Srrs				}
1462163953Srrs			}
1463163953Srrs		} else if (ptype == SCTP_CHUNK_LIST) {
1464163953Srrs			int i;
1465163953Srrs
1466166675Srrs			if (plen > sizeof(chunks_store))
1467163953Srrs				break;
1468163953Srrs			phdr = sctp_get_next_param(m, offset,
1469169208Srrs			    (struct sctp_paramhdr *)chunks_store, min(plen, sizeof(chunks_store)));
1470163953Srrs			if (phdr == NULL)
1471163953Srrs				return;
1472163953Srrs			chunks = (struct sctp_auth_chunk_list *)phdr;
1473163953Srrs			num_chunks = plen - sizeof(*chunks);
1474163953Srrs			/* save chunks list and num for the key */
1475163953Srrs			if (stcb->asoc.local_auth_chunks != NULL)
1476163953Srrs				sctp_clear_chunklist(stcb->asoc.local_auth_chunks);
1477163953Srrs			else
1478163953Srrs				stcb->asoc.local_auth_chunks = sctp_alloc_chunklist();
1479163953Srrs			for (i = 0; i < num_chunks; i++) {
1480169378Srrs				(void)sctp_auth_add_chunk(chunks->chunk_types[i],
1481163953Srrs				    stcb->asoc.local_auth_chunks);
1482163953Srrs			}
1483163953Srrs		}
1484163953Srrs		/* get next parameter */
1485163953Srrs		offset += SCTP_SIZE32(plen);
1486163953Srrs		if (offset + sizeof(struct sctp_paramhdr) > length)
1487163953Srrs			break;
1488163953Srrs		phdr = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
1489163953Srrs		    (uint8_t *) & tmp_param);
1490163953Srrs	}
1491163953Srrs	/* concatenate the full random key */
1492188067Srrs	keylen = sizeof(*p_random) + random_len + sizeof(*hmacs) + hmacs_len;
1493188067Srrs	if (chunks != NULL) {
1494188067Srrs		keylen += sizeof(*chunks) + num_chunks;
1495188067Srrs	}
1496166675Srrs	new_key = sctp_alloc_key(keylen);
1497166675Srrs	if (new_key != NULL) {
1498166675Srrs		/* copy in the RANDOM */
1499168124Srrs		if (p_random != NULL) {
1500168124Srrs			keylen = sizeof(*p_random) + random_len;
1501168124Srrs			bcopy(p_random, new_key->key, keylen);
1502166675Srrs		}
1503163953Srrs		/* append in the AUTH chunks */
1504166675Srrs		if (chunks != NULL) {
1505166675Srrs			bcopy(chunks, new_key->key + keylen,
1506166675Srrs			    sizeof(*chunks) + num_chunks);
1507166675Srrs			keylen += sizeof(*chunks) + num_chunks;
1508166675Srrs		}
1509163953Srrs		/* append in the HMACs */
1510166675Srrs		if (hmacs != NULL) {
1511166675Srrs			bcopy(hmacs, new_key->key + keylen,
1512166675Srrs			    sizeof(*hmacs) + hmacs_len);
1513166675Srrs		}
1514163953Srrs	}
1515163953Srrs	if (stcb->asoc.authinfo.random != NULL)
1516163953Srrs		sctp_free_key(stcb->asoc.authinfo.random);
1517163953Srrs	stcb->asoc.authinfo.random = new_key;
1518163953Srrs	stcb->asoc.authinfo.random_len = random_len;
1519163953Srrs	sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.assoc_keyid);
1520163953Srrs	sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.recv_keyid);
1521163953Srrs
1522163953Srrs	/* negotiate what HMAC to use for the peer */
1523163953Srrs	stcb->asoc.peer_hmac_id = sctp_negotiate_hmacid(stcb->asoc.peer_hmacs,
1524163953Srrs	    stcb->asoc.local_hmacs);
1525185694Srrs
1526163953Srrs	/* copy defaults from the endpoint */
1527163953Srrs	/* FIX ME: put in cookie? */
1528185694Srrs	stcb->asoc.authinfo.active_keyid = stcb->sctp_ep->sctp_ep.default_keyid;
1529185694Srrs	/* copy out the shared key list (by reference) from the endpoint */
1530185694Srrs	(void)sctp_copy_skeylist(&stcb->sctp_ep->sctp_ep.shared_keys,
1531185694Srrs	    &stcb->asoc.shared_keys);
1532163953Srrs}
1533163953Srrs
1534163953Srrs/*
1535163953Srrs * compute and fill in the HMAC digest for a packet
1536163953Srrs */
1537163953Srrsvoid
1538163953Srrssctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
1539185694Srrs    struct sctp_auth_chunk *auth, struct sctp_tcb *stcb, uint16_t keyid)
1540163953Srrs{
1541163953Srrs	uint32_t digestlen;
1542163953Srrs	sctp_sharedkey_t *skey;
1543163953Srrs	sctp_key_t *key;
1544163953Srrs
1545163953Srrs	if ((stcb == NULL) || (auth == NULL))
1546163953Srrs		return;
1547163953Srrs
1548163953Srrs	/* zero the digest + chunk padding */
1549163953Srrs	digestlen = sctp_get_hmac_digest_len(stcb->asoc.peer_hmac_id);
1550163953Srrs	bzero(auth->hmac, SCTP_SIZE32(digestlen));
1551185694Srrs
1552185694Srrs	/* is the desired key cached? */
1553185694Srrs	if ((keyid != stcb->asoc.authinfo.assoc_keyid) ||
1554185694Srrs	    (stcb->asoc.authinfo.assoc_key == NULL)) {
1555185694Srrs		if (stcb->asoc.authinfo.assoc_key != NULL) {
1556185694Srrs			/* free the old cached key */
1557185694Srrs			sctp_free_key(stcb->asoc.authinfo.assoc_key);
1558163953Srrs		}
1559185694Srrs		skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
1560163953Srrs		/* the only way skey is NULL is if null key id 0 is used */
1561163953Srrs		if (skey != NULL)
1562163953Srrs			key = skey->key;
1563163953Srrs		else
1564163953Srrs			key = NULL;
1565163953Srrs		/* compute a new assoc key and cache it */
1566163953Srrs		stcb->asoc.authinfo.assoc_key =
1567163953Srrs		    sctp_compute_hashkey(stcb->asoc.authinfo.random,
1568163953Srrs		    stcb->asoc.authinfo.peer_random, key);
1569185694Srrs		stcb->asoc.authinfo.assoc_keyid = keyid;
1570169420Srrs		SCTPDBG(SCTP_DEBUG_AUTH1, "caching key id %u\n",
1571169420Srrs		    stcb->asoc.authinfo.assoc_keyid);
1572163953Srrs#ifdef SCTP_DEBUG
1573169420Srrs		if (SCTP_AUTH_DEBUG)
1574169420Srrs			sctp_print_key(stcb->asoc.authinfo.assoc_key,
1575169420Srrs			    "Assoc Key");
1576163953Srrs#endif
1577163953Srrs	}
1578163953Srrs	/* set in the active key id */
1579185694Srrs	auth->shared_key_id = htons(keyid);
1580163953Srrs
1581163953Srrs	/* compute and fill in the digest */
1582185694Srrs	(void)sctp_compute_hmac_m(stcb->asoc.peer_hmac_id, stcb->asoc.authinfo.assoc_key,
1583163953Srrs	    m, auth_offset, auth->hmac);
1584163953Srrs}
1585163953Srrs
1586163953Srrs
1587163953Srrsstatic void
1588163953Srrssctp_bzero_m(struct mbuf *m, uint32_t m_offset, uint32_t size)
1589163953Srrs{
1590163953Srrs	struct mbuf *m_tmp;
1591163953Srrs	uint8_t *data;
1592163953Srrs
1593163953Srrs	/* sanity check */
1594163953Srrs	if (m == NULL)
1595163953Srrs		return;
1596163953Srrs
1597163953Srrs	/* find the correct starting mbuf and offset (get start position) */
1598163953Srrs	m_tmp = m;
1599165647Srrs	while ((m_tmp != NULL) && (m_offset >= (uint32_t) SCTP_BUF_LEN(m_tmp))) {
1600165647Srrs		m_offset -= SCTP_BUF_LEN(m_tmp);
1601165647Srrs		m_tmp = SCTP_BUF_NEXT(m_tmp);
1602163953Srrs	}
1603163953Srrs	/* now use the rest of the mbuf chain */
1604163953Srrs	while ((m_tmp != NULL) && (size > 0)) {
1605163953Srrs		data = mtod(m_tmp, uint8_t *) + m_offset;
1606165647Srrs		if (size > (uint32_t) SCTP_BUF_LEN(m_tmp)) {
1607165647Srrs			bzero(data, SCTP_BUF_LEN(m_tmp));
1608165647Srrs			size -= SCTP_BUF_LEN(m_tmp);
1609163953Srrs		} else {
1610163953Srrs			bzero(data, size);
1611163953Srrs			size = 0;
1612163953Srrs		}
1613163953Srrs		/* clear the offset since it's only for the first mbuf */
1614163953Srrs		m_offset = 0;
1615165647Srrs		m_tmp = SCTP_BUF_NEXT(m_tmp);
1616163953Srrs	}
1617163953Srrs}
1618163953Srrs
1619185694Srrs/*-
1620185694Srrs * process the incoming Authentication chunk
1621185694Srrs * return codes:
1622185694Srrs *   -1 on any authentication error
1623185694Srrs *    0 on authentication verification
1624163953Srrs */
1625163953Srrsint
1626163953Srrssctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
1627163953Srrs    struct mbuf *m, uint32_t offset)
1628163953Srrs{
1629163953Srrs	uint16_t chunklen;
1630163953Srrs	uint16_t shared_key_id;
1631163953Srrs	uint16_t hmac_id;
1632163953Srrs	sctp_sharedkey_t *skey;
1633163953Srrs	uint32_t digestlen;
1634163953Srrs	uint8_t digest[SCTP_AUTH_DIGEST_LEN_MAX];
1635163953Srrs	uint8_t computed_digest[SCTP_AUTH_DIGEST_LEN_MAX];
1636163953Srrs
1637163953Srrs	/* auth is checked for NULL by caller */
1638163953Srrs	chunklen = ntohs(auth->ch.chunk_length);
1639163953Srrs	if (chunklen < sizeof(*auth)) {
1640163953Srrs		SCTP_STAT_INCR(sctps_recvauthfailed);
1641163953Srrs		return (-1);
1642163953Srrs	}
1643163953Srrs	SCTP_STAT_INCR(sctps_recvauth);
1644163953Srrs
1645163953Srrs	/* get the auth params */
1646163953Srrs	shared_key_id = ntohs(auth->shared_key_id);
1647163953Srrs	hmac_id = ntohs(auth->hmac_id);
1648169420Srrs	SCTPDBG(SCTP_DEBUG_AUTH1,
1649169420Srrs	    "SCTP AUTH Chunk: shared key %u, HMAC id %u\n",
1650169420Srrs	    shared_key_id, hmac_id);
1651163953Srrs
1652163953Srrs	/* is the indicated HMAC supported? */
1653163953Srrs	if (!sctp_auth_is_supported_hmac(stcb->asoc.local_hmacs, hmac_id)) {
1654163953Srrs		struct mbuf *m_err;
1655163953Srrs		struct sctp_auth_invalid_hmac *err;
1656163953Srrs
1657163953Srrs		SCTP_STAT_INCR(sctps_recvivalhmacid);
1658169420Srrs		SCTPDBG(SCTP_DEBUG_AUTH1,
1659169420Srrs		    "SCTP Auth: unsupported HMAC id %u\n",
1660169420Srrs		    hmac_id);
1661163953Srrs		/*
1662163953Srrs		 * report this in an Error Chunk: Unsupported HMAC
1663163953Srrs		 * Identifier
1664163953Srrs		 */
1665243882Sglebius		m_err = sctp_get_mbuf_for_msg(sizeof(*err), 0, M_NOWAIT,
1666169420Srrs		    1, MT_HEADER);
1667163953Srrs		if (m_err != NULL) {
1668163953Srrs			/* pre-reserve some space */
1669165647Srrs			SCTP_BUF_RESV_UF(m_err, sizeof(struct sctp_chunkhdr));
1670163953Srrs			/* fill in the error */
1671163953Srrs			err = mtod(m_err, struct sctp_auth_invalid_hmac *);
1672163953Srrs			bzero(err, sizeof(*err));
1673163953Srrs			err->ph.param_type = htons(SCTP_CAUSE_UNSUPPORTED_HMACID);
1674163953Srrs			err->ph.param_length = htons(sizeof(*err));
1675163953Srrs			err->hmac_id = ntohs(hmac_id);
1676165647Srrs			SCTP_BUF_LEN(m_err) = sizeof(*err);
1677163953Srrs			/* queue it */
1678163953Srrs			sctp_queue_op_err(stcb, m_err);
1679163953Srrs		}
1680163953Srrs		return (-1);
1681163953Srrs	}
1682163953Srrs	/* get the indicated shared key, if available */
1683163953Srrs	if ((stcb->asoc.authinfo.recv_key == NULL) ||
1684163953Srrs	    (stcb->asoc.authinfo.recv_keyid != shared_key_id)) {
1685163953Srrs		/* find the shared key on the assoc first */
1686185694Srrs		skey = sctp_find_sharedkey(&stcb->asoc.shared_keys,
1687185694Srrs		    shared_key_id);
1688163953Srrs		/* if the shared key isn't found, discard the chunk */
1689163953Srrs		if (skey == NULL) {
1690163953Srrs			SCTP_STAT_INCR(sctps_recvivalkeyid);
1691169420Srrs			SCTPDBG(SCTP_DEBUG_AUTH1,
1692169420Srrs			    "SCTP Auth: unknown key id %u\n",
1693169420Srrs			    shared_key_id);
1694163953Srrs			return (-1);
1695163953Srrs		}
1696163953Srrs		/* generate a notification if this is a new key id */
1697163953Srrs		if (stcb->asoc.authinfo.recv_keyid != shared_key_id)
1698163953Srrs			/*
1699163953Srrs			 * sctp_ulp_notify(SCTP_NOTIFY_AUTH_NEW_KEY, stcb,
1700163953Srrs			 * shared_key_id, (void
1701163953Srrs			 * *)stcb->asoc.authinfo.recv_keyid);
1702163953Srrs			 */
1703234699Stuexen			sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY,
1704185694Srrs			    shared_key_id, stcb->asoc.authinfo.recv_keyid,
1705185694Srrs			    SCTP_SO_NOT_LOCKED);
1706163953Srrs		/* compute a new recv assoc key and cache it */
1707163953Srrs		if (stcb->asoc.authinfo.recv_key != NULL)
1708163953Srrs			sctp_free_key(stcb->asoc.authinfo.recv_key);
1709163953Srrs		stcb->asoc.authinfo.recv_key =
1710163953Srrs		    sctp_compute_hashkey(stcb->asoc.authinfo.random,
1711163953Srrs		    stcb->asoc.authinfo.peer_random, skey->key);
1712163953Srrs		stcb->asoc.authinfo.recv_keyid = shared_key_id;
1713163953Srrs#ifdef SCTP_DEBUG
1714163953Srrs		if (SCTP_AUTH_DEBUG)
1715163953Srrs			sctp_print_key(stcb->asoc.authinfo.recv_key, "Recv Key");
1716163953Srrs#endif
1717163953Srrs	}
1718163953Srrs	/* validate the digest length */
1719163953Srrs	digestlen = sctp_get_hmac_digest_len(hmac_id);
1720163953Srrs	if (chunklen < (sizeof(*auth) + digestlen)) {
1721163953Srrs		/* invalid digest length */
1722163953Srrs		SCTP_STAT_INCR(sctps_recvauthfailed);
1723169420Srrs		SCTPDBG(SCTP_DEBUG_AUTH1,
1724169420Srrs		    "SCTP Auth: chunk too short for HMAC\n");
1725163953Srrs		return (-1);
1726163953Srrs	}
1727163953Srrs	/* save a copy of the digest, zero the pseudo header, and validate */
1728163953Srrs	bcopy(auth->hmac, digest, digestlen);
1729163953Srrs	sctp_bzero_m(m, offset + sizeof(*auth), SCTP_SIZE32(digestlen));
1730163953Srrs	(void)sctp_compute_hmac_m(hmac_id, stcb->asoc.authinfo.recv_key,
1731163953Srrs	    m, offset, computed_digest);
1732163953Srrs
1733163953Srrs	/* compare the computed digest with the one in the AUTH chunk */
1734163953Srrs	if (memcmp(digest, computed_digest, digestlen) != 0) {
1735163953Srrs		SCTP_STAT_INCR(sctps_recvauthfailed);
1736169420Srrs		SCTPDBG(SCTP_DEBUG_AUTH1,
1737169420Srrs		    "SCTP Auth: HMAC digest check failed\n");
1738163953Srrs		return (-1);
1739163953Srrs	}
1740163953Srrs	return (0);
1741163953Srrs}
1742163953Srrs
1743163953Srrs/*
1744163953Srrs * Generate NOTIFICATION
1745163953Srrs */
1746163953Srrsvoid
1747163953Srrssctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
1748185694Srrs    uint16_t keyid, uint16_t alt_keyid, int so_locked
1749185694Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
1750185694Srrs    SCTP_UNUSED
1751185694Srrs#endif
1752185694Srrs)
1753163953Srrs{
1754163953Srrs	struct mbuf *m_notify;
1755163953Srrs	struct sctp_authkey_event *auth;
1756163953Srrs	struct sctp_queued_to_read *control;
1757163953Srrs
1758175750Srrs	if ((stcb == NULL) ||
1759175750Srrs	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
1760175750Srrs	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1761175750Srrs	    (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)
1762175750Srrs	    ) {
1763175750Srrs		/* If the socket is gone we are out of here */
1764175750Srrs		return;
1765175750Srrs	}
1766223132Stuexen	if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_AUTHEVNT))
1767163953Srrs		/* event not enabled */
1768163953Srrs		return;
1769163953Srrs
1770163953Srrs	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_authkey_event),
1771243882Sglebius	    0, M_NOWAIT, 1, MT_HEADER);
1772163953Srrs	if (m_notify == NULL)
1773163953Srrs		/* no space left */
1774163953Srrs		return;
1775165647Srrs
1776165647Srrs	SCTP_BUF_LEN(m_notify) = 0;
1777163953Srrs	auth = mtod(m_notify, struct sctp_authkey_event *);
1778268432Sdelphij	memset(auth, 0, sizeof(struct sctp_authkey_event));
1779163953Srrs	auth->auth_type = SCTP_AUTHENTICATION_EVENT;
1780163953Srrs	auth->auth_flags = 0;
1781163953Srrs	auth->auth_length = sizeof(*auth);
1782163953Srrs	auth->auth_keynumber = keyid;
1783163953Srrs	auth->auth_altkeynumber = alt_keyid;
1784163953Srrs	auth->auth_indication = indication;
1785163953Srrs	auth->auth_assoc_id = sctp_get_associd(stcb);
1786163953Srrs
1787165647Srrs	SCTP_BUF_LEN(m_notify) = sizeof(*auth);
1788165647Srrs	SCTP_BUF_NEXT(m_notify) = NULL;
1789163953Srrs
1790163953Srrs	/* append to socket */
1791163953Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
1792228653Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0, m_notify);
1793163953Srrs	if (control == NULL) {
1794163953Srrs		/* no memory */
1795163953Srrs		sctp_m_freem(m_notify);
1796163953Srrs		return;
1797163953Srrs	}
1798165647Srrs	control->spec_flags = M_NOTIFICATION;
1799165647Srrs	control->length = SCTP_BUF_LEN(m_notify);
1800163953Srrs	/* not that we need this */
1801163953Srrs	control->tail_mbuf = m_notify;
1802163953Srrs	sctp_add_to_readq(stcb->sctp_ep, stcb, control,
1803195918Srrs	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
1804163953Srrs}
1805163953Srrs
1806163953Srrs
1807185694Srrs/*-
1808163953Srrs * validates the AUTHentication related parameters in an INIT/INIT-ACK
1809163953Srrs * Note: currently only used for INIT as INIT-ACK is handled inline
1810163953Srrs * with sctp_load_addresses_from_init()
1811163953Srrs */
1812163953Srrsint
1813163953Srrssctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
1814163953Srrs{
1815163953Srrs	struct sctp_paramhdr *phdr, parm_buf;
1816163953Srrs	uint16_t ptype, plen;
1817163953Srrs	int peer_supports_asconf = 0;
1818163953Srrs	int peer_supports_auth = 0;
1819168124Srrs	int got_random = 0, got_hmacs = 0, got_chklist = 0;
1820171990Srrs	uint8_t saw_asconf = 0;
1821171990Srrs	uint8_t saw_asconf_ack = 0;
1822163953Srrs
1823163953Srrs	/* go through each of the params. */
1824163953Srrs	phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
1825163953Srrs	while (phdr) {
1826163953Srrs		ptype = ntohs(phdr->param_type);
1827163953Srrs		plen = ntohs(phdr->param_length);
1828163953Srrs
1829163953Srrs		if (offset + plen > limit) {
1830163953Srrs			break;
1831163953Srrs		}
1832171990Srrs		if (plen < sizeof(struct sctp_paramhdr)) {
1833163953Srrs			break;
1834163953Srrs		}
1835163953Srrs		if (ptype == SCTP_SUPPORTED_CHUNK_EXT) {
1836163953Srrs			/* A supported extension chunk */
1837163953Srrs			struct sctp_supported_chunk_types_param *pr_supported;
1838166675Srrs			uint8_t local_store[SCTP_PARAM_BUFFER_SIZE];
1839163953Srrs			int num_ent, i;
1840163953Srrs
1841163953Srrs			phdr = sctp_get_next_param(m, offset,
1842169208Srrs			    (struct sctp_paramhdr *)&local_store, min(plen, sizeof(local_store)));
1843163953Srrs			if (phdr == NULL) {
1844163953Srrs				return (-1);
1845163953Srrs			}
1846163953Srrs			pr_supported = (struct sctp_supported_chunk_types_param *)phdr;
1847163953Srrs			num_ent = plen - sizeof(struct sctp_paramhdr);
1848163953Srrs			for (i = 0; i < num_ent; i++) {
1849163953Srrs				switch (pr_supported->chunk_types[i]) {
1850163953Srrs				case SCTP_ASCONF:
1851163953Srrs				case SCTP_ASCONF_ACK:
1852163953Srrs					peer_supports_asconf = 1;
1853163953Srrs					break;
1854163953Srrs				default:
1855163953Srrs					/* one we don't care about */
1856163953Srrs					break;
1857163953Srrs				}
1858163953Srrs			}
1859163953Srrs		} else if (ptype == SCTP_RANDOM) {
1860163953Srrs			got_random = 1;
1861163953Srrs			/* enforce the random length */
1862163953Srrs			if (plen != (sizeof(struct sctp_auth_random) +
1863163953Srrs			    SCTP_AUTH_RANDOM_SIZE_REQUIRED)) {
1864169420Srrs				SCTPDBG(SCTP_DEBUG_AUTH1,
1865169420Srrs				    "SCTP: invalid RANDOM len\n");
1866163953Srrs				return (-1);
1867163953Srrs			}
1868163953Srrs		} else if (ptype == SCTP_HMAC_LIST) {
1869166675Srrs			uint8_t store[SCTP_PARAM_BUFFER_SIZE];
1870163953Srrs			struct sctp_auth_hmac_algo *hmacs;
1871163953Srrs			int num_hmacs;
1872163953Srrs
1873163953Srrs			if (plen > sizeof(store))
1874163953Srrs				break;
1875163953Srrs			phdr = sctp_get_next_param(m, offset,
1876169208Srrs			    (struct sctp_paramhdr *)store, min(plen, sizeof(store)));
1877163953Srrs			if (phdr == NULL)
1878163953Srrs				return (-1);
1879163953Srrs			hmacs = (struct sctp_auth_hmac_algo *)phdr;
1880163953Srrs			num_hmacs = (plen - sizeof(*hmacs)) /
1881163953Srrs			    sizeof(hmacs->hmac_ids[0]);
1882163953Srrs			/* validate the hmac list */
1883163953Srrs			if (sctp_verify_hmac_param(hmacs, num_hmacs)) {
1884169420Srrs				SCTPDBG(SCTP_DEBUG_AUTH1,
1885169420Srrs				    "SCTP: invalid HMAC param\n");
1886163953Srrs				return (-1);
1887163953Srrs			}
1888163953Srrs			got_hmacs = 1;
1889168124Srrs		} else if (ptype == SCTP_CHUNK_LIST) {
1890171990Srrs			int i, num_chunks;
1891171990Srrs			uint8_t chunks_store[SCTP_SMALL_CHUNK_STORE];
1892171990Srrs
1893168124Srrs			/* did the peer send a non-empty chunk list? */
1894171990Srrs			struct sctp_auth_chunk_list *chunks = NULL;
1895171990Srrs
1896171990Srrs			phdr = sctp_get_next_param(m, offset,
1897171990Srrs			    (struct sctp_paramhdr *)chunks_store,
1898171990Srrs			    min(plen, sizeof(chunks_store)));
1899171990Srrs			if (phdr == NULL)
1900171990Srrs				return (-1);
1901171990Srrs
1902171990Srrs			/*-
1903171990Srrs			 * Flip through the list and mark that the
1904171990Srrs			 * peer supports asconf/asconf_ack.
1905171990Srrs			 */
1906171990Srrs			chunks = (struct sctp_auth_chunk_list *)phdr;
1907171990Srrs			num_chunks = plen - sizeof(*chunks);
1908171990Srrs			for (i = 0; i < num_chunks; i++) {
1909171990Srrs				/* record asconf/asconf-ack if listed */
1910171990Srrs				if (chunks->chunk_types[i] == SCTP_ASCONF)
1911171990Srrs					saw_asconf = 1;
1912171990Srrs				if (chunks->chunk_types[i] == SCTP_ASCONF_ACK)
1913171990Srrs					saw_asconf_ack = 1;
1914171990Srrs
1915171990Srrs			}
1916171990Srrs			if (num_chunks)
1917168124Srrs				got_chklist = 1;
1918163953Srrs		}
1919163953Srrs		offset += SCTP_SIZE32(plen);
1920163953Srrs		if (offset >= limit) {
1921163953Srrs			break;
1922163953Srrs		}
1923163953Srrs		phdr = sctp_get_next_param(m, offset, &parm_buf,
1924163953Srrs		    sizeof(parm_buf));
1925163953Srrs	}
1926163953Srrs	/* validate authentication required parameters */
1927163953Srrs	if (got_random && got_hmacs) {
1928163953Srrs		peer_supports_auth = 1;
1929163953Srrs	} else {
1930163953Srrs		peer_supports_auth = 0;
1931163953Srrs	}
1932168124Srrs	if (!peer_supports_auth && got_chklist) {
1933169420Srrs		SCTPDBG(SCTP_DEBUG_AUTH1,
1934169420Srrs		    "SCTP: peer sent chunk list w/o AUTH\n");
1935168124Srrs		return (-1);
1936168124Srrs	}
1937270355Stuexen	if (peer_supports_asconf && !peer_supports_auth) {
1938169420Srrs		SCTPDBG(SCTP_DEBUG_AUTH1,
1939169420Srrs		    "SCTP: peer supports ASCONF but not AUTH\n");
1940163953Srrs		return (-1);
1941171990Srrs	} else if ((peer_supports_asconf) && (peer_supports_auth) &&
1942171990Srrs	    ((saw_asconf == 0) || (saw_asconf_ack == 0))) {
1943171990Srrs		return (-2);
1944163953Srrs	}
1945163953Srrs	return (0);
1946163953Srrs}
1947163953Srrs
1948163953Srrsvoid
1949163953Srrssctp_initialize_auth_params(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
1950163953Srrs{
1951163953Srrs	uint16_t chunks_len = 0;
1952163953Srrs	uint16_t hmacs_len = 0;
1953167598Srrs	uint16_t random_len = SCTP_AUTH_RANDOM_SIZE_DEFAULT;
1954163953Srrs	sctp_key_t *new_key;
1955163953Srrs	uint16_t keylen;
1956163953Srrs
1957163953Srrs	/* initialize hmac list from endpoint */
1958163953Srrs	stcb->asoc.local_hmacs = sctp_copy_hmaclist(inp->sctp_ep.local_hmacs);
1959163953Srrs	if (stcb->asoc.local_hmacs != NULL) {
1960163953Srrs		hmacs_len = stcb->asoc.local_hmacs->num_algo *
1961163953Srrs		    sizeof(stcb->asoc.local_hmacs->hmac[0]);
1962163953Srrs	}
1963163953Srrs	/* initialize auth chunks list from endpoint */
1964163953Srrs	stcb->asoc.local_auth_chunks =
1965163953Srrs	    sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks);
1966163953Srrs	if (stcb->asoc.local_auth_chunks != NULL) {
1967163953Srrs		int i;
1968163953Srrs
1969163953Srrs		for (i = 0; i < 256; i++) {
1970163953Srrs			if (stcb->asoc.local_auth_chunks->chunks[i])
1971163953Srrs				chunks_len++;
1972163953Srrs		}
1973163953Srrs	}
1974163953Srrs	/* copy defaults from the endpoint */
1975185694Srrs	stcb->asoc.authinfo.active_keyid = inp->sctp_ep.default_keyid;
1976163953Srrs
1977185694Srrs	/* copy out the shared key list (by reference) from the endpoint */
1978185694Srrs	(void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys,
1979185694Srrs	    &stcb->asoc.shared_keys);
1980185694Srrs
1981163953Srrs	/* now set the concatenated key (random + chunks + hmacs) */
1982166675Srrs	/* key includes parameter headers */
1983166675Srrs	keylen = (3 * sizeof(struct sctp_paramhdr)) + random_len + chunks_len +
1984166675Srrs	    hmacs_len;
1985163953Srrs	new_key = sctp_alloc_key(keylen);
1986163953Srrs	if (new_key != NULL) {
1987166675Srrs		struct sctp_paramhdr *ph;
1988166675Srrs		int plen;
1989166675Srrs
1990163953Srrs		/* generate and copy in the RANDOM */
1991166675Srrs		ph = (struct sctp_paramhdr *)new_key->key;
1992166675Srrs		ph->param_type = htons(SCTP_RANDOM);
1993166675Srrs		plen = sizeof(*ph) + random_len;
1994166675Srrs		ph->param_length = htons(plen);
1995166675Srrs		SCTP_READ_RANDOM(new_key->key + sizeof(*ph), random_len);
1996166675Srrs		keylen = plen;
1997166675Srrs
1998163953Srrs		/* append in the AUTH chunks */
1999166675Srrs		/* NOTE: currently we always have chunks to list */
2000166675Srrs		ph = (struct sctp_paramhdr *)(new_key->key + keylen);
2001166675Srrs		ph->param_type = htons(SCTP_CHUNK_LIST);
2002166675Srrs		plen = sizeof(*ph) + chunks_len;
2003166675Srrs		ph->param_length = htons(plen);
2004166675Srrs		keylen += sizeof(*ph);
2005163953Srrs		if (stcb->asoc.local_auth_chunks) {
2006163953Srrs			int i;
2007163953Srrs
2008163953Srrs			for (i = 0; i < 256; i++) {
2009163953Srrs				if (stcb->asoc.local_auth_chunks->chunks[i])
2010163953Srrs					new_key->key[keylen++] = i;
2011163953Srrs			}
2012163953Srrs		}
2013163953Srrs		/* append in the HMACs */
2014166675Srrs		ph = (struct sctp_paramhdr *)(new_key->key + keylen);
2015166675Srrs		ph->param_type = htons(SCTP_HMAC_LIST);
2016166675Srrs		plen = sizeof(*ph) + hmacs_len;
2017166675Srrs		ph->param_length = htons(plen);
2018166675Srrs		keylen += sizeof(*ph);
2019169420Srrs		(void)sctp_serialize_hmaclist(stcb->asoc.local_hmacs,
2020163953Srrs		    new_key->key + keylen);
2021163953Srrs	}
2022163953Srrs	if (stcb->asoc.authinfo.random != NULL)
2023163953Srrs		sctp_free_key(stcb->asoc.authinfo.random);
2024163953Srrs	stcb->asoc.authinfo.random = new_key;
2025163953Srrs	stcb->asoc.authinfo.random_len = random_len;
2026163953Srrs}
2027