ssldecode.c (ssldump-0.9b3) | : | ssldecode.c (ssldump-1.3) | ||
---|---|---|---|---|
skipping to change at line 52 | skipping to change at line 52 | |||
*/ | */ | |||
#include "network.h" | #include "network.h" | |||
#include "ssl_h.h" | #include "ssl_h.h" | |||
#include "sslprint.h" | #include "sslprint.h" | |||
#include "ssl.enums.h" | #include "ssl.enums.h" | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
#include <openssl/ssl.h> | #include <openssl/ssl.h> | |||
#include <openssl/hmac.h> | #include <openssl/hmac.h> | |||
#include <openssl/evp.h> | #include <openssl/evp.h> | |||
#include <openssl/md5.h> | ||||
#include <openssl/x509v3.h> | #include <openssl/x509v3.h> | |||
#endif | #endif | |||
#include "ssldecode.h" | #include "ssldecode.h" | |||
#include "ssl_rec.h" | #include "ssl_rec.h" | |||
#include "r_assoc.h" | #include "r_assoc.h" | |||
static char *RCSSTRING="$Id: ssldecode.c,v 1.9 2002/08/17 01:33:17 ekr Exp $"; | ||||
#define PRF(ssl,secret,usage,rnd1,rnd2,out) (ssl->version==SSLV3_VERSION)? \ | #define PRF(ssl,secret,usage,rnd1,rnd2,out) (ssl->version==SSLV3_VERSION)? \ | |||
ssl3_prf(ssl,secret,usage,rnd1,rnd2,out): \ | ssl3_prf(ssl,secret,usage,rnd1,rnd2,out): \ | |||
tls_prf(ssl,secret,usage,rnd1,rnd2,out) | ((ssl->version == TLSV12_VERSION) ? \ | |||
tls12_prf(ssl,secret,usage,rnd1,rnd2,out): \ | ||||
tls_prf(ssl,secret,usage,rnd1,rnd2,out)) | ||||
static char *ssl_password; | static char *ssl_password; | |||
extern char *digests[]; | ||||
extern UINT4 SSL_print_flags; | extern UINT4 SSL_print_flags; | |||
struct ssl_decode_ctx_ { | struct ssl_decode_ctx_ { | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
SSL_CTX *ssl_ctx; | SSL_CTX *ssl_ctx; | |||
SSL *ssl; | SSL *ssl; | |||
r_assoc *session_cache; | r_assoc *session_cache; | |||
FILE *ssl_key_log_file; | ||||
#else | #else | |||
char dummy; /* Some compilers (Win32) don't like empty | char dummy; /* Some compilers (Win32) don't like empty | |||
structs */ | structs */ | |||
#endif | #endif | |||
}; | }; | |||
struct ssl_decoder_ { | struct ssl_decoder_ { | |||
ssl_decode_ctx *ctx; | ssl_decode_ctx *ctx; | |||
Data *session_id; | Data *session_id; | |||
SSL_CipherSuite *cs; | SSL_CipherSuite *cs; | |||
Data *client_random; | Data *client_random; | |||
Data *server_random; | Data *server_random; | |||
int ephemeral_rsa; | int ephemeral_rsa; | |||
Data *PMS; | Data *PMS; | |||
Data *MS; | Data *MS; | |||
Data *handshake_messages; | ||||
Data *session_hash; | ||||
ssl_rec_decoder *c_to_s; | ssl_rec_decoder *c_to_s; | |||
ssl_rec_decoder *s_to_c; | ssl_rec_decoder *s_to_c; | |||
ssl_rec_decoder *c_to_s_n; | ssl_rec_decoder *c_to_s_n; | |||
ssl_rec_decoder *s_to_c_n; | ssl_rec_decoder *s_to_c_n; | |||
}; | }; | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
static int tls_P_hash PROTO_LIST((ssl_obj *ssl,Data *secret,Data *seed, | static int tls_P_hash PROTO_LIST((ssl_obj *ssl,Data *secret,Data *seed, | |||
const EVP_MD *md,Data *out)); | const EVP_MD *md,Data *out)); | |||
static int tls12_prf PROTO_LIST((ssl_obj *ssl,Data *secret,char *usage, | ||||
Data *rnd1,Data *rnd2,Data *out)); | ||||
static int tls_prf PROTO_LIST((ssl_obj *ssl,Data *secret,char *usage, | static int tls_prf PROTO_LIST((ssl_obj *ssl,Data *secret,char *usage, | |||
Data *rnd1,Data *rnd2,Data *out)); | Data *rnd1,Data *rnd2,Data *out)); | |||
static int ssl3_prf PROTO_LIST((ssl_obj *ssl,Data *secret,char *usage, | static int ssl3_prf PROTO_LIST((ssl_obj *ssl,Data *secret,char *usage, | |||
Data *rnd1,Data *rnd2,Data *out)); | Data *rnd1,Data *rnd2,Data *out)); | |||
static int ssl3_generate_export_iv PROTO_LIST((ssl_obj *ssl, | static int ssl3_generate_export_iv PROTO_LIST((ssl_obj *ssl, | |||
Data *rnd1,Data *rnd2,Data *out)); | Data *rnd1,Data *rnd2,Data *out)); | |||
static int ssl_generate_keying_material PROTO_LIST((ssl_obj *ssl, | static int ssl_generate_keying_material PROTO_LIST((ssl_obj *ssl, | |||
ssl_decoder *d)); | ssl_decoder *d)); | |||
static int ssl_generate_session_hash PROTO_LIST((ssl_obj *ssl, | ||||
ssl_decoder *d)); | ||||
static int ssl_read_key_log_file PROTO_LIST((ssl_decoder *d)); | ||||
#endif | #endif | |||
static int ssl_create_session_lookup_key PROTO_LIST((ssl_obj *ssl, | static int ssl_create_session_lookup_key PROTO_LIST((ssl_obj *ssl, | |||
UCHAR *id,UINT4 idlen,UCHAR **keyp,UINT4 *keyl)); | UCHAR *id,UINT4 idlen,UCHAR **keyp,UINT4 *keyl)); | |||
int ssl_save_session PROTO_LIST((ssl_obj *ssl,ssl_decoder *d)); | int ssl_save_session PROTO_LIST((ssl_obj *ssl,ssl_decoder *d)); | |||
int ssl_restore_session PROTO_LIST((ssl_obj *ssl,ssl_decoder *d)); | int ssl_restore_session PROTO_LIST((ssl_obj *ssl,ssl_decoder *d)); | |||
/*The password code is not thread safe*/ | /*The password code is not thread safe*/ | |||
static int password_cb(char *buf,int num,int rwflag,void *userdata) | static int password_cb(char *buf,int num,int rwflag,void *userdata) | |||
{ | { | |||
if(num<strlen(ssl_password)+1) | if(num<strlen(ssl_password)+1) | |||
return(0); | return(0); | |||
strcpy(buf,ssl_password); | strcpy(buf,ssl_password); | |||
return(strlen(ssl_password)); | return(strlen(ssl_password)); | |||
} | } | |||
int ssl_decode_ctx_create(dp,keyfile,pass) | int ssl_decode_ctx_create(dp,keyfile,pass,keylogfile) | |||
ssl_decode_ctx **dp; | ssl_decode_ctx **dp; | |||
char *keyfile; | char *keyfile; | |||
char *pass; | char *pass; | |||
char *keylogfile; | ||||
{ | { | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
ssl_decode_ctx *d=0; | ssl_decode_ctx *d=0; | |||
int r,_status; | int _status; | |||
SSLeay_add_all_algorithms(); | SSL_library_init(); | |||
OpenSSL_add_all_algorithms(); | ||||
if(!(d=(ssl_decode_ctx *)malloc(sizeof(ssl_decode_ctx)))) | if(!(d=(ssl_decode_ctx *)malloc(sizeof(ssl_decode_ctx)))) | |||
ABORT(R_NO_MEMORY); | ABORT(R_NO_MEMORY); | |||
if(!(d->ssl_ctx=SSL_CTX_new(SSLv23_server_method()))) | if(!(d->ssl_ctx=SSL_CTX_new(SSLv23_server_method()))) | |||
ABORT(R_NO_MEMORY); | ABORT(R_NO_MEMORY); | |||
if(keyfile){ | if(keyfile){ | |||
if(pass){ | if(pass){ | |||
ssl_password=pass; | ssl_password=pass; | |||
SSL_CTX_set_default_passwd_cb(d->ssl_ctx,password_cb); | SSL_CTX_set_default_passwd_cb(d->ssl_ctx,password_cb); | |||
} | } | |||
#if 0 | #if 0 | |||
skipping to change at line 157 | skipping to change at line 170 | |||
fprintf(stderr,"Problem loading private key\n"); | fprintf(stderr,"Problem loading private key\n"); | |||
ABORT(R_INTERNAL); | ABORT(R_INTERNAL); | |||
} | } | |||
} | } | |||
if(!(d->ssl=SSL_new(d->ssl_ctx))) | if(!(d->ssl=SSL_new(d->ssl_ctx))) | |||
ABORT(R_NO_MEMORY); | ABORT(R_NO_MEMORY); | |||
if(r_assoc_create(&d->session_cache)) | if(r_assoc_create(&d->session_cache)) | |||
ABORT(R_NO_MEMORY); | ABORT(R_NO_MEMORY); | |||
if (keylogfile) { | ||||
if(!(d->ssl_key_log_file=fopen(keylogfile, "r"))){ | ||||
fprintf(stderr,"Failed to open ssl key log file"); | ||||
ABORT(R_INTERNAL); | ||||
} | ||||
} else { | ||||
d->ssl_key_log_file = NULL; | ||||
} | ||||
X509V3_add_standard_extensions(); | X509V3_add_standard_extensions(); | |||
*dp=d; | *dp=d; | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
return(_status); | return(_status); | |||
#else | #else | |||
return(0); | return(0); | |||
#endif | #endif | |||
} | } | |||
int ssl_decode_ctx_destroy(dp) | ||||
ssl_decode_ctx **dp; | ||||
{ | ||||
#ifdef OPENSSL | ||||
ssl_decode_ctx *d = *dp; | ||||
if(d->ssl_key_log_file) { | ||||
fclose(d->ssl_key_log_file); | ||||
} | ||||
r_assoc *x = d->session_cache; | ||||
r_assoc_destroy(&d->session_cache); | ||||
SSL_CTX_free(d->ssl_ctx); | ||||
SSL_free(d->ssl); | ||||
free(d); | ||||
#endif | ||||
return(0); | ||||
} | ||||
int ssl_decoder_create(dp,ctx) | int ssl_decoder_create(dp,ctx) | |||
ssl_decoder **dp; | ssl_decoder **dp; | |||
ssl_decode_ctx *ctx; | ssl_decode_ctx *ctx; | |||
{ | { | |||
int _status; | int _status; | |||
ssl_decoder *d=0; | ssl_decoder *d=0; | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
if(!(d=(ssl_decoder *)calloc(sizeof(ssl_decoder),1))) | if(!(d=(ssl_decoder *)calloc(1,sizeof(ssl_decoder)))) | |||
ABORT(R_NO_MEMORY); | ABORT(R_NO_MEMORY); | |||
d->ctx=ctx; | d->ctx=ctx; | |||
*dp=d; | *dp=d; | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
if(_status) | if(_status) | |||
ssl_decoder_destroy(&d); | ssl_decoder_destroy(&d); | |||
return(_status); | return(_status); | |||
#else | #else | |||
skipping to change at line 206 | skipping to change at line 247 | |||
ssl_decoder *d; | ssl_decoder *d; | |||
if(!dp || !*dp) | if(!dp || !*dp) | |||
return(0); | return(0); | |||
d=*dp; | d=*dp; | |||
r_data_destroy(&d->client_random); | r_data_destroy(&d->client_random); | |||
r_data_destroy(&d->server_random); | r_data_destroy(&d->server_random); | |||
r_data_destroy(&d->session_id); | r_data_destroy(&d->session_id); | |||
r_data_destroy(&d->PMS); | r_data_destroy(&d->PMS); | |||
r_data_destroy(&d->MS); | 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); | |||
ssl_destroy_rec_decoder(&d->c_to_s_n); | ssl_destroy_rec_decoder(&d->c_to_s_n); | |||
ssl_destroy_rec_decoder(&d->s_to_c); | ssl_destroy_rec_decoder(&d->s_to_c); | |||
ssl_destroy_rec_decoder(&d->s_to_c_n); | ssl_destroy_rec_decoder(&d->s_to_c_n); | |||
free(d); | free(d); | |||
*dp=0; | *dp=0; | |||
#endif | #endif | |||
return(0); | return(0); | |||
} | } | |||
int ssl_set_client_random(d,msg,len) | int ssl_set_client_random(d,msg,len) | |||
ssl_decoder *d; | ssl_decoder *d; | |||
UCHAR *msg; | UCHAR *msg; | |||
int len; | int len; | |||
{ | { | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
int r; | int r; | |||
if(r=r_data_create(&d->client_random,msg,len)) | r_data_destroy(&d->client_random); | |||
if((r=r_data_create(&d->client_random,msg,len))) | ||||
ERETURN(r); | ERETURN(r); | |||
#endif | #endif | |||
return(0); | return(0); | |||
} | } | |||
int ssl_set_server_random(d,msg,len) | int ssl_set_server_random(d,msg,len) | |||
ssl_decoder *d; | ssl_decoder *d; | |||
UCHAR *msg; | UCHAR *msg; | |||
int len; | int len; | |||
{ | { | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
int r; | int r; | |||
if(r=r_data_create(&d->server_random,msg,len)) | r_data_destroy(&d->server_random); | |||
if((r=r_data_create(&d->server_random,msg,len))) | ||||
ERETURN(r); | ERETURN(r); | |||
#endif | #endif | |||
return(0); | return(0); | |||
} | } | |||
int ssl_set_client_session_id(d,msg,len) | int ssl_set_client_session_id(d,msg,len) | |||
ssl_decoder *d; | ssl_decoder *d; | |||
UCHAR *msg; | UCHAR *msg; | |||
int len; | int len; | |||
{ | { | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
int r; | int r; | |||
if(r=r_data_create(&d->session_id,msg,len)) | if(len>0) { | |||
ERETURN(r); | r_data_destroy(&d->session_id); | |||
if((r=r_data_create(&d->session_id,msg,len))) | ||||
ERETURN(r); | ||||
} | ||||
#endif | #endif | |||
return(0); | return(0); | |||
} | } | |||
int ssl_process_server_session_id(ssl,d,msg,len) | int ssl_process_server_session_id(ssl,d,msg,len) | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
ssl_decoder *d; | ssl_decoder *d; | |||
UCHAR *msg; | UCHAR *msg; | |||
int len; | int len; | |||
{ | { | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
int r,_status; | int r,_status; | |||
Data idd; | Data idd; | |||
int restored=0; | int restored=0; | |||
INIT_DATA(idd,msg,len); | INIT_DATA(idd,msg,len); | |||
/* First check to see if the client tried to restore */ | /* First check to see if the client tried to restore */ | |||
if(d->session_id){ | if(d->session_id){ | |||
/* Now check to see if we restored */ | /* Now check to see if we restored */ | |||
if(r_data_compare(&idd,d->session_id)) | if((r=r_data_compare(&idd,d->session_id))) | |||
goto abort; | ABORT(r); | |||
/* Now try to look up the session. We may not be able | /* Now try to look up the session. We may not be able | |||
to find it if, for instance, the original session | to find it if, for instance, the original session | |||
was initiated with something other than static RSA */ | was initiated with something other than static RSA */ | |||
if(r=ssl_restore_session(ssl,d)) | if((r=ssl_restore_session(ssl,d))) | |||
ABORT(r); | ABORT(r); | |||
restored=1; | restored=1; | |||
} | } | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
if(!restored){ | if(!restored){ | |||
/* Copy over the session ID */ | /* Copy over the session ID */ | |||
r_data_zfree(d->session_id); | r_data_destroy(&d->session_id); | |||
r_data_create(&d->session_id,msg,len); | r_data_create(&d->session_id,msg,len); | |||
} | } | |||
return(_status); | return(_status); | |||
#else | #else | |||
return(0); | return(0); | |||
#endif | #endif | |||
} | } | |||
int ssl_process_client_session_id(ssl,d,msg,len) | ||||
ssl_obj *ssl; | ||||
ssl_decoder *d; | ||||
UCHAR *msg; | ||||
int len; | ||||
{ | ||||
#ifdef OPENSSL | ||||
int _status; | ||||
/* First check if the client set session id */ | ||||
//todo: check that session_id in decoder and msg are the same (and if not th | ||||
en take from msg?) | ||||
if(d->session_id) | ||||
{ | ||||
/* Remove the master secret */ | ||||
//todo: better save and destroy only when successfully read key log | ||||
r_data_destroy(&d->MS); | ||||
if(d->ctx->ssl_key_log_file && (ssl_read_key_log_file(d)==0) && d->MS) | ||||
{ | ||||
//we found master secret for session in keylog | ||||
//try to save session | ||||
_status = ssl_save_session(ssl,d); | ||||
} | ||||
else | ||||
{ | ||||
//just return error | ||||
_status = -1; | ||||
} | ||||
} | ||||
else | ||||
{ | ||||
_status = -1; | ||||
} | ||||
return(_status); | ||||
#else | ||||
return(0); | ||||
#endif | ||||
} | ||||
int ssl_process_change_cipher_spec(ssl,d,direction) | int ssl_process_change_cipher_spec(ssl,d,direction) | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
ssl_decoder *d; | ssl_decoder *d; | |||
int direction; | int direction; | |||
{ | { | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
if(direction==DIR_I2R){ | if(direction==DIR_I2R){ | |||
d->c_to_s=d->c_to_s_n; | d->c_to_s=d->c_to_s_n; | |||
d->c_to_s_n=0; | d->c_to_s_n=0; | |||
if(d->c_to_s) ssl->process_ciphertext |= direction; | if(d->c_to_s) ssl->process_ciphertext |= direction; | |||
skipping to change at line 355 | skipping to change at line 442 | |||
ssl->record_encryption=REC_PLAINTEXT; | ssl->record_encryption=REC_PLAINTEXT; | |||
return(0); | return(0); | |||
} | } | |||
} | } | |||
ssl->record_encryption=REC_CIPHERTEXT; | ssl->record_encryption=REC_CIPHERTEXT; | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
if(!(out=(UCHAR *)malloc(d->len))) | if(!(out=(UCHAR *)malloc(d->len))) | |||
ABORT(R_NO_MEMORY); | ABORT(R_NO_MEMORY); | |||
if(r=ssl_decode_rec_data(ssl,rd,ct,version,d->data,d->len,out,&outl)){ | if((r=ssl_decode_rec_data(ssl,rd,ct,version,d->data,d->len,out,&outl))){ | |||
ABORT(r); | ABORT(r); | |||
} | } | |||
memcpy(d->data,out,outl); | memcpy(d->data,out,outl); | |||
d->len=outl; | d->len=outl; | |||
ssl->record_encryption=REC_DECRYPTED_CIPHERTEXT; | ssl->record_encryption=REC_DECRYPTED_CIPHERTEXT; | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
FREE(out); | FREE(out); | |||
return(_status); | return(_status); | |||
#else | #else | |||
return(0); | return(0); | |||
#endif | #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) | static int ssl_create_session_lookup_key(ssl,id,idlen,keyp,keyl) | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
UCHAR *id; | UCHAR *id; | |||
UINT4 idlen; | UINT4 idlen; | |||
UCHAR **keyp; | UCHAR **keyp; | |||
UINT4 *keyl; | UINT4 *keyl; | |||
{ | { | |||
UCHAR *key=0; | UCHAR *key=0; | |||
UINT4 l; | UINT4 l; | |||
int r,_status; | int _status; | |||
l=idlen+strlen(ssl->server_name)+idlen+15; /* HOST + PORT + id */ | l=idlen+strlen(ssl->server_name)+idlen+15; /* HOST + PORT + id */ | |||
if(!(key=(UCHAR *)malloc(l))) | if(!(key=(UCHAR *)malloc(l))) | |||
ABORT(R_NO_MEMORY); | ABORT(R_NO_MEMORY); | |||
*keyp=key; | *keyp=key; | |||
memcpy(key,id,idlen); | memcpy(key,id,idlen); | |||
*keyl=idlen; | *keyl=idlen; | |||
key+=idlen; | key+=idlen; | |||
sprintf(key,"%s:%d",ssl->server_name,ssl->server_port); | snprintf((char *)key,l,"%s:%d",ssl->server_name,ssl->server_port); | |||
*keyl+=strlen(key); | *keyl+=strlen((char *)key); | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
return(_status); | return(_status); | |||
} | } | |||
/* Look up the session id in the session cache and generate | /* Look up the session id in the session cache and generate | |||
the appropriate keying material */ | the appropriate keying material */ | |||
int ssl_restore_session(ssl,d) | int ssl_restore_session(ssl,d) | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
ssl_decoder *d; | ssl_decoder *d; | |||
{ | { | |||
UCHAR *lookup_key=0; | UCHAR *lookup_key=0; | |||
void *msv; | void *msv; | |||
Data *msd; | Data *msd; | |||
int lookup_key_len; | int lookup_key_len; | |||
int r,_status; | int r,_status; | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
if(r=ssl_create_session_lookup_key(ssl, | if((r=ssl_create_session_lookup_key(ssl, | |||
d->session_id->data,d->session_id->len,&lookup_key, | d->session_id->data,d->session_id->len,&lookup_key, | |||
&lookup_key_len)) | (UINT4 *) &lookup_key_len))) | |||
ABORT(r); | ABORT(r); | |||
if(r=r_assoc_fetch(d->ctx->session_cache,lookup_key,lookup_key_len, | if((r=r_assoc_fetch(d->ctx->session_cache,(char *) lookup_key,lookup_key_len | |||
&msv)) | , | |||
&msv))) | ||||
ABORT(r); | ABORT(r); | |||
msd=(Data *)msv; | msd=(Data *)msv; | |||
if(r=r_data_create(&d->MS,msd->data,msd->len)) | if((r=r_data_create(&d->MS,msd->data,msd->len))) | |||
ABORT(r); | ABORT(r); | |||
CRDUMPD("Restored MS",d->MS); | CRDUMPD("Restored MS",d->MS); | |||
switch(ssl->version){ | switch(ssl->version){ | |||
case SSLV3_VERSION: | case SSLV3_VERSION: | |||
if(r=ssl_generate_keying_material(ssl,d)) | ||||
ABORT(r); | ||||
break; | ||||
case TLSV1_VERSION: | case TLSV1_VERSION: | |||
if(r=ssl_generate_keying_material(ssl,d)) | case TLSV11_VERSION: | |||
case TLSV12_VERSION: | ||||
if((r=ssl_generate_keying_material(ssl,d))) | ||||
ABORT(r); | ABORT(r); | |||
break; | break; | |||
default: | default: | |||
ABORT(SSL_CANT_DO_CIPHER); | ABORT(SSL_CANT_DO_CIPHER); | |||
} | } | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
FREE(lookup_key); | FREE(lookup_key); | |||
return(_status); | return(_status); | |||
skipping to change at line 456 | skipping to change at line 572 | |||
} | } | |||
/* Look up the session id in the session cache and generate | /* Look up the session id in the session cache and generate | |||
the appropriate keying material */ | the appropriate keying material */ | |||
int ssl_save_session(ssl,d) | int ssl_save_session(ssl,d) | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
ssl_decoder *d; | ssl_decoder *d; | |||
{ | { | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
UCHAR *lookup_key=0; | UCHAR *lookup_key=0; | |||
void *msv; | ||||
Data *msd=0; | Data *msd=0; | |||
int lookup_key_len; | int lookup_key_len; | |||
int r,_status; | int r,_status; | |||
if(r=ssl_create_session_lookup_key(ssl,d->session_id->data, | if((r=ssl_create_session_lookup_key(ssl,d->session_id->data, | |||
d->session_id->len,&lookup_key, | d->session_id->len,&lookup_key, | |||
&lookup_key_len)) | (UINT4 *) &lookup_key_len))) | |||
ABORT(r); | ABORT(r); | |||
if(r=r_data_create(&msd,d->MS->data,d->MS->len)) | if((r=r_data_create(&msd,d->MS->data,d->MS->len))) | |||
ABORT(r); | ABORT(r); | |||
if(r=r_assoc_insert(d->ctx->session_cache,lookup_key,lookup_key_len, | if((r=r_assoc_insert(d->ctx->session_cache,(char *)lookup_key,lookup_key_len , | |||
(void *)msd,0,(int (*)(void *))r_data_zfree, | (void *)msd,0,(int (*)(void *))r_data_zfree, | |||
R_ASSOC_NEW | R_ASSOC_REPLACE)) | R_ASSOC_NEW | R_ASSOC_REPLACE))) | |||
ABORT(r); | ABORT(r); | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
if(_status){ | if(_status){ | |||
r_data_zfree(msd); | r_data_zfree(msd); | |||
} | } | |||
FREE(lookup_key); | FREE(lookup_key); | |||
return(_status); | return(_status); | |||
#else | #else | |||
skipping to change at line 495 | skipping to change at line 610 | |||
offer PFS. Yuck. */ | offer PFS. Yuck. */ | |||
int ssl_process_client_key_exchange(ssl,d,msg,len) | int ssl_process_client_key_exchange(ssl,d,msg,len) | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
ssl_decoder *d; | ssl_decoder *d; | |||
UCHAR *msg; | UCHAR *msg; | |||
int len; | int len; | |||
{ | { | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
int r,_status; | int r,_status; | |||
int i; | int i; | |||
EVP_PKEY *pk; | EVP_PKEY *pk; | |||
const BIGNUM *n; | ||||
if(ssl->cs->kex!=KEX_RSA) | /* Remove the master secret if it was there | |||
return(-1); | to force keying material regeneration in | |||
case we're renegotiating */ | ||||
r_data_destroy(&d->MS); | ||||
if(d->ephemeral_rsa) | if(!d->ctx->ssl_key_log_file || | |||
return(-1); | ssl_read_key_log_file(d) || | |||
!d->MS){ | ||||
if(ssl->cs->kex!=KEX_RSA) | ||||
return(-1); | ||||
pk=SSL_get_privatekey(d->ctx->ssl); | if(d->ephemeral_rsa) | |||
if(!pk) | return(-1); | |||
return(-1); | ||||
if(pk->type!=EVP_PKEY_RSA) | pk=SSL_get_privatekey(d->ctx->ssl); | |||
return(-1); | if(!pk) | |||
return(-1); | ||||
if(r=r_data_alloc(&d->PMS,BN_num_bytes(pk->pkey.rsa->n))) | if(EVP_PKEY_id(pk)!=EVP_PKEY_RSA) | |||
ABORT(r); | return(-1); | |||
i=RSA_private_decrypt(len,msg,d->PMS->data, | RSA_get0_key(EVP_PKEY_get0_RSA(pk), &n, NULL, NULL); | |||
pk->pkey.rsa,RSA_PKCS1_PADDING); | if((r=r_data_alloc(&d->PMS,BN_num_bytes(n)))) | |||
ABORT(r); | ||||
if(i!=48) | i=RSA_private_decrypt(len,msg,d->PMS->data, | |||
ABORT(SSL_BAD_PMS); | EVP_PKEY_get0_RSA(pk),RSA_PKCS1_PADDING); | |||
d->PMS->len=48; | if(i!=48) | |||
ABORT(SSL_BAD_PMS); | ||||
CRDUMPD("PMS",d->PMS); | d->PMS->len=48; | |||
/* Remove the master secret if it was there | CRDUMPD("PMS",d->PMS); | |||
to force keying material regeneration in | } | |||
case we're renegotiating */ | ||||
r_data_destroy(&d->MS); | ||||
switch(ssl->version){ | switch(ssl->version){ | |||
case SSLV3_VERSION: | case SSLV3_VERSION: | |||
if(r=ssl_generate_keying_material(ssl,d)) | ||||
ABORT(r); | ||||
break; | ||||
case TLSV1_VERSION: | case TLSV1_VERSION: | |||
if(r=ssl_generate_keying_material(ssl,d)) | case TLSV11_VERSION: | |||
case TLSV12_VERSION: | ||||
if((r=ssl_generate_keying_material(ssl,d))) | ||||
ABORT(r); | ABORT(r); | |||
break; | break; | |||
default: | default: | |||
ABORT(SSL_CANT_DO_CIPHER); | ABORT(SSL_CANT_DO_CIPHER); | |||
} | } | |||
/* Now store the data in the session cache */ | /* Now store the data in the session cache */ | |||
if(r=ssl_save_session(ssl,d)) | if((r=ssl_save_session(ssl,d))) | |||
ABORT(r); | ABORT(r); | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
return(_status); | return(_status); | |||
#else | #else | |||
return 0; | return 0; | |||
#endif | #endif | |||
} | } | |||
skipping to change at line 567 | skipping to change at line 686 | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
Data *secret; | Data *secret; | |||
Data *seed; | Data *seed; | |||
const EVP_MD *md; | const EVP_MD *md; | |||
Data *out; | Data *out; | |||
{ | { | |||
UCHAR *ptr=out->data; | UCHAR *ptr=out->data; | |||
int left=out->len; | int left=out->len; | |||
int tocpy; | int tocpy; | |||
UCHAR *A; | UCHAR *A; | |||
UCHAR _A[20],tmp[20]; | UCHAR _A[128],tmp[128]; | |||
unsigned int A_l,tmp_l; | unsigned int A_l,tmp_l; | |||
HMAC_CTX hm; | HMAC_CTX *hm = HMAC_CTX_new(); | |||
CRDUMPD("P_hash secret",secret); | CRDUMPD("P_hash secret",secret); | |||
CRDUMPD("P_hash seed",seed); | CRDUMPD("P_hash seed",seed); | |||
A=seed->data; | A=seed->data; | |||
A_l=seed->len; | A_l=seed->len; | |||
while(left){ | while(left){ | |||
HMAC_Init(&hm,secret->data,secret->len,md); | HMAC_Init_ex(hm,secret->data,secret->len,md,NULL); | |||
HMAC_Update(&hm,A,A_l); | HMAC_Update(hm,A,A_l); | |||
HMAC_Final(&hm,_A,&A_l); | HMAC_Final(hm,_A,&A_l); | |||
A=_A; | A=_A; | |||
HMAC_Init(&hm,secret->data,secret->len,md); | HMAC_Init_ex(hm,secret->data,secret->len,md,NULL); | |||
HMAC_Update(&hm,A,A_l); | HMAC_Update(hm,A,A_l); | |||
HMAC_Update(&hm,seed->data,seed->len); | HMAC_Update(hm,seed->data,seed->len); | |||
HMAC_Final(&hm,tmp,&tmp_l); | HMAC_Final(hm,tmp,&tmp_l); | |||
tocpy=MIN(left,tmp_l); | tocpy=MIN(left,tmp_l); | |||
memcpy(ptr,tmp,tocpy); | memcpy(ptr,tmp,tocpy); | |||
ptr+=tocpy; | ptr+=tocpy; | |||
left-=tocpy; | left-=tocpy; | |||
} | } | |||
HMAC_cleanup(&hm); | HMAC_CTX_free(hm); | |||
CRDUMPD("P_hash out",out); | CRDUMPD("P_hash out",out); | |||
return (0); | return (0); | |||
} | } | |||
static int tls_prf(ssl,secret,usage,rnd1,rnd2,out) | static int tls_prf(ssl,secret,usage,rnd1,rnd2,out) | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
Data *secret; | Data *secret; | |||
char *usage; | char *usage; | |||
Data *rnd1; | Data *rnd1; | |||
Data *rnd2; | Data *rnd2; | |||
Data *out; | Data *out; | |||
{ | { | |||
int r,_status; | int r,_status; | |||
Data *md5_out=0,*sha_out=0; | Data *md5_out=0,*sha_out=0; | |||
Data *seed; | Data *seed; | |||
UCHAR *ptr; | UCHAR *ptr; | |||
Data *S1=0,*S2=0; | Data *S1=0,*S2=0; | |||
int i,S_l; | int i,S_l; | |||
if(r=r_data_alloc(&md5_out,MAX(out->len,16))) | if((r=r_data_alloc(&md5_out,MAX(out->len,16)))) | |||
ABORT(r); | ABORT(r); | |||
if(r=r_data_alloc(&sha_out,MAX(out->len,20))) | if((r=r_data_alloc(&sha_out,MAX(out->len,20)))) | |||
ABORT(r); | ABORT(r); | |||
if(r=r_data_alloc(&seed,strlen(usage)+rnd1->len+rnd2->len)) | if((r=r_data_alloc(&seed,strlen(usage)+rnd1->len+rnd2->len))) | |||
ABORT(r); | ABORT(r); | |||
ptr=seed->data; | ptr=seed->data; | |||
memcpy(ptr,usage,strlen(usage)); ptr+=strlen(usage); | memcpy(ptr,usage,strlen(usage)); ptr+=strlen(usage); | |||
memcpy(ptr,rnd1->data,rnd1->len); ptr+=rnd1->len; | memcpy(ptr,rnd1->data,rnd1->len); ptr+=rnd1->len; | |||
memcpy(ptr,rnd2->data,rnd2->len); ptr+=rnd2->len; | memcpy(ptr,rnd2->data,rnd2->len); ptr+=rnd2->len; | |||
S_l=secret->len/2 + secret->len%2; | S_l=secret->len/2 + secret->len%2; | |||
if(r=r_data_alloc(&S1,S_l)) | if((r=r_data_alloc(&S1,S_l))) | |||
ABORT(r); | ABORT(r); | |||
if(r=r_data_alloc(&S2,S_l)) | if((r=r_data_alloc(&S2,S_l))) | |||
ABORT(r); | ABORT(r); | |||
memcpy(S1->data,secret->data,S_l); | memcpy(S1->data,secret->data,S_l); | |||
memcpy(S2->data,secret->data + (secret->len - S_l),S_l); | memcpy(S2->data,secret->data + (secret->len - S_l),S_l); | |||
if(r=tls_P_hash | if((r=tls_P_hash | |||
(ssl,S1,seed,EVP_get_digestbyname("MD5"),md5_out)) | (ssl,S1,seed,EVP_get_digestbyname("MD5"),md5_out))) | |||
ABORT(r); | ABORT(r); | |||
if(r=tls_P_hash(ssl,S2,seed,EVP_get_digestbyname("SHA1"),sha_out)) | if((r=tls_P_hash(ssl,S2,seed,EVP_get_digestbyname("SHA1"),sha_out))) | |||
ABORT(r); | ABORT(r); | |||
for(i=0;i<out->len;i++) | for(i=0;i<out->len;i++) | |||
out->data[i]=md5_out->data[i] ^ sha_out->data[i]; | out->data[i]=md5_out->data[i] ^ sha_out->data[i]; | |||
CRDUMPD("PRF out",out); | CRDUMPD("PRF out",out); | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
r_data_destroy(&md5_out); | r_data_destroy(&md5_out); | |||
r_data_destroy(&sha_out); | r_data_destroy(&sha_out); | |||
r_data_destroy(&seed); | r_data_destroy(&seed); | |||
r_data_destroy(&S1); | r_data_destroy(&S1); | |||
r_data_destroy(&S2); | r_data_destroy(&S2); | |||
return(_status); | return(_status); | |||
} | } | |||
static int tls12_prf(ssl,secret,usage,rnd1,rnd2,out) | ||||
ssl_obj *ssl; | ||||
Data *secret; | ||||
char *usage; | ||||
Data *rnd1; | ||||
Data *rnd2; | ||||
Data *out; | ||||
{ | ||||
const EVP_MD *md; | ||||
int r,_status; | ||||
Data *sha_out=0; | ||||
Data *seed; | ||||
UCHAR *ptr; | ||||
int i, dgi; | ||||
if((r=r_data_alloc(&sha_out,MAX(out->len,64)))) /* assume max SHA512 */ | ||||
ABORT(r); | ||||
if((r=r_data_alloc(&seed,strlen(usage)+rnd1->len+rnd2->len))) | ||||
ABORT(r); | ||||
ptr=seed->data; | ||||
memcpy(ptr,usage,strlen(usage)); ptr+=strlen(usage); | ||||
memcpy(ptr,rnd1->data,rnd1->len); ptr+=rnd1->len; | ||||
memcpy(ptr,rnd2->data,rnd2->len); ptr+=rnd2->len; | ||||
/* Earlier versions of openssl didn't have SHA256 of course... */ | ||||
dgi = MAX(DIG_SHA256, ssl->cs->dig); | ||||
dgi-=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); | ||||
} | ||||
if((r=tls_P_hash(ssl,secret,seed,md,sha_out))) | ||||
ABORT(r); | ||||
for(i=0;i<out->len;i++) | ||||
out->data[i]=sha_out->data[i]; | ||||
CRDUMPD("PRF out",out); | ||||
_status=0; | ||||
abort: | ||||
r_data_destroy(&sha_out); | ||||
r_data_destroy(&seed); | ||||
return(_status); | ||||
} | ||||
static int ssl3_generate_export_iv(ssl,r1,r2,out) | static int ssl3_generate_export_iv(ssl,r1,r2,out) | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
Data *r1; | Data *r1; | |||
Data *r2; | Data *r2; | |||
Data *out; | Data *out; | |||
{ | { | |||
MD5_CTX md5; | MD5_CTX md5; | |||
UCHAR tmp[16]; | UCHAR tmp[16]; | |||
MD5_Init(&md5); | MD5_Init(&md5); | |||
skipping to change at line 737 | skipping to change at line 903 | |||
CRDUMPD("rnd2",rnd2); | CRDUMPD("rnd2",rnd2); | |||
} | } | |||
SHA1_Final(buf,&sha); | SHA1_Final(buf,&sha); | |||
CRDUMP("SHA out",buf,20); | CRDUMP("SHA out",buf,20); | |||
SHA1_Init(&sha); | SHA1_Init(&sha); | |||
MD5_Update(&md5,secret->data,secret->len); | MD5_Update(&md5,secret->data,secret->len); | |||
MD5_Update(&md5,buf,20); | MD5_Update(&md5,buf,20); | |||
MD5_Final(outbuf,&md5); | MD5_Final((unsigned char *)outbuf,&md5); | |||
tocpy=MIN(out->len-off,16); | tocpy=MIN(out->len-off,16); | |||
memcpy(out->data+off,outbuf,tocpy); | memcpy(out->data+off,outbuf,tocpy); | |||
CRDUMP("MD5 out",outbuf,16); | CRDUMP("MD5 out",(UCHAR *)outbuf,16); | |||
MD5_Init(&md5); | MD5_Init(&md5); | |||
} | } | |||
return(0); | return(0); | |||
} | } | |||
static int ssl_generate_keying_material(ssl,d) | static int ssl_generate_keying_material(ssl,d) | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
ssl_decoder *d; | ssl_decoder *d; | |||
{ | { | |||
Data *key_block=0; | Data *key_block=0,temp; | |||
UCHAR _iv_c[8],_iv_s[8]; | UCHAR _iv_c[8],_iv_s[8]; | |||
UCHAR _key_c[16],_key_s[16]; | UCHAR _key_c[16],_key_s[16]; | |||
int needed; | int needed; | |||
int r,_status; | int r,_status; | |||
UCHAR *ptr,*c_wk,*s_wk,*c_mk,*s_mk,*c_iv,*s_iv; | UCHAR *ptr,*c_wk,*s_wk,*c_mk=NULL,*s_mk=NULL,*c_iv=NULL,*s_iv=NULL; | |||
if(!d->MS){ | if(!d->MS){ | |||
if(r=r_data_alloc(&d->MS,48)) | if((r=r_data_alloc(&d->MS,48))) | |||
ABORT(r); | ABORT(r); | |||
if(r=PRF(ssl,d->PMS,"master secret",d->client_random,d->server_random, | if (ssl->extensions->extended_master_secret==2) { | |||
d->MS)) | if((r=ssl_generate_session_hash(ssl,d))) | |||
ABORT(r); | 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); | CRDUMPD("MS",d->MS); | |||
} | } | |||
/* Compute the key block. First figure out how much data | /* Compute the key block. First figure out how much data | |||
we need*/ | we need*/ | |||
needed=ssl->cs->dig_len*2; | /* Ideally find a cleaner way to check for AEAD cipher */ | |||
needed=!IS_AEAD_CIPHER(ssl->cs)?ssl->cs->dig_len*2:0; | ||||
needed+=ssl->cs->bits / 4; | needed+=ssl->cs->bits / 4; | |||
if(ssl->cs->block>1) needed+=ssl->cs->block*2; | if(ssl->cs->block>1) needed+=ssl->cs->block*2; | |||
if(r=r_data_alloc(&key_block,needed)) | if((r=r_data_alloc(&key_block,needed))) | |||
ABORT(r); | ABORT(r); | |||
if(r=PRF(ssl,d->MS,"key expansion",d->server_random,d->client_random, | if((r=PRF(ssl,d->MS,"key expansion",d->server_random,d->client_random, | |||
key_block)) | key_block))) | |||
ABORT(r); | ABORT(r); | |||
ptr=key_block->data; | ptr=key_block->data; | |||
c_mk=ptr; ptr+=ssl->cs->dig_len; | /* Ideally find a cleaner way to check for AEAD cipher */ | |||
s_mk=ptr; ptr+=ssl->cs->dig_len; | if(!IS_AEAD_CIPHER(ssl->cs)){ | |||
c_mk=ptr; ptr+=ssl->cs->dig_len; | ||||
s_mk=ptr; ptr+=ssl->cs->dig_len; | ||||
} | ||||
c_wk=ptr; ptr+=ssl->cs->eff_bits/8; | c_wk=ptr; ptr+=ssl->cs->eff_bits/8; | |||
s_wk=ptr; ptr+=ssl->cs->eff_bits/8; | s_wk=ptr; ptr+=ssl->cs->eff_bits/8; | |||
if(ssl->cs->block>1){ | if(ssl->cs->block>1){ | |||
c_iv=ptr; ptr+=ssl->cs->block; | c_iv=ptr; ptr+=ssl->cs->block; | |||
s_iv=ptr; ptr+=ssl->cs->block; | s_iv=ptr; ptr+=ssl->cs->block; | |||
} | } | |||
if(ssl->cs->export){ | if(ssl->cs->export){ | |||
Data iv_c,iv_s; | Data iv_c,iv_s; | |||
Data c_iv_d,s_iv_d; | ||||
Data key_c,key_s; | Data key_c,key_s; | |||
Data k; | Data k; | |||
if(ssl->cs->block>1){ | if(ssl->cs->block>1){ | |||
ATTACH_DATA(iv_c,_iv_c); | ATTACH_DATA(iv_c,_iv_c); | |||
ATTACH_DATA(iv_s,_iv_s); | ATTACH_DATA(iv_s,_iv_s); | |||
if(ssl->version==SSLV3_VERSION){ | if(ssl->version==SSLV3_VERSION){ | |||
if(r=ssl3_generate_export_iv(ssl,d->client_random, | if((r=ssl3_generate_export_iv(ssl,d->client_random, | |||
d->server_random,&iv_c)) | d->server_random,&iv_c))) | |||
ABORT(r); | ABORT(r); | |||
if(r=ssl3_generate_export_iv(ssl,d->server_random, | if((r=ssl3_generate_export_iv(ssl,d->server_random, | |||
d->client_random,&iv_s)) | d->client_random,&iv_s))) | |||
ABORT(r); | ABORT(r); | |||
} | } | |||
else{ | else{ | |||
UCHAR _iv_block[16]; | UCHAR _iv_block[16]; | |||
Data iv_block; | Data iv_block; | |||
Data key_null; | Data key_null; | |||
UCHAR _key_null; | UCHAR _key_null; | |||
INIT_DATA(key_null,&_key_null,0); | INIT_DATA(key_null,&_key_null,0); | |||
/* We only have room for 8 bit IVs, but that's | /* We only have room for 8 bit IVs, but that's | |||
all we should need. This is a sanity check */ | all we should need. This is a sanity check */ | |||
if(ssl->cs->block>8) | if(ssl->cs->block>8) | |||
ABORT(R_INTERNAL); | ABORT(R_INTERNAL); | |||
ATTACH_DATA(iv_block,_iv_block); | ATTACH_DATA(iv_block,_iv_block); | |||
if(r=PRF(ssl,&key_null,"IV block",d->client_random, | if((r=PRF(ssl,&key_null,"IV block",d->client_random, | |||
d->server_random,&iv_block)) | d->server_random,&iv_block))) | |||
ABORT(r); | ABORT(r); | |||
memcpy(_iv_c,iv_block.data,8); | memcpy(_iv_c,iv_block.data,8); | |||
memcpy(_iv_s,iv_block.data+8,8); | memcpy(_iv_s,iv_block.data+8,8); | |||
} | } | |||
c_iv=_iv_c; | c_iv=_iv_c; | |||
s_iv=_iv_s; | s_iv=_iv_s; | |||
} | } | |||
skipping to change at line 860 | skipping to change at line 1039 | |||
MD5_Update(&md5,s_wk,ssl->cs->eff_bits/8); | MD5_Update(&md5,s_wk,ssl->cs->eff_bits/8); | |||
MD5_Update(&md5,d->server_random->data,d->server_random->len); | MD5_Update(&md5,d->server_random->data,d->server_random->len); | |||
MD5_Update(&md5,d->client_random->data,d->client_random->len); | MD5_Update(&md5,d->client_random->data,d->client_random->len); | |||
MD5_Final(_key_s,&md5); | MD5_Final(_key_s,&md5); | |||
s_wk=_key_s; | s_wk=_key_s; | |||
} | } | |||
else{ | else{ | |||
ATTACH_DATA(key_c,_key_c); | ATTACH_DATA(key_c,_key_c); | |||
ATTACH_DATA(key_s,_key_s); | ATTACH_DATA(key_s,_key_s); | |||
INIT_DATA(k,c_wk,ssl->cs->eff_bits/8); | INIT_DATA(k,c_wk,ssl->cs->eff_bits/8); | |||
if(r=PRF(ssl,&k,"client write key",d->client_random,d->server_random, | if((r=PRF(ssl,&k,"client write key",d->client_random,d->server_random, | |||
&key_c)) | &key_c))) | |||
ABORT(r); | ABORT(r); | |||
c_wk=_key_c; | c_wk=_key_c; | |||
INIT_DATA(k,s_wk,ssl->cs->eff_bits/8); | INIT_DATA(k,s_wk,ssl->cs->eff_bits/8); | |||
if(r=PRF(ssl,&k,"server write key",d->client_random,d->server_random, | if((r=PRF(ssl,&k,"server write key",d->client_random,d->server_random, | |||
&key_s)) | &key_s))) | |||
ABORT(r); | ABORT(r); | |||
s_wk=_key_s; | s_wk=_key_s; | |||
} | } | |||
} | } | |||
CRDUMP("Client MAC key",c_mk,ssl->cs->dig_len); | CRDUMP("Client MAC key",c_mk,ssl->cs->dig_len); | |||
CRDUMP("Server MAC key",s_mk,ssl->cs->dig_len); | CRDUMP("Server MAC key",s_mk,ssl->cs->dig_len); | |||
CRDUMP("Client Write key",c_wk,ssl->cs->bits/8); | CRDUMP("Client Write key",c_wk,ssl->cs->bits/8); | |||
CRDUMP("Server Write key",s_wk,ssl->cs->bits/8); | CRDUMP("Server Write key",s_wk,ssl->cs->bits/8); | |||
if(ssl->cs->block>1){ | if(ssl->cs->block>1){ | |||
CRDUMP("Client Write IV",c_iv,ssl->cs->block); | CRDUMP("Client Write IV",c_iv,ssl->cs->block); | |||
CRDUMP("Server Write IV",s_iv,ssl->cs->block); | CRDUMP("Server Write IV",s_iv,ssl->cs->block); | |||
} | } | |||
if(r=ssl_create_rec_decoder(&d->c_to_s_n, | if((r=ssl_create_rec_decoder(&d->c_to_s_n, | |||
ssl->cs,c_mk,c_wk,c_iv)) | ssl->cs,c_mk,c_wk,c_iv))) | |||
ABORT(r); | ABORT(r); | |||
if(r=ssl_create_rec_decoder(&d->s_to_c_n, | if((r=ssl_create_rec_decoder(&d->s_to_c_n, | |||
ssl->cs,s_mk,s_wk,s_iv)) | ssl->cs,s_mk,s_wk,s_iv))) | |||
ABORT(r); | ABORT(r); | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
if(key_block){ | if(key_block){ | |||
r_data_zfree(key_block); | r_data_zfree(key_block); | |||
free(key_block); | free(key_block); | |||
} | } | |||
return(_status); | 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 = EVP_MD_CTX_create(); | ||||
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,(unsigned int *) &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,(unsigned int *) &d->sess | ||||
ion_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); | ||||
} | ||||
static int ssl_read_key_log_file(d) | ||||
ssl_decoder *d; | ||||
{ | ||||
int r,_status,n,i; | ||||
unsigned int t; | ||||
size_t l=0; | ||||
char *line,*label_data; | ||||
while ((n=getline(&line,&l,d->ctx->ssl_key_log_file))!=-1) { | ||||
if(n==(d->client_random->len*2)+112 && | ||||
!strncmp(line,"CLIENT_RANDOM",13)) { | ||||
if(!(label_data=malloc((d->client_random->len*2)+1))) | ||||
ABORT(r); | ||||
for(i=0;i<d->client_random->len;i++) | ||||
if(snprintf(label_data+(i*2),3,"%02x",d->client_random->data[i])!=2) | ||||
ABORT(r); | ||||
if(STRNICMP(line+14,label_data,64)) | ||||
continue; | ||||
if((r=r_data_alloc(&d->MS,48))) | ||||
ABORT(r); | ||||
for(i=0; i < d->MS->len; i++) { | ||||
if(sscanf(line+14+65+(i*2),"%2x",&t)!=1) | ||||
ABORT(r); | ||||
*(d->MS->data+i)=(char)t; | ||||
} | ||||
} | ||||
/* | ||||
Eventually add support for other labels defined here: | ||||
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Fo | ||||
rmat | ||||
*/ | ||||
} | ||||
_status=0; | ||||
abort: | ||||
if (d->ctx->ssl_key_log_file != NULL) | ||||
fseek(d->ctx->ssl_key_log_file, 0, SEEK_SET); | ||||
return(_status); | ||||
} | ||||
#endif | #endif | |||
End of changes. 86 change blocks. | ||||
108 lines changed or deleted | 385 lines changed or added |