* [including the GNU Public Licence.]
*/
/* ====================================================================
- * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1998-2001 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
}
if (n > max) /* does not happen */
{
- SSLerr(SSL_F_SSL3_READ_N,SSL_R_INTERNAL_ERROR);
+ SSLerr(SSL_F_SSL3_READ_N,ERR_R_INTERNAL_ERROR);
return -1;
}
static int ssl3_get_record(SSL *s)
{
int ssl_major,ssl_minor,al;
- int n,i,ret= -1;
+ int enc_err,n,i,ret= -1;
SSL3_RECORD *rr;
SSL_SESSION *sess;
unsigned char *p;
/* decrypt in place in 'rr->input' */
rr->data=rr->input;
- if (!s->method->ssl3_enc->enc(s,0))
+ enc_err = s->method->ssl3_enc->enc(s,0);
+ if (enc_err <= 0)
{
- al=SSL_AD_DECRYPT_ERROR;
- goto f_err;
+ if (enc_err == 0)
+ /* SSLerr() and ssl3_send_alert() have been called */
+ goto err;
+
+ /* otherwise enc_err == -1 */
+ goto decryption_failed_or_bad_record_mac;
}
+
#ifdef TLS_DEBUG
printf("dec %d\n",rr->length);
{ unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
printf("\n");
#endif
+
/* r->length is now the compressed data plus mac */
if ( (sess == NULL) ||
(s->enc_read_ctx == NULL) ||
if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
{
+#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */
al=SSL_AD_RECORD_OVERFLOW;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG);
goto f_err;
+#else
+ goto decryption_failed_or_bad_record_mac;
+#endif
}
/* check the MAC for rr->input (it's in mac_size bytes at the tail) */
if (rr->length < mac_size)
{
+#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;
+#endif
}
rr->length-=mac_size;
i=s->method->ssl3_enc->mac(s,md,0);
if (memcmp(md,&(rr->data[rr->length]),mac_size) != 0)
{
- al=SSL_AD_BAD_RECORD_MAC;
- SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_MAC_DECODE);
- ret= -1;
- goto f_err;
+ goto decryption_failed_or_bad_record_mac;
}
}
if (rr->length == 0) goto again;
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:
* Application data protocol
* none of our business
*/
-int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len)
+int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
{
int al,i,j,ret;
unsigned int n;
SSL3_RECORD *rr;
- void (*cb)()=NULL;
+ void (*cb)(const SSL *ssl,int type2,int val)=NULL;
if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
if (!ssl3_setup_buffers(s))
return(-1);
- if ((type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type)
+ if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type) ||
+ (peek && (type != SSL3_RT_APPLICATION_DATA)))
{
- SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_INTERNAL_ERROR);
+ SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
return -1;
}
unsigned char *dst = buf;
unsigned int k;
+ /* peek == 0 */
n = 0;
while ((len > 0) && (s->s3->handshake_fragment_len > 0))
{
* s->s3->rrec.length, - number of bytes. */
rr = &(s->s3->rrec);
- /* get new packet */
+ /* get new packet if necessary */
if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
{
ret=ssl3_get_record(s);
goto err;
}
- /* If the other end has shutdown, throw anything we read away */
+ /* If the other end has shut down, throw anything we read away
+ * (even in 'peek' mode) */
if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
{
rr->length=0;
n = (unsigned int)len;
memcpy(buf,&(rr->data[rr->off]),n);
- rr->length-=n;
- rr->off+=n;
- if (rr->length == 0)
+ if (!peek)
{
- s->rstate=SSL_ST_READ_HEADER;
- rr->off=0;
+ rr->length-=n;
+ rr->off+=n;
+ if (rr->length == 0)
+ {
+ s->rstate=SSL_ST_READ_HEADER;
+ rr->off=0;
+ }
}
return(n);
}
goto err;
}
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->s3->handshake_fragment, 4, s, s->msg_callback_arg);
+
if (SSL_is_init_finished(s) &&
!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
!s->s3->renegotiate)
return(-1);
}
- if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+ if (!(s->mode & SSL_MODE_AUTO_RETRY))
{
- BIO *bio;
- /* In the case where we try to read application data
- * the first time, but we trigger an SSL handshake, we
- * return -1 with the retry option set. I do this
- * otherwise renegotiation can cause nasty problems
- * in the blocking world */ /* ? */
- s->rwstate=SSL_READING;
- bio=SSL_get_rbio(s);
- BIO_clear_retry_flags(bio);
- BIO_set_retry_read(bio);
- return(-1);
+ if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+ {
+ BIO *bio;
+ /* In the case where we try to read application data,
+ * but we trigger an SSL handshake, we return -1 with
+ * the retry option set. Otherwise renegotiation may
+ * cause nasty problems in the blocking world */
+ s->rwstate=SSL_READING;
+ bio=SSL_get_rbio(s);
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
}
}
}
s->s3->alert_fragment_len = 0;
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_ALERT, s->s3->alert_fragment, 2, s, s->msg_callback_arg);
+
if (s->info_callback != NULL)
cb=s->info_callback;
else if (s->ctx->info_callback != NULL)
}
rr->length=0;
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg);
+
s->s3->change_cipher_spec=1;
if (!do_change_cipher_spec(s))
goto err;
return(-1);
}
- if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+ if (!(s->mode & SSL_MODE_AUTO_RETRY))
{
- BIO *bio;
- /* In the case where we try to read application data
- * the first time, but we trigger an SSL handshake, we
- * return -1 with the retry option set. I do this
- * otherwise renegotiation can cause nasty problems
- * in the blocking world */ /* ? */
- s->rwstate=SSL_READING;
- bio=SSL_get_rbio(s);
- BIO_clear_retry_flags(bio);
- BIO_set_retry_read(bio);
- return(-1);
+ if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+ {
+ BIO *bio;
+ /* In the case where we try to read application data,
+ * but we trigger an SSL handshake, we return -1 with
+ * the retry option set. Otherwise renegotiation may
+ * cause nasty problems in the blocking world */
+ s->rwstate=SSL_READING;
+ bio=SSL_get_rbio(s);
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
}
goto start;
}
switch (rr->type)
{
default:
-#ifndef NO_TLS
+#ifndef OPENSSL_NO_TLS
/* TLS just ignores unknown message types */
if (s->version == TLS1_VERSION)
{
+ rr->length = 0;
goto start;
}
#endif
* of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that
* should not happen when type != rr->type */
al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_INTERNAL_ERROR);
+ SSLerr(SSL_F_SSL3_READ_BYTES,ERR_R_INTERNAL_ERROR);
goto f_err;
case SSL3_RT_APPLICATION_DATA:
/* At this point, we were expecting handshake data,
{
/* Map tls/ssl alert value to correct one */
desc=s->method->ssl3_enc->alert_value(desc);
+ if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION)
+ desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have protocol_version alerts */
if (desc < 0) return;
/* If a fatal one, remove from cache */
if ((level == 2) && (s->session != NULL))
s->s3->alert_dispatch=1;
s->s3->send_alert[0]=level;
s->s3->send_alert[1]=desc;
- if (s->s3->wbuf.left == 0) /* data still being written out */
+ if (s->s3->wbuf.left == 0) /* data still being written out? */
ssl3_dispatch_alert(s);
/* else data is still being written out, we will get written
* some time in the future */
int ssl3_dispatch_alert(SSL *s)
{
int i,j;
- void (*cb)()=NULL;
+ 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);
}
else
{
- /* If it is important, send it now. If the message
- * does not get sent due to non-blocking IO, we will
- * not worry too much. */
+ /* Alert sent to BIO. If it is important, flush it now.
+ * If the message does not get sent due to non-blocking IO,
+ * we will not worry too much. */
if (s->s3->send_alert[0] == SSL3_AL_FATAL)
(void)BIO_flush(s->wbio);
+ if (s->msg_callback)
+ s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, 2, s, s->msg_callback_arg);
+
if (s->info_callback != NULL)
cb=s->info_callback;
else if (s->ctx->info_callback != NULL)