123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- /*
- * 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 "tls/s2n_alerts.h"
- #include <stdint.h>
- #include <sys/param.h>
- #include "error/s2n_errno.h"
- #include "tls/s2n_connection.h"
- #include "tls/s2n_record.h"
- #include "tls/s2n_resume.h"
- #include "tls/s2n_tls_parameters.h"
- #include "utils/s2n_atomic.h"
- #include "utils/s2n_blob.h"
- #include "utils/s2n_safety.h"
- #define S2N_ALERT_CASE(error, alert_code) \
- case (error): \
- *alert = (alert_code); \
- return S2N_RESULT_OK
- #define S2N_NO_ALERT(error) \
- case (error): \
- RESULT_BAIL(S2N_ERR_NO_ALERT)
- static S2N_RESULT s2n_translate_protocol_error_to_alert(int error_code, uint8_t *alert)
- {
- RESULT_ENSURE_REF(alert);
- switch (error_code) {
- S2N_ALERT_CASE(S2N_ERR_MISSING_EXTENSION, S2N_TLS_ALERT_MISSING_EXTENSION);
- /* TODO: The ERR_BAD_MESSAGE -> ALERT_UNEXPECTED_MESSAGE mapping
- * isn't always correct. Sometimes s2n-tls uses ERR_BAD_MESSAGE
- * to indicate S2N_TLS_ALERT_ILLEGAL_PARAMETER instead.
- * We'll want to add a new error to distinguish between the two usages:
- * our errors should be equally or more specific than alerts, not less.
- */
- S2N_ALERT_CASE(S2N_ERR_BAD_MESSAGE, S2N_TLS_ALERT_UNEXPECTED_MESSAGE);
- /* For errors involving secure renegotiation:
- *= https://tools.ietf.org/rfc/rfc5746#3.4
- *# Note: later in Section 3, "abort the handshake" is used as
- *# shorthand for "send a fatal handshake_failure alert and
- *# terminate the connection".
- */
- S2N_ALERT_CASE(S2N_ERR_NO_RENEGOTIATION, S2N_TLS_ALERT_HANDSHAKE_FAILURE);
- /* TODO: Add mappings for other protocol errors.
- */
- S2N_NO_ALERT(S2N_ERR_ENCRYPT);
- S2N_NO_ALERT(S2N_ERR_DECRYPT);
- S2N_NO_ALERT(S2N_ERR_KEY_INIT);
- S2N_NO_ALERT(S2N_ERR_KEY_DESTROY);
- S2N_NO_ALERT(S2N_ERR_DH_SERIALIZING);
- S2N_NO_ALERT(S2N_ERR_DH_SHARED_SECRET);
- S2N_NO_ALERT(S2N_ERR_DH_WRITING_PUBLIC_KEY);
- S2N_NO_ALERT(S2N_ERR_DH_FAILED_SIGNING);
- S2N_NO_ALERT(S2N_ERR_DH_COPYING_PARAMETERS);
- S2N_NO_ALERT(S2N_ERR_DH_GENERATING_PARAMETERS);
- S2N_NO_ALERT(S2N_ERR_CIPHER_NOT_SUPPORTED);
- S2N_NO_ALERT(S2N_ERR_NO_APPLICATION_PROTOCOL);
- S2N_NO_ALERT(S2N_ERR_FALLBACK_DETECTED);
- S2N_NO_ALERT(S2N_ERR_HASH_DIGEST_FAILED);
- S2N_NO_ALERT(S2N_ERR_HASH_INIT_FAILED);
- S2N_NO_ALERT(S2N_ERR_HASH_UPDATE_FAILED);
- S2N_NO_ALERT(S2N_ERR_HASH_COPY_FAILED);
- S2N_NO_ALERT(S2N_ERR_HASH_WIPE_FAILED);
- S2N_NO_ALERT(S2N_ERR_HASH_NOT_READY);
- S2N_NO_ALERT(S2N_ERR_ALLOW_MD5_FOR_FIPS_FAILED);
- S2N_NO_ALERT(S2N_ERR_DECODE_CERTIFICATE);
- S2N_NO_ALERT(S2N_ERR_DECODE_PRIVATE_KEY);
- S2N_NO_ALERT(S2N_ERR_INVALID_HELLO_RETRY);
- S2N_NO_ALERT(S2N_ERR_INVALID_SIGNATURE_ALGORITHM);
- S2N_NO_ALERT(S2N_ERR_INVALID_SIGNATURE_SCHEME);
- S2N_NO_ALERT(S2N_ERR_CBC_VERIFY);
- S2N_NO_ALERT(S2N_ERR_DH_COPYING_PUBLIC_KEY);
- S2N_NO_ALERT(S2N_ERR_SIGN);
- S2N_NO_ALERT(S2N_ERR_VERIFY_SIGNATURE);
- S2N_NO_ALERT(S2N_ERR_ECDHE_GEN_KEY);
- S2N_NO_ALERT(S2N_ERR_ECDHE_SHARED_SECRET);
- S2N_NO_ALERT(S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
- S2N_NO_ALERT(S2N_ERR_ECDSA_UNSUPPORTED_CURVE);
- S2N_NO_ALERT(S2N_ERR_ECDHE_SERIALIZING);
- S2N_NO_ALERT(S2N_ERR_KEM_UNSUPPORTED_PARAMS);
- S2N_NO_ALERT(S2N_ERR_SHUTDOWN_RECORD_TYPE);
- S2N_NO_ALERT(S2N_ERR_SHUTDOWN_CLOSED);
- S2N_NO_ALERT(S2N_ERR_NON_EMPTY_RENEGOTIATION_INFO);
- S2N_NO_ALERT(S2N_ERR_RECORD_LIMIT);
- S2N_NO_ALERT(S2N_ERR_CERT_UNTRUSTED);
- S2N_NO_ALERT(S2N_ERR_CERT_REVOKED);
- S2N_NO_ALERT(S2N_ERR_CERT_NOT_YET_VALID);
- S2N_NO_ALERT(S2N_ERR_CERT_EXPIRED);
- S2N_NO_ALERT(S2N_ERR_CERT_TYPE_UNSUPPORTED);
- S2N_NO_ALERT(S2N_ERR_CERT_INVALID);
- S2N_NO_ALERT(S2N_ERR_CERT_MAX_CHAIN_DEPTH_EXCEEDED);
- S2N_NO_ALERT(S2N_ERR_CERT_REJECTED);
- S2N_NO_ALERT(S2N_ERR_CRL_LOOKUP_FAILED);
- S2N_NO_ALERT(S2N_ERR_CRL_SIGNATURE);
- S2N_NO_ALERT(S2N_ERR_CRL_ISSUER);
- S2N_NO_ALERT(S2N_ERR_CRL_UNHANDLED_CRITICAL_EXTENSION);
- S2N_NO_ALERT(S2N_ERR_CRL_INVALID_THIS_UPDATE);
- S2N_NO_ALERT(S2N_ERR_CRL_INVALID_NEXT_UPDATE);
- S2N_NO_ALERT(S2N_ERR_CRL_NOT_YET_VALID);
- S2N_NO_ALERT(S2N_ERR_CRL_EXPIRED);
- S2N_NO_ALERT(S2N_ERR_INVALID_MAX_FRAG_LEN);
- S2N_NO_ALERT(S2N_ERR_MAX_FRAG_LEN_MISMATCH);
- S2N_NO_ALERT(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);
- S2N_NO_ALERT(S2N_ERR_BAD_KEY_SHARE);
- S2N_NO_ALERT(S2N_ERR_CANCELLED);
- S2N_NO_ALERT(S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED);
- S2N_NO_ALERT(S2N_ERR_MAX_INNER_PLAINTEXT_SIZE);
- S2N_NO_ALERT(S2N_ERR_RECORD_STUFFER_SIZE);
- S2N_NO_ALERT(S2N_ERR_FRAGMENT_LENGTH_TOO_LARGE);
- S2N_NO_ALERT(S2N_ERR_FRAGMENT_LENGTH_TOO_SMALL);
- S2N_NO_ALERT(S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
- S2N_NO_ALERT(S2N_ERR_UNSUPPORTED_EXTENSION);
- S2N_NO_ALERT(S2N_ERR_DUPLICATE_EXTENSION);
- S2N_NO_ALERT(S2N_ERR_MAX_EARLY_DATA_SIZE);
- S2N_NO_ALERT(S2N_ERR_EARLY_DATA_TRIAL_DECRYPT);
- }
- RESULT_BAIL(S2N_ERR_UNIMPLEMENTED);
- }
- static bool s2n_alerts_supported(struct s2n_connection *conn)
- {
- /* If running in QUIC mode, QUIC handles alerting.
- * S2N should not send or receive alerts. */
- return !s2n_connection_is_quic_enabled(conn);
- }
- /* In TLS1.3 all Alerts
- *= https://tools.ietf.org/rfc/rfc8446#section-6
- *# MUST be treated as error alerts when received
- *# regardless of the AlertLevel in the message.
- */
- static bool s2n_process_as_warning(struct s2n_connection *conn, uint8_t level, uint8_t type)
- {
- /* Only TLS1.2 considers the alert level. The alert level field is
- * considered deprecated in TLS1.3. */
- if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) {
- return level == S2N_TLS_ALERT_LEVEL_WARNING
- && conn->config->alert_behavior == S2N_ALERT_IGNORE_WARNINGS;
- }
- /* user_canceled is the only alert currently treated as a warning in TLS1.3.
- * We need to treat it as a warning regardless of alert_behavior to avoid marking
- * correctly-closed connections as failed. */
- return type == S2N_TLS_ALERT_USER_CANCELED;
- }
- int s2n_error_get_alert(int error, uint8_t *alert)
- {
- int error_type = s2n_error_get_type(error);
- POSIX_ENSURE_REF(alert);
- switch (error_type) {
- case S2N_ERR_T_OK:
- case S2N_ERR_T_CLOSED:
- case S2N_ERR_T_BLOCKED:
- case S2N_ERR_T_USAGE:
- case S2N_ERR_T_ALERT:
- POSIX_BAIL(S2N_ERR_NO_ALERT);
- break;
- case S2N_ERR_T_PROTO:
- POSIX_GUARD_RESULT(s2n_translate_protocol_error_to_alert(error, alert));
- break;
- case S2N_ERR_T_IO:
- case S2N_ERR_T_INTERNAL:
- *alert = S2N_TLS_ALERT_INTERNAL_ERROR;
- break;
- }
- return S2N_SUCCESS;
- }
- int s2n_process_alert_fragment(struct s2n_connection *conn)
- {
- POSIX_ENSURE_REF(conn);
- S2N_ERROR_IF(s2n_stuffer_data_available(&conn->in) == 0, S2N_ERR_BAD_MESSAGE);
- S2N_ERROR_IF(s2n_stuffer_data_available(&conn->alert_in) == 2, S2N_ERR_ALERT_PRESENT);
- POSIX_ENSURE(s2n_alerts_supported(conn), S2N_ERR_BAD_MESSAGE);
- while (s2n_stuffer_data_available(&conn->in)) {
- uint8_t bytes_required = 2;
- /* Alerts are two bytes long, but can still be fragmented or coalesced */
- if (s2n_stuffer_data_available(&conn->alert_in) == 1) {
- bytes_required = 1;
- }
- int bytes_to_read = MIN(bytes_required, s2n_stuffer_data_available(&conn->in));
- POSIX_GUARD(s2n_stuffer_copy(&conn->in, &conn->alert_in, bytes_to_read));
- if (s2n_stuffer_data_available(&conn->alert_in) == 2) {
- /* Close notifications are handled as shutdowns */
- if (conn->alert_in_data[1] == S2N_TLS_ALERT_CLOSE_NOTIFY) {
- s2n_atomic_flag_set(&conn->read_closed);
- s2n_atomic_flag_set(&conn->close_notify_received);
- return 0;
- }
- /* Ignore warning-level alerts if we're in warning-tolerant mode */
- if (s2n_process_as_warning(conn, conn->alert_in_data[0], conn->alert_in_data[1])) {
- POSIX_GUARD(s2n_stuffer_wipe(&conn->alert_in));
- return 0;
- }
- /* RFC 5077 5.1 - Expire any cached session on an error alert */
- if (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);
- }
- /* All other alerts are treated as fatal errors.
- *
- *= https://tools.ietf.org/rfc/rfc8446#section-6
- *# Unknown Alert types MUST be treated as error alerts.
- */
- POSIX_GUARD_RESULT(s2n_connection_set_closed(conn));
- s2n_atomic_flag_set(&conn->error_alert_received);
- POSIX_BAIL(S2N_ERR_ALERT);
- }
- }
- return 0;
- }
- static S2N_RESULT s2n_queue_reader_alert(struct s2n_connection *conn, s2n_tls_alert_code code)
- {
- RESULT_ENSURE_REF(conn);
- if (!conn->reader_alert_out) {
- conn->reader_alert_out = code;
- }
- return S2N_RESULT_OK;
- }
- int s2n_queue_reader_unsupported_protocol_version_alert(struct s2n_connection *conn)
- {
- POSIX_GUARD_RESULT(s2n_queue_reader_alert(conn, S2N_TLS_ALERT_PROTOCOL_VERSION));
- return S2N_SUCCESS;
- }
- int s2n_queue_reader_handshake_failure_alert(struct s2n_connection *conn)
- {
- POSIX_GUARD_RESULT(s2n_queue_reader_alert(conn, S2N_TLS_ALERT_HANDSHAKE_FAILURE));
- return S2N_SUCCESS;
- }
- S2N_RESULT s2n_queue_reader_no_renegotiation_alert(struct s2n_connection *conn)
- {
- /**
- *= https://tools.ietf.org/rfc/rfc5746#4.5
- *# SSLv3 does not define the "no_renegotiation" alert (and does
- *# not offer a way to indicate a refusal to renegotiate at a "warning"
- *# level). SSLv3 clients that refuse renegotiation SHOULD use a fatal
- *# handshake_failure alert.
- **/
- if (s2n_connection_get_protocol_version(conn) == S2N_SSLv3) {
- RESULT_GUARD_POSIX(s2n_queue_reader_handshake_failure_alert(conn));
- RESULT_BAIL(S2N_ERR_BAD_MESSAGE);
- }
- if (!conn->reader_warning_out) {
- conn->reader_warning_out = S2N_TLS_ALERT_NO_RENEGOTIATION;
- }
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_alerts_write_error_or_close_notify(struct s2n_connection *conn)
- {
- if (!s2n_alerts_supported(conn)) {
- return S2N_RESULT_OK;
- }
- /*
- *= https://tools.ietf.org/rfc/rfc8446#section-6.2
- *= type=exception
- *= reason=Specific alerts could expose a side-channel attack vector.
- *# The phrases "terminate the connection with an X
- *# alert" and "abort the handshake with an X alert" mean that the
- *# implementation MUST send alert X if it sends any alert.
- *
- * By default, s2n-tls sends a generic close_notify alert, even in
- * response to fatal errors. This is done to avoid potential
- * side-channel attacks since specific alerts could reveal information
- * about why the error occured.
- */
- uint8_t code = S2N_TLS_ALERT_CLOSE_NOTIFY;
- uint8_t level = S2N_TLS_ALERT_LEVEL_WARNING;
- /* s2n-tls sends a very small subset of more specific error alerts.
- * Since either the reader or the writer can produce one of these alerts,
- * but only a single alert can be reported, we prioritize writer alerts.
- */
- if (conn->writer_alert_out) {
- code = conn->writer_alert_out;
- level = S2N_TLS_ALERT_LEVEL_FATAL;
- } else if (conn->reader_alert_out) {
- code = conn->reader_alert_out;
- level = S2N_TLS_ALERT_LEVEL_FATAL;
- }
- struct s2n_blob alert = { 0 };
- uint8_t alert_bytes[] = { level, code };
- RESULT_GUARD_POSIX(s2n_blob_init(&alert, alert_bytes, sizeof(alert_bytes)));
- RESULT_GUARD(s2n_record_write(conn, TLS_ALERT, &alert));
- conn->alert_sent = true;
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_alerts_write_warning(struct s2n_connection *conn)
- {
- if (!s2n_alerts_supported(conn)) {
- return S2N_RESULT_OK;
- }
- uint8_t code = conn->reader_warning_out;
- uint8_t level = S2N_TLS_ALERT_LEVEL_WARNING;
- struct s2n_blob alert = { 0 };
- uint8_t alert_bytes[] = { level, code };
- RESULT_GUARD_POSIX(s2n_blob_init(&alert, alert_bytes, sizeof(alert_bytes)));
- RESULT_GUARD(s2n_record_write(conn, TLS_ALERT, &alert));
- return S2N_RESULT_OK;
- }
|