/* * Fill the input message buffer */ int ssl_fetch_input(ssl_context * ssl, size_t nb_want) { int ret; size_t len; SSL_DEBUG_MSG(2, ("=> fetch input")); while (ssl->in_left < nb_want) { len = nb_want - ssl->in_left; ret = ssl->f_recv(ssl->p_recv, ssl->in_hdr + ssl->in_left, len); SSL_DEBUG_MSG(2, ("in_left: %d, nb_want: %d", ssl->in_left, nb_want)); SSL_DEBUG_RET(2, "ssl->f_recv", ret); if (ret < 0) return (ret); ssl->in_left += ret; } SSL_DEBUG_MSG(2, ("<= fetch input")); return (0); }
int ssl_init( ssl_context *ssl ) { int len = SSL_BUFFER_LEN; memset( ssl, 0, sizeof( ssl_context ) ); ssl->in_ctr = (unsigned char *) malloc( len ); ssl->in_hdr = ssl->in_ctr + 8; ssl->in_msg = ssl->in_ctr + 13; if( ssl->in_ctr == NULL ){ SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len ) ); return( 1 ); } ssl->out_ctr = (unsigned char *) malloc( len ); ssl->out_hdr = ssl->out_ctr + 8; ssl->out_msg = ssl->out_ctr + 13; if( ssl->out_ctr == NULL ) { SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len ) ); free( ssl-> in_ctr ); return( 1 ); } memset( ssl-> in_ctr, 0, SSL_BUFFER_LEN ); memset( ssl->out_ctr, 0, SSL_BUFFER_LEN ); ssl->hostname = NULL; ssl->hostname_len = 0; md5_starts( &ssl->fin_md5 ); sha1_starts( &ssl->fin_sha1 ); return 0; }
/* * Flush any data not yet written */ int ssl_flush_output(ssl_context * ssl) { int ret; uint8_t *buf; SSL_DEBUG_MSG(2, ("=> flush output")); while (ssl->out_left > 0) { SSL_DEBUG_MSG(2, ("message length: %d, out_left: %d", 5 + ssl->out_msglen, ssl->out_left)); buf = ssl->out_hdr + 5 + ssl->out_msglen - ssl->out_left; ret = ssl->f_send(ssl->p_send, buf, ssl->out_left); SSL_DEBUG_RET(2, "ssl->f_send", ret); if (ret <= 0) return (ret); ssl->out_left -= ret; } SSL_DEBUG_MSG(2, ("<= flush output")); return (0); }
static int ssl_parse_servername_ext( ssl_context *ssl, const unsigned char *buf, size_t len ) { int ret; size_t servername_list_size, hostname_len; const unsigned char *p; servername_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); if( servername_list_size + 2 != len ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } p = buf + 2; while( servername_list_size > 0 ) { hostname_len = ( ( p[1] << 8 ) | p[2] ); if( hostname_len + 3 > servername_list_size ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } if( p[0] == TLS_EXT_SERVERNAME_HOSTNAME ) { ret = ssl->f_sni( ssl->p_sni, ssl, p + 3, hostname_len ); if( ret != 0 ) { ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL, SSL_ALERT_MSG_UNRECOGNIZED_NAME ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } return( 0 ); } servername_list_size -= hostname_len + 3; p += hostname_len + 3; } if( servername_list_size != 0 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } return( 0 ); }
void ssl_calc_verify(ssl_context * ssl, uint8_t hash[36]) { md5_context md5; sha1_context sha1; uint8_t pad_1[48]; uint8_t pad_2[48]; SSL_DEBUG_MSG(2, ("=> calc verify")); memcpy(&md5, &ssl->fin_md5, sizeof(md5_context)); memcpy(&sha1, &ssl->fin_sha1, sizeof(sha1_context)); if (ssl->minor_ver == SSL_MINOR_VERSION_0) { memset(pad_1, 0x36, 48); memset(pad_2, 0x5C, 48); md5_update(&md5, ssl->session->master, 48); md5_update(&md5, pad_1, 48); md5_finish(&md5, hash); md5_starts(&md5); md5_update(&md5, ssl->session->master, 48); md5_update(&md5, pad_2, 48); md5_update(&md5, hash, 16); md5_finish(&md5, hash); sha1_update(&sha1, ssl->session->master, 48); sha1_update(&sha1, pad_1, 40); sha1_finish(&sha1, hash + 16); sha1_starts(&sha1); sha1_update(&sha1, ssl->session->master, 48); sha1_update(&sha1, pad_2, 40); sha1_update(&sha1, hash + 16, 20); sha1_finish(&sha1, hash + 16); } else { /* TLSv1 */ md5_finish(&md5, hash); sha1_finish(&sha1, hash + 16); } SSL_DEBUG_BUF(3, "calculated verify result", hash, 36); SSL_DEBUG_MSG(2, ("<= calc verify")); return; }
static int ssl_parse_renegotiation_info( ssl_context *ssl, const unsigned char *buf, size_t len ) { int ret; if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) { if( len != 1 || buf[0] != 0x0 ) { SSL_DEBUG_MSG( 1, ( "non-zero length renegotiated connection field" ) ); if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) return( ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; } else { if( len != 1 + ssl->verify_data_len || buf[0] != ssl->verify_data_len || memcmp( buf + 1, ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) { SSL_DEBUG_MSG( 1, ( "non-matching renegotiated connection field" ) ); if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) return( ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } } return( 0 ); }
/* * Record layer functions */ int ssl_write_record(ssl_context * ssl) { int ret; size_t len = ssl->out_msglen; SSL_DEBUG_MSG(2, ("=> write record")); ssl->out_hdr[0] = (uint8_t)ssl->out_msgtype; ssl->out_hdr[1] = (uint8_t)ssl->major_ver; ssl->out_hdr[2] = (uint8_t)ssl->minor_ver; ssl->out_hdr[3] = (uint8_t)(len >> 8); ssl->out_hdr[4] = (uint8_t)(len); if (ssl->out_msgtype == SSL_MSG_HANDSHAKE) { ssl->out_msg[1] = (uint8_t)((len - 4) >> 16); ssl->out_msg[2] = (uint8_t)((len - 4) >> 8); ssl->out_msg[3] = (uint8_t)((len - 4)); md5_update(&ssl->fin_md5, ssl->out_msg, len); sha1_update(&ssl->fin_sha1, ssl->out_msg, len); }
static int ssl_write_server_hello( ssl_context *ssl ) { time_t t; int ret, n; size_t ext_len = 0; unsigned char *buf, *p; SSL_DEBUG_MSG( 2, ( "=> write server hello" ) ); /* * 0 . 0 handshake type * 1 . 3 handshake length * 4 . 5 protocol version * 6 . 9 UNIX time() * 10 . 37 random bytes */ buf = ssl->out_msg; p = buf + 4; *p++ = (unsigned char) ssl->major_ver; *p++ = (unsigned char) ssl->minor_ver; SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]", buf[4], buf[5] ) ); t = time( NULL ); *p++ = (unsigned char)( t >> 24 ); *p++ = (unsigned char)( t >> 16 ); *p++ = (unsigned char)( t >> 8 ); *p++ = (unsigned char)( t ); SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) ); if( ( ret = ssl->f_rng( ssl->p_rng, p, 28 ) ) != 0 ) return( ret ); p += 28; memcpy( ssl->handshake->randbytes + 32, buf + 6, 32 ); SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 ); /* * 38 . 38 session id length * 39 . 38+n session id * 39+n . 40+n chosen ciphersuite * 41+n . 41+n chosen compression alg. */ ssl->session_negotiate->length = n = 32; *p++ = (unsigned char) ssl->session_negotiate->length; if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || ssl->f_get_cache == NULL || ssl->f_get_cache( ssl->p_get_cache, ssl->session_negotiate ) != 0 ) { /* * Not found, create a new session id */ ssl->handshake->resume = 0; ssl->state++; if( ( ret = ssl->f_rng( ssl->p_rng, ssl->session_negotiate->id, n ) ) != 0 ) return( ret ); } else { /* * Found a matching session, resuming it */ ssl->handshake->resume = 1; ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC; if( ( ret = ssl_derive_keys( ssl ) ) != 0 ) { SSL_DEBUG_RET( 1, "ssl_derive_keys", ret ); return( ret ); } } memcpy( p, ssl->session_negotiate->id, ssl->session_negotiate->length ); p += ssl->session_negotiate->length; SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) ); SSL_DEBUG_BUF( 3, "server hello, session id", buf + 39, n ); SSL_DEBUG_MSG( 3, ( "%s session has been resumed", ssl->handshake->resume ? "a" : "no" ) ); *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite >> 8 ); *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite ); *p++ = (unsigned char)( ssl->session_negotiate->compression ); SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %d", ssl->session_negotiate->ciphersuite ) ); SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", ssl->session_negotiate->compression ) ); if( ssl->secure_renegotiation == SSL_SECURE_RENEGOTIATION ) { SSL_DEBUG_MSG( 3, ( "server hello, prepping for secure renegotiation extension" ) ); ext_len += 5 + ssl->verify_data_len * 2; SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", ext_len ) ); *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); *p++ = (unsigned char)( ( ext_len ) & 0xFF ); /* * Secure renegotiation */ SSL_DEBUG_MSG( 3, ( "client hello, secure renegotiation extension" ) ); *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF ); *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO ) & 0xFF ); *p++ = 0x00; *p++ = ( ssl->verify_data_len * 2 + 1 ) & 0xFF; *p++ = ssl->verify_data_len * 2 & 0xFF; memcpy( p, ssl->peer_verify_data, ssl->verify_data_len ); p += ssl->verify_data_len; memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); p += ssl->verify_data_len; }
static int ssl_parse_client_hello( ssl_context *ssl ) { int ret; unsigned int i, j; size_t n; unsigned int ciph_len, sess_len; unsigned int comp_len; unsigned int ext_len = 0; unsigned char *buf, *p, *ext; int renegotiation_info_seen = 0; int handshake_failure = 0; SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) ); if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE && ( ret = ssl_fetch_input( ssl, 5 ) ) != 0 ) { SSL_DEBUG_RET( 1, "ssl_fetch_input", ret ); return( ret ); } buf = ssl->in_hdr; #if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) if( ( buf[0] & 0x80 ) != 0 ) return ssl_parse_client_hello_v2( ssl ); #endif SSL_DEBUG_BUF( 4, "record header", buf, 5 ); SSL_DEBUG_MSG( 3, ( "client hello v3, message type: %d", buf[0] ) ); SSL_DEBUG_MSG( 3, ( "client hello v3, message len.: %d", ( buf[3] << 8 ) | buf[4] ) ); SSL_DEBUG_MSG( 3, ( "client hello v3, protocol ver: [%d:%d]", buf[1], buf[2] ) ); /* * SSLv3 Client Hello * * Record layer: * 0 . 0 message type * 1 . 2 protocol version * 3 . 4 message length */ if( buf[0] != SSL_MSG_HANDSHAKE || buf[1] != SSL_MAJOR_VERSION_3 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } n = ( buf[3] << 8 ) | buf[4]; if( n < 45 || n > 512 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE && ( ret = ssl_fetch_input( ssl, 5 + n ) ) != 0 ) { SSL_DEBUG_RET( 1, "ssl_fetch_input", ret ); return( ret ); } buf = ssl->in_msg; if( !ssl->renegotiation ) n = ssl->in_left - 5; else n = ssl->in_msglen; ssl->handshake->update_checksum( ssl, buf, n ); /* * SSL layer: * 0 . 0 handshake type * 1 . 3 handshake length * 4 . 5 protocol version * 6 . 9 UNIX time() * 10 . 37 random bytes * 38 . 38 session id length * 39 . 38+x session id * 39+x . 40+x ciphersuitelist length * 41+x . .. ciphersuitelist * .. . .. compression alg. * .. . .. extensions */ SSL_DEBUG_BUF( 4, "record contents", buf, n ); SSL_DEBUG_MSG( 3, ( "client hello v3, handshake type: %d", buf[0] ) ); SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d", ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) ); SSL_DEBUG_MSG( 3, ( "client hello v3, max. version: [%d:%d]", buf[4], buf[5] ) ); /* * Check the handshake type and protocol version */ if( buf[0] != SSL_HS_CLIENT_HELLO || buf[4] != SSL_MAJOR_VERSION_3 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } ssl->major_ver = SSL_MAJOR_VERSION_3; ssl->minor_ver = ( buf[5] <= SSL_MINOR_VERSION_3 ) ? buf[5] : SSL_MINOR_VERSION_3; if( ssl->minor_ver < ssl->min_minor_ver ) { SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum" " [%d:%d] < [%d:%d]", ssl->major_ver, ssl->minor_ver, ssl->min_major_ver, ssl->min_minor_ver ) ); ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL, SSL_ALERT_MSG_PROTOCOL_VERSION ); return( POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); } ssl->max_major_ver = buf[4]; ssl->max_minor_ver = buf[5]; memcpy( ssl->handshake->randbytes, buf + 6, 32 ); /* * Check the handshake message length */ if( buf[1] != 0 || n != (unsigned int) 4 + ( ( buf[2] << 8 ) | buf[3] ) ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } /* * Check the session length */ sess_len = buf[38]; if( sess_len > 32 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } ssl->session_negotiate->length = sess_len; memset( ssl->session_negotiate->id, 0, sizeof( ssl->session_negotiate->id ) ); memcpy( ssl->session_negotiate->id, buf + 39, ssl->session_negotiate->length ); /* * Check the ciphersuitelist length */ ciph_len = ( buf[39 + sess_len] << 8 ) | ( buf[40 + sess_len] ); if( ciph_len < 2 || ciph_len > 256 || ( ciph_len % 2 ) != 0 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } /* * Check the compression algorithms length */ comp_len = buf[41 + sess_len + ciph_len]; if( comp_len < 1 || comp_len > 16 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } /* * Check the extension length */ if( n > 42 + sess_len + ciph_len + comp_len ) { ext_len = ( buf[42 + sess_len + ciph_len + comp_len] << 8 ) | ( buf[43 + sess_len + ciph_len + comp_len] ); if( ( ext_len > 0 && ext_len < 4 ) || n != 44 + sess_len + ciph_len + comp_len + ext_len ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); SSL_DEBUG_BUF( 3, "Ext", buf + 44 + sess_len + ciph_len + comp_len, ext_len); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } } ssl->session_negotiate->compression = SSL_COMPRESS_NULL; #if defined(POLARSSL_ZLIB_SUPPORT) for( i = 0; i < comp_len; ++i ) { if( buf[42 + sess_len + ciph_len + i] == SSL_COMPRESS_DEFLATE ) { ssl->session_negotiate->compression = SSL_COMPRESS_DEFLATE; break; } } #endif SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 6, 32 ); SSL_DEBUG_BUF( 3, "client hello, session id", buf + 38, sess_len ); SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", buf + 41 + sess_len, ciph_len ); SSL_DEBUG_BUF( 3, "client hello, compression", buf + 42 + sess_len + ciph_len, comp_len ); /* * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV */ for( i = 0, p = buf + 41 + sess_len; i < ciph_len; i += 2, p += 2 ) { if( p[0] == 0 && p[1] == SSL_EMPTY_RENEGOTIATION_INFO ) { SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); if( ssl->renegotiation == SSL_RENEGOTIATION ) { SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during renegotiation" ) ); if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) return( ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; break; } } /* * Search for a matching ciphersuite */ for( i = 0; ssl->ciphersuites[ssl->minor_ver][i] != 0; i++ ) { for( j = 0, p = buf + 41 + sess_len; j < ciph_len; j += 2, p += 2 ) { if( p[0] == 0 && p[1] == ssl->ciphersuites[ssl->minor_ver][i] && ssl_get_ciphersuite_min_version( p[1] ) <= ssl->minor_ver ) goto have_ciphersuite; } } SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN ); have_ciphersuite: ssl->session_negotiate->ciphersuite = ssl->ciphersuites[ssl->minor_ver][i]; ssl_optimize_checksum( ssl, ssl->session_negotiate->ciphersuite ); ext = buf + 44 + sess_len + ciph_len + comp_len; while( ext_len ) { unsigned int ext_id = ( ( ext[0] << 8 ) | ( ext[1] ) ); unsigned int ext_size = ( ( ext[2] << 8 ) | ( ext[3] ) ); if( ext_size + 4 > ext_len ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } switch( ext_id ) { case TLS_EXT_SERVERNAME: SSL_DEBUG_MSG( 3, ( "found ServerName extension" ) ); if( ssl->f_sni == NULL ) break; ret = ssl_parse_servername_ext( ssl, ext + 4, ext_size ); if( ret != 0 ) return( ret ); break; case TLS_EXT_RENEGOTIATION_INFO: SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); renegotiation_info_seen = 1; ret = ssl_parse_renegotiation_info( ssl, ext + 4, ext_size ); if( ret != 0 ) return( ret ); break; case TLS_EXT_SIG_ALG: SSL_DEBUG_MSG( 3, ( "found signature_algorithms extension" ) ); if( ssl->renegotiation == SSL_RENEGOTIATION ) break; ret = ssl_parse_signature_algorithms_ext( ssl, ext + 4, ext_size ); if( ret != 0 ) return( ret ); break; default: SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", ext_id ) ); } ext_len -= 4 + ext_size; ext += 4 + ext_size; if( ext_len > 0 && ext_len < 4 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } } /* * Renegotiation security checks */ if( ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && ssl->allow_legacy_renegotiation == SSL_LEGACY_BREAK_HANDSHAKE ) { SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); handshake_failure = 1; } else if( ssl->renegotiation == SSL_RENEGOTIATION && ssl->secure_renegotiation == SSL_SECURE_RENEGOTIATION && renegotiation_info_seen == 0 ) { SSL_DEBUG_MSG( 1, ( "renegotiation_info extension missing (secure)" ) ); handshake_failure = 1; } else if( ssl->renegotiation == SSL_RENEGOTIATION && ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && ssl->allow_legacy_renegotiation == SSL_LEGACY_NO_RENEGOTIATION ) { SSL_DEBUG_MSG( 1, ( "legacy renegotiation not allowed" ) ); handshake_failure = 1; } else if( ssl->renegotiation == SSL_RENEGOTIATION && ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && renegotiation_info_seen == 1 ) { SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); handshake_failure = 1; } if( handshake_failure == 1 ) { if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) return( ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } ssl->in_left = 0; ssl->state++; SSL_DEBUG_MSG( 2, ( "<= parse client hello" ) ); return( 0 ); }
static int ssl_parse_client_hello_v2( ssl_context *ssl ) { int ret; unsigned int i, j; size_t n; unsigned int ciph_len, sess_len, chal_len; unsigned char *buf, *p; SSL_DEBUG_MSG( 2, ( "=> parse client hello v2" ) ); if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE ) { SSL_DEBUG_MSG( 1, ( "client hello v2 illegal for renegotiation" ) ); if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) return( ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } buf = ssl->in_hdr; SSL_DEBUG_BUF( 4, "record header", buf, 5 ); SSL_DEBUG_MSG( 3, ( "client hello v2, message type: %d", buf[2] ) ); SSL_DEBUG_MSG( 3, ( "client hello v2, message len.: %d", ( ( buf[0] & 0x7F ) << 8 ) | buf[1] ) ); SSL_DEBUG_MSG( 3, ( "client hello v2, max. version: [%d:%d]", buf[3], buf[4] ) ); /* * SSLv2 Client Hello * * Record layer: * 0 . 1 message length * * SSL layer: * 2 . 2 message type * 3 . 4 protocol version */ if( buf[2] != SSL_HS_CLIENT_HELLO || buf[3] != SSL_MAJOR_VERSION_3 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } n = ( ( buf[0] << 8 ) | buf[1] ) & 0x7FFF; if( n < 17 || n > 512 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } ssl->major_ver = SSL_MAJOR_VERSION_3; ssl->minor_ver = ( buf[4] <= SSL_MINOR_VERSION_3 ) ? buf[4] : SSL_MINOR_VERSION_3; if( ssl->minor_ver < ssl->min_minor_ver ) { SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum" " [%d:%d] < [%d:%d]", ssl->major_ver, ssl->minor_ver, ssl->min_major_ver, ssl->min_minor_ver ) ); ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL, SSL_ALERT_MSG_PROTOCOL_VERSION ); return( POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); } ssl->max_major_ver = buf[3]; ssl->max_minor_ver = buf[4]; if( ( ret = ssl_fetch_input( ssl, 2 + n ) ) != 0 ) { SSL_DEBUG_RET( 1, "ssl_fetch_input", ret ); return( ret ); } ssl->handshake->update_checksum( ssl, buf + 2, n ); buf = ssl->in_msg; n = ssl->in_left - 5; /* * 0 . 1 ciphersuitelist length * 2 . 3 session id length * 4 . 5 challenge length * 6 . .. ciphersuitelist * .. . .. session id * .. . .. challenge */ SSL_DEBUG_BUF( 4, "record contents", buf, n ); ciph_len = ( buf[0] << 8 ) | buf[1]; sess_len = ( buf[2] << 8 ) | buf[3]; chal_len = ( buf[4] << 8 ) | buf[5]; SSL_DEBUG_MSG( 3, ( "ciph_len: %d, sess_len: %d, chal_len: %d", ciph_len, sess_len, chal_len ) ); /* * Make sure each parameter length is valid */ if( ciph_len < 3 || ( ciph_len % 3 ) != 0 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } if( sess_len > 32 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } if( chal_len < 8 || chal_len > 32 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } if( n != 6 + ciph_len + sess_len + chal_len ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", buf + 6, ciph_len ); SSL_DEBUG_BUF( 3, "client hello, session id", buf + 6 + ciph_len, sess_len ); SSL_DEBUG_BUF( 3, "client hello, challenge", buf + 6 + ciph_len + sess_len, chal_len ); p = buf + 6 + ciph_len; ssl->session_negotiate->length = sess_len; memset( ssl->session_negotiate->id, 0, sizeof( ssl->session_negotiate->id ) ); memcpy( ssl->session_negotiate->id, p, ssl->session_negotiate->length ); p += sess_len; memset( ssl->handshake->randbytes, 0, 64 ); memcpy( ssl->handshake->randbytes + 32 - chal_len, p, chal_len ); /* * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV */ for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 ) { if( p[0] == 0 && p[1] == 0 && p[2] == SSL_EMPTY_RENEGOTIATION_INFO ) { SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); if( ssl->renegotiation == SSL_RENEGOTIATION ) { SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during renegotiation" ) ); if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) return( ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; break; } } for( i = 0; ssl->ciphersuites[ssl->minor_ver][i] != 0; i++ ) { for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 ) { if( p[0] == 0 && p[1] == 0 && p[2] == ssl->ciphersuites[ssl->minor_ver][i] ) goto have_ciphersuite_v2; } } SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN ); have_ciphersuite_v2: ssl->session_negotiate->ciphersuite = ssl->ciphersuites[ssl->minor_ver][i]; ssl_optimize_checksum( ssl, ssl->session_negotiate->ciphersuite ); /* * SSLv2 Client Hello relevant renegotiation security checks */ if( ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && ssl->allow_legacy_renegotiation == SSL_LEGACY_BREAK_HANDSHAKE ) { SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) return( ret ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } ssl->in_left = 0; ssl->state++; SSL_DEBUG_MSG( 2, ( "<= parse client hello v2" ) ); return( 0 ); }
static int ssl_parse_signature_algorithms_ext( ssl_context *ssl, const unsigned char *buf, size_t len ) { size_t sig_alg_list_size; const unsigned char *p; sig_alg_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); if( sig_alg_list_size + 2 != len || sig_alg_list_size %2 != 0 ) { SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } p = buf + 2; while( sig_alg_list_size > 0 ) { if( p[1] != SSL_SIG_RSA ) { sig_alg_list_size -= 2; p += 2; continue; } #if defined(POLARSSL_SHA4_C) if( p[0] == SSL_HASH_SHA512 ) { ssl->handshake->sig_alg = SSL_HASH_SHA512; break; } if( p[0] == SSL_HASH_SHA384 ) { ssl->handshake->sig_alg = SSL_HASH_SHA384; break; } #endif #if defined(POLARSSL_SHA2_C) if( p[0] == SSL_HASH_SHA256 ) { ssl->handshake->sig_alg = SSL_HASH_SHA256; break; } if( p[0] == SSL_HASH_SHA224 ) { ssl->handshake->sig_alg = SSL_HASH_SHA224; break; } #endif if( p[0] == SSL_HASH_SHA1 ) { ssl->handshake->sig_alg = SSL_HASH_SHA1; break; } if( p[0] == SSL_HASH_MD5 ) { ssl->handshake->sig_alg = SSL_HASH_MD5; break; } sig_alg_list_size -= 2; p += 2; } SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: %d", ssl->handshake->sig_alg ) ); return( 0 ); }
static int ssl_write_client_hello( ssl_context *ssl ) { int ret; size_t i, n, ext_len = 0; unsigned char *buf; unsigned char *p; time_t t; unsigned char sig_alg_list[20]; size_t sig_alg_len = 0; SSL_DEBUG_MSG( 2, ( "=> write client hello" ) ); ssl->major_ver = SSL_MAJOR_VERSION_3; ssl->minor_ver = SSL_MINOR_VERSION_0; if( ssl->max_major_ver == 0 && ssl->max_minor_ver == 0 ) { ssl->max_major_ver = SSL_MAJOR_VERSION_3; ssl->max_minor_ver = SSL_MINOR_VERSION_3; } /* * 0 . 0 handshake type * 1 . 3 handshake length * 4 . 5 highest version supported * 6 . 9 current UNIX time * 10 . 37 random bytes */ buf = ssl->out_msg; p = buf + 4; *p++ = (unsigned char) ssl->max_major_ver; *p++ = (unsigned char) ssl->max_minor_ver; SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]", buf[4], buf[5] ) ); t = time( NULL ); *p++ = (unsigned char)( t >> 24 ); *p++ = (unsigned char)( t >> 16 ); *p++ = (unsigned char)( t >> 8 ); *p++ = (unsigned char)( t ); SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) ); if( ( ret = ssl->f_rng( ssl->p_rng, p, 28 ) ) != 0 ) return( ret ); p += 28; memcpy( ssl->randbytes, buf + 6, 32 ); SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 6, 32 ); /* * 38 . 38 session id length * 39 . 39+n session id * 40+n . 41+n ciphersuitelist length * 42+n . .. ciphersuitelist * .. . .. compression methods length * .. . .. compression methods * .. . .. extensions length * .. . .. extensions */ n = ssl->session->length; if( n < 16 || n > 32 || ssl->resume == 0 || ( ssl->timeout != 0 && t - ssl->session->start > ssl->timeout ) ) n = 0; *p++ = (unsigned char) n; for( i = 0; i < n; i++ ) *p++ = ssl->session->id[i]; SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) ); SSL_DEBUG_BUF( 3, "client hello, session id", buf + 39, n ); for( n = 0; ssl->ciphersuites[n] != 0; n++ ); *p++ = (unsigned char)( n >> 7 ); *p++ = (unsigned char)( n << 1 ); SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites", n ) ); for( i = 0; i < n; i++ ) { SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %2d", ssl->ciphersuites[i] ) ); *p++ = (unsigned char)( ssl->ciphersuites[i] >> 8 ); *p++ = (unsigned char)( ssl->ciphersuites[i] ); } SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) ); SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", 0 ) ); *p++ = 1; *p++ = SSL_COMPRESS_NULL; if ( ssl->hostname != NULL ) { SSL_DEBUG_MSG( 3, ( "client hello, prepping for server name extension: %s", ssl->hostname ) ); ext_len += ssl->hostname_len + 9; } /* * Prepare signature_algorithms extension (TLS 1.2) */ if( ssl->max_minor_ver == SSL_MINOR_VERSION_3 ) { #if defined(POLARSSL_SHA4_C) sig_alg_list[sig_alg_len++] = SSL_HASH_SHA512; sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; sig_alg_list[sig_alg_len++] = SSL_HASH_SHA384; sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; #endif #if defined(POLARSSL_SHA2_C) sig_alg_list[sig_alg_len++] = SSL_HASH_SHA256; sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; sig_alg_list[sig_alg_len++] = SSL_HASH_SHA224; sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; #endif #if defined(POLARSSL_SHA1_C) sig_alg_list[sig_alg_len++] = SSL_HASH_SHA1; sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; #endif #if defined(POLARSSL_MD5_C) sig_alg_list[sig_alg_len++] = SSL_HASH_MD5; sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; #endif ext_len = 6 + sig_alg_len; } SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d", ext_len ) ); *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); *p++ = (unsigned char)( ( ext_len ) & 0xFF ); if ( ssl->hostname != NULL ) { /* * struct { * NameType name_type; * select (name_type) { * case host_name: HostName; * } name; * } ServerName; * * enum { * host_name(0), (255) * } NameType; * * opaque HostName<1..2^16-1>; * * struct { * ServerName server_name_list<1..2^16-1> * } ServerNameList; */ SSL_DEBUG_MSG( 3, ( "client hello, adding server name extension: %s", ssl->hostname ) ); *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME >> 8 ) & 0xFF ); *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME ) & 0xFF ); *p++ = (unsigned char)( ( (ssl->hostname_len + 5) >> 8 ) & 0xFF ); *p++ = (unsigned char)( ( (ssl->hostname_len + 5) ) & 0xFF ); *p++ = (unsigned char)( ( (ssl->hostname_len + 3) >> 8 ) & 0xFF ); *p++ = (unsigned char)( ( (ssl->hostname_len + 3) ) & 0xFF ); *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME_HOSTNAME ) & 0xFF ); *p++ = (unsigned char)( ( ssl->hostname_len >> 8 ) & 0xFF ); *p++ = (unsigned char)( ( ssl->hostname_len ) & 0xFF ); memcpy( p, ssl->hostname, ssl->hostname_len ); p += ssl->hostname_len; }
static int ssl_decrypt_buf(ssl_context * ssl) { size_t i, padlen; uint8_t tmp[20]; SSL_DEBUG_MSG(2, ("=> decrypt buf")); if (ssl->in_msglen < ssl->minlen) { SSL_DEBUG_MSG(1, ("in_msglen (%d) < minlen (%d)", ssl->in_msglen, ssl->minlen)); return (TROPICSSL_ERR_SSL_INVALID_MAC); } if (ssl->ivlen == 0) { #if defined(TROPICSSL_ARC4) padlen = 0; arc4_crypt((arc4_context *) ssl->ctx_dec, ssl->in_msg, ssl->in_msglen); #else return (TROPICSSL_ERR_SSL_FEATURE_UNAVAILABLE); #endif } else { /* * Decrypt and check the padding */ if (ssl->in_msglen % ssl->ivlen != 0) { SSL_DEBUG_MSG(1, ("msglen (%d) %% ivlen (%d) != 0", ssl->in_msglen, ssl->ivlen)); return (TROPICSSL_ERR_SSL_INVALID_MAC); } switch (ssl->ivlen) { #if defined(TROPICSSL_DES) case 8: des3_crypt_cbc((des3_context *) ssl->ctx_dec, DES_DECRYPT, ssl->in_msglen, ssl->iv_dec, ssl->in_msg, ssl->in_msg); break; #endif case 16: #if defined(TROPICSSL_AES) if (ssl->session->cipher == TLS_RSA_WITH_AES_128_CBC_SHA || ssl->session->cipher == TLS_RSA_WITH_AES_256_CBC_SHA || ssl->session->cipher == TLS_DHE_RSA_WITH_AES_256_CBC_SHA) { aes_crypt_cbc((aes_context *) ssl->ctx_dec, AES_DECRYPT, ssl->in_msglen, ssl->iv_dec, ssl->in_msg, ssl->in_msg); break; } #endif #if defined(TROPICSSL_CAMELLIA) if (ssl->session->cipher == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA || ssl->session->cipher == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA || ssl->session->cipher == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA) { camellia_crypt_cbc((camellia_context *) ssl->ctx_dec, CAMELLIA_DECRYPT, ssl->in_msglen, ssl->iv_dec, ssl->in_msg, ssl->in_msg); break; } #endif default: return (TROPICSSL_ERR_SSL_FEATURE_UNAVAILABLE); } padlen = 1 + ssl->in_msg[ssl->in_msglen - 1]; if (ssl->minor_ver == SSL_MINOR_VERSION_0) { if (padlen > ssl->ivlen) { SSL_DEBUG_MSG(1, ("bad padding length: is %d, " "should be no more than %d", padlen, ssl->ivlen)); padlen = 0; } } else { /* * TLSv1: always check the padding */ for (i = 1; i <= padlen; i++) { if (ssl->in_msg[ssl->in_msglen - i] != padlen - 1) { SSL_DEBUG_MSG(1, ("bad padding byte: should be " "%02x, but is %02x", padlen - 1, ssl-> in_msg[ssl->in_msglen - i])); padlen = 0; } } } } SSL_DEBUG_BUF(4, "raw buffer after decryption", ssl->in_msg, ssl->in_msglen); /* * Always compute the MAC (RFC4346, CBCTIME). */ ssl->in_msglen -= (ssl->maclen + padlen); ssl->in_hdr[3] = (uint8_t)(ssl->in_msglen >> 8); ssl->in_hdr[4] = (uint8_t)(ssl->in_msglen); memcpy(tmp, ssl->in_msg + ssl->in_msglen, 20); if (ssl->minor_ver == SSL_MINOR_VERSION_0) { if (ssl->maclen == 16) ssl_mac_md5(ssl->mac_dec, ssl->in_msg, ssl->in_msglen, ssl->in_ctr, ssl->in_msgtype); else ssl_mac_sha1(ssl->mac_dec, ssl->in_msg, ssl->in_msglen, ssl->in_ctr, ssl->in_msgtype); } else { if (ssl->maclen == 16) md5_hmac(ssl->mac_dec, 16, ssl->in_ctr, ssl->in_msglen + 13, ssl->in_msg + ssl->in_msglen); else sha1_hmac(ssl->mac_dec, 20, ssl->in_ctr, ssl->in_msglen + 13, ssl->in_msg + ssl->in_msglen); } SSL_DEBUG_BUF(4, "message mac", tmp, ssl->maclen); SSL_DEBUG_BUF(4, "computed mac", ssl->in_msg + ssl->in_msglen, ssl->maclen); if (memcmp(tmp, ssl->in_msg + ssl->in_msglen, ssl->maclen) != 0) { SSL_DEBUG_MSG(1, ("message mac does not match")); return (TROPICSSL_ERR_SSL_INVALID_MAC); } /* * Finally check the padding length; bad padding * will produce the same error as an invalid MAC. */ if (ssl->ivlen != 0 && padlen == 0) return (TROPICSSL_ERR_SSL_INVALID_MAC); if (ssl->in_msglen == 0) { ssl->nb_zero++; /* * Three or more empty messages may be a DoS attack * (excessive CPU consumption). */ if (ssl->nb_zero > 3) { SSL_DEBUG_MSG(1, ("received four consecutive empty " "messages, possible DoS attack")); return (TROPICSSL_ERR_SSL_INVALID_MAC); } } else ssl->nb_zero = 0; for (i = 7; i >= 0; i--) if (++ssl->in_ctr[i] != 0) break; SSL_DEBUG_MSG(2, ("<= decrypt buf")); return (0); }
/* * Encryption/decryption functions */ static int ssl_encrypt_buf(ssl_context * ssl) { size_t i, padlen; SSL_DEBUG_MSG(2, ("=> encrypt buf")); /* * Add MAC then encrypt */ if (ssl->minor_ver == SSL_MINOR_VERSION_0) { if (ssl->maclen == 16) ssl_mac_md5(ssl->mac_enc, ssl->out_msg, ssl->out_msglen, ssl->out_ctr, ssl->out_msgtype); if (ssl->maclen == 20) ssl_mac_sha1(ssl->mac_enc, ssl->out_msg, ssl->out_msglen, ssl->out_ctr, ssl->out_msgtype); } else { if (ssl->maclen == 16) md5_hmac(ssl->mac_enc, 16, ssl->out_ctr, ssl->out_msglen + 13, ssl->out_msg + ssl->out_msglen); if (ssl->maclen == 20) sha1_hmac(ssl->mac_enc, 20, ssl->out_ctr, ssl->out_msglen + 13, ssl->out_msg + ssl->out_msglen); } SSL_DEBUG_BUF(4, "computed mac", ssl->out_msg + ssl->out_msglen, ssl->maclen); ssl->out_msglen += ssl->maclen; for (i = 7; i >= 0; i--) if (++ssl->out_ctr[i] != 0) break; if (ssl->ivlen == 0) { #if defined(TROPICSSL_ARC4) padlen = 0; SSL_DEBUG_MSG(3, ("before encrypt: msglen = %d, " "including %d bytes of padding", ssl->out_msglen, 0)); SSL_DEBUG_BUF(4, "before encrypt: output payload", ssl->out_msg, ssl->out_msglen); arc4_crypt((arc4_context *) ssl->ctx_enc, ssl->out_msg, ssl->out_msglen); #else return (TROPICSSL_ERR_SSL_FEATURE_UNAVAILABLE); #endif } else { padlen = ssl->ivlen - (ssl->out_msglen + 1) % ssl->ivlen; if (padlen == ssl->ivlen) padlen = 0; for (i = 0; i <= padlen; i++) ssl->out_msg[ssl->out_msglen + i] = (uint8_t)padlen; ssl->out_msglen += padlen + 1; SSL_DEBUG_MSG(3, ("before encrypt: msglen = %d, " "including %d bytes of padding", ssl->out_msglen, padlen + 1)); SSL_DEBUG_BUF(4, "before encrypt: output payload", ssl->out_msg, ssl->out_msglen); switch (ssl->ivlen) { case 8: #if defined(TROPICSSL_DES) des3_crypt_cbc((des3_context *) ssl->ctx_enc, DES_ENCRYPT, ssl->out_msglen, ssl->iv_enc, ssl->out_msg, ssl->out_msg); break; #endif case 16: #if defined(TROPICSSL_AES) if (ssl->session->cipher == TLS_RSA_WITH_AES_128_CBC_SHA || ssl->session->cipher == TLS_RSA_WITH_AES_256_CBC_SHA || ssl->session->cipher == TLS_DHE_RSA_WITH_AES_256_CBC_SHA) { aes_crypt_cbc((aes_context *) ssl->ctx_enc, AES_ENCRYPT, ssl->out_msglen, ssl->iv_enc, ssl->out_msg, ssl->out_msg); break; } #endif #if defined(TROPICSSL_CAMELLIA) if (ssl->session->cipher == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA || ssl->session->cipher == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA || ssl->session->cipher == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA) { camellia_crypt_cbc((camellia_context *) ssl->ctx_enc, CAMELLIA_ENCRYPT, ssl->out_msglen, ssl->iv_enc, ssl->out_msg, ssl->out_msg); break; } #endif default: return (TROPICSSL_ERR_SSL_FEATURE_UNAVAILABLE); } } SSL_DEBUG_MSG(2, ("<= encrypt buf")); return (0); }
int ssl_derive_keys(ssl_context * ssl) { size_t i; md5_context md5; sha1_context sha1; uint8_t tmp[64]; uint8_t padding[16]; uint8_t sha1sum[20]; uint8_t keyblk[256]; uint8_t *key1; uint8_t *key2; SSL_DEBUG_MSG(2, ("=> derive keys")); /* * SSLv3: * master = * MD5( premaster + SHA1( 'A' + premaster + randbytes ) ) + * MD5( premaster + SHA1( 'BB' + premaster + randbytes ) ) + * MD5( premaster + SHA1( 'CCC' + premaster + randbytes ) ) * * TLSv1: * master = PRF( premaster, "master secret", randbytes )[0..47] */ if (ssl->resume == 0) { size_t len = ssl->pmslen; SSL_DEBUG_BUF(3, "premaster secret", ssl->premaster, len); if (ssl->minor_ver == SSL_MINOR_VERSION_0) { for (i = 0; i < 3; i++) { memset(padding, 'A' + i, 1 + i); sha1_starts(&sha1); sha1_update(&sha1, padding, 1 + i); sha1_update(&sha1, ssl->premaster, len); sha1_update(&sha1, ssl->randbytes, 64); sha1_finish(&sha1, sha1sum); md5_starts(&md5); md5_update(&md5, ssl->premaster, len); md5_update(&md5, sha1sum, 20); md5_finish(&md5, ssl->session->master + i * 16); } } else tls1_prf(ssl->premaster, len, "master secret", ssl->randbytes, 64, ssl->session->master, 48); memset(ssl->premaster, 0, sizeof(ssl->premaster)); } else SSL_DEBUG_MSG(3, ("no premaster (session resumed)")); /* * Swap the client and server random values. */ memcpy(tmp, ssl->randbytes, 64); memcpy(ssl->randbytes, tmp + 32, 32); memcpy(ssl->randbytes + 32, tmp, 32); memset(tmp, 0, sizeof(tmp)); /* * SSLv3: * key block = * MD5( master + SHA1( 'A' + master + randbytes ) ) + * MD5( master + SHA1( 'BB' + master + randbytes ) ) + * MD5( master + SHA1( 'CCC' + master + randbytes ) ) + * MD5( master + SHA1( 'DDDD' + master + randbytes ) ) + * ... * * TLSv1: * key block = PRF( master, "key expansion", randbytes ) */ if (ssl->minor_ver == SSL_MINOR_VERSION_0) { for (i = 0; i < 16; i++) { memset(padding, 'A' + i, 1 + i); sha1_starts(&sha1); sha1_update(&sha1, padding, 1 + i); sha1_update(&sha1, ssl->session->master, 48); sha1_update(&sha1, ssl->randbytes, 64); sha1_finish(&sha1, sha1sum); md5_starts(&md5); md5_update(&md5, ssl->session->master, 48); md5_update(&md5, sha1sum, 20); md5_finish(&md5, keyblk + i * 16); } memset(&md5, 0, sizeof(md5)); memset(&sha1, 0, sizeof(sha1)); memset(padding, 0, sizeof(padding)); memset(sha1sum, 0, sizeof(sha1sum)); } else tls1_prf(ssl->session->master, 48, "key expansion", ssl->randbytes, 64, keyblk, 256); SSL_DEBUG_MSG(3, ("cipher = %s", ssl_get_cipher(ssl))); SSL_DEBUG_BUF(3, "master secret", ssl->session->master, 48); SSL_DEBUG_BUF(4, "random bytes", ssl->randbytes, 64); SSL_DEBUG_BUF(4, "key block", keyblk, 256); memset(ssl->randbytes, 0, sizeof(ssl->randbytes)); /* * Determine the appropriate key, IV and MAC length. */ switch (ssl->session->cipher) { #if defined(TROPICSSL_ARC4) case TLS_RSA_WITH_RC4_128_MD5: ssl->keylen = 16; ssl->minlen = 16; ssl->ivlen = 0; ssl->maclen = 16; break; case TLS_RSA_WITH_RC4_128_SHA: ssl->keylen = 16; ssl->minlen = 20; ssl->ivlen = 0; ssl->maclen = 20; break; #endif #if defined(TROPICSSL_DES) case TLS_RSA_WITH_3DES_EDE_CBC_SHA: case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: ssl->keylen = 24; ssl->minlen = 24; ssl->ivlen = 8; ssl->maclen = 20; break; #endif #if defined(TROPICSSL_AES) case TLS_RSA_WITH_AES_128_CBC_SHA: ssl->keylen = 16; ssl->minlen = 32; ssl->ivlen = 16; ssl->maclen = 20; break; case TLS_RSA_WITH_AES_256_CBC_SHA: case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: ssl->keylen = 32; ssl->minlen = 32; ssl->ivlen = 16; ssl->maclen = 20; break; #endif #if defined(TROPICSSL_CAMELLIA) case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: ssl->keylen = 16; ssl->minlen = 32; ssl->ivlen = 16; ssl->maclen = 20; break; case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: ssl->keylen = 32; ssl->minlen = 32; ssl->ivlen = 16; ssl->maclen = 20; break; #endif default: SSL_DEBUG_MSG(1, ("cipher %s is not available", ssl_get_cipher(ssl))); return (TROPICSSL_ERR_SSL_FEATURE_UNAVAILABLE); } SSL_DEBUG_MSG(3, ("keylen: %d, minlen: %d, ivlen: %d, maclen: %d", ssl->keylen, ssl->minlen, ssl->ivlen, ssl->maclen)); /* * Finally setup the cipher contexts, IVs and MAC secrets. */ if (ssl->endpoint == SSL_IS_CLIENT) { key1 = keyblk + ssl->maclen * 2; key2 = keyblk + ssl->maclen * 2 + ssl->keylen; memcpy(ssl->mac_enc, keyblk, ssl->maclen); memcpy(ssl->mac_dec, keyblk + ssl->maclen, ssl->maclen); memcpy(ssl->iv_enc, key2 + ssl->keylen, ssl->ivlen); memcpy(ssl->iv_dec, key2 + ssl->keylen + ssl->ivlen, ssl->ivlen); } else { key1 = keyblk + ssl->maclen * 2 + ssl->keylen; key2 = keyblk + ssl->maclen * 2; memcpy(ssl->mac_dec, keyblk, ssl->maclen); memcpy(ssl->mac_enc, keyblk + ssl->maclen, ssl->maclen); memcpy(ssl->iv_dec, key1 + ssl->keylen, ssl->ivlen); memcpy(ssl->iv_enc, key1 + ssl->keylen + ssl->ivlen, ssl->ivlen); } switch (ssl->session->cipher) { #if defined(TROPICSSL_ARC4) case TLS_RSA_WITH_RC4_128_MD5: case TLS_RSA_WITH_RC4_128_SHA: arc4_setup((arc4_context *) ssl->ctx_enc, key1, ssl->keylen); arc4_setup((arc4_context *) ssl->ctx_dec, key2, ssl->keylen); break; #endif #if defined(TROPICSSL_DES) case TLS_RSA_WITH_3DES_EDE_CBC_SHA: case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: des3_set3key_enc((des3_context *) ssl->ctx_enc, key1); des3_set3key_dec((des3_context *) ssl->ctx_dec, key2); break; #endif #if defined(TROPICSSL_AES) case TLS_RSA_WITH_AES_128_CBC_SHA: aes_setkey_enc((aes_context *) ssl->ctx_enc, key1, 128); aes_setkey_dec((aes_context *) ssl->ctx_dec, key2, 128); break; case TLS_RSA_WITH_AES_256_CBC_SHA: case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: aes_setkey_enc((aes_context *) ssl->ctx_enc, key1, 256); aes_setkey_dec((aes_context *) ssl->ctx_dec, key2, 256); break; #endif #if defined(TROPICSSL_CAMELLIA) case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: camellia_setkey_enc((camellia_context *) ssl->ctx_enc, key1, 128); camellia_setkey_dec((camellia_context *) ssl->ctx_dec, key2, 128); break; case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: camellia_setkey_enc((camellia_context *) ssl->ctx_enc, key1, 256); camellia_setkey_dec((camellia_context *) ssl->ctx_dec, key2, 256); break; #endif default: return (TROPICSSL_ERR_SSL_FEATURE_UNAVAILABLE); } memset(keyblk, 0, sizeof(keyblk)); SSL_DEBUG_MSG(2, ("<= derive keys")); return (0); }
static int ssl_write_client_hello( ssl_context *ssl ) { int ret, i, n; unsigned char *buf; unsigned char *p; time_t t; SSL_DEBUG_MSG( 2, ( "=> write client hello" ) ); ssl->major_ver = SSL_MAJOR_VERSION_3; ssl->minor_ver = SSL_MINOR_VERSION_0; ssl->max_major_ver = SSL_MAJOR_VERSION_3; ssl->max_minor_ver = SSL_MINOR_VERSION_1; /* * 0 . 0 handshake type * 1 . 3 handshake length * 4 . 5 highest version supported * 6 . 9 current UNIX time * 10 . 37 random bytes */ buf = ssl->out_msg; p = buf + 4; *p++ = (unsigned char) ssl->max_major_ver; *p++ = (unsigned char) ssl->max_minor_ver; SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]", buf[4], buf[5] ) ); t = time( NULL ); *p++ = (unsigned char)( t >> 24 ); *p++ = (unsigned char)( t >> 16 ); *p++ = (unsigned char)( t >> 8 ); *p++ = (unsigned char)( t ); SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) ); for( i = 28; i > 0; i-- ) *p++ = (unsigned char) ssl->f_rng( ssl->p_rng ); memcpy( ssl->randbytes, buf + 6, 32 ); SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 6, 32 ); /* * 38 . 38 session id length * 39 . 39+n session id * 40+n . 41+n cipherlist length * 42+n . .. cipherlist * .. . .. compression alg. (0) * .. . .. extensions (unused) */ n = ssl->session->length; if( n < 16 || n > 32 || ssl->resume == 0 || t - ssl->session->start < ssl->timeout ) n = 0; *p++ = (unsigned char) n; for( i = 0; i < n; i++ ) *p++ = ssl->session->id[i]; SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) ); SSL_DEBUG_BUF( 3, "client hello, session id", buf + 39, n ); for( n = 0; ssl->ciphers[n] != 0; n++ ); *p++ = (unsigned char)( n >> 7 ); *p++ = (unsigned char)( n << 1 ); SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphers", n ) ); for( i = 0; i < n; i++ ) { SSL_DEBUG_MSG( 3, ( "client hello, add cipher: %2d", ssl->ciphers[i] ) ); *p++ = (unsigned char)( ssl->ciphers[i] >> 8 ); *p++ = (unsigned char)( ssl->ciphers[i] ); } SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) ); SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", 0 ) ); *p++ = 1; *p++ = SSL_COMPRESS_NULL; if ( ssl->hostname != NULL ) { SSL_DEBUG_MSG( 3, ( "client hello, server name extension: %s", ssl->hostname ) ); // Extensions length *p++ = (unsigned char)( ( ( ssl->hostname_len + 9 ) >> 8 ) & 0xff ); *p++ = (unsigned char)( ( ( ssl->hostname_len + 9 ) ) & 0xff ); // Extension type *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME >> 8 ) & 0xff ); *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME ) & 0xff ); // Extension length *p++ = (unsigned char)( ( ( ssl->hostname_len + 5 ) >> 8 ) & 0xff ); *p++ = (unsigned char)( ( ( ssl->hostname_len + 5 ) ) & 0xff ); // Server name list length *p++ = (unsigned char)( ( ( ssl->hostname_len + 3 ) >> 8 ) & 0xff ); *p++ = (unsigned char)( ( ( ssl->hostname_len + 3 ) ) & 0xff ); // Name type *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME_HOSTNAME ) & 0xff ); // Hostname length *p++ = (unsigned char)( ( ( ssl->hostname_len ) >> 8 ) & 0xff ); *p++ = (unsigned char)( ( ( ssl->hostname_len ) ) & 0xff ); // Hostname memcpy( p, ssl->hostname, ssl->hostname_len ); p += ssl->hostname_len; }
static int ssl_write_client_hello( ssl_context *ssl ) { int ret; size_t i, n, ext_len = 0; unsigned char *buf; unsigned char *p; time_t t; unsigned char sig_alg_list[20]; size_t sig_alg_len = 0; SSL_DEBUG_MSG( 2, ( "=> write client hello" ) ); if( ssl->f_rng == NULL ) { SSL_DEBUG_MSG( 1, ( "no RNG provided") ); return( POLARSSL_ERR_SSL_NO_RNG ); } if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) { ssl->major_ver = ssl->min_major_ver; ssl->minor_ver = ssl->min_minor_ver; } if( ssl->max_major_ver == 0 && ssl->max_minor_ver == 0 ) { ssl->max_major_ver = SSL_MAJOR_VERSION_3; ssl->max_minor_ver = SSL_MINOR_VERSION_3; } /* * 0 . 0 handshake type * 1 . 3 handshake length * 4 . 5 highest version supported * 6 . 9 current UNIX time * 10 . 37 random bytes */ buf = ssl->out_msg; p = buf + 4; *p++ = (unsigned char) ssl->max_major_ver; *p++ = (unsigned char) ssl->max_minor_ver; SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]", buf[4], buf[5] ) ); t = time( NULL ); *p++ = (unsigned char)( t >> 24 ); *p++ = (unsigned char)( t >> 16 ); *p++ = (unsigned char)( t >> 8 ); *p++ = (unsigned char)( t ); SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) ); if( ( ret = ssl->f_rng( ssl->p_rng, p, 28 ) ) != 0 ) return( ret ); p += 28; memcpy( ssl->handshake->randbytes, buf + 6, 32 ); SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 6, 32 ); /* * 38 . 38 session id length * 39 . 39+n session id * 40+n . 41+n ciphersuitelist length * 42+n . .. ciphersuitelist * .. . .. compression methods length * .. . .. compression methods * .. . .. extensions length * .. . .. extensions */ n = ssl->session_negotiate->length; if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || n < 16 || n > 32 || ssl->handshake->resume == 0 ) n = 0; *p++ = (unsigned char) n; for( i = 0; i < n; i++ ) *p++ = ssl->session_negotiate->id[i]; SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) ); SSL_DEBUG_BUF( 3, "client hello, session id", buf + 39, n ); for( n = 0; ssl->ciphersuites[ssl->minor_ver][n] != 0; n++ ); if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) n++; *p++ = (unsigned char)( n >> 7 ); *p++ = (unsigned char)( n << 1 ); /* * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV */ if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) { *p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO >> 8 ); *p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO ); n--; }