Use the maximum block length for the extra size in the encrypt
[openssl.git] / ssl / s3_pkt.c
index a3d656be407d4aaead90771ae16a17c45a0a917f..e0b13d99b99b195f983874ceefcdd9abd806bb21 100644 (file)
@@ -170,7 +170,7 @@ static int ssl3_read_n(SSL *s, int n, int max, int extend)
        }
        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;
                }
 
@@ -231,7 +231,7 @@ static int ssl3_read_n(SSL *s, int n, int max, int extend)
 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;
@@ -342,16 +342,23 @@ again:
        /* 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) ||
@@ -364,25 +371,30 @@ printf("\n");
 
                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;
                        }
                }
 
@@ -427,6 +439,15 @@ printf("\n");
        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:
@@ -704,7 +725,7 @@ static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
  *     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;
@@ -715,9 +736,10 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len)
                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;
                }
 
@@ -726,8 +748,9 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len)
                {
                unsigned char *src = s->s3->handshake_fragment;
                unsigned char *dst = buf;
-               unsigned int j;
+               unsigned int k;
 
+               /* peek == 0 */
                n = 0;
                while ((len > 0) && (s->s3->handshake_fragment_len > 0))
                        {
@@ -736,8 +759,8 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len)
                        n++;
                        }
                /* move any remaining fragment bytes: */
-               for (j = 0; j < s->s3->handshake_fragment_len; j++)
-                       s->s3->handshake_fragment[j] = *src++;
+               for (k = 0; k < s->s3->handshake_fragment_len; k++)
+                       s->s3->handshake_fragment[k] = *src++;
                return n;
        }
 
@@ -763,7 +786,7 @@ start:
         * 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);
@@ -781,7 +804,8 @@ start:
                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;
@@ -810,12 +834,15 @@ start:
                        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);
                }
@@ -899,19 +926,21 @@ start:
                                        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);
+                                               }
                                        }
                                }
                        }
@@ -954,7 +983,7 @@ start:
                        s->rwstate=SSL_NOTHING;
                        s->s3->fatal_alert = alert_descr;
                        SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr);
-                       sprintf(tmp,"%d",alert_descr);
+                       BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);
                        ERR_add_error_data(2,"SSL alert number ",tmp);
                        s->shutdown|=SSL_RECEIVED_SHUTDOWN;
                        SSL_CTX_remove_session(s->ctx,s->session);
@@ -1022,19 +1051,21 @@ start:
                        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;
                }
@@ -1042,7 +1073,7 @@ start:
        switch (rr->type)
                {
        default:
-#ifndef NO_TLS
+#ifndef OPENSSL_NO_TLS
                /* TLS just ignores unknown message types */
                if (s->version == TLS1_VERSION)
                        {
@@ -1059,7 +1090,7 @@ start:
                 * 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,
@@ -1154,7 +1185,7 @@ void ssl3_send_alert(SSL *s, int level, int desc)
        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 */
@@ -1173,9 +1204,9 @@ int ssl3_dispatch_alert(SSL *s)
                }
        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);