FreeBSD/sys/netinet/sctp_auth.c
/*
 * get local authentication parameters from cookie (from INIT-ACK)
 */
get local authentication parameters from cookie (from INIT-ACK)
get local authentication parameters from cookie ( from INIT - ACK )
void
sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
    uint32_t offset, uint32_t length)
{
	struct sctp_paramhdr *phdr, tmp_param;
	uint16_t plen, ptype;
	uint8_t random_store[SCTP_PARAM_BUFFER_SIZE];
	struct sctp_auth_random *p_random = NULL;
	uint16_t random_len = 0;
	uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE];
	struct sctp_auth_hmac_algo *hmacs = NULL;
	uint16_t hmacs_len = 0;
	uint8_t chunks_store[SCTP_PARAM_BUFFER_SIZE];
	struct sctp_auth_chunk_list *chunks = NULL;
	uint16_t num_chunks = 0;
	sctp_key_t *new_key;
	uint32_t keylen;
	length += offset;
	phdr = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
	    sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
	while (phdr != NULL) {
		ptype = ntohs(phdr->param_type);
		plen = ntohs(phdr->param_length);
		if ((plen == 0) || (offset + plen > length))
			break;
		if (ptype == SCTP_RANDOM) {
			if (plen > sizeof(random_store))
				break;
			phdr = sctp_get_next_param(m, offset,
			    (struct sctp_paramhdr *)random_store, min(plen, sizeof(random_store)));
			if (phdr == NULL)
				return;
			p_random = (struct sctp_auth_random *)phdr;
			random_len = plen - sizeof(*p_random);
		} else if (ptype == SCTP_HMAC_LIST) {
			uint16_t num_hmacs;
			uint16_t i;
			if (plen > sizeof(hmacs_store))
				break;
			phdr = sctp_get_next_param(m, offset,
			    (struct sctp_paramhdr *)hmacs_store, min(plen, sizeof(hmacs_store)));
			if (phdr == NULL)
				return;
			hmacs = (struct sctp_auth_hmac_algo *)phdr;
			hmacs_len = plen - sizeof(*hmacs);
			num_hmacs = hmacs_len / sizeof(hmacs->hmac_ids[0]);
			if (stcb->asoc.local_hmacs != NULL)
				sctp_free_hmaclist(stcb->asoc.local_hmacs);
			stcb->asoc.local_hmacs = sctp_alloc_hmaclist(num_hmacs);
			if (stcb->asoc.local_hmacs != NULL) {
				for (i = 0; i < num_hmacs; i++) {
					(void)sctp_auth_add_hmacid(stcb->asoc.local_hmacs,
					    ntohs(hmacs->hmac_ids[i]));
				}
			}
		} else if (ptype == SCTP_CHUNK_LIST) {
			int i;
			if (plen > sizeof(chunks_store))
				break;
			phdr = sctp_get_next_param(m, offset,
			    (struct sctp_paramhdr *)chunks_store, min(plen, sizeof(chunks_store)));
			if (phdr == NULL)
				return;
			chunks = (struct sctp_auth_chunk_list *)phdr;
			num_chunks = plen - sizeof(*chunks);
			if (stcb->asoc.local_auth_chunks != NULL)
				sctp_clear_chunklist(stcb->asoc.local_auth_chunks);
			else
				stcb->asoc.local_auth_chunks = sctp_alloc_chunklist();
			for (i = 0; i < num_chunks; i++) {
				(void)sctp_auth_add_chunk(chunks->chunk_types[i],
				    stcb->asoc.local_auth_chunks);
			}
		}
		offset += SCTP_SIZE32(plen);
		if (offset + sizeof(struct sctp_paramhdr) > length)
			break;
		phdr = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
		    (uint8_t *) & tmp_param);
	}
	keylen = sizeof(*p_random) + random_len + sizeof(*hmacs) + hmacs_len;
	if (chunks != NULL) {
		keylen += sizeof(*chunks) + num_chunks;
	}
	new_key = sctp_alloc_key(keylen);
	if (new_key != NULL) {
		if (p_random != NULL) {
			keylen = sizeof(*p_random) + random_len;
			bcopy(p_random, new_key->key, keylen);
		}
		if (chunks != NULL) {
			bcopy(chunks, new_key->key + keylen,
			    sizeof(*chunks) + num_chunks);
			keylen += sizeof(*chunks) + num_chunks;
		}
		if (hmacs != NULL) {
			bcopy(hmacs, new_key->key + keylen,
			    sizeof(*hmacs) + hmacs_len);
		}
	}
	if (stcb->asoc.authinfo.random != NULL)
		sctp_free_key(stcb->asoc.authinfo.random);
	stcb->asoc.authinfo.random = new_key;
	stcb->asoc.authinfo.random_len = random_len;
	sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.assoc_keyid);
	sctp_clear_cachedkeys(stcb, stcb->asoc.authinfo.recv_keyid);
	stcb->asoc.peer_hmac_id = sctp_negotiate_hmacid(stcb->asoc.peer_hmacs,
	    stcb->asoc.local_hmacs);
	stcb->asoc.authinfo.active_keyid = stcb->sctp_ep->sctp_ep.default_keyid;
	(void)sctp_copy_skeylist(&stcb->sctp_ep->sctp_ep.shared_keys,
	    &stcb->asoc.shared_keys);
}
void sctp_auth_get_cookie_params ( struct sctp_tcb * stcb , struct mbuf * m , uint32_t offset , uint32_t length ) { struct sctp_paramhdr * phdr , tmp_param ; uint16_t plen , ptype ; uint8_t random_store [ SCTP_PARAM_BUFFER_SIZE ] ; struct sctp_auth_random * p_random = NULL ; uint16_t random_len = 0 ; uint8_t hmacs_store [ SCTP_PARAM_BUFFER_SIZE ] ; struct sctp_auth_hmac_algo * hmacs = NULL ; uint16_t hmacs_len = 0 ; uint8_t chunks_store [ SCTP_PARAM_BUFFER_SIZE ] ; struct sctp_auth_chunk_list * chunks = NULL ; uint16_t num_chunks = 0 ; sctp_key_t * new_key ; uint32_t keylen ; length += offset ; phdr = ( struct sctp_paramhdr * ) sctp_m_getptr ( m , offset , sizeof ( struct sctp_paramhdr ) , ( uint8_t * ) & tmp_param ) ; while ( phdr != NULL ) { ptype = ntohs ( phdr -> param_type ) ; plen = ntohs ( phdr -> param_length ) ; if ( ( plen == 0 ) || ( offset + plen > length ) ) break ; if ( ptype == SCTP_RANDOM ) { if ( plen > sizeof ( random_store ) ) break ; phdr = sctp_get_next_param ( m , offset , ( struct sctp_paramhdr * ) random_store , min ( plen , sizeof ( random_store ) ) ) ; if ( phdr == NULL ) return ; p_random = ( struct sctp_auth_random * ) phdr ; random_len = plen - sizeof ( * p_random ) ; } else if ( ptype == SCTP_HMAC_LIST ) { uint16_t num_hmacs ; uint16_t i ; if ( plen > sizeof ( hmacs_store ) ) break ; phdr = sctp_get_next_param ( m , offset , ( struct sctp_paramhdr * ) hmacs_store , min ( plen , sizeof ( hmacs_store ) ) ) ; if ( phdr == NULL ) return ; hmacs = ( struct sctp_auth_hmac_algo * ) phdr ; hmacs_len = plen - sizeof ( * hmacs ) ; num_hmacs = hmacs_len / sizeof ( hmacs -> hmac_ids [ 0 ] ) ; if ( stcb -> asoc . local_hmacs != NULL ) sctp_free_hmaclist ( stcb -> asoc . local_hmacs ) ; stcb -> asoc . local_hmacs = sctp_alloc_hmaclist ( num_hmacs ) ; if ( stcb -> asoc . local_hmacs != NULL ) { for ( i = 0 ; i < num_hmacs ; i ++ ) { ( void ) sctp_auth_add_hmacid ( stcb -> asoc . local_hmacs , ntohs ( hmacs -> hmac_ids [ i ] ) ) ; } } } else if ( ptype == SCTP_CHUNK_LIST ) { int i ; if ( plen > sizeof ( chunks_store ) ) break ; phdr = sctp_get_next_param ( m , offset , ( struct sctp_paramhdr * ) chunks_store , min ( plen , sizeof ( chunks_store ) ) ) ; if ( phdr == NULL ) return ; chunks = ( struct sctp_auth_chunk_list * ) phdr ; num_chunks = plen - sizeof ( * chunks ) ; if ( stcb -> asoc . local_auth_chunks != NULL ) sctp_clear_chunklist ( stcb -> asoc . local_auth_chunks ) ; else stcb -> asoc . local_auth_chunks = sctp_alloc_chunklist ( ) ; for ( i = 0 ; i < num_chunks ; i ++ ) { ( void ) sctp_auth_add_chunk ( chunks -> chunk_types [ i ] , stcb -> asoc . local_auth_chunks ) ; } } offset += SCTP_SIZE32 ( plen ) ; if ( offset + sizeof ( struct sctp_paramhdr ) > length ) break ; phdr = ( struct sctp_paramhdr * ) sctp_m_getptr ( m , offset , sizeof ( struct sctp_paramhdr ) , ( uint8_t * ) & tmp_param ) ; } keylen = sizeof ( * p_random ) + random_len + sizeof ( * hmacs ) + hmacs_len ; if ( chunks != NULL ) { keylen += sizeof ( * chunks ) + num_chunks ; } new_key = sctp_alloc_key ( keylen ) ; if ( new_key != NULL ) { if ( p_random != NULL ) { keylen = sizeof ( * p_random ) + random_len ; bcopy ( p_random , new_key -> key , keylen ) ; } if ( chunks != NULL ) { bcopy ( chunks , new_key -> key + keylen , sizeof ( * chunks ) + num_chunks ) ; keylen += sizeof ( * chunks ) + num_chunks ; } if ( hmacs != NULL ) { bcopy ( hmacs , new_key -> key + keylen , sizeof ( * hmacs ) + hmacs_len ) ; } } if ( stcb -> asoc . authinfo . random != NULL ) sctp_free_key ( stcb -> asoc . authinfo . random ) ; stcb -> asoc . authinfo . random = new_key ; stcb -> asoc . authinfo . random_len = random_len ; sctp_clear_cachedkeys ( stcb , stcb -> asoc . authinfo . assoc_keyid ) ; sctp_clear_cachedkeys ( stcb , stcb -> asoc . authinfo . recv_keyid ) ; stcb -> asoc . peer_hmac_id = sctp_negotiate_hmacid ( stcb -> asoc . peer_hmacs , stcb -> asoc . local_hmacs ) ; stcb -> asoc . authinfo . active_keyid = stcb -> sctp_ep -> sctp_ep . default_keyid ; ( void ) sctp_copy_skeylist ( & stcb -> sctp_ep -> sctp_ep . shared_keys , & stcb -> asoc . shared_keys ) ; }
get local authentication parameters from cookie (from INIT-ACK)
get local authentication parameters from cookie ( from INIT - ACK )
/* convert to upper bound */ /* save the random and length for the key */ /* save the hmacs list and num for the key */ /* save chunks list and num for the key */ /* get next parameter */ /* concatenate the full random key */ /* copy in the RANDOM */ /* append in the AUTH chunks */ /* append in the HMACs */ /* negotiate what HMAC to use for the peer */ /* copy defaults from the endpoint */ /* FIX ME: put in cookie? */ /* copy out the shared key list (by reference) from the endpoint */