diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/restricted/aws/s2n/tls/s2n_recv.c | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/aws/s2n/tls/s2n_recv.c')
-rw-r--r-- | contrib/restricted/aws/s2n/tls/s2n_recv.c | 458 |
1 files changed, 229 insertions, 229 deletions
diff --git a/contrib/restricted/aws/s2n/tls/s2n_recv.c b/contrib/restricted/aws/s2n/tls/s2n_recv.c index 8d0d04d4f0..e04b752fe8 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_recv.c +++ b/contrib/restricted/aws/s2n/tls/s2n_recv.c @@ -1,229 +1,229 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <sys/param.h> - -/* Use usleep */ -#define _XOPEN_SOURCE 500 -#include <unistd.h> - -#include <errno.h> -#include <s2n.h> - -#include "error/s2n_errno.h" - -#include "tls/s2n_connection.h" -#include "tls/s2n_handshake.h" -#include "tls/s2n_record.h" -#include "tls/s2n_resume.h" -#include "tls/s2n_alerts.h" -#include "tls/s2n_tls.h" -#include "tls/s2n_post_handshake.h" - -#include "stuffer/s2n_stuffer.h" - -#include "utils/s2n_socket.h" -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" - -S2N_RESULT s2n_read_in_bytes(struct s2n_connection *conn, struct s2n_stuffer *output, uint32_t length) -{ - while (s2n_stuffer_data_available(output) < length) { - uint32_t remaining = length - s2n_stuffer_data_available(output); - - errno = 0; - int r = s2n_connection_recv_stuffer(output, conn, remaining); - if (r == 0) { - conn->closed = 1; - BAIL(S2N_ERR_CLOSED); - } else if (r < 0) { - if (errno == EWOULDBLOCK || errno == EAGAIN) { - BAIL(S2N_ERR_IO_BLOCKED); - } - BAIL(S2N_ERR_IO); - } - conn->wire_bytes_in += r; - } - - return S2N_RESULT_OK; -} - -int s2n_read_full_record(struct s2n_connection *conn, uint8_t * record_type, int *isSSLv2) -{ - *isSSLv2 = 0; - - /* If the record has already been decrypted, then leave it alone */ - if (conn->in_status == PLAINTEXT) { - /* Only application data packets count as plaintext */ - *record_type = TLS_APPLICATION_DATA; - return S2N_SUCCESS; - } - GUARD(s2n_stuffer_resize_if_empty(&conn->in, S2N_LARGE_FRAGMENT_LENGTH)); - - /* Read the record until we at least have a header */ - GUARD_AS_POSIX(s2n_read_in_bytes(conn, &conn->header_in, S2N_TLS_RECORD_HEADER_LENGTH)); - - uint16_t fragment_length; - - /* If the first bit is set then this is an SSLv2 record */ - if (conn->header_in.blob.data[0] & 0x80) { - conn->header_in.blob.data[0] &= 0x7f; - *isSSLv2 = 1; - - if (s2n_sslv2_record_header_parse(conn, record_type, &conn->client_protocol_version, &fragment_length) < 0) { - GUARD(s2n_connection_kill(conn)); - S2N_ERROR_PRESERVE_ERRNO(); - } - } else { - if (s2n_record_header_parse(conn, record_type, &fragment_length) < 0) { - GUARD(s2n_connection_kill(conn)); - S2N_ERROR_PRESERVE_ERRNO(); - } - } - - /* Read enough to have the whole record */ - GUARD_AS_POSIX(s2n_read_in_bytes(conn, &conn->in, fragment_length)); - - if (*isSSLv2) { - return 0; - } - - /* Decrypt and parse the record */ - if (s2n_record_parse(conn) < 0) { - GUARD(s2n_connection_kill(conn)); - S2N_ERROR_PRESERVE_ERRNO(); - } - - /* In TLS 1.3, encrypted handshake records would appear to be of record type - * TLS_APPLICATION_DATA. The actual record content type is found after the encrypted - * is decrypted. - */ - if (conn->actual_protocol_version == S2N_TLS13 && *record_type == TLS_APPLICATION_DATA) { - GUARD(s2n_tls13_parse_record_type(&conn->in, record_type)); - } - - return 0; -} - -ssize_t s2n_recv(struct s2n_connection * conn, void *buf, ssize_t size, s2n_blocked_status * blocked) -{ - ssize_t bytes_read = 0; - struct s2n_blob out = {.data = (uint8_t *) buf }; - - if (conn->closed) { - return 0; - } - *blocked = S2N_BLOCKED_ON_READ; - - S2N_ERROR_IF(conn->config->quic_enabled, S2N_ERR_UNSUPPORTED_WITH_QUIC); - - while (size && !conn->closed) { - int isSSLv2 = 0; - uint8_t record_type; - int r = s2n_read_full_record(conn, &record_type, &isSSLv2); - if (r < 0) { - if (s2n_errno == S2N_ERR_CLOSED) { - *blocked = S2N_NOT_BLOCKED; - if (!bytes_read) { - return 0; - } else { - return bytes_read; - } - } - - /* Don't propagate the error if we already read some bytes */ - if (s2n_errno == S2N_ERR_IO_BLOCKED && bytes_read) { - s2n_errno = S2N_ERR_OK; - return bytes_read; - } - - /* If we get here, it's an error condition */ - if (s2n_errno != S2N_ERR_IO_BLOCKED && s2n_allowed_to_cache_connection(conn) && conn->session_id_len) { - conn->config->cache_delete(conn, conn->config->cache_delete_data, conn->session_id, conn->session_id_len); - } - - S2N_ERROR_PRESERVE_ERRNO(); - } - - S2N_ERROR_IF(isSSLv2, S2N_ERR_BAD_MESSAGE); - - if (record_type != TLS_APPLICATION_DATA) { - switch (record_type) - { - case TLS_ALERT: - GUARD(s2n_process_alert_fragment(conn)); - GUARD(s2n_flush(conn, blocked)); - break; - case TLS_HANDSHAKE: - GUARD(s2n_post_handshake_recv(conn)); - break; - } - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); - conn->in_status = ENCRYPTED; - continue; - } - - out.size = MIN(size, s2n_stuffer_data_available(&conn->in)); - - GUARD(s2n_stuffer_erase_and_read(&conn->in, &out)); - bytes_read += out.size; - - out.data += out.size; - size -= out.size; - - /* Are we ready for more encrypted data? */ - if (s2n_stuffer_data_available(&conn->in) == 0) { - GUARD(s2n_stuffer_wipe(&conn->header_in)); - GUARD(s2n_stuffer_wipe(&conn->in)); - conn->in_status = ENCRYPTED; - } - - /* If we've read some data, return it */ - if (bytes_read) { - break; - } - } - - if (s2n_stuffer_data_available(&conn->in) == 0) { - *blocked = S2N_NOT_BLOCKED; - } - - return bytes_read; -} - -uint32_t s2n_peek(struct s2n_connection *conn) { - return s2n_stuffer_data_available(&conn->in); -} - -int s2n_recv_close_notify(struct s2n_connection *conn, s2n_blocked_status * blocked) -{ - uint8_t record_type; - int isSSLv2; - *blocked = S2N_BLOCKED_ON_READ; - - GUARD(s2n_read_full_record(conn, &record_type, &isSSLv2)); - - S2N_ERROR_IF(isSSLv2, S2N_ERR_BAD_MESSAGE); - - S2N_ERROR_IF(record_type != TLS_ALERT, S2N_ERR_SHUTDOWN_RECORD_TYPE); - - /* Only succeeds for an incoming close_notify alert */ - GUARD(s2n_process_alert_fragment(conn)); - - *blocked = S2N_NOT_BLOCKED; - return 0; -} - +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <sys/param.h> + +/* Use usleep */ +#define _XOPEN_SOURCE 500 +#include <unistd.h> + +#include <errno.h> +#include <s2n.h> + +#include "error/s2n_errno.h" + +#include "tls/s2n_connection.h" +#include "tls/s2n_handshake.h" +#include "tls/s2n_record.h" +#include "tls/s2n_resume.h" +#include "tls/s2n_alerts.h" +#include "tls/s2n_tls.h" +#include "tls/s2n_post_handshake.h" + +#include "stuffer/s2n_stuffer.h" + +#include "utils/s2n_socket.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" + +S2N_RESULT s2n_read_in_bytes(struct s2n_connection *conn, struct s2n_stuffer *output, uint32_t length) +{ + while (s2n_stuffer_data_available(output) < length) { + uint32_t remaining = length - s2n_stuffer_data_available(output); + + errno = 0; + int r = s2n_connection_recv_stuffer(output, conn, remaining); + if (r == 0) { + conn->closed = 1; + BAIL(S2N_ERR_CLOSED); + } else if (r < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) { + BAIL(S2N_ERR_IO_BLOCKED); + } + BAIL(S2N_ERR_IO); + } + conn->wire_bytes_in += r; + } + + return S2N_RESULT_OK; +} + +int s2n_read_full_record(struct s2n_connection *conn, uint8_t * record_type, int *isSSLv2) +{ + *isSSLv2 = 0; + + /* If the record has already been decrypted, then leave it alone */ + if (conn->in_status == PLAINTEXT) { + /* Only application data packets count as plaintext */ + *record_type = TLS_APPLICATION_DATA; + return S2N_SUCCESS; + } + GUARD(s2n_stuffer_resize_if_empty(&conn->in, S2N_LARGE_FRAGMENT_LENGTH)); + + /* Read the record until we at least have a header */ + GUARD_AS_POSIX(s2n_read_in_bytes(conn, &conn->header_in, S2N_TLS_RECORD_HEADER_LENGTH)); + + uint16_t fragment_length; + + /* If the first bit is set then this is an SSLv2 record */ + if (conn->header_in.blob.data[0] & 0x80) { + conn->header_in.blob.data[0] &= 0x7f; + *isSSLv2 = 1; + + if (s2n_sslv2_record_header_parse(conn, record_type, &conn->client_protocol_version, &fragment_length) < 0) { + GUARD(s2n_connection_kill(conn)); + S2N_ERROR_PRESERVE_ERRNO(); + } + } else { + if (s2n_record_header_parse(conn, record_type, &fragment_length) < 0) { + GUARD(s2n_connection_kill(conn)); + S2N_ERROR_PRESERVE_ERRNO(); + } + } + + /* Read enough to have the whole record */ + GUARD_AS_POSIX(s2n_read_in_bytes(conn, &conn->in, fragment_length)); + + if (*isSSLv2) { + return 0; + } + + /* Decrypt and parse the record */ + if (s2n_record_parse(conn) < 0) { + GUARD(s2n_connection_kill(conn)); + S2N_ERROR_PRESERVE_ERRNO(); + } + + /* In TLS 1.3, encrypted handshake records would appear to be of record type + * TLS_APPLICATION_DATA. The actual record content type is found after the encrypted + * is decrypted. + */ + if (conn->actual_protocol_version == S2N_TLS13 && *record_type == TLS_APPLICATION_DATA) { + GUARD(s2n_tls13_parse_record_type(&conn->in, record_type)); + } + + return 0; +} + +ssize_t s2n_recv(struct s2n_connection * conn, void *buf, ssize_t size, s2n_blocked_status * blocked) +{ + ssize_t bytes_read = 0; + struct s2n_blob out = {.data = (uint8_t *) buf }; + + if (conn->closed) { + return 0; + } + *blocked = S2N_BLOCKED_ON_READ; + + S2N_ERROR_IF(conn->config->quic_enabled, S2N_ERR_UNSUPPORTED_WITH_QUIC); + + while (size && !conn->closed) { + int isSSLv2 = 0; + uint8_t record_type; + int r = s2n_read_full_record(conn, &record_type, &isSSLv2); + if (r < 0) { + if (s2n_errno == S2N_ERR_CLOSED) { + *blocked = S2N_NOT_BLOCKED; + if (!bytes_read) { + return 0; + } else { + return bytes_read; + } + } + + /* Don't propagate the error if we already read some bytes */ + if (s2n_errno == S2N_ERR_IO_BLOCKED && bytes_read) { + s2n_errno = S2N_ERR_OK; + return bytes_read; + } + + /* If we get here, it's an error condition */ + if (s2n_errno != S2N_ERR_IO_BLOCKED && s2n_allowed_to_cache_connection(conn) && conn->session_id_len) { + conn->config->cache_delete(conn, conn->config->cache_delete_data, conn->session_id, conn->session_id_len); + } + + S2N_ERROR_PRESERVE_ERRNO(); + } + + S2N_ERROR_IF(isSSLv2, S2N_ERR_BAD_MESSAGE); + + if (record_type != TLS_APPLICATION_DATA) { + switch (record_type) + { + case TLS_ALERT: + GUARD(s2n_process_alert_fragment(conn)); + GUARD(s2n_flush(conn, blocked)); + break; + case TLS_HANDSHAKE: + GUARD(s2n_post_handshake_recv(conn)); + break; + } + GUARD(s2n_stuffer_wipe(&conn->header_in)); + GUARD(s2n_stuffer_wipe(&conn->in)); + conn->in_status = ENCRYPTED; + continue; + } + + out.size = MIN(size, s2n_stuffer_data_available(&conn->in)); + + GUARD(s2n_stuffer_erase_and_read(&conn->in, &out)); + bytes_read += out.size; + + out.data += out.size; + size -= out.size; + + /* Are we ready for more encrypted data? */ + if (s2n_stuffer_data_available(&conn->in) == 0) { + GUARD(s2n_stuffer_wipe(&conn->header_in)); + GUARD(s2n_stuffer_wipe(&conn->in)); + conn->in_status = ENCRYPTED; + } + + /* If we've read some data, return it */ + if (bytes_read) { + break; + } + } + + if (s2n_stuffer_data_available(&conn->in) == 0) { + *blocked = S2N_NOT_BLOCKED; + } + + return bytes_read; +} + +uint32_t s2n_peek(struct s2n_connection *conn) { + return s2n_stuffer_data_available(&conn->in); +} + +int s2n_recv_close_notify(struct s2n_connection *conn, s2n_blocked_status * blocked) +{ + uint8_t record_type; + int isSSLv2; + *blocked = S2N_BLOCKED_ON_READ; + + GUARD(s2n_read_full_record(conn, &record_type, &isSSLv2)); + + S2N_ERROR_IF(isSSLv2, S2N_ERR_BAD_MESSAGE); + + S2N_ERROR_IF(record_type != TLS_ALERT, S2N_ERR_SHUTDOWN_RECORD_TYPE); + + /* Only succeeds for an incoming close_notify alert */ + GUARD(s2n_process_alert_fragment(conn)); + + *blocked = S2N_NOT_BLOCKED; + return 0; +} + |