LCOV - code coverage report
Current view: top level - tls - s2n_shutdown.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 58 64 90.6 %
Date: 2025-08-15 07:28:39 Functions: 3 3 100.0 %
Branches: 45 68 66.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License").
       5                 :            :  * You may not use this file except in compliance with the License.
       6                 :            :  * A copy of the License is located at
       7                 :            :  *
       8                 :            :  *  http://aws.amazon.com/apache2.0
       9                 :            :  *
      10                 :            :  * or in the "license" file accompanying this file. This file is distributed
      11                 :            :  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
      12                 :            :  * express or implied. See the License for the specific language governing
      13                 :            :  * permissions and limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "api/s2n.h"
      17                 :            : #include "tls/s2n_alerts.h"
      18                 :            : #include "tls/s2n_connection.h"
      19                 :            : #include "tls/s2n_tls.h"
      20                 :            : #include "utils/s2n_atomic.h"
      21                 :            : #include "utils/s2n_safety.h"
      22                 :            : 
      23                 :            : static bool s2n_shutdown_expect_close_notify(struct s2n_connection *conn)
      24                 :       9357 : {
      25                 :            :     /* No close_notify expected if we already received an error instead */
      26         [ -  + ]:       9357 :     if (s2n_atomic_flag_test(&conn->error_alert_received)) {
      27                 :          0 :         return false;
      28                 :          0 :     }
      29                 :            : 
      30                 :            :     /* No close_notify expected if we sent an error instead of a close_notify */
      31 [ -  + ][ +  + ]:       9357 :     if (conn->writer_alert_out || conn->reader_alert_out) {
      32                 :          3 :         return false;
      33                 :          3 :     }
      34                 :            : 
      35                 :            :     /* The purpose of the peer responding to our close_notify
      36                 :            :      * with its own close_notify is to prevent application data truncation.
      37                 :            :      * However, application data is not a concern during the handshake.
      38                 :            :      *
      39                 :            :      * Additionally, decrypting alerts sent during the handshake can be error prone
      40                 :            :      * due to different encryption keys and may lead to unnecessary error reporting
      41                 :            :      * and unnecessary blinding.
      42                 :            :      */
      43         [ +  + ]:       9354 :     if (!s2n_handshake_is_complete(conn)) {
      44                 :         31 :         return false;
      45                 :         31 :     }
      46                 :            : 
      47                 :            :     /* QUIC does not use TLS alerts */
      48         [ -  + ]:       9323 :     if (conn->quic_enabled) {
      49                 :          0 :         return false;
      50                 :          0 :     }
      51                 :            : 
      52                 :            :     /* Blinded errors indicate a fatal error handling inputs.
      53                 :            :      * We should not attempt to handle further inputs.
      54                 :            :      */
      55         [ -  + ]:       9323 :     if (conn->delay) {
      56                 :          0 :         return false;
      57                 :          0 :     }
      58                 :            : 
      59                 :       9323 :     return true;
      60                 :       9323 : }
      61                 :            : 
      62                 :            : int s2n_shutdown_send(struct s2n_connection *conn, s2n_blocked_status *blocked)
      63                 :      16537 : {
      64 [ +  - ][ +  + ]:      16537 :     POSIX_ENSURE_REF(conn);
      65 [ +  + ][ +  - ]:      16536 :     POSIX_ENSURE_REF(blocked);
      66                 :      16535 :     *blocked = S2N_NOT_BLOCKED;
      67                 :            : 
      68                 :            :     /* Treat this call as a no-op if already wiped.
      69                 :            :      * This should probably be an error, but wasn't in the past so is left as-is
      70                 :            :      * for backwards compatibility.
      71                 :            :      */
      72 [ +  + ][ +  - ]:      16535 :     if (conn->send == NULL && conn->recv == NULL) {
      73                 :          2 :         return S2N_SUCCESS;
      74                 :          2 :     }
      75                 :            : 
      76                 :            :     /* Flush any outstanding data */
      77                 :      16533 :     s2n_atomic_flag_set(&conn->write_closed);
      78         [ +  + ]:      16533 :     POSIX_GUARD(s2n_flush(conn, blocked));
      79                 :            : 
      80                 :            :     /* For a connection closed due to receiving an alert, we don't send anything. */
      81         [ +  + ]:       9445 :     if (s2n_atomic_flag_test(&conn->error_alert_received)) {
      82                 :          7 :         return S2N_SUCCESS;
      83                 :          7 :     }
      84                 :            : 
      85                 :            :     /* If we've already sent an alert, don't send another. */
      86         [ +  + ]:       9438 :     if (conn->alert_sent) {
      87                 :       7119 :         return S2N_SUCCESS;
      88                 :       7119 :     }
      89                 :            : 
      90                 :            :     /* Enforce blinding.
      91                 :            :      * If an application is using self-service blinding, ensure that they have
      92                 :            :      * waited the required time before triggering any alerts.
      93                 :            :      */
      94                 :       2319 :     uint64_t elapsed = 0;
      95         [ -  + ]:       2319 :     POSIX_GUARD_RESULT(s2n_timer_elapsed(conn->config, &conn->write_timer, &elapsed));
      96 [ -  + ][ #  # ]:       2319 :     S2N_ERROR_IF(elapsed < conn->delay, S2N_ERR_SHUTDOWN_PAUSED);
      97                 :            : 
      98                 :            :     /**
      99                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-6.1
     100                 :            :      *# Each party MUST send a "close_notify" alert before closing its write
     101                 :            :      *# side of the connection, unless it has already sent some error alert.
     102                 :            :      */
     103         [ -  + ]:       2319 :     POSIX_GUARD_RESULT(s2n_alerts_write_error_or_close_notify(conn));
     104         [ +  + ]:       2319 :     POSIX_GUARD(s2n_flush(conn, blocked));
     105                 :       2315 :     return S2N_SUCCESS;
     106                 :       2319 : }
     107                 :            : 
     108                 :            : int s2n_shutdown(struct s2n_connection *conn, s2n_blocked_status *blocked)
     109                 :      16487 : {
     110 [ -  + ][ #  # ]:      16487 :     POSIX_ENSURE_REF(conn);
     111 [ -  + ][ #  # ]:      16487 :     POSIX_ENSURE_REF(blocked);
     112                 :      16487 :     *blocked = S2N_NOT_BLOCKED;
     113                 :            : 
     114                 :            :     /* If necessary, send an alert to indicate shutdown. */
     115         [ +  + ]:      16487 :     POSIX_GUARD(s2n_shutdown_send(conn, blocked));
     116                 :            : 
     117                 :            :     /* If we don't expect a close_notify from our peer,
     118                 :            :      * just ensure that the connection is marked closed.
     119                 :            :      */
     120         [ +  + ]:       9401 :     if (!s2n_shutdown_expect_close_notify(conn)) {
     121         [ -  + ]:         46 :         POSIX_GUARD_RESULT(s2n_connection_set_closed(conn));
     122                 :         46 :         *blocked = S2N_NOT_BLOCKED;
     123                 :         46 :         return S2N_SUCCESS;
     124                 :         46 :     }
     125                 :            : 
     126                 :            :     /* Wait for the peer's close_notify. */
     127                 :       9355 :     uint8_t record_type = 0;
     128                 :       9355 :     int isSSLv2 = false;
     129                 :       9355 :     *blocked = S2N_BLOCKED_ON_READ;
     130         [ +  + ]:      11633 :     while (!s2n_atomic_flag_test(&conn->close_notify_received)) {
     131         [ +  + ]:       9333 :         POSIX_GUARD(s2n_read_full_record(conn, &record_type, &isSSLv2));
     132 [ -  + ][ #  # ]:       2279 :         POSIX_ENSURE(!isSSLv2, S2N_ERR_BAD_MESSAGE);
     133         [ +  + ]:       2279 :         if (record_type == TLS_ALERT) {
     134         [ +  + ]:       2270 :             POSIX_GUARD(s2n_process_alert_fragment(conn));
     135                 :       2270 :         }
     136         [ -  + ]:       2278 :         POSIX_GUARD_RESULT(s2n_record_wipe(conn));
     137                 :       2278 :     }
     138                 :            : 
     139                 :       2300 :     *blocked = S2N_NOT_BLOCKED;
     140                 :       2300 :     return S2N_SUCCESS;
     141                 :       9355 : }

Generated by: LCOV version 1.14