From: Matt Caswell Date: Thu, 7 Apr 2022 16:35:36 +0000 (+0100) Subject: Transfer the functionality from ssl3_read_n to the new record layer X-Git-Tag: openssl-3.2.0-alpha1~2255 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=e2d5742b1460c45bf39094ea08e4e85a8f507ea8;p=thirdparty%2Fopenssl.git Transfer the functionality from ssl3_read_n to the new record layer This transfers the low level function ssl3_read_n to the new record layer. We temporarily make the read_n function a top level record layer function. Eventually, in later commits in this refactor, we will remove it as a top level function and it will just be called from read_record. Reviewed-by: Hugo Landau Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/18132) --- diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 7c9a516c137..9ab7c0fdd48 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1351,6 +1351,7 @@ SSL_R_EXCESSIVE_MESSAGE_SIZE:152:excessive message size SSL_R_EXTENSION_NOT_RECEIVED:279:extension not received SSL_R_EXTRA_DATA_IN_MESSAGE:153:extra data in message SSL_R_EXT_LENGTH_MISMATCH:163:ext length mismatch +SSL_R_FAILED_TO_GET_PARAMETER:316:failed to get parameter SSL_R_FAILED_TO_INIT_ASYNC:405:failed to init async SSL_R_FRAGMENTED_CLIENT_HELLO:401:fragmented client hello SSL_R_GOT_A_FIN_BEFORE_A_CCS:154:got a fin before a ccs @@ -1457,6 +1458,7 @@ SSL_R_PSK_NO_CLIENT_CB:224:psk no client cb SSL_R_PSK_NO_SERVER_CB:225:psk no server cb SSL_R_READ_BIO_NOT_SET:211:read bio not set SSL_R_READ_TIMEOUT_EXPIRED:312:read timeout expired +SSL_R_RECORD_LAYER_FAILURE:313:record layer failure SSL_R_RECORD_LENGTH_MISMATCH:213:record length mismatch SSL_R_RECORD_TOO_SMALL:298:record too small SSL_R_RENEGOTIATE_EXT_TOO_LONG:335:renegotiate ext too long diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index a8f875a59ab..1d866368f7e 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -555,6 +555,13 @@ extern "C" { /* OSSL_DECODER input type if a decoder is used by the store */ #define OSSL_STORE_PARAM_INPUT_TYPE "input-type" /* UTF8_STRING */ + +/* Libssl record layer */ + +#define OSSL_LIBSSL_RECORD_LAYER_PARAM_OPTIONS "options" +#define OSSL_LIBSSL_RECORD_LAYER_PARAM_MODE "mode" +#define OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD "read_ahead" + # ifdef __cplusplus } # endif diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index a4746d70b5b..e984fe375e3 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -119,6 +119,7 @@ # define SSL_R_EXTENSION_NOT_RECEIVED 279 # define SSL_R_EXTRA_DATA_IN_MESSAGE 153 # define SSL_R_EXT_LENGTH_MISMATCH 163 +# define SSL_R_FAILED_TO_GET_PARAMETER 316 # define SSL_R_FAILED_TO_INIT_ASYNC 405 # define SSL_R_FRAGMENTED_CLIENT_HELLO 401 # define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154 @@ -222,6 +223,7 @@ # define SSL_R_PSK_NO_SERVER_CB 225 # define SSL_R_READ_BIO_NOT_SET 211 # define SSL_R_READ_TIMEOUT_EXPIRED 312 +# define SSL_R_RECORD_LAYER_FAILURE 313 # define SSL_R_RECORD_LENGTH_MISMATCH 213 # define SSL_R_RECORD_TOO_SMALL 298 # define SSL_R_RENEGOTIATE_EXT_TOO_LONG 335 diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index 3b76065be9e..e38c6d677f0 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -490,13 +490,13 @@ int DTLSv1_listen(SSL *ssl, BIO_ADDR *client) /* ERR_raise() already called */ return -1; } - buf = RECORD_LAYER_get_rbuf(&s->rlayer)->buf; + buf = s->rrlmethod->get0_rbuf(s->rrl)->buf; wbuf = RECORD_LAYER_get_wbuf(&s->rlayer)[0].buf; #if defined(SSL3_ALIGN_PAYLOAD) # if SSL3_ALIGN_PAYLOAD != 0 /* * Using SSL3_RT_HEADER_LENGTH here instead of DTLS1_RT_HEADER_LENGTH for - * consistency with ssl3_read_n. In practice it should make no difference + * consistency with read_n. In practice it should make no difference * for sensible values of SSL3_ALIGN_PAYLOAD because the difference between * SSL3_RT_HEADER_LENGTH and DTLS1_RT_HEADER_LENGTH is exactly 8 */ diff --git a/ssl/ktls.c b/ssl/ktls.c index 67499c35074..78e6ecd554b 100644 --- a/ssl/ktls.c +++ b/ssl/ktls.c @@ -20,7 +20,7 @@ */ static int count_unprocessed_records(SSL_CONNECTION *s) { - SSL3_BUFFER *rbuf = RECORD_LAYER_get_rbuf(&s->rlayer); + SSL3_BUFFER *rbuf = s->rrlmethod->get0_rbuf(s->rrl); PACKET pkt, subpkt; int count = 0; diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c index 9f90bee9d91..dd78921948f 100644 --- a/ssl/record/rec_layer_d1.c +++ b/ssl/record/rec_layer_d1.c @@ -130,11 +130,10 @@ static int dtls1_copy_record(SSL_CONNECTION *s, pitem *item) rdata = (DTLS1_RECORD_DATA *)item->data; - SSL3_BUFFER_release(&s->rlayer.rbuf); + SSL3_BUFFER_release(s->rrlmethod->get0_rbuf(s->rrl)); - s->rlayer.packet = rdata->packet; - s->rlayer.packet_length = rdata->packet_length; - memcpy(&s->rlayer.rbuf, &(rdata->rbuf), sizeof(SSL3_BUFFER)); + s->rrlmethod->set0_packet(s->rrl, rdata->packet, rdata->packet_length); + memcpy(s->rrlmethod->get0_rbuf(s->rrl), &(rdata->rbuf), sizeof(SSL3_BUFFER)); memcpy(&s->rlayer.rrec, &(rdata->rrec), sizeof(SSL3_RECORD)); /* Set proper sequence number for mac calculation */ @@ -165,9 +164,9 @@ int dtls1_buffer_record(SSL_CONNECTION *s, record_pqueue *queue, return -1; } - rdata->packet = s->rlayer.packet; - rdata->packet_length = s->rlayer.packet_length; - memcpy(&(rdata->rbuf), &s->rlayer.rbuf, sizeof(SSL3_BUFFER)); + rdata->packet = s->rrlmethod->get0_packet(s->rrl); + rdata->packet_length = s->rrlmethod->get_packet_length(s->rrl); + memcpy(&(rdata->rbuf), s->rrlmethod->get0_rbuf(s->rrl), sizeof(SSL3_BUFFER)); memcpy(&(rdata->rrec), &s->rlayer.rrec, sizeof(SSL3_RECORD)); item->data = rdata; @@ -182,9 +181,8 @@ int dtls1_buffer_record(SSL_CONNECTION *s, record_pqueue *queue, } #endif - s->rlayer.packet = NULL; - s->rlayer.packet_length = 0; - memset(&s->rlayer.rbuf, 0, sizeof(s->rlayer.rbuf)); + s->rrlmethod->set0_packet(s->rrl, NULL, 0); + memset(s->rrlmethod->get0_rbuf(s->rrl), 0, sizeof(SSL3_BUFFER)); memset(&s->rlayer.rrec, 0, sizeof(s->rlayer.rrec)); if (!ssl3_setup_buffers(s)) { @@ -247,7 +245,7 @@ int dtls1_process_buffered_records(SSL_CONNECTION *s) rr = RECORD_LAYER_get_rrec(&s->rlayer); - rb = RECORD_LAYER_get_rbuf(&s->rlayer); + rb = s->rrlmethod->get0_rbuf(s->rrl); if (SSL3_BUFFER_get_left(rb) > 0) { /* @@ -293,7 +291,7 @@ int dtls1_process_buffered_records(SSL_CONNECTION *s) } /* dump this record */ rr->length = 0; - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); continue; } @@ -356,7 +354,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, if (sc == NULL) return -1; - if (!SSL3_BUFFER_is_initialised(&sc->rlayer.rbuf)) { + if (!SSL3_BUFFER_is_initialised(sc->rrlmethod->get0_rbuf(sc->rrl))) { /* Not initialized yet */ if (!ssl3_setup_buffers(sc)) { /* SSLfatal() already called */ @@ -689,7 +687,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, SSL3_RECORD_set_length(rr, 0); SSL3_RECORD_set_read(rr); if (!(sc->mode & SSL_MODE_AUTO_RETRY)) { - if (SSL3_BUFFER_get_left(&sc->rlayer.rbuf) == 0) { + if (SSL3_BUFFER_get_left(sc->rrlmethod->get0_rbuf(sc->rrl)) == 0) { /* no read-ahead left? */ BIO *bio; @@ -725,7 +723,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, return -1; if (!(sc->mode & SSL_MODE_AUTO_RETRY)) { - if (SSL3_BUFFER_get_left(&sc->rlayer.rbuf) == 0) { + if (SSL3_BUFFER_get_left(sc->rrlmethod->get0_rbuf(sc->rrl)) == 0) { /* no read-ahead left? */ BIO *bio; /* diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 05b49a21e3a..d7791cf9353 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -152,8 +152,7 @@ void SSL_set_default_read_buffer_len(SSL *s, size_t len) if (sc == NULL) return; - - SSL3_BUFFER_set_default_len(RECORD_LAYER_get_rbuf(&sc->rlayer), len); + SSL3_BUFFER_set_default_len(sc->rrlmethod->get0_rbuf(sc->rrl), len); } const char *SSL_rstate_string_long(const SSL *s) @@ -194,186 +193,6 @@ const char *SSL_rstate_string(const SSL *s) } } -/* - * Return values are as per SSL_read() - */ -int ssl3_read_n(SSL_CONNECTION *s, size_t n, size_t max, int extend, - int clearold, size_t *readbytes) -{ - /* - * If extend == 0, obtain new n-byte packet; if extend == 1, increase - * packet by another n bytes. The packet will be in the sub-array of - * s->rlayer.rbuf.buf specified by s->rlayer.packet and - * s->rlayer.packet_length. (If s->rlayer.read_ahead is set, 'max' bytes may - * be stored in rbuf [plus s->rlayer.packet_length bytes if extend == 1].) - * if clearold == 1, move the packet to the start of the buffer; if - * clearold == 0 then leave any old packets where they were - */ - size_t len, left, align = 0; - unsigned char *pkt; - SSL3_BUFFER *rb; - - if (n == 0) - return 0; - - rb = &s->rlayer.rbuf; - if (rb->buf == NULL) - if (!ssl3_setup_read_buffer(s)) { - /* SSLfatal() already called */ - return -1; - } - - left = rb->left; -#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 - align = (size_t)rb->buf + SSL3_RT_HEADER_LENGTH; - align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD); -#endif - - if (!extend) { - /* start with empty packet ... */ - 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->rlayer.packet = rb->buf + rb->offset; - s->rlayer.packet_length = 0; - /* ... now we can act as if 'extend' was set */ - } - - len = s->rlayer.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->rlayer.packet != pkt && clearold == 1) { - memmove(pkt, s->rlayer.packet, len + left); - s->rlayer.packet = pkt; - rb->offset = len + align; - } - - /* - * For DTLS/UDP reads should not span multiple packets because the read - * operation returns the whole packet at once (as long as it fits into - * the buffer). - */ - if (SSL_CONNECTION_IS_DTLS(s)) { - if (left == 0 && extend) - return 0; - if (left > 0 && n > left) - n = left; - } - - /* if there is enough in the buffer from a previous read, take some */ - if (left >= n) { - s->rlayer.packet_length += n; - rb->left = left - n; - rb->offset += n; - *readbytes = n; - return 1; - } - - /* else we need to read more data */ - - if (n > rb->len - rb->offset) { - /* does not happen */ - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return -1; - } - - /* - * Ktls always reads full records. - * Also, we always act like read_ahead is set for DTLS. - */ - if (!BIO_get_ktls_recv(s->rbio) && !s->rlayer.read_ahead - && !SSL_CONNECTION_IS_DTLS(s)) { - /* ignore max parameter */ - max = n; - } else { - if (max < n) - max = n; - if (max > rb->len - rb->offset) - max = rb->len - rb->offset; - } - - while (left < n) { - size_t bioread = 0; - int ret; - - /* - * 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; - ret = BIO_read(s->rbio, pkt + len + left, max - left); - if (ret >= 0) - bioread = ret; - if (ret <= 0 - && !BIO_should_retry(s->rbio) - && BIO_eof(s->rbio)) { - if (s->options & SSL_OP_IGNORE_UNEXPECTED_EOF) { - SSL_set_shutdown(SSL_CONNECTION_GET_SSL(s), - SSL_RECEIVED_SHUTDOWN); - s->s3.warn_alert = SSL_AD_CLOSE_NOTIFY; - } else { - SSLfatal(s, SSL_AD_DECODE_ERROR, - SSL_R_UNEXPECTED_EOF_WHILE_READING); - } - } - } else { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_READ_BIO_NOT_SET); - ret = -1; - } - - if (ret <= 0) { - rb->left = left; - if ((s->mode & SSL_MODE_RELEASE_BUFFERS) != 0 - && !SSL_CONNECTION_IS_DTLS(s)) - if (len + left == 0) - ssl3_release_read_buffer(s); - return ret; - } - left += bioread; - /* - * reads should *never* span multiple packets for DTLS because the - * underlying transport protocol is message oriented as opposed to - * byte oriented as in the TLS case. - */ - if (SSL_CONNECTION_IS_DTLS(s)) { - if (n > left) - n = left; /* makes the while condition false */ - } - } - - /* done reading, now the book-keeping */ - rb->offset += n; - rb->left = left - n; - s->rlayer.packet_length += n; - s->rwstate = SSL_NOTHING; - *readbytes = n; - return 1; -} /* * Call this to write data in records of type 'type' It will return <= 0 if @@ -1321,7 +1140,7 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf, is_tls13 = SSL_CONNECTION_IS_TLS13(s); - rbuf = &s->rlayer.rbuf; + rbuf = s->rrlmethod->get0_rbuf(s->rrl); if (!SSL3_BUFFER_is_initialised(rbuf)) { /* Not initialized yet */ diff --git a/ssl/record/record_local.h b/ssl/record/record_local.h index 31691787b17..7d92c973ec4 100644 --- a/ssl/record/record_local.h +++ b/ssl/record/record_local.h @@ -36,9 +36,6 @@ #define RECORD_LAYER_clear_first_record(rl) ((rl)->is_first_record = 0) #define DTLS_RECORD_LAYER_get_r_epoch(rl) ((rl)->d->r_epoch) -__owur int ssl3_read_n(SSL_CONNECTION *s, size_t n, size_t max, int extend, - int clearold, size_t *readbytes); - DTLS1_BITMAP *dtls1_get_bitmap(SSL_CONNECTION *s, SSL3_RECORD *rr, unsigned int *is_next_epoch); int dtls1_process_buffered_records(SSL_CONNECTION *s); diff --git a/ssl/record/recordmethod.h b/ssl/record/recordmethod.h index 22dfa7afe79..da5739f8e74 100644 --- a/ssl/record/recordmethod.h +++ b/ssl/record/recordmethod.h @@ -69,6 +69,12 @@ typedef struct ossl_record_layer_st OSSL_RECORD_LAYER; #define OSSL_RECORD_PROTECTION_LEVEL_APPLICATION 3 +#define OSSL_RECORD_RETURN_SUCCESS 1 +#define OSSL_RECORD_RETURN_RETRY 0 +#define OSSL_RECORD_RETURN_NON_FATAL_ERR -1 +#define OSSL_RECORD_RETURN_FATAL -2 +#define OSSL_RECORD_RETURN_EOF -3 + /* * Template for creating a record. A record consists of the |type| of data it * will contain (e.g. alert, handshake, application data, etc) along with an @@ -237,4 +243,35 @@ struct ossl_record_method_st { */ void (*release_record)(OSSL_RECORD_LAYER *rl, void *rechandle); + /* + * In the event that a fatal error is returned from the functions above then + * get_alert_code() can be called to obtain a more details identifier for + * the error. In (D)TLS this is the alert description code. + */ + int (*get_alert_code)(OSSL_RECORD_LAYER *rl); + + /* + * Update the transport BIO from the one originally set in the + * new_record_layer call + */ + int (*set1_bio)(OSSL_RECORD_LAYER *rl, BIO *bio); + + /* + * TODO(RECLAYER): Remove these. These function pointers are temporary hacks + * during the record layer refactoring. They need to be removed before the + * refactor is complete. + */ + int (*read_n)(OSSL_RECORD_LAYER *rl, size_t n, size_t max, int extend, + int clearold, size_t *readbytes); + SSL3_BUFFER *(*get0_rbuf)(OSSL_RECORD_LAYER *rl); + unsigned char *(*get0_packet)(OSSL_RECORD_LAYER *rl); + void (*set0_packet)(OSSL_RECORD_LAYER *rl, unsigned char *packet, + size_t packetlen); + size_t (*get_packet_length)(OSSL_RECORD_LAYER *rl); + void (*reset_packet_length)(OSSL_RECORD_LAYER *rl); }; + + +/* Standard built-in record methods */ +extern const OSSL_RECORD_METHOD ossl_tls_record_method; +extern const OSSL_RECORD_METHOD ossl_dtls_record_method; \ No newline at end of file diff --git a/ssl/record/ssl3_buffer.c b/ssl/record/ssl3_buffer.c index 95149bfc052..514f522297e 100644 --- a/ssl/record/ssl3_buffer.c +++ b/ssl/record/ssl3_buffer.c @@ -40,7 +40,7 @@ int ssl3_setup_read_buffer(SSL_CONNECTION *s) size_t len, align = 0, headerlen; SSL3_BUFFER *b; - b = RECORD_LAYER_get_rbuf(&s->rlayer); + b = s->rrlmethod->get0_rbuf(s->rrl); if (SSL_CONNECTION_IS_DTLS(s)) headerlen = DTLS1_RT_HEADER_LENGTH; @@ -177,7 +177,7 @@ int ssl3_release_read_buffer(SSL_CONNECTION *s) { SSL3_BUFFER *b; - b = RECORD_LAYER_get_rbuf(&s->rlayer); + b = s->rrlmethod->get0_rbuf(s->rrl); if (s->options & SSL_OP_CLEANSE_PLAINTEXT) OPENSSL_cleanse(b->buf, b->len); OPENSSL_free(b->buf); diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c index 02bf81b9fa8..0225a85b90e 100644 --- a/ssl/record/ssl3_record.c +++ b/ssl/record/ssl3_record.c @@ -73,7 +73,7 @@ static int ssl3_record_app_data_waiting(SSL_CONNECTION *s) size_t left, len; unsigned char *p; - rbuf = RECORD_LAYER_get_rbuf(&s->rlayer); + rbuf = s->rrlmethod->get0_rbuf(s->rrl); p = SSL3_BUFFER_get_buf(rbuf); if (p == NULL) @@ -149,6 +149,54 @@ int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length, return 1; } +static int tls_handle_rlayer_return(SSL_CONNECTION *s, int ret, char *file, + int line) +{ + SSL *ssl = SSL_CONNECTION_GET_SSL(s); + + if (ret == OSSL_RECORD_RETURN_RETRY) { + s->rwstate = SSL_READING; + ret = -1; + } else { + s->rwstate = SSL_NOTHING; + if (ret == OSSL_RECORD_RETURN_EOF) { + if (s->options & SSL_OP_IGNORE_UNEXPECTED_EOF) { + SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); + s->s3.warn_alert = SSL_AD_CLOSE_NOTIFY; + } else { + ERR_new(); + ERR_set_debug(file, line, 0); + ossl_statem_fatal(s, SSL_AD_DECODE_ERROR, + SSL_R_UNEXPECTED_EOF_WHILE_READING, NULL); + } + } else if (ret == OSSL_RECORD_RETURN_FATAL) { + ERR_new(); + ERR_set_debug(file, line, 0); + ossl_statem_fatal(s, s->rrlmethod->get_alert_code(s->rrl), + SSL_R_RECORD_LAYER_FAILURE, NULL); + } + /* + * The record layer distinguishes the cases of EOF, non-fatal + * err and retry. Upper layers do not. + * If we got a retry or success then *ret is already correct, + * otherwise we need to convert the return value. + */ + /* + * TODO(RECLAYER): What does a non fatal err that isn't a retry even + * mean??? + */ + if (ret == OSSL_RECORD_RETURN_NON_FATAL_ERR || ret == OSSL_RECORD_RETURN_EOF) + ret = 0; + else if (ret < OSSL_RECORD_RETURN_NON_FATAL_ERR) + ret = -1; + } + + return ret; +} + +# define HANDLE_RLAYER_RETURN(s, ret) \ + tls_handle_rlayer_return(s, ret, OPENSSL_FILE, OPENSSL_LINE) + /* * MAX_EMPTY_RECORDS defines the number of consecutive, empty records that * will be processed per call to ssl3_get_record. Without this limit an @@ -192,7 +240,8 @@ int ssl3_get_record(SSL_CONNECTION *s) SSL *ssl = SSL_CONNECTION_GET_SSL(s); rr = RECORD_LAYER_get_rrec(&s->rlayer); - rbuf = RECORD_LAYER_get_rbuf(&s->rlayer); + rbuf = s->rrlmethod->get0_rbuf(s->rrl); + max_recs = s->max_pipelines; if (max_recs == 0) max_recs = 1; @@ -209,14 +258,15 @@ int ssl3_get_record(SSL_CONNECTION *s) /* check if we have the header */ if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) || - (RECORD_LAYER_get_packet_length(&s->rlayer) - < SSL3_RT_HEADER_LENGTH)) { + (s->rrlmethod->get_packet_length(s->rrl) < SSL3_RT_HEADER_LENGTH)) { size_t sslv2len; unsigned int type; - rret = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, - SSL3_BUFFER_get_len(rbuf), 0, - num_recs == 0 ? 1 : 0, &n); + rret = HANDLE_RLAYER_RETURN(s, + s->rrlmethod->read_n(s->rrl, SSL3_RT_HEADER_LENGTH, + SSL3_BUFFER_get_len(rbuf), 0, + num_recs == 0 ? 1 : 0, &n)); + if (rret <= 0) { #ifndef OPENSSL_NO_KTLS if (!using_ktls || rret == 0) @@ -242,9 +292,9 @@ int ssl3_get_record(SSL_CONNECTION *s) } RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY); - p = RECORD_LAYER_get_packet(&s->rlayer); - if (!PACKET_buf_init(&pkt, RECORD_LAYER_get_packet(&s->rlayer), - RECORD_LAYER_get_packet_length(&s->rlayer))) { + p = s->rrlmethod->get0_packet(s->rrl); + if (!PACKET_buf_init(&pkt, p, + s->rrlmethod->get_packet_length(s->rrl))) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return -1; } @@ -344,7 +394,7 @@ int ssl3_get_record(SSL_CONNECTION *s) if (RECORD_LAYER_is_first_record(&s->rlayer)) { /* Go back to start of packet, look at the five bytes * that we have. */ - p = RECORD_LAYER_get_packet(&s->rlayer); + p = s->rrlmethod->get0_packet(s->rrl); if (HAS_PREFIX((char *)p, "GET ") || HAS_PREFIX((char *)p, "POST ") || HAS_PREFIX((char *)p, "HEAD ") || @@ -449,7 +499,8 @@ int ssl3_get_record(SSL_CONNECTION *s) if (more > 0) { /* now s->rlayer.packet_length == SSL3_RT_HEADER_LENGTH */ - rret = ssl3_read_n(s, more, more, 1, 0, &n); + rret = HANDLE_RLAYER_RETURN(s, + s->rrlmethod->read_n(s->rrl, more, more, 1, 0, &n)); if (rret <= 0) return rret; /* error or non-blocking io */ } @@ -464,10 +515,10 @@ int ssl3_get_record(SSL_CONNECTION *s) */ if (thisrr->rec_version == SSL2_VERSION) { thisrr->input = - &(RECORD_LAYER_get_packet(&s->rlayer)[SSL2_RT_HEADER_LENGTH]); + &(s->rrlmethod->get0_packet(s->rrl)[SSL2_RT_HEADER_LENGTH]); } else { thisrr->input = - &(RECORD_LAYER_get_packet(&s->rlayer)[SSL3_RT_HEADER_LENGTH]); + &(s->rrlmethod->get0_packet(s->rrl)[SSL3_RT_HEADER_LENGTH]); } /* @@ -493,7 +544,7 @@ int ssl3_get_record(SSL_CONNECTION *s) num_recs++; /* we have pulled in a full packet so zero things */ - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); RECORD_LAYER_clear_first_record(&s->rlayer); } while (num_recs < max_recs && thisrr->type == SSL3_RT_APPLICATION_DATA @@ -1543,7 +1594,7 @@ int dtls1_process_record(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap) * At this point, s->rlayer.packet_length == SSL3_RT_HEADER_LNGTH + rr->length, * and we have that many bytes in s->rlayer.packet */ - rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[DTLS1_RT_HEADER_LENGTH]); + rr->input = &(s->rrlmethod->get0_packet(s->rrl)[DTLS1_RT_HEADER_LENGTH]); /* * ok, we can now read from 's->rlayer.packet' data into 'rr'. rr->input @@ -1624,7 +1675,7 @@ int dtls1_process_record(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap) } /* For DTLS we simply ignore bad packets. */ rr->length = 0; - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); goto end; } ERR_clear_last_mark(); @@ -1651,7 +1702,7 @@ int dtls1_process_record(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap) if (enc_err == 0) { /* decryption failed, silently discard message */ rr->length = 0; - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); goto end; } @@ -1689,7 +1740,7 @@ int dtls1_process_record(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap) */ /* we have pulled in a full packet so zero things */ - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); /* Mark receipt of record. */ dtls1_record_bitmap_update(s, bitmap); @@ -1750,9 +1801,10 @@ int dtls1_get_record(SSL_CONNECTION *s) /* check if we have the header */ if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) || - (RECORD_LAYER_get_packet_length(&s->rlayer) < DTLS1_RT_HEADER_LENGTH)) { - rret = ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, - SSL3_BUFFER_get_len(&s->rlayer.rbuf), 0, 1, &n); + (s->rrlmethod->get_packet_length(s->rrl) < DTLS1_RT_HEADER_LENGTH)) { + rret = HANDLE_RLAYER_RETURN(s, + s->rrlmethod->read_n(s->rrl, DTLS1_RT_HEADER_LENGTH, + SSL3_BUFFER_get_len(s->rrlmethod->get0_rbuf(s->rrl)), 0, 1, &n)); /* read timeout is handled by dtls1_read_bytes */ if (rret <= 0) { /* SSLfatal() already called if appropriate */ @@ -1760,15 +1812,14 @@ int dtls1_get_record(SSL_CONNECTION *s) } /* this packet contained a partial record, dump it */ - if (RECORD_LAYER_get_packet_length(&s->rlayer) != - DTLS1_RT_HEADER_LENGTH) { - RECORD_LAYER_reset_packet_length(&s->rlayer); + if (s->rrlmethod->get_packet_length(s->rrl) != DTLS1_RT_HEADER_LENGTH) { + s->rrlmethod->reset_packet_length(s->rrl); goto again; } RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY); - p = RECORD_LAYER_get_packet(&s->rlayer); + p = s->rrlmethod->get0_packet(s->rrl); if (s->msg_callback) s->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH, @@ -1798,7 +1849,7 @@ int dtls1_get_record(SSL_CONNECTION *s) /* unexpected version, silently discard */ rr->length = 0; rr->read = 1; - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); goto again; } } @@ -1807,7 +1858,7 @@ int dtls1_get_record(SSL_CONNECTION *s) /* wrong version, silently discard record */ rr->length = 0; rr->read = 1; - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); goto again; } @@ -1815,7 +1866,7 @@ int dtls1_get_record(SSL_CONNECTION *s) /* record too long, silently discard it */ rr->length = 0; rr->read = 1; - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); goto again; } @@ -1825,7 +1876,7 @@ int dtls1_get_record(SSL_CONNECTION *s) /* record too long, silently discard it */ rr->length = 0; rr->read = 1; - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); goto again; } @@ -1835,19 +1886,20 @@ int dtls1_get_record(SSL_CONNECTION *s) /* s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data */ if (rr->length > - RECORD_LAYER_get_packet_length(&s->rlayer) - DTLS1_RT_HEADER_LENGTH) { + s->rrlmethod->get_packet_length(s->rrl) - DTLS1_RT_HEADER_LENGTH) { /* now s->rlayer.packet_length == DTLS1_RT_HEADER_LENGTH */ more = rr->length; - rret = ssl3_read_n(s, more, more, 1, 1, &n); + rret = HANDLE_RLAYER_RETURN(s, + s->rrlmethod->read_n(s->rrl, more, more, 1, 1, &n)); /* this packet contained a partial record, dump it */ if (rret <= 0 || n != more) { if (ossl_statem_in_error(s)) { - /* ssl3_read_n() called SSLfatal() */ + /* read_n() called SSLfatal() */ return -1; } rr->length = 0; rr->read = 1; - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); goto again; } @@ -1863,7 +1915,7 @@ int dtls1_get_record(SSL_CONNECTION *s) bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); if (bitmap == NULL) { rr->length = 0; - RECORD_LAYER_reset_packet_length(&s->rlayer); /* dump this record */ + s->rrlmethod->reset_packet_length(s->rrl); /* dump this record */ goto again; /* get another record */ } #ifndef OPENSSL_NO_SCTP @@ -1874,7 +1926,7 @@ int dtls1_get_record(SSL_CONNECTION *s) if (!dtls1_record_replay_check(s, bitmap)) { rr->length = 0; rr->read = 1; - RECORD_LAYER_reset_packet_length(&s->rlayer); /* dump this record */ + s->rrlmethod->reset_packet_length(s->rrl); /* dump this record */ goto again; /* get another record */ } #ifndef OPENSSL_NO_SCTP @@ -1903,7 +1955,7 @@ int dtls1_get_record(SSL_CONNECTION *s) } rr->length = 0; rr->read = 1; - RECORD_LAYER_reset_packet_length(&s->rlayer); + s->rrlmethod->reset_packet_length(s->rrl); goto again; } @@ -1914,7 +1966,7 @@ int dtls1_get_record(SSL_CONNECTION *s) } rr->length = 0; rr->read = 1; - RECORD_LAYER_reset_packet_length(&s->rlayer); /* dump this record */ + s->rrlmethod->reset_packet_length(s->rrl); /* dump this record */ goto again; /* get another record */ } @@ -1935,9 +1987,9 @@ int dtls_buffer_listen_record(SSL_CONNECTION *s, size_t len, unsigned char *seq, memcpy(rr->seq_num, seq, sizeof(rr->seq_num)); rr->off = off; - s->rlayer.packet = RECORD_LAYER_get_rbuf(&s->rlayer)->buf; - s->rlayer.packet_length = DTLS1_RT_HEADER_LENGTH + len; - rr->data = s->rlayer.packet + DTLS1_RT_HEADER_LENGTH; + s->rrlmethod->set0_packet(s->rrl, s->rrlmethod->get0_rbuf(s->rrl)->buf, + DTLS1_RT_HEADER_LENGTH + len); + rr->data = s->rrlmethod->get0_packet(s->rrl) + DTLS1_RT_HEADER_LENGTH; if (dtls1_buffer_record(s, &(s->rlayer.d->processed_rcds), SSL3_RECORD_get_seq_num(s->rlayer.rrec)) <= 0) { diff --git a/ssl/record/tlsrecord.c b/ssl/record/tlsrecord.c index 51fb5687a8d..c262eefd199 100644 --- a/ssl/record/tlsrecord.c +++ b/ssl/record/tlsrecord.c @@ -9,29 +9,383 @@ #include #include +#include +#include +#include "internal/e_os.h" +#include "record.h" #include "recordmethod.h" struct ossl_record_layer_st { - /* Placeholder until we have real data to store */ - int dummy; + int isdtls; + int version; + int role; + int direction; + BIO *bio; + /* Types match the equivalent structures in the SSL object */ + uint64_t options; + /* + * TODO(RECLAYER): Should we take the opportunity to make this uint64_t + * even though upper layer continue to use uint32_t? + */ + uint32_t mode; + + /* read IO goes into here */ + SSL3_BUFFER rbuf; + + /* used internally to point at a raw packet */ + unsigned char *packet; + size_t packet_length; + + int alert; + + /* + * Read as many input bytes as possible (for + * non-blocking reads) + * TODO(RECLAYER): Why isn't this just an option? + */ + int read_ahead; }; +static int tls_set1_bio(OSSL_RECORD_LAYER *rl, BIO *bio); + +# define SSL_AD_NO_ALERT -1 + +static void rlayer_fatal(OSSL_RECORD_LAYER *rl, int al, int reason, + const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + ERR_vset_error(ERR_LIB_SSL, reason, fmt, args); + va_end(args); + + rl->alert = al; +} + + +# define RLAYERfatal(rl, al, r) RLAYERfatal_data((rl), (al), (r), NULL) +# define RLAYERfatal_data \ + (ERR_new(), \ + ERR_set_debug(OPENSSL_FILE, OPENSSL_LINE, OPENSSL_FUNC), \ + rlayer_fatal) + +static int rlayer_allow_compression(OSSL_RECORD_LAYER *rl) +{ + if (rl->options & SSL_OP_NO_COMPRESSION) + return 0; +#if 0 + /* TODO(RECLAYER): Implement ssl_security inside the record layer */ + return ssl_security(s, SSL_SECOP_COMPRESSION, 0, 0, NULL); +#else + return 1; +#endif +} + +static int rlayer_setup_read_buffer(OSSL_RECORD_LAYER *rl) +{ + unsigned char *p; + size_t len, align = 0, headerlen; + SSL3_BUFFER *b; + + b = &rl->rbuf; + + if (rl->isdtls) + headerlen = DTLS1_RT_HEADER_LENGTH; + else + headerlen = SSL3_RT_HEADER_LENGTH; + +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1); +#endif + + if (b->buf == NULL) { + len = SSL3_RT_MAX_PLAIN_LENGTH + + SSL3_RT_MAX_ENCRYPTED_OVERHEAD + headerlen + align; +#ifndef OPENSSL_NO_COMP + if (rlayer_allow_compression(rl)) + len += SSL3_RT_MAX_COMPRESSED_OVERHEAD; +#endif + if (b->default_len > len) + len = b->default_len; + if ((p = OPENSSL_malloc(len)) == NULL) { + /* + * We've got a malloc failure, and we're still initialising buffers. + * We assume we're so doomed that we won't even be able to send an + * alert. + */ + RLAYERfatal(rl, SSL_AD_NO_ALERT, ERR_R_MALLOC_FAILURE); + return 0; + } + b->buf = p; + b->len = len; + } + + return 1; +} + +static int rlayer_release_read_buffer(OSSL_RECORD_LAYER *rl) +{ + SSL3_BUFFER *b; + + b = &rl->rbuf; + if (rl->options & SSL_OP_CLEANSE_PLAINTEXT) + OPENSSL_cleanse(b->buf, b->len); + OPENSSL_free(b->buf); + b->buf = NULL; + return 1; +} + +/* + * Return values are as per SSL_read() + */ +static int tls_read_n(OSSL_RECORD_LAYER *rl, size_t n, size_t max, int extend, + int clearold, size_t *readbytes) +{ + /* + * If extend == 0, obtain new n-byte packet; if extend == 1, increase + * packet by another n bytes. The packet will be in the sub-array of + * s->rlayer.rbuf.buf specified by s->rlayer.packet and + * s->rlayer.packet_length. (If s->rlayer.read_ahead is set, 'max' bytes may + * be stored in rbuf [plus s->rlayer.packet_length bytes if extend == 1].) + * if clearold == 1, move the packet to the start of the buffer; if + * clearold == 0 then leave any old packets where they were + */ + size_t len, left, align = 0; + unsigned char *pkt; + SSL3_BUFFER *rb; + + if (n == 0) + return OSSL_RECORD_RETURN_NON_FATAL_ERR; + + rb = &rl->rbuf; + if (rb->buf == NULL) { + if (!rlayer_setup_read_buffer(rl)) { + /* RLAYERfatal() already called */ + return OSSL_RECORD_RETURN_FATAL; + } + } + + left = rb->left; +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0 + align = (size_t)rb->buf + SSL3_RT_HEADER_LENGTH; + align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD); +#endif + + if (!extend) { + /* start with empty packet ... */ + 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; + } + } + rl->packet = rb->buf + rb->offset; + rl->packet_length = 0; + /* ... now we can act as if 'extend' was set */ + } + + len = rl->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 (rl->packet != pkt && clearold == 1) { + memmove(pkt, rl->packet, len + left); + rl->packet = pkt; + rb->offset = len + align; + } + + /* + * For DTLS/UDP reads should not span multiple packets because the read + * operation returns the whole packet at once (as long as it fits into + * the buffer). + */ + if (rl->isdtls) { + if (left == 0 && extend) + return 0; + if (left > 0 && n > left) + n = left; + } + + /* if there is enough in the buffer from a previous read, take some */ + if (left >= n) { + rl->packet_length += n; + rb->left = left - n; + rb->offset += n; + *readbytes = n; + return OSSL_RECORD_RETURN_SUCCESS; + } + + /* else we need to read more data */ + + if (n > rb->len - rb->offset) { + /* does not happen */ + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + + /* + * Ktls always reads full records. + * Also, we always act like read_ahead is set for DTLS. + */ + if (!BIO_get_ktls_recv(s->rbio) && !rl->read_ahead + && !rl->isdtls) { + /* ignore max parameter */ + max = n; + } else { + if (max < n) + max = n; + if (max > rb->len - rb->offset) + max = rb->len - rb->offset; + } + + while (left < n) { + size_t bioread = 0; + int ret; + + /* + * 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 (rl->bio != NULL) { + ret = BIO_read(rl->bio, pkt + len + left, max - left); + if (ret > 0) { + bioread = ret; + ret = OSSL_RECORD_RETURN_SUCCESS; + } else if (BIO_should_retry(rl->bio)) { + ret = OSSL_RECORD_RETURN_RETRY; + } else if (BIO_eof(rl->bio)) { + ret = OSSL_RECORD_RETURN_EOF; + } else { + ret = OSSL_RECORD_RETURN_FATAL; + } + } else { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_READ_BIO_NOT_SET); + ret = OSSL_RECORD_RETURN_FATAL; + } + + if (ret <= OSSL_RECORD_RETURN_RETRY) { + rb->left = left; + if (rl->mode & SSL_MODE_RELEASE_BUFFERS && !rl->isdtls) + if (len + left == 0) + rlayer_release_read_buffer(rl); + return ret; + } + left += bioread; + /* + * reads should *never* span multiple packets for DTLS because the + * underlying transport protocol is message oriented as opposed to + * byte oriented as in the TLS case. + */ + if (rl->isdtls) { + if (n > left) + n = left; /* makes the while condition false */ + } + } + + /* done reading, now the book-keeping */ + rb->offset += n; + rb->left = left - n; + rl->packet_length += n; + *readbytes = n; + return OSSL_RECORD_RETURN_SUCCESS; +} + static OSSL_RECORD_LAYER *tls_new_record_layer(int vers, int role, int direction, int level, unsigned char *secret, size_t secretlen, SSL_CIPHER *c, BIO *transport, BIO_ADDR *local, BIO_ADDR *peer, - OSSL_PARAM *settings, - OSSL_PARAM *options) + const OSSL_PARAM *settings, + const OSSL_PARAM *options) { OSSL_RECORD_LAYER *rl = OPENSSL_zalloc(sizeof(*rl)); + const OSSL_PARAM *p; + + if (rl == NULL) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (transport != NULL && !BIO_up_ref(transport)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + goto err; + } + + p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_OPTIONS); + if (p != NULL && !OSSL_PARAM_get_uint64(p, &rl->options)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER); + goto err; + } + + p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_MODE); + if (p != NULL && !OSSL_PARAM_get_uint32(p, &rl->mode)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER); + goto err; + } + + + p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD); + if (p != NULL && !OSSL_PARAM_get_int(p, &rl->read_ahead)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER); + goto err; + } + + rl->version = vers; + rl->role = role; + rl->direction = direction; + if (!tls_set1_bio(rl, transport)) + goto err; + + return rl; + err: + OPENSSL_free(rl); + return NULL; +} + +static OSSL_RECORD_LAYER *dtls_new_record_layer(int vers, int role, int direction, + int level, unsigned char *secret, + size_t secretlen, SSL_CIPHER *c, + BIO *transport, BIO_ADDR *local, + BIO_ADDR *peer, + const OSSL_PARAM *settings, + const OSSL_PARAM *options) +{ + OSSL_RECORD_LAYER *rl = tls_new_record_layer(vers, role, direction, level, + secret, secretlen, c, transport, + local, peer, settings, options); + + if (rl == NULL) + return NULL; + + rl->isdtls = 1; return rl; } static void tls_free(OSSL_RECORD_LAYER *rl) { + BIO_free(rl->bio); OPENSSL_free(rl); } @@ -97,6 +451,48 @@ static void tls_release_record(OSSL_RECORD_LAYER *rl, void *rechandle) return; } +static int tls_get_alert_code(OSSL_RECORD_LAYER *rl) +{ + return rl->alert; +} + +static int tls_set1_bio(OSSL_RECORD_LAYER *rl, BIO *bio) +{ + if (bio != NULL && !BIO_up_ref(bio)) + return 0; + BIO_free(rl->bio); + rl->bio = bio; + + return 1; +} + +static SSL3_BUFFER *tls_get0_rbuf(OSSL_RECORD_LAYER *rl) +{ + return &rl->rbuf; +} + +static unsigned char *tls_get0_packet(OSSL_RECORD_LAYER *rl) +{ + return rl->packet; +} + +static void tls_set0_packet(OSSL_RECORD_LAYER *rl, unsigned char *packet, + size_t packetlen) +{ + rl->packet = packet; + rl->packet_length = packetlen; +} + +static size_t tls_get_packet_length(OSSL_RECORD_LAYER *rl) +{ + return rl->packet_length; +} + +static void tls_reset_packet_length(OSSL_RECORD_LAYER *rl) +{ + rl->packet_length = 0; +} + const OSSL_RECORD_METHOD ossl_tls_record_method = { tls_new_record_layer, tls_free, @@ -110,5 +506,49 @@ const OSSL_RECORD_METHOD ossl_tls_record_method = { tls_write_records, tls_retry_write_records, tls_read_record, - tls_release_record + tls_release_record, + tls_get_alert_code, + tls_set1_bio, + + /* + * TODO(RECLAYER): Remove these. These function pointers are temporary hacks + * during the record layer refactoring. They need to be removed before the + * refactor is complete. + */ + tls_read_n, + tls_get0_rbuf, + tls_get0_packet, + tls_set0_packet, + tls_get_packet_length, + tls_reset_packet_length +}; + +const OSSL_RECORD_METHOD ossl_dtls_record_method = { + dtls_new_record_layer, + tls_free, + tls_reset, + tls_unprocessed_read_pending, + tls_processed_read_pending, + tls_app_data_pending, + tls_write_pending, + tls_get_max_record_len, + tls_get_max_records, + tls_write_records, + tls_retry_write_records, + tls_read_record, + tls_release_record, + tls_get_alert_code, + tls_set1_bio, + + /* + * TODO(RECLAYER): Remove these. These function pointers are temporary hacks + * during the record layer refactoring. They need to be removed before the + * refactor is complete. + */ + tls_read_n, + tls_get0_rbuf, + tls_get0_packet, + tls_set0_packet, + tls_get_packet_length, + tls_reset_packet_length }; diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 75d720f990d..a202cf92991 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -170,6 +170,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { "extra data in message"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXT_LENGTH_MISMATCH), "ext length mismatch"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_FAILED_TO_GET_PARAMETER), + "failed to get parameter"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_FAILED_TO_INIT_ASYNC), "failed to init async"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_FRAGMENTED_CLIENT_HELLO), @@ -342,6 +344,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_BIO_NOT_SET), "read bio not set"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_TIMEOUT_EXPIRED), "read timeout expired"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_LAYER_FAILURE), + "record layer failure"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_LENGTH_MISMATCH), "record length mismatch"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_TOO_SMALL), "record too small"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 1a7242aee22..c61ad65063d 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -885,6 +885,22 @@ SSL *ossl_ssl_connection_new(SSL_CTX *ctx) goto err; #endif + /* + * TODO(RECLAYER): This assignment should probably initialy come from the + * SSL_METHOD, and potentially be updated later. For now though we just + * assign it. + */ + if (SSL_CONNECTION_IS_DTLS(s)) + s->rrlmethod = &ossl_dtls_record_method; + else + s->rrlmethod = &ossl_tls_record_method; + + /* BIO is NULL initially. It will get updated later */ + s->rrl = s->rrlmethod->new_record_layer(s->version, s->server, + OSSL_RECORD_DIRECTION_READ, + 0, 0, 0, NULL, NULL, NULL, + NULL, NULL, NULL); + return ssl; err: SSL_free(ssl); @@ -1422,6 +1438,7 @@ void SSL_set0_rbio(SSL *s, BIO *rbio) BIO_free_all(sc->rbio); sc->rbio = rbio; + sc->rrlmethod->set1_bio(sc->rrl, sc->rbio); } void SSL_set0_wbio(SSL *s, BIO *wbio) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 76719f9e2c8..3af39c8cc70 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -28,6 +28,7 @@ # include # include # include "record/record.h" +# include "record/recordmethod.h" # include "statem/statem.h" # include "internal/packet.h" # include "internal/dane.h" @@ -1762,7 +1763,16 @@ struct ssl_connection_st { * basis, depending on the chosen cipher. */ int (*not_resumable_session_cb) (SSL *ssl, int is_forward_secure); + + /* Old RECORD_LAYER structure - to be removed eventually */ RECORD_LAYER rlayer; + + /* New read direciton OSSL_RECORD_LAYER - to replace rlayer above */ + const OSSL_RECORD_METHOD *rrlmethod; + /* The read direction record layer */ + OSSL_RECORD_LAYER *rrl; + + /* Default password callback. */ pem_password_cb *default_passwd_callback; /* Default password callback user data. */ diff --git a/ssl/sslerr.h b/ssl/sslerr.h index 5c5b760e382..6715ac6a325 100644 --- a/ssl/sslerr.h +++ b/ssl/sslerr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index f54aaf71882..b422dd76c16 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -172,6 +172,27 @@ int tls1_change_cipher_state(SSL_CONNECTION *s, int which) BIO *bio; #endif +#if 0 + if ((which & SSL3_CC_READ) != 0) { + /* + * TODO(RECLAYER): This is probably not the right place to free this. The + * OSSL_RECORD_METHOD might have changed since we created the rl object. + * We should free it at the point that we update the OSSL_RECORD_METHOD. + * But for now this will do. + */ + s->rrlmethod->free(s->rrl); + s->rrl = s->rrlmethod->new_record_layer(s->version, s->server, + OSSL_RECORD_DIRECTION_READ, + 0, 0, 0, NULL, s->rbio, NULL, + NULL, NULL, NULL); + } +#endif + + if (s->rrl == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + c = s->s3.tmp.new_sym_enc; m = s->s3.tmp.new_hash; mac_type = s->s3.tmp.new_mac_pkey_type;