/*
- * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
*/
if ((len < s->rlayer.wnum)
|| ((wb->left != 0) && (len < (s->rlayer.wnum + s->rlayer.wpend_tot)))) {
- SSLerr(SSL_F_SSL3_WRITE_BYTES, SSL_R_BAD_LENGTH);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_WRITE_BYTES,
+ SSL_R_BAD_LENGTH);
return -1;
}
if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s)
&& s->early_data_state != SSL_EARLY_DATA_UNAUTH_WRITING) {
i = s->handshake_func(s);
+ /* SSLfatal() already called */
if (i < 0)
return i;
if (i == 0) {
- SSLerr(SSL_F_SSL3_WRITE_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE);
return -1;
}
}
* will happen with non blocking IO
*/
if (wb->left != 0) {
+ /* SSLfatal() already called if appropriate */
i = ssl3_write_pending(s, type, &buf[tot], s->rlayer.wpend_tot,
&tmpwrit);
if (i <= 0) {
packlen *= 4;
if (!ssl3_setup_write_buffer(s, 1, packlen)) {
- SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_MALLOC_FAILURE);
+ /* SSLfatal() already called */
return -1;
}
} else if (tot == len) { /* done? */
if (s->s3->alert_dispatch) {
i = s->method->ssl_dispatch_alert(s);
if (i <= 0) {
+ /* SSLfatal() already called if appropriate */
s->rlayer.wnum = tot;
return i;
}
i = ssl3_write_pending(s, type, &buf[tot], nw, &tmpwrit);
if (i <= 0) {
+ /* SSLfatal() already called if appropriate */
if (i < 0 && (!s->wbio || !BIO_should_retry(s->wbio))) {
/* free jumbo buffer */
ssl3_release_write_buffer(s);
* We should have prevented this when we set max_pipelines so we
* shouldn't get here
*/
- SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_WRITE_BYTES,
+ ERR_R_INTERNAL_ERROR);
return -1;
}
if (maxpipes == 0
* We should have prevented this when we set/get the split and max send
* fragments so we shouldn't get here
*/
- SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_WRITE_BYTES,
+ ERR_R_INTERNAL_ERROR);
return -1;
}
i = do_ssl3_write(s, type, &(buf[tot]), pipelens, numpipes, 0,
&tmpwrit);
if (i <= 0) {
+ /* SSLfatal() already called if appropriate */
/* XXX should we ssl3_release_write_buffer if i<0? */
s->rlayer.wnum = tot;
return i;
* first check if there is a SSL3_BUFFER still being written out. This
* will happen with non blocking IO
*/
- if (RECORD_LAYER_write_pending(&s->rlayer))
+ if (RECORD_LAYER_write_pending(&s->rlayer)) {
+ /* Calls SSLfatal() as required */
return ssl3_write_pending(s, type, buf, totlen, written);
+ }
/* If we have an alert to send, lets send it */
if (s->s3->alert_dispatch) {
i = s->method->ssl_dispatch_alert(s);
- if (i <= 0)
+ if (i <= 0) {
+ /* SSLfatal() already called if appropriate */
return i;
+ }
/* if it went, fall through and send more stuff */
}
- if (s->rlayer.numwpipes < numpipes)
- if (!ssl3_setup_write_buffer(s, numpipes, 0))
+ if (s->rlayer.numwpipes < numpipes) {
+ if (!ssl3_setup_write_buffer(s, numpipes, 0)) {
+ /* SSLfatal() already called */
return -1;
+ }
+ }
if (totlen == 0 && !create_empty_fragment)
return 0;
} else {
/* TODO(siz_t): Convert me */
mac_size = EVP_MD_CTX_size(s->write_hash);
- if (mac_size < 0)
+ if (mac_size < 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
+ }
}
/*
int ret;
ret = do_ssl3_write(s, type, buf, &tmppipelen, 1, 1, &prefix_len);
- if (ret <= 0)
+ if (ret <= 0) {
+ /* SSLfatal() already called if appropriate */
goto err;
+ }
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);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
}
if (!WPACKET_init_static_len(&pkt[0], SSL3_BUFFER_get_buf(wb),
SSL3_BUFFER_get_len(wb), 0)
|| !WPACKET_allocate_bytes(&pkt[0], align, NULL)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
wpinited = 1;
SSL3_BUFFER_get_len(wb), 0)
|| !WPACKET_allocate_bytes(&pkt[0], SSL3_BUFFER_get_offset(wb)
+ prefix_len, NULL)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
wpinited = 1;
if (!WPACKET_init_static_len(thispkt, SSL3_BUFFER_get_buf(wb),
SSL3_BUFFER_get_len(wb), 0)
|| !WPACKET_allocate_bytes(thispkt, align, NULL)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
wpinited++;
/* Clear our SSL3_RECORD structures */
memset(wr, 0, sizeof(wr));
for (j = 0; j < numpipes; j++) {
- unsigned int version = SSL_TREAT_AS_TLS13(s) ? TLS1_VERSION : s->version;
+ unsigned int version = SSL_TREAT_AS_TLS13(s) ? TLS1_2_VERSION
+ : s->version;
unsigned char *compressdata = NULL;
size_t maxcomplen;
unsigned int rectype;
thispkt = &pkt[j];
thiswr = &wr[j];
- SSL3_RECORD_set_type(thiswr, type);
/*
* In TLSv1.3, once encrypting, we always use application data for the
* record type
rectype = SSL3_RT_APPLICATION_DATA;
else
rectype = type;
+ SSL3_RECORD_set_type(thiswr, rectype);
+
/*
* Some servers hang if initial client hello is larger than 256 bytes
* and record version number > TLS 1.0
*/
if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO
- && !s->renegotiate && TLS1_get_version(s) > TLS1_VERSION)
+ && !s->renegotiate
+ && TLS1_get_version(s) > TLS1_VERSION
+ && s->hello_retry_request == SSL_HRR_NONE)
version = TLS1_VERSION;
+ SSL3_RECORD_set_rec_version(thiswr, version);
maxcomplen = pipelens[j];
if (s->compress != NULL)
|| (maxcomplen > 0
&& !WPACKET_reserve_bytes(thispkt, maxcomplen,
&compressdata))) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
if (s->compress != NULL) {
if (!ssl3_do_compress(s, thiswr)
|| !WPACKET_allocate_bytes(thispkt, thiswr->length, NULL)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, SSL_R_COMPRESSION_FAILURE);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ SSL_R_COMPRESSION_FAILURE);
goto err;
}
} else {
if (!WPACKET_memcpy(thispkt, thiswr->input, thiswr->length)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
SSL3_RECORD_reset_input(&wr[j]);
size_t rlen, max_send_fragment;
if (!WPACKET_put_bytes_u8(thispkt, type)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
SSL3_RECORD_add_length(thiswr, 1);
if (padding > max_padding)
padding = max_padding;
if (!WPACKET_memset(thispkt, 0, padding)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
SSL3_RECORD_add_length(thiswr, padding);
if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
|| !s->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
}
* sub-packet
*/
|| !WPACKET_get_length(thispkt, &len)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
* We haven't actually negotiated the version yet, but we're trying to
* send early data - so we need to use the tls13enc function.
*/
- if (tls13_enc(s, wr, numpipes, 1) < 1)
+ if (tls13_enc(s, wr, numpipes, 1) < 1) {
+ if (!ossl_statem_in_error(s)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
+ }
goto err;
+ }
} else {
- if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1)
+ if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1) {
+ if (!ossl_statem_in_error(s)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
+ }
goto err;
+ }
}
for (j = 0; j < numpipes; j++) {
|| (thiswr->length > origlen
&& !WPACKET_allocate_bytes(thispkt,
thiswr->length - origlen, NULL))) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
if (SSL_WRITE_ETM(s) && mac_size != 0) {
if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
|| !s->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
SSL3_RECORD_add_length(thiswr, mac_size);
if (!WPACKET_get_length(thispkt, &len)
|| !WPACKET_close(thispkt)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
}
if (!WPACKET_finish(thispkt)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
*/
if (j > 0) {
/* We should never be pipelining an empty fragment!! */
- SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
*written = SSL3_RECORD_get_length(thiswr);
size_t tmpwrit = 0;
if ((s->rlayer.wpend_tot > len)
- || ((s->rlayer.wpend_buf != buf) &&
- !(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER))
+ || (!(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
+ && (s->rlayer.wpend_buf != buf))
|| (s->rlayer.wpend_type != type)) {
- SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BAD_WRITE_RETRY);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_WRITE_PENDING,
+ SSL_R_BAD_WRITE_RETRY);
return -1;
}
if (i >= 0)
tmpwrit = i;
} else {
- SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BIO_NOT_SET);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_WRITE_PENDING,
+ SSL_R_BIO_NOT_SET);
i = -1;
}
if (i > 0 && tmpwrit == SSL3_BUFFER_get_left(&wb[currbuf])) {
SSL3_RECORD *rr;
SSL3_BUFFER *rbuf;
void (*cb) (const SSL *ssl, int type2, int val) = NULL;
+ int is_tls13 = SSL_IS_TLS13(s);
rbuf = &s->rlayer.rbuf;
if (type == SSL3_RECORD_get_type(rr)
|| (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
&& type == SSL3_RT_HANDSHAKE && recvd_type != NULL
- && !SSL_IS_TLS13(s))) {
+ && !is_tls13)) {
/*
* SSL3_RT_APPLICATION_DATA or
* SSL3_RT_HANDSHAKE or
return -1;
}
- /*
- * In case of record types for which we have 'fragment' storage, fill
- * that so that we can process the data at a fixed place.
- */
- {
- size_t dest_maxlen = 0;
- unsigned char *dest = NULL;
- size_t *dest_len = NULL;
-
- if (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) {
- dest_maxlen = sizeof(s->rlayer.handshake_fragment);
- dest = s->rlayer.handshake_fragment;
- dest_len = &s->rlayer.handshake_fragment_len;
- }
-
- if (dest_maxlen > 0) {
- n = dest_maxlen - *dest_len; /* available space in 'dest' */
- if (SSL3_RECORD_get_length(rr) < n)
- n = SSL3_RECORD_get_length(rr); /* available bytes */
-
- /* now move 'n' bytes: */
- memcpy(dest + *dest_len,
- SSL3_RECORD_get_data(rr) + SSL3_RECORD_get_off(rr), n);
- SSL3_RECORD_add_off(rr, n);
- SSL3_RECORD_sub_length(rr, n);
- *dest_len += n;
- if (SSL3_RECORD_get_length(rr) == 0)
- SSL3_RECORD_set_read(rr);
-
- if (*dest_len < dest_maxlen)
- goto start; /* fragment was too small */
- }
- }
-
/*-
* s->rlayer.handshake_fragment_len == 4 iff rr->type == SSL3_RT_HANDSHAKE;
* (Possibly rr is 'empty' now, i.e. rr->length may be 0.)
*/
- /*
- * If we are a server and get a client hello when renegotiation isn't
- * allowed send back a no renegotiation alert and carry on. WARNING:
- * experimental code, needs reviewing (steve)
- */
- if (s->server &&
- SSL_is_init_finished(s) &&
- (s->version > SSL3_VERSION) &&
- !SSL_IS_TLS13(s) &&
- (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) &&
- (s->rlayer.handshake_fragment_len >= 4) &&
- (s->rlayer.handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) &&
- (s->session != NULL) && (s->session->cipher != NULL) &&
- ((!s->s3->send_connection_binding &&
- !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) ||
- (s->options & SSL_OP_NO_RENEGOTIATION))) {
- SSL3_RECORD_set_length(rr, 0);
- SSL3_RECORD_set_read(rr);
- ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION);
- goto start;
- }
if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) {
unsigned int alert_level, alert_descr;
unsigned char *alert_bytes = SSL3_RECORD_get_data(rr)
cb(s, SSL_CB_READ_ALERT, j);
}
- if (alert_level == SSL3_AL_WARNING) {
+ if (alert_level == SSL3_AL_WARNING
+ || (is_tls13 && alert_descr == SSL_AD_USER_CANCELLED)) {
s->s3->warn_alert = alert_descr;
SSL3_RECORD_set_read(rr);
SSL_R_TOO_MANY_WARN_ALERTS);
return -1;
}
+ }
- if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
- s->shutdown |= SSL_RECEIVED_SHUTDOWN;
- return 0;
- }
- /*
- * Apart from close_notify the only other warning alert in TLSv1.3
- * is user_cancelled - which we just ignore.
- */
- if (SSL_IS_TLS13(s) && alert_descr != SSL_AD_USER_CANCELLED) {
- SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SSL3_READ_BYTES,
- SSL_R_UNKNOWN_ALERT_TYPE);
- return -1;
- }
- /*
- * This is a warning but we receive it if we requested
- * renegotiation and the peer denied it. Terminate with a fatal
- * alert because if application tried to renegotiate it
- * presumably had a good reason and expects it to succeed. In
- * future we might have a renegotiation where we don't care if
- * the peer refused it where we carry on.
- */
- if (alert_descr == SSL_AD_NO_RENEGOTIATION) {
- SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_SSL3_READ_BYTES,
- SSL_R_NO_RENEGOTIATION);
- return -1;
- }
- } else if (alert_level == SSL3_AL_FATAL) {
+ /*
+ * Apart from close_notify the only other warning alert in TLSv1.3
+ * is user_cancelled - which we just ignore.
+ */
+ if (is_tls13 && alert_descr == SSL_AD_USER_CANCELLED) {
+ goto start;
+ } else if (alert_descr == SSL_AD_CLOSE_NOTIFY
+ && (is_tls13 || alert_level == SSL3_AL_WARNING)) {
+ s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+ return 0;
+ } else if (alert_level == SSL3_AL_FATAL || is_tls13) {
char tmp[16];
s->rwstate = SSL_NOTHING;
SSL3_RECORD_set_read(rr);
SSL_CTX_remove_session(s->session_ctx, s->session);
return 0;
- } else {
- SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SSL3_READ_BYTES,
- SSL_R_UNKNOWN_ALERT_TYPE);
+ } else if (alert_descr == SSL_AD_NO_RENEGOTIATION) {
+ /*
+ * This is a warning but we receive it if we requested
+ * renegotiation and the peer denied it. Terminate with a fatal
+ * alert because if application tried to renegotiate it
+ * presumably had a good reason and expects it to succeed. In
+ * future we might have a renegotiation where we don't care if
+ * the peer refused it where we carry on.
+ */
+ SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_SSL3_READ_BYTES,
+ SSL_R_NO_RENEGOTIATION);
return -1;
+ } else if (alert_level == SSL3_AL_WARNING) {
+ /* We ignore any other warning alert in TLSv1.2 and below */
+ goto start;
}
- goto start;
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SSL3_READ_BYTES,
+ SSL_R_UNKNOWN_ALERT_TYPE);
+ return -1;
}
- if (s->shutdown & SSL_SENT_SHUTDOWN) { /* but we have not received a
- * shutdown */
+ /*
+ * If we've sent a close_notify but not yet received one back then ditch
+ * anything we read.
+ */
+ if ((s->shutdown & SSL_SENT_SHUTDOWN) != 0 ) {
+ /*
+ * In TLSv1.3 this could get problematic if we receive a KeyUpdate
+ * message after we sent a close_notify because we're about to ditch it,
+ * so we won't be able to read a close_notify sent afterwards! We don't
+ * support that.
+ */
s->rwstate = SSL_NOTHING;
SSL3_RECORD_set_length(rr, 0);
SSL3_RECORD_set_read(rr);
+
+ if (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE
+ && (s->mode & SSL_MODE_AUTO_RETRY) != 0)
+ goto start;
return 0;
}
+ /*
+ * For handshake data we have 'fragment' storage, so fill that so that we
+ * can process the header at a fixed place. This is done after the
+ * "SHUTDOWN" code above to avoid filling the fragment storage with data
+ * that we're just going to discard.
+ */
+ if (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) {
+ size_t dest_maxlen = sizeof(s->rlayer.handshake_fragment);
+ unsigned char *dest = s->rlayer.handshake_fragment;
+ size_t *dest_len = &s->rlayer.handshake_fragment_len;
+
+ n = dest_maxlen - *dest_len; /* available space in 'dest' */
+ if (SSL3_RECORD_get_length(rr) < n)
+ n = SSL3_RECORD_get_length(rr); /* available bytes */
+
+ /* now move 'n' bytes: */
+ memcpy(dest + *dest_len,
+ SSL3_RECORD_get_data(rr) + SSL3_RECORD_get_off(rr), n);
+ SSL3_RECORD_add_off(rr, n);
+ SSL3_RECORD_sub_length(rr, n);
+ *dest_len += n;
+ if (SSL3_RECORD_get_length(rr) == 0)
+ SSL3_RECORD_set_read(rr);
+
+ if (*dest_len < dest_maxlen)
+ goto start; /* fragment was too small */
+ }
+
if (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC) {
SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
SSL_R_CCS_RECEIVED_EARLY);