netwerk/sctp/src/netinet/sctp_auth.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/sctp/src/netinet/sctp_auth.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2351 @@
     1.4 +/*-
     1.5 + * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
     1.6 + * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
     1.7 + * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
     1.8 + *
     1.9 + * Redistribution and use in source and binary forms, with or without
    1.10 + * modification, are permitted provided that the following conditions are met:
    1.11 + *
    1.12 + * a) Redistributions of source code must retain the above copyright notice,
    1.13 + *    this list of conditions and the following disclaimer.
    1.14 + *
    1.15 + * b) Redistributions in binary form must reproduce the above copyright
    1.16 + *    notice, this list of conditions and the following disclaimer in
    1.17 + *    the documentation and/or other materials provided with the distribution.
    1.18 + *
    1.19 + * c) Neither the name of Cisco Systems, Inc. nor the names of its
    1.20 + *    contributors may be used to endorse or promote products derived
    1.21 + *    from this software without specific prior written permission.
    1.22 + *
    1.23 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.24 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    1.25 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    1.26 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    1.27 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    1.28 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    1.29 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    1.30 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    1.31 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    1.32 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
    1.33 + * THE POSSIBILITY OF SUCH DAMAGE.
    1.34 + */
    1.35 +
    1.36 +#ifdef __FreeBSD__
    1.37 +#include <sys/cdefs.h>
    1.38 +__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.c 257804 2013-11-07 18:50:11Z tuexen $");
    1.39 +#endif
    1.40 +
    1.41 +#include <netinet/sctp_os.h>
    1.42 +#include <netinet/sctp.h>
    1.43 +#include <netinet/sctp_header.h>
    1.44 +#include <netinet/sctp_pcb.h>
    1.45 +#include <netinet/sctp_var.h>
    1.46 +#include <netinet/sctp_sysctl.h>
    1.47 +#include <netinet/sctputil.h>
    1.48 +#include <netinet/sctp_indata.h>
    1.49 +#include <netinet/sctp_output.h>
    1.50 +#include <netinet/sctp_auth.h>
    1.51 +
    1.52 +#ifdef SCTP_DEBUG
    1.53 +#define SCTP_AUTH_DEBUG		(SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_AUTH1)
    1.54 +#define SCTP_AUTH_DEBUG2	(SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_AUTH2)
    1.55 +#endif /* SCTP_DEBUG */
    1.56 +
    1.57 +
    1.58 +void
    1.59 +sctp_clear_chunklist(sctp_auth_chklist_t *chklist)
    1.60 +{
    1.61 +	bzero(chklist, sizeof(*chklist));
    1.62 +	/* chklist->num_chunks = 0; */
    1.63 +}
    1.64 +
    1.65 +sctp_auth_chklist_t *
    1.66 +sctp_alloc_chunklist(void)
    1.67 +{
    1.68 +	sctp_auth_chklist_t *chklist;
    1.69 +
    1.70 +	SCTP_MALLOC(chklist, sctp_auth_chklist_t *, sizeof(*chklist),
    1.71 +		    SCTP_M_AUTH_CL);
    1.72 +	if (chklist == NULL) {
    1.73 +		SCTPDBG(SCTP_DEBUG_AUTH1, "sctp_alloc_chunklist: failed to get memory!\n");
    1.74 +	} else {
    1.75 +		sctp_clear_chunklist(chklist);
    1.76 +	}
    1.77 +	return (chklist);
    1.78 +}
    1.79 +
    1.80 +void
    1.81 +sctp_free_chunklist(sctp_auth_chklist_t *list)
    1.82 +{
    1.83 +	if (list != NULL)
    1.84 +		SCTP_FREE(list, SCTP_M_AUTH_CL);
    1.85 +}
    1.86 +
    1.87 +sctp_auth_chklist_t *
    1.88 +sctp_copy_chunklist(sctp_auth_chklist_t *list)
    1.89 +{
    1.90 +	sctp_auth_chklist_t *new_list;
    1.91 +
    1.92 +	if (list == NULL)
    1.93 +		return (NULL);
    1.94 +
    1.95 +	/* get a new list */
    1.96 +	new_list = sctp_alloc_chunklist();
    1.97 +	if (new_list == NULL)
    1.98 +		return (NULL);
    1.99 +	/* copy it */
   1.100 +	bcopy(list, new_list, sizeof(*new_list));
   1.101 +
   1.102 +	return (new_list);
   1.103 +}
   1.104 +
   1.105 +
   1.106 +/*
   1.107 + * add a chunk to the required chunks list
   1.108 + */
   1.109 +int
   1.110 +sctp_auth_add_chunk(uint8_t chunk, sctp_auth_chklist_t *list)
   1.111 +{
   1.112 +	if (list == NULL)
   1.113 +		return (-1);
   1.114 +
   1.115 +	/* is chunk restricted? */
   1.116 +	if ((chunk == SCTP_INITIATION) ||
   1.117 +	    (chunk == SCTP_INITIATION_ACK) ||
   1.118 +	    (chunk == SCTP_SHUTDOWN_COMPLETE) ||
   1.119 +	    (chunk == SCTP_AUTHENTICATION)) {
   1.120 +		return (-1);
   1.121 +	}
   1.122 +	if (list->chunks[chunk] == 0) {
   1.123 +		list->chunks[chunk] = 1;
   1.124 +		list->num_chunks++;
   1.125 +		SCTPDBG(SCTP_DEBUG_AUTH1,
   1.126 +			"SCTP: added chunk %u (0x%02x) to Auth list\n",
   1.127 +			chunk, chunk);
   1.128 +	}
   1.129 +	return (0);
   1.130 +}
   1.131 +
   1.132 +/*
   1.133 + * delete a chunk from the required chunks list
   1.134 + */
   1.135 +int
   1.136 +sctp_auth_delete_chunk(uint8_t chunk, sctp_auth_chklist_t *list)
   1.137 +{
   1.138 +	if (list == NULL)
   1.139 +		return (-1);
   1.140 +
   1.141 +	/* is chunk restricted? */
   1.142 +	if ((chunk == SCTP_ASCONF) ||
   1.143 +	    (chunk == SCTP_ASCONF_ACK)) {
   1.144 +		return (-1);
   1.145 +	}
   1.146 +	if (list->chunks[chunk] == 1) {
   1.147 +		list->chunks[chunk] = 0;
   1.148 +		list->num_chunks--;
   1.149 +		SCTPDBG(SCTP_DEBUG_AUTH1,
   1.150 +			"SCTP: deleted chunk %u (0x%02x) from Auth list\n",
   1.151 +			chunk, chunk);
   1.152 +	}
   1.153 +	return (0);
   1.154 +}
   1.155 +
   1.156 +size_t
   1.157 +sctp_auth_get_chklist_size(const sctp_auth_chklist_t *list)
   1.158 +{
   1.159 +	if (list == NULL)
   1.160 +		return (0);
   1.161 +	else
   1.162 +		return (list->num_chunks);
   1.163 +}
   1.164 +
   1.165 +/*
   1.166 + * set the default list of chunks requiring AUTH
   1.167 + */
   1.168 +void
   1.169 +sctp_auth_set_default_chunks(sctp_auth_chklist_t *list)
   1.170 +{
   1.171 +	(void)sctp_auth_add_chunk(SCTP_ASCONF, list);
   1.172 +	(void)sctp_auth_add_chunk(SCTP_ASCONF_ACK, list);
   1.173 +}
   1.174 +
   1.175 +/*
   1.176 + * return the current number and list of required chunks caller must
   1.177 + * guarantee ptr has space for up to 256 bytes
   1.178 + */
   1.179 +int
   1.180 +sctp_serialize_auth_chunks(const sctp_auth_chklist_t *list, uint8_t *ptr)
   1.181 +{
   1.182 +	int i, count = 0;
   1.183 +
   1.184 +	if (list == NULL)
   1.185 +		return (0);
   1.186 +
   1.187 +	for (i = 0; i < 256; i++) {
   1.188 +		if (list->chunks[i] != 0) {
   1.189 +			*ptr++ = i;
   1.190 +			count++;
   1.191 +		}
   1.192 +	}
   1.193 +	return (count);
   1.194 +}
   1.195 +
   1.196 +int
   1.197 +sctp_pack_auth_chunks(const sctp_auth_chklist_t *list, uint8_t *ptr)
   1.198 +{
   1.199 +	int i, size = 0;
   1.200 +
   1.201 +	if (list == NULL)
   1.202 +		return (0);
   1.203 +
   1.204 +	if (list->num_chunks <= 32) {
   1.205 +		/* just list them, one byte each */
   1.206 +		for (i = 0; i < 256; i++) {
   1.207 +			if (list->chunks[i] != 0) {
   1.208 +				*ptr++ = i;
   1.209 +				size++;
   1.210 +			}
   1.211 +		}
   1.212 +	} else {
   1.213 +		int index, offset;
   1.214 +
   1.215 +		/* pack into a 32 byte bitfield */
   1.216 +		for (i = 0; i < 256; i++) {
   1.217 +			if (list->chunks[i] != 0) {
   1.218 +				index = i / 8;
   1.219 +				offset = i % 8;
   1.220 +				ptr[index] |= (1 << offset);
   1.221 +			}
   1.222 +		}
   1.223 +		size = 32;
   1.224 +	}
   1.225 +	return (size);
   1.226 +}
   1.227 +
   1.228 +int
   1.229 +sctp_unpack_auth_chunks(const uint8_t *ptr, uint8_t num_chunks,
   1.230 +    sctp_auth_chklist_t *list)
   1.231 +{
   1.232 +	int i;
   1.233 +	int size;
   1.234 +
   1.235 +	if (list == NULL)
   1.236 +		return (0);
   1.237 +
   1.238 +	if (num_chunks <= 32) {
   1.239 +		/* just pull them, one byte each */
   1.240 +		for (i = 0; i < num_chunks; i++) {
   1.241 +			(void)sctp_auth_add_chunk(*ptr++, list);
   1.242 +		}
   1.243 +		size = num_chunks;
   1.244 +	} else {
   1.245 +		int index, offset;
   1.246 +
   1.247 +		/* unpack from a 32 byte bitfield */
   1.248 +		for (index = 0; index < 32; index++) {
   1.249 +			for (offset = 0; offset < 8; offset++) {
   1.250 +				if (ptr[index] & (1 << offset)) {
   1.251 +					(void)sctp_auth_add_chunk((index * 8) + offset, list);
   1.252 +				}
   1.253 +			}
   1.254 +		}
   1.255 +		size = 32;
   1.256 +	}
   1.257 +	return (size);
   1.258 +}
   1.259 +
   1.260 +
   1.261 +/*
   1.262 + * allocate structure space for a key of length keylen
   1.263 + */
   1.264 +sctp_key_t *
   1.265 +sctp_alloc_key(uint32_t keylen)
   1.266 +{
   1.267 +	sctp_key_t *new_key;
   1.268 +
   1.269 +	SCTP_MALLOC(new_key, sctp_key_t *, sizeof(*new_key) + keylen,
   1.270 +		    SCTP_M_AUTH_KY);
   1.271 +	if (new_key == NULL) {
   1.272 +		/* out of memory */
   1.273 +		return (NULL);
   1.274 +	}
   1.275 +	new_key->keylen = keylen;
   1.276 +	return (new_key);
   1.277 +}
   1.278 +
   1.279 +void
   1.280 +sctp_free_key(sctp_key_t *key)
   1.281 +{
   1.282 +	if (key != NULL)
   1.283 +		SCTP_FREE(key,SCTP_M_AUTH_KY);
   1.284 +}
   1.285 +
   1.286 +void
   1.287 +sctp_print_key(sctp_key_t *key, const char *str)
   1.288 +{
   1.289 +	uint32_t i;
   1.290 +
   1.291 +	if (key == NULL) {
   1.292 +		SCTP_PRINTF("%s: [Null key]\n", str);
   1.293 +		return;
   1.294 +	}
   1.295 +	SCTP_PRINTF("%s: len %u, ", str, key->keylen);
   1.296 +	if (key->keylen) {
   1.297 +		for (i = 0; i < key->keylen; i++)
   1.298 +			SCTP_PRINTF("%02x", key->key[i]);
   1.299 +		SCTP_PRINTF("\n");
   1.300 +	} else {
   1.301 +		SCTP_PRINTF("[Null key]\n");
   1.302 +	}
   1.303 +}
   1.304 +
   1.305 +void
   1.306 +sctp_show_key(sctp_key_t *key, const char *str)
   1.307 +{
   1.308 +	uint32_t i;
   1.309 +
   1.310 +	if (key == NULL) {
   1.311 +		SCTP_PRINTF("%s: [Null key]\n", str);
   1.312 +		return;
   1.313 +	}
   1.314 +	SCTP_PRINTF("%s: len %u, ", str, key->keylen);
   1.315 +	if (key->keylen) {
   1.316 +		for (i = 0; i < key->keylen; i++)
   1.317 +			SCTP_PRINTF("%02x", key->key[i]);
   1.318 +		SCTP_PRINTF("\n");
   1.319 +	} else {
   1.320 +		SCTP_PRINTF("[Null key]\n");
   1.321 +	}
   1.322 +}
   1.323 +
   1.324 +static uint32_t
   1.325 +sctp_get_keylen(sctp_key_t *key)
   1.326 +{
   1.327 +	if (key != NULL)
   1.328 +		return (key->keylen);
   1.329 +	else
   1.330 +		return (0);
   1.331 +}
   1.332 +
   1.333 +/*
   1.334 + * generate a new random key of length 'keylen'
   1.335 + */
   1.336 +sctp_key_t *
   1.337 +sctp_generate_random_key(uint32_t keylen)
   1.338 +{
   1.339 +	sctp_key_t *new_key;
   1.340 +
   1.341 +	new_key = sctp_alloc_key(keylen);
   1.342 +	if (new_key == NULL) {
   1.343 +		/* out of memory */
   1.344 +		return (NULL);
   1.345 +	}
   1.346 +	SCTP_READ_RANDOM(new_key->key, keylen);
   1.347 +	new_key->keylen = keylen;
   1.348 +	return (new_key);
   1.349 +}
   1.350 +
   1.351 +sctp_key_t *
   1.352 +sctp_set_key(uint8_t *key, uint32_t keylen)
   1.353 +{
   1.354 +	sctp_key_t *new_key;
   1.355 +
   1.356 +	new_key = sctp_alloc_key(keylen);
   1.357 +	if (new_key == NULL) {
   1.358 +		/* out of memory */
   1.359 +		return (NULL);
   1.360 +	}
   1.361 +	bcopy(key, new_key->key, keylen);
   1.362 +	return (new_key);
   1.363 +}
   1.364 +
   1.365 +/*-
   1.366 + * given two keys of variable size, compute which key is "larger/smaller"
   1.367 + * returns:  1 if key1 > key2
   1.368 + *          -1 if key1 < key2
   1.369 + *           0 if key1 = key2
   1.370 + */
   1.371 +static int
   1.372 +sctp_compare_key(sctp_key_t *key1, sctp_key_t *key2)
   1.373 +{
   1.374 +	uint32_t maxlen;
   1.375 +	uint32_t i;
   1.376 +	uint32_t key1len, key2len;
   1.377 +	uint8_t *key_1, *key_2;
   1.378 +	uint8_t val1, val2;
   1.379 +
   1.380 +	/* sanity/length check */
   1.381 +	key1len = sctp_get_keylen(key1);
   1.382 +	key2len = sctp_get_keylen(key2);
   1.383 +	if ((key1len == 0) && (key2len == 0))
   1.384 +		return (0);
   1.385 +	else if (key1len == 0)
   1.386 +		return (-1);
   1.387 +	else if (key2len == 0)
   1.388 +		return (1);
   1.389 +
   1.390 +	if (key1len < key2len) {
   1.391 +		maxlen = key2len;
   1.392 +	} else {
   1.393 +		maxlen = key1len;
   1.394 +	}
   1.395 +	key_1 = key1->key;
   1.396 +	key_2 = key2->key;
   1.397 +	/* check for numeric equality */
   1.398 +	for (i = 0; i < maxlen; i++) {
   1.399 +		/* left-pad with zeros */
   1.400 +		val1 = (i < (maxlen - key1len)) ? 0 : *(key_1++);
   1.401 +		val2 = (i < (maxlen - key2len)) ? 0 : *(key_2++);
   1.402 +		if (val1 > val2) {
   1.403 + 			return (1);
   1.404 +		} else if (val1 < val2) {
   1.405 + 			return (-1);
   1.406 +		}
   1.407 +	}
   1.408 +	/* keys are equal value, so check lengths */
   1.409 +	if (key1len == key2len)
   1.410 +		return (0);
   1.411 +	else if (key1len < key2len)
   1.412 +		return (-1);
   1.413 +	else
   1.414 +		return (1);
   1.415 +}
   1.416 +
   1.417 +/*
   1.418 + * generate the concatenated keying material based on the two keys and the
   1.419 + * shared key (if available). draft-ietf-tsvwg-auth specifies the specific
   1.420 + * order for concatenation
   1.421 + */
   1.422 +sctp_key_t *
   1.423 +sctp_compute_hashkey(sctp_key_t *key1, sctp_key_t *key2, sctp_key_t *shared)
   1.424 +{
   1.425 +	uint32_t keylen;
   1.426 +	sctp_key_t *new_key;
   1.427 +	uint8_t *key_ptr;
   1.428 +
   1.429 +	keylen = sctp_get_keylen(key1) + sctp_get_keylen(key2) +
   1.430 +	    sctp_get_keylen(shared);
   1.431 +
   1.432 +	if (keylen > 0) {
   1.433 +		/* get space for the new key */
   1.434 +		new_key = sctp_alloc_key(keylen);
   1.435 +		if (new_key == NULL) {
   1.436 +			/* out of memory */
   1.437 +			return (NULL);
   1.438 +		}
   1.439 +		new_key->keylen = keylen;
   1.440 +		key_ptr = new_key->key;
   1.441 +	} else {
   1.442 +		/* all keys empty/null?! */
   1.443 +		return (NULL);
   1.444 +	}
   1.445 +
   1.446 +	/* concatenate the keys */
   1.447 +	if (sctp_compare_key(key1, key2) <= 0) {
   1.448 +		/* key is shared + key1 + key2 */
   1.449 +		if (sctp_get_keylen(shared)) {
   1.450 +			bcopy(shared->key, key_ptr, shared->keylen);
   1.451 +			key_ptr += shared->keylen;
   1.452 +		}
   1.453 +		if (sctp_get_keylen(key1)) {
   1.454 +			bcopy(key1->key, key_ptr, key1->keylen);
   1.455 +			key_ptr += key1->keylen;
   1.456 +		}
   1.457 +		if (sctp_get_keylen(key2)) {
   1.458 +			bcopy(key2->key, key_ptr, key2->keylen);
   1.459 +		}
   1.460 +	} else {
   1.461 +		/* key is shared + key2 + key1 */
   1.462 +		if (sctp_get_keylen(shared)) {
   1.463 +			bcopy(shared->key, key_ptr, shared->keylen);
   1.464 +			key_ptr += shared->keylen;
   1.465 +		}
   1.466 +		if (sctp_get_keylen(key2)) {
   1.467 +			bcopy(key2->key, key_ptr, key2->keylen);
   1.468 +			key_ptr += key2->keylen;
   1.469 +		}
   1.470 +		if (sctp_get_keylen(key1)) {
   1.471 +			bcopy(key1->key, key_ptr, key1->keylen);
   1.472 +		}
   1.473 +	}
   1.474 +	return (new_key);
   1.475 +}
   1.476 +
   1.477 +
   1.478 +sctp_sharedkey_t *
   1.479 +sctp_alloc_sharedkey(void)
   1.480 +{
   1.481 +	sctp_sharedkey_t *new_key;
   1.482 +
   1.483 +	SCTP_MALLOC(new_key, sctp_sharedkey_t *, sizeof(*new_key),
   1.484 +		    SCTP_M_AUTH_KY);
   1.485 +	if (new_key == NULL) {
   1.486 +		/* out of memory */
   1.487 +		return (NULL);
   1.488 +	}
   1.489 +	new_key->keyid = 0;
   1.490 +	new_key->key = NULL;
   1.491 +	new_key->refcount = 1;
   1.492 +	new_key->deactivated = 0;
   1.493 +	return (new_key);
   1.494 +}
   1.495 +
   1.496 +void
   1.497 +sctp_free_sharedkey(sctp_sharedkey_t *skey)
   1.498 +{
   1.499 +	if (skey == NULL)
   1.500 +		return;
   1.501 +
   1.502 +	if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&skey->refcount)) {
   1.503 +		if (skey->key != NULL)
   1.504 +			sctp_free_key(skey->key);
   1.505 +		SCTP_FREE(skey, SCTP_M_AUTH_KY);
   1.506 +	}
   1.507 +}
   1.508 +
   1.509 +sctp_sharedkey_t *
   1.510 +sctp_find_sharedkey(struct sctp_keyhead *shared_keys, uint16_t key_id)
   1.511 +{
   1.512 +	sctp_sharedkey_t *skey;
   1.513 +
   1.514 +	LIST_FOREACH(skey, shared_keys, next) {
   1.515 +		if (skey->keyid == key_id)
   1.516 +			return (skey);
   1.517 +	}
   1.518 +	return (NULL);
   1.519 +}
   1.520 +
   1.521 +int
   1.522 +sctp_insert_sharedkey(struct sctp_keyhead *shared_keys,
   1.523 +		      sctp_sharedkey_t *new_skey)
   1.524 +{
   1.525 +	sctp_sharedkey_t *skey;
   1.526 +
   1.527 +	if ((shared_keys == NULL) || (new_skey == NULL))
   1.528 +		return (EINVAL);
   1.529 +
   1.530 +	/* insert into an empty list? */
   1.531 +	if (LIST_EMPTY(shared_keys)) {
   1.532 +		LIST_INSERT_HEAD(shared_keys, new_skey, next);
   1.533 +		return (0);
   1.534 +	}
   1.535 +	/* insert into the existing list, ordered by key id */
   1.536 +	LIST_FOREACH(skey, shared_keys, next) {
   1.537 +		if (new_skey->keyid < skey->keyid) {
   1.538 +			/* insert it before here */
   1.539 +			LIST_INSERT_BEFORE(skey, new_skey, next);
   1.540 +			return (0);
   1.541 +		} else if (new_skey->keyid == skey->keyid) {
   1.542 +			/* replace the existing key */
   1.543 +			/* verify this key *can* be replaced */
   1.544 +			if ((skey->deactivated) && (skey->refcount > 1)) {
   1.545 +				SCTPDBG(SCTP_DEBUG_AUTH1,
   1.546 +					"can't replace shared key id %u\n",
   1.547 +					new_skey->keyid);
   1.548 +				return (EBUSY);
   1.549 +			}
   1.550 +			SCTPDBG(SCTP_DEBUG_AUTH1,
   1.551 +				"replacing shared key id %u\n",
   1.552 +				new_skey->keyid);
   1.553 +			LIST_INSERT_BEFORE(skey, new_skey, next);
   1.554 +			LIST_REMOVE(skey, next);
   1.555 +			sctp_free_sharedkey(skey);
   1.556 +			return (0);
   1.557 +		}
   1.558 +		if (LIST_NEXT(skey, next) == NULL) {
   1.559 +			/* belongs at the end of the list */
   1.560 +			LIST_INSERT_AFTER(skey, new_skey, next);
   1.561 +			return (0);
   1.562 +		}
   1.563 +	}
   1.564 +	/* shouldn't reach here */
   1.565 +	return (0);
   1.566 +}
   1.567 +
   1.568 +void
   1.569 +sctp_auth_key_acquire(struct sctp_tcb *stcb, uint16_t key_id)
   1.570 +{
   1.571 +	sctp_sharedkey_t *skey;
   1.572 +
   1.573 +	/* find the shared key */
   1.574 +	skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, key_id);
   1.575 +
   1.576 +	/* bump the ref count */
   1.577 +	if (skey) {
   1.578 +		atomic_add_int(&skey->refcount, 1);
   1.579 +		SCTPDBG(SCTP_DEBUG_AUTH2,
   1.580 +			"%s: stcb %p key %u refcount acquire to %d\n",
   1.581 +			__FUNCTION__, (void *)stcb, key_id, skey->refcount);
   1.582 +	}
   1.583 +}
   1.584 +
   1.585 +void
   1.586 +sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t key_id, int so_locked
   1.587 +#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
   1.588 +	SCTP_UNUSED
   1.589 +#endif
   1.590 +)
   1.591 +{
   1.592 +	sctp_sharedkey_t *skey;
   1.593 +
   1.594 +	/* find the shared key */
   1.595 +	skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, key_id);
   1.596 +
   1.597 +	/* decrement the ref count */
   1.598 +	if (skey) {
   1.599 +		sctp_free_sharedkey(skey);
   1.600 +		SCTPDBG(SCTP_DEBUG_AUTH2,
   1.601 +			"%s: stcb %p key %u refcount release to %d\n",
   1.602 +			__FUNCTION__, (void *)stcb, key_id, skey->refcount);
   1.603 +
   1.604 +		/* see if a notification should be generated */
   1.605 +		if ((skey->refcount <= 1) && (skey->deactivated)) {
   1.606 +			/* notify ULP that key is no longer used */
   1.607 +			sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb,
   1.608 +					key_id, 0, so_locked);
   1.609 +			SCTPDBG(SCTP_DEBUG_AUTH2,
   1.610 +				"%s: stcb %p key %u no longer used, %d\n",
   1.611 +				__FUNCTION__, (void *)stcb, key_id, skey->refcount);
   1.612 +		}
   1.613 +	}
   1.614 +}
   1.615 +
   1.616 +static sctp_sharedkey_t *
   1.617 +sctp_copy_sharedkey(const sctp_sharedkey_t *skey)
   1.618 +{
   1.619 +	sctp_sharedkey_t *new_skey;
   1.620 +
   1.621 +	if (skey == NULL)
   1.622 +		return (NULL);
   1.623 +	new_skey = sctp_alloc_sharedkey();
   1.624 +	if (new_skey == NULL)
   1.625 +		return (NULL);
   1.626 +	if (skey->key != NULL)
   1.627 +		new_skey->key = sctp_set_key(skey->key->key, skey->key->keylen);
   1.628 +	else
   1.629 +		new_skey->key = NULL;
   1.630 +	new_skey->keyid = skey->keyid;
   1.631 +	return (new_skey);
   1.632 +}
   1.633 +
   1.634 +int
   1.635 +sctp_copy_skeylist(const struct sctp_keyhead *src, struct sctp_keyhead *dest)
   1.636 +{
   1.637 +	sctp_sharedkey_t *skey, *new_skey;
   1.638 +	int count = 0;
   1.639 +
   1.640 +	if ((src == NULL) || (dest == NULL))
   1.641 +		return (0);
   1.642 +	LIST_FOREACH(skey, src, next) {
   1.643 +		new_skey = sctp_copy_sharedkey(skey);
   1.644 +		if (new_skey != NULL) {
   1.645 +			(void)sctp_insert_sharedkey(dest, new_skey);
   1.646 +			count++;
   1.647 +		}
   1.648 +	}
   1.649 +	return (count);
   1.650 +}
   1.651 +
   1.652 +
   1.653 +sctp_hmaclist_t *
   1.654 +sctp_alloc_hmaclist(uint8_t num_hmacs)
   1.655 +{
   1.656 +	sctp_hmaclist_t *new_list;
   1.657 +	int alloc_size;
   1.658 +
   1.659 +	alloc_size = sizeof(*new_list) + num_hmacs * sizeof(new_list->hmac[0]);
   1.660 +	SCTP_MALLOC(new_list, sctp_hmaclist_t *, alloc_size,
   1.661 +		    SCTP_M_AUTH_HL);
   1.662 +	if (new_list == NULL) {
   1.663 +		/* out of memory */
   1.664 +		return (NULL);
   1.665 +	}
   1.666 +	new_list->max_algo = num_hmacs;
   1.667 +	new_list->num_algo = 0;
   1.668 +	return (new_list);
   1.669 +}
   1.670 +
   1.671 +void
   1.672 +sctp_free_hmaclist(sctp_hmaclist_t *list)
   1.673 +{
   1.674 +	if (list != NULL) {
   1.675 +		SCTP_FREE(list,SCTP_M_AUTH_HL);
   1.676 +		list = NULL;
   1.677 +	}
   1.678 +}
   1.679 +
   1.680 +int
   1.681 +sctp_auth_add_hmacid(sctp_hmaclist_t *list, uint16_t hmac_id)
   1.682 +{
   1.683 +	int i;
   1.684 +	if (list == NULL)
   1.685 +		return (-1);
   1.686 +	if (list->num_algo == list->max_algo) {
   1.687 +		SCTPDBG(SCTP_DEBUG_AUTH1,
   1.688 +			"SCTP: HMAC id list full, ignoring add %u\n", hmac_id);
   1.689 +		return (-1);
   1.690 +	}
   1.691 +#if defined(SCTP_SUPPORT_HMAC_SHA256)
   1.692 +	if ((hmac_id != SCTP_AUTH_HMAC_ID_SHA1) &&
   1.693 +	    (hmac_id != SCTP_AUTH_HMAC_ID_SHA256)) {
   1.694 +#else
   1.695 +	if (hmac_id != SCTP_AUTH_HMAC_ID_SHA1) {
   1.696 +#endif
   1.697 +		return (-1);
   1.698 +	}
   1.699 +	/* Now is it already in the list */
   1.700 +	for (i = 0; i < list->num_algo; i++) {
   1.701 +		if (list->hmac[i] == hmac_id) {
   1.702 +			/* already in list */
   1.703 +			return (-1);
   1.704 +		}
   1.705 +	}
   1.706 +	SCTPDBG(SCTP_DEBUG_AUTH1, "SCTP: add HMAC id %u to list\n", hmac_id);
   1.707 +	list->hmac[list->num_algo++] = hmac_id;
   1.708 +	return (0);
   1.709 +}
   1.710 +
   1.711 +sctp_hmaclist_t *
   1.712 +sctp_copy_hmaclist(sctp_hmaclist_t *list)
   1.713 +{
   1.714 +	sctp_hmaclist_t *new_list;
   1.715 +	int i;
   1.716 +
   1.717 +	if (list == NULL)
   1.718 +		return (NULL);
   1.719 +	/* get a new list */
   1.720 +	new_list = sctp_alloc_hmaclist(list->max_algo);
   1.721 +	if (new_list == NULL)
   1.722 +		return (NULL);
   1.723 +	/* copy it */
   1.724 +	new_list->max_algo = list->max_algo;
   1.725 +	new_list->num_algo = list->num_algo;
   1.726 +	for (i = 0; i < list->num_algo; i++)
   1.727 +		new_list->hmac[i] = list->hmac[i];
   1.728 +	return (new_list);
   1.729 +}
   1.730 +
   1.731 +sctp_hmaclist_t *
   1.732 +sctp_default_supported_hmaclist(void)
   1.733 +{
   1.734 +	sctp_hmaclist_t *new_list;
   1.735 +
   1.736 +#if defined(SCTP_SUPPORT_HMAC_SHA256)
   1.737 +	new_list = sctp_alloc_hmaclist(2);
   1.738 +#else
   1.739 +	new_list = sctp_alloc_hmaclist(1);
   1.740 +#endif
   1.741 +	if (new_list == NULL)
   1.742 +		return (NULL);
   1.743 +#if defined(SCTP_SUPPORT_HMAC_SHA256)
   1.744 +	/* We prefer SHA256, so list it first */
   1.745 +	(void)sctp_auth_add_hmacid(new_list, SCTP_AUTH_HMAC_ID_SHA256);
   1.746 +#endif
   1.747 +	(void)sctp_auth_add_hmacid(new_list, SCTP_AUTH_HMAC_ID_SHA1);
   1.748 +	return (new_list);
   1.749 +}
   1.750 +
   1.751 +/*-
   1.752 + * HMAC algos are listed in priority/preference order
   1.753 + * find the best HMAC id to use for the peer based on local support
   1.754 + */
   1.755 +uint16_t
   1.756 +sctp_negotiate_hmacid(sctp_hmaclist_t *peer, sctp_hmaclist_t *local)
   1.757 +{
   1.758 +	int i, j;
   1.759 +
   1.760 +	if ((local == NULL) || (peer == NULL))
   1.761 +		return (SCTP_AUTH_HMAC_ID_RSVD);
   1.762 +
   1.763 +	for (i = 0; i < peer->num_algo; i++) {
   1.764 +		for (j = 0; j < local->num_algo; j++) {
   1.765 +			if (peer->hmac[i] == local->hmac[j]) {
   1.766 +				/* found the "best" one */
   1.767 +				SCTPDBG(SCTP_DEBUG_AUTH1,
   1.768 +					"SCTP: negotiated peer HMAC id %u\n",
   1.769 +					peer->hmac[i]);
   1.770 +				return (peer->hmac[i]);
   1.771 +			}
   1.772 +		}
   1.773 +	}
   1.774 +	/* didn't find one! */
   1.775 +	return (SCTP_AUTH_HMAC_ID_RSVD);
   1.776 +}
   1.777 +
   1.778 +/*-
   1.779 + * serialize the HMAC algo list and return space used
   1.780 + * caller must guarantee ptr has appropriate space
   1.781 + */
   1.782 +int
   1.783 +sctp_serialize_hmaclist(sctp_hmaclist_t *list, uint8_t *ptr)
   1.784 +{
   1.785 +	int i;
   1.786 +	uint16_t hmac_id;
   1.787 +
   1.788 +	if (list == NULL)
   1.789 +		return (0);
   1.790 +
   1.791 +	for (i = 0; i < list->num_algo; i++) {
   1.792 +		hmac_id = htons(list->hmac[i]);
   1.793 +		bcopy(&hmac_id, ptr, sizeof(hmac_id));
   1.794 +		ptr += sizeof(hmac_id);
   1.795 +	}
   1.796 +	return (list->num_algo * sizeof(hmac_id));
   1.797 +}
   1.798 +
   1.799 +int
   1.800 +sctp_verify_hmac_param (struct sctp_auth_hmac_algo *hmacs, uint32_t num_hmacs)
   1.801 +{
   1.802 +	uint32_t i;
   1.803 +
   1.804 +	for (i = 0; i < num_hmacs; i++) {
   1.805 +		if (ntohs(hmacs->hmac_ids[i]) == SCTP_AUTH_HMAC_ID_SHA1) {
   1.806 +	 		return (0);
   1.807 +		}
   1.808 +	}
   1.809 +	return (-1);
   1.810 +}
   1.811 +
   1.812 +sctp_authinfo_t *
   1.813 +sctp_alloc_authinfo(void)
   1.814 +{
   1.815 +	sctp_authinfo_t *new_authinfo;
   1.816 +
   1.817 +	SCTP_MALLOC(new_authinfo, sctp_authinfo_t *, sizeof(*new_authinfo),
   1.818 +		    SCTP_M_AUTH_IF);
   1.819 +
   1.820 +	if (new_authinfo == NULL) {
   1.821 +		/* out of memory */
   1.822 +		return (NULL);
   1.823 +	}
   1.824 +	bzero(new_authinfo, sizeof(*new_authinfo));
   1.825 +	return (new_authinfo);
   1.826 +}
   1.827 +
   1.828 +void
   1.829 +sctp_free_authinfo(sctp_authinfo_t *authinfo)
   1.830 +{
   1.831 +	if (authinfo == NULL)
   1.832 +		return;
   1.833 +
   1.834 +	if (authinfo->random != NULL)
   1.835 +		sctp_free_key(authinfo->random);
   1.836 +	if (authinfo->peer_random != NULL)
   1.837 +		sctp_free_key(authinfo->peer_random);
   1.838 +	if (authinfo->assoc_key != NULL)
   1.839 +		sctp_free_key(authinfo->assoc_key);
   1.840 +	if (authinfo->recv_key != NULL)
   1.841 +		sctp_free_key(authinfo->recv_key);
   1.842 +
   1.843 +	/* We are NOT dynamically allocating authinfo's right now... */
   1.844 +	/* SCTP_FREE(authinfo, SCTP_M_AUTH_??); */
   1.845 +}
   1.846 +
   1.847 +
   1.848 +uint32_t
   1.849 +sctp_get_auth_chunk_len(uint16_t hmac_algo)
   1.850 +{
   1.851 +	int size;
   1.852 +
   1.853 +	size = sizeof(struct sctp_auth_chunk) + sctp_get_hmac_digest_len(hmac_algo);
   1.854 +	return (SCTP_SIZE32(size));
   1.855 +}
   1.856 +
   1.857 +uint32_t
   1.858 +sctp_get_hmac_digest_len(uint16_t hmac_algo)
   1.859 +{
   1.860 +	switch (hmac_algo) {
   1.861 +	case SCTP_AUTH_HMAC_ID_SHA1:
   1.862 +		return (SCTP_AUTH_DIGEST_LEN_SHA1);
   1.863 +#if defined(SCTP_SUPPORT_HMAC_SHA256)
   1.864 +	case SCTP_AUTH_HMAC_ID_SHA256:
   1.865 +		return (SCTP_AUTH_DIGEST_LEN_SHA256);
   1.866 +#endif
   1.867 +	default:
   1.868 +		/* unknown HMAC algorithm: can't do anything */
   1.869 +		return (0);
   1.870 +	} /* end switch */
   1.871 +}
   1.872 +
   1.873 +static inline int
   1.874 +sctp_get_hmac_block_len(uint16_t hmac_algo)
   1.875 +{
   1.876 +	switch (hmac_algo) {
   1.877 +	case SCTP_AUTH_HMAC_ID_SHA1:
   1.878 +		return (64);
   1.879 +#if defined(SCTP_SUPPORT_HMAC_SHA256)
   1.880 +	case SCTP_AUTH_HMAC_ID_SHA256:
   1.881 +		return (64);
   1.882 +#endif
   1.883 +	case SCTP_AUTH_HMAC_ID_RSVD:
   1.884 +	default:
   1.885 +		/* unknown HMAC algorithm: can't do anything */
   1.886 +		return (0);
   1.887 +	} /* end switch */
   1.888 +}
   1.889 +
   1.890 +#if defined(__Userspace__)
   1.891 +/* __Userspace__ SHA1_Init is defined in libcrypto.a (libssl-dev on Ubuntu) */
   1.892 +#endif
   1.893 +static void
   1.894 +sctp_hmac_init(uint16_t hmac_algo, sctp_hash_context_t *ctx)
   1.895 +{
   1.896 +	switch (hmac_algo) {
   1.897 +	case SCTP_AUTH_HMAC_ID_SHA1:
   1.898 +		SCTP_SHA1_INIT(&ctx->sha1);
   1.899 +		break;
   1.900 +#if defined(SCTP_SUPPORT_HMAC_SHA256)
   1.901 +	case SCTP_AUTH_HMAC_ID_SHA256:
   1.902 +		SCTP_SHA256_INIT(&ctx->sha256);
   1.903 +		break;
   1.904 +#endif
   1.905 +	case SCTP_AUTH_HMAC_ID_RSVD:
   1.906 +	default:
   1.907 +		/* unknown HMAC algorithm: can't do anything */
   1.908 +		return;
   1.909 +	} /* end switch */
   1.910 +}
   1.911 +
   1.912 +static void
   1.913 +sctp_hmac_update(uint16_t hmac_algo, sctp_hash_context_t *ctx,
   1.914 +    uint8_t *text, uint32_t textlen)
   1.915 +{
   1.916 +	switch (hmac_algo) {
   1.917 +	case SCTP_AUTH_HMAC_ID_SHA1:
   1.918 +		SCTP_SHA1_UPDATE(&ctx->sha1, text, textlen);
   1.919 +		break;
   1.920 +#if defined(SCTP_SUPPORT_HMAC_SHA256)
   1.921 +	case SCTP_AUTH_HMAC_ID_SHA256:
   1.922 +		SCTP_SHA256_UPDATE(&ctx->sha256, text, textlen);
   1.923 +		break;
   1.924 +#endif
   1.925 +	case SCTP_AUTH_HMAC_ID_RSVD:
   1.926 +	default:
   1.927 +		/* unknown HMAC algorithm: can't do anything */
   1.928 +		return;
   1.929 +	} /* end switch */
   1.930 +}
   1.931 +
   1.932 +static void
   1.933 +sctp_hmac_final(uint16_t hmac_algo, sctp_hash_context_t *ctx,
   1.934 +    uint8_t *digest)
   1.935 +{
   1.936 +	switch (hmac_algo) {
   1.937 +	case SCTP_AUTH_HMAC_ID_SHA1:
   1.938 +		SCTP_SHA1_FINAL(digest, &ctx->sha1);
   1.939 +		break;
   1.940 +#if defined(SCTP_SUPPORT_HMAC_SHA256)
   1.941 +	case SCTP_AUTH_HMAC_ID_SHA256:
   1.942 +		SCTP_SHA256_FINAL(digest, &ctx->sha256);
   1.943 +		break;
   1.944 +#endif
   1.945 +	case SCTP_AUTH_HMAC_ID_RSVD:
   1.946 +	default:
   1.947 +		/* unknown HMAC algorithm: can't do anything */
   1.948 +		return;
   1.949 +	} /* end switch */
   1.950 +}
   1.951 +
   1.952 +/*-
   1.953 + * Keyed-Hashing for Message Authentication: FIPS 198 (RFC 2104)
   1.954 + *
   1.955 + * Compute the HMAC digest using the desired hash key, text, and HMAC
   1.956 + * algorithm.  Resulting digest is placed in 'digest' and digest length
   1.957 + * is returned, if the HMAC was performed.
   1.958 + *
   1.959 + * WARNING: it is up to the caller to supply sufficient space to hold the
   1.960 + * resultant digest.
   1.961 + */
   1.962 +uint32_t
   1.963 +sctp_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
   1.964 +    uint8_t *text, uint32_t textlen, uint8_t *digest)
   1.965 +{
   1.966 +	uint32_t digestlen;
   1.967 +	uint32_t blocklen;
   1.968 +	sctp_hash_context_t ctx;
   1.969 +	uint8_t ipad[128], opad[128];	/* keyed hash inner/outer pads */
   1.970 +	uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
   1.971 +	uint32_t i;
   1.972 +
   1.973 +	/* sanity check the material and length */
   1.974 +	if ((key == NULL) || (keylen == 0) || (text == NULL) ||
   1.975 +	    (textlen == 0) || (digest == NULL)) {
   1.976 +		/* can't do HMAC with empty key or text or digest store */
   1.977 +		return (0);
   1.978 +	}
   1.979 +	/* validate the hmac algo and get the digest length */
   1.980 +	digestlen = sctp_get_hmac_digest_len(hmac_algo);
   1.981 +	if (digestlen == 0)
   1.982 +		return (0);
   1.983 +
   1.984 +	/* hash the key if it is longer than the hash block size */
   1.985 +	blocklen = sctp_get_hmac_block_len(hmac_algo);
   1.986 +	if (keylen > blocklen) {
   1.987 +		sctp_hmac_init(hmac_algo, &ctx);
   1.988 +		sctp_hmac_update(hmac_algo, &ctx, key, keylen);
   1.989 +		sctp_hmac_final(hmac_algo, &ctx, temp);
   1.990 +		/* set the hashed key as the key */
   1.991 +		keylen = digestlen;
   1.992 +		key = temp;
   1.993 +	}
   1.994 +	/* initialize the inner/outer pads with the key and "append" zeroes */
   1.995 +	bzero(ipad, blocklen);
   1.996 +	bzero(opad, blocklen);
   1.997 +	bcopy(key, ipad, keylen);
   1.998 +	bcopy(key, opad, keylen);
   1.999 +
  1.1000 +	/* XOR the key with ipad and opad values */
  1.1001 +	for (i = 0; i < blocklen; i++) {
  1.1002 +		ipad[i] ^= 0x36;
  1.1003 +		opad[i] ^= 0x5c;
  1.1004 +	}
  1.1005 +
  1.1006 +	/* perform inner hash */
  1.1007 +	sctp_hmac_init(hmac_algo, &ctx);
  1.1008 +	sctp_hmac_update(hmac_algo, &ctx, ipad, blocklen);
  1.1009 +	sctp_hmac_update(hmac_algo, &ctx, text, textlen);
  1.1010 +	sctp_hmac_final(hmac_algo, &ctx, temp);
  1.1011 +
  1.1012 +	/* perform outer hash */
  1.1013 +	sctp_hmac_init(hmac_algo, &ctx);
  1.1014 +	sctp_hmac_update(hmac_algo, &ctx, opad, blocklen);
  1.1015 +	sctp_hmac_update(hmac_algo, &ctx, temp, digestlen);
  1.1016 +	sctp_hmac_final(hmac_algo, &ctx, digest);
  1.1017 +
  1.1018 +	return (digestlen);
  1.1019 +}
  1.1020 +
  1.1021 +/* mbuf version */
  1.1022 +uint32_t
  1.1023 +sctp_hmac_m(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
  1.1024 +    struct mbuf *m, uint32_t m_offset, uint8_t *digest, uint32_t trailer)
  1.1025 +{
  1.1026 +	uint32_t digestlen;
  1.1027 +	uint32_t blocklen;
  1.1028 +	sctp_hash_context_t ctx;
  1.1029 +	uint8_t ipad[128], opad[128];	/* keyed hash inner/outer pads */
  1.1030 +	uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
  1.1031 +	uint32_t i;
  1.1032 +	struct mbuf *m_tmp;
  1.1033 +
  1.1034 +	/* sanity check the material and length */
  1.1035 +	if ((key == NULL) || (keylen == 0) || (m == NULL) || (digest == NULL)) {
  1.1036 +		/* can't do HMAC with empty key or text or digest store */
  1.1037 +		return (0);
  1.1038 +	}
  1.1039 +	/* validate the hmac algo and get the digest length */
  1.1040 +	digestlen = sctp_get_hmac_digest_len(hmac_algo);
  1.1041 +	if (digestlen == 0)
  1.1042 +		return (0);
  1.1043 +
  1.1044 +	/* hash the key if it is longer than the hash block size */
  1.1045 +	blocklen = sctp_get_hmac_block_len(hmac_algo);
  1.1046 +	if (keylen > blocklen) {
  1.1047 +		sctp_hmac_init(hmac_algo, &ctx);
  1.1048 +		sctp_hmac_update(hmac_algo, &ctx, key, keylen);
  1.1049 +		sctp_hmac_final(hmac_algo, &ctx, temp);
  1.1050 +		/* set the hashed key as the key */
  1.1051 +		keylen = digestlen;
  1.1052 +		key = temp;
  1.1053 +	}
  1.1054 +	/* initialize the inner/outer pads with the key and "append" zeroes */
  1.1055 +	bzero(ipad, blocklen);
  1.1056 +	bzero(opad, blocklen);
  1.1057 +	bcopy(key, ipad, keylen);
  1.1058 +	bcopy(key, opad, keylen);
  1.1059 +
  1.1060 +	/* XOR the key with ipad and opad values */
  1.1061 +	for (i = 0; i < blocklen; i++) {
  1.1062 +		ipad[i] ^= 0x36;
  1.1063 +		opad[i] ^= 0x5c;
  1.1064 +	}
  1.1065 +
  1.1066 +	/* perform inner hash */
  1.1067 +	sctp_hmac_init(hmac_algo, &ctx);
  1.1068 +	sctp_hmac_update(hmac_algo, &ctx, ipad, blocklen);
  1.1069 +	/* find the correct starting mbuf and offset (get start of text) */
  1.1070 +	m_tmp = m;
  1.1071 +	while ((m_tmp != NULL) && (m_offset >= (uint32_t) SCTP_BUF_LEN(m_tmp))) {
  1.1072 +		m_offset -= SCTP_BUF_LEN(m_tmp);
  1.1073 +		m_tmp = SCTP_BUF_NEXT(m_tmp);
  1.1074 +	}
  1.1075 +	/* now use the rest of the mbuf chain for the text */
  1.1076 +	while (m_tmp != NULL) {
  1.1077 +		if ((SCTP_BUF_NEXT(m_tmp) == NULL) && trailer) {
  1.1078 +			sctp_hmac_update(hmac_algo, &ctx, mtod(m_tmp, uint8_t *) + m_offset,
  1.1079 +					 SCTP_BUF_LEN(m_tmp) - (trailer+m_offset));
  1.1080 +		} else {
  1.1081 +			sctp_hmac_update(hmac_algo, &ctx, mtod(m_tmp, uint8_t *) + m_offset,
  1.1082 +					 SCTP_BUF_LEN(m_tmp) - m_offset);
  1.1083 +		}
  1.1084 +
  1.1085 +		/* clear the offset since it's only for the first mbuf */
  1.1086 +		m_offset = 0;
  1.1087 +		m_tmp = SCTP_BUF_NEXT(m_tmp);
  1.1088 +	}
  1.1089 +	sctp_hmac_final(hmac_algo, &ctx, temp);
  1.1090 +
  1.1091 +	/* perform outer hash */
  1.1092 +	sctp_hmac_init(hmac_algo, &ctx);
  1.1093 +	sctp_hmac_update(hmac_algo, &ctx, opad, blocklen);
  1.1094 +	sctp_hmac_update(hmac_algo, &ctx, temp, digestlen);
  1.1095 +	sctp_hmac_final(hmac_algo, &ctx, digest);
  1.1096 +
  1.1097 +	return (digestlen);
  1.1098 +}
  1.1099 +
  1.1100 +/*-
  1.1101 + * verify the HMAC digest using the desired hash key, text, and HMAC
  1.1102 + * algorithm.
  1.1103 + * Returns -1 on error, 0 on success.
  1.1104 + */
  1.1105 +int
  1.1106 +sctp_verify_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
  1.1107 +    uint8_t *text, uint32_t textlen,
  1.1108 +    uint8_t *digest, uint32_t digestlen)
  1.1109 +{
  1.1110 +	uint32_t len;
  1.1111 +	uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
  1.1112 +
  1.1113 +	/* sanity check the material and length */
  1.1114 +	if ((key == NULL) || (keylen == 0) ||
  1.1115 +	    (text == NULL) || (textlen == 0) || (digest == NULL)) {
  1.1116 +		/* can't do HMAC with empty key or text or digest */
  1.1117 +		return (-1);
  1.1118 +	}
  1.1119 +	len = sctp_get_hmac_digest_len(hmac_algo);
  1.1120 +	if ((len == 0) || (digestlen != len))
  1.1121 +		return (-1);
  1.1122 +
  1.1123 +	/* compute the expected hash */
  1.1124 +	if (sctp_hmac(hmac_algo, key, keylen, text, textlen, temp) != len)
  1.1125 +		return (-1);
  1.1126 +
  1.1127 +	if (memcmp(digest, temp, digestlen) != 0)
  1.1128 +		return (-1);
  1.1129 +	else
  1.1130 +		return (0);
  1.1131 +}
  1.1132 +
  1.1133 +
  1.1134 +/*
  1.1135 + * computes the requested HMAC using a key struct (which may be modified if
  1.1136 + * the keylen exceeds the HMAC block len).
  1.1137 + */
  1.1138 +uint32_t
  1.1139 +sctp_compute_hmac(uint16_t hmac_algo, sctp_key_t *key, uint8_t *text,
  1.1140 +    uint32_t textlen, uint8_t *digest)
  1.1141 +{
  1.1142 +	uint32_t digestlen;
  1.1143 +	uint32_t blocklen;
  1.1144 +	sctp_hash_context_t ctx;
  1.1145 +	uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
  1.1146 +
  1.1147 +	/* sanity check */
  1.1148 +	if ((key == NULL) || (text == NULL) || (textlen == 0) ||
  1.1149 +	    (digest == NULL)) {
  1.1150 +		/* can't do HMAC with empty key or text or digest store */
  1.1151 +		return (0);
  1.1152 +	}
  1.1153 +	/* validate the hmac algo and get the digest length */
  1.1154 +	digestlen = sctp_get_hmac_digest_len(hmac_algo);
  1.1155 +	if (digestlen == 0)
  1.1156 +		return (0);
  1.1157 +
  1.1158 +	/* hash the key if it is longer than the hash block size */
  1.1159 +	blocklen = sctp_get_hmac_block_len(hmac_algo);
  1.1160 +	if (key->keylen > blocklen) {
  1.1161 +		sctp_hmac_init(hmac_algo, &ctx);
  1.1162 +		sctp_hmac_update(hmac_algo, &ctx, key->key, key->keylen);
  1.1163 +		sctp_hmac_final(hmac_algo, &ctx, temp);
  1.1164 +		/* save the hashed key as the new key */
  1.1165 +		key->keylen = digestlen;
  1.1166 +		bcopy(temp, key->key, key->keylen);
  1.1167 +	}
  1.1168 +	return (sctp_hmac(hmac_algo, key->key, key->keylen, text, textlen,
  1.1169 +	    digest));
  1.1170 +}
  1.1171 +
  1.1172 +/* mbuf version */
  1.1173 +uint32_t
  1.1174 +sctp_compute_hmac_m(uint16_t hmac_algo, sctp_key_t *key, struct mbuf *m,
  1.1175 +    uint32_t m_offset, uint8_t *digest)
  1.1176 +{
  1.1177 +	uint32_t digestlen;
  1.1178 +	uint32_t blocklen;
  1.1179 +	sctp_hash_context_t ctx;
  1.1180 +	uint8_t temp[SCTP_AUTH_DIGEST_LEN_MAX];
  1.1181 +
  1.1182 +	/* sanity check */
  1.1183 +	if ((key == NULL) || (m == NULL) || (digest == NULL)) {
  1.1184 +		/* can't do HMAC with empty key or text or digest store */
  1.1185 +		return (0);
  1.1186 +	}
  1.1187 +	/* validate the hmac algo and get the digest length */
  1.1188 +	digestlen = sctp_get_hmac_digest_len(hmac_algo);
  1.1189 +	if (digestlen == 0)
  1.1190 +		return (0);
  1.1191 +
  1.1192 +	/* hash the key if it is longer than the hash block size */
  1.1193 +	blocklen = sctp_get_hmac_block_len(hmac_algo);
  1.1194 +	if (key->keylen > blocklen) {
  1.1195 +		sctp_hmac_init(hmac_algo, &ctx);
  1.1196 +		sctp_hmac_update(hmac_algo, &ctx, key->key, key->keylen);
  1.1197 +		sctp_hmac_final(hmac_algo, &ctx, temp);
  1.1198 +		/* save the hashed key as the new key */
  1.1199 +		key->keylen = digestlen;
  1.1200 +		bcopy(temp, key->key, key->keylen);
  1.1201 +	}
  1.1202 +	return (sctp_hmac_m(hmac_algo, key->key, key->keylen, m, m_offset, digest, 0));
  1.1203 +}
  1.1204 +
  1.1205 +int
  1.1206 +sctp_auth_is_supported_hmac(sctp_hmaclist_t *list, uint16_t id)
  1.1207 +{
  1.1208 +	int i;
  1.1209 +
  1.1210 +	if ((list == NULL) || (id == SCTP_AUTH_HMAC_ID_RSVD))
  1.1211 +		return (0);
  1.1212 +
  1.1213 +	for (i = 0; i < list->num_algo; i++)
  1.1214 +		if (list->hmac[i] == id)
  1.1215 +			return (1);
  1.1216 +
  1.1217 +	/* not in the list */
  1.1218 +	return (0);
  1.1219 +}
  1.1220 +
  1.1221 +
  1.1222 +/*-
  1.1223 + * clear any cached key(s) if they match the given key id on an association.
  1.1224 + * the cached key(s) will be recomputed and re-cached at next use.
  1.1225 + * ASSUMES TCB_LOCK is already held
  1.1226 + */
  1.1227 +void
  1.1228 +sctp_clear_cachedkeys(struct sctp_tcb *stcb, uint16_t keyid)
  1.1229 +{
  1.1230 +	if (stcb == NULL)
  1.1231 +		return;
  1.1232 +
  1.1233 +	if (keyid == stcb->asoc.authinfo.assoc_keyid) {
  1.1234 +		sctp_free_key(stcb->asoc.authinfo.assoc_key);
  1.1235 +		stcb->asoc.authinfo.assoc_key = NULL;
  1.1236 +	}
  1.1237 +	if (keyid == stcb->asoc.authinfo.recv_keyid) {
  1.1238 +		sctp_free_key(stcb->asoc.authinfo.recv_key);
  1.1239 +		stcb->asoc.authinfo.recv_key = NULL;
  1.1240 +	}
  1.1241 +}
  1.1242 +
  1.1243 +/*-
  1.1244 + * clear any cached key(s) if they match the given key id for all assocs on
  1.1245 + * an endpoint.
  1.1246 + * ASSUMES INP_WLOCK is already held
  1.1247 + */
  1.1248 +void
  1.1249 +sctp_clear_cachedkeys_ep(struct sctp_inpcb *inp, uint16_t keyid)
  1.1250 +{
  1.1251 +	struct sctp_tcb *stcb;
  1.1252 +
  1.1253 +	if (inp == NULL)
  1.1254 +		return;
  1.1255 +
  1.1256 +	/* clear the cached keys on all assocs on this instance */
  1.1257 +	LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.1258 +		SCTP_TCB_LOCK(stcb);
  1.1259 +		sctp_clear_cachedkeys(stcb, keyid);
  1.1260 +		SCTP_TCB_UNLOCK(stcb);
  1.1261 +	}
  1.1262 +}
  1.1263 +
  1.1264 +/*-
  1.1265 + * delete a shared key from an association
  1.1266 + * ASSUMES TCB_LOCK is already held
  1.1267 + */
  1.1268 +int
  1.1269 +sctp_delete_sharedkey(struct sctp_tcb *stcb, uint16_t keyid)
  1.1270 +{
  1.1271 +	sctp_sharedkey_t *skey;
  1.1272 +
  1.1273 +	if (stcb == NULL)
  1.1274 +		return (-1);
  1.1275 +
  1.1276 +	/* is the keyid the assoc active sending key */
  1.1277 +	if (keyid == stcb->asoc.authinfo.active_keyid)
  1.1278 +		return (-1);
  1.1279 +
  1.1280 +	/* does the key exist? */
  1.1281 +	skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
  1.1282 +	if (skey == NULL)
  1.1283 +		return (-1);
  1.1284 +
  1.1285 +	/* are there other refcount holders on the key? */
  1.1286 +	if (skey->refcount > 1)
  1.1287 +		return (-1);
  1.1288 +
  1.1289 +	/* remove it */
  1.1290 +	LIST_REMOVE(skey, next);
  1.1291 +	sctp_free_sharedkey(skey);	/* frees skey->key as well */
  1.1292 +
  1.1293 +	/* clear any cached keys */
  1.1294 +	sctp_clear_cachedkeys(stcb, keyid);
  1.1295 +	return (0);
  1.1296 +}
  1.1297 +
  1.1298 +/*-
  1.1299 + * deletes a shared key from the endpoint
  1.1300 + * ASSUMES INP_WLOCK is already held
  1.1301 + */
  1.1302 +int
  1.1303 +sctp_delete_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid)
  1.1304 +{
  1.1305 +	sctp_sharedkey_t *skey;
  1.1306 +
  1.1307 +	if (inp == NULL)
  1.1308 +		return (-1);
  1.1309 +
  1.1310 +	/* is the keyid the active sending key on the endpoint */
  1.1311 +	if (keyid == inp->sctp_ep.default_keyid)
  1.1312 +		return (-1);
  1.1313 +
  1.1314 +	/* does the key exist? */
  1.1315 +	skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid);
  1.1316 +	if (skey == NULL)
  1.1317 +		return (-1);
  1.1318 +
  1.1319 +	/* endpoint keys are not refcounted */
  1.1320 +
  1.1321 +	/* remove it */
  1.1322 +	LIST_REMOVE(skey, next);
  1.1323 +	sctp_free_sharedkey(skey);	/* frees skey->key as well */
  1.1324 +
  1.1325 +	/* clear any cached keys */
  1.1326 +	sctp_clear_cachedkeys_ep(inp, keyid);
  1.1327 +	return (0);
  1.1328 +}
  1.1329 +
  1.1330 +/*-
  1.1331 + * set the active key on an association
  1.1332 + * ASSUMES TCB_LOCK is already held
  1.1333 + */
  1.1334 +int
  1.1335 +sctp_auth_setactivekey(struct sctp_tcb *stcb, uint16_t keyid)
  1.1336 +{
  1.1337 +	sctp_sharedkey_t *skey = NULL;
  1.1338 +
  1.1339 +	/* find the key on the assoc */
  1.1340 +	skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
  1.1341 +	if (skey == NULL) {
  1.1342 +		/* that key doesn't exist */
  1.1343 +		return (-1);
  1.1344 +	}
  1.1345 +	if ((skey->deactivated) && (skey->refcount > 1)) {
  1.1346 +		/* can't reactivate a deactivated key with other refcounts */
  1.1347 +		return (-1);
  1.1348 +	}
  1.1349 +
  1.1350 +	/* set the (new) active key */
  1.1351 +	stcb->asoc.authinfo.active_keyid = keyid;
  1.1352 +	/* reset the deactivated flag */
  1.1353 +	skey->deactivated = 0;
  1.1354 +
  1.1355 +	return (0);
  1.1356 +}
  1.1357 +
  1.1358 +/*-
  1.1359 + * set the active key on an endpoint
  1.1360 + * ASSUMES INP_WLOCK is already held
  1.1361 + */
  1.1362 +int
  1.1363 +sctp_auth_setactivekey_ep(struct sctp_inpcb *inp, uint16_t keyid)
  1.1364 +{
  1.1365 +	sctp_sharedkey_t *skey;
  1.1366 +
  1.1367 +	/* find the key */
  1.1368 +	skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid);
  1.1369 +	if (skey == NULL) {
  1.1370 +		/* that key doesn't exist */
  1.1371 +		return (-1);
  1.1372 +	}
  1.1373 +	inp->sctp_ep.default_keyid = keyid;
  1.1374 +	return (0);
  1.1375 +}
  1.1376 +
  1.1377 +/*-
  1.1378 + * deactivates a shared key from the association
  1.1379 + * ASSUMES INP_WLOCK is already held
  1.1380 + */
  1.1381 +int
  1.1382 +sctp_deact_sharedkey(struct sctp_tcb *stcb, uint16_t keyid)
  1.1383 +{
  1.1384 +	sctp_sharedkey_t *skey;
  1.1385 +
  1.1386 +	if (stcb == NULL)
  1.1387 +		return (-1);
  1.1388 +
  1.1389 +	/* is the keyid the assoc active sending key */
  1.1390 +	if (keyid == stcb->asoc.authinfo.active_keyid)
  1.1391 +		return (-1);
  1.1392 +
  1.1393 +	/* does the key exist? */
  1.1394 +	skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
  1.1395 +	if (skey == NULL)
  1.1396 +		return (-1);
  1.1397 +
  1.1398 +	/* are there other refcount holders on the key? */
  1.1399 +	if (skey->refcount == 1) {
  1.1400 +		/* no other users, send a notification for this key */
  1.1401 +		sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb, keyid, 0,
  1.1402 +				SCTP_SO_LOCKED);
  1.1403 +	}
  1.1404 +
  1.1405 +	/* mark the key as deactivated */
  1.1406 +	skey->deactivated = 1;
  1.1407 +
  1.1408 +	return (0);
  1.1409 +}
  1.1410 +
  1.1411 +/*-
  1.1412 + * deactivates a shared key from the endpoint
  1.1413 + * ASSUMES INP_WLOCK is already held
  1.1414 + */
  1.1415 +int
  1.1416 +sctp_deact_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid)
  1.1417 +{
  1.1418 +	sctp_sharedkey_t *skey;
  1.1419 +
  1.1420 +	if (inp == NULL)
  1.1421 +		return (-1);
  1.1422 +
  1.1423 +	/* is the keyid the active sending key on the endpoint */
  1.1424 +	if (keyid == inp->sctp_ep.default_keyid)
  1.1425 +		return (-1);
  1.1426 +
  1.1427 +	/* does the key exist? */
  1.1428 +	skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid);
  1.1429 +	if (skey == NULL)
  1.1430 +		return (-1);
  1.1431 +
  1.1432 +	/* endpoint keys are not refcounted */
  1.1433 +
  1.1434 +	/* remove it */
  1.1435 +	LIST_REMOVE(skey, next);
  1.1436 +	sctp_free_sharedkey(skey);	/* frees skey->key as well */
  1.1437 +
  1.1438 +	return (0);
  1.1439 +}
  1.1440 +
  1.1441 +/*
  1.1442 + * get local authentication parameters from cookie (from INIT-ACK)
  1.1443 + */
  1.1444 +void
  1.1445 +sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
  1.1446 +    uint32_t offset, uint32_t length)
  1.1447 +{
  1.1448 +	struct sctp_paramhdr *phdr, tmp_param;
  1.1449 +	uint16_t plen, ptype;
  1.1450 +	uint8_t random_store[SCTP_PARAM_BUFFER_SIZE];
  1.1451 +	struct sctp_auth_random *p_random = NULL;
  1.1452 +	uint16_t random_len = 0;
  1.1453 +	uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE];
  1.1454 +	struct sctp_auth_hmac_algo *hmacs = NULL;
  1.1455 +	uint16_t hmacs_len = 0;
  1.1456 +	uint8_t chunks_store[SCTP_PARAM_BUFFER_SIZE];
  1.1457 +	struct sctp_auth_chunk_list *chunks = NULL;
  1.1458 +	uint16_t num_chunks = 0;
  1.1459 +	sctp_key_t *new_key;
  1.1460 +	uint32_t keylen;
  1.1461 +
  1.1462 +	/* convert to upper bound */
  1.1463 +	length += offset;
  1.1464 +
  1.1465 +	phdr = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
  1.1466 +	    sizeof(struct sctp_paramhdr), (uint8_t *)&tmp_param);
  1.1467 +	while (phdr != NULL) {
  1.1468 +		ptype = ntohs(phdr->param_type);
  1.1469 +		plen = ntohs(phdr->param_length);
  1.1470 +
  1.1471 +		if ((plen == 0) || (offset + plen > length))
  1.1472 +			break;
  1.1473 +
  1.1474 +		if (ptype == SCTP_RANDOM) {
  1.1475 +			if (plen > sizeof(random_store))
  1.1476 +				break;
  1.1477 +			phdr = sctp_get_next_param(m, offset,
  1.1478 +			    (struct sctp_paramhdr *)random_store, min(plen, sizeof(random_store)));
  1.1479 +			if (phdr == NULL)
  1.1480 +				return;
  1.1481 +			/* save the random and length for the key */
  1.1482 +			p_random = (struct sctp_auth_random *)phdr;
  1.1483 +			random_len = plen - sizeof(*p_random);
  1.1484 +		} else if (ptype == SCTP_HMAC_LIST) {
  1.1485 +			int num_hmacs;
  1.1486 +			int i;
  1.1487 +
  1.1488 +			if (plen > sizeof(hmacs_store))
  1.1489 +				break;
  1.1490 +			phdr = sctp_get_next_param(m, offset,
  1.1491 +			    (struct sctp_paramhdr *)hmacs_store, min(plen,sizeof(hmacs_store)));
  1.1492 +			if (phdr == NULL)
  1.1493 +				return;
  1.1494 +			/* save the hmacs list and num for the key */
  1.1495 +			hmacs = (struct sctp_auth_hmac_algo *)phdr;
  1.1496 +			hmacs_len = plen - sizeof(*hmacs);
  1.1497 +			num_hmacs = hmacs_len / sizeof(hmacs->hmac_ids[0]);
  1.1498 +			if (stcb->asoc.local_hmacs != NULL)
  1.1499 +				sctp_free_hmaclist(stcb->asoc.local_hmacs);
  1.1500 +			stcb->asoc.local_hmacs = sctp_alloc_hmaclist(num_hmacs);
  1.1501 +			if (stcb->asoc.local_hmacs != NULL) {
  1.1502 +				for (i = 0; i < num_hmacs; i++) {
  1.1503 +					(void)sctp_auth_add_hmacid(stcb->asoc.local_hmacs,
  1.1504 +					    ntohs(hmacs->hmac_ids[i]));
  1.1505 +				}
  1.1506 +			}
  1.1507 +		} else if (ptype == SCTP_CHUNK_LIST) {
  1.1508 +			int i;
  1.1509 +
  1.1510 +			if (plen > sizeof(chunks_store))
  1.1511 +				break;
  1.1512 +			phdr = sctp_get_next_param(m, offset,
  1.1513 +			    (struct sctp_paramhdr *)chunks_store, min(plen,sizeof(chunks_store)));
  1.1514 +			if (phdr == NULL)
  1.1515 +				return;
  1.1516 +			chunks = (struct sctp_auth_chunk_list *)phdr;
  1.1517 +			num_chunks = plen - sizeof(*chunks);
  1.1518 +			/* save chunks list and num for the key */
  1.1519 +			if (stcb->asoc.local_auth_chunks != NULL)
  1.1520 +				sctp_clear_chunklist(stcb->asoc.local_auth_chunks);
  1.1521 +			else
  1.1522 +				stcb->asoc.local_auth_chunks = sctp_alloc_chunklist();
  1.1523 +			for (i = 0; i < num_chunks; i++) {
  1.1524 +				(void)sctp_auth_add_chunk(chunks->chunk_types[i],
  1.1525 +				    stcb->asoc.local_auth_chunks);
  1.1526 +			}
  1.1527 +		}
  1.1528 +		/* get next parameter */
  1.1529 +		offset += SCTP_SIZE32(plen);
  1.1530 +		if (offset + sizeof(struct sctp_paramhdr) > length)
  1.1531 +			break;
  1.1532 +		phdr = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
  1.1533 +		    (uint8_t *)&tmp_param);
  1.1534 +	}
  1.1535 +	/* concatenate the full random key */
  1.1536 +	keylen = sizeof(*p_random) + random_len + sizeof(*hmacs) + hmacs_len;
  1.1537 +	if (chunks != NULL) {
  1.1538 +		keylen += sizeof(*chunks) + num_chunks;
  1.1539 +	}
  1.1540 +	new_key = sctp_alloc_key(keylen);
  1.1541 +	if (new_key != NULL) {
  1.1542 +	    /* copy in the RANDOM */
  1.1543 +	    if (p_random != NULL) {
  1.1544 +		keylen = sizeof(*p_random) + random_len;
  1.1545 +		bcopy(p_random, new_key->key, keylen);
  1.1546 +	    }
  1.1547 +	    /* append in the AUTH chunks */
  1.1548 +	    if (chunks != NULL) {
  1.1549 +		bcopy(chunks, new_key->key + keylen,
  1.1550 +		      sizeof(*chunks) + num_chunks);
  1.1551 +		keylen += sizeof(*chunks) + num_chunks;
  1.1552 +	    }
  1.1553 +	    /* append in the HMACs */
  1.1554 +	    if (hmacs != NULL) {
  1.1555 +		bcopy(hmacs, new_key->key + keylen,
  1.1556 +		      sizeof(*hmacs) + hmacs_len);
  1.1557 +	    }
  1.1558 +	}
  1.1559 +	if (stcb->asoc.authinfo.random != NULL)
  1.1560 +	    sctp_free_key(stcb->asoc.authinfo.random);
  1.1561 +	stcb->asoc.authinfo.random = new_key;
  1.1562 +	stcb->asoc.authinfo.random_len = random_len;
  1.1563 +	sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.assoc_keyid);
  1.1564 +	sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.recv_keyid);
  1.1565 +
  1.1566 +	/* negotiate what HMAC to use for the peer */
  1.1567 +	stcb->asoc.peer_hmac_id = sctp_negotiate_hmacid(stcb->asoc.peer_hmacs,
  1.1568 +	    stcb->asoc.local_hmacs);
  1.1569 +
  1.1570 +	/* copy defaults from the endpoint */
  1.1571 +	/* FIX ME: put in cookie? */
  1.1572 +	stcb->asoc.authinfo.active_keyid = stcb->sctp_ep->sctp_ep.default_keyid;
  1.1573 +	/* copy out the shared key list (by reference) from the endpoint */
  1.1574 +	(void)sctp_copy_skeylist(&stcb->sctp_ep->sctp_ep.shared_keys,
  1.1575 +				 &stcb->asoc.shared_keys);
  1.1576 +}
  1.1577 +
  1.1578 +/*
  1.1579 + * compute and fill in the HMAC digest for a packet
  1.1580 + */
  1.1581 +void
  1.1582 +sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
  1.1583 +    struct sctp_auth_chunk *auth, struct sctp_tcb *stcb, uint16_t keyid)
  1.1584 +{
  1.1585 +	uint32_t digestlen;
  1.1586 +	sctp_sharedkey_t *skey;
  1.1587 +	sctp_key_t *key;
  1.1588 +
  1.1589 +	if ((stcb == NULL) || (auth == NULL))
  1.1590 +		return;
  1.1591 +
  1.1592 +	/* zero the digest + chunk padding */
  1.1593 +	digestlen = sctp_get_hmac_digest_len(stcb->asoc.peer_hmac_id);
  1.1594 +	bzero(auth->hmac, SCTP_SIZE32(digestlen));
  1.1595 +
  1.1596 +	/* is the desired key cached? */
  1.1597 +	if ((keyid != stcb->asoc.authinfo.assoc_keyid) ||
  1.1598 +	    (stcb->asoc.authinfo.assoc_key == NULL)) {
  1.1599 +		if (stcb->asoc.authinfo.assoc_key != NULL) {
  1.1600 +			/* free the old cached key */
  1.1601 +			sctp_free_key(stcb->asoc.authinfo.assoc_key);
  1.1602 +		}
  1.1603 +		skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
  1.1604 +		/* the only way skey is NULL is if null key id 0 is used */
  1.1605 +		if (skey != NULL)
  1.1606 +			key = skey->key;
  1.1607 +		else
  1.1608 +			key = NULL;
  1.1609 +		/* compute a new assoc key and cache it */
  1.1610 +		stcb->asoc.authinfo.assoc_key =
  1.1611 +		    sctp_compute_hashkey(stcb->asoc.authinfo.random,
  1.1612 +					 stcb->asoc.authinfo.peer_random, key);
  1.1613 +		stcb->asoc.authinfo.assoc_keyid = keyid;
  1.1614 +		SCTPDBG(SCTP_DEBUG_AUTH1, "caching key id %u\n",
  1.1615 +			stcb->asoc.authinfo.assoc_keyid);
  1.1616 +#ifdef SCTP_DEBUG
  1.1617 +		if (SCTP_AUTH_DEBUG)
  1.1618 +			sctp_print_key(stcb->asoc.authinfo.assoc_key,
  1.1619 +				       "Assoc Key");
  1.1620 +#endif
  1.1621 +	}
  1.1622 +
  1.1623 +	/* set in the active key id */
  1.1624 +	auth->shared_key_id = htons(keyid);
  1.1625 +
  1.1626 +	/* compute and fill in the digest */
  1.1627 +	(void)sctp_compute_hmac_m(stcb->asoc.peer_hmac_id, stcb->asoc.authinfo.assoc_key,
  1.1628 +				  m, auth_offset, auth->hmac);
  1.1629 +}
  1.1630 +
  1.1631 +
  1.1632 +static void
  1.1633 +sctp_bzero_m(struct mbuf *m, uint32_t m_offset, uint32_t size)
  1.1634 +{
  1.1635 +	struct mbuf *m_tmp;
  1.1636 +	uint8_t *data;
  1.1637 +
  1.1638 +	/* sanity check */
  1.1639 +	if (m == NULL)
  1.1640 +		return;
  1.1641 +
  1.1642 +	/* find the correct starting mbuf and offset (get start position) */
  1.1643 +	m_tmp = m;
  1.1644 +	while ((m_tmp != NULL) && (m_offset >= (uint32_t) SCTP_BUF_LEN(m_tmp))) {
  1.1645 +		m_offset -= SCTP_BUF_LEN(m_tmp);
  1.1646 +		m_tmp = SCTP_BUF_NEXT(m_tmp);
  1.1647 +	}
  1.1648 +	/* now use the rest of the mbuf chain */
  1.1649 +	while ((m_tmp != NULL) && (size > 0)) {
  1.1650 +		data = mtod(m_tmp, uint8_t *) + m_offset;
  1.1651 +		if (size > (uint32_t) SCTP_BUF_LEN(m_tmp)) {
  1.1652 +			bzero(data, SCTP_BUF_LEN(m_tmp));
  1.1653 +			size -= SCTP_BUF_LEN(m_tmp);
  1.1654 +		} else {
  1.1655 +			bzero(data, size);
  1.1656 +			size = 0;
  1.1657 +		}
  1.1658 +		/* clear the offset since it's only for the first mbuf */
  1.1659 +		m_offset = 0;
  1.1660 +		m_tmp = SCTP_BUF_NEXT(m_tmp);
  1.1661 +	}
  1.1662 +}
  1.1663 +
  1.1664 +/*-
  1.1665 + * process the incoming Authentication chunk
  1.1666 + * return codes:
  1.1667 + *   -1 on any authentication error
  1.1668 + *    0 on authentication verification
  1.1669 + */
  1.1670 +int
  1.1671 +sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
  1.1672 +    struct mbuf *m, uint32_t offset)
  1.1673 +{
  1.1674 +	uint16_t chunklen;
  1.1675 +	uint16_t shared_key_id;
  1.1676 +	uint16_t hmac_id;
  1.1677 +	sctp_sharedkey_t *skey;
  1.1678 +	uint32_t digestlen;
  1.1679 +	uint8_t digest[SCTP_AUTH_DIGEST_LEN_MAX];
  1.1680 +	uint8_t computed_digest[SCTP_AUTH_DIGEST_LEN_MAX];
  1.1681 +
  1.1682 +	/* auth is checked for NULL by caller */
  1.1683 +	chunklen = ntohs(auth->ch.chunk_length);
  1.1684 +	if (chunklen < sizeof(*auth)) {
  1.1685 +		SCTP_STAT_INCR(sctps_recvauthfailed);
  1.1686 +		return (-1);
  1.1687 +	}
  1.1688 +	SCTP_STAT_INCR(sctps_recvauth);
  1.1689 +
  1.1690 +	/* get the auth params */
  1.1691 +	shared_key_id = ntohs(auth->shared_key_id);
  1.1692 +	hmac_id = ntohs(auth->hmac_id);
  1.1693 +	SCTPDBG(SCTP_DEBUG_AUTH1,
  1.1694 +		"SCTP AUTH Chunk: shared key %u, HMAC id %u\n",
  1.1695 +		shared_key_id, hmac_id);
  1.1696 +
  1.1697 +	/* is the indicated HMAC supported? */
  1.1698 +	if (!sctp_auth_is_supported_hmac(stcb->asoc.local_hmacs, hmac_id)) {
  1.1699 +		struct mbuf *m_err;
  1.1700 +		struct sctp_auth_invalid_hmac *err;
  1.1701 +
  1.1702 +		SCTP_STAT_INCR(sctps_recvivalhmacid);
  1.1703 +		SCTPDBG(SCTP_DEBUG_AUTH1,
  1.1704 +			"SCTP Auth: unsupported HMAC id %u\n",
  1.1705 +			hmac_id);
  1.1706 +		/*
  1.1707 +		 * report this in an Error Chunk: Unsupported HMAC
  1.1708 +		 * Identifier
  1.1709 +		 */
  1.1710 +		m_err = sctp_get_mbuf_for_msg(sizeof(*err), 0, M_NOWAIT,
  1.1711 +					      1, MT_HEADER);
  1.1712 +		if (m_err != NULL) {
  1.1713 +			/* pre-reserve some space */
  1.1714 +			SCTP_BUF_RESV_UF(m_err, sizeof(struct sctp_chunkhdr));
  1.1715 +			/* fill in the error */
  1.1716 +			err = mtod(m_err, struct sctp_auth_invalid_hmac *);
  1.1717 +			bzero(err, sizeof(*err));
  1.1718 +			err->ph.param_type = htons(SCTP_CAUSE_UNSUPPORTED_HMACID);
  1.1719 +			err->ph.param_length = htons(sizeof(*err));
  1.1720 +			err->hmac_id = ntohs(hmac_id);
  1.1721 +			SCTP_BUF_LEN(m_err) = sizeof(*err);
  1.1722 +			/* queue it */
  1.1723 +			sctp_queue_op_err(stcb, m_err);
  1.1724 +		}
  1.1725 +		return (-1);
  1.1726 +	}
  1.1727 +	/* get the indicated shared key, if available */
  1.1728 +	if ((stcb->asoc.authinfo.recv_key == NULL) ||
  1.1729 +	    (stcb->asoc.authinfo.recv_keyid != shared_key_id)) {
  1.1730 +		/* find the shared key on the assoc first */
  1.1731 +		skey = sctp_find_sharedkey(&stcb->asoc.shared_keys,
  1.1732 +					   shared_key_id);
  1.1733 +		/* if the shared key isn't found, discard the chunk */
  1.1734 +		if (skey == NULL) {
  1.1735 +			SCTP_STAT_INCR(sctps_recvivalkeyid);
  1.1736 +			SCTPDBG(SCTP_DEBUG_AUTH1,
  1.1737 +				"SCTP Auth: unknown key id %u\n",
  1.1738 +				shared_key_id);
  1.1739 +			return (-1);
  1.1740 +		}
  1.1741 +		/* generate a notification if this is a new key id */
  1.1742 +		if (stcb->asoc.authinfo.recv_keyid != shared_key_id)
  1.1743 +			/*
  1.1744 +			 * sctp_ulp_notify(SCTP_NOTIFY_AUTH_NEW_KEY, stcb,
  1.1745 +			 * shared_key_id, (void
  1.1746 +			 * *)stcb->asoc.authinfo.recv_keyid);
  1.1747 +			 */
  1.1748 +			sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY,
  1.1749 +			    shared_key_id, stcb->asoc.authinfo.recv_keyid,
  1.1750 +			    SCTP_SO_NOT_LOCKED);
  1.1751 +		/* compute a new recv assoc key and cache it */
  1.1752 +		if (stcb->asoc.authinfo.recv_key != NULL)
  1.1753 +			sctp_free_key(stcb->asoc.authinfo.recv_key);
  1.1754 +		stcb->asoc.authinfo.recv_key =
  1.1755 +		    sctp_compute_hashkey(stcb->asoc.authinfo.random,
  1.1756 +		    stcb->asoc.authinfo.peer_random, skey->key);
  1.1757 +		stcb->asoc.authinfo.recv_keyid = shared_key_id;
  1.1758 +#ifdef SCTP_DEBUG
  1.1759 +		if (SCTP_AUTH_DEBUG)
  1.1760 +			sctp_print_key(stcb->asoc.authinfo.recv_key, "Recv Key");
  1.1761 +#endif
  1.1762 +	}
  1.1763 +	/* validate the digest length */
  1.1764 +	digestlen = sctp_get_hmac_digest_len(hmac_id);
  1.1765 +	if (chunklen < (sizeof(*auth) + digestlen)) {
  1.1766 +		/* invalid digest length */
  1.1767 +		SCTP_STAT_INCR(sctps_recvauthfailed);
  1.1768 +		SCTPDBG(SCTP_DEBUG_AUTH1,
  1.1769 +			"SCTP Auth: chunk too short for HMAC\n");
  1.1770 +		return (-1);
  1.1771 +	}
  1.1772 +	/* save a copy of the digest, zero the pseudo header, and validate */
  1.1773 +	bcopy(auth->hmac, digest, digestlen);
  1.1774 +	sctp_bzero_m(m, offset + sizeof(*auth), SCTP_SIZE32(digestlen));
  1.1775 +	(void)sctp_compute_hmac_m(hmac_id, stcb->asoc.authinfo.recv_key,
  1.1776 +	    m, offset, computed_digest);
  1.1777 +
  1.1778 +	/* compare the computed digest with the one in the AUTH chunk */
  1.1779 +	if (memcmp(digest, computed_digest, digestlen) != 0) {
  1.1780 +		SCTP_STAT_INCR(sctps_recvauthfailed);
  1.1781 +		SCTPDBG(SCTP_DEBUG_AUTH1,
  1.1782 +			"SCTP Auth: HMAC digest check failed\n");
  1.1783 +		return (-1);
  1.1784 +	}
  1.1785 +	return (0);
  1.1786 +}
  1.1787 +
  1.1788 +/*
  1.1789 + * Generate NOTIFICATION
  1.1790 + */
  1.1791 +void
  1.1792 +sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
  1.1793 +			   uint16_t keyid, uint16_t alt_keyid, int so_locked
  1.1794 +#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
  1.1795 +	SCTP_UNUSED
  1.1796 +#endif
  1.1797 +)
  1.1798 +{
  1.1799 +	struct mbuf *m_notify;
  1.1800 +	struct sctp_authkey_event *auth;
  1.1801 +	struct sctp_queued_to_read *control;
  1.1802 +
  1.1803 +	if ((stcb == NULL) ||
  1.1804 +	   (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
  1.1805 +	   (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
  1.1806 +	   (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)
  1.1807 +		) {
  1.1808 +		/* If the socket is gone we are out of here */
  1.1809 +		return;
  1.1810 +	}
  1.1811 +
  1.1812 +	if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_AUTHEVNT))
  1.1813 +		/* event not enabled */
  1.1814 +		return;
  1.1815 +
  1.1816 +	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_authkey_event),
  1.1817 +					  0, M_NOWAIT, 1, MT_HEADER);
  1.1818 +	if (m_notify == NULL)
  1.1819 +		/* no space left */
  1.1820 +		return;
  1.1821 +
  1.1822 +	SCTP_BUF_LEN(m_notify) = 0;
  1.1823 +	auth = mtod(m_notify, struct sctp_authkey_event *);
  1.1824 +	auth->auth_type = SCTP_AUTHENTICATION_EVENT;
  1.1825 +	auth->auth_flags = 0;
  1.1826 +	auth->auth_length = sizeof(*auth);
  1.1827 +	auth->auth_keynumber = keyid;
  1.1828 +	auth->auth_altkeynumber = alt_keyid;
  1.1829 +	auth->auth_indication = indication;
  1.1830 +	auth->auth_assoc_id = sctp_get_associd(stcb);
  1.1831 +
  1.1832 +	SCTP_BUF_LEN(m_notify) = sizeof(*auth);
  1.1833 +	SCTP_BUF_NEXT(m_notify) = NULL;
  1.1834 +
  1.1835 +	/* append to socket */
  1.1836 +	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
  1.1837 +	    0, 0, stcb->asoc.context, 0, 0, 0, m_notify);
  1.1838 +	if (control == NULL) {
  1.1839 +		/* no memory */
  1.1840 +		sctp_m_freem(m_notify);
  1.1841 +		return;
  1.1842 +	}
  1.1843 +	control->spec_flags = M_NOTIFICATION;
  1.1844 +	control->length = SCTP_BUF_LEN(m_notify);
  1.1845 +	/* not that we need this */
  1.1846 +	control->tail_mbuf = m_notify;
  1.1847 +	sctp_add_to_readq(stcb->sctp_ep, stcb, control,
  1.1848 +	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
  1.1849 +}
  1.1850 +
  1.1851 +
  1.1852 +/*-
  1.1853 + * validates the AUTHentication related parameters in an INIT/INIT-ACK
  1.1854 + * Note: currently only used for INIT as INIT-ACK is handled inline
  1.1855 + * with sctp_load_addresses_from_init()
  1.1856 + */
  1.1857 +int
  1.1858 +sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
  1.1859 +{
  1.1860 +	struct sctp_paramhdr *phdr, parm_buf;
  1.1861 +	uint16_t ptype, plen;
  1.1862 +	int peer_supports_asconf = 0;
  1.1863 +	int peer_supports_auth = 0;
  1.1864 +	int got_random = 0, got_hmacs = 0, got_chklist = 0;
  1.1865 +	uint8_t saw_asconf = 0;
  1.1866 +	uint8_t saw_asconf_ack = 0;
  1.1867 +
  1.1868 +	/* go through each of the params. */
  1.1869 +	phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
  1.1870 +	while (phdr) {
  1.1871 +		ptype = ntohs(phdr->param_type);
  1.1872 +		plen = ntohs(phdr->param_length);
  1.1873 +
  1.1874 +		if (offset + plen > limit) {
  1.1875 +			break;
  1.1876 +		}
  1.1877 +		if (plen < sizeof(struct sctp_paramhdr)) {
  1.1878 +			break;
  1.1879 +		}
  1.1880 +		if (ptype == SCTP_SUPPORTED_CHUNK_EXT) {
  1.1881 +			/* A supported extension chunk */
  1.1882 +			struct sctp_supported_chunk_types_param *pr_supported;
  1.1883 +			uint8_t local_store[SCTP_PARAM_BUFFER_SIZE];
  1.1884 +			int num_ent, i;
  1.1885 +
  1.1886 +			phdr = sctp_get_next_param(m, offset,
  1.1887 +			    (struct sctp_paramhdr *)&local_store, min(plen,sizeof(local_store)));
  1.1888 +			if (phdr == NULL) {
  1.1889 +				return (-1);
  1.1890 +			}
  1.1891 +			pr_supported = (struct sctp_supported_chunk_types_param *)phdr;
  1.1892 +			num_ent = plen - sizeof(struct sctp_paramhdr);
  1.1893 +			for (i = 0; i < num_ent; i++) {
  1.1894 +				switch (pr_supported->chunk_types[i]) {
  1.1895 +				case SCTP_ASCONF:
  1.1896 +				case SCTP_ASCONF_ACK:
  1.1897 +					peer_supports_asconf = 1;
  1.1898 +					break;
  1.1899 +				default:
  1.1900 +					/* one we don't care about */
  1.1901 +					break;
  1.1902 +				}
  1.1903 +			}
  1.1904 +		} else if (ptype == SCTP_RANDOM) {
  1.1905 +			got_random = 1;
  1.1906 +			/* enforce the random length */
  1.1907 +			if (plen != (sizeof(struct sctp_auth_random) +
  1.1908 +				     SCTP_AUTH_RANDOM_SIZE_REQUIRED)) {
  1.1909 +				SCTPDBG(SCTP_DEBUG_AUTH1,
  1.1910 +					"SCTP: invalid RANDOM len\n");
  1.1911 +				return (-1);
  1.1912 +			}
  1.1913 +		} else if (ptype == SCTP_HMAC_LIST) {
  1.1914 +			uint8_t store[SCTP_PARAM_BUFFER_SIZE];
  1.1915 +			struct sctp_auth_hmac_algo *hmacs;
  1.1916 +			int num_hmacs;
  1.1917 +
  1.1918 +			if (plen > sizeof(store))
  1.1919 +				break;
  1.1920 +			phdr = sctp_get_next_param(m, offset,
  1.1921 +			    (struct sctp_paramhdr *)store, min(plen,sizeof(store)));
  1.1922 +			if (phdr == NULL)
  1.1923 +				return (-1);
  1.1924 +			hmacs = (struct sctp_auth_hmac_algo *)phdr;
  1.1925 +			num_hmacs = (plen - sizeof(*hmacs)) /
  1.1926 +			    sizeof(hmacs->hmac_ids[0]);
  1.1927 +			/* validate the hmac list */
  1.1928 +			if (sctp_verify_hmac_param(hmacs, num_hmacs)) {
  1.1929 +				SCTPDBG(SCTP_DEBUG_AUTH1,
  1.1930 +					"SCTP: invalid HMAC param\n");
  1.1931 +				return (-1);
  1.1932 +			}
  1.1933 +			got_hmacs = 1;
  1.1934 +		} else if (ptype == SCTP_CHUNK_LIST) {
  1.1935 +			int i, num_chunks;
  1.1936 +			uint8_t chunks_store[SCTP_SMALL_CHUNK_STORE];
  1.1937 +			/* did the peer send a non-empty chunk list? */
  1.1938 +			struct sctp_auth_chunk_list *chunks = NULL;
  1.1939 +			phdr = sctp_get_next_param(m, offset,
  1.1940 +						   (struct sctp_paramhdr *)chunks_store,
  1.1941 +						   min(plen,sizeof(chunks_store)));
  1.1942 +			if (phdr == NULL)
  1.1943 +				return (-1);
  1.1944 +
  1.1945 +			/*-
  1.1946 +			 * Flip through the list and mark that the
  1.1947 +			 * peer supports asconf/asconf_ack.
  1.1948 +			 */
  1.1949 +			chunks = (struct sctp_auth_chunk_list *)phdr;
  1.1950 +			num_chunks = plen - sizeof(*chunks);
  1.1951 +			for (i = 0; i < num_chunks; i++) {
  1.1952 +				/* record asconf/asconf-ack if listed */
  1.1953 +				if (chunks->chunk_types[i] == SCTP_ASCONF)
  1.1954 +					saw_asconf = 1;
  1.1955 +				if (chunks->chunk_types[i] == SCTP_ASCONF_ACK)
  1.1956 +					saw_asconf_ack = 1;
  1.1957 +
  1.1958 +			}
  1.1959 +			if (num_chunks)
  1.1960 +				got_chklist = 1;
  1.1961 +		}
  1.1962 +
  1.1963 +		offset += SCTP_SIZE32(plen);
  1.1964 +		if (offset >= limit) {
  1.1965 +			break;
  1.1966 +		}
  1.1967 +		phdr = sctp_get_next_param(m, offset, &parm_buf,
  1.1968 +		    sizeof(parm_buf));
  1.1969 +	}
  1.1970 +	/* validate authentication required parameters */
  1.1971 +	if (got_random && got_hmacs) {
  1.1972 +		peer_supports_auth = 1;
  1.1973 +	} else {
  1.1974 +		peer_supports_auth = 0;
  1.1975 +	}
  1.1976 +	if (!peer_supports_auth && got_chklist) {
  1.1977 +		SCTPDBG(SCTP_DEBUG_AUTH1,
  1.1978 +			"SCTP: peer sent chunk list w/o AUTH\n");
  1.1979 +		return (-1);
  1.1980 +	}
  1.1981 +	if (!SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk) && peer_supports_asconf &&
  1.1982 +	    !peer_supports_auth) {
  1.1983 +		SCTPDBG(SCTP_DEBUG_AUTH1,
  1.1984 +			"SCTP: peer supports ASCONF but not AUTH\n");
  1.1985 +		return (-1);
  1.1986 +	} else if ((peer_supports_asconf) && (peer_supports_auth) &&
  1.1987 +		   ((saw_asconf == 0) || (saw_asconf_ack == 0))) {
  1.1988 +		return (-2);
  1.1989 +	}
  1.1990 +	return (0);
  1.1991 +}
  1.1992 +
  1.1993 +void
  1.1994 +sctp_initialize_auth_params(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
  1.1995 +{
  1.1996 +	uint16_t chunks_len = 0;
  1.1997 +	uint16_t hmacs_len = 0;
  1.1998 +	uint16_t random_len = SCTP_AUTH_RANDOM_SIZE_DEFAULT;
  1.1999 +	sctp_key_t *new_key;
  1.2000 +	uint16_t keylen;
  1.2001 +
  1.2002 +	/* initialize hmac list from endpoint */
  1.2003 +	stcb->asoc.local_hmacs = sctp_copy_hmaclist(inp->sctp_ep.local_hmacs);
  1.2004 +	if (stcb->asoc.local_hmacs != NULL) {
  1.2005 +		hmacs_len = stcb->asoc.local_hmacs->num_algo *
  1.2006 +		    sizeof(stcb->asoc.local_hmacs->hmac[0]);
  1.2007 +	}
  1.2008 +	/* initialize auth chunks list from endpoint */
  1.2009 +	stcb->asoc.local_auth_chunks =
  1.2010 +	    sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks);
  1.2011 +	if (stcb->asoc.local_auth_chunks != NULL) {
  1.2012 +		int i;
  1.2013 +		for (i = 0; i < 256; i++) {
  1.2014 +			if (stcb->asoc.local_auth_chunks->chunks[i])
  1.2015 +				chunks_len++;
  1.2016 +		}
  1.2017 +	}
  1.2018 +	/* copy defaults from the endpoint */
  1.2019 +	stcb->asoc.authinfo.active_keyid = inp->sctp_ep.default_keyid;
  1.2020 +
  1.2021 +	/* copy out the shared key list (by reference) from the endpoint */
  1.2022 +	(void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys,
  1.2023 +				 &stcb->asoc.shared_keys);
  1.2024 +
  1.2025 +	/* now set the concatenated key (random + chunks + hmacs) */
  1.2026 +	/* key includes parameter headers */
  1.2027 +	keylen = (3 * sizeof(struct sctp_paramhdr)) + random_len + chunks_len +
  1.2028 +	    hmacs_len;
  1.2029 +	new_key = sctp_alloc_key(keylen);
  1.2030 +	if (new_key != NULL) {
  1.2031 +		struct sctp_paramhdr *ph;
  1.2032 +		int plen;
  1.2033 +		/* generate and copy in the RANDOM */
  1.2034 +		ph = (struct sctp_paramhdr *)new_key->key;
  1.2035 +		ph->param_type = htons(SCTP_RANDOM);
  1.2036 +		plen = sizeof(*ph) + random_len;
  1.2037 +		ph->param_length = htons(plen);
  1.2038 +		SCTP_READ_RANDOM(new_key->key + sizeof(*ph), random_len);
  1.2039 +		keylen = plen;
  1.2040 +
  1.2041 +		/* append in the AUTH chunks */
  1.2042 +		/* NOTE: currently we always have chunks to list */
  1.2043 +		ph = (struct sctp_paramhdr *)(new_key->key + keylen);
  1.2044 +		ph->param_type = htons(SCTP_CHUNK_LIST);
  1.2045 +		plen = sizeof(*ph) + chunks_len;
  1.2046 +		ph->param_length = htons(plen);
  1.2047 +		keylen += sizeof(*ph);
  1.2048 +		if (stcb->asoc.local_auth_chunks) {
  1.2049 +			int i;
  1.2050 +			for (i = 0; i < 256; i++) {
  1.2051 +				if (stcb->asoc.local_auth_chunks->chunks[i])
  1.2052 +					new_key->key[keylen++] = i;
  1.2053 +			}
  1.2054 +		}
  1.2055 +
  1.2056 +		/* append in the HMACs */
  1.2057 +		ph = (struct sctp_paramhdr *)(new_key->key + keylen);
  1.2058 +		ph->param_type = htons(SCTP_HMAC_LIST);
  1.2059 +		plen = sizeof(*ph) + hmacs_len;
  1.2060 +		ph->param_length = htons(plen);
  1.2061 +		keylen += sizeof(*ph);
  1.2062 +		(void)sctp_serialize_hmaclist(stcb->asoc.local_hmacs,
  1.2063 +					new_key->key + keylen);
  1.2064 +	}
  1.2065 +	if (stcb->asoc.authinfo.random != NULL)
  1.2066 +	    sctp_free_key(stcb->asoc.authinfo.random);
  1.2067 +	stcb->asoc.authinfo.random = new_key;
  1.2068 +	stcb->asoc.authinfo.random_len = random_len;
  1.2069 +}
  1.2070 +
  1.2071 +
  1.2072 +#ifdef SCTP_HMAC_TEST
  1.2073 +/*
  1.2074 + * HMAC and key concatenation tests
  1.2075 + */
  1.2076 +static void
  1.2077 +sctp_print_digest(uint8_t *digest, uint32_t digestlen, const char *str)
  1.2078 +{
  1.2079 +	uint32_t i;
  1.2080 +
  1.2081 +	SCTP_PRINTF("\n%s: 0x", str);
  1.2082 +	if (digest == NULL)
  1.2083 +		return;
  1.2084 +
  1.2085 +	for (i = 0; i < digestlen; i++)
  1.2086 +		SCTP_PRINTF("%02x", digest[i]);
  1.2087 +}
  1.2088 +
  1.2089 +static int
  1.2090 +sctp_test_hmac(const char *str, uint16_t hmac_id, uint8_t *key,
  1.2091 +    uint32_t keylen, uint8_t *text, uint32_t textlen,
  1.2092 +    uint8_t *digest, uint32_t digestlen)
  1.2093 +{
  1.2094 +	uint8_t computed_digest[SCTP_AUTH_DIGEST_LEN_MAX];
  1.2095 +
  1.2096 +	SCTP_PRINTF("\n%s:", str);
  1.2097 +	sctp_hmac(hmac_id, key, keylen, text, textlen, computed_digest);
  1.2098 +	sctp_print_digest(digest, digestlen, "Expected digest");
  1.2099 +	sctp_print_digest(computed_digest, digestlen, "Computed digest");
  1.2100 +	if (memcmp(digest, computed_digest, digestlen) != 0) {
  1.2101 +		SCTP_PRINTF("\nFAILED");
  1.2102 +		return (-1);
  1.2103 +	} else {
  1.2104 +		SCTP_PRINTF("\nPASSED");
  1.2105 +		return (0);
  1.2106 +	}
  1.2107 +}
  1.2108 +
  1.2109 +
  1.2110 +/*
  1.2111 + * RFC 2202: HMAC-SHA1 test cases
  1.2112 + */
  1.2113 +void
  1.2114 +sctp_test_hmac_sha1(void)
  1.2115 +{
  1.2116 +	uint8_t *digest;
  1.2117 +	uint8_t key[128];
  1.2118 +	uint32_t keylen;
  1.2119 +	uint8_t text[128];
  1.2120 +	uint32_t textlen;
  1.2121 +	uint32_t digestlen = 20;
  1.2122 +	int failed = 0;
  1.2123 +
  1.2124 +	/*-
  1.2125 +	 * test_case =     1
  1.2126 +	 * key =           0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
  1.2127 +	 * key_len =       20
  1.2128 +	 * data =          "Hi There"
  1.2129 +	 * data_len =      8
  1.2130 +	 * digest =        0xb617318655057264e28bc0b6fb378c8ef146be00
  1.2131 +	 */
  1.2132 +	keylen = 20;
  1.2133 +	memset(key, 0x0b, keylen);
  1.2134 +	textlen = 8;
  1.2135 +	strcpy(text, "Hi There");
  1.2136 +	digest = "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00";
  1.2137 +	if (sctp_test_hmac("SHA1 test case 1", SCTP_AUTH_HMAC_ID_SHA1, key, keylen,
  1.2138 +	    text, textlen, digest, digestlen) < 0)
  1.2139 +		failed++;
  1.2140 +
  1.2141 +	/*-
  1.2142 +	 * test_case =     2
  1.2143 +	 * key =           "Jefe"
  1.2144 +	 * key_len =       4
  1.2145 +	 * data =          "what do ya want for nothing?"
  1.2146 +	 * data_len =      28
  1.2147 +	 * digest =        0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
  1.2148 +	 */
  1.2149 +	keylen = 4;
  1.2150 +	strcpy(key, "Jefe");
  1.2151 +	textlen = 28;
  1.2152 +	strcpy(text, "what do ya want for nothing?");
  1.2153 +	digest = "\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79";
  1.2154 +	if (sctp_test_hmac("SHA1 test case 2", SCTP_AUTH_HMAC_ID_SHA1, key, keylen,
  1.2155 +	    text, textlen, digest, digestlen) < 0)
  1.2156 +		failed++;
  1.2157 +
  1.2158 +	/*-
  1.2159 +	 * test_case =     3
  1.2160 +	 * key =           0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  1.2161 +	 * key_len =       20
  1.2162 +	 * data =          0xdd repeated 50 times
  1.2163 +	 * data_len =      50
  1.2164 +	 * digest =        0x125d7342b9ac11cd91a39af48aa17b4f63f175d3
  1.2165 +	 */
  1.2166 +	keylen = 20;
  1.2167 +	memset(key, 0xaa, keylen);
  1.2168 +	textlen = 50;
  1.2169 +	memset(text, 0xdd, textlen);
  1.2170 +	digest = "\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3";
  1.2171 +	if (sctp_test_hmac("SHA1 test case 3", SCTP_AUTH_HMAC_ID_SHA1, key, keylen,
  1.2172 +	    text, textlen, digest, digestlen) < 0)
  1.2173 +		failed++;
  1.2174 +
  1.2175 +	/*-
  1.2176 +	 * test_case =     4
  1.2177 +	 * key =           0x0102030405060708090a0b0c0d0e0f10111213141516171819
  1.2178 +	 * key_len =       25
  1.2179 +	 * data =          0xcd repeated 50 times
  1.2180 +	 * data_len =      50
  1.2181 +	 * digest =        0x4c9007f4026250c6bc8414f9bf50c86c2d7235da
  1.2182 +	 */
  1.2183 +	keylen = 25;
  1.2184 +	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);
  1.2185 +	textlen = 50;
  1.2186 +	memset(text, 0xcd, textlen);
  1.2187 +	digest = "\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda";
  1.2188 +	if (sctp_test_hmac("SHA1 test case 4", SCTP_AUTH_HMAC_ID_SHA1, key, keylen,
  1.2189 +	    text, textlen, digest, digestlen) < 0)
  1.2190 +		failed++;
  1.2191 +
  1.2192 +	/*-
  1.2193 +	 * test_case =     5
  1.2194 +	 * key =           0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
  1.2195 +	 * key_len =       20
  1.2196 +	 * data =          "Test With Truncation"
  1.2197 +	 * data_len =      20
  1.2198 +	 * digest =        0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
  1.2199 +	 * digest-96 =     0x4c1a03424b55e07fe7f27be1
  1.2200 +	 */
  1.2201 +	keylen = 20;
  1.2202 +	memset(key, 0x0c, keylen);
  1.2203 +	textlen = 20;
  1.2204 +	strcpy(text, "Test With Truncation");
  1.2205 +	digest = "\x4c\x1a\x03\x42\x4b\x55\xe0\x7f\xe7\xf2\x7b\xe1\xd5\x8b\xb9\x32\x4a\x9a\x5a\x04";
  1.2206 +	if (sctp_test_hmac("SHA1 test case 5", SCTP_AUTH_HMAC_ID_SHA1, key, keylen,
  1.2207 +	    text, textlen, digest, digestlen) < 0)
  1.2208 +		failed++;
  1.2209 +
  1.2210 +	/*-
  1.2211 +	 * test_case =     6
  1.2212 +	 * key =           0xaa repeated 80 times
  1.2213 +	 * key_len =       80
  1.2214 +	 * data =          "Test Using Larger Than Block-Size Key - Hash Key First"
  1.2215 +	 * data_len =      54
  1.2216 +	 * digest =        0xaa4ae5e15272d00e95705637ce8a3b55ed402112
  1.2217 +	 */
  1.2218 +	keylen = 80;
  1.2219 +	memset(key, 0xaa, keylen);
  1.2220 +	textlen = 54;
  1.2221 +	strcpy(text, "Test Using Larger Than Block-Size Key - Hash Key First");
  1.2222 +	digest = "\xaa\x4a\xe5\xe1\x52\x72\xd0\x0e\x95\x70\x56\x37\xce\x8a\x3b\x55\xed\x40\x21\x12";
  1.2223 +	if (sctp_test_hmac("SHA1 test case 6", SCTP_AUTH_HMAC_ID_SHA1, key, keylen,
  1.2224 +	    text, textlen, digest, digestlen) < 0)
  1.2225 +		failed++;
  1.2226 +
  1.2227 +	/*-
  1.2228 +	 * test_case =     7
  1.2229 +	 * key =           0xaa repeated 80 times
  1.2230 +	 * key_len =       80
  1.2231 +	 * data =          "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
  1.2232 +	 * data_len =      73
  1.2233 +	 * digest =        0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
  1.2234 +	 */
  1.2235 +	keylen = 80;
  1.2236 +	memset(key, 0xaa, keylen);
  1.2237 +	textlen = 73;
  1.2238 +	strcpy(text, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data");
  1.2239 +	digest = "\xe8\xe9\x9d\x0f\x45\x23\x7d\x78\x6d\x6b\xba\xa7\x96\x5c\x78\x08\xbb\xff\x1a\x91";
  1.2240 +	if (sctp_test_hmac("SHA1 test case 7", SCTP_AUTH_HMAC_ID_SHA1, key, keylen,
  1.2241 +	    text, textlen, digest, digestlen) < 0)
  1.2242 +		failed++;
  1.2243 +
  1.2244 +	/* done with all tests */
  1.2245 +	if (failed)
  1.2246 +		SCTP_PRINTF("\nSHA1 test results: %d cases failed", failed);
  1.2247 +	else
  1.2248 +		SCTP_PRINTF("\nSHA1 test results: all test cases passed");
  1.2249 +}
  1.2250 +
  1.2251 +/*
  1.2252 + * test assoc key concatenation
  1.2253 + */
  1.2254 +static int
  1.2255 +sctp_test_key_concatenation(sctp_key_t *key1, sctp_key_t *key2,
  1.2256 +    sctp_key_t *expected_key)
  1.2257 +{
  1.2258 +	sctp_key_t *key;
  1.2259 +	int ret_val;
  1.2260 +
  1.2261 +	sctp_show_key(key1, "\nkey1");
  1.2262 +	sctp_show_key(key2, "\nkey2");
  1.2263 +	key = sctp_compute_hashkey(key1, key2, NULL);
  1.2264 +	sctp_show_key(expected_key, "\nExpected");
  1.2265 +	sctp_show_key(key, "\nComputed");
  1.2266 +	if (memcmp(key, expected_key, expected_key->keylen) != 0) {
  1.2267 +		SCTP_PRINTF("\nFAILED");
  1.2268 +		ret_val = -1;
  1.2269 +	} else {
  1.2270 +		SCTP_PRINTF("\nPASSED");
  1.2271 +		ret_val = 0;
  1.2272 +	}
  1.2273 +	sctp_free_key(key1);
  1.2274 +	sctp_free_key(key2);
  1.2275 +	sctp_free_key(expected_key);
  1.2276 +	sctp_free_key(key);
  1.2277 +	return (ret_val);
  1.2278 +}
  1.2279 +
  1.2280 +
  1.2281 +void
  1.2282 +sctp_test_authkey(void)
  1.2283 +{
  1.2284 +	sctp_key_t *key1, *key2, *expected_key;
  1.2285 +	int failed = 0;
  1.2286 +
  1.2287 +	/* test case 1 */
  1.2288 +	key1 = sctp_set_key("\x01\x01\x01\x01", 4);
  1.2289 +	key2 = sctp_set_key("\x01\x02\x03\x04", 4);
  1.2290 +	expected_key = sctp_set_key("\x01\x01\x01\x01\x01\x02\x03\x04", 8);
  1.2291 +	if (sctp_test_key_concatenation(key1, key2, expected_key) < 0)
  1.2292 +		failed++;
  1.2293 +
  1.2294 +	/* test case 2 */
  1.2295 +	key1 = sctp_set_key("\x00\x00\x00\x01", 4);
  1.2296 +	key2 = sctp_set_key("\x02", 1);
  1.2297 +	expected_key = sctp_set_key("\x00\x00\x00\x01\x02", 5);
  1.2298 +	if (sctp_test_key_concatenation(key1, key2, expected_key) < 0)
  1.2299 +		failed++;
  1.2300 +
  1.2301 +	/* test case 3 */
  1.2302 +	key1 = sctp_set_key("\x01", 1);
  1.2303 +	key2 = sctp_set_key("\x00\x00\x00\x02", 4);
  1.2304 +	expected_key = sctp_set_key("\x01\x00\x00\x00\x02", 5);
  1.2305 +	if (sctp_test_key_concatenation(key1, key2, expected_key) < 0)
  1.2306 +		failed++;
  1.2307 +
  1.2308 +	/* test case 4 */
  1.2309 +	key1 = sctp_set_key("\x00\x00\x00\x01", 4);
  1.2310 +	key2 = sctp_set_key("\x01", 1);
  1.2311 +	expected_key = sctp_set_key("\x01\x00\x00\x00\x01", 5);
  1.2312 +	if (sctp_test_key_concatenation(key1, key2, expected_key) < 0)
  1.2313 +		failed++;
  1.2314 +
  1.2315 +	/* test case 5 */
  1.2316 +	key1 = sctp_set_key("\x01", 1);
  1.2317 +	key2 = sctp_set_key("\x00\x00\x00\x01", 4);
  1.2318 +	expected_key = sctp_set_key("\x01\x00\x00\x00\x01", 5);
  1.2319 +	if (sctp_test_key_concatenation(key1, key2, expected_key) < 0)
  1.2320 +		failed++;
  1.2321 +
  1.2322 +	/* test case 6 */
  1.2323 +	key1 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07", 11);
  1.2324 +	key2 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x08", 11);
  1.2325 +	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);
  1.2326 +	if (sctp_test_key_concatenation(key1, key2, expected_key) < 0)
  1.2327 +		failed++;
  1.2328 +
  1.2329 +	/* test case 7 */
  1.2330 +	key1 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x08", 11);
  1.2331 +	key2 = sctp_set_key("\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07", 11);
  1.2332 +	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);
  1.2333 +	if (sctp_test_key_concatenation(key1, key2, expected_key) < 0)
  1.2334 +		failed++;
  1.2335 +
  1.2336 +	/* done with all tests */
  1.2337 +	if (failed)
  1.2338 +		SCTP_PRINTF("\nKey concatenation test results: %d cases failed", failed);
  1.2339 +	else
  1.2340 +		SCTP_PRINTF("\nKey concatenation test results: all test cases passed");
  1.2341 +}
  1.2342 +
  1.2343 +
  1.2344 +#if defined(STANDALONE_HMAC_TEST)
  1.2345 +int
  1.2346 +main(void)
  1.2347 +{
  1.2348 +	sctp_test_hmac_sha1();
  1.2349 +	sctp_test_authkey();
  1.2350 +}
  1.2351 +
  1.2352 +#endif /* STANDALONE_HMAC_TEST */
  1.2353 +
  1.2354 +#endif /* SCTP_HMAC_TEST */

mercurial