diff --git a/ssl/ssl.enums.c b/ssl/ssl.enums.c index 57bf9a9..78cf07d 100644 --- a/ssl/ssl.enums.c +++ b/ssl/ssl.enums.c @@ -6,6 +6,8 @@ #include #endif #include "ssl.enums.h" +static int decode_extension(ssl,dir,seg,data); +static int decode_server_name(ssl,dir,seg,data); static int decode_ContentType_ChangeCipherSpec(ssl,dir,seg,data) ssl_obj *ssl; int dir; @@ -174,14 +176,16 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data) { - UINT4 vj,vn,cs,cslen,complen,comp,odd; + UINT4 vj,vn,cs,cslen,complen,comp,odd,exlen,ex; Data session_id,random; int r; extern decoder cipher_suite_decoder[]; - extern decoder compression_method_decoder[]; + extern decoder compression_method_decoder[]; + extern decoder extension_decoder[]; - printf("\n"); + printf("\n"); + ssl_update_handshake_messages(ssl,data); SSL_DECODE_UINT8(ssl,0,0,data,&vj); SSL_DECODE_UINT8(ssl,0,0,data,&vn); @@ -226,6 +230,22 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data) printf("\n"); } } + + SSL_DECODE_UINT16(ssl,"extensions len",0,data,&exlen); + if (exlen) { + explain(ssl , "extensions\n"); + while(data->len) { + SSL_DECODE_UINT16(ssl, "extension type", 0, data, &ex); + if (ssl_decode_switch(ssl,extension_decoder,ex,dir,seg,data) == R_NOT_FOUND) { + decode_extension(ssl,dir,seg,data); + P_(P_RH){ + explain(ssl, "Extension type: %s not yet implemented in ssldump", ex); + } + continue; + } + printf("\n"); + } + } return(0); } @@ -236,11 +256,14 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data) Data *data; { - int r; Data rnd,session_id; - UINT4 vj,vn; - printf("\n"); + UINT4 vj,vn,exlen,ex; + + extern decoder extension_decoder[]; + + printf("\n"); + ssl_update_handshake_messages(ssl,data); SSL_DECODE_UINT8(ssl,0,0,data,&vj); SSL_DECODE_UINT8(ssl,0,0,data,&vn); @@ -266,7 +289,24 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data) P_(P_HL) printf("\n"); SSL_DECODE_ENUM(ssl,"compressionMethod",1,compression_method_decoder,P_HL,data,0); - P_(P_HL) printf("\n"); + P_(P_HL) printf("\n"); + + SSL_DECODE_UINT16(ssl,"extensions len",0,data,&exlen); + if (exlen) { + explain(ssl , "extensions\n"); + while(data->len) { + SSL_DECODE_UINT16(ssl, "extension type", 0, data, &ex); + if (ssl_decode_switch(ssl,extension_decoder,ex,dir,seg,data) == R_NOT_FOUND) { + decode_extension(ssl,dir,seg,data); + P_(P_RH){ + explain(ssl, "Extension type: %s not yet implemented in ssldump", ex); + } + continue; + } + printf("\n"); + } + } + return(0); } @@ -283,6 +323,7 @@ static int decode_HandshakeType_Certificate(ssl,dir,seg,data) int r; printf("\n"); + ssl_update_handshake_messages(ssl,data); SSL_DECODE_UINT24(ssl,"certificates len",0,data,&len); while(len){ @@ -306,7 +347,7 @@ static int decode_HandshakeType_ServerKeyExchange(ssl,dir,seg,data) int r; printf("\n"); - + ssl_update_handshake_messages(ssl,data); if(ssl->cs){ P_(P_ND){ explain(ssl,"params\n"); @@ -344,6 +385,7 @@ static int decode_HandshakeType_CertificateRequest(ssl,dir,seg,data) int r; printf("\n"); + ssl_update_handshake_messages(ssl,data); SSL_DECODE_UINT8(ssl,"certificate_types len",0,data,&len); for(;len;len--){ SSL_DECODE_ENUM(ssl,"certificate_types",1, @@ -375,6 +417,7 @@ static int decode_HandshakeType_ServerHelloDone(ssl,dir,seg,data) printf("\n"); + ssl_update_handshake_messages(ssl,data); return(0); } @@ -388,6 +431,7 @@ static int decode_HandshakeType_CertificateVerify(ssl,dir,seg,data) int r; printf("\n"); + ssl_update_handshake_messages(ssl,data); SSL_DECODE_OPAQUE_ARRAY(ssl,"Signature",-(1<<15-1),P_HL,data,0); return(0); @@ -404,6 +448,7 @@ static int decode_HandshakeType_ClientKeyExchange(ssl,dir,seg,data) Data pms; printf("\n"); + ssl_update_handshake_messages(ssl,data); if(ssl->cs){ switch(ssl->cs->kex){ @@ -2403,3 +2448,184 @@ decoder client_certificate_type_decoder[]={ {-1} }; +static int decode_extension_server_name(ssl,dir,seg,data) + ssl_obj *ssl; + int dir; + segment *seg; + Data *data; + { + UINT4 t; + int l,r,p; + + extern decoder server_name_type_decoder[]; + + SSL_DECODE_UINT16(ssl,"extension length",0,data,&l); + + if(dir==DIR_I2R){ + SSL_DECODE_UINT16(ssl,"server name list length",0,data,&l); + printf("\n"); + while(l) { + p=data->len; + SSL_DECODE_UINT8(ssl, "server name type", 0, data, &t); + + if (ssl_decode_switch(ssl,server_name_type_decoder,t,dir,seg,data) == R_NOT_FOUND) { + decode_server_name(ssl,dir,seg,data); + P_(P_RH){ + explain(ssl, "Server Name type: %s not yet implemented in ssldump", t); + } + continue; + } + l-=(p-data->len); + } + } + else{ + data->len-=l; + data->data+=l; + } + return(0); + } +static int decode_extension_encrypt_then_mac(ssl,dir,seg,data) + ssl_obj *ssl; + int dir; + segment *seg; + Data *data; + { + int l,r,*etm; + + etm=&ssl->extensions->encrypt_then_mac; + + SSL_DECODE_UINT16(ssl,"extension length",0,data,&l); + data->len-=l; + data->data+=l; + + *etm=dir==DIR_I2R?1:*etm==1; + return(0); + } +static int decode_extension_extended_master_secret(ssl,dir,seg,data) + ssl_obj *ssl; + int dir; + segment *seg; + Data *data; + { + int l,r,*ems; + + ems=&ssl->extensions->extended_master_secret; + + SSL_DECODE_UINT16(ssl,"extension length",0,data,&l); + data->len-=l; + data->data+=l; + + *ems=dir==DIR_I2R?1:*ems==1; + return(0); + } +static int decode_extension(ssl,dir,seg,data) + ssl_obj *ssl; + int dir; + segment *seg; + Data *data; + { + int l,r; + SSL_DECODE_UINT16(ssl,"extension length",0,data,&l); + data->len-=l; + data->data+=l; + return(0); + } + + +decoder extension_decoder[] = { + { + 0, + "server_name", + decode_extension_server_name, + }, + { + 1, + "max_fragment_length", + decode_extension + }, + { + 2, + "client_certificate_url", + decode_extension + }, + { + 3, + "trusted_ca_keys", + decode_extension + }, + { + 4, + "truncated_hmac", + decode_extension + }, + { + 5, + "status_request", + decode_extension + }, + { + 13, + "signature_algorithms", + decode_extension + }, + { + 16, + "application_layer_protocol_negotiation", + decode_extension + }, + { + 22, + "encrypt_then_mac", + decode_extension_encrypt_then_mac + }, + { + 23, + "extended_master_secret", + decode_extension_extended_master_secret + }, + { + 13172, + "next_protocol_negotiation", + decode_extension + }, + +{-1} +}; + +static int decode_server_name_type_host_name(ssl,dir,seg,data) + ssl_obj *ssl; + int dir; + segment *seg; + Data *data; + { + int l,r; + SSL_DECODE_UINT16(ssl,"server name length",0,data,&l); + printf(": %.*s",l,data->data); + + /* Possibly use data->data to set/modify ssl->server_name */ + + data->len-=l; + data->data+=l; + return(0); + } +static int decode_server_name(ssl,dir,seg,data) + ssl_obj *ssl; + int dir; + segment *seg; + Data *data; + { + int l,r; + SSL_DECODE_UINT16(ssl,"server name length",0,data,&l); + data->len-=l; + data->data+=l; + return(0); + } + +decoder server_name_type_decoder[]={ + { + 0, + "host_name", + decode_server_name_type_host_name + }, +{-1} +}; diff --git a/ssl/ssl_analyze.c b/ssl/ssl_analyze.c index dde5b54..67b1f73 100644 --- a/ssl/ssl_analyze.c +++ b/ssl/ssl_analyze.c @@ -265,6 +265,9 @@ static int create_ssl_analyzer(handle,ctx,conn,objp,i_addr,i_port,r_addr,r_port, if(r=ssl_decoder_create(&obj->decoder,obj->ssl_ctx)) ABORT(r); + + if (!(obj->extensions=malloc(sizeof(ssl_extensions)))) + ABORT(R_NO_MEMORY); *objp=(proto_obj *)obj; @@ -291,7 +294,8 @@ static int destroy_ssl_analyzer(objp) free_r_queue(obj->r2i_queue); ssl_decoder_destroy(&obj->decoder); free(obj->client_name); - free(obj->server_name); + free(obj->server_name); + free(obj->extensions); free(*objp); *objp=0; diff --git a/ssl/ssl_h.h b/ssl/ssl_h.h index c166df5..4a64ede 100644 --- a/ssl/ssl_h.h +++ b/ssl/ssl_h.h @@ -67,6 +67,11 @@ typedef struct d_queue_ { int offset; /*How far into the first segment this record starts*/ } r_queue; +typedef struct ssl_extensions_ { + int encrypt_then_mac; + int extended_master_secret; +} ssl_extensions; + typedef struct ssl_obj_ { tcp_conn *conn; int r_state; @@ -86,6 +91,7 @@ typedef struct ssl_obj_ { struct timeval time_last; ssl_decode_ctx *ssl_ctx; ssl_decoder *decoder; + ssl_extensions *extensions; int process_ciphertext; diff --git a/ssl/ssl_rec.c b/ssl/ssl_rec.c index 85b46a2..62b575a 100644 --- a/ssl/ssl_rec.c +++ b/ssl/ssl_rec.c @@ -94,7 +94,7 @@ char *ciphers[]={ static int tls_check_mac PROTO_LIST((ssl_rec_decoder *d,int ct, - int ver,UCHAR *data,UINT4 datalen,UCHAR *mac)); + int ver,UCHAR *data,UINT4 datalen,UCHAR *iv,UINT4 ivlen,UCHAR *mac)); static int fmt_seq PROTO_LIST((UINT4 num,UCHAR *buf)); int ssl_create_rec_decoder(dp,cs,mk,sk,iv) @@ -161,7 +161,8 @@ int ssl_destroy_rec_decoder(dp) *dp=0; return(0); } - + + int ssl_decode_rec_data(ssl,d,ct,version,in,inl,out,outl) ssl_obj *ssl; ssl_rec_decoder *d; @@ -174,50 +175,91 @@ int ssl_decode_rec_data(ssl,d,ct,version,in,inl,out,outl) { #ifdef OPENSSL int pad; - int r; - UCHAR *mac; + int r,encpadl; + UCHAR *mac,*iv; CRDUMP("Ciphertext",in,inl); - /* First decrypt*/ - EVP_Cipher(d->evp,out,in,inl); - CRDUMP("Plaintext",out,inl); - *outl=inl; - - /* Now strip off the padding*/ - if(d->cs->block>1){ - pad=out[inl-1]; - *outl-=(pad+1); - } + if(ssl->extensions->encrypt_then_mac){ + *outl=inl; - /* And the MAC */ - *outl-=d->cs->dig_len; - mac=out+(*outl); - CRDUMP("Record data",out,*outl); + /* First strip off the MAC */ + *outl-=d->cs->dig_len; + mac=in+(*outl); - /* Now check the MAC */ - if(ssl->version==0x300){ - if(r=ssl3_check_mac(d,ct,version,out,*outl,mac)) - ERETURN(r); - } - else{ + encpadl=*outl; + /* Now decrypt */ + EVP_Cipher(d->evp,out,in,*outl); + CRDUMP("Plaintext",out,*outl); + + /* And then strip off the padding*/ + if(d->cs->block>1){ + pad=out[*outl-1]; + *outl-=(pad+1); + } /* TLS 1.1 and beyond: remove explicit IV, only used with * non-stream ciphers. */ if (ssl->version>=0x0302 && ssl->cs->block > 1) { UINT4 blk = ssl->cs->block; if (blk <= *outl) { - *outl-=blk; - memmove(out, out+blk, *outl); + *outl-=blk; + memmove(out, out+blk, *outl); } else { DBG((0,"Block size greater than Plaintext!")); ERETURN(SSL_BAD_MAC); } + + if(r=tls_check_mac(d,ct,version,in+blk,encpadl,in,blk,mac)) + ERETURN(r); + } - if(r=tls_check_mac(d,ct,version,out,*outl,mac)) - ERETURN(r); + else + if(r=tls_check_mac(d,ct,version,in,encpadl,NULL,0,mac)) + ERETURN(r); + } + else { + /* First decrypt*/ + EVP_Cipher(d->evp,out,in,inl); + + CRDUMP("Plaintext",out,inl); + *outl=inl; + /* Now strip off the padding*/ + if(d->cs->block>1){ + pad=out[inl-1]; + *outl-=(pad+1); + } + + /* And the MAC */ + *outl-=d->cs->dig_len; + mac=out+(*outl); + CRDUMP("Record data",out,*outl); + + /* Now check the MAC */ + if(ssl->version==0x300){ + if(r=ssl3_check_mac(d,ct,version,out,*outl,mac)) + ERETURN(r); + } + else{ + /* TLS 1.1 and beyond: remove explicit IV, only used with + * non-stream ciphers. */ + if (ssl->version>=0x0302 && ssl->cs->block > 1) { + UINT4 blk = ssl->cs->block; + if (blk <= *outl) { + *outl-=blk; + memmove(out, out+blk, *outl); + } + else { + DBG((0,"Block size greater than Plaintext!")); + ERETURN(SSL_BAD_MAC); + } + } + if(r=tls_check_mac(d,ct,version,out,*outl,NULL,0,mac)) + ERETURN(r); + } + } #endif return(0); } @@ -241,13 +283,15 @@ static int fmt_seq(num,buf) return(0); } - -static int tls_check_mac(d,ct,ver,data,datalen,mac) + +static int tls_check_mac(d,ct,ver,data,datalen,iv,ivlen,mac) ssl_rec_decoder *d; int ct; int ver; UCHAR *data; UINT4 datalen; + UCHAR *iv; + UINT4 ivlen; UCHAR *mac; { HMAC_CTX hm; @@ -272,7 +316,13 @@ static int tls_check_mac(d,ct,ver,data,datalen,mac) buf[1]=LSB(datalen); HMAC_Update(&hm,buf,2); - HMAC_Update(&hm,data,datalen); + /* for encrypt-then-mac with an explicit IV */ + if(ivlen && iv){ + HMAC_Update(&hm,iv,ivlen); + HMAC_Update(&hm,data,datalen-ivlen); + } + else + HMAC_Update(&hm,data,datalen); HMAC_Final(&hm,buf,&l); if(memcmp(mac,buf,l)) diff --git a/ssl/ssldecode.c b/ssl/ssldecode.c index 787a28f..ff094ff 100644 --- a/ssl/ssldecode.c +++ b/ssl/ssldecode.c @@ -91,6 +91,8 @@ struct ssl_decoder_ { int ephemeral_rsa; Data *PMS; Data *MS; + Data *handshake_messages; + Data *session_hash; ssl_rec_decoder *c_to_s; ssl_rec_decoder *s_to_c; ssl_rec_decoder *c_to_s_n; @@ -111,6 +113,8 @@ static int ssl3_generate_export_iv PROTO_LIST((ssl_obj *ssl, Data *rnd1,Data *rnd2,Data *out)); static int ssl_generate_keying_material PROTO_LIST((ssl_obj *ssl, ssl_decoder *d)); +static int ssl_generate_session_hash PROTO_LIST((ssl_obj *ssl, + ssl_decoder *d)); #endif static int ssl_create_session_lookup_key PROTO_LIST((ssl_obj *ssl, @@ -214,6 +218,8 @@ int ssl_decoder_destroy(dp) r_data_destroy(&d->session_id); r_data_destroy(&d->PMS); r_data_destroy(&d->MS); + r_data_destroy(&d->handshake_messages); + r_data_destroy(&d->session_hash); ssl_destroy_rec_decoder(&d->c_to_s); ssl_destroy_rec_decoder(&d->c_to_s_n); ssl_destroy_rec_decoder(&d->s_to_c); @@ -382,6 +388,35 @@ int ssl_decode_record(ssl,dec,direction,ct,version,d) #endif } +int ssl_update_handshake_messages(ssl,data) + ssl_obj *ssl; + Data *data; + { +#ifdef OPENSSL + Data *hms; + UCHAR *d; + int l,r; + + hms = ssl->decoder->handshake_messages; + d = data->data-4; + l = data->len+4; + + if(hms){ + if(!(hms->data = realloc(hms->data,l+hms->len))) + ERETURN(R_NO_MEMORY); + + memcpy(hms->data+hms->len,d,l); + hms->len+=l; + } + else{ + if(r=r_data_create(&hms,d,l)) + ERETURN(r); + ssl->decoder->handshake_messages=hms; + } +#endif + return(0); + + } static int ssl_create_session_lookup_key(ssl,id,idlen,keyp,keyl) ssl_obj *ssl; @@ -564,6 +599,7 @@ int ssl_process_client_key_exchange(ssl,d,msg,len) } + #ifdef OPENSSL static int tls_P_hash(ssl,secret,seed,md,out) ssl_obj *ssl; @@ -810,7 +846,7 @@ static int ssl_generate_keying_material(ssl,d) ssl_obj *ssl; ssl_decoder *d; { - Data *key_block=0; + Data *key_block=0,temp; UCHAR _iv_c[8],_iv_s[8]; UCHAR _key_c[16],_key_s[16]; int needed; @@ -820,10 +856,20 @@ static int ssl_generate_keying_material(ssl,d) if(!d->MS){ if(r=r_data_alloc(&d->MS,48)) ABORT(r); - - if(r=PRF(ssl,d->PMS,"master secret",d->client_random,d->server_random, - d->MS)) - ABORT(r); + + if (ssl->extensions->extended_master_secret) { + if(r=ssl_generate_session_hash(ssl,d)) + ABORT(r); + + temp.len=0; + if(r=PRF(ssl,d->PMS,"extended master secret",d->session_hash,&temp, + d->MS)) + ABORT(r); + } + else + if(r=PRF(ssl,d->PMS,"master secret",d->client_random,d->server_random, + d->MS)) + ABORT(r); CRDUMPD("MS",d->MS); } @@ -958,4 +1004,51 @@ static int ssl_generate_keying_material(ssl,d) return(_status); } +static int ssl_generate_session_hash(ssl,d) + ssl_obj *ssl; + ssl_decoder *d; + { + int r,_status,dgi; + unsigned int len; + const EVP_MD *md; + EVP_MD_CTX dgictx; + + if(r=r_data_alloc(&d->session_hash,EVP_MAX_MD_SIZE)) + ABORT(r); + + switch(ssl->version){ + case TLSV12_VERSION: + dgi = MAX(DIG_SHA256,ssl->cs->dig)-0x40; + if ((md=EVP_get_digestbyname(digests[dgi])) == NULL) { + DBG((0,"Cannot get EVP for digest %s, openssl library current?", + digests[dgi])); + ERETURN(SSL_BAD_MAC); + } + + EVP_DigestInit(&dgictx,md); + EVP_DigestUpdate(&dgictx,d->handshake_messages->data,d->handshake_messages->len); + EVP_DigestFinal(&dgictx,d->session_hash->data,&d->session_hash->len); + + break; + case SSLV3_VERSION: + case TLSV1_VERSION: + case TLSV11_VERSION: + EVP_DigestInit(&dgictx,EVP_get_digestbyname("MD5")); + EVP_DigestUpdate(&dgictx,d->handshake_messages->data,d->handshake_messages->len); + EVP_DigestFinal_ex(&dgictx,d->session_hash->data,&d->session_hash->len); + + EVP_DigestInit(&dgictx,EVP_get_digestbyname("SHA1")); + EVP_DigestUpdate(&dgictx,d->handshake_messages->data,d->handshake_messages->len); + EVP_DigestFinal(&dgictx,d->session_hash->data+d->session_hash->len,&len); + + d->session_hash->len+=len; + break; + default: + ABORT(SSL_CANT_DO_CIPHER); + } + + _status=0; + abort: + return(_status); + } #endif diff --git a/ssl/ssldecode.h b/ssl/ssldecode.h index e47f836..3ef9226 100644 --- a/ssl/ssldecode.h +++ b/ssl/ssldecode.h @@ -66,7 +66,8 @@ int ssl_process_client_key_exchange PROTO_LIST((struct ssl_obj_ *, ssl_decoder *d,UCHAR *msg,int len)); int ssl_process_change_cipher_spec PROTO_LIST((ssl_obj *ssl, ssl_decoder *d,int direction)); - +int ssl_update_handshake_messages PROTO_LIST((ssl_obj *ssl, + Data *data)); int ssl_decode_record PROTO_LIST((ssl_obj *ssl,ssl_decoder *dec,int direction, int ct,int version,Data *d));