static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
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);
-static int do_compress(SSL *ssl);
-static int do_uncompress(SSL *ssl);
-static int do_change_cipher_spec(SSL *ssl);
-/* used only by ssl3_get_record */
-static int ssl3_read_n(SSL *s, int n, int max, int extend)
+int ssl3_read_n(SSL *s, int n, int max, int extend)
{
/* If extend == 0, obtain new n-byte packet; if extend == 1, increase
* packet by another n bytes.
* (If s->read_ahead is set, 'max' bytes may be stored in rbuf
* [plus s->packet_length bytes if extend == 1].)
*/
- int i,off,newb;
+ int i,len,left,align=0;
+ unsigned char *pkt;
+ SSL3_BUFFER *rb;
+
+ if (n <= 0) return n;
+
+ rb = &(s->s3->rbuf);
+ left = rb->left;
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+ align = (int)rb->buf + SSL3_RT_HEADER_LENGTH;
+ align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
if (!extend)
{
/* start with empty packet ... */
- if (s->s3->rbuf.left == 0)
- s->s3->rbuf.offset = 0;
- s->packet = s->s3->rbuf.buf + s->s3->rbuf.offset;
+ if (left == 0)
+ rb->offset = align;
+ else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH)
+ {
+ /* check if next packet length is large
+ * enough to justify payload alignment... */
+ pkt = rb->buf + rb->offset;
+ if (pkt[0] == SSL3_RT_APPLICATION_DATA
+ && (pkt[3]<<8|pkt[4]) >= 128)
+ {
+ /* Note that even if packet is corrupted
+ * and its length field is insane, we can
+ * only be led to wrong decision about
+ * whether memmove will occur or not.
+ * Header values has no effect on memmove
+ * arguments and therefore no buffer
+ * overrun can be triggered. */
+ memmove (rb->buf+align,pkt,left);
+ rb->offset = align;
+ }
+ }
+ s->packet = rb->buf + rb->offset;
s->packet_length = 0;
/* ... now we can act as if 'extend' was set */
}
+ /* extend reads should not span multiple packets for DTLS */
+ if ( SSL_version(s) == DTLS1_VERSION &&
+ extend)
+ {
+ if ( left > 0 && n > left)
+ n = left;
+ }
+
/* if there is enough in the buffer from a previous read, take some */
- if (s->s3->rbuf.left >= (int)n)
+ if (left >= n)
{
s->packet_length+=n;
- s->s3->rbuf.left-=n;
- s->s3->rbuf.offset+=n;
+ rb->left=left-n;
+ rb->offset+=n;
return(n);
}
/* else we need to read more data */
- if (!s->read_ahead)
- max=n;
- {
- /* avoid buffer overflow */
- int max_max = s->s3->rbuf.len - s->packet_length;
- if (max > max_max)
- max = max_max;
- }
+ len = s->packet_length;
+ pkt = rb->buf+align;
+ /* Move any available bytes to front of buffer:
+ * 'len' bytes already pointed to by 'packet',
+ * 'left' extra ones at the end */
+ if (s->packet != pkt) /* len > 0 */
+ {
+ memmove(pkt, s->packet, len+left);
+ s->packet = pkt;
+ rb->offset = len + align;
+ }
+
+ max = rb->len - rb->offset;
if (n > max) /* does not happen */
{
SSLerr(SSL_F_SSL3_READ_N,ERR_R_INTERNAL_ERROR);
return -1;
}
- off = s->packet_length;
- newb = s->s3->rbuf.left;
- /* Move any available bytes to front of buffer:
- * 'off' bytes already pointed to by 'packet',
- * 'newb' extra ones at the end */
- if (s->packet != s->s3->rbuf.buf)
- {
- /* off > 0 */
- memmove(s->s3->rbuf.buf, s->packet, off+newb);
- s->packet = s->s3->rbuf.buf;
- }
+ if (!s->read_ahead)
+ max=n;
- while (newb < n)
+ while (left < n)
{
- /* Now we have off+newb bytes at the front of s->s3->rbuf.buf and need
- * to read in more until we have off+n (up to off+max if possible) */
+ /* Now we have len+left bytes at the front of s->s3->rbuf.buf
+ * and need to read in more until we have len+n (up to
+ * len+max if possible) */
clear_sys_error();
if (s->rbio != NULL)
{
s->rwstate=SSL_READING;
- i=BIO_read(s->rbio, &(s->s3->rbuf.buf[off+newb]), max-newb);
+ i=BIO_read(s->rbio,pkt+len+left, max-left);
}
else
{
if (i <= 0)
{
- s->s3->rbuf.left = newb;
+ rb->left = left;
return(i);
}
- newb+=i;
+ left+=i;
}
/* done reading, now the book-keeping */
- s->s3->rbuf.offset = off + n;
- s->s3->rbuf.left = newb - n;
+ rb->offset += n;
+ rb->left = left - n;
s->packet_length += n;
s->rwstate=SSL_NOTHING;
return(n);
extra=SSL3_RT_MAX_EXTRA;
else
extra=0;
- if (extra != s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE)
+ if (extra && !s->s3->init_extra)
{
- /* actually likely an application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
+ /* 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;
ssl_minor= *(p++);
version=(ssl_major<<8)|ssl_minor;
n2s(p,rr->length);
+#if 0
+fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length);
+#endif
/* Lets check version */
if (s->first_packet)
goto err;
}
- if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH+extra)
+ if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH)
{
al=SSL_AD_RECORD_OVERFLOW;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PACKET_LENGTH_TOO_LONG);
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
goto f_err;
}
- if (!do_uncompress(s))
+ if (!ssl3_do_uncompress(s))
{
al=SSL_AD_DECOMPRESSION_FAILURE;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_DECOMPRESSION);
/* just read a 0 length packet */
if (rr->length == 0) goto again;
+#if 0
+fprintf(stderr, "Ultimate Record type=%d, Length=%d\n", rr->type, rr->length);
+#endif
+
return(1);
f_err:
return(ret);
}
-static int do_uncompress(SSL *ssl)
+int ssl3_do_uncompress(SSL *ssl)
{
+#ifndef OPENSSL_NO_COMP
int i;
SSL3_RECORD *rr;
else
rr->length=i;
rr->data=rr->comp;
-
+#endif
return(1);
}
-static int do_compress(SSL *ssl)
+int ssl3_do_compress(SSL *ssl)
{
+#ifndef OPENSSL_NO_COMP
int i;
SSL3_RECORD *wr;
wr->length=i;
wr->input=wr->data;
+#endif
return(1);
}
n=(len-tot);
for (;;)
{
- if (n > SSL3_RT_MAX_PLAIN_LENGTH)
- nw=SSL3_RT_MAX_PLAIN_LENGTH;
+ if (n > s->max_send_fragment)
+ nw=s->max_send_fragment;
else
nw=n;
{
unsigned char *p,*plen;
int i,mac_size,clear=0;
- int prefix_len = 0;
+ int prefix_len=0,align=0;
SSL3_RECORD *wr;
- SSL3_BUFFER *wb;
+ SSL3_BUFFER *wb=&(s->s3->wbuf);
SSL_SESSION *sess;
/* 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)
+ if (wb->left != 0)
return(ssl3_write_pending(s,type,buf,len));
/* If we have an alert to send, lets send it */
if (s->s3->alert_dispatch)
{
- i=ssl3_dispatch_alert(s);
+ i=s->method->ssl_dispatch_alert(s);
if (i <= 0)
return(i);
/* if it went, fall through and send more stuff */
return 0;
wr= &(s->s3->wrec);
- wb= &(s->s3->wbuf);
sess=s->session;
if ( (sess == NULL) ||
if (prefix_len <= 0)
goto err;
- if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
+ if (prefix_len >
+ (SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD))
{
/* insufficient space */
SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
s->s3->empty_fragment_done = 1;
}
- p = wb->buf + prefix_len;
+ if (create_empty_fragment)
+ {
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+ /* extra fragment would be couple of cipher blocks,
+ * which would be multiple of SSL3_ALIGN_PAYLOAD, so
+ * if we want to align the real payload, then we can
+ * just pretent we simply have two headers. */
+ align = (int)wb->buf + 2*SSL3_RT_HEADER_LENGTH;
+ align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
+ p = wb->buf + align;
+ wb->offset = align;
+ }
+ else if (prefix_len)
+ {
+ p = wb->buf + wb->offset + prefix_len;
+ }
+ else
+ {
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+ align = (int)wb->buf + SSL3_RT_HEADER_LENGTH;
+ align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
+#endif
+ p = wb->buf + align;
+ wb->offset = align;
+ }
/* write the header */
/* first we compress */
if (s->compress != NULL)
{
- if (!do_compress(s))
+ if (!ssl3_do_compress(s))
{
SSLerr(SSL_F_DO_SSL3_WRITE,SSL_R_COMPRESSION_FAILURE);
goto err;
/* 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;
}
/* if s->s3->wbuf.left != 0, we need to call this */
-static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
- unsigned int len)
+int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
+ unsigned int len)
{
int i;
+ SSL3_BUFFER *wb=&(s->s3->wbuf);
/* XXXX */
if ((s->s3->wpend_tot > (int)len)
{
s->rwstate=SSL_WRITING;
i=BIO_write(s->wbio,
- (char *)&(s->s3->wbuf.buf[s->s3->wbuf.offset]),
- (unsigned int)s->s3->wbuf.left);
+ (char *)&(wb->buf[wb->offset]),
+ (unsigned int)wb->left);
}
else
{
SSLerr(SSL_F_SSL3_WRITE_PENDING,SSL_R_BIO_NOT_SET);
i= -1;
}
- if (i == s->s3->wbuf.left)
+ if (i == wb->left)
{
- s->s3->wbuf.left=0;
+ wb->left=0;
+ wb->offset+=i;
s->rwstate=SSL_NOTHING;
return(s->s3->wpend_ret);
}
else if (i <= 0)
return(i);
- s->s3->wbuf.offset+=i;
- s->s3->wbuf.left-=i;
+ wb->offset+=i;
+ wb->left-=i;
}
}
{
al=SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
- goto err;
+ goto f_err;
}
/* If the other end has shut down, throw anything we read away
{
al=SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_HELLO_REQUEST);
- goto err;
+ goto f_err;
}
if (s->msg_callback)
if ( (rr->length != 1) || (rr->off != 0) ||
(rr->data[0] != SSL3_MT_CCS))
{
- i=SSL_AD_ILLEGAL_PARAMETER;
+ al=SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
- goto err;
+ goto f_err;
+ }
+
+ /* Check we have a cipher to change to */
+ if (s->s3->tmp.new_cipher == NULL)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_CCS_RECEIVED_EARLY);
+ goto f_err;
}
rr->length=0;
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))
+ if (!ssl3_do_change_cipher_spec(s))
goto err;
else
goto start;
return(-1);
}
-static int do_change_cipher_spec(SSL *s)
+int ssl3_do_change_cipher_spec(SSL *s)
{
int i;
const char *sender;
s->s3->send_alert[0]=level;
s->s3->send_alert[1]=desc;
if (s->s3->wbuf.left == 0) /* data still being written out? */
- ssl3_dispatch_alert(s);
+ s->method->ssl_dispatch_alert(s);
/* else data is still being written out, we will get written
* some time in the future */
}