Fix seg fault with 0 p val in SKE
[openssl.git] / ssl / s3_pkt.c
index 780acec50571a83b37dd7da68e8e730e56d95361..379890237e8663b72a68f38a6e472a1d019e4312 100644 (file)
@@ -231,7 +231,8 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
         return -1;
     }
 
-    if (!s->read_ahead)
+    /* We always act like read_ahead is set for DTLS */
+    if (!s->read_ahead && !SSL_IS_DTLS(s))
         /* ignore max parameter */
         max = n;
     else {
@@ -360,11 +361,22 @@ static int ssl3_get_record(SSL *s)
             if (version != s->version) {
                 SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
                 if ((s->version & 0xFF00) == (version & 0xFF00)
-                    && !s->enc_write_ctx && !s->write_hash)
+                    && !s->enc_write_ctx && !s->write_hash) {
+                    if (rr->type == SSL3_RT_ALERT) {
+                        /*
+                         * The record is using an incorrect version number, but
+                         * what we've got appears to be an alert. We haven't
+                         * read the body yet to check whether its a fatal or
+                         * not - but chances are it is. We probably shouldn't
+                         * send a fatal alert back. We'll just end.
+                         */
+                         goto err;
+                    }
                     /*
                      * Send back error using their minor version number :-)
                      */
                     s->version = (unsigned short)version;
+                }
                 al = SSL_AD_PROTOCOL_VERSION;
                 goto f_err;
             }
@@ -429,12 +441,12 @@ static int ssl3_get_record(SSL *s)
     rr->data = rr->input;
 
     enc_err = s->method->ssl3_enc->enc(s, 0);
-        /*-
-         * enc_err is:
-         *    0: (in non-constant time) if the record is publically invalid.
-         *    1: if the padding is valid
-         *    -1: if the padding is invalid
-         */
+    /*-
+     * enc_err is:
+     *    0: (in non-constant time) if the record is publically invalid.
+     *    1: if the padding is valid
+     *    -1: if the padding is invalid
+     */
     if (enc_err == 0) {
         al = SSL_AD_DECRYPTION_FAILED;
         SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
@@ -542,14 +554,14 @@ static int ssl3_get_record(SSL *s)
     }
 
     rr->off = 0;
-        /*-
-         * So at this point the following is true
-         * ssl->s3->rrec.type   is the type of record
-         * ssl->s3->rrec.length == number of bytes in record
-         * ssl->s3->rrec.off    == offset to first valid byte
-         * ssl->s3->rrec.data   == where to take bytes from, increment
-         *                         after use :-).
-         */
+    /*-
+     * So at this point the following is true
+     * ssl->s3->rrec.type   is the type of record
+     * ssl->s3->rrec.length == number of bytes in record
+     * ssl->s3->rrec.off    == offset to first valid byte
+     * ssl->s3->rrec.data   == where to take bytes from, increment
+     *                         after use :-).
+     */
 
     /* we have pulled in a full packet so zero things */
     s->packet_length = 0;
@@ -684,8 +696,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
         len >= 4 * (int)(max_send_fragment = s->max_send_fragment) &&
         s->compress == NULL && s->msg_callback == NULL &&
         SSL_USE_EXPLICIT_IV(s) &&
-        EVP_CIPHER_flags(s->
-                         enc_write_ctx->cipher) &
+        EVP_CIPHER_flags(s->enc_write_ctx->cipher) &
         EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK) {
         unsigned char aad[13];
         EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param;
@@ -708,6 +719,10 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
                 packlen *= 4;
 
             wb->buf = OPENSSL_malloc(packlen);
+            if (!wb->buf) {
+                SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_MALLOC_FAILURE);
+                return -1;
+            }
             wb->len = packlen;
         } else if (tot == len) { /* done? */
             OPENSSL_free(wb->buf); /* free jumbo buffer */
@@ -781,7 +796,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
 
             i = ssl3_write_pending(s, type, &buf[tot], nw);
             if (i <= 0) {
-                if (i < 0) {
+                if (i < 0 && (!s->wbio || !BIO_should_retry(s->wbio))) {
                     OPENSSL_free(wb->buf);
                     wb->buf = NULL;
                 }
@@ -1100,7 +1115,7 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
             s->rwstate = SSL_NOTHING;
             return (s->s3->wpend_ret);
         } else if (i <= 0) {
-            if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) {
+            if (SSL_IS_DTLS(s)) {
                 /*
                  * For DTLS, just drop it. That's kind of the whole point in
                  * using a datagram service
@@ -1199,12 +1214,12 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
  start:
     s->rwstate = SSL_NOTHING;
 
-        /*-
-         * s->s3->rrec.type         - is the type of record
-         * s->s3->rrec.data,    - data
-         * s->s3->rrec.off,     - offset into 'data' for next read
-         * s->s3->rrec.length,  - number of bytes.
-         */
+    /*-
+     * s->s3->rrec.type         - is the type of record
+     * s->s3->rrec.data,    - data
+     * s->s3->rrec.off,     - offset into 'data' for next read
+     * s->s3->rrec.length,  - number of bytes.
+     */
     rr = &(s->s3->rrec);
 
     /* get new packet if necessary */
@@ -1322,11 +1337,11 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
         }
     }
 
-        /*-
-         * s->s3->handshake_fragment_len == 4  iff  rr->type == SSL3_RT_HANDSHAKE;
-         * s->s3->alert_fragment_len == 2      iff  rr->type == SSL3_RT_ALERT.
-         * (Possibly rr is 'empty' now, i.e. rr->length may be 0.)
-         */
+    /*-
+     * s->s3->handshake_fragment_len == 4  iff  rr->type == SSL3_RT_HANDSHAKE;
+     * s->s3->alert_fragment_len == 2      iff  rr->type == SSL3_RT_ALERT.
+     * (Possibly rr is 'empty' now, i.e. rr->length may be 0.)
+     */
 
     /* If we are a client, check for an incoming 'Hello Request': */
     if ((!s->server) &&
@@ -1426,7 +1441,7 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
             cb(s, SSL_CB_READ_ALERT, j);
         }
 
-        if (alert_level == 1) { /* warning */
+        if (alert_level == SSL3_AL_WARNING) {
             s->s3->warn_alert = alert_descr;
             if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
                 s->shutdown |= SSL_RECEIVED_SHUTDOWN;
@@ -1449,7 +1464,7 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
             else if (alert_descr == SSL_AD_MISSING_SRP_USERNAME)
                 return (0);
 #endif
-        } else if (alert_level == 2) { /* fatal */
+        } else if (alert_level == SSL3_AL_FATAL) {
             char tmp[16];
 
             s->rwstate = SSL_NOTHING;