ssl_rec.c (ssldump-0.9b3) | : | ssl_rec.c (ssldump-1.3) | ||
---|---|---|---|---|
skipping to change at line 44 | skipping to change at line 44 | |||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY SUCH DAMA GE. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY SUCH DAMA GE. | |||
$Id: ssl_rec.c,v 1.3 2000/11/03 06:38:06 ekr Exp $ | $Id: ssl_rec.c,v 1.3 2000/11/03 06:38:06 ekr Exp $ | |||
ekr@rtfm.com Wed Aug 18 15:46:57 1999 | ekr@rtfm.com Wed Aug 18 15:46:57 1999 | |||
*/ | */ | |||
static char *RCSSTRING="$Id: ssl_rec.c,v 1.3 2000/11/03 06:38:06 ekr Exp $"; | ||||
#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> | |||
#endif | #endif | |||
#include "ssldecode.h" | #include "ssldecode.h" | |||
#include "ssl_rec.h" | #include "ssl_rec.h" | |||
struct ssl_rec_decoder_ { | struct ssl_rec_decoder_ { | |||
SSL_CipherSuite *cs; | SSL_CipherSuite *cs; | |||
Data *mac_key; | Data *mac_key; | |||
Data *implicit_iv; /* for AEAD ciphers */ | ||||
Data *write_key; /* for AEAD ciphers */ | ||||
#ifdef OPENSSL | #ifdef OPENSSL | |||
EVP_CIPHER_CTX *evp; | EVP_CIPHER_CTX *evp; | |||
#endif | #endif | |||
UINT4 seq; | UINT4 seq; | |||
}; | }; | |||
static char *digests[]={ | char *digests[]={ | |||
"MD5", | "MD5", | |||
"SHA1" | "SHA1", | |||
"SHA224", | ||||
"SHA256", | ||||
"SHA384", | ||||
"SHA512", | ||||
NULL | ||||
}; | }; | |||
static char *ciphers[]={ | char *ciphers[]={ | |||
"DES", | "DES", | |||
"DES3", | "3DES", | |||
"RC4", | "RC4", | |||
"RC2", | "RC2", | |||
"IDEA" | "IDEA", | |||
"AES128", | ||||
"AES256", | ||||
"CAMELLIA128", | ||||
"CAMELLIA256", | ||||
"SEED", | ||||
NULL, | ||||
"aes-128-gcm", | ||||
"aes-256-gcm" | ||||
}; | }; | |||
static int tls_check_mac PROTO_LIST((ssl_rec_decoder *d,int ct, | 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)); | static int fmt_seq PROTO_LIST((UINT4 num,UCHAR *buf)); | |||
int ssl_create_rec_decoder(dp,cs,mk,sk,iv) | int ssl_create_rec_decoder(dp,cs,mk,sk,iv) | |||
ssl_rec_decoder **dp; | ssl_rec_decoder **dp; | |||
SSL_CipherSuite *cs; | SSL_CipherSuite *cs; | |||
UCHAR *mk; | UCHAR *mk; | |||
UCHAR *sk; | UCHAR *sk; | |||
UCHAR *iv; | UCHAR *iv; | |||
{ | { | |||
int r,_status; | int r,_status; | |||
ssl_rec_decoder *dec=0; | ssl_rec_decoder *dec=0; | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
const EVP_CIPHER *ciph=0; | const EVP_CIPHER *ciph=0; | |||
/* Find the SSLeay cipher */ | /* Find the SSLeay cipher */ | |||
if(cs->enc!=ENC_NULL){ | if(cs->enc!=ENC_NULL){ | |||
ciph=(EVP_CIPHER *)EVP_get_cipherbyname(ciphers[cs->enc-0x30]); | ciph=(EVP_CIPHER *)EVP_get_cipherbyname(ciphers[cs->enc-0x30]); | |||
if(!ciph) | ||||
ABORT(R_INTERNAL); | ||||
} | ||||
else { | ||||
ciph=EVP_enc_null(); | ||||
} | } | |||
if(!(dec=(ssl_rec_decoder *)calloc(sizeof(ssl_rec_decoder),1))) | if(!(dec=(ssl_rec_decoder *)calloc(1,sizeof(ssl_rec_decoder)))) | |||
ABORT(R_NO_MEMORY); | ABORT(R_NO_MEMORY); | |||
dec->cs=cs; | dec->cs=cs; | |||
if(r=r_data_create(&dec->mac_key,mk,cs->dig_len)) | ||||
if((r=r_data_alloc(&dec->mac_key,cs->dig_len))) | ||||
ABORT(r); | ||||
if((r=r_data_alloc(&dec->implicit_iv,cs->block))) | ||||
ABORT(r); | ABORT(r); | |||
if(!(dec->evp=(EVP_CIPHER_CTX *)malloc(sizeof(EVP_CIPHER_CTX)))) | memcpy(dec->implicit_iv->data,iv,cs->block); | |||
if((r=r_data_create(&dec->write_key,sk,cs->eff_bits/8))) | ||||
ABORT(r); | ||||
/* | ||||
This is necessary for AEAD ciphers, because we must wait to fully initial | ||||
ize the cipher | ||||
in order to include the implicit IV | ||||
*/ | ||||
if(IS_AEAD_CIPHER(cs)){ | ||||
sk=NULL; | ||||
iv=NULL; | ||||
} | ||||
else | ||||
memcpy(dec->mac_key->data,mk,cs->dig_len); | ||||
if(!(dec->evp=EVP_CIPHER_CTX_new())) | ||||
ABORT(R_NO_MEMORY); | ABORT(R_NO_MEMORY); | |||
EVP_CIPHER_CTX_init(dec->evp); | EVP_CIPHER_CTX_init(dec->evp); | |||
EVP_CipherInit(dec->evp,ciph,sk,iv,0); | EVP_CipherInit(dec->evp,ciph,sk,iv,0); | |||
#endif | #endif | |||
*dp=dec; | *dp=dec; | |||
_status=0; | _status=0; | |||
abort: | abort: | |||
if(_status){ | if(_status){ | |||
ssl_destroy_rec_decoder(&dec); | ssl_destroy_rec_decoder(&dec); | |||
skipping to change at line 132 | skipping to change at line 170 | |||
int ssl_destroy_rec_decoder(dp) | int ssl_destroy_rec_decoder(dp) | |||
ssl_rec_decoder **dp; | ssl_rec_decoder **dp; | |||
{ | { | |||
ssl_rec_decoder *d; | ssl_rec_decoder *d; | |||
if(!dp || !*dp) | if(!dp || !*dp) | |||
return(0); | return(0); | |||
d=*dp; | d=*dp; | |||
r_data_destroy(&d->mac_key); | r_data_destroy(&d->mac_key); | |||
r_data_destroy(&d->implicit_iv); | ||||
r_data_destroy(&d->write_key); | ||||
#ifdef OPENSSL | #ifdef OPENSSL | |||
if(d->evp){ | if(d->evp){ | |||
EVP_CIPHER_CTX_cleanup(d->evp); | EVP_CIPHER_CTX_free(d->evp); | |||
free(d->evp); | ||||
} | } | |||
free(*dp); | free(*dp); | |||
#endif | #endif | |||
*dp=0; | *dp=0; | |||
return(0); | return(0); | |||
} | } | |||
#define MSB(a) ((a>>8)&0xff) | ||||
#define LSB(a) (a&0xff) | ||||
int ssl_decode_rec_data(ssl,d,ct,version,in,inl,out,outl) | int ssl_decode_rec_data(ssl,d,ct,version,in,inl,out,outl) | |||
ssl_obj *ssl; | ssl_obj *ssl; | |||
ssl_rec_decoder *d; | ssl_rec_decoder *d; | |||
int ct; | int ct; | |||
int version; | int version; | |||
UCHAR *in; | UCHAR *in; | |||
int inl; | int inl; | |||
UCHAR *out; | UCHAR *out; | |||
int *outl; | int *outl; | |||
{ | { | |||
#ifdef OPENSSL | #ifdef OPENSSL | |||
int pad; | int pad; | |||
int r; | int r,encpadl,x; | |||
UCHAR *mac; | UCHAR *mac,aead_tag[13],aead_nonce[12]; | |||
CRDUMP("Ciphertext",in,inl); | CRDUMP("Ciphertext",in,inl); | |||
/* First decrypt*/ | if(IS_AEAD_CIPHER(d->cs)){ | |||
EVP_Cipher(d->evp,out,in,inl); | memcpy(aead_nonce,d->implicit_iv->data,d->implicit_iv->len); | |||
memcpy(aead_nonce+d->implicit_iv->len,in,12-d->implicit_iv->len); | ||||
in+=12-d->implicit_iv->len; | ||||
inl-=12-d->implicit_iv->len; | ||||
EVP_DecryptInit(d->evp, | ||||
NULL, | ||||
d->write_key->data, | ||||
aead_nonce); | ||||
/* | ||||
Then tag is always 16 bytes, as per: | ||||
https://tools.ietf.org/html/rfc5116#section-5.2 | ||||
*/ | ||||
EVP_CIPHER_CTX_ctrl(d->evp,EVP_CTRL_GCM_SET_TAG,16,in+(inl-16)); | ||||
inl-=16; | ||||
fmt_seq(d->seq,aead_tag); | ||||
d->seq++; | ||||
aead_tag[8]=ct; | ||||
aead_tag[9]=MSB(version); | ||||
aead_tag[10]=LSB(version); | ||||
aead_tag[11]=MSB(inl); | ||||
aead_tag[12]=LSB(inl); | ||||
CRDUMP("Plaintext",out,inl); | EVP_DecryptUpdate(d->evp,NULL,outl,aead_tag,13); | |||
*outl=inl; | EVP_DecryptUpdate(d->evp,out,outl,in,inl); | |||
/* Now strip off the padding*/ | if (!(x=EVP_DecryptFinal(d->evp,NULL,&x))) | |||
if(d->cs->block!=1){ | ERETURN(SSL_BAD_MAC); | |||
pad=out[inl-1]; | ||||
*outl-=(pad+1); | ||||
} | } | |||
/* And the MAC */ | /* | |||
*outl-=d->cs->dig_len; | Encrypt-then-MAC is not used with AEAD ciphers, as per: | |||
mac=out+(*outl); | https://tools.ietf.org/html/rfc7366#section-3 | |||
CRDUMP("Record data",out,*outl); | */ | |||
else if(ssl->extensions->encrypt_then_mac==2){ | ||||
/* Now check the MAC */ | *outl=inl; | |||
if(ssl->version==0x300){ | ||||
if(r=ssl3_check_mac(d,ct,version,out,*outl,mac)) | /* First strip off the MAC */ | |||
ERETURN(r); | *outl-=d->cs->dig_len; | |||
mac=in+(*outl); | ||||
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); | ||||
} | ||||
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); | ||||
} | ||||
else | ||||
if((r=tls_check_mac(d,ct,version,in,encpadl,NULL,0,mac))) | ||||
ERETURN(r); | ||||
} | } | |||
else{ | else { | |||
if(r=tls_check_mac(d,ct,version,out,*outl,mac)) | /* First decrypt*/ | |||
ERETURN(r); | 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 | #endif | |||
return(0); | return(0); | |||
} | } | |||
#define MSB(a) ((a>>8)&0xff) | ||||
#define LSB(a) (a&0xff) | ||||
#ifdef OPENSSL | #ifdef OPENSSL | |||
/* This should go to 2^128, but we're never really going to see | /* This should go to 2^128, but we're never really going to see | |||
more than 2^64, so we cheat*/ | more than 2^64, so we cheat*/ | |||
static int fmt_seq(num,buf) | static int fmt_seq(num,buf) | |||
UINT4 num; | UINT4 num; | |||
UCHAR *buf; | UCHAR *buf; | |||
{ | { | |||
UINT4 netnum; | UINT4 netnum; | |||
memset(buf,0,8); | memset(buf,0,8); | |||
netnum=htonl(num); | netnum=htonl(num); | |||
memcpy(buf+4,&netnum,4); | memcpy(buf+4,&netnum,4); | |||
return(0); | 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; | ssl_rec_decoder *d; | |||
int ct; | int ct; | |||
int ver; | int ver; | |||
UCHAR *data; | UCHAR *data; | |||
UINT4 datalen; | UINT4 datalen; | |||
UCHAR *iv; | ||||
UINT4 ivlen; | ||||
UCHAR *mac; | UCHAR *mac; | |||
{ | { | |||
HMAC_CTX hm; | HMAC_CTX *hm = HMAC_CTX_new(); | |||
if(!hm) | ||||
ERETURN(R_NO_MEMORY); | ||||
const EVP_MD *md; | const EVP_MD *md; | |||
UINT4 l; | UINT4 l; | |||
UCHAR buf[20]; | UCHAR buf[128]; | |||
md=EVP_get_digestbyname(digests[d->cs->dig-0x40]); | md=EVP_get_digestbyname(digests[d->cs->dig-0x40]); | |||
HMAC_Init(&hm,d->mac_key->data,d->mac_key->len,md); | HMAC_Init_ex(hm,d->mac_key->data,d->mac_key->len,md,NULL); | |||
fmt_seq(d->seq,buf); | fmt_seq(d->seq,buf); | |||
d->seq++; | d->seq++; | |||
HMAC_Update(&hm,buf,8); | HMAC_Update(hm,buf,8); | |||
buf[0]=ct; | buf[0]=ct; | |||
HMAC_Update(&hm,buf,1); | HMAC_Update(hm,buf,1); | |||
buf[0]=MSB(ver); | buf[0]=MSB(ver); | |||
buf[1]=LSB(ver); | buf[1]=LSB(ver); | |||
HMAC_Update(&hm,buf,2); | HMAC_Update(hm,buf,2); | |||
buf[0]=MSB(datalen); | buf[0]=MSB(datalen); | |||
buf[1]=LSB(datalen); | buf[1]=LSB(datalen); | |||
HMAC_Update(&hm,buf,2); | 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); | HMAC_Final(hm,buf,&l); | |||
if(memcmp(mac,buf,l)) | if(memcmp(mac,buf,l)) | |||
ERETURN(SSL_BAD_MAC); | ERETURN(SSL_BAD_MAC); | |||
HMAC_cleanup(&hm); | HMAC_CTX_free(hm); | |||
return(0); | return(0); | |||
} | } | |||
int ssl3_check_mac(d,ct,ver,data,datalen,mac) | int ssl3_check_mac(d,ct,ver,data,datalen,mac) | |||
ssl_rec_decoder *d; | ssl_rec_decoder *d; | |||
int ct; | int ct; | |||
int ver; | int ver; | |||
UCHAR *data; | UCHAR *data; | |||
UINT4 datalen; | UINT4 datalen; | |||
UCHAR *mac; | UCHAR *mac; | |||
{ | { | |||
EVP_MD_CTX mc; | EVP_MD_CTX *mc = EVP_MD_CTX_new(); | |||
const EVP_MD *md; | const EVP_MD *md; | |||
UINT4 l; | UINT4 l; | |||
UCHAR buf[64],dgst[20]; | UCHAR buf[64],dgst[20]; | |||
int pad_ct; | int pad_ct; | |||
pad_ct=(d->cs->dig==DIG_SHA)?40:48; | pad_ct=(d->cs->dig==DIG_SHA)?40:48; | |||
md=EVP_get_digestbyname(digests[d->cs->dig-0x40]); | md=EVP_get_digestbyname(digests[d->cs->dig-0x40]); | |||
EVP_DigestInit(&mc,md); | EVP_DigestInit(mc,md); | |||
EVP_DigestUpdate(&mc,d->mac_key->data,d->mac_key->len); | EVP_DigestUpdate(mc,d->mac_key->data,d->mac_key->len); | |||
memset(buf,0x36,pad_ct); | memset(buf,0x36,pad_ct); | |||
EVP_DigestUpdate(&mc,buf,pad_ct); | EVP_DigestUpdate(mc,buf,pad_ct); | |||
fmt_seq(d->seq,buf); | fmt_seq(d->seq,buf); | |||
d->seq++; | d->seq++; | |||
EVP_DigestUpdate(&mc,buf,8); | EVP_DigestUpdate(mc,buf,8); | |||
buf[0]=ct; | buf[0]=ct; | |||
EVP_DigestUpdate(&mc,buf,1); | EVP_DigestUpdate(mc,buf,1); | |||
buf[0]=MSB(datalen); | buf[0]=MSB(datalen); | |||
buf[1]=LSB(datalen); | buf[1]=LSB(datalen); | |||
EVP_DigestUpdate(&mc,buf,2); | EVP_DigestUpdate(mc,buf,2); | |||
EVP_DigestUpdate(&mc,data,datalen); | EVP_DigestUpdate(mc,data,datalen); | |||
EVP_DigestFinal(&mc,dgst,&l); | EVP_DigestFinal(mc,dgst,&l); | |||
EVP_DigestInit(&mc,md); | EVP_DigestInit(mc,md); | |||
EVP_DigestUpdate(&mc,d->mac_key->data,d->mac_key->len); | EVP_DigestUpdate(mc,d->mac_key->data,d->mac_key->len); | |||
memset(buf,0x5c,pad_ct); | memset(buf,0x5c,pad_ct); | |||
EVP_DigestUpdate(&mc,buf,pad_ct); | EVP_DigestUpdate(mc,buf,pad_ct); | |||
EVP_DigestUpdate(&mc,dgst,l); | EVP_DigestUpdate(mc,dgst,l); | |||
EVP_DigestFinal(&mc,dgst,&l); | EVP_DigestFinal(mc,dgst,&l); | |||
if(memcmp(mac,dgst,l)) | if(memcmp(mac,dgst,l)) | |||
ERETURN(SSL_BAD_MAC); | ERETURN(SSL_BAD_MAC); | |||
EVP_MD_CTX_free(mc); | ||||
return(0); | return(0); | |||
} | } | |||
#endif | #endif | |||
End of changes. 50 change blocks. | ||||
63 lines changed or deleted | 206 lines changed or added |