FreeBSD/sys/netinet/sctp_auth.c
/*-
 * validates the AUTHentication related parameters in an INIT/INIT-ACK
 * Note: currently only used for INIT as INIT-ACK is handled inline
 * with sctp_load_addresses_from_init()
 */
validates the AUTHentication related parameters in an INIT/INIT-ACK
Note: currently only used for INIT as INIT-ACK is handled inline
with sctp_load_addresses_from_init()
validates the AUTHentication related parameters in an INIT / INIT - ACK Note : currently only used for INIT as INIT - ACK is handled inline with sctp_load_addresses_from_init ()
int
sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
{
	struct sctp_paramhdr *phdr, parm_buf;
	uint16_t ptype, plen;
	int peer_supports_asconf = 0;
	int peer_supports_auth = 0;
	int got_random = 0, got_hmacs = 0, got_chklist = 0;
	uint8_t saw_asconf = 0;
	uint8_t saw_asconf_ack = 0;
	phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
	while (phdr) {
		ptype = ntohs(phdr->param_type);
		plen = ntohs(phdr->param_length);
		if (offset + plen > limit) {
			break;
		}
		if (plen < sizeof(struct sctp_paramhdr)) {
			break;
		}
		if (ptype == SCTP_SUPPORTED_CHUNK_EXT) {
			struct sctp_supported_chunk_types_param *pr_supported;
			uint8_t local_store[SCTP_PARAM_BUFFER_SIZE];
			int num_ent, i;
			phdr = sctp_get_next_param(m, offset,
			    (struct sctp_paramhdr *)&local_store, min(plen, sizeof(local_store)));
			if (phdr == NULL) {
				return (-1);
			}
			pr_supported = (struct sctp_supported_chunk_types_param *)phdr;
			num_ent = plen - sizeof(struct sctp_paramhdr);
			for (i = 0; i < num_ent; i++) {
				switch (pr_supported->chunk_types[i]) {
				case SCTP_ASCONF:
				case SCTP_ASCONF_ACK:
					peer_supports_asconf = 1;
					break;
				default:
					break;
				}
			}
		} else if (ptype == SCTP_RANDOM) {
			got_random = 1;
			if (plen != (sizeof(struct sctp_auth_random) +
			    SCTP_AUTH_RANDOM_SIZE_REQUIRED)) {
				SCTPDBG(SCTP_DEBUG_AUTH1,
				    "SCTP: invalid RANDOM len\n");
				return (-1);
			}
		} else if (ptype == SCTP_HMAC_LIST) {
			uint8_t store[SCTP_PARAM_BUFFER_SIZE];
			struct sctp_auth_hmac_algo *hmacs;
			int num_hmacs;
			if (plen > sizeof(store))
				break;
			phdr = sctp_get_next_param(m, offset,
			    (struct sctp_paramhdr *)store, min(plen, sizeof(store)));
			if (phdr == NULL)
				return (-1);
			hmacs = (struct sctp_auth_hmac_algo *)phdr;
			num_hmacs = (plen - sizeof(*hmacs)) /
			    sizeof(hmacs->hmac_ids[0]);
			if (sctp_verify_hmac_param(hmacs, num_hmacs)) {
				SCTPDBG(SCTP_DEBUG_AUTH1,
				    "SCTP: invalid HMAC param\n");
				return (-1);
			}
			got_hmacs = 1;
		} else if (ptype == SCTP_CHUNK_LIST) {
			int i, num_chunks;
			uint8_t chunks_store[SCTP_SMALL_CHUNK_STORE];
			struct sctp_auth_chunk_list *chunks = NULL;
			phdr = sctp_get_next_param(m, offset,
			    (struct sctp_paramhdr *)chunks_store,
			    min(plen, sizeof(chunks_store)));
			if (phdr == NULL)
				return (-1);
			chunks = (struct sctp_auth_chunk_list *)phdr;
			num_chunks = plen - sizeof(*chunks);
			for (i = 0; i < num_chunks; i++) {
				if (chunks->chunk_types[i] == SCTP_ASCONF)
					saw_asconf = 1;
				if (chunks->chunk_types[i] == SCTP_ASCONF_ACK)
					saw_asconf_ack = 1;
			}
			if (num_chunks)
				got_chklist = 1;
		}
		offset += SCTP_SIZE32(plen);
		if (offset >= limit) {
			break;
		}
		phdr = sctp_get_next_param(m, offset, &parm_buf,
		    sizeof(parm_buf));
	}
	if (got_random && got_hmacs) {
		peer_supports_auth = 1;
	} else {
		peer_supports_auth = 0;
	}
	if (!peer_supports_auth && got_chklist) {
		SCTPDBG(SCTP_DEBUG_AUTH1,
		    "SCTP: peer sent chunk list w/o AUTH\n");
		return (-1);
	}
	if (peer_supports_asconf && !peer_supports_auth) {
		SCTPDBG(SCTP_DEBUG_AUTH1,
		    "SCTP: peer supports ASCONF but not AUTH\n");
		return (-1);
	} else if ((peer_supports_asconf) && (peer_supports_auth) &&
	    ((saw_asconf == 0) || (saw_asconf_ack == 0))) {
		return (-2);
	}
	return (0);
}
int sctp_validate_init_auth_params ( struct mbuf * m , int offset , int limit ) { struct sctp_paramhdr * phdr , parm_buf ; uint16_t ptype , plen ; int peer_supports_asconf = 0 ; int peer_supports_auth = 0 ; int got_random = 0 , got_hmacs = 0 , got_chklist = 0 ; uint8_t saw_asconf = 0 ; uint8_t saw_asconf_ack = 0 ; phdr = sctp_get_next_param ( m , offset , & parm_buf , sizeof ( parm_buf ) ) ; while ( phdr ) { ptype = ntohs ( phdr -> param_type ) ; plen = ntohs ( phdr -> param_length ) ; if ( offset + plen > limit ) { break ; } if ( plen < sizeof ( struct sctp_paramhdr ) ) { break ; } if ( ptype == SCTP_SUPPORTED_CHUNK_EXT ) { struct sctp_supported_chunk_types_param * pr_supported ; uint8_t local_store [ SCTP_PARAM_BUFFER_SIZE ] ; int num_ent , i ; phdr = sctp_get_next_param ( m , offset , ( struct sctp_paramhdr * ) & local_store , min ( plen , sizeof ( local_store ) ) ) ; if ( phdr == NULL ) { return ( -1 ) ; } pr_supported = ( struct sctp_supported_chunk_types_param * ) phdr ; num_ent = plen - sizeof ( struct sctp_paramhdr ) ; for ( i = 0 ; i < num_ent ; i ++ ) { switch ( pr_supported -> chunk_types [ i ] ) { case SCTP_ASCONF : case SCTP_ASCONF_ACK : peer_supports_asconf = 1 ; break ; default : break ; } } } else if ( ptype == SCTP_RANDOM ) { got_random = 1 ; if ( plen != ( sizeof ( struct sctp_auth_random ) + SCTP_AUTH_RANDOM_SIZE_REQUIRED ) ) { SCTPDBG ( SCTP_DEBUG_AUTH1 , " \n " ) ; return ( -1 ) ; } } else if ( ptype == SCTP_HMAC_LIST ) { uint8_t store [ SCTP_PARAM_BUFFER_SIZE ] ; struct sctp_auth_hmac_algo * hmacs ; int num_hmacs ; if ( plen > sizeof ( store ) ) break ; phdr = sctp_get_next_param ( m , offset , ( struct sctp_paramhdr * ) store , min ( plen , sizeof ( store ) ) ) ; if ( phdr == NULL ) return ( -1 ) ; hmacs = ( struct sctp_auth_hmac_algo * ) phdr ; num_hmacs = ( plen - sizeof ( * hmacs ) ) / sizeof ( hmacs -> hmac_ids [ 0 ] ) ; if ( sctp_verify_hmac_param ( hmacs , num_hmacs ) ) { SCTPDBG ( SCTP_DEBUG_AUTH1 , " \n " ) ; return ( -1 ) ; } got_hmacs = 1 ; } else if ( ptype == SCTP_CHUNK_LIST ) { int i , num_chunks ; uint8_t chunks_store [ SCTP_SMALL_CHUNK_STORE ] ; struct sctp_auth_chunk_list * chunks = NULL ; phdr = sctp_get_next_param ( m , offset , ( struct sctp_paramhdr * ) chunks_store , min ( plen , sizeof ( chunks_store ) ) ) ; if ( phdr == NULL ) return ( -1 ) ; chunks = ( struct sctp_auth_chunk_list * ) phdr ; num_chunks = plen - sizeof ( * chunks ) ; for ( i = 0 ; i < num_chunks ; i ++ ) { if ( chunks -> chunk_types [ i ] == SCTP_ASCONF ) saw_asconf = 1 ; if ( chunks -> chunk_types [ i ] == SCTP_ASCONF_ACK ) saw_asconf_ack = 1 ; } if ( num_chunks ) got_chklist = 1 ; } offset += SCTP_SIZE32 ( plen ) ; if ( offset >= limit ) { break ; } phdr = sctp_get_next_param ( m , offset , & parm_buf , sizeof ( parm_buf ) ) ; } if ( got_random && got_hmacs ) { peer_supports_auth = 1 ; } else { peer_supports_auth = 0 ; } if ( ! peer_supports_auth && got_chklist ) { SCTPDBG ( SCTP_DEBUG_AUTH1 , " \n " ) ; return ( -1 ) ; } if ( peer_supports_asconf && ! peer_supports_auth ) { SCTPDBG ( SCTP_DEBUG_AUTH1 , " \n " ) ; return ( -1 ) ; } else if ( ( peer_supports_asconf ) && ( peer_supports_auth ) && ( ( saw_asconf == 0 ) || ( saw_asconf_ack == 0 ) ) ) { return ( -2 ) ; } return ( 0 ) ; }
validates the AUTHentication related parameters in an INIT/INIT-ACK
 Note: currently only used for INIT as INIT-ACK is handled inline
 with sctp_load_addresses_from_init()
validates the AUTHentication related parameters in an INIT / INIT - ACK Note : currently only used for INIT as INIT - ACK is handled inline with sctp_load_addresses_from_init ()
/* go through each of the params. */ /* A supported extension chunk */ /* one we don't care about */ /* enforce the random length */ /* validate the hmac list */ /* did the peer send a non-empty chunk list? */ /*-
			 * Flip through the list and mark that the
			 * peer supports asconf/asconf_ack.
			 */ /* record asconf/asconf-ack if listed */ /* validate authentication required parameters */