2013-05-01 14:52:55 +02:00
# include "capwap.h"
# include "capwap_dtls.h"
# include "capwap_protocol.h"
2014-05-15 21:43:21 +02:00
# include <cyassl/options.h>
# include <cyassl/ssl.h>
# include <cyassl/ctaocrypt/sha.h>
2013-05-27 23:10:49 +02:00
2013-05-01 14:52:55 +02:00
/* */
2014-05-15 21:43:21 +02:00
static const char g_char2hex [ ] = {
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
10 , 11 , 12 , 13 , 14 , 15 , /* Upper Case A - F */
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
10 , 11 , 12 , 13 , 14 , 15 /* Lower Case a - f */
2013-05-01 14:52:55 +02:00
} ;
2014-05-15 21:43:21 +02:00
static const int g_char2hex_length = sizeof ( g_char2hex ) / sizeof ( g_char2hex [ 0 ] ) ;
2013-05-01 14:52:55 +02:00
/* */
2014-05-15 21:43:21 +02:00
static int capwap_bio_method_recv ( CYASSL * ssl , char * buffer , int length , void * context ) {
struct capwap_dtls * dtls = ( struct capwap_dtls * ) context ;
2013-05-01 14:52:55 +02:00
struct capwap_dtls_header * dtlspreamble ;
int size ;
/* Check read packet */
2014-05-15 21:43:21 +02:00
if ( ( dtls - > length < sizeof ( struct capwap_dtls_header ) ) | | ! dtls - > buffer ) {
if ( ! dtls - > length & & ! dtls - > buffer ) {
return CYASSL_CBIO_ERR_WANT_READ ; /* Notify empty buffer */
2013-05-01 14:52:55 +02:00
}
2014-05-15 21:43:21 +02:00
return CYASSL_CBIO_ERR_GENERAL ;
2013-05-01 14:52:55 +02:00
}
/* Check DTLS Capwap Preamble */
2014-05-15 21:43:21 +02:00
dtlspreamble = ( struct capwap_dtls_header * ) dtls - > buffer ;
2013-05-01 14:52:55 +02:00
if ( ( dtlspreamble - > preamble . version ! = CAPWAP_PROTOCOL_VERSION ) | | ( dtlspreamble - > preamble . type ! = CAPWAP_PREAMBLE_DTLS_HEADER ) ) {
capwap_logging_debug ( " Wrong DTLS Capwap Preamble " ) ;
2014-05-15 21:43:21 +02:00
return CYASSL_CBIO_ERR_GENERAL ; /* Wrong DTLS Capwap Preamble */
2013-05-01 14:52:55 +02:00
}
/* */
2014-05-15 21:43:21 +02:00
size = dtls - > length - sizeof ( struct capwap_dtls_header ) ;
dtls - > length = 0 ;
2013-05-01 14:52:55 +02:00
2014-05-15 21:43:21 +02:00
dtls - > buffer + = sizeof ( struct capwap_dtls_header ) ;
2013-05-01 14:52:55 +02:00
if ( size > length ) {
2014-05-15 21:43:21 +02:00
dtls - > buffer = NULL ;
return CYASSL_CBIO_ERR_GENERAL ;
2013-05-01 14:52:55 +02:00
}
/* Copy DTLS packet */
2014-05-15 21:43:21 +02:00
memcpy ( buffer , dtls - > buffer , size ) ;
dtls - > buffer = NULL ;
2013-05-01 14:52:55 +02:00
return size ;
}
/* */
2014-05-15 21:43:21 +02:00
static int capwap_bio_method_send ( CYASSL * ssl , char * buffer , int length , void * context ) {
char data [ CAPWAP_MAX_PACKET_SIZE ] ;
struct capwap_dtls * dtls = ( struct capwap_dtls * ) context ;
struct capwap_dtls_header * dtlspreamble = ( struct capwap_dtls_header * ) data ;
2013-05-01 14:52:55 +02:00
/* Check for maxium size of packet */
if ( length > ( CAPWAP_MAX_PACKET_SIZE - sizeof ( struct capwap_dtls_header ) ) ) {
2014-05-15 21:43:21 +02:00
return CYASSL_CBIO_ERR_GENERAL ;
2013-05-01 14:52:55 +02:00
}
2014-05-15 21:43:21 +02:00
2013-05-01 14:52:55 +02:00
/* Create DTLS Capwap Preamble */
dtlspreamble - > preamble . version = CAPWAP_PROTOCOL_VERSION ;
dtlspreamble - > preamble . type = CAPWAP_PREAMBLE_DTLS_HEADER ;
dtlspreamble - > reserved1 = dtlspreamble - > reserved2 = dtlspreamble - > reserved3 = 0 ;
2014-05-15 21:43:21 +02:00
memcpy ( & data [ 0 ] + sizeof ( struct capwap_dtls_header ) , buffer , length ) ;
2013-05-01 14:52:55 +02:00
/* Send packet */
2014-05-15 21:43:21 +02:00
if ( ! dtls - > send ( dtls , data , length + sizeof ( struct capwap_dtls_header ) , dtls - > sendparam ) ) {
return CYASSL_CBIO_ERR_GENERAL ;
2013-05-01 14:52:55 +02:00
}
2014-05-15 21:43:21 +02:00
2013-05-01 14:52:55 +02:00
/* Don't return size of DTLS Capwap Preamble */
return length ;
}
/* */
2014-05-15 21:43:21 +02:00
int capwap_crypt_init ( ) {
int result ;
2013-05-01 14:52:55 +02:00
2014-05-15 21:43:21 +02:00
/* Init library */
result = CyaSSL_Init ( ) ;
if ( result ! = SSL_SUCCESS ) {
return - 1 ;
2013-05-01 14:52:55 +02:00
}
2014-05-15 21:43:21 +02:00
return 0 ;
2013-05-23 22:38:48 +02:00
}
/* */
2014-05-15 21:43:21 +02:00
void capwap_crypt_free ( ) {
CyaSSL_Cleanup ( ) ;
2013-05-23 22:38:48 +02:00
}
2013-05-01 14:52:55 +02:00
/* */
2014-05-15 21:43:21 +02:00
static int capwap_crypt_verifycertificate ( int preverify_ok , CYASSL_X509_STORE_CTX * ctx ) {
return preverify_ok ;
2013-05-01 14:52:55 +02:00
}
/* */
2014-05-15 21:43:21 +02:00
static unsigned int capwap_crypt_psk_client ( CYASSL * ssl , const char * hint , char * identity , unsigned int max_identity_len , unsigned char * psk , unsigned int max_psk_len ) {
struct capwap_dtls * dtls = ( struct capwap_dtls * ) CyaSSL_GetIOReadCtx ( ssl ) ;
2013-05-27 21:33:23 +02:00
2014-05-15 21:43:21 +02:00
ASSERT ( dtls ! = NULL ) ;
ASSERT ( dtls - > dtlscontext ! = NULL ) ;
2013-05-23 22:38:48 +02:00
/* */
2014-05-15 21:43:21 +02:00
if ( ( max_identity_len < strlen ( dtls - > dtlscontext - > presharedkey . identity ) ) | | ( max_psk_len < dtls - > dtlscontext - > presharedkey . pskkeylength ) ) {
return 0 ;
2013-05-23 22:38:48 +02:00
}
/* */
2014-05-15 21:43:21 +02:00
strcpy ( identity , dtls - > dtlscontext - > presharedkey . identity ) ;
memcpy ( psk , dtls - > dtlscontext - > presharedkey . pskkey , dtls - > dtlscontext - > presharedkey . pskkeylength ) ;
return dtls - > dtlscontext - > presharedkey . pskkeylength ;
2013-05-01 14:52:55 +02:00
}
/* */
2014-05-15 21:43:21 +02:00
static unsigned int capwap_crypt_psk_server ( CYASSL * ssl , const char * identity , unsigned char * psk , unsigned int max_psk_len ) {
struct capwap_dtls * dtls = ( struct capwap_dtls * ) CyaSSL_GetIOReadCtx ( ssl ) ;
ASSERT ( dtls ! = NULL ) ;
ASSERT ( dtls - > dtlscontext ! = NULL ) ;
2013-05-01 14:52:55 +02:00
2014-05-15 21:43:21 +02:00
/* */
if ( strcmp ( identity , dtls - > dtlscontext - > presharedkey . identity ) | | ( max_psk_len < dtls - > dtlscontext - > presharedkey . pskkeylength ) ) {
2013-05-01 14:52:55 +02:00
return 0 ;
}
2014-05-15 21:43:21 +02:00
/* */
memcpy ( psk , dtls - > dtlscontext - > presharedkey . pskkey , dtls - > dtlscontext - > presharedkey . pskkeylength ) ;
return dtls - > dtlscontext - > presharedkey . pskkeylength ;
2013-05-01 14:52:55 +02:00
}
/* */
2014-05-15 21:43:21 +02:00
static unsigned int capwap_crypt_psk_to_bin ( char * pskkey , unsigned char * * pskbin ) {
int i , j ;
2013-05-01 14:52:55 +02:00
int length ;
2014-05-15 21:43:21 +02:00
int result ;
2013-05-01 14:52:55 +02:00
unsigned char * buffer ;
2014-05-15 21:43:21 +02:00
/* Convert string to hex */
length = strlen ( pskkey ) ;
if ( ! length | | ( length % 2 ) ) {
2013-05-01 14:52:55 +02:00
return 0 ;
}
/* */
2014-05-15 21:43:21 +02:00
result = length / 2 ;
buffer = ( unsigned char * ) capwap_alloc ( result ) ;
for ( i = 0 , j = 0 ; i < length ; i + = 2 , j + + ) {
char valuehi = pskkey [ i ] - 48 ;
char valuelo = pskkey [ i + 1 ] - 48 ;
/* Check value */
if ( ( valuehi < 0 ) | | ( valuehi > = g_char2hex_length ) | | ( valuelo < 0 ) | | ( valuelo > = g_char2hex_length ) ) {
capwap_free ( buffer ) ;
return 0 ;
}
2013-05-01 14:52:55 +02:00
2014-05-15 21:43:21 +02:00
/* */
valuehi = g_char2hex [ ( int ) valuehi ] ;
valuelo = g_char2hex [ ( int ) valuelo ] ;
2013-05-01 14:52:55 +02:00
2014-05-15 21:43:21 +02:00
/* Check value */
if ( ( valuehi < 0 ) | | ( valuelo < 0 ) ) {
capwap_free ( buffer ) ;
return 0 ;
}
2013-05-01 14:52:55 +02:00
2014-05-15 21:43:21 +02:00
/* */
buffer [ j ] = ( unsigned char ) ( ( ( unsigned char ) valuehi < < 4 ) | ( unsigned char ) valuelo ) ;
2013-05-01 14:52:55 +02:00
}
2014-05-15 21:43:21 +02:00
/* */
* pskbin = buffer ;
return result ;
2013-05-01 14:52:55 +02:00
}
/* */
2014-05-15 21:43:21 +02:00
static int capwap_crypt_createcookie ( CYASSL * ssl , unsigned char * buffer , int size , void * context ) {
int length ;
unsigned char temp [ 32 ] ;
Sha sha ;
byte digest [ SHA_DIGEST_SIZE ] ;
struct capwap_dtls * dtls = ( struct capwap_dtls * ) context ;
2013-05-01 14:52:55 +02:00
2014-05-15 21:43:21 +02:00
if ( size ! = SHA_DIGEST_SIZE ) {
return - 1 ;
2013-05-01 14:52:55 +02:00
}
2014-05-15 21:43:21 +02:00
/* Create buffer with peer's address and port */
if ( dtls - > peeraddr . ss_family = = AF_INET ) {
struct sockaddr_in * peeripv4 = ( struct sockaddr_in * ) & dtls - > peeraddr ;
2013-05-27 23:10:49 +02:00
2014-05-15 21:43:21 +02:00
length = sizeof ( struct in_addr ) + sizeof ( in_port_t ) ;
memcpy ( temp , & peeripv4 - > sin_port , sizeof ( in_port_t ) ) ;
memcpy ( temp + sizeof ( in_port_t ) , & peeripv4 - > sin_addr , sizeof ( struct in_addr ) ) ;
} else if ( dtls - > peeraddr . ss_family = = AF_INET6 ) {
struct sockaddr_in6 * peeripv6 = ( struct sockaddr_in6 * ) & dtls - > peeraddr ;
2013-05-27 23:10:49 +02:00
2014-05-15 21:43:21 +02:00
length = sizeof ( struct in6_addr ) + sizeof ( in_port_t ) ;
memcpy ( temp , & peeripv6 - > sin6_port , sizeof ( in_port_t ) ) ;
memcpy ( temp + sizeof ( in_port_t ) , & peeripv6 - > sin6_addr , sizeof ( struct in6_addr ) ) ;
} else {
return - 1 ;
2013-05-27 23:10:49 +02:00
}
/* */
2014-05-15 21:43:21 +02:00
if ( InitSha ( & sha ) ) {
return - 1 ;
2013-05-27 23:10:49 +02:00
}
2014-05-15 21:43:21 +02:00
ShaUpdate ( & sha , temp , length ) ;
ShaFinal ( & sha , digest ) ;
2013-05-27 23:10:49 +02:00
/* */
2014-05-15 21:43:21 +02:00
memcpy ( buffer , digest , SHA_DIGEST_SIZE ) ;
return SHA_DIGEST_SIZE ;
2013-05-27 23:10:49 +02:00
}
/* */
int capwap_crypt_createcontext ( struct capwap_dtls_context * dtlscontext , struct capwap_dtls_param * param ) {
2013-05-01 14:52:55 +02:00
ASSERT ( dtlscontext ! = NULL ) ;
ASSERT ( param ! = NULL ) ;
2013-05-27 23:10:49 +02:00
2013-05-01 14:52:55 +02:00
memset ( dtlscontext , 0 , sizeof ( struct capwap_dtls_context ) ) ;
dtlscontext - > type = param - > type ;
dtlscontext - > mode = param - > mode ;
2013-05-27 23:10:49 +02:00
2013-05-01 14:52:55 +02:00
/* Alloc context */
2014-05-15 21:43:21 +02:00
dtlscontext - > sslcontext = ( void * ) CyaSSL_CTX_new ( ( ( param - > type = = CAPWAP_DTLS_SERVER ) ? CyaDTLSv1_server_method ( ) : CyaDTLSv1_client_method ( ) ) ) ;
2013-05-01 14:52:55 +02:00
if ( ! dtlscontext - > sslcontext ) {
capwap_logging_debug ( " Error to initialize dtls context " ) ;
return 0 ;
}
2013-05-27 23:10:49 +02:00
2014-05-15 21:43:21 +02:00
/* Set context IO */
CyaSSL_SetIORecv ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , capwap_bio_method_recv ) ;
CyaSSL_SetIOSend ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , capwap_bio_method_send ) ;
CyaSSL_CTX_SetGenCookie ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , capwap_crypt_createcookie ) ;
/* */
2013-05-01 14:52:55 +02:00
if ( dtlscontext - > mode = = CAPWAP_DTLS_MODE_CERTIFICATE ) {
/* Check context */
if ( ! param - > cert . filecert | | ! strlen ( param - > cert . filecert ) ) {
capwap_logging_debug ( " Error, request certificate file " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
} else if ( ! param - > cert . filekey | | ! strlen ( param - > cert . filekey ) ) {
capwap_logging_debug ( " Error, request privatekey file " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
} else if ( ! param - > cert . fileca | | ! strlen ( param - > cert . fileca ) ) {
capwap_logging_debug ( " Error, request ca file " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
}
2013-05-27 23:10:49 +02:00
2013-05-01 14:52:55 +02:00
/* Public certificate */
2014-05-15 21:43:21 +02:00
if ( ! CyaSSL_CTX_use_certificate_file ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , param - > cert . filecert , SSL_FILETYPE_PEM ) ) {
2013-05-01 14:52:55 +02:00
capwap_logging_debug ( " Error to load certificate file " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
}
2013-05-27 23:10:49 +02:00
2013-05-01 14:52:55 +02:00
/* Private key */
2014-05-15 21:43:21 +02:00
if ( ! CyaSSL_CTX_use_PrivateKey_file ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , param - > cert . filekey , SSL_FILETYPE_PEM ) ) {
2013-05-01 14:52:55 +02:00
capwap_logging_debug ( " Error to load private key file " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
}
2013-05-27 23:10:49 +02:00
2014-05-15 21:43:21 +02:00
if ( ! CyaSSL_CTX_check_private_key ( ( CYASSL_CTX * ) dtlscontext - > sslcontext ) ) {
2013-05-01 14:52:55 +02:00
capwap_logging_debug ( " Error to check private key " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
}
2013-05-27 23:10:49 +02:00
2013-05-01 14:52:55 +02:00
/* Certificate Authority */
2014-05-15 21:43:21 +02:00
if ( ! CyaSSL_CTX_load_verify_locations ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , param - > cert . fileca , NULL ) ) {
2013-05-01 14:52:55 +02:00
capwap_logging_debug ( " Error to load ca file " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
}
2013-05-27 23:10:49 +02:00
2013-05-01 14:52:55 +02:00
/* Verify certificate callback */
2014-05-15 21:43:21 +02:00
CyaSSL_CTX_set_verify ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , ( ( param - > type = = CAPWAP_DTLS_SERVER ) ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_PEER ) , capwap_crypt_verifycertificate ) ;
2013-05-01 14:52:55 +02:00
/* Cipher list:
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
*/
2014-05-15 21:43:21 +02:00
if ( ! CyaSSL_CTX_set_cipher_list ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , " AES128-SHA:DHE-RSA-AES128-SHA:AES256-SHA:DHE-RSA-AES256-SHA " ) ) {
2013-05-01 14:52:55 +02:00
capwap_logging_debug ( " Error to select cipher list " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
}
} else if ( dtlscontext - > mode = = CAPWAP_DTLS_MODE_PRESHAREDKEY ) {
2013-05-27 23:10:49 +02:00
/* Cipher list:
TLS_PSK_WITH_AES_128_CBC_SHA
TLS_DHE_PSK_WITH_AES_128_CBC_SHA
TLS_PSK_WITH_AES_256_CBC_SHA
TLS_DHE_PSK_WITH_AES_256_CBC_SHA
*/
2014-05-15 21:43:21 +02:00
if ( ! CyaSSL_CTX_set_cipher_list ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , " PSK-AES128-CBC-SHA:PSK-AES256-CBC-SHA " ) ) {
2013-05-27 23:10:49 +02:00
capwap_logging_debug ( " Error to select cipher list " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
}
/* */
if ( dtlscontext - > type = = CAPWAP_DTLS_SERVER ) {
if ( param - > presharedkey . hint ) {
2014-05-15 21:43:21 +02:00
CyaSSL_CTX_use_psk_identity_hint ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , param - > presharedkey . hint ) ;
2013-05-27 23:10:49 +02:00
} else {
capwap_logging_debug ( " Error to presharedkey hint " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
}
}
/* */
dtlscontext - > presharedkey . identity = capwap_duplicate_string ( param - > presharedkey . identity ) ;
dtlscontext - > presharedkey . pskkeylength = capwap_crypt_psk_to_bin ( param - > presharedkey . pskkey , & dtlscontext - > presharedkey . pskkey ) ;
if ( ! dtlscontext - > presharedkey . pskkeylength ) {
capwap_logging_debug ( " Error to presharedkey " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
}
/* */
if ( dtlscontext - > type = = CAPWAP_DTLS_SERVER ) {
2014-05-15 21:43:21 +02:00
CyaSSL_CTX_set_psk_server_callback ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , capwap_crypt_psk_server ) ;
2013-05-27 23:10:49 +02:00
} else {
2014-05-15 21:43:21 +02:00
CyaSSL_CTX_set_psk_client_callback ( ( CYASSL_CTX * ) dtlscontext - > sslcontext , capwap_crypt_psk_client ) ;
2013-05-27 23:10:49 +02:00
}
2013-05-01 14:52:55 +02:00
} else {
capwap_logging_debug ( " Invalid DTLS mode " ) ;
capwap_crypt_freecontext ( dtlscontext ) ;
return 0 ;
}
return 1 ;
}
/* */
void capwap_crypt_freecontext ( struct capwap_dtls_context * dtlscontext ) {
ASSERT ( dtlscontext ! = NULL ) ;
/* */
2014-05-15 21:43:21 +02:00
if ( dtlscontext - > mode = = CAPWAP_DTLS_MODE_PRESHAREDKEY ) {
2013-05-27 23:10:49 +02:00
if ( dtlscontext - > presharedkey . identity ) {
capwap_free ( dtlscontext - > presharedkey . identity ) ;
}
if ( dtlscontext - > presharedkey . pskkey ) {
capwap_free ( dtlscontext - > presharedkey . pskkey ) ;
}
2013-05-01 14:52:55 +02:00
}
/* Free context */
if ( dtlscontext - > sslcontext ) {
2014-05-15 21:43:21 +02:00
CyaSSL_CTX_free ( ( CYASSL_CTX * ) dtlscontext - > sslcontext ) ;
2013-05-01 14:52:55 +02:00
}
2014-05-15 21:43:21 +02:00
memset ( dtlscontext , 0 , sizeof ( struct capwap_dtls_context ) ) ;
2013-05-01 14:52:55 +02:00
}
/* */
int capwap_crypt_createsession ( struct capwap_dtls * dtls , int sessiontype , struct capwap_dtls_context * dtlscontext , capwap_bio_send biosend , void * param ) {
ASSERT ( dtls ! = NULL ) ;
ASSERT ( dtlscontext ! = NULL ) ;
2014-05-15 21:43:21 +02:00
ASSERT ( dtlscontext - > sslcontext ! = NULL ) ;
2013-05-01 14:52:55 +02:00
ASSERT ( biosend ! = NULL ) ;
memset ( dtls , 0 , sizeof ( struct capwap_dtls ) ) ;
/* Create ssl session */
2014-05-15 21:43:21 +02:00
dtls - > sslsession = ( void * ) CyaSSL_new ( ( CYASSL_CTX * ) dtlscontext - > sslcontext ) ;
2013-05-01 14:52:55 +02:00
if ( ! dtls - > sslsession ) {
capwap_logging_debug ( " Error to initialize dtls session " ) ;
return 0 ;
}
2014-05-15 21:43:21 +02:00
/* Send callback */
dtls - > send = biosend ;
dtls - > sendparam = param ;
2013-05-01 14:52:55 +02:00
/* */
2014-05-15 21:43:21 +02:00
CyaSSL_set_using_nonblock ( ( CYASSL * ) dtls - > sslsession , 1 ) ;
CyaSSL_SetIOReadCtx ( ( CYASSL * ) dtls - > sslsession , ( void * ) dtls ) ;
CyaSSL_SetIOWriteCtx ( ( CYASSL * ) dtls - > sslsession , ( void * ) dtls ) ;
CyaSSL_SetCookieCtx ( ( CYASSL * ) dtls - > sslsession , ( void * ) dtls ) ;
2013-05-01 14:52:55 +02:00
/* */
dtls - > action = CAPWAP_DTLS_ACTION_NONE ;
dtls - > session = sessiontype ;
2014-05-15 21:43:21 +02:00
dtls - > dtlscontext = dtlscontext ;
2013-05-01 14:52:55 +02:00
dtls - > enable = 1 ;
return 1 ;
}
/* */
static int capwap_crypt_handshake ( struct capwap_dtls * dtls ) {
int result ;
ASSERT ( dtls ! = NULL ) ;
ASSERT ( dtls - > enable ! = 0 ) ;
ASSERT ( ( dtls - > action = = CAPWAP_DTLS_ACTION_NONE ) | | ( dtls - > action = = CAPWAP_DTLS_ACTION_HANDSHAKE ) ) ;
2014-05-15 21:43:21 +02:00
/* */
if ( dtls - > dtlscontext - > type = = CAPWAP_DTLS_SERVER ) {
result = CyaSSL_accept ( ( CYASSL * ) dtls - > sslsession ) ;
} else {
result = CyaSSL_connect ( ( CYASSL * ) dtls - > sslsession ) ;
}
/* */
if ( result ! = SSL_SUCCESS ) {
result = CyaSSL_get_error ( ( CYASSL * ) dtls - > sslsession , 0 ) ;
2013-05-01 14:52:55 +02:00
if ( ( result = = SSL_ERROR_WANT_READ ) | | ( result = = SSL_ERROR_WANT_WRITE ) ) {
/* Incomplete handshake */
dtls - > action = CAPWAP_DTLS_ACTION_HANDSHAKE ;
return CAPWAP_HANDSHAKE_CONTINUE ;
}
/* Handshake error */
dtls - > action = CAPWAP_DTLS_ACTION_ERROR ;
return CAPWAP_HANDSHAKE_ERROR ;
}
2014-05-15 21:43:21 +02:00
2013-05-01 14:52:55 +02:00
/* Handshake complete */
dtls - > action = CAPWAP_DTLS_ACTION_DATA ;
return CAPWAP_HANDSHAKE_COMPLETE ;
}
/* */
int capwap_crypt_open ( struct capwap_dtls * dtls , struct sockaddr_storage * peeraddr ) {
2014-05-15 21:43:21 +02:00
memcpy ( & dtls - > peeraddr , peeraddr , sizeof ( struct sockaddr_storage ) ) ;
2013-05-01 14:52:55 +02:00
return capwap_crypt_handshake ( dtls ) ;
}
/* */
void capwap_crypt_close ( struct capwap_dtls * dtls ) {
ASSERT ( dtls ! = NULL ) ;
ASSERT ( dtls - > enable ! = 0 ) ;
2013-05-27 21:33:23 +02:00
2014-05-15 21:43:21 +02:00
if ( dtls - > sslsession ) {
CyaSSL_shutdown ( ( CYASSL * ) dtls - > sslsession ) ;
2013-05-01 14:52:55 +02:00
}
}
/* */
void capwap_crypt_freesession ( struct capwap_dtls * dtls ) {
ASSERT ( dtls ! = NULL ) ;
2013-05-27 21:33:23 +02:00
2013-05-01 14:52:55 +02:00
/* Free SSL session */
if ( dtls - > sslsession ) {
2014-05-15 21:43:21 +02:00
CyaSSL_free ( ( CYASSL * ) dtls - > sslsession ) ;
2013-05-01 14:52:55 +02:00
}
2013-05-27 21:33:23 +02:00
/* */
2013-05-01 14:52:55 +02:00
memset ( dtls , 0 , sizeof ( struct capwap_dtls ) ) ;
}
/* TODO: con SSL vengono utilizzati gli indirizzi predefiniti invece quelli specificati nella funzione. Reingegnerizzarla basandosi sul concetto di connessione */
int capwap_crypt_sendto ( struct capwap_dtls * dtls , int sock , void * buffer , int size , struct sockaddr_storage * sendfromaddr , struct sockaddr_storage * sendtoaddr ) {
ASSERT ( sock > = 0 ) ;
ASSERT ( buffer ! = NULL ) ;
ASSERT ( size > 0 ) ;
ASSERT ( sendtoaddr ! = NULL ) ;
if ( ! dtls | | ! dtls - > enable ) {
return capwap_sendto ( sock , buffer , size , sendfromaddr , sendtoaddr ) ;
}
/* Valid DTLS status */
if ( dtls - > action ! = CAPWAP_DTLS_ACTION_DATA ) {
return 0 ;
}
2014-05-15 21:43:21 +02:00
return CyaSSL_write ( ( CYASSL * ) dtls - > sslsession , buffer , size ) ;
2013-05-01 14:52:55 +02:00
}
2013-05-27 21:33:23 +02:00
/* */
int capwap_crypt_sendto_fragmentpacket ( struct capwap_dtls * dtls , int sock , struct capwap_list * fragmentlist , struct sockaddr_storage * sendfromaddr , struct sockaddr_storage * sendtoaddr ) {
struct capwap_list_item * item ;
ASSERT ( sock > = 0 ) ;
ASSERT ( fragmentlist ! = NULL ) ;
ASSERT ( sendtoaddr ! = NULL ) ;
item = fragmentlist - > first ;
while ( item ) {
struct capwap_fragment_packet_item * fragmentpacket = ( struct capwap_fragment_packet_item * ) item - > item ;
ASSERT ( fragmentpacket ! = NULL ) ;
ASSERT ( fragmentpacket - > offset > 0 ) ;
if ( ! capwap_crypt_sendto ( dtls , sock , fragmentpacket - > buffer , fragmentpacket - > offset , sendfromaddr , sendtoaddr ) ) {
return 0 ;
}
/* */
item = item - > next ;
}
return 1 ;
}
2013-05-01 14:52:55 +02:00
/* */
int capwap_decrypt_packet ( struct capwap_dtls * dtls , void * encrybuffer , int size , void * plainbuffer , int maxsize ) {
int sslerror ;
int result = - 1 ;
char * clone = NULL ;
ASSERT ( dtls ! = NULL ) ;
ASSERT ( dtls - > enable ! = 0 ) ;
ASSERT ( ( dtls - > action = = CAPWAP_DTLS_ACTION_HANDSHAKE ) | | ( dtls - > action = = CAPWAP_DTLS_ACTION_DATA ) ) ;
ASSERT ( dtls - > buffer = = NULL ) ;
ASSERT ( dtls - > length = = 0 ) ;
ASSERT ( encrybuffer ! = NULL ) ;
ASSERT ( size > 0 ) ;
ASSERT ( maxsize > 0 ) ;
/* */
if ( ! plainbuffer ) {
clone = capwap_clone ( encrybuffer , size ) ;
}
dtls - > buffer = ( clone ? clone : encrybuffer ) ;
dtls - > length = size ;
/* */
if ( dtls - > action = = CAPWAP_DTLS_ACTION_HANDSHAKE ) {
if ( capwap_crypt_handshake ( dtls ) = = CAPWAP_HANDSHAKE_ERROR ) {
capwap_logging_debug ( " Error in DTLS handshake " ) ;
result = CAPWAP_ERROR_CLOSE ; /* Error handshake */
} else {
result = CAPWAP_ERROR_AGAIN ; /* Don't parsing DTLS packet */
}
} else if ( dtls - > action = = CAPWAP_DTLS_ACTION_DATA ) {
2014-05-15 21:43:21 +02:00
result = CyaSSL_read ( ( CYASSL * ) dtls - > sslsession , ( plainbuffer ? plainbuffer : encrybuffer ) , maxsize ) ;
2013-05-01 14:52:55 +02:00
if ( ! result ) {
2014-05-15 21:43:21 +02:00
dtls - > action = CAPWAP_DTLS_ACTION_SHUTDOWN ;
result = CAPWAP_ERROR_SHUTDOWN ;
2013-05-01 14:52:55 +02:00
} else if ( result < 0 ) {
/* Check error */
2014-05-15 21:43:21 +02:00
sslerror = CyaSSL_get_error ( ( CYASSL * ) dtls - > sslsession , 0 ) ;
2013-05-01 14:52:55 +02:00
if ( ( sslerror = = SSL_ERROR_WANT_READ ) | | ( sslerror = = SSL_ERROR_WANT_WRITE ) ) {
result = CAPWAP_ERROR_AGAIN ; /* DTLS Renegotiation */
} else {
result = CAPWAP_ERROR_CLOSE ;
}
}
}
/* Verify BIO read */
ASSERT ( dtls - > buffer = = NULL ) ;
ASSERT ( dtls - > length = = 0 ) ;
/* Free clone */
if ( clone ) {
capwap_free ( clone ) ;
}
return result ;
}
2013-10-21 18:44:37 +02:00
/* */
# define SIZEOF_DTLS_LAYERS 14
# define DTLS_RECORD_LAYER_HANDSHAKE_CONTENT_TYPE 22
# define DTLS_1_0_VERSION 0xfeff
# define DTLS_1_2_VERSION 0xfefd
# define DTLS_HANDSHAKE_LAYER_CLIENT_HELLO 1
/* */
2014-05-15 21:43:21 +02:00
int capwap_crypt_has_dtls_clienthello ( void * buffer , int buffersize ) {
2013-10-21 18:44:37 +02:00
unsigned char * dtlsdata = ( unsigned char * ) buffer ;
/* Read DTLS packet in RAW mode */
if ( ( buffer ! = NULL ) & & ( buffersize > SIZEOF_DTLS_LAYERS ) ) {
if ( dtlsdata [ 0 ] = = DTLS_RECORD_LAYER_HANDSHAKE_CONTENT_TYPE ) {
uint16_t version = ntohs ( * ( uint16_t * ) ( dtlsdata + 1 ) ) ;
if ( ( ( version = = DTLS_1_0_VERSION ) | | ( version = = DTLS_1_2_VERSION ) ) & & ( dtlsdata [ 13 ] = = DTLS_HANDSHAKE_LAYER_CLIENT_HELLO ) ) {
return 1 ;
}
}
}
return 0 ;
}