* [including the GNU Public Licence.]
*/
/* ====================================================================
- * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include <stdio.h>
#include <errno.h>
#define USE_SOCKETS
+#include "ssl_locl.h"
#include <openssl/evp.h>
#include <openssl/buffer.h>
-#include "ssl_locl.h"
static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
- unsigned int len);
+ unsigned int len, int create_empty_fragment);
static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
unsigned int len);
static int ssl3_get_record(SSL *s);
{
/* avoid buffer overflow */
- int max_max = SSL3_RT_MAX_PACKET_SIZE - s->packet_length;
- if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
- max_max += SSL3_RT_MAX_EXTRA;
+ int max_max = s->s3->rbuf.len - s->packet_length;
if (max > max_max)
max = max_max;
}
unsigned char md[EVP_MAX_MD_SIZE];
short version;
unsigned int mac_size;
- int clear=0,extra;
+ int clear=0;
+ size_t extra;
+ int decryption_failed_or_bad_record_mac = 0;
+ unsigned char *mac = NULL;
rr= &(s->s3->rrec);
sess=s->session;
extra=SSL3_RT_MAX_EXTRA;
else
extra=0;
+ if (extra != s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE)
+ {
+ /* actually likely an application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
+ * set after ssl3_setup_buffers() was done */
+ SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
again:
/* check if we have the header */
if ( (s->rstate != SSL_ST_READ_BODY) ||
(s->packet_length < SSL3_RT_HEADER_LENGTH))
{
- n=ssl3_read_n(s,SSL3_RT_HEADER_LENGTH,
- SSL3_RT_MAX_PACKET_SIZE,0);
+ n=ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
if (n <= 0) return(n); /* error or non-blocking */
s->rstate=SSL_ST_READ_BODY;
goto err;
}
- if (rr->length >
- (unsigned int)SSL3_RT_MAX_ENCRYPTED_LENGTH+extra)
+ if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH+extra)
{
al=SSL_AD_RECORD_OVERFLOW;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PACKET_LENGTH_TOO_LONG);
/* s->rstate == SSL_ST_READ_BODY, get and decode the data */
- if (rr->length > (s->packet_length-SSL3_RT_HEADER_LENGTH))
+ if (rr->length > s->packet_length-SSL3_RT_HEADER_LENGTH)
{
/* now s->packet_length == SSL3_RT_HEADER_LENGTH */
i=rr->length;
* rr->length bytes of encrypted compressed stuff. */
/* check is not needed I believe */
- if (rr->length > (unsigned int)SSL3_RT_MAX_ENCRYPTED_LENGTH+extra)
+ if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH+extra)
{
al=SSL_AD_RECORD_OVERFLOW;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
/* SSLerr() and ssl3_send_alert() have been called */
goto err;
- /* otherwise enc_err == -1 */
- goto decryption_failed_or_bad_record_mac;
+ /* Otherwise enc_err == -1, which indicates bad padding
+ * (rec->length has not been changed in this case).
+ * To minimize information leaked via timing, we will perform
+ * the MAC computation anyway. */
+ decryption_failed_or_bad_record_mac = 1;
}
#ifdef TLS_DEBUG
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG);
goto f_err;
#else
- goto decryption_failed_or_bad_record_mac;
+ decryption_failed_or_bad_record_mac = 1;
#endif
}
/* check the MAC for rr->input (it's in mac_size bytes at the tail) */
- if (rr->length < mac_size)
+ if (rr->length >= mac_size)
+ {
+ rr->length -= mac_size;
+ mac = &rr->data[rr->length];
+ }
+ else
{
+ /* record (minus padding) is too short to contain a MAC */
#if 0 /* OK only for stream ciphers */
al=SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
goto f_err;
#else
- goto decryption_failed_or_bad_record_mac;
+ decryption_failed_or_bad_record_mac = 1;
+ rr->length = 0;
#endif
}
- rr->length-=mac_size;
i=s->method->ssl3_enc->mac(s,md,0);
- if (memcmp(md,&(rr->data[rr->length]),mac_size) != 0)
+ if (mac == NULL || memcmp(md, mac, mac_size) != 0)
{
- goto decryption_failed_or_bad_record_mac;
+ decryption_failed_or_bad_record_mac = 1;
}
}
+ if (decryption_failed_or_bad_record_mac)
+ {
+ /* A separate 'decryption_failed' alert was introduced with TLS 1.0,
+ * SSL 3.0 only has 'bad_record_mac'. But unless a decryption
+ * failure is directly visible from the ciphertext anyway,
+ * we should not reveal which kind of error occured -- this
+ * might become visible to an attacker (e.g. via a logfile) */
+ al=SSL_AD_BAD_RECORD_MAC;
+ SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+ goto f_err;
+ }
+
/* r->length is now just compressed */
if (s->expand != NULL)
{
- if (rr->length >
- (unsigned int)SSL3_RT_MAX_COMPRESSED_LENGTH+extra)
+ if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra)
{
al=SSL_AD_RECORD_OVERFLOW;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
}
}
- if (rr->length > (unsigned int)SSL3_RT_MAX_PLAIN_LENGTH+extra)
+ if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH+extra)
{
al=SSL_AD_RECORD_OVERFLOW;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DATA_LENGTH_TOO_LONG);
return(1);
-decryption_failed_or_bad_record_mac:
- /* Separate 'decryption_failed' alert was introduced with TLS 1.0,
- * SSL 3.0 only has 'bad_record_mac'. But unless a decryption
- * failure is directly visible from the ciphertext anyway,
- * we should not reveal which kind of error occured -- this
- * might become visible to an attacker (e.g. via logfile) */
- al=SSL_AD_BAD_RECORD_MAC;
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
f_err:
ssl3_send_alert(s,SSL3_AL_FATAL,al);
err:
if (i == 0)
{
SSLerr(SSL_F_SSL3_WRITE_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
- return(-1);
+ return -1;
}
}
else
nw=n;
- i=do_ssl3_write(s,type,&(buf[tot]),nw);
+ i=do_ssl3_write(s, type, &(buf[tot]), nw, 0);
if (i <= 0)
{
s->s3->wnum=tot;
- return(i);
+ return i;
}
if ((i == (int)n) ||
(type == SSL3_RT_APPLICATION_DATA &&
(s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)))
{
- return(tot+i);
+ /* next chunk of data should get another prepended empty fragment
+ * in ciphersuites with known-IV weakness: */
+ s->s3->empty_fragment_done = 0;
+
+ return tot+i;
}
n-=i;
}
static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
- unsigned int len)
+ unsigned int len, int create_empty_fragment)
{
unsigned char *p,*plen;
int i,mac_size,clear=0;
+ int prefix_len = 0;
SSL3_RECORD *wr;
SSL3_BUFFER *wb;
SSL_SESSION *sess;
- /* first check is there is a SSL3_RECORD still being written
+ /* first check if there is a SSL3_BUFFER still being written
* out. This will happen with non blocking IO */
if (s->s3->wbuf.left != 0)
return(ssl3_write_pending(s,type,buf,len));
/* if it went, fall through and send more stuff */
}
- if (len == 0) return(len);
+ if (len == 0 && !create_empty_fragment)
+ return 0;
wr= &(s->s3->wrec);
wb= &(s->s3->wbuf);
else
mac_size=EVP_MD_size(s->write_hash);
- p=wb->buf;
+ /* 'create_empty_fragment' is true only when this function calls itself */
+ if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done)
+ {
+ /* countermeasure against known-IV weakness in CBC ciphersuites
+ * (see http://www.openssl.org/~bodo/tls-cbc.txt) */
+
+ if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA)
+ {
+ /* recursive function call with 'create_empty_fragment' set;
+ * this prepares and buffers the data for an empty fragment
+ * (these 'prefix_len' bytes are sent out later
+ * together with the actual payload) */
+ prefix_len = do_ssl3_write(s, type, buf, 0, 1);
+ if (prefix_len <= 0)
+ goto err;
+
+ if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
+ {
+ /* insufficient space */
+ SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ s->s3->empty_fragment_done = 1;
+ }
+
+ p = wb->buf + prefix_len;
/* write the header */
+
*(p++)=type&0xff;
wr->type=type;
*(p++)=(s->version>>8);
*(p++)=s->version&0xff;
- /* record where we are to write out packet length */
+ /* field where we are to write out packet length */
plen=p;
p+=2;
wr->type=type; /* not needed but helps for debugging */
wr->length+=SSL3_RT_HEADER_LENGTH;
- /* Now lets setup wb */
- wb->left=wr->length;
- wb->offset=0;
+ if (create_empty_fragment)
+ {
+ /* we are in a recursive call;
+ * just return the length, don't write out anything here
+ */
+ return wr->length;
+ }
+
+ /* now let's set up wb */
+ wb->left = prefix_len + wr->length;
+ wb->offset = 0;
+ /* memorize arguments so that ssl3_write_pending can detect bad write retries later */
s->s3->wpend_tot=len;
s->s3->wpend_buf=buf;
s->s3->wpend_type=type;
s->s3->wpend_ret=len;
/* we now just need to write the buffer */
- return(ssl3_write_pending(s,type,buf,len));
+ return ssl3_write_pending(s,type,buf,len);
err:
- return(-1);
+ return -1;
}
/* if s->s3->wbuf.left != 0, we need to call this */
)
))
{
- s->s3->in_read_app_data=0;
+ s->s3->in_read_app_data=2;
return(-1);
}
else
void (*cb)(const SSL *ssl,int type,int val)=NULL;
s->s3->alert_dispatch=0;
- i=do_ssl3_write(s,SSL3_RT_ALERT,&s->s3->send_alert[0],2);
+ i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0);
if (i <= 0)
{
s->s3->alert_dispatch=1;