diff --git a/ssl/test/killgnutls.sh b/ssl/test/killgnutls.sh new file mode 100755 index 000000000..f910f4b07 --- /dev/null +++ b/ssl/test/killgnutls.sh @@ -0,0 +1,2 @@ +#!/bin/sh +ps -ef|grep gnutls-serv | /usr/bin/awk '{print $2}' |xargs kill -9 diff --git a/ssl/test/ssltest.c b/ssl/test/ssltest.c index 9ecd2275b..4dd1fca47 100644 --- a/ssl/test/ssltest.c +++ b/ssl/test/ssltest.c @@ -802,7 +802,7 @@ static void do_client(client_t *clnt) "-connect localhost:%d %s 2>&1 | grep \"Session-ID:\"", g_port, clnt->openssl_option); } - else + else if (strstr(clnt->testname, "GNUTLS") == NULL) { sprintf(openssl_buf, "echo \"hello client\" | openssl s_client -tls1 " #ifdef WIN32 @@ -812,6 +812,16 @@ static void do_client(client_t *clnt) #endif g_port, clnt->openssl_option); } + else /* gnutls */ + { + sprintf(openssl_buf, "echo \"hello client\" | gnutls-cli " +#ifdef WIN32 + "-p %d %s 127.0.0.1", +#else + "-p %d %s 127.0.0.1 > /dev/null 2>&1", +#endif + g_port, clnt->openssl_option); + } system(openssl_buf); } @@ -1243,6 +1253,15 @@ int SSL_server_tests(void) NULL, "abcd", DEFAULT_SVR_OPTION))) goto cleanup; + /* + * GNUTLS + */ + if ((ret = SSL_server_test("GNUTLS client", + "", + "../ssl/test/axTLS.x509_1024.cer", NULL, + "../ssl/test/axTLS.key_1024", + NULL, NULL, DEFAULT_SVR_OPTION))) + goto cleanup; ret = 0; cleanup: @@ -1279,6 +1298,7 @@ typedef struct { const char *testname; const char *openssl_option; + int do_gnutls; } server_t; static void do_server(server_t *svr) @@ -1287,8 +1307,17 @@ static void do_server(server_t *svr) #ifndef WIN32 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); #endif - sprintf(openssl_buf, "openssl s_server -tls1 " - "-accept %d -quiet %s ", g_port, svr->openssl_option); + if (svr->do_gnutls) + { + sprintf(openssl_buf, "gnutls-serv " + "-p %d --quiet %s ", g_port, svr->openssl_option); + } + else + { + sprintf(openssl_buf, "openssl s_server -tls1 " + "-accept %d -quiet %s ", g_port, svr->openssl_option); + } + system(openssl_buf); } @@ -1311,6 +1340,8 @@ static int SSL_client_test( pthread_t thread; #endif + server_data.do_gnutls = strstr(test, "GNUTLS") != NULL; + if (sess_resume == NULL || sess_resume->start_server) { g_port++; @@ -1592,6 +1623,14 @@ int SSL_client_tests(void) } printf("SSL client test \"Invalid certificate type\" passed\n"); + + if ((ret = SSL_client_test("GNUTLS client", + &ssl_ctx, + "--x509certfile ../ssl/test/axTLS.x509_1024.pem " + "--x509keyfile ../ssl/test/axTLS.key_1024.pem -q", NULL, + DEFAULT_CLNT_OPTION, NULL, NULL, NULL))) + goto cleanup; + ret = 0; cleanup: @@ -1600,6 +1639,7 @@ cleanup: ssl_display_error(ret); printf("Error: A client test failed\n"); system("sh ../ssl/test/killopenssl.sh"); + system("sh ../ssl/test/killgnutls.sh"); exit(1); } else @@ -2171,6 +2211,7 @@ int main(int argc, char *argv[]) goto cleanup; system("sh ../ssl/test/killopenssl.sh"); + system("sh ../ssl/test/killgnutls.sh"); if (SSL_server_tests()) goto cleanup; diff --git a/ssl/tls1.c b/ssl/tls1.c index 21a01733b..5a828e91a 100755 --- a/ssl/tls1.c +++ b/ssl/tls1.c @@ -715,7 +715,7 @@ static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len) } } } - else + else /* stream cipher */ { hmac_offset = read_len - ssl->cipher_info->digest_size; @@ -1009,9 +1009,7 @@ static int send_raw_packet(SSL *ssl, uint8_t protocol) */ int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length) { - int msg_length = length; - int ret, pad_bytes = 0; - ssl->bm_index = msg_length; + int ret, msg_length = 0; /* if our state is bad, don't bother */ if (ssl->hs_status == SSL_ERROR_DEAD) @@ -1022,17 +1020,19 @@ int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length) memcpy(ssl->bm_data, in, length); } + msg_length += length; if (IS_SET_SSL_FLAG(SSL_TX_ENCRYPTED)) { int mode = IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? SSL_CLIENT_WRITE : SSL_SERVER_WRITE; - uint8_t hmac_header[SSL_RECORD_SIZE]; - - hmac_header[0] = protocol; - hmac_header[1] = 0x03; /* version = 3.1 or higher */ - hmac_header[2] = ssl->version & 0x0f; - hmac_header[3] = length >> 8; - hmac_header[4] = length & 0xff; + uint8_t hmac_header[SSL_RECORD_SIZE] = + { + protocol, + 0x03, /* version = 3.1 or higher */ + ssl->version & 0x0f, + msg_length >> 8, + msg_length & 0xff + }; if (protocol == PT_HANDSHAKE_PROTOCOL) { @@ -1040,21 +1040,20 @@ int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length) if (ssl->bm_data[0] != HS_HELLO_REQUEST) { - add_packet(ssl, ssl->bm_data, ssl->bm_index); + add_packet(ssl, ssl->bm_data, msg_length); } } /* add the packet digest */ + add_hmac_digest(ssl, mode, hmac_header, ssl->bm_data, msg_length, + &ssl->bm_data[msg_length]); msg_length += ssl->cipher_info->digest_size; - ssl->bm_index = msg_length; - add_hmac_digest(ssl, mode, hmac_header, ssl->bm_data, length, - &ssl->bm_data[length]); /* add padding? */ if (ssl->cipher_info->padding_size) { int last_blk_size = msg_length%ssl->cipher_info->padding_size; - pad_bytes = ssl->cipher_info->padding_size - last_blk_size; + int pad_bytes = ssl->cipher_info->padding_size - last_blk_size; /* ensure we always have at least 1 padding byte */ if (pad_bytes == 0) @@ -1062,12 +1061,24 @@ int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length) memset(&ssl->bm_data[msg_length], pad_bytes-1, pad_bytes); msg_length += pad_bytes; - ssl->bm_index = msg_length; } DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_data, msg_length); increment_write_sequence(ssl); + /* add the explicit IV for TLS1.1 */ + if (ssl->version >= SSL_PROTOCOL_VERSION1_1 && + ssl->cipher_info->iv_size) + + { + uint8_t iv_size = ssl->cipher_info->iv_size; + uint8_t *t_buf = alloca(msg_length + iv_size); + memcpy(t_buf + iv_size, ssl->bm_data, msg_length); + get_random(iv_size, t_buf); + msg_length += iv_size; + memcpy(ssl->bm_data, t_buf, msg_length); + } + /* now encrypt the packet */ ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_data, ssl->bm_data, msg_length); @@ -1078,10 +1089,11 @@ int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length) if (ssl->bm_data[0] != HS_HELLO_REQUEST) { - add_packet(ssl, ssl->bm_data, ssl->bm_index); + add_packet(ssl, ssl->bm_data, length); } } + ssl->bm_index = msg_length; if ((ret = send_raw_packet(ssl, protocol)) <= 0) return ret; @@ -1223,10 +1235,27 @@ int basic_read(SSL *ssl, uint8_t **in_data) if (IS_SET_SSL_FLAG(SSL_NEED_RECORD)) { /* check for sslv2 "client hello" */ - if (buf[0] & 0x80 && buf[2] == 1 && buf[3] == 0x03) + if (buf[0] & 0x80 && buf[2] == 1) { #ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE + uint8_t version = (buf[3] << 4) + buf[4]; DISPLAY_BYTES(ssl, "ssl2 record", buf, 5); + + /* should be v3.1 (TLSv1) or better */ + ssl->version = ssl->client_version = version; + + if (version > SSL_PROTOCOL_VERSION_MAX) + { + /* use client's version */ + ssl->version = SSL_PROTOCOL_VERSION_MAX; + } + else if (version < SSL_PROTOCOL_MIN_VERSION) + { + ret = SSL_ERROR_INVALID_VERSION; + ssl_display_error(ret); + return ret; + } + add_packet(ssl, &buf[2], 3); ret = process_sslv23_client_hello(ssl); #else @@ -1259,6 +1288,14 @@ int basic_read(SSL *ssl, uint8_t **in_data) if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED)) { ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, read_len); + + if (ssl->version >= SSL_PROTOCOL_VERSION1_1 && + ssl->cipher_info->iv_size) + { + buf += ssl->cipher_info->iv_size; + read_len -= ssl->cipher_info->iv_size; + } + read_len = verify_digest(ssl, is_client ? SSL_CLIENT_READ : SSL_SERVER_READ, buf, read_len); @@ -1310,7 +1347,7 @@ int basic_read(SSL *ssl, uint8_t **in_data) case PT_APP_PROTOCOL_DATA: if (in_data) { - *in_data = ssl->bm_data; /* point to the work buffer */ + *in_data = buf; /* point to the work buffer */ (*in_data)[read_len] = 0; /* null terminate just in case */ } @@ -1414,12 +1451,8 @@ int send_change_cipher_spec(SSL *ssl) */ int send_finished(SSL *ssl) { - uint8_t *buf = ssl->bm_data; - - buf[0] = HS_FINISHED; - buf[1] = 0; - buf[2] = 0; - buf[3] = SSL_FINISHED_HASH_SIZE; + uint8_t buf[SSL_FINISHED_HASH_SIZE+4] = { + HS_FINISHED, 0, 0, SSL_FINISHED_HASH_SIZE }; /* now add the finished digest mac (12 bytes) */ finished_digest(ssl, @@ -1436,7 +1469,7 @@ int send_finished(SSL *ssl) #endif return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, - NULL, SSL_FINISHED_HASH_SIZE+4); + buf, SSL_FINISHED_HASH_SIZE+4); } /** @@ -1516,9 +1549,8 @@ int send_alert(SSL *ssl, int error_code) /** * Process a client finished message. */ -int process_finished(SSL *ssl, int hs_len) +int process_finished(SSL *ssl, uint8_t *buf, int hs_len) { - uint8_t *buf = ssl->bm_data; int ret = SSL_OK; int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME); diff --git a/ssl/tls1.h b/ssl/tls1.h index 079613530..b533096ee 100755 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -45,10 +45,9 @@ extern "C" { #include "crypto_misc.h" #define SSL_PROTOCOL_MIN_VERSION 0x31 /* TLS v1.0 */ -//#define SSL_PROTOCOL_MINOR_VERSION 0x02 /* TLS v1.1 */ -#define SSL_PROTOCOL_MINOR_VERSION 0x01 /* TLS v1.0 */ -//#define SSL_PROTOCOL_VERSION 0x32 /* TLS v1.1 */ -#define SSL_PROTOCOL_VERSION 0x31 /* TLS v1.1 */ +#define SSL_PROTOCOL_MINOR_VERSION 0x02 /* TLS v1.1 */ +#define SSL_PROTOCOL_VERSION_MAX 0x32 /* TLS v1.1 */ +#define SSL_PROTOCOL_VERSION1_1 0x32 /* TLS v1.1 */ #define SSL_RANDOM_SIZE 32 #define SSL_SECRET_SIZE 48 #define SSL_FINISHED_HASH_SIZE 12 @@ -236,7 +235,7 @@ int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length); int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len); int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len); -int process_finished(SSL *ssl, int hs_len); +int process_finished(SSL *ssl, uint8_t *buf, int hs_len); int process_sslv23_client_hello(SSL *ssl); int send_alert(SSL *ssl, int error_code); int send_finished(SSL *ssl); diff --git a/ssl/tls1_clnt.c b/ssl/tls1_clnt.c index 33aa1ad60..616c78976 100644 --- a/ssl/tls1_clnt.c +++ b/ssl/tls1_clnt.c @@ -51,7 +51,7 @@ EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size) { SSL *ssl = ssl_new(ssl_ctx, client_fd); - ssl->version = SSL_PROTOCOL_VERSION; + ssl->version = SSL_PROTOCOL_VERSION_MAX; /* try top version first */ if (session_id && ssl_ctx->num_sessions) { @@ -118,7 +118,7 @@ int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) break; case HS_FINISHED: - ret = process_finished(ssl, hs_len); + ret = process_finished(ssl, buf, hs_len); disposable_free(ssl); /* free up some memory */ /* note: client renegotiation is not allowed after this */ break; @@ -234,8 +234,10 @@ static int process_server_hello(SSL *ssl) /* check that we are talking to a TLSv1 server */ uint8_t version = (buf[4] << 4) + buf[5]; - if (version > SSL_PROTOCOL_VERSION) - version = SSL_PROTOCOL_VERSION; + if (version > SSL_PROTOCOL_VERSION_MAX) + { + version = SSL_PROTOCOL_VERSION_MAX; + } else if (ssl->version < SSL_PROTOCOL_MIN_VERSION) { ret = SSL_ERROR_INVALID_VERSION; diff --git a/ssl/tls1_svr.c b/ssl/tls1_svr.c index 13305332c..f374928f1 100644 --- a/ssl/tls1_svr.c +++ b/ssl/tls1_svr.c @@ -103,7 +103,7 @@ int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) break; case HS_FINISHED: - ret = process_finished(ssl, hs_len); + ret = process_finished(ssl, buf, hs_len); disposable_free(ssl); /* free up some memory */ break; } @@ -125,8 +125,11 @@ static int process_client_hello(SSL *ssl) uint8_t version = (record_buf[1] << 4) + record_buf[2]; ssl->version = ssl->client_version = version; - if (version > SSL_PROTOCOL_VERSION) - ssl->version = SSL_PROTOCOL_VERSION; /* use client's version */ + if (version > SSL_PROTOCOL_VERSION_MAX) + { + /* use client's version instead */ + ssl->version = SSL_PROTOCOL_VERSION_MAX; + } else if (version < SSL_PROTOCOL_MIN_VERSION) /* old version supported? */ { ret = SSL_ERROR_INVALID_VERSION; @@ -196,13 +199,6 @@ int process_sslv23_client_hello(SSL *ssl) DISPLAY_BYTES(ssl, "received %d bytes", buf, read_len, read_len); - /* should be v3.1 (TLSv1) or better */ - ssl->version = (buf[3] << 4) + buf[4]; - if (ssl->version < SSL_PROTOCOL_MIN_VERSION) - { - return SSL_ERROR_INVALID_VERSION; - } - add_packet(ssl, buf, read_len); /* connection has gone, so die */