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