I haven't actually seen this in practice, but I have been reading the
code for ssl3_get_record in ssl/s3_pkt.c and I think there might be a bug.
Immediately following the "again" label is this code:
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, s->s3->rbuf.len, 0);
if (n <= 0) return(n); /* error or non-blocking */
s->rstate=SSL_ST_READ_BODY;
(This is lines 311-318 in ssl/s3_pkt from OpenSSL 1.0.1e.)
I think the problem occurs because passing zero for the "extend"
parameter of ssl3_read_n discards any data already pointed to by
s->packet, even if s->packet_length is nonzero.
Suppose, with a non-blocking socket, that a TCP segment containing a
full TLS record and (say) the first two bytes of the next record is the
most recent data received. When we call ssl3_get_record to read the
partial header, ssl3_read_n will read two bytes into s->packet and
return -1 (non-blocking I/O). Later, when more data is available, we
will again call ssl3_get_record to read the rest of the header.
However, doesn't the call to ssl3_read_n actually discard the two bytes
already read?
Have I misread this?
- Ken