Ethereal-dev: [Ethereal-dev] ssl decryption patch
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Paolo Abeni <00918190@xxxxxxxxx>
Date: Wed, 13 Apr 2005 12:04:30 +0200
Hi, I have assembled a patch for the ssl dissector that enables ssl decryption when it is possible [*]. It support session key renegotiation and ssl sessions cache. Decrypted application data is re-inserted into ethereal dissection process. The patch is derived from ssldump code and requires the ssl library and headers. The patch require also a couple of new file (attached) to be put into the epan/dissectors/ directory. I have tested the patch only on a gnu/linux (Mandrake 11) system. There is an issue about decryption. Basically I need to perform some operations only when processing the packets sequentially [**], but a I don't known any reliable method to get this information at dissection time. The not-so-clean hack is to use the proto_tree pointer as 'processing selected/out of order packet' flag. It's ugly and does not work always, so I'm open to any suggestion... Best regards, Paolo Abeni [*] Only sessions with RSA key exchange can be decrypted, providing the host private key via the preferences. For more information see the ssldump documentation [**] that is, when processing packets provided by a capture file or a live capture, and not when dissecting a random packet selected by user via the GUI Gruppo Telecom Italia - Direzione e coordinamento di Telecom Italia S.p.A. ==================================================================== CONFIDENTIALITY NOTICE This message and its attachments are addressed solely to the persons above and may contain confidential information. If you have received the message in error, be informed that any use of the content hereof is prohibited. Please return it immediately to the sender and delete the message. Should you have any questions, please send an e_mail to MailAdmin@xxxxxxxxx. Thank you ====================================================================
/* This code is derived from ssldump. See: http://www.rtfm.com/ssldump/ Copyright (C) 1999-2001 RTFM, Inc. All Rights Reserved This package is a SSLv3/TLS protocol analyzer written by Eric Rescorla <ekr@xxxxxxxx> and licensed by RTFM, Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by Eric Rescorla for RTFM, Inc. 4. Neither the name of RTFM, Inc. nor the name of Eric Rescorla may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE ERIC RESCORLA AND RTFM ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <glib.h> #define SSL_DECRYPT_DEBUG #include <epan/packet.h> #include <epan/dissectors/packet-ssl-utils.h> #define PRF(ssl,secret,usage,rnd1,rnd2,out) ((ssl->version_netorder==SSLV3_VERSION)? \ ssl3_prf(ssl,secret,usage,rnd1,rnd2,out): \ tls_prf(ssl,secret,usage,rnd1,rnd2,out)) static char *digests[]={ "MD5", "SHA1" }; static char *ciphers[]={ "DES", "DES3", "RC4", "RC2", "IDEA" }; static SslCipherSuite cipher_suites[]={ {1,KEX_RSA,SIG_RSA,ENC_NULL,0,0,0,DIG_MD5,16,0}, {2,KEX_RSA,SIG_RSA,ENC_NULL,0,0,0,DIG_SHA,20,0}, {3,KEX_RSA,SIG_RSA,ENC_RC4,1,128,40,DIG_MD5,16,1}, {4,KEX_RSA,SIG_RSA,ENC_RC4,1,128,128,DIG_MD5,16,0}, {5,KEX_RSA,SIG_RSA,ENC_RC4,1,128,128,DIG_SHA,20,0}, {6,KEX_RSA,SIG_RSA,ENC_RC2,8,128,40,DIG_SHA,20,1}, {7,KEX_RSA,SIG_RSA,ENC_IDEA,8,128,128,DIG_SHA,20,0}, {8,KEX_RSA,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1}, {9,KEX_RSA,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0}, {10,KEX_RSA,SIG_RSA,ENC_3DES,8,192,192,DIG_SHA,20,0}, {11,KEX_DH,SIG_DSS,ENC_DES,8,64,40,DIG_SHA,20,1}, {12,KEX_DH,SIG_DSS,ENC_DES,8,64,64,DIG_SHA,20,0}, {13,KEX_DH,SIG_DSS,ENC_3DES,8,192,192,DIG_SHA,20,0}, {14,KEX_DH,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1}, {15,KEX_DH,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0}, {16,KEX_DH,SIG_RSA,ENC_3DES,8,192,192,DIG_SHA,20,0}, {17,KEX_DH,SIG_DSS,ENC_DES,8,64,40,DIG_SHA,20,1}, {18,KEX_DH,SIG_DSS,ENC_DES,8,64,64,DIG_SHA,20,0}, {19,KEX_DH,SIG_DSS,ENC_3DES,8,192,192,DIG_SHA,20,0}, {20,KEX_DH,SIG_RSA,ENC_DES,8,64,40,DIG_SHA,20,1}, {21,KEX_DH,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,0}, {22,KEX_DH,SIG_RSA,ENC_3DES,8,192,192,DIG_SHA,20,0}, {23,KEX_DH,SIG_NONE,ENC_RC4,1,128,40,DIG_MD5,16,1}, {24,KEX_DH,SIG_NONE,ENC_RC4,1,128,128,DIG_MD5,16,0}, {25,KEX_DH,SIG_NONE,ENC_DES,8,64,40,DIG_MD5,16,1}, {26,KEX_DH,SIG_NONE,ENC_DES,8,64,64,DIG_MD5,16,0}, {27,KEX_DH,SIG_NONE,ENC_3DES,8,192,192,DIG_MD5,16,0}, {96,KEX_RSA,SIG_RSA,ENC_RC4,1,128,56,DIG_MD5,16,1}, {97,KEX_RSA,SIG_RSA,ENC_RC2,1,128,56,DIG_MD5,16,1}, {98,KEX_RSA,SIG_RSA,ENC_DES,8,64,64,DIG_SHA,20,1}, {99,KEX_DH,SIG_DSS,ENC_DES,8,64,64,DIG_SHA,16,1}, {100,KEX_RSA,SIG_RSA,ENC_RC4,1,128,56,DIG_SHA,20,1}, {101,KEX_DH,SIG_DSS,ENC_RC4,1,128,56,DIG_SHA,20,1}, {102,KEX_DH,SIG_DSS,ENC_RC4,1,128,128,DIG_SHA,20,0}, {-1, 0,0,0,0,0,0,0,20,0} }; typedef struct { int ssl_port; int decrypted_port; } SslPortPair; static SslPortPair ssl_ports [] = { {443, 80}, /* https */ {636, 389}, /* ldap */ {993, 143}, /* imap */ {995, 110}, /* pop3 */ {0,0}}; int ssl_packet_from_server(int port) { SslPortPair* current; for (current = ssl_ports; current->ssl_port != 0; current++) { if (current->ssl_port == port) return 1; } return 0; } int ssl_data_init(StringInfo* str, char* src, unsigned int len) { if (str->data) free(str->data); str->data = malloc(len); if (!str->data) return -1; if (src) memcpy(str->data, src,len); str->data_len = len; return 0; } int ssl_data_alloc(StringInfo* str, unsigned int len) { str->data = malloc(len); if (!str->data) return -1; str->data_len = len; return 0; } int ssl_data_set(StringInfo* str, char* data, unsigned int len) { memcpy(str->data, data, len); str->data_len = len; return 0; } void ssl_debug_printf(char* fmt,...) { #ifdef SSL_DECRYPT_DEBUG va_list ap; int ret=0; va_start(ap, fmt); ret += vfprintf(stderr, fmt, ap); va_end(ap); #endif } void ssl_print_text_data(const char* name, const char* data, int len) { #ifdef SSL_DECRYPT_DEBUG int i; printf("%s: ",name); for (i=0; i< len; i++) { printf("%c",data[i]); } printf("\n"); #endif } void ssl_print_data(const char* name, const char* data, int len) { #ifdef SSL_DECRYPT_DEBUG int i; printf("%s[%d]:\n",name, len); for (i=0; i< len; i++) { if ((i>0) && (i%16 == 0)) printf("\n"); printf("%.2x ",data[i]&255); } printf("\n"); #endif } void ssl_print_string(const char* name, const StringInfo* data) { #ifdef SSL_DECRYPT_DEBUG ssl_print_data(name, data->data, data->data_len); #endif } int ssl_find_cipher(int num,SslCipherSuite* cs) { SslCipherSuite *c; for(c=cipher_suites;c->number!=-1;c++){ if(c->number==num){ *cs=*c; return 0; } } return -1; } /* get ssl data for this session. if no ssl data is found allocate a new one*/ SslDecryptSession* ssl_alloc_session(void) { SslDecryptSession*ssl_session = g_malloc0(sizeof(SslDecryptSession)); if (!ssl_session) return NULL; ssl_debug_printf("ssl_alloc_session ptr %p size %d\n", ssl_session, sizeof(SslDecryptSession)); ssl_session->master_secret.data = ssl_session->_master_secret; ssl_session->session_id.data = ssl_session->_session_id; ssl_session->client_random.data = ssl_session->_client_random; ssl_session->server_random.data = ssl_session->_server_random; ssl_session->master_secret.data_len = 48; return ssl_session; } static int tls_hash(SslDecryptSession* ssl,StringInfo* secret, StringInfo* seed, const EVP_MD *md, StringInfo* out) { u_int8_t *ptr=out->data; unsigned int left=out->data_len; int tocpy; u_int8_t *A; u_int8_t _A[20],tmp[20]; unsigned int A_l,tmp_l; HMAC_CTX hm; ssl_print_string("hash secret", secret); ssl_print_string("hash seed", seed); ssl_debug_printf("tls_hash: hmac %p\n",md); A=seed->data; A_l=seed->data_len; while(left){ HMAC_Init(&hm,secret->data,secret->data_len,md); HMAC_Update(&hm,A,A_l); HMAC_Final(&hm,_A,&A_l); A=_A; HMAC_Init(&hm,secret->data,secret->data_len,md); HMAC_Update(&hm,A,A_l); HMAC_Update(&hm,seed->data,seed->data_len); HMAC_Final(&hm,tmp,&tmp_l); tocpy=MIN(left,tmp_l); memcpy(ptr,tmp,tocpy); ptr+=tocpy; left-=tocpy; } HMAC_cleanup(&hm); ssl_print_string("hash out", out); return (0); } static int tls_prf(SslDecryptSession*ssl,StringInfo* secret,char *usage, StringInfo* rnd1, StringInfo* rnd2, StringInfo* out) { StringInfo seed, sha_out, md5_out; u_int8_t *ptr; StringInfo s1, s2; unsigned int i,s_l, r=-1; int usage_len = strlen(usage); /* initalize buffer for sha, md5 random seed*/ if (ssl_data_alloc(&sha_out, MAX(out->data_len,20)) < 0) return -1; if (ssl_data_alloc(&md5_out, MAX(out->data_len,16)) < 0) goto free_sha; if (ssl_data_alloc(&seed, usage_len+rnd1->data_len+rnd2->data_len) < 0) goto free_md5; ptr=seed.data; memcpy(ptr,usage,usage_len); ptr+=usage_len; memcpy(ptr,rnd1->data,rnd1->data_len); ptr+=rnd1->data_len; memcpy(ptr,rnd2->data,rnd2->data_len); ptr+=rnd2->data_len; /* initalize buffer for client/server seeds*/ s_l=secret->data_len/2 + secret->data_len%2; if (ssl_data_alloc(&s1, s_l) < 0) goto free_seed; if (ssl_data_alloc(&s2, s_l) < 0) goto free_s1; memcpy(s1.data,secret->data,s_l); memcpy(s2.data,secret->data + (secret->data_len - s_l),s_l); ssl_debug_printf("tls_prf: tls_hash(md5 secret_len %d seed_len %d )\n", s1.data_len, seed.data_len); if(tls_hash(ssl,&s1,&seed,EVP_get_digestbyname("MD5"),&md5_out) != 0) goto free_all; ssl_debug_printf("tls_prf: tls_hash(sha)\n"); if(tls_hash(ssl,&s2,&seed,EVP_get_digestbyname("SHA1"),&sha_out) != 0) goto free_all; for(i=0;i<out->data_len;i++) out->data[i]=md5_out.data[i] ^ sha_out.data[i]; r =0; ssl_print_string("PRF out",out); free_all: free(s2.data); free_s1: free(s1.data); free_seed: free(seed.data); free_md5: free(md5_out.data); free_sha: free(sha_out.data); return r; } static int ssl3_generate_export_iv(SslDecryptSession* ssl, StringInfo* r1, StringInfo* r2, StringInfo* out) { MD5_CTX md5; u_int8_t tmp[16]; MD5_Init(&md5); MD5_Update(&md5,r1->data,r1->data_len); MD5_Update(&md5,r2->data,r2->data_len); MD5_Final(tmp,&md5); memcpy(out->data,tmp,out->data_len); ssl_print_string("export iv", out); return(0); } static int ssl3_prf(SslDecryptSession* ssl, StringInfo* secret, char* usage, StringInfo* r1, StringInfo* r2,StringInfo* out) { MD5_CTX md5; SHA_CTX sha; StringInfo *rnd1,*rnd2; unsigned int off; int i=0,j; u_int8_t buf[20]; rnd1=r1; rnd2=r2; MD5_Init(&md5); memset(&sha,0,sizeof(sha)); SHA1_Init(&sha); for(off=0;off<out->data_len;off+=16){ char outbuf[16]; int tocpy; i++; ssl_debug_printf("ssl3_prf: sha1_update(%d)\n",i); /* A, BB, CCC, ... */ for(j=0;j<i;j++){ buf[j]=64+i; } SHA1_Update(&sha,buf,i); if (secret) SHA1_Update(&sha,secret->data,secret->data_len); if(!strcmp(usage,"client write key") || !strcmp(usage,"server write key")){ SHA1_Update(&sha,rnd2->data,rnd2->data_len); SHA1_Update(&sha,rnd1->data,rnd1->data_len); } else{ SHA1_Update(&sha,rnd1->data,rnd1->data_len); SHA1_Update(&sha,rnd2->data,rnd2->data_len); } SHA1_Final(buf,&sha); SHA1_Init(&sha); ssl_debug_printf("ssl3_prf: md5_update(%d)\n",i); MD5_Update(&md5,secret->data,secret->data_len); MD5_Update(&md5,buf,20); MD5_Final(outbuf,&md5); tocpy=MIN(out->data_len-off,16); memcpy(out->data+off,outbuf,tocpy); MD5_Init(&md5); } return(0); } int ssl_create_decoder(SslDecoder *dec, SslCipherSuite *cipher_suite, u_int8_t *mk, u_int8_t *sk, u_int8_t *iv) { const EVP_CIPHER *ciph=0; /* Find the SSLeay cipher */ if(cipher_suite->enc!=ENC_NULL) { ssl_debug_printf("CIPHER: %s\n", ciphers[cipher_suite->enc-0x30]); ciph=(EVP_CIPHER *)EVP_get_cipherbyname(ciphers[cipher_suite->enc-0x30]); } dec->cipher_suite=cipher_suite; dec->mac_key.data = dec->_mac_key; ssl_data_set(&dec->mac_key, mk, cipher_suite->dig_len); EVP_CIPHER_CTX_init(&dec->evp); EVP_CipherInit(&dec->evp,ciph,sk,iv,0); ssl_debug_printf("decoder initialized (digest len %d)\n", cipher_suite->dig_len); return 0; } int ssl_generate_keyring_material(SslDecryptSession*ssl_session, EVP_PKEY *key) { StringInfo key_block; u_int8_t _iv_c[8],_iv_s[8]; u_int8_t _key_c[16],_key_s[16]; int needed; u_int8_t *ptr,*c_wk,*s_wk,*c_mk,*s_mk,*c_iv,*s_iv; /* if master_key is not yet generate, create it now*/ if (!(ssl_session->state & SSL_MASTER_SECRET)) { ssl_debug_printf("ssl_generate_keyring_material:PRF(pre_master_secret)\n"); if (PRF(ssl_session,&ssl_session->pre_master_secret,"master secret", &ssl_session->client_random, &ssl_session->server_random, &ssl_session->master_secret)) { ssl_debug_printf("ssl_generate_keyring_material can't generate master_secret\n"); return -1; } ssl_print_string("master secret",&ssl_session->master_secret); } /* Compute the key block. First figure out how much data we need*/ needed=ssl_session->cipher_suite.dig_len*2; needed+=ssl_session->cipher_suite.bits / 4; if(ssl_session->cipher_suite.block>1) needed+=ssl_session->cipher_suite.block*2; key_block.data_len = needed; key_block.data = malloc(needed); if (!key_block.data) { ssl_debug_printf("ssl_generate_keyring_material can't allacate key_block\n"); return -1; } ssl_debug_printf("ssl_generate_keyring_material sess key generation\n"); if (PRF(ssl_session,&ssl_session->master_secret,"key expansion", &ssl_session->server_random,&ssl_session->client_random, &key_block)) { ssl_debug_printf("ssl_generate_keyring_material can't generate key_block\n"); goto fail; } ssl_print_string("key expansion", &key_block); ptr=key_block.data; c_mk=ptr; ptr+=ssl_session->cipher_suite.dig_len; s_mk=ptr; ptr+=ssl_session->cipher_suite.dig_len; c_wk=ptr; ptr+=ssl_session->cipher_suite.eff_bits/8; s_wk=ptr; ptr+=ssl_session->cipher_suite.eff_bits/8; if(ssl_session->cipher_suite.block>1){ c_iv=ptr; ptr+=ssl_session->cipher_suite.block; s_iv=ptr; ptr+=ssl_session->cipher_suite.block; } if(ssl_session->cipher_suite.export){ StringInfo iv_c,iv_s; StringInfo key_c,key_s; StringInfo k; if(ssl_session->cipher_suite.block>1){ iv_c.data = _iv_c; iv_c.data_len = sizeof(_iv_c); iv_s.data = _iv_s; iv_s.data_len = sizeof(_iv_s); if(ssl_session->version_netorder==SSLV3_VERSION){ ssl_debug_printf("ssl_generate_keyring_material ssl3_generate_export_iv\n"); if (ssl3_generate_export_iv(ssl_session, &ssl_session->client_random, &ssl_session->server_random,&iv_c)) { ssl_debug_printf("ssl_generate_keyring_material can't generate sslv3 client iv\n"); goto fail; } ssl_debug_printf("ssl_generate_keyring_material ssl3_generate_export_iv(2)\n"); if (ssl3_generate_export_iv(ssl_session, &ssl_session->server_random, &ssl_session->client_random,&iv_s)) { ssl_debug_printf("ssl_generate_keyring_material can't generate sslv3 server iv\n"); goto fail; } } else{ u_int8_t _iv_block[16]; StringInfo iv_block; StringInfo key_null; u_int8_t _key_null; key_null.data = &_key_null; key_null.data_len = 0; /* We only have room for 8 bit IVs, but that's all we should need. This is a sanity check */ if(ssl_session->cipher_suite.block>8) { ssl_debug_printf("ssl_generate_keyring_material cipher suite block must be at most 7 nut is %d\n", ssl_session->cipher_suite.block); goto fail; } iv_block.data = _iv_block; iv_block.data_len = sizeof(_iv_block); ssl_debug_printf("ssl_generate_keyring_material prf(iv_block)\n"); if(PRF(ssl_session,&key_null, "IV block", &ssl_session->client_random, &ssl_session->server_random,&iv_block)) { ssl_debug_printf("ssl_generate_keyring_material can't generate tls31 iv block\n"); goto fail; } memcpy(_iv_c,iv_block.data,8); memcpy(_iv_s,iv_block.data+8,8); } c_iv=_iv_c; s_iv=_iv_s; } if (ssl_session->version_netorder==SSLV3_VERSION){ MD5_CTX md5; ssl_debug_printf("ssl_generate_keyring_material MD5(client_random)\n"); MD5_Init(&md5); MD5_Update(&md5,c_wk,ssl_session->cipher_suite.eff_bits/8); MD5_Update(&md5,ssl_session->client_random.data, ssl_session->client_random.data_len); MD5_Update(&md5,ssl_session->server_random.data, ssl_session->server_random.data_len); MD5_Final(_key_c,&md5); c_wk=_key_c; MD5_Init(&md5); ssl_debug_printf("ssl_generate_keyring_material MD5(server_random)\n"); MD5_Update(&md5,s_wk,ssl_session->cipher_suite.eff_bits/8); MD5_Update(&md5,ssl_session->server_random.data, ssl_session->server_random.data_len); MD5_Update(&md5,ssl_session->client_random.data, ssl_session->client_random.data_len); MD5_Final(_key_s,&md5); s_wk=_key_s; } else{ key_c.data = _key_c; key_c.data_len = sizeof(_key_c); key_s.data = _key_s; key_s.data_len = sizeof(_key_s); k.data = c_wk; k.data_len = ssl_session->cipher_suite.eff_bits/8; ssl_debug_printf("ssl_generate_keyring_material PRF(key_c)\n"); if (PRF(ssl_session,&k,"client write key", &ssl_session->client_random, &ssl_session->server_random, &key_c)) { ssl_debug_printf("ssl_generate_keyring_material can't generate tll31 server key \n"); goto fail; } c_wk=_key_c; k.data = s_wk; k.data_len = ssl_session->cipher_suite.eff_bits/8; ssl_debug_printf("ssl_generate_keyring_material PRF(key_s)\n"); if(PRF(ssl_session,&k,"server write key", &ssl_session->client_random, &ssl_session->server_random, &key_s)) { ssl_debug_printf("ssl_generate_keyring_material can't generate tll31 client key \n"); goto fail; } s_wk=_key_s; } } ssl_print_data("Client MAC key",c_mk,ssl_session->cipher_suite.dig_len); ssl_print_data("Server MAC key",s_mk,ssl_session->cipher_suite.dig_len); ssl_print_data("Client Write key",c_wk,ssl_session->cipher_suite.bits/8); ssl_print_data("Server Write key",s_wk,ssl_session->cipher_suite.bits/8); if(ssl_session->cipher_suite.block>1){ ssl_print_data("Client Write IV",c_iv,ssl_session->cipher_suite.block); ssl_print_data("Server Write IV",s_iv,ssl_session->cipher_suite.block); } ssl_debug_printf("ssl_generate_keyring_material ssl_create_decoder(client)\n"); if(ssl_create_decoder(&ssl_session->client, &ssl_session->cipher_suite,c_mk,c_wk,c_iv)) { ssl_debug_printf("ssl_generate_keyring_material can't init client decoder\n"); goto fail; } ssl_debug_printf("ssl_generate_keyring_material ssl_create_decoder(server)\n"); if(ssl_create_decoder(&ssl_session->server, &ssl_session->cipher_suite,s_mk,s_wk,s_iv)) { ssl_debug_printf("ssl_generate_keyring_material can't init client decoder\n"); goto fail; } free(key_block.data); return 0; fail: free(key_block.data); return -1; } int ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session, StringInfo* entrypted_pre_master, EVP_PKEY *pk) { int i; if(ssl_session->cipher_suite.kex!=KEX_RSA) { ssl_debug_printf("ssl_decrypt_pre_master_secret key %d diferent from KEX_RSA(%d)\n", ssl_session->cipher_suite.kex, KEX_RSA); return(-1); } #if 0 /* can'f find any place where ephemeral_rsa is set ...*/ if(d->ephemeral_rsa) { ssl_debug_printf("ssl_decrypt_pre_master_secret ephimeral RSA\n"); return(-1); } #endif if(pk->type!=EVP_PKEY_RSA) { ssl_debug_printf("ssl_decrypt_pre_master_secret type %d different from %d \n", pk->type, EVP_PKEY_RSA); return(-1); } if(ssl_data_init(&ssl_session->pre_master_secret,NULL, BN_num_bytes(pk->pkey.rsa->n)) < 0) { ssl_debug_printf("ssl_decrypt_pre_master_secret can't init pre_master_secret buffer, len %d\n", BN_num_bytes(pk->pkey.rsa->n)); return -1; } ssl_print_string("pre master encrypted",entrypted_pre_master); ssl_debug_printf("ssl_decrypt_pre_master_secret:RSA_private_decrypt\n"); i=RSA_private_decrypt(entrypted_pre_master->data_len, entrypted_pre_master->data,ssl_session->pre_master_secret.data, pk->pkey.rsa,RSA_PKCS1_PADDING); ssl_debug_printf("ssl_decrypt_pre_master_secret private decripyt(%d) %d\n", entrypted_pre_master->data_len,i); if(i!=48) { return -1; } ssl_session->pre_master_secret.data_len=48; ssl_print_string("pre master secret",&ssl_session->pre_master_secret); /* Remove the master secret if it was there to force keying material regeneration in case we're renegotiating */ ssl_session->state &= ~SSL_MASTER_SECRET; return 0; } #define MSB(a) ((a>>8)&0xff) #define LSB(a) (a&0xff) /* This should go to 2^128, but we're never really going to see more than 2^64, so we cheat*/ static int fmt_seq(u_int32_t num, u_int8_t* buf) { u_int32_t netnum; memset(buf,0,8); netnum=htonl(num); memcpy(buf+4,&netnum,4); return(0); } static int tls_check_mac(SslDecoder*decoder, int ct,int ver, u_int8_t* data, u_int32_t datalen, u_int8_t* mac) { HMAC_CTX hm; const EVP_MD *md; u_int32_t l; u_int8_t buf[20]; md=EVP_get_digestbyname(digests[decoder->cipher_suite->dig-0x40]); HMAC_Init(&hm,decoder->mac_key.data,decoder->mac_key.data_len,md); fmt_seq(decoder->seq,buf); decoder->seq++; HMAC_Update(&hm,buf,8); buf[0]=ct; HMAC_Update(&hm,buf,1); buf[0]=MSB(ver); buf[1]=LSB(ver); HMAC_Update(&hm,buf,2); buf[0]=MSB(datalen); buf[1]=LSB(datalen); HMAC_Update(&hm,buf,2); HMAC_Update(&hm,data,datalen); HMAC_Final(&hm,buf,&l); if(memcmp(mac,buf,l)) return -1; HMAC_cleanup(&hm); return(0); } int ssl3_check_mac(SslDecoder*decoder,int ct,int ver,u_int8_t* data, u_int32_t datalen, u_int8_t* mac) { EVP_MD_CTX mc; const EVP_MD *md; u_int32_t l; u_int8_t buf[64],dgst[20]; int pad_ct; pad_ct=(decoder->cipher_suite->dig==DIG_SHA)?40:48; md=EVP_get_digestbyname(digests[decoder->cipher_suite->dig-0x40]); EVP_DigestInit(&mc,md); EVP_DigestUpdate(&mc,decoder->mac_key.data,decoder->mac_key.data_len); memset(buf,0x36,pad_ct); EVP_DigestUpdate(&mc,buf,pad_ct); fmt_seq(decoder->seq,buf); decoder->seq++; EVP_DigestUpdate(&mc,buf,8); buf[0]=ct; EVP_DigestUpdate(&mc,buf,1); buf[0]=MSB(datalen); buf[1]=LSB(datalen); EVP_DigestUpdate(&mc,buf,2); EVP_DigestUpdate(&mc,data,datalen); EVP_DigestFinal(&mc,dgst,&l); EVP_DigestInit(&mc,md); EVP_DigestUpdate(&mc,decoder->mac_key.data,decoder->mac_key.data_len); memset(buf,0x5c,pad_ct); EVP_DigestUpdate(&mc,buf,pad_ct); EVP_DigestUpdate(&mc,dgst,l); EVP_DigestFinal(&mc,dgst,&l); if(memcmp(mac,dgst,l)) return -1; return(0); } int ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, int ct, const char* in, int inl,char*out,int* outl) { int pad; u_int8_t *mac; ssl_debug_printf("ssl_decrypt_record ciphertext len %d\n", inl); /*ssl_print_data("Ciphertext",in, inl);*/ /* First decrypt*/ EVP_Cipher(&decoder->evp,out,in,inl); /*ssl_print_data("Plaintext",out,inl);*/ {static int __idx = 0; if (__idx++ > 0)ssl_print_text_data("\n\n",out, inl - decoder->cipher_suite->dig_len);} *outl=inl; /* Now strip off the padding*/ if(decoder->cipher_suite->block!=1){ pad=out[inl-1]; *outl-=(pad+1); } /* And the MAC */ *outl-=decoder->cipher_suite->dig_len; mac=out+(*outl); /*ssl_print_data("Record data",out,*outl);*/ /* Now check the MAC */ ssl_debug_printf("checking mac (len %d, version %X, ct %d)", *outl,ssl->version_netorder, ct); if(ssl->version_netorder==0x300){ if(ssl3_check_mac(decoder,ct,ssl->version_netorder,out,*outl,mac) < 0) { ssl_debug_printf("mac falied\n"); return -1; } } else{ if(tls_check_mac(decoder,ct,ssl->version_netorder,out,*outl,mac)< 0) { ssl_debug_printf("mac falied\n"); return -1; } } ssl_debug_printf("mac ok\n"); return(0); }
/* This code is based on ssldump. See: http://www.rtfm.com/ssldump/ Copyright (C) 1999-2001 RTFM, Inc. All Rights Reserved This package is a SSLv3/TLS protocol analyzer written by Eric Rescorla <ekr@xxxxxxxx> and licensed by RTFM, Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by Eric Rescorla for RTFM, Inc. 4. Neither the name of RTFM, Inc. nor the name of Eric Rescorla may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE ERIC RESCORLA AND RTFM ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __SSL_UTILS_H_ #define __SSL_UTILS_H_ #include <openssl/pem.h> #include <openssl/ssl.h> #include <openssl/hmac.h> #include <openssl/evp.h> #include <openssl/x509v3.h> #include <epan/address.h> #include <netinet/in.h> typedef struct _StringInfo { char* data; unsigned int data_len; } StringInfo; void ssl_debug_printf(char* fmt,...); void ssl_print_data(const char* name, const char* data, int len); void ssl_print_string(const char* name, const StringInfo* data); void ssl_print_text_data(const char* name, const char* data, int len); #define SSL_WRITE_KEY 1 #define SSLV3_VERSION 0x300 #define TLSV1_VERSION 0x301 #define SSL_CLIENT_RANDOM 1 #define SSL_SERVER_RANDOM 2 #define SSL_CIPHER 4 #define SSL_HAVE_SESSION_KEY 8 #define SSL_VERSION 0x10 #define SSL_MASTER_SECRET 0x20 typedef struct _SslCipherSuite { int number; int kex; int sig; int enc; int block; int bits; int eff_bits; int dig; int dig_len; int export; } SslCipherSuite; #define SSL_DECRYPTED_LEN 512 typedef struct _SslDecoder { SslCipherSuite* cipher_suite; char _mac_key[20]; char decrypted_data[SSL_DECRYPTED_LEN]; StringInfo mac_key; EVP_CIPHER_CTX evp; u_int32_t seq; } SslDecoder; #define KEX_RSA 0x10 #define KEX_DH 0x11 #define SIG_RSA 0x20 #define SIG_DSS 0x21 #define SIG_NONE 0x22 #define ENC_DES 0x30 #define ENC_3DES 0x31 #define ENC_RC4 0x32 #define ENC_RC2 0x33 #define ENC_IDEA 0x34 #define ENC_NULL 0x35 #define DIG_MD5 0x40 #define DIG_SHA 0x41 typedef struct _SslService { address addr; guint port; } SslService; typedef struct _SslDecryptSession { char _master_secret[48]; char _session_id[256]; char _client_random[32]; char _server_random[32]; StringInfo session_id; StringInfo server_random; StringInfo client_random; StringInfo master_secret; StringInfo pre_master_secret; int cipher; int state; guint16 version; guint16 version_netorder; SslCipherSuite cipher_suite; SslDecoder server; SslDecoder client; EVP_PKEY* private_key; } SslDecryptSession; int ssl_data_set(StringInfo* data, char* src, unsigned int len); int ssl_data_init(StringInfo* data, char* src, unsigned int len); SslDecryptSession* ssl_alloc_session(void); int ssl_find_cipher(int num,SslCipherSuite* cs); int ssl_packet_from_server(int port); int ssl_generate_keyring_material(SslDecryptSession*ssl_session, EVP_PKEY *key); int ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session, StringInfo* entrypted_pre_master, EVP_PKEY *pk); int ssl_decrypt_record(SslDecryptSession*ssl,SslDecoder* decoder, int ct, const char* in, int inl,char*out,int* outl); #endif
--- ethereal-0.10.10/epan/dissectors/Makefile.common 2005-03-10 16:53:40.000000000 +0100 +++ /home/paolo/tgz/ethereal-0.10.10/epan/dissectors/Makefile.common 2005-04-12 12:03:01.000000000 +0200 @@ -501,6 +501,7 @@ packet-skinny.c \ packet-slimp3.c \ packet-sll.c \ + packet-ssl-utils.c \ packet-slowprotocols.c \ packet-slsk.c \ packet-smb-browse.c \ --- ethereal-0.10.10/epan/dissectors/packet-ssl.c 2005-03-10 16:53:42.000000000 +0100 +++ /home/paolo/tgz/ethereal-0.10.10/epan/dissectors/packet-ssl.c 2005-04-13 10:55:48.579071224 +0200 @@ -56,14 +56,7 @@ * * Notes: * - * - Uses conversations in a no-malloc fashion. Since we just want to - * remember the version of the conversation, we store the version - * integer directly in the void *data member of the conversation - * structure. This means that we don't have to manage any memory, - * but will cause problems if anyone assumes that all data pointers - * are actually pointers to memory allocated by g_mem_chunk_alloc. - * - * - Does not support decryption of encrypted frames, nor dissection + * - Does not support dissection * of frames that would require state maintained between frames * (e.g., single ssl records spread across multiple tcp frames) * @@ -82,6 +75,18 @@ * - Request Certificate * - Client Certificate * + * - Decryption is supported only for session that use RSA key exchange, + * if the host private key is provided via preference. + * + * - Decryption need to be performed 'sequentially', so it's done + * at packet reception time. This may cause a significative packet capture + * slow down. This also cause do dissect some ssl info that in previous + * dissector version were dissected only when a proto_tree context was + * available + * + * XXXX I assume packet reception time if prote_tree is not null, because + * I can't access easily capture_file state. + * */ #ifdef HAVE_CONFIG_H @@ -97,6 +102,8 @@ #include <epan/conversation.h> #include <epan/prefs.h> #include <epan/dissectors/packet-x509af.h> +#include <epan/dissectors/packet-ssl-utils.h> + static gboolean ssl_desegment = TRUE; @@ -114,6 +121,7 @@ static int hf_ssl_record_version = -1; static int hf_ssl_record_length = -1; static int hf_ssl_record_appdata = -1; +static int hf_ssl_record_appdata_decrypted = -1; static int hf_ssl2_record = -1; static int hf_ssl2_record_is_escape = -1; static int hf_ssl2_record_padding_length = -1; @@ -199,6 +207,70 @@ static gint ett_pct_cert_suites = -1; static gint ett_pct_exch_suites = -1; +typedef struct { + unsigned int ssl_port; + dissector_handle_t handle; +} SslDissector; + +static char* ssl_keys_list = NULL; +static SslDissector ssl_dissectors[] = { + {443, 0}, /* https */ + {636, 0}, /* ldap */ + {993, 0}, /* imap */ + {995, 0}, /* pop3 */ + {0,0}}; + + +/* Hash Functions */ +static gint ssl_equal (gconstpointer v, gconstpointer v2) +{ + const StringInfo *val1 = (const StringInfo *)v; + const StringInfo *val2 = (const StringInfo *)v2; + + if (val1->data_len == val2->data_len && + !memcmp(val1->data, val2->data, val2->data_len)) { + return 1; + } + return 0; +} + +static guint ssl_hash (gconstpointer v) +{ + guint l,hash = 0; + StringInfo* id = (StringInfo*) v; + guint* cur = (guint*) id->data; + for (l=4; (l<id->data_len); l+=4, cur++) + hash = hash ^ (*cur); + + return hash; +} +static gint ssl_private_key_equal (gconstpointer v, gconstpointer v2) +{ + const SslService *val1 = (const SslService *)v; + const SslService *val2 = (const SslService *)v2; + + if ((val1->port == val2->port) && + ! CMP_ADDRESS(&val1->addr, &val2->addr)) { + return 1; + } + return 0; +} + +static guint ssl_private_key_hash (gconstpointer v) +{ + const SslService *key = (const SslService *)v; + guint l,hash = key->port, len = key->addr.len; + + guint* cur = (guint*) key->addr.data; + for (l=4; (l<len); l+=4, cur++) + hash = hash ^ (*cur); + + return hash; +} + +static GHashTable *ssl_session_hash = NULL; +static GHashTable *ssl_key_hash = NULL; + /* The TCP port to associate with by default */ #define TCP_PORT_SSL 443 #define TCP_PORT_SSL_LDAP 636 @@ -703,34 +775,35 @@ /* record layer dissector */ static int dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version, + SslDecryptSession *conv_data, gboolean *need_desegmentation); /* change cipher spec dissector */ static void dissect_ssl3_change_cipher_spec(tvbuff_t *tvb, proto_tree *tree, guint32 offset, - guint *conv_version, guint8 content_type); + SslDecryptSession *conv_data, guint8 content_type); /* alert message dissector */ static void dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version); + SslDecryptSession *conv_data); /* handshake protocol dissector */ static void dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint32 record_length, - guint *conv_version, guint8 content_type); + SslDecryptSession *conv_data, guint8 content_type); static void dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb, proto_tree *tree, - guint32 offset, guint32 length); + guint32 offset, guint32 length, + SslDecryptSession* ssl); static void dissect_ssl3_hnd_srv_hello(tvbuff_t *tvb, proto_tree *tree, - guint32 offset, guint32 length); + guint32 offset, guint32 length, SslDecryptSession* ssl); static void dissect_ssl3_hnd_cert(tvbuff_t *tvb, proto_tree *tree, guint32 offset, packet_info *pinfo); @@ -742,7 +815,7 @@ static void dissect_ssl3_hnd_finished(tvbuff_t *tvb, proto_tree *tree, guint32 offset, - guint *conv_version); + SslDecryptSession *conv_data); /* @@ -753,7 +826,7 @@ /* record layer dissector */ static int dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version, + SslDecryptSession *conv_data, gboolean *need_desegmentation); /* client hello dissector */ @@ -794,7 +867,7 @@ * Support Functions * */ -static void ssl_set_conv_version(packet_info *pinfo, guint version); +/*static void ssl_set_conv_version(packet_info *pinfo, guint version);*/ static int ssl_is_valid_handshake_type(guint8 type); static int ssl_is_valid_content_type(guint8 type); static int ssl_is_valid_ssl_version(guint16 version); @@ -809,7 +882,9 @@ static int ssl_looks_like_valid_pct_handshake(tvbuff_t *tvb, guint32 offset, guint32 record_length); - +static dissector_handle_t ssl_find_dissector(packet_info* pinfo); +static void ssl_save_session(SslDecryptSession* ssl); +static void ssl_restore_session(SslDecryptSession* ssl); /********************************************************************* * * Main dissector @@ -830,6 +905,9 @@ guint32 offset = 0; gboolean first_record_in_frame = TRUE; gboolean need_desegmentation; + int from_server; + SslDecryptSession* ssl_session; + SslService dummy; /* Track the version using conversations to reduce the * chance that a packet that simply *looks* like a v2 or @@ -854,9 +932,36 @@ conv_data = conversation_get_proto_data(conversation, proto_ssl); if (conv_data != NULL) { - conv_version = GPOINTER_TO_UINT(conv_data); + conv_version = ((SslDecryptSession*)conv_data)->version; + ssl_session = conv_data; + } + else { + ssl_session= ssl_alloc_session(); + conversation_add_proto_data(conversation, proto_ssl, ssl_session); + } + + if (ssl_packet_from_server(pinfo->srcport)) { + from_server = 1; + dummy.addr = pinfo->net_src; + dummy.port = pinfo->srcport; + } + else { + from_server = 0; + dummy.addr = pinfo->net_dst; + dummy.port = pinfo->destport; + } + + /* try to retrive private key for this service. Do it now 'cause pinfo + * is not always available*/ + ssl_session->private_key = g_hash_table_lookup(ssl_key_hash, &dummy); + if (!ssl_session->private_key) { + ssl_debug_printf("dissect_ssl can't find private key for " + "%hhd.%hhd.%hhd.%hhd:%d\n", dummy.addr.data[0], + dummy.addr.data[1],dummy.addr.data[2], + dummy.addr.data[3],dummy.port); } + /* Initialize the protocol column; we'll set it later when we * figure out what flavor of SSL it is (assuming we don't * throw an exception before we get the chance to do so). */ @@ -914,7 +1019,7 @@ case SSL_VER_SSLv2: case SSL_VER_PCT: offset = dissect_ssl2_record(tvb, pinfo, ssl_tree, - offset, &conv_version, + offset, ssl_session, &need_desegmentation); break; @@ -929,13 +1034,13 @@ if (ssl_is_v2_client_hello(tvb, offset)) { offset = dissect_ssl2_record(tvb, pinfo, ssl_tree, - offset, &conv_version, + offset, ssl_session, &need_desegmentation); } else { offset = dissect_ssl3_record(tvb, pinfo, ssl_tree, - offset, &conv_version, + offset, ssl_session, &need_desegmentation); } break; @@ -948,14 +1053,14 @@ { /* looks like sslv2 or pct client hello */ offset = dissect_ssl2_record(tvb, pinfo, ssl_tree, - offset, &conv_version, + offset, ssl_session, &need_desegmentation); } else if (ssl_looks_like_sslv3(tvb, offset)) { /* looks like sslv3 or tls */ offset = dissect_ssl3_record(tvb, pinfo, ssl_tree, - offset, &conv_version, + offset, ssl_session, &need_desegmentation); } else @@ -981,15 +1086,6 @@ /* Desegmentation return check */ if (need_desegmentation) return; - - /* If we haven't already set the version information for - * this conversation, do so. */ - if (conv_data == NULL) - { - conv_data = GINT_TO_POINTER(conv_version); - conversation_add_proto_data(conversation, proto_ssl, conv_data); - } - /* set up for next record in frame, if any */ first_record_in_frame = FALSE; } @@ -1005,7 +1101,7 @@ static int dissect_ssl3_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version, gboolean *need_desegmentation) + SslDecryptSession* ssl, gboolean *need_desegmentation) { /* @@ -1033,8 +1129,8 @@ proto_tree *ti = NULL; proto_tree *ssl_record_tree = NULL; guint32 available_bytes = 0; - gchar *proto_name_str = NULL; - + gchar *proto_name_str = NULL; + available_bytes = tvb_length_remaining(tvb, offset); /* @@ -1098,7 +1194,7 @@ if (check_col(pinfo->cinfo, COL_PROTOCOL)) { col_set_str(pinfo->cinfo, COL_PROTOCOL, - ssl_version_short_names[*conv_version]); + ssl_version_short_names[ssl->version]); } return offset + 5 + record_length; } @@ -1146,18 +1242,22 @@ * structure and print the column version */ next_byte = tvb_get_guint8(tvb, offset); - if (*conv_version == SSL_VER_UNKNOWN + if (ssl->version == SSL_VER_UNKNOWN && ssl_is_authoritative_version_message(content_type, next_byte)) { if (version == 0x0300) { - *conv_version = SSL_VER_SSLv3; - ssl_set_conv_version(pinfo, *conv_version); + ssl->state |= SSL_VERSION; + ssl->version = SSL_VER_SSLv3; + ssl->version_netorder = version; + /*ssl_set_conv_version(pinfo, ssl->version);*/ } else if (version == 0x0301) { - *conv_version = SSL_VER_TLS; - ssl_set_conv_version(pinfo, *conv_version); + ssl->state |= SSL_VERSION; + ssl->version = SSL_VER_TLS; + ssl->version_netorder = version; + /*ssl_set_conv_version(pinfo, ssl->version);*/ } } if (check_col(pinfo->cinfo, COL_PROTOCOL)) @@ -1175,7 +1275,7 @@ else { col_set_str(pinfo->cinfo, COL_PROTOCOL, - ssl_version_short_names[*conv_version]); + ssl_version_short_names[ssl->version]); } } @@ -1187,29 +1287,110 @@ if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, "Change Cipher Spec"); dissect_ssl3_change_cipher_spec(tvb, ssl_record_tree, - offset, conv_version, content_type); + offset, ssl, content_type); break; case SSL_ID_ALERT: dissect_ssl3_alert(tvb, pinfo, ssl_record_tree, offset, - conv_version); + ssl); break; case SSL_ID_HANDSHAKE: dissect_ssl3_handshake(tvb, pinfo, ssl_record_tree, offset, - record_length, conv_version, content_type); + record_length, ssl, content_type); break; case SSL_ID_APP_DATA: if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, "Application Data"); + if (ssl_record_tree) { - proto_name_str = match_strval(content_type, ssl_31_content_type); + StringInfo* decrypted; + proto_name_str = match_strval(content_type, ssl_31_content_type); proto_item_set_text(ssl_record_tree, "%s Record Layer: %s Protocol: Application Data", - ssl_version_short_names[*conv_version], + ssl_version_short_names[ssl->version], (proto_name_str!=NULL) ? proto_name_str : "unknown"); - proto_tree_add_item(ssl_record_tree, hf_ssl_record_appdata, tvb, + /* PAOLO test if any decrypted data is attached to this packet*/ + decrypted = p_get_proto_data(pinfo->fd, proto_ssl); + if (decrypted) + { + /* try to dissect decrypted data*/ + dissector_handle_t dissector; + ssl_debug_printf("dissect_ssl3_record decrypted len %d\n", decrypted->data_len); + + /* create new tvbuff for the decrypted data */ + tvbuff_t* new_tvb = tvb_new_real_data(decrypted->data, + decrypted->data_len, decrypted->data_len); + + /* XXXX is this correct ?!? */ + tvb_set_free_cb(new_tvb, g_free); + /*tvb_set_child_real_data_tvbuff(tvb, new_tvb);*/ + + /* find out a dissector using server port*/ + dissector = ssl_find_dissector(pinfo); + if (dissector) { + ssl_debug_printf("dissect_ssl3_record found dissector %p\n", dissector); + ssl_print_text_data("decrypted app data",decrypted->data, + decrypted->data_len); + call_dissector(dissector, new_tvb, pinfo, tree); + } + proto_tree_add_string(ssl_record_tree, hf_ssl_record_appdata_decrypted, tvb, + offset, decrypted->data_len, decrypted->data); + } + else + proto_tree_add_item(ssl_record_tree, hf_ssl_record_appdata, tvb, offset, record_length, 0); } + else { + /* PAOLO: try to decrypt appdata */ + int len; + SslDecoder* decoder; + StringInfo* data; + + /* retrive decoder for this packet direction*/ + if (ssl_packet_from_server(pinfo->srcport)) + decoder = &ssl->server; + else + decoder = &ssl->client; + ssl_debug_printf("dissect_ssl3_record app_data len %d ssl state %X\n", + record_length, ssl->state); + + /* if we can decrypt and decryption have success + * add decrypted data to this packet info*/ + if (ssl->state & SSL_HAVE_SESSION_KEY) { + if (ssl_decrypt_record(ssl, decoder, + content_type, tvb_get_ptr(tvb, offset, record_length), + record_length, decoder->decrypted_data, &len) == 0) { + data = p_get_proto_data(pinfo->fd, proto_ssl); + + if (!data) + { + ssl_debug_printf("dissect_ssl3_record allocating app_data %d bytes for app data\n", len); + /* first app data record: allocate and put packet data*/ + data = g_malloc0(sizeof(StringInfo)+ len); + data->data = ((char*)data) + sizeof(StringInfo); + ssl_data_set(data, decoder->decrypted_data, len); + } + else { + /* update previus record*/ + ssl_debug_printf("dissect_ssl3_record reallocating app_data " + "%d bytes for app data (total %d appdata bytes)\n", + len, data->data_len + len+sizeof(StringInfo)); + data = g_realloc(data, data->data_len + len+sizeof(StringInfo)); + data->data= ((char*)data) + sizeof(StringInfo); + memcpy(&data->data[data->data_len], decoder->decrypted_data, len); + data->data_len += len; + + /* realloc can change ptr so remove old one and readd the new one*/ + ssl_debug_printf("dissect_ssl3_record removing old app_data ptr\n"); + p_rem_proto_data(pinfo->fd, proto_ssl); + } + + ssl_debug_printf("dissect_ssl3_record setting decrypted app_data ptr %p\n",data); + p_add_proto_data(pinfo->fd, proto_ssl, data); + } + } + } + break; default: @@ -1227,7 +1408,7 @@ static void dissect_ssl3_change_cipher_spec(tvbuff_t *tvb, proto_tree *tree, guint32 offset, - guint *conv_version, guint8 content_type) + SslDecryptSession* ssl, guint8 content_type) { /* * struct { @@ -1242,7 +1423,7 @@ proto_name_str = match_strval(content_type, ssl_31_content_type); proto_item_set_text(tree, "%s Record Layer: %s Protocol: Change Cipher Spec", - ssl_version_short_names[*conv_version], + ssl_version_short_names[ssl->version], (proto_name_str!=NULL) ? proto_name_str : "unknown"); proto_tree_add_item(tree, hf_ssl_change_cipher_spec, tvb, offset++, 1, FALSE); @@ -1253,7 +1434,7 @@ static void dissect_ssl3_alert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint *conv_version) + SslDecryptSession* ssl) { /* struct { * AlertLevel level; @@ -1303,7 +1484,7 @@ { proto_item_set_text(tree, "%s Record Layer: Alert " "(Level: %s, Description: %s)", - ssl_version_short_names[*conv_version], + ssl_version_short_names[ssl->version], level, desc); proto_tree_add_item(ssl_alert_tree, hf_ssl_alert_message_level, tvb, offset++, 1, FALSE); @@ -1315,7 +1496,7 @@ { proto_item_set_text(tree, "%s Record Layer: Encrypted Alert", - ssl_version_short_names[*conv_version]); + ssl_version_short_names[ssl->version]); proto_item_set_text(ssl_alert_tree, "Alert Message: Encrypted Alert"); } @@ -1327,7 +1508,7 @@ static void dissect_ssl3_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, - guint32 record_length, guint *conv_version, guint8 content_type) + guint32 record_length, SslDecryptSession* ssl, guint8 content_type) { /* struct { * HandshakeType msg_type; @@ -1400,7 +1581,7 @@ if (first_iteration) { proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s", - ssl_version_short_names[*conv_version], + ssl_version_short_names[ssl->version], (proto_name_str!=NULL) ? proto_name_str : "unknown", (msg_type_str!=NULL) ? msg_type_str : "Encrypted Handshake Message"); @@ -1408,7 +1589,7 @@ else { proto_item_set_text(tree, "%s Record Layer: %s Protocol: %s", - ssl_version_short_names[*conv_version], + ssl_version_short_names[ssl->version], (proto_name_str!=NULL) ? proto_name_str : "unknown", "Multiple Handshake Messages"); } @@ -1430,16 +1611,81 @@ /* if we don't have a valid handshake type, just quit dissecting */ if (!msg_type_str) { + /*PAOLO: this is (shold be) an encrypted message. we must + * try to decrypt it to keep decoder state 'aligned'*/ + SslDecoder* decoder; + int len = record_length - offset; + + if (ssl_hand_tree) + return; + + /* retrive the decoder for this direction*/ + if (ssl_packet_from_server(pinfo->srcport)) + decoder = &ssl->server; + else + decoder = &ssl->client; + + /* run the decoder if we have the session key*/ + ssl_debug_printf("dissect_ssl3_handshake encrypted handshake msg len %d ssl state %X\n", + len, ssl->state); + if (ssl->state & SSL_HAVE_SESSION_KEY) + ssl_decrypt_record(ssl, decoder, content_type, tvb_get_ptr(tvb, offset, len), + len, decoder->decrypted_data, &len); return; } + if ((msg_type == SSL_HND_CLIENT_KEY_EXCHG) && !ssl_hand_tree) + { + /* PAOLO: build keyring material*/ + StringInfo encrypted_pre_master; + int ret; + + /* check for required session data */ + ssl_debug_printf("dissect_ssl3_handshake found SSL_HND_CLIENT_KEY_EXCHG state %X\n", + ssl->state); + if ((ssl->state & (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) != + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) { + ssl_debug_printf("dissect_ssl3_handshake not enough data to generate key (required %X)\n", + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)); + goto cant_generate_key; + } + + /* get encrypted data, we must skip tls record len && version and + * 2 bytes of record data */ + encrypted_pre_master.data = g_malloc(length - 2); + encrypted_pre_master.data_len = length-2; + tvb_memcpy(tvb, encrypted_pre_master.data, offset+6, length-2); + + if (!ssl->private_key) { + ssl_debug_printf("dissect_ssl3_handshake can't find private key\n"); + goto cant_generate_key; + } + + /* go with ssl key processessing*/ + ret = ssl_decrypt_pre_master_secret(ssl, &encrypted_pre_master, ssl->private_key); + g_free(encrypted_pre_master.data); + if (ret < 0) { + ssl_debug_printf("dissect_ssl3_handshake can't decrypt pre master secret\n"); + goto cant_generate_key; + } + if (ssl_generate_keyring_material(ssl, ssl->private_key)<0) { + ssl_debug_printf("dissect_ssl3_handshake can't generate keyring material\n"); + goto cant_generate_key; + } + ssl->state |= SSL_HAVE_SESSION_KEY; + ssl_save_session(ssl); + ssl_debug_printf("dissect_ssl3_handshake session keys succesfully generated\n"); + } - if (ssl_hand_tree) +cant_generate_key: + { /* add nodes for the message type and message length */ - proto_tree_add_item(ssl_hand_tree, hf_ssl_handshake_type, - tvb, offset, 1, msg_type); + if (ssl_hand_tree) + proto_tree_add_item(ssl_hand_tree, hf_ssl_handshake_type, + tvb, offset, 1, msg_type); offset++; - proto_tree_add_uint(ssl_hand_tree, hf_ssl_handshake_length, + if (ssl_hand_tree) + proto_tree_add_uint(ssl_hand_tree, hf_ssl_handshake_length, tvb, offset, 3, length); offset += 3; @@ -1450,11 +1696,11 @@ break; case SSL_HND_CLIENT_HELLO: - dissect_ssl3_hnd_cli_hello(tvb, ssl_hand_tree, offset, length); + dissect_ssl3_hnd_cli_hello(tvb, ssl_hand_tree, offset, length, ssl); break; case SSL_HND_SERVER_HELLO: - dissect_ssl3_hnd_srv_hello(tvb, ssl_hand_tree, offset, length); + dissect_ssl3_hnd_srv_hello(tvb, ssl_hand_tree, offset, length, ssl); break; case SSL_HND_CERTIFICATE: @@ -1477,21 +1723,23 @@ /* unimplemented */ break; - case SSL_HND_CLIENT_KEY_EXCHG: - /* unimplemented */ + case SSL_HND_CLIENT_KEY_EXCHG: + /* yet done */ break; case SSL_HND_FINISHED: dissect_ssl3_hnd_finished(tvb, ssl_hand_tree, - offset, conv_version); + offset, ssl); break; } } +#if 0 else { offset += 4; /* skip the handshake header */ } +#endif offset += length; first_iteration = FALSE; /* set up for next pass, if any */ } @@ -1499,34 +1747,77 @@ static int dissect_ssl3_hnd_hello_common(tvbuff_t *tvb, proto_tree *tree, - guint32 offset) + guint32 offset, SslDecryptSession* ssl, gint from_server) { /* show the client's random challenge */ guint32 initial_offset = offset; nstime_t gmt_unix_time; guint8 session_id_length = 0; - + if (tree) { + /* show the time */ gmt_unix_time.secs = tvb_get_ntohl(tvb, offset); gmt_unix_time.nsecs = 0; proto_tree_add_time(tree, hf_ssl_handshake_random_time, - tvb, offset, 4, &gmt_unix_time); + tvb, offset, 4, &gmt_unix_time); offset += 4; /* show the random bytes */ proto_tree_add_item(tree, hf_ssl_handshake_random_bytes, tvb, offset, 28, 0); offset += 28; - + } + else { + /* PAOLO: get proper peer information*/ + StringInfo* rnd; + if (from_server) + rnd = &ssl->server_random; + else + rnd = &ssl->client_random; + + /* get provided random for keyring generation*/ + tvb_memcpy(tvb, rnd->data, offset, 32); + rnd->data_len = 32; + if (from_server) + ssl->state |= SSL_SERVER_RANDOM; + else + ssl->state |= SSL_CLIENT_RANDOM; + ssl_debug_printf("dissect_ssl3_hnd_hello_common found random state %X\n", + ssl->state); + offset += 32; + } + + { /* show the session id */ session_id_length = tvb_get_guint8(tvb, offset); - proto_tree_add_item(tree, hf_ssl_handshake_session_id_len, - tvb, offset++, 1, 0); + if (tree) + proto_tree_add_item(tree, hf_ssl_handshake_session_id_len, + tvb, offset, 1, 0); + offset++; + if (session_id_length > 0) { - proto_tree_add_bytes_format(tree, hf_ssl_handshake_session_id, + /* PAOLO check store session id info */ + if (from_server && (session_id_length == ssl->session_id.data_len) && + (tvb_memeql(tvb, offset, ssl->session_id.data, session_id_length) == 0)) + { + /* clinet/server id match: try to restore a previous cached session*/ + ssl_restore_session(ssl); + } + else { + /* reset state on renegotiation*/ + if (!from_server) + ssl->state &= ~(SSL_HAVE_SESSION_KEY|SSL_MASTER_SECRET| + SSL_CIPHER|SSL_SERVER_RANDOM); + + tvb_memcpy(tvb,ssl->session_id.data, offset, session_id_length); + ssl->session_id.data_len = session_id_length; + } + + if (tree) + proto_tree_add_bytes_format(tree, hf_ssl_handshake_session_id, tvb, offset, session_id_length, tvb_get_ptr(tvb, offset, session_id_length), "Session ID (%u byte%s)", @@ -1534,7 +1825,6 @@ plurality(session_id_length, "", "s")); offset += session_id_length; } - } return offset - initial_offset; } @@ -1594,7 +1884,8 @@ static void dissect_ssl3_hnd_cli_hello(tvbuff_t *tvb, - proto_tree *tree, guint32 offset, guint32 length) + proto_tree *tree, guint32 offset, guint32 length, + SslDecryptSession*ssl) { /* struct { * ProtocolVersion client_version; @@ -1613,20 +1904,23 @@ guint8 compression_method; guint16 start_offset = offset; - if (tree) { /* show the client version */ - proto_tree_add_item(tree, hf_ssl_handshake_client_version, tvb, + if (tree) + proto_tree_add_item(tree, hf_ssl_handshake_client_version, tvb, offset, 2, FALSE); offset += 2; /* show the fields in common with server hello */ - offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset); + offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset, ssl, 0); /* tell the user how many cipher suites there are */ cipher_suite_length = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(tree, hf_ssl_handshake_cipher_suites_len, + if (tree) + proto_tree_add_uint(tree, hf_ssl_handshake_cipher_suites_len, tvb, offset, 2, cipher_suite_length); + else + return; offset += 2; /* skip opaque length */ if (cipher_suite_length > 0) @@ -1707,7 +2001,7 @@ static void dissect_ssl3_hnd_srv_hello(tvbuff_t *tvb, - proto_tree *tree, guint32 offset, guint32 length) + proto_tree *tree, guint32 offset, guint32 length, SslDecryptSession* ssl) { /* struct { * ProtocolVersion server_version; @@ -1720,21 +2014,57 @@ */ guint16 start_offset = offset; - if (tree) + { /* show the server version */ - proto_tree_add_item(tree, hf_ssl_handshake_server_version, tvb, + if (tree) + proto_tree_add_item(tree, hf_ssl_handshake_server_version, tvb, offset, 2, FALSE); offset += 2; /* first display the elements conveniently in * common with client hello */ - offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset); + offset += dissect_ssl3_hnd_hello_common(tvb, tree, offset, ssl, 1); /* now the server-selected cipher suite */ - proto_tree_add_item(tree, hf_ssl_handshake_cipher_suite, + if (tree) + proto_tree_add_item(tree, hf_ssl_handshake_cipher_suite, tvb, offset, 2, FALSE); + else { + /* PAOLO: store selected cipher suite for decription */ + ssl->cipher = tvb_get_ntohs(tvb, offset); + if (ssl_find_cipher(ssl->cipher,&ssl->cipher_suite) < 0) { + ssl_debug_printf("dissect_ssl3_hnd_srv_hello can't find cipher suite %X\n", ssl->cipher); + return; + } + + ssl->state |= SSL_CIPHER; + ssl_debug_printf("dissect_ssl3_hnd_srv_hello found cipher %X, state %X\n", + ssl->cipher, ssl->state); + + /* if we have restored a session now we can have enought material + * to build session key, check it out*/ + if ((ssl->state & (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) != + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)) { + ssl_debug_printf("dissect_ssl3_hnd_srv_hello not enough data to generate key (required %X)\n", + (SSL_CIPHER|SSL_CLIENT_RANDOM|SSL_SERVER_RANDOM|SSL_VERSION)); + return; + } + + if (!ssl->private_key) { + ssl_debug_printf("dissect_ssl3_hnd_srv_hello can't find private key\n"); + return; + } + + ssl_debug_printf("dissect_ssl3_hnd_srv_hello trying to generate keys\n"); + if (ssl_generate_keyring_material(ssl, ssl->private_key)<0) { + ssl_debug_printf("dissect_ssl3_hnd_srv_hello can't generate keyring material\n"); + return; + } + ssl->state |= SSL_HAVE_SESSION_KEY; + return; + } offset += 2; /* and the server-selected compression method */ @@ -1908,7 +2238,7 @@ static void dissect_ssl3_hnd_finished(tvbuff_t *tvb, proto_tree *tree, guint32 offset, - guint *conv_version) + SslDecryptSession* ssl) { /* For TLS: * struct { @@ -1928,7 +2258,7 @@ return; } - switch(*conv_version) { + switch(ssl->version) { case SSL_VER_TLS: proto_tree_add_item(tree, hf_ssl_handshake_finished, tvb, offset, 12, FALSE); @@ -1955,7 +2285,7 @@ /* record layer dissector */ static int dissect_ssl2_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, - guint32 offset, guint *conv_version, + guint32 offset, SslDecryptSession* ssl, gboolean *need_desegmentation) { guint32 initial_offset = offset; @@ -2049,19 +2379,19 @@ /* if we get a server_hello or later handshake in v2, then set * this to sslv2 */ - if (*conv_version == SSL_VER_UNKNOWN) + if (ssl->version == SSL_VER_UNKNOWN) { if (ssl_looks_like_valid_pct_handshake(tvb, (initial_offset + record_length_length), record_length)) { - *conv_version = SSL_VER_PCT; - ssl_set_conv_version(pinfo, *conv_version); + ssl->version = SSL_VER_PCT; + /*ssl_set_conv_version(pinfo, ssl->version);*/ } else if (msg_type >= 2 && msg_type <= 8) { - *conv_version = SSL_VER_SSLv2; - ssl_set_conv_version(pinfo, *conv_version); + ssl->version = SSL_VER_SSLv2; + /*ssl_set_conv_version(pinfo, ssl->version);*/ } } @@ -2072,21 +2402,21 @@ if (check_col(pinfo->cinfo, COL_PROTOCOL)) { col_set_str(pinfo->cinfo, COL_PROTOCOL, - (*conv_version == SSL_VER_PCT) ? "PCT" : "SSLv2"); + (ssl->version == SSL_VER_PCT) ? "PCT" : "SSLv2"); } /* see if the msg_type is valid; if not the payload is * probably encrypted, so note that fact and bail */ msg_type_str = match_strval(msg_type, - (*conv_version == SSL_VER_PCT) + (ssl->version == SSL_VER_PCT) ? pct_msg_types : ssl_20_msg_types); if (!msg_type_str - || ((*conv_version != SSL_VER_PCT) && + || ((ssl->version != SSL_VER_PCT) && !ssl_looks_like_valid_v2_handshake(tvb, initial_offset + record_length_length, record_length)) - || ((*conv_version == SSL_VER_PCT) && + || ((ssl->version == SSL_VER_PCT) && !ssl_looks_like_valid_pct_handshake(tvb, initial_offset + record_length_length, record_length))) @@ -2094,7 +2424,7 @@ if (ssl_record_tree) { proto_item_set_text(ssl_record_tree, "%s Record Layer: %s", - (*conv_version == SSL_VER_PCT) + (ssl->version == SSL_VER_PCT) ? "PCT" : "SSLv2", "Encrypted Data"); } @@ -2110,7 +2440,7 @@ if (ssl_record_tree) { proto_item_set_text(ssl_record_tree, "%s Record Layer: %s", - (*conv_version == SSL_VER_PCT) + (ssl->version == SSL_VER_PCT) ? "PCT" : "SSLv2", msg_type_str); } @@ -2152,13 +2482,13 @@ if (ssl_record_tree) { proto_tree_add_item(ssl_record_tree, - (*conv_version == SSL_VER_PCT) + (ssl->version == SSL_VER_PCT) ? hf_pct_msg_type : hf_ssl2_msg_type, tvb, offset, 1, 0); } offset++; /* move past msg_type byte */ - if (*conv_version != SSL_VER_PCT) + if (ssl->version != SSL_VER_PCT) { /* dissect the message (only handle client hello right now) */ switch (msg_type) { @@ -2838,7 +3168,7 @@ * Support Functions * *********************************************************************/ - +#if 0 static void ssl_set_conv_version(packet_info *pinfo, guint version) { @@ -2869,6 +3199,7 @@ } conversation_add_proto_data(conversation, proto_ssl, GINT_TO_POINTER(version)); } +#endif static int ssl_is_valid_handshake_type(guint8 type) @@ -3149,6 +3480,108 @@ return 0; } +static void ssl_init(void) +{ + if (ssl_session_hash) + g_hash_table_destroy(ssl_session_hash); + if (ssl_key_hash) + g_hash_table_destroy(ssl_key_hash); + + ssl_key_hash = g_hash_table_new(ssl_private_key_hash,ssl_private_key_equal); + ssl_session_hash = g_hash_table_new(ssl_hash, ssl_equal); + if (ssl_keys_list) + { + char* end; + char* start = strdup(ssl_keys_list); + char* tmp = start; + do { + char* addr, *port, *filename, *ip; + SslService* service; + EVP_PKEY * private_key; + FILE* fp; + + addr = start; + /* split ip/file couple with ',' separator*/ + end = strchr(start, ','); + if (end) { + *end = 0; + start = end+1; + } + + /* for each entry split ip , port and filename with ':' separator */ + ssl_debug_printf("ssl_init found host entry %s\n", addr); + port = strchr(addr, ':'); + if (!port) + return; + *port = 0; + port++; + + filename = strchr(port,':'); + if (!filename) + return; + *filename=0; + filename++; + + /* convert ip and port string to network rappresentation*/ + service = g_malloc(sizeof(SslService) + 4); + service->addr.type = AT_IPv4; + service->addr.len = 4; + service->addr.data = ip = ((char*)service) + sizeof(SslService); + sscanf(addr, "%hhu.%hhu.%hhu.%hhu", &ip[0], + &ip[1], &ip[2], &ip[3]); + service->port = atoi(port); + ssl_debug_printf("ssl_init addr %hhu.%hhu.%hhu.%hhu port %d filename %s\n", + ip[0], ip[1], ip[2], ip[3], service->port, filename); + + /* try to load pen file*/ + fp = fopen(filename, "r"); + if (!fp) { + fprintf(stderr, "can't open file %s \n",filename); + return; + } + + private_key = PEM_read_PrivateKey(fp, NULL, NULL,"XXX"); + if (!private_key) { + fprintf(stderr,"can't load private key from %s\n", + filename); + return; + } + fclose(fp); + + ssl_debug_printf("ssl_init private key file %s successfully loaded\n", + filename); + g_hash_table_insert(ssl_key_hash, service, private_key); + + } while (end != NULL); + free(tmp); + } +} + +static void ssl_save_session(SslDecryptSession* ssl) +{ + StringInfo* session_id = g_malloc0(sizeof(StringInfo) + ssl->session_id.data_len); + StringInfo* master_secret = g_malloc0(48 + sizeof(StringInfo)); + + master_secret->data = ((char*)master_secret+sizeof(StringInfo)); + session_id->data = ((char*)session_id+sizeof(StringInfo)); + ssl_data_set(session_id, ssl->session_id.data, ssl->session_id.data_len); + ssl_data_set(master_secret, ssl->master_secret.data, ssl->master_secret.data_len); + g_hash_table_insert(ssl_session_hash, session_id, master_secret); + ssl_print_string("ssl_save_session stored session id", session_id); + ssl_print_string("ssl_save_session stored master secret", master_secret); +} + +static void ssl_restore_session(SslDecryptSession* ssl) +{ + StringInfo* ms = g_hash_table_lookup(ssl_session_hash, &ssl->session_id); + if (!ms) { + ssl_debug_printf("ssl_restore_session can't find stored session\n"); + return; + } + ssl_data_set(&ssl->master_secret, ms->data, ms->data_len); + ssl->state |= SSL_MASTER_SECRET; + ssl_debug_printf("ssl_restore_session master key retrived\n"); +} /********************************************************************* * @@ -3196,6 +3629,12 @@ FT_NONE, BASE_NONE, NULL, 0x0, "Payload is application data", HFILL } }, + { &hf_ssl_record_appdata_decrypted, + { "Application Data decrypted", "ssl.app_data_decrypted", + FT_STRING, BASE_NONE, NULL, 0x0, + "Payload is decrypted application data", HFILL } + }, + { & hf_ssl2_record, { "SSLv2/PCT Record Header", "ssl.record", FT_NONE, BASE_DEC, NULL, 0x0, @@ -3563,10 +4002,31 @@ "Whether the SSL dissector should reassemble SSL records spanning multiple TCP segments. " "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", &ssl_desegment); + prefs_register_string_preference(ssl_module, "rsa_private_key", "RSA private keys list", + "comma separated list of RSA private to be used for decryption; " + "each list entry must be in the form of <ip>:<port>:<key_file_name>", + &ssl_keys_list); + + } register_dissector("ssl", dissect_ssl, proto_ssl); + register_init_routine(ssl_init); + SSLeay_add_all_algorithms(); +} +dissector_handle_t ssl_find_dissector(packet_info* pinfo) +{ + SslDissector* cur; + for (cur = ssl_dissectors; cur->ssl_port != 0; cur++) { + ssl_debug_printf("ssl_find_dissector cur port %d src port %d dest port %d\n", + cur->ssl_port, pinfo->srcport, pinfo->destport); + if ((cur->ssl_port == pinfo->srcport) || (cur->ssl_port == pinfo->destport)) { + ssl_debug_printf("ssl_find_dissector found %p\n", cur->handle); + return cur->handle; + } + } + return 0; } /* If this dissector uses sub-dissector registration add a registration @@ -3579,6 +4039,17 @@ dissector_handle_t ssl_handle; ssl_handle = find_dissector("ssl"); + + ssl_dissectors[0].handle = find_dissector("http"); + ssl_dissectors[1].handle = find_dissector("ldap"); + ssl_dissectors[2].handle = find_dissector("imap"); + ssl_dissectors[3].handle = find_dissector("pop"); + ssl_debug_printf("http: %p ldap %p imap %p pop %p\n", ssl_dissectors[0].handle, + ssl_dissectors[1].handle, ssl_dissectors[2].handle, + ssl_dissectors[3].handle); + ssl_debug_printf("http: %p ldap %p imap %p pop %p\n", find_dissector("http"), + find_dissector("ldap"), find_dissector("imap"), + find_dissector("pop")); dissector_add("tcp.port", TCP_PORT_SSL, ssl_handle); dissector_add("tcp.port", TCP_PORT_SSL_LDAP, ssl_handle); dissector_add("tcp.port", TCP_PORT_SSL_IMAP, ssl_handle); --- ethereal-0.10.10/epan/dissectors/packet-http.c 2005-03-10 16:53:42.000000000 +0100 +++ /home/paolo/tgz/ethereal-0.10.10/epan/dissectors/packet-http.c 2005-04-12 16:59:38.000000000 +0200 @@ -2014,6 +2014,7 @@ proto_register_subtree_array(ett, array_length(ett)); message_http_handle = create_dissector_handle(dissect_message_http, proto_message_http); + register_dissector("http", dissect_http, proto_http); } void
- Prev by Date: Re: [Ethereal-dev] New feature: Clear running capture
- Next by Date: Re: [Ethereal-dev] New feature: Clear running capture
- Previous by thread: [Ethereal-dev] ethereal crash after apply on preferences
- Next by thread: RE: [Ethereal-dev] ssl decryption patch
- Index(es):