LCOV - code coverage report
Current view: top level - tls - s2n_resume.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 672 699 96.1 %
Date: 2025-08-15 07:28:39 Functions: 42 42 100.0 %
Branches: 450 888 50.7 %

           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                 :            : #include "tls/s2n_resume.h"
      16                 :            : 
      17                 :            : #include <math.h>
      18                 :            : #include <sys/param.h>
      19                 :            : 
      20                 :            : #include "api/s2n.h"
      21                 :            : #include "error/s2n_errno.h"
      22                 :            : #include "stuffer/s2n_stuffer.h"
      23                 :            : #include "tls/s2n_cipher_suites.h"
      24                 :            : #include "tls/s2n_connection.h"
      25                 :            : #include "tls/s2n_crypto.h"
      26                 :            : #include "tls/s2n_tls.h"
      27                 :            : #include "utils/s2n_blob.h"
      28                 :            : #include "utils/s2n_random.h"
      29                 :            : #include "utils/s2n_safety.h"
      30                 :            : 
      31                 :            : int s2n_allowed_to_cache_connection(struct s2n_connection *conn)
      32                 :      12394 : {
      33                 :            :     /* We're unable to cache connections with a Client Cert since we currently don't serialize the Client Cert,
      34                 :            :      * which means that callers won't have access to the Client's Cert if the connection is resumed. */
      35         [ +  + ]:      12394 :     if (s2n_connection_is_client_auth_enabled(conn)) {
      36                 :       4752 :         return 0;
      37                 :       4752 :     }
      38                 :            : 
      39                 :       7642 :     struct s2n_config *config = conn->config;
      40                 :            : 
      41 [ -  + ][ #  # ]:       7642 :     POSIX_ENSURE_REF(config);
      42                 :       7642 :     return config->use_session_cache;
      43                 :       7642 : }
      44                 :            : 
      45                 :            : /* If a protocol version is required before the actual_protocol_version
      46                 :            :  * is negotiated, we should fall back to resume_protocol_version if available.
      47                 :            :  *
      48                 :            :  * This covers the case where the application requests a ticket / session state
      49                 :            :  * before a NewSessionTicket message has been sent or received. Historically,
      50                 :            :  * in that case we return the ticket / session state already set for the connection.
      51                 :            :  * resume_protocol_version represents the protocol version of that existing ticket / state.
      52                 :            :  */
      53                 :            : static uint8_t s2n_resume_protocol_version(struct s2n_connection *conn)
      54                 :        943 : {
      55 [ +  + ][ -  + ]:        943 :     if (!IS_NEGOTIATED(conn) && conn->resume_protocol_version) {
      56                 :          0 :         return conn->resume_protocol_version;
      57                 :        943 :     } else {
      58                 :        943 :         return conn->actual_protocol_version;
      59                 :        943 :     }
      60                 :        943 : }
      61                 :            : 
      62                 :            : static int s2n_tls12_serialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *to)
      63                 :         39 : {
      64 [ #  # ][ -  + ]:         39 :     POSIX_ENSURE_REF(to);
      65 [ -  + ][ #  # ]:         39 :     POSIX_ENSURE_REF(conn);
      66 [ -  + ][ #  # ]:         39 :     POSIX_ENSURE_REF(conn->secure);
      67                 :            : 
      68                 :         39 :     uint64_t now = 0;
      69                 :            : 
      70 [ -  + ][ #  # ]:         39 :     S2N_ERROR_IF(s2n_stuffer_space_remaining(to) < S2N_TLS12_STATE_SIZE_IN_BYTES, S2N_ERR_STUFFER_IS_FULL);
      71                 :            : 
      72                 :            :     /* Get the time */
      73         [ -  + ]:         39 :     POSIX_GUARD_RESULT(s2n_config_wall_clock(conn->config, &now));
      74                 :            : 
      75                 :            :     /* Write the entry */
      76         [ -  + ]:         39 :     POSIX_GUARD(s2n_stuffer_write_uint8(to, S2N_SERIALIZED_FORMAT_TLS12_V3));
      77         [ -  + ]:         39 :     POSIX_GUARD(s2n_stuffer_write_uint8(to, s2n_resume_protocol_version(conn)));
      78         [ -  + ]:         39 :     POSIX_GUARD(s2n_stuffer_write_bytes(to, conn->secure->cipher_suite->iana_value, S2N_TLS_CIPHER_SUITE_LEN));
      79         [ -  + ]:         39 :     POSIX_GUARD(s2n_stuffer_write_uint64(to, now));
      80         [ -  + ]:         39 :     POSIX_GUARD(s2n_stuffer_write_bytes(to, conn->secrets.version.tls12.master_secret, S2N_TLS_SECRET_LEN));
      81         [ -  + ]:         39 :     POSIX_GUARD(s2n_stuffer_write_uint8(to, conn->ems_negotiated));
      82                 :            : 
      83                 :         39 :     return S2N_SUCCESS;
      84                 :         39 : }
      85                 :            : 
      86                 :            : static S2N_RESULT s2n_tls13_serialize_keying_material_expiration(struct s2n_connection *conn,
      87                 :            :         uint64_t now, struct s2n_stuffer *out)
      88                 :        386 : {
      89 [ #  # ][ -  + ]:        386 :     RESULT_ENSURE_REF(conn);
      90 [ #  # ][ -  + ]:        386 :     RESULT_ENSURE_REF(out);
      91                 :            : 
      92         [ +  + ]:        386 :     if (conn->mode != S2N_SERVER) {
      93                 :        207 :         return S2N_RESULT_OK;
      94                 :        207 :     }
      95                 :            : 
      96                 :        179 :     uint64_t expiration_timestamp = now + (conn->server_keying_material_lifetime * (uint64_t) ONE_SEC_IN_NANOS);
      97                 :            : 
      98                 :        179 :     struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk;
      99 [ +  + ][ +  - ]:        179 :     if (chosen_psk && chosen_psk->type == S2N_PSK_TYPE_RESUMPTION) {
     100                 :          5 :         expiration_timestamp = MIN(chosen_psk->keying_material_expiration, expiration_timestamp);
     101                 :          5 :     }
     102                 :            : 
     103         [ -  + ]:        179 :     RESULT_GUARD_POSIX(s2n_stuffer_write_uint64(out, expiration_timestamp));
     104                 :        179 :     return S2N_RESULT_OK;
     105                 :        179 : }
     106                 :            : 
     107                 :            : static S2N_RESULT s2n_tls13_serialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *out)
     108                 :        386 : {
     109 [ -  + ][ #  # ]:        386 :     RESULT_ENSURE_REF(out);
     110 [ #  # ][ -  + ]:        386 :     RESULT_ENSURE_REF(conn);
     111 [ -  + ][ #  # ]:        386 :     RESULT_ENSURE_REF(conn->secure);
     112                 :            : 
     113                 :        386 :     uint64_t current_time = 0;
     114                 :        386 :     struct s2n_ticket_fields *ticket_fields = &conn->tls13_ticket_fields;
     115                 :            : 
     116                 :            :     /* Get the time */
     117         [ -  + ]:        386 :     RESULT_GUARD(s2n_config_wall_clock(conn->config, &current_time));
     118                 :            : 
     119         [ -  + ]:        386 :     RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, S2N_SERIALIZED_FORMAT_TLS13_V1));
     120         [ -  + ]:        386 :     RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, conn->actual_protocol_version));
     121         [ -  + ]:        386 :     RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(out, conn->secure->cipher_suite->iana_value, S2N_TLS_CIPHER_SUITE_LEN));
     122         [ -  + ]:        386 :     RESULT_GUARD_POSIX(s2n_stuffer_write_uint64(out, current_time));
     123         [ -  + ]:        386 :     RESULT_GUARD_POSIX(s2n_stuffer_write_uint32(out, ticket_fields->ticket_age_add));
     124 [ #  # ][ -  + ]:        386 :     RESULT_ENSURE_INCLUSIVE_RANGE(1, ticket_fields->session_secret.size, UINT8_MAX);
         [ -  + ][ #  # ]
     125         [ -  + ]:        386 :     RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, ticket_fields->session_secret.size));
     126         [ -  + ]:        386 :     RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(out, ticket_fields->session_secret.data, ticket_fields->session_secret.size));
     127         [ -  + ]:        386 :     RESULT_GUARD(s2n_tls13_serialize_keying_material_expiration(conn, current_time, out));
     128                 :            : 
     129                 :        386 :     uint32_t server_max_early_data = 0;
     130         [ -  + ]:        386 :     RESULT_GUARD(s2n_early_data_get_server_max_size(conn, &server_max_early_data));
     131         [ -  + ]:        386 :     RESULT_GUARD_POSIX(s2n_stuffer_write_uint32(out, server_max_early_data));
     132         [ +  + ]:        386 :     if (server_max_early_data > 0) {
     133                 :         81 :         uint8_t application_protocol_len = strlen(conn->application_protocol);
     134         [ -  + ]:         81 :         RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, application_protocol_len));
     135         [ -  + ]:         81 :         RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(out, (uint8_t *) conn->application_protocol, application_protocol_len));
     136         [ -  + ]:         81 :         RESULT_GUARD_POSIX(s2n_stuffer_write_uint16(out, conn->server_early_data_context.size));
     137         [ -  + ]:         81 :         RESULT_GUARD_POSIX(s2n_stuffer_write(out, &conn->server_early_data_context));
     138                 :         81 :     }
     139                 :            : 
     140                 :        386 :     return S2N_RESULT_OK;
     141                 :        386 : }
     142                 :            : 
     143                 :            : static S2N_RESULT s2n_serialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *out)
     144                 :        425 : {
     145         [ +  + ]:        425 :     if (s2n_resume_protocol_version(conn) < S2N_TLS13) {
     146         [ -  + ]:         39 :         RESULT_GUARD_POSIX(s2n_tls12_serialize_resumption_state(conn, out));
     147                 :        386 :     } else {
     148         [ -  + ]:        386 :         RESULT_GUARD(s2n_tls13_serialize_resumption_state(conn, out));
     149                 :        386 :     }
     150                 :        425 :     return S2N_RESULT_OK;
     151                 :        425 : }
     152                 :            : 
     153                 :            : static int s2n_tls12_deserialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *from)
     154                 :         11 : {
     155 [ #  # ][ -  + ]:         11 :     POSIX_ENSURE_REF(conn);
     156 [ -  + ][ #  # ]:         11 :     POSIX_ENSURE_REF(conn->secure);
     157                 :            : 
     158                 :         11 :     uint8_t protocol_version = 0;
     159                 :         11 :     uint8_t cipher_suite[S2N_TLS_CIPHER_SUITE_LEN] = { 0 };
     160                 :            : 
     161 [ -  + ][ #  # ]:         11 :     S2N_ERROR_IF(s2n_stuffer_data_available(from) < S2N_TLS12_STATE_SIZE_IN_BYTES - sizeof(uint8_t), S2N_ERR_STUFFER_OUT_OF_DATA);
     162                 :            : 
     163         [ -  + ]:         11 :     POSIX_GUARD(s2n_stuffer_read_uint8(from, &protocol_version));
     164 [ -  + ][ #  # ]:         11 :     S2N_ERROR_IF(protocol_version != conn->actual_protocol_version, S2N_ERR_INVALID_SERIALIZED_SESSION_STATE);
     165                 :            : 
     166         [ -  + ]:         11 :     POSIX_GUARD(s2n_stuffer_read_bytes(from, cipher_suite, S2N_TLS_CIPHER_SUITE_LEN));
     167 [ #  # ][ -  + ]:         11 :     POSIX_ENSURE(s2n_constant_time_equals(conn->secure->cipher_suite->iana_value, cipher_suite, S2N_TLS_CIPHER_SUITE_LEN), S2N_ERR_INVALID_SERIALIZED_SESSION_STATE);
     168                 :            : 
     169                 :         11 :     uint64_t now = 0;
     170         [ -  + ]:         11 :     POSIX_GUARD_RESULT(s2n_config_wall_clock(conn->config, &now));
     171                 :            : 
     172                 :         11 :     uint64_t then = 0;
     173         [ -  + ]:         11 :     POSIX_GUARD(s2n_stuffer_read_uint64(from, &then));
     174 [ -  + ][ #  # ]:         11 :     S2N_ERROR_IF(then > now, S2N_ERR_INVALID_SERIALIZED_SESSION_STATE);
     175 [ -  + ][ #  # ]:         11 :     S2N_ERROR_IF(now - then > conn->config->session_state_lifetime_in_nanos, S2N_ERR_INVALID_SERIALIZED_SESSION_STATE);
     176                 :            : 
     177         [ -  + ]:         11 :     POSIX_GUARD(s2n_stuffer_read_bytes(from, conn->secrets.version.tls12.master_secret, S2N_TLS_SECRET_LEN));
     178                 :            : 
     179         [ +  - ]:         11 :     if (s2n_stuffer_data_available(from)) {
     180                 :         11 :         uint8_t ems_negotiated = 0;
     181         [ -  + ]:         11 :         POSIX_GUARD(s2n_stuffer_read_uint8(from, &ems_negotiated));
     182                 :            : 
     183                 :            :         /**
     184                 :            :          *= https://www.rfc-editor.org/rfc/rfc7627#section-5.3
     185                 :            :          *# o  If the original session did not use the "extended_master_secret"
     186                 :            :          *#    extension but the new ClientHello contains the extension, then the
     187                 :            :          *#    server MUST NOT perform the abbreviated handshake.  Instead, it
     188                 :            :          *#    SHOULD continue with a full handshake (as described in
     189                 :            :          *#    Section 5.2) to negotiate a new session.
     190                 :            :          *#
     191                 :            :          *# o  If the original session used the "extended_master_secret"
     192                 :            :          *#    extension but the new ClientHello does not contain it, the server
     193                 :            :          *#    MUST abort the abbreviated handshake.
     194                 :            :          **/
     195         [ +  + ]:         11 :         if (conn->ems_negotiated != ems_negotiated) {
     196                 :            :             /* The session ticket needs to have the same EMS state as the current session. If it doesn't
     197                 :            :              * have the same state, the current session takes the state of the session ticket and errors.
     198                 :            :              * If the deserialization process errors, we will use this state in a few extra checks
     199                 :            :              * to determine if we can fallback to a full handshake.
     200                 :            :              */
     201                 :          4 :             conn->ems_negotiated = ems_negotiated;
     202         [ +  - ]:          4 :             POSIX_BAIL(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE);
     203                 :          4 :         }
     204                 :         11 :     }
     205                 :            : 
     206                 :          7 :     return S2N_SUCCESS;
     207                 :         11 : }
     208                 :            : 
     209                 :            : static int s2n_client_serialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *to)
     210                 :        218 : {
     211                 :            :     /* Serialize session ticket */
     212 [ +  + ][ +  + ]:        218 :     if (conn->config->use_tickets && conn->client_ticket.size > 0) {
     213         [ -  + ]:        213 :         POSIX_GUARD(s2n_stuffer_write_uint8(to, S2N_STATE_WITH_SESSION_TICKET));
     214         [ -  + ]:        213 :         POSIX_GUARD(s2n_stuffer_write_uint16(to, conn->client_ticket.size));
     215         [ -  + ]:        213 :         POSIX_GUARD(s2n_stuffer_write(to, &conn->client_ticket));
     216                 :        213 :     } else {
     217                 :            :         /* Serialize session id */
     218 [ -  + ][ #  # ]:          5 :         POSIX_ENSURE_LT(conn->actual_protocol_version, S2N_TLS13);
     219         [ -  + ]:          5 :         POSIX_GUARD(s2n_stuffer_write_uint8(to, S2N_STATE_WITH_SESSION_ID));
     220         [ -  + ]:          5 :         POSIX_GUARD(s2n_stuffer_write_uint8(to, conn->session_id_len));
     221         [ -  + ]:          5 :         POSIX_GUARD(s2n_stuffer_write_bytes(to, conn->session_id, conn->session_id_len));
     222                 :          5 :     }
     223                 :            : 
     224                 :            :     /* Serialize session state */
     225         [ -  + ]:        218 :     POSIX_GUARD_RESULT(s2n_serialize_resumption_state(conn, to));
     226                 :            : 
     227                 :        218 :     return 0;
     228                 :        218 : }
     229                 :            : 
     230                 :            : static S2N_RESULT s2n_tls12_client_deserialize_session_state(struct s2n_connection *conn,
     231                 :            :         struct s2n_blob *ticket, struct s2n_stuffer *from)
     232                 :         13 : {
     233 [ -  + ][ #  # ]:         13 :     RESULT_ENSURE_REF(conn);
     234 [ -  + ][ #  # ]:         13 :     RESULT_ENSURE_REF(from);
     235                 :            : 
     236                 :            :     /* Operate on a copy of the connection to avoid mutating the connection on
     237                 :            :      * failure. We have tests in s2n_resume_test.c that prove this level of copy
     238                 :            :      * is sufficient.
     239                 :            :      */
     240                 :         13 :     struct s2n_crypto_parameters *secure = conn->secure;
     241 [ -  + ][ #  # ]:         13 :     RESULT_ENSURE_REF(secure);
     242                 :         13 :     struct s2n_connection temp_conn = *conn;
     243                 :         13 :     struct s2n_crypto_parameters temp_secure = *secure;
     244                 :         13 :     temp_conn.secure = &temp_secure;
     245                 :            : 
     246         [ -  + ]:         13 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &temp_conn.resume_protocol_version));
     247                 :            : 
     248                 :         13 :     uint8_t *cipher_suite_wire = s2n_stuffer_raw_read(from, S2N_TLS_CIPHER_SUITE_LEN);
     249 [ -  + ][ #  # ]:         13 :     RESULT_ENSURE_REF(cipher_suite_wire);
     250         [ -  + ]:         13 :     RESULT_GUARD_POSIX(s2n_set_cipher_as_client(&temp_conn, cipher_suite_wire));
     251                 :            : 
     252                 :         13 :     uint64_t then = 0;
     253         [ -  + ]:         13 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint64(from, &then));
     254                 :            : 
     255         [ -  + ]:         13 :     RESULT_GUARD_POSIX(s2n_stuffer_read_bytes(from, temp_conn.secrets.version.tls12.master_secret,
     256                 :         13 :             S2N_TLS_SECRET_LEN));
     257                 :            : 
     258         [ +  - ]:         13 :     if (s2n_stuffer_data_available(from)) {
     259                 :         13 :         uint8_t ems_negotiated = 0;
     260         [ -  + ]:         13 :         RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &ems_negotiated));
     261                 :         13 :         temp_conn.ems_negotiated = ems_negotiated;
     262                 :         13 :     }
     263                 :            : 
     264                 :         13 :     DEFER_CLEANUP(struct s2n_blob client_ticket = { 0 }, s2n_free);
     265         [ +  + ]:         13 :     if (ticket) {
     266         [ -  + ]:          8 :         RESULT_GUARD_POSIX(s2n_dup(ticket, &client_ticket));
     267                 :          8 :     }
     268                 :            : 
     269                 :            :     /* Finally, actually update the connection */
     270         [ -  + ]:         13 :     RESULT_GUARD_POSIX(s2n_free(&conn->client_ticket));
     271                 :         13 :     *secure = temp_secure;
     272                 :         13 :     *conn = temp_conn;
     273                 :         13 :     conn->secure = secure;
     274                 :         13 :     conn->client_ticket = client_ticket;
     275                 :         13 :     ZERO_TO_DISABLE_DEFER_CLEANUP(client_ticket);
     276                 :            : 
     277                 :         13 :     return S2N_RESULT_OK;
     278                 :         13 : }
     279                 :            : 
     280                 :            : /* `s2n_validate_ticket_age` is a best effort check that the session ticket is
     281                 :            :  * less than one week old.
     282                 :            :  *
     283                 :            :  * Clock skew between hosts or the possibility of a clock jump prevent this from
     284                 :            :  * being a precise check.
     285                 :            :  */
     286                 :            : static S2N_RESULT s2n_validate_ticket_age(uint64_t current_time, uint64_t ticket_issue_time)
     287                 :         18 : {
     288                 :            :     /* If the `ticket_issue_time` is in the future, then we are observing clock skew.
     289                 :            :      * We shouldn't fully reject the ticket, but we assert that the clock skew is
     290                 :            :      * less than some MAX_ALLOWED_CLOCK_SKEW_SEC
     291                 :            :      */
     292         [ -  + ]:         18 :     if (current_time < ticket_issue_time) {
     293                 :          0 :         uint64_t clock_skew_in_nanos = ticket_issue_time - current_time;
     294                 :          0 :         uint64_t clock_skew_in_seconds = clock_skew_in_nanos / ONE_SEC_IN_NANOS;
     295 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE(clock_skew_in_seconds <= MAX_ALLOWED_CLOCK_SKEW_SEC, S2N_ERR_INVALID_SESSION_TICKET);
     296                 :         18 :     } else {
     297                 :         18 :         uint64_t ticket_age_in_nanos = current_time - ticket_issue_time;
     298                 :         18 :         uint64_t ticket_age_in_sec = ticket_age_in_nanos / ONE_SEC_IN_NANOS;
     299 [ #  # ][ -  + ]:         18 :         RESULT_ENSURE(ticket_age_in_sec <= ONE_WEEK_IN_SEC, S2N_ERR_INVALID_SESSION_TICKET);
     300                 :         18 :     }
     301                 :         18 :     return S2N_RESULT_OK;
     302                 :         18 : }
     303                 :            : 
     304                 :            : static S2N_RESULT s2n_tls13_deserialize_session_state(struct s2n_connection *conn, struct s2n_blob *psk_identity, struct s2n_stuffer *from)
     305                 :         18 : {
     306 [ -  + ][ #  # ]:         18 :     RESULT_ENSURE_REF(conn);
     307 [ -  + ][ #  # ]:         18 :     RESULT_ENSURE_REF(psk_identity);
     308 [ -  + ][ #  # ]:         18 :     RESULT_ENSURE_REF(from);
     309                 :            : 
     310                 :         18 :     DEFER_CLEANUP(struct s2n_psk psk = { 0 }, s2n_psk_wipe);
     311         [ -  + ]:         18 :     RESULT_GUARD(s2n_psk_init(&psk, S2N_PSK_TYPE_RESUMPTION));
     312         [ -  + ]:         18 :     RESULT_GUARD_POSIX(s2n_psk_set_identity(&psk, psk_identity->data, psk_identity->size));
     313                 :            : 
     314                 :         18 :     uint8_t protocol_version = 0;
     315         [ -  + ]:         18 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &protocol_version));
     316 [ #  # ][ -  + ]:         18 :     RESULT_ENSURE_GTE(protocol_version, S2N_TLS13);
     317                 :            : 
     318                 :         18 :     uint8_t iana_id[S2N_TLS_CIPHER_SUITE_LEN] = { 0 };
     319         [ -  + ]:         18 :     RESULT_GUARD_POSIX(s2n_stuffer_read_bytes(from, iana_id, S2N_TLS_CIPHER_SUITE_LEN));
     320                 :         18 :     struct s2n_cipher_suite *cipher_suite = NULL;
     321         [ -  + ]:         18 :     RESULT_GUARD(s2n_cipher_suite_from_iana(iana_id, sizeof(iana_id), &cipher_suite));
     322 [ -  + ][ #  # ]:         18 :     RESULT_ENSURE_REF(cipher_suite);
     323                 :         18 :     psk.hmac_alg = cipher_suite->prf_alg;
     324                 :            : 
     325         [ -  + ]:         18 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint64(from, &psk.ticket_issue_time));
     326                 :            : 
     327                 :            :     /**
     328                 :            :      *= https://www.rfc-editor.org/rfc/rfc8446#section-4.6.1
     329                 :            :      *# Clients MUST NOT cache
     330                 :            :      *# tickets for longer than 7 days, regardless of the ticket_lifetime,
     331                 :            :      *# and MAY delete tickets earlier based on local policy.
     332                 :            :      */
     333                 :         18 :     uint64_t current_time = 0;
     334         [ -  + ]:         18 :     RESULT_GUARD(s2n_config_wall_clock(conn->config, &current_time));
     335         [ -  + ]:         18 :     RESULT_GUARD(s2n_validate_ticket_age(current_time, psk.ticket_issue_time));
     336                 :            : 
     337         [ -  + ]:         18 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint32(from, &psk.ticket_age_add));
     338                 :            : 
     339                 :         18 :     uint8_t secret_len = 0;
     340         [ -  + ]:         18 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &secret_len));
     341 [ #  # ][ -  + ]:         18 :     RESULT_ENSURE_LTE(secret_len, S2N_TLS_SECRET_LEN);
     342                 :         18 :     uint8_t *secret_data = s2n_stuffer_raw_read(from, secret_len);
     343 [ -  + ][ #  # ]:         18 :     RESULT_ENSURE_REF(secret_data);
     344         [ -  + ]:         18 :     RESULT_GUARD_POSIX(s2n_psk_set_secret(&psk, secret_data, secret_len));
     345                 :            : 
     346         [ +  + ]:         18 :     if (conn->mode == S2N_SERVER) {
     347         [ -  + ]:         11 :         RESULT_GUARD_POSIX(s2n_stuffer_read_uint64(from, &psk.keying_material_expiration));
     348 [ -  + ][ #  # ]:         11 :         RESULT_ENSURE(psk.keying_material_expiration > current_time, S2N_ERR_KEYING_MATERIAL_EXPIRED);
     349                 :         11 :     }
     350                 :            : 
     351                 :         18 :     uint32_t max_early_data_size = 0;
     352         [ -  + ]:         18 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint32(from, &max_early_data_size));
     353         [ -  + ]:         18 :     if (max_early_data_size > 0) {
     354         [ #  # ]:          0 :         RESULT_GUARD_POSIX(s2n_psk_configure_early_data(&psk, max_early_data_size,
     355                 :          0 :                 iana_id[0], iana_id[1]));
     356                 :            : 
     357                 :          0 :         uint8_t app_proto_size = 0;
     358         [ #  # ]:          0 :         RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &app_proto_size));
     359                 :          0 :         uint8_t *app_proto_data = s2n_stuffer_raw_read(from, app_proto_size);
     360 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE_REF(app_proto_data);
     361         [ #  # ]:          0 :         RESULT_GUARD_POSIX(s2n_psk_set_application_protocol(&psk, app_proto_data, app_proto_size));
     362                 :            : 
     363                 :          0 :         uint16_t early_data_context_size = 0;
     364         [ #  # ]:          0 :         RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(from, &early_data_context_size));
     365                 :          0 :         uint8_t *early_data_context_data = s2n_stuffer_raw_read(from, early_data_context_size);
     366 [ #  # ][ #  # ]:          0 :         RESULT_ENSURE_REF(early_data_context_data);
     367         [ #  # ]:          0 :         RESULT_GUARD_POSIX(s2n_psk_set_early_data_context(&psk, early_data_context_data, early_data_context_size));
     368                 :          0 :     }
     369                 :            : 
     370                 :            :     /* Make sure that this connection is configured for resumption PSKs, not external PSKs */
     371         [ -  + ]:         18 :     RESULT_GUARD(s2n_connection_set_psk_type(conn, S2N_PSK_TYPE_RESUMPTION));
     372                 :            :     /* Remove all previously-set PSKs. To keep the session ticket API behavior consistent
     373                 :            :      * across protocol versions, we currently only support setting a single resumption PSK. */
     374         [ -  + ]:         18 :     RESULT_GUARD(s2n_psk_parameters_wipe(&conn->psk_params));
     375         [ -  + ]:         18 :     RESULT_GUARD_POSIX(s2n_connection_append_psk(conn, &psk));
     376                 :            : 
     377                 :         18 :     return S2N_RESULT_OK;
     378                 :         18 : }
     379                 :            : 
     380                 :            : S2N_RESULT s2n_deserialize_resumption_state(struct s2n_connection *conn,
     381                 :            :         struct s2n_blob *ticket, struct s2n_stuffer *from)
     382                 :        328 : {
     383 [ #  # ][ -  + ]:        328 :     RESULT_ENSURE_REF(conn);
     384 [ -  + ][ #  # ]:        328 :     RESULT_ENSURE_REF(from);
     385                 :            : 
     386                 :        328 :     uint8_t format = 0;
     387         [ -  + ]:        328 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &format));
     388                 :            : 
     389         [ +  + ]:        328 :     if (format == S2N_SERIALIZED_FORMAT_TLS12_V3) {
     390         [ +  + ]:         82 :         if (conn->mode == S2N_SERVER) {
     391         [ +  + ]:         37 :             RESULT_GUARD_POSIX(s2n_tls12_deserialize_resumption_state(conn, from));
     392                 :         45 :         } else {
     393         [ +  + ]:         45 :             RESULT_GUARD(s2n_tls12_client_deserialize_session_state(conn, ticket, from));
     394                 :         45 :         }
     395         [ +  + ]:        246 :     } else if (format == S2N_SERIALIZED_FORMAT_TLS13_V1) {
     396         [ +  + ]:        244 :         RESULT_GUARD(s2n_tls13_deserialize_session_state(conn, ticket, from));
     397                 :        244 :     } else {
     398         [ +  - ]:          2 :         RESULT_BAIL(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE);
     399                 :          2 :     }
     400                 :        315 :     conn->set_session = true;
     401                 :        315 :     return S2N_RESULT_OK;
     402                 :        328 : }
     403                 :            : 
     404                 :            : static int s2n_client_deserialize_with_session_id(struct s2n_connection *conn, struct s2n_stuffer *from)
     405                 :          6 : {
     406                 :          6 :     uint8_t session_id_len = 0;
     407         [ -  + ]:          6 :     POSIX_GUARD(s2n_stuffer_read_uint8(from, &session_id_len));
     408                 :            : 
     409 [ +  + ][ -  + ]:          6 :     if (session_id_len == 0 || session_id_len > S2N_TLS_SESSION_ID_MAX_LEN
     410         [ -  + ]:          6 :             || session_id_len > s2n_stuffer_data_available(from)) {
     411         [ +  - ]:          1 :         POSIX_BAIL(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE);
     412                 :          1 :     }
     413                 :            : 
     414                 :          5 :     conn->session_id_len = session_id_len;
     415         [ -  + ]:          5 :     POSIX_GUARD(s2n_stuffer_read_bytes(from, conn->session_id, session_id_len));
     416                 :            : 
     417         [ -  + ]:          5 :     POSIX_GUARD_RESULT(s2n_deserialize_resumption_state(conn, NULL, from));
     418                 :            : 
     419                 :          5 :     return 0;
     420                 :          5 : }
     421                 :            : 
     422                 :            : static int s2n_client_deserialize_with_session_ticket(struct s2n_connection *conn, struct s2n_stuffer *from)
     423                 :         14 : {
     424                 :         14 :     uint16_t session_ticket_len = 0;
     425         [ -  + ]:         14 :     POSIX_GUARD(s2n_stuffer_read_uint16(from, &session_ticket_len));
     426                 :            : 
     427 [ -  + ][ -  + ]:         14 :     if (session_ticket_len == 0 || session_ticket_len > s2n_stuffer_data_available(from)) {
     428         [ #  # ]:          0 :         POSIX_BAIL(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE);
     429                 :          0 :     }
     430                 :            : 
     431                 :         14 :     struct s2n_blob session_ticket = { 0 };
     432                 :         14 :     uint8_t *session_ticket_bytes = s2n_stuffer_raw_read(from, session_ticket_len);
     433 [ -  + ][ #  # ]:         14 :     POSIX_ENSURE_REF(session_ticket_bytes);
     434         [ -  + ]:         14 :     POSIX_GUARD(s2n_blob_init(&session_ticket, session_ticket_bytes, session_ticket_len));
     435                 :            : 
     436         [ -  + ]:         14 :     POSIX_GUARD_RESULT(s2n_deserialize_resumption_state(conn, &session_ticket, from));
     437                 :         14 :     return 0;
     438                 :         14 : }
     439                 :            : 
     440                 :            : static int s2n_client_deserialize_resumption_state(struct s2n_connection *conn, struct s2n_stuffer *from)
     441                 :         21 : {
     442                 :         21 :     uint8_t format = 0;
     443         [ -  + ]:         21 :     POSIX_GUARD(s2n_stuffer_read_uint8(from, &format));
     444                 :            : 
     445                 :         21 :     switch (format) {
     446         [ +  + ]:          6 :         case S2N_STATE_WITH_SESSION_ID:
     447         [ +  + ]:          6 :             POSIX_GUARD(s2n_client_deserialize_with_session_id(conn, from));
     448                 :          5 :             break;
     449         [ +  + ]:         14 :         case S2N_STATE_WITH_SESSION_TICKET:
     450         [ -  + ]:         14 :             POSIX_GUARD(s2n_client_deserialize_with_session_ticket(conn, from));
     451                 :         14 :             break;
     452         [ +  + ]:         14 :         default:
     453         [ +  - ]:          1 :             POSIX_BAIL(S2N_ERR_INVALID_SERIALIZED_SESSION_STATE);
     454                 :         21 :     }
     455                 :            : 
     456                 :         19 :     return 0;
     457                 :         21 : }
     458                 :            : 
     459                 :            : int s2n_resume_from_cache(struct s2n_connection *conn)
     460                 :         16 : {
     461 [ +  + ][ +  - ]:         16 :     S2N_ERROR_IF(conn->session_id_len == 0, S2N_ERR_SESSION_ID_TOO_SHORT);
     462 [ -  + ][ #  # ]:         13 :     S2N_ERROR_IF(conn->session_id_len > S2N_TLS_SESSION_ID_MAX_LEN, S2N_ERR_SESSION_ID_TOO_LONG);
     463                 :            : 
     464                 :         13 :     uint8_t data[S2N_TLS12_TICKET_SIZE_IN_BYTES] = { 0 };
     465                 :         13 :     struct s2n_blob entry = { 0 };
     466         [ -  + ]:         13 :     POSIX_GUARD(s2n_blob_init(&entry, data, S2N_TLS12_TICKET_SIZE_IN_BYTES));
     467                 :         13 :     uint64_t size = entry.size;
     468                 :         13 :     int result = conn->config->cache_retrieve(conn, conn->config->cache_retrieve_data, conn->session_id, conn->session_id_len, entry.data, &size);
     469         [ +  + ]:         13 :     if (result == S2N_CALLBACK_BLOCKED) {
     470         [ +  - ]:          6 :         POSIX_BAIL(S2N_ERR_ASYNC_BLOCKED);
     471                 :          6 :     }
     472 [ +  - ][ +  + ]:          7 :     POSIX_ENSURE(result >= S2N_SUCCESS, S2N_ERR_CANCELLED);
     473                 :            : 
     474 [ -  + ][ #  # ]:          6 :     S2N_ERROR_IF(size != entry.size, S2N_ERR_SIZE_MISMATCH);
     475                 :            : 
     476                 :          6 :     struct s2n_stuffer from = { 0 };
     477         [ -  + ]:          6 :     POSIX_GUARD(s2n_stuffer_init(&from, &entry));
     478         [ -  + ]:          6 :     POSIX_GUARD(s2n_stuffer_write(&from, &entry));
     479         [ +  + ]:          6 :     POSIX_GUARD_RESULT(s2n_resume_decrypt_session(conn, &from));
     480                 :            : 
     481                 :          3 :     return 0;
     482                 :          6 : }
     483                 :            : 
     484                 :            : S2N_RESULT s2n_store_to_cache(struct s2n_connection *conn)
     485                 :          7 : {
     486                 :          7 :     uint8_t data[S2N_TLS12_TICKET_SIZE_IN_BYTES] = { 0 };
     487                 :          7 :     struct s2n_blob entry = { 0 };
     488         [ -  + ]:          7 :     RESULT_GUARD_POSIX(s2n_blob_init(&entry, data, S2N_TLS12_TICKET_SIZE_IN_BYTES));
     489                 :          7 :     struct s2n_stuffer to = { 0 };
     490                 :            : 
     491                 :            :     /* session_id_len should always be >0 since either the Client provided a SessionId or the Server generated a new
     492                 :            :      * one for the Client */
     493 [ #  # ][ -  + ]:          7 :     RESULT_ENSURE(conn->session_id_len > 0, S2N_ERR_SESSION_ID_TOO_SHORT);
     494 [ #  # ][ -  + ]:          7 :     RESULT_ENSURE(conn->session_id_len <= S2N_TLS_SESSION_ID_MAX_LEN, S2N_ERR_SESSION_ID_TOO_LONG);
     495                 :            : 
     496         [ -  + ]:          7 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&to, &entry));
     497                 :            : 
     498                 :          7 :     struct s2n_ticket_key *key = s2n_get_ticket_encrypt_decrypt_key(conn->config);
     499         [ +  + ]:          7 :     RESULT_GUARD(s2n_resume_encrypt_session_ticket(conn, key, &to));
     500                 :            : 
     501                 :            :     /* Store to the cache */
     502                 :          5 :     conn->config->cache_store(conn, conn->config->cache_store_data, S2N_TLS_SESSION_CACHE_TTL, conn->session_id, conn->session_id_len, entry.data, entry.size);
     503                 :            : 
     504                 :          5 :     return S2N_RESULT_OK;
     505                 :          7 : }
     506                 :            : 
     507                 :            : int s2n_connection_set_session(struct s2n_connection *conn, const uint8_t *session, size_t length)
     508                 :        157 : {
     509 [ #  # ][ -  + ]:        157 :     POSIX_ENSURE_REF(conn);
     510 [ #  # ][ -  + ]:        157 :     POSIX_ENSURE_REF(session);
     511                 :            : 
     512                 :        157 :     DEFER_CLEANUP(struct s2n_blob session_data = { 0 }, s2n_free);
     513         [ -  + ]:        157 :     POSIX_GUARD(s2n_alloc(&session_data, length));
     514 [ #  # ][ -  + ]:        157 :     POSIX_CHECKED_MEMCPY(session_data.data, session, length);
                 [ +  - ]
     515                 :            : 
     516                 :        157 :     struct s2n_stuffer from = { 0 };
     517         [ -  + ]:        157 :     POSIX_GUARD(s2n_stuffer_init(&from, &session_data));
     518         [ -  + ]:        157 :     POSIX_GUARD(s2n_stuffer_write(&from, &session_data));
     519         [ +  + ]:        157 :     POSIX_GUARD(s2n_client_deserialize_resumption_state(conn, &from));
     520                 :        152 :     return 0;
     521                 :        157 : }
     522                 :            : 
     523                 :            : int s2n_connection_get_session(struct s2n_connection *conn, uint8_t *session, size_t max_length)
     524                 :        470 : {
     525 [ -  + ][ #  # ]:        470 :     POSIX_ENSURE_REF(conn);
     526 [ -  + ][ #  # ]:        470 :     POSIX_ENSURE_REF(session);
     527                 :            : 
     528                 :        470 :     const int len = s2n_connection_get_session_length(conn);
     529         [ -  + ]:        470 :     POSIX_GUARD(len);
     530                 :            : 
     531         [ +  + ]:        470 :     if (len == 0) {
     532                 :          2 :         return 0;
     533                 :          2 :     }
     534                 :            : 
     535 [ +  - ][ +  + ]:        468 :     POSIX_ENSURE((size_t) len <= max_length, S2N_ERR_SERIALIZED_SESSION_STATE_TOO_LONG);
     536                 :            : 
     537                 :        467 :     struct s2n_blob serialized_data = { 0 };
     538         [ -  + ]:        467 :     POSIX_GUARD(s2n_blob_init(&serialized_data, session, len));
     539         [ -  + ]:        467 :     POSIX_GUARD(s2n_blob_zero(&serialized_data));
     540                 :            : 
     541                 :        467 :     struct s2n_stuffer to = { 0 };
     542         [ -  + ]:        467 :     POSIX_GUARD(s2n_stuffer_init(&to, &serialized_data));
     543         [ -  + ]:        467 :     POSIX_GUARD(s2n_client_serialize_resumption_state(conn, &to));
     544                 :            : 
     545                 :        467 :     return len;
     546                 :        467 : }
     547                 :            : 
     548                 :            : int s2n_connection_get_session_ticket_lifetime_hint(struct s2n_connection *conn)
     549                 :         19 : {
     550 [ #  # ][ -  + ]:         19 :     POSIX_ENSURE_REF(conn);
     551 [ +  + ][ +  - ]:         19 :     S2N_ERROR_IF(!(conn->config->use_tickets && conn->client_ticket.size > 0), S2N_ERR_SESSION_TICKET_NOT_SUPPORTED);
                 [ +  - ]
     552                 :            : 
     553                 :            :     /* Session resumption using session ticket */
     554                 :         18 :     return conn->ticket_lifetime_hint;
     555                 :         19 : }
     556                 :            : 
     557                 :            : S2N_RESULT s2n_connection_get_session_state_size(struct s2n_connection *conn, size_t *state_size)
     558                 :       1227 : {
     559 [ +  + ][ +  - ]:       1227 :     RESULT_ENSURE_REF(conn);
     560 [ -  + ][ #  # ]:       1226 :     RESULT_ENSURE_REF(conn->secure);
     561 [ +  + ][ +  - ]:       1226 :     RESULT_ENSURE_REF(state_size);
     562                 :            : 
     563         [ +  + ]:       1225 :     if (s2n_resume_protocol_version(conn) < S2N_TLS13) {
     564                 :         64 :         *state_size = S2N_TLS12_STATE_SIZE_IN_BYTES;
     565                 :         64 :         return S2N_RESULT_OK;
     566                 :         64 :     }
     567                 :            : 
     568                 :       1161 :     *state_size = S2N_TLS13_FIXED_STATE_SIZE;
     569                 :            : 
     570                 :       1161 :     uint8_t secret_size = 0;
     571 [ #  # ][ -  + ]:       1161 :     RESULT_ENSURE_REF(conn->secure->cipher_suite);
     572         [ -  + ]:       1161 :     RESULT_GUARD_POSIX(s2n_hmac_digest_size(conn->secure->cipher_suite->prf_alg, &secret_size));
     573                 :       1161 :     *state_size += secret_size;
     574                 :            : 
     575                 :       1161 :     uint32_t server_max_early_data = 0;
     576         [ -  + ]:       1161 :     RESULT_GUARD(s2n_early_data_get_server_max_size(conn, &server_max_early_data));
     577         [ +  + ]:       1161 :     if (server_max_early_data > 0) {
     578                 :        386 :         *state_size += S2N_TLS13_FIXED_EARLY_DATA_STATE_SIZE
     579                 :        386 :                 + strlen(conn->application_protocol)
     580                 :        386 :                 + conn->server_early_data_context.size;
     581                 :        386 :     }
     582                 :            : 
     583                 :       1161 :     return S2N_RESULT_OK;
     584                 :       1161 : }
     585                 :            : 
     586                 :            : static S2N_RESULT s2n_connection_get_session_length_impl(struct s2n_connection *conn, size_t *length)
     587                 :        437 : {
     588 [ #  # ][ -  + ]:        437 :     RESULT_ENSURE_REF(conn);
     589 [ -  + ][ #  # ]:        437 :     RESULT_ENSURE_REF(conn->config);
     590 [ #  # ][ -  + ]:        437 :     RESULT_ENSURE_REF(length);
     591                 :        437 :     *length = 0;
     592                 :            : 
     593 [ +  + ][ +  + ]:        437 :     if (conn->config->use_tickets && conn->client_ticket.size > 0) {
     594                 :        423 :         size_t session_state_size = 0;
     595         [ -  + ]:        423 :         RESULT_GUARD(s2n_connection_get_session_state_size(conn, &session_state_size));
     596                 :        423 :         *length = S2N_STATE_FORMAT_LEN + S2N_SESSION_TICKET_SIZE_LEN + conn->client_ticket.size + session_state_size;
     597 [ +  + ][ +  + ]:        423 :     } else if (conn->session_id_len > 0 && conn->actual_protocol_version < S2N_TLS13) {
     598                 :         10 :         *length = S2N_STATE_FORMAT_LEN + sizeof(conn->session_id_len) + conn->session_id_len + S2N_TLS12_STATE_SIZE_IN_BYTES;
     599                 :         10 :     }
     600                 :        437 :     return S2N_RESULT_OK;
     601                 :        437 : }
     602                 :            : 
     603                 :            : int s2n_connection_get_session_length(struct s2n_connection *conn)
     604                 :        948 : {
     605                 :        948 :     size_t length = 0;
     606         [ +  + ]:        948 :     if (s2n_result_is_ok(s2n_connection_get_session_length_impl(conn, &length))) {
     607                 :        947 :         return length;
     608                 :        947 :     }
     609                 :          1 :     return 0;
     610                 :        948 : }
     611                 :            : 
     612                 :            : int s2n_connection_is_session_resumed(struct s2n_connection *conn)
     613                 :       3685 : {
     614 [ +  + ][ +  + ]:       3685 :     return conn && IS_RESUMPTION_HANDSHAKE(conn)
                 [ +  - ]
     615 [ +  + ][ +  + ]:       3685 :             && (conn->actual_protocol_version < S2N_TLS13 || conn->psk_params.type == S2N_PSK_TYPE_RESUMPTION);
     616                 :       3685 : }
     617                 :            : 
     618                 :            : int s2n_connection_is_ocsp_stapled(struct s2n_connection *conn)
     619                 :         18 : {
     620 [ -  + ][ #  # ]:         18 :     POSIX_ENSURE_REF(conn);
     621                 :            : 
     622         [ +  + ]:         18 :     if (conn->actual_protocol_version >= S2N_TLS13) {
     623 [ +  + ][ +  - ]:         10 :         return (s2n_server_can_send_ocsp(conn) || s2n_server_sent_ocsp(conn));
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
     624                 :         10 :     } else {
     625                 :          8 :         return IS_OCSP_STAPLED(conn);
     626                 :          8 :     }
     627                 :         18 : }
     628                 :            : 
     629                 :            : S2N_RESULT s2n_config_is_encrypt_key_available(struct s2n_config *config)
     630                 :         26 : {
     631 [ -  + ][ #  # ]:         26 :     RESULT_ENSURE_REF(config);
     632                 :            : 
     633                 :         26 :     uint64_t now = 0;
     634                 :         26 :     struct s2n_ticket_key *ticket_key = NULL;
     635         [ -  + ]:         26 :     RESULT_GUARD(s2n_config_wall_clock(config, &now));
     636 [ -  + ][ #  # ]:         26 :     RESULT_ENSURE_REF(config->ticket_keys);
     637                 :            : 
     638                 :         26 :     uint32_t ticket_keys_len = 0;
     639         [ -  + ]:         26 :     RESULT_GUARD(s2n_array_num_elements(config->ticket_keys, &ticket_keys_len));
     640                 :            : 
     641         [ +  + ]:         27 :     for (uint32_t i = ticket_keys_len; i > 0; i--) {
     642                 :         21 :         uint32_t idx = i - 1;
     643         [ -  + ]:         21 :         RESULT_GUARD(s2n_array_get(config->ticket_keys, idx, (void **) &ticket_key));
     644                 :         21 :         uint64_t key_intro_time = ticket_key->intro_timestamp;
     645                 :            : 
     646         [ +  + ]:         21 :         if (key_intro_time <= now
     647         [ +  - ]:         21 :                 && now < key_intro_time + config->encrypt_decrypt_key_lifetime_in_nanos) {
     648                 :         20 :             return S2N_RESULT_OK;
     649                 :         20 :         }
     650                 :         21 :     }
     651                 :            : 
     652         [ +  - ]:          6 :     RESULT_BAIL(S2N_ERR_NO_TICKET_ENCRYPT_DECRYPT_KEY);
     653                 :          6 : }
     654                 :            : 
     655                 :            : /* This function is used in s2n_get_ticket_encrypt_decrypt_key to compute the weight
     656                 :            :  * of the keys and to choose a single key from all of the encrypt-decrypt keys.
     657                 :            :  * Higher the weight of the key, higher the probability of being picked.
     658                 :            :  */
     659                 :            : int s2n_compute_weight_of_encrypt_decrypt_keys(struct s2n_config *config,
     660                 :            :         uint8_t *encrypt_decrypt_keys_index,
     661                 :            :         uint8_t num_encrypt_decrypt_keys,
     662                 :            :         uint64_t now)
     663                 :          3 : {
     664                 :          3 :     double total_weight = 0;
     665                 :          3 :     struct s2n_ticket_key_weight ticket_keys_weight[S2N_MAX_TICKET_KEYS];
     666                 :          3 :     struct s2n_ticket_key *ticket_key = NULL;
     667                 :            : 
     668                 :            :     /* Compute weight of encrypt-decrypt keys */
     669         [ +  + ]:         11 :     for (int i = 0; i < num_encrypt_decrypt_keys; i++) {
     670         [ -  + ]:          8 :         POSIX_GUARD_RESULT(s2n_array_get(config->ticket_keys, encrypt_decrypt_keys_index[i], (void **) &ticket_key));
     671                 :            : 
     672                 :          8 :         uint64_t key_intro_time = ticket_key->intro_timestamp;
     673                 :          8 :         uint64_t key_encryption_peak_time = key_intro_time + (config->encrypt_decrypt_key_lifetime_in_nanos / 2);
     674                 :            : 
     675                 :            :         /* The % of encryption using this key is linearly increasing */
     676         [ +  + ]:          8 :         if (now < key_encryption_peak_time) {
     677                 :          4 :             ticket_keys_weight[i].key_weight = now - key_intro_time;
     678                 :          4 :         } else {
     679                 :            :             /* The % of encryption using this key is linearly decreasing */
     680                 :          4 :             ticket_keys_weight[i].key_weight = (config->encrypt_decrypt_key_lifetime_in_nanos / 2) - (now - key_encryption_peak_time);
     681                 :          4 :         }
     682                 :            : 
     683                 :          8 :         ticket_keys_weight[i].key_index = encrypt_decrypt_keys_index[i];
     684                 :          8 :         total_weight += ticket_keys_weight[i].key_weight;
     685                 :          8 :     }
     686                 :            : 
     687                 :            :     /* Pick a random number in [0, 1). Using 53 bits (IEEE 754 double-precision floats). */
     688                 :          3 :     uint64_t random_int = 0;
     689         [ -  + ]:          3 :     POSIX_GUARD_RESULT(s2n_public_random(pow(2, 53), &random_int));
     690                 :          3 :     double random = (double) random_int / (double) pow(2, 53);
     691                 :            : 
     692                 :            :     /* Compute cumulative weight of encrypt-decrypt keys */
     693         [ +  - ]:          7 :     for (int i = 0; i < num_encrypt_decrypt_keys; i++) {
     694                 :          7 :         ticket_keys_weight[i].key_weight = ticket_keys_weight[i].key_weight / total_weight;
     695                 :            : 
     696         [ +  + ]:          7 :         if (i > 0) {
     697                 :          4 :             ticket_keys_weight[i].key_weight += ticket_keys_weight[i - 1].key_weight;
     698                 :          4 :         }
     699                 :            : 
     700         [ +  + ]:          7 :         if (ticket_keys_weight[i].key_weight > random) {
     701                 :          3 :             return ticket_keys_weight[i].key_index;
     702                 :          3 :         }
     703                 :          7 :     }
     704                 :            : 
     705         [ #  # ]:          0 :     POSIX_BAIL(S2N_ERR_ENCRYPT_DECRYPT_KEY_SELECTION_FAILED);
     706                 :          0 : }
     707                 :            : 
     708                 :            : /* This function is used in s2n_resume_encrypt_session_ticket in order for s2n to
     709                 :            :  * choose a key in encrypt-decrypt state from all of the keys added to config
     710                 :            :  */
     711                 :            : struct s2n_ticket_key *s2n_get_ticket_encrypt_decrypt_key(struct s2n_config *config)
     712                 :        469 : {
     713                 :        469 :     uint8_t num_encrypt_decrypt_keys = 0;
     714                 :        469 :     uint8_t encrypt_decrypt_keys_index[S2N_MAX_TICKET_KEYS] = { 0 };
     715                 :        469 :     struct s2n_ticket_key *ticket_key = NULL;
     716                 :            : 
     717                 :        469 :     uint64_t now = 0;
     718         [ -  + ]:        469 :     PTR_GUARD_RESULT(s2n_config_wall_clock(config, &now));
     719 [ +  - ][ +  + ]:        469 :     PTR_ENSURE_REF(config->ticket_keys);
     720                 :            : 
     721                 :        468 :     uint32_t ticket_keys_len = 0;
     722         [ -  + ]:        468 :     PTR_GUARD_RESULT(s2n_array_num_elements(config->ticket_keys, &ticket_keys_len));
     723                 :            : 
     724         [ +  + ]:        939 :     for (uint32_t i = ticket_keys_len; i > 0; i--) {
     725                 :        471 :         uint32_t idx = i - 1;
     726         [ -  + ]:        471 :         PTR_GUARD_RESULT(s2n_array_get(config->ticket_keys, idx, (void **) &ticket_key));
     727                 :        471 :         uint64_t key_intro_time = ticket_key->intro_timestamp;
     728                 :            : 
     729                 :            :         /* A key can be used at its intro time (<=) and it can be used up to (<) 
     730                 :            :          * its expiration time.
     731                 :            :          */
     732         [ +  + ]:        471 :         if (key_intro_time <= now
     733         [ +  + ]:        471 :                 && now < key_intro_time + config->encrypt_decrypt_key_lifetime_in_nanos) {
     734                 :        466 :             encrypt_decrypt_keys_index[num_encrypt_decrypt_keys] = idx;
     735                 :        466 :             num_encrypt_decrypt_keys++;
     736                 :        466 :         }
     737                 :        471 :     }
     738                 :            : 
     739         [ +  + ]:        468 :     if (num_encrypt_decrypt_keys == 0) {
     740         [ +  - ]:          7 :         PTR_BAIL(S2N_ERR_NO_TICKET_ENCRYPT_DECRYPT_KEY);
     741                 :          7 :     }
     742                 :            : 
     743         [ +  + ]:        461 :     if (num_encrypt_decrypt_keys == 1) {
     744         [ -  + ]:        458 :         PTR_GUARD_RESULT(s2n_array_get(config->ticket_keys, encrypt_decrypt_keys_index[0], (void **) &ticket_key));
     745                 :        458 :         return ticket_key;
     746                 :        458 :     }
     747                 :            : 
     748                 :          3 :     int8_t idx = 0;
     749         [ -  + ]:          3 :     PTR_GUARD_POSIX(idx = s2n_compute_weight_of_encrypt_decrypt_keys(config, encrypt_decrypt_keys_index, num_encrypt_decrypt_keys, now));
     750                 :            : 
     751         [ -  + ]:          3 :     PTR_GUARD_RESULT(s2n_array_get(config->ticket_keys, idx, (void **) &ticket_key));
     752                 :          3 :     return ticket_key;
     753                 :          3 : }
     754                 :            : 
     755                 :            : /* This function is used in s2n_resume_decrypt_session in order for s2n to
     756                 :            :  * find the matching key that was used for encryption.
     757                 :            :  */
     758                 :            : struct s2n_ticket_key *s2n_find_ticket_key(struct s2n_config *config, const uint8_t name[S2N_TICKET_KEY_NAME_LEN])
     759                 :        162 : {
     760                 :        162 :     uint64_t now = 0;
     761                 :        162 :     struct s2n_ticket_key *ticket_key = NULL;
     762         [ -  + ]:        162 :     PTR_GUARD_RESULT(s2n_config_wall_clock(config, &now));
     763 [ -  + ][ #  # ]:        162 :     PTR_ENSURE_REF(config->ticket_keys);
     764                 :            : 
     765                 :        162 :     uint32_t ticket_keys_len = 0;
     766         [ -  + ]:        162 :     PTR_GUARD_RESULT(s2n_array_num_elements(config->ticket_keys, &ticket_keys_len));
     767                 :            : 
     768         [ +  + ]:        165 :     for (uint32_t i = 0; i < ticket_keys_len; i++) {
     769         [ -  + ]:        158 :         PTR_GUARD_RESULT(s2n_array_get(config->ticket_keys, i, (void **) &ticket_key));
     770                 :            : 
     771         [ +  + ]:        158 :         if (s2n_constant_time_equals(ticket_key->key_name, name, S2N_TICKET_KEY_NAME_LEN)) {
     772                 :            :             /* Check to see if the key has expired */
     773         [ -  + ]:        155 :             if (now >= ticket_key->intro_timestamp
     774                 :        155 :                             + config->encrypt_decrypt_key_lifetime_in_nanos
     775                 :        155 :                             + config->decrypt_key_lifetime_in_nanos) {
     776                 :          0 :                 return NULL;
     777                 :          0 :             }
     778                 :            : 
     779                 :        155 :             return ticket_key;
     780                 :        155 :         }
     781                 :        158 :     }
     782                 :            : 
     783                 :          7 :     return NULL;
     784                 :        162 : }
     785                 :            : 
     786                 :            : struct s2n_unique_ticket_key {
     787                 :            :     struct s2n_blob initial_key;
     788                 :            :     uint8_t info[S2N_AES256_KEY_LEN];
     789                 :            :     uint8_t output_key[S2N_AES256_KEY_LEN];
     790                 :            : };
     791                 :            : 
     792                 :            : /* Ensures that a session ticket encryption key is used only once per ticket.
     793                 :            :  *
     794                 :            :  * The AES-GCM encryption scheme breaks if the same nonce is used with the same key more than once.
     795                 :            :  * As the number of TLS connections increases per second, it becomes more probable that the same
     796                 :            :  * random nonce will be generated twice and used with the same ticket key.
     797                 :            :  * To avoid this we generate a unique session ticket encryption key for each ticket.
     798                 :            :  **/
     799                 :            : static S2N_RESULT s2n_resume_generate_unique_ticket_key(struct s2n_unique_ticket_key *key)
     800                 :        232 : {
     801 [ -  + ][ #  # ]:        232 :     RESULT_ENSURE_REF(key);
     802                 :            : 
     803                 :        232 :     struct s2n_blob out_key_blob = { 0 };
     804         [ -  + ]:        232 :     RESULT_GUARD_POSIX(s2n_blob_init(&out_key_blob, key->output_key, sizeof(key->output_key)));
     805                 :        232 :     struct s2n_blob info_blob = { 0 };
     806         [ -  + ]:        232 :     RESULT_GUARD_POSIX(s2n_blob_init(&info_blob, key->info, sizeof(key->info)));
     807                 :        232 :     struct s2n_blob salt = { 0 };
     808         [ -  + ]:        232 :     RESULT_GUARD_POSIX(s2n_blob_init(&salt, NULL, 0));
     809                 :            : 
     810                 :        232 :     DEFER_CLEANUP(struct s2n_hmac_state hmac = { 0 }, s2n_hmac_free);
     811                 :            :     /* TODO: There may be an optimization here to reuse existing hmac memory instead of
     812                 :            :      * creating an entirely new hmac. See: https://github.com/aws/s2n-tls/issues/3206 */
     813         [ -  + ]:        232 :     RESULT_GUARD_POSIX(s2n_hmac_new(&hmac));
     814         [ -  + ]:        232 :     RESULT_GUARD_POSIX(s2n_hkdf(&hmac, S2N_HMAC_SHA256, &salt, &key->initial_key, &info_blob, &out_key_blob));
     815                 :            : 
     816                 :        232 :     return S2N_RESULT_OK;
     817                 :        232 : }
     818                 :            : 
     819                 :            : S2N_RESULT s2n_resume_encrypt_session_ticket(struct s2n_connection *conn,
     820                 :            :         struct s2n_ticket_key *key, struct s2n_stuffer *to)
     821                 :        463 : {
     822 [ -  + ][ #  # ]:        463 :     RESULT_ENSURE_REF(conn);
     823 [ -  + ][ #  # ]:        463 :     RESULT_ENSURE_REF(to);
     824                 :            : 
     825 [ +  + ][ +  - ]:        463 :     RESULT_ENSURE(key != NULL, S2N_ERR_NO_TICKET_ENCRYPT_DECRYPT_KEY);
     826                 :            : 
     827                 :            :     /* Generate unique per-ticket encryption key */
     828                 :        460 :     struct s2n_unique_ticket_key ticket_key = { 0 };
     829         [ -  + ]:        460 :     RESULT_GUARD_POSIX(s2n_blob_init(&ticket_key.initial_key, key->aes_key, sizeof(key->aes_key)));
     830                 :        460 :     struct s2n_blob info_blob = { 0 };
     831         [ -  + ]:        460 :     RESULT_GUARD_POSIX(s2n_blob_init(&info_blob, ticket_key.info, sizeof(ticket_key.info)));
     832         [ -  + ]:        460 :     RESULT_GUARD(s2n_get_public_random_data(&info_blob));
     833         [ -  + ]:        460 :     RESULT_GUARD(s2n_resume_generate_unique_ticket_key(&ticket_key));
     834                 :            : 
     835                 :            :     /* Initialize AES key */
     836                 :        460 :     struct s2n_blob aes_key_blob = { 0 };
     837         [ -  + ]:        460 :     RESULT_GUARD_POSIX(s2n_blob_init(&aes_key_blob, ticket_key.output_key, sizeof(ticket_key.output_key)));
     838                 :        460 :     DEFER_CLEANUP(struct s2n_session_key aes_ticket_key = { 0 }, s2n_session_key_free);
     839         [ -  + ]:        460 :     RESULT_GUARD_POSIX(s2n_session_key_alloc(&aes_ticket_key));
     840         [ -  + ]:        460 :     RESULT_GUARD(s2n_aes256_gcm.init(&aes_ticket_key));
     841         [ -  + ]:        460 :     RESULT_GUARD(s2n_aes256_gcm.set_encryption_key(&aes_ticket_key, &aes_key_blob));
     842                 :            : 
     843                 :            :     /* Ensure we never encrypt with a zero-filled key */
     844                 :        460 :     uint8_t zero_block[S2N_AES256_KEY_LEN] = { 0 };
     845 [ +  - ][ +  + ]:        460 :     RESULT_ENSURE(!s2n_constant_time_equals(key->aes_key, zero_block, S2N_AES256_KEY_LEN),
     846                 :        459 :             S2N_ERR_KEY_CHECK);
     847                 :            : 
     848                 :            :     /* Initialize Additional Authenticated Data */
     849                 :        459 :     uint8_t aad_data[S2N_TICKET_AAD_LEN] = { 0 };
     850                 :        459 :     struct s2n_blob aad_blob = { 0 };
     851         [ -  + ]:        459 :     RESULT_GUARD_POSIX(s2n_blob_init(&aad_blob, aad_data, sizeof(aad_data)));
     852                 :        459 :     struct s2n_stuffer aad = { 0 };
     853         [ -  + ]:        459 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&aad, &aad_blob));
     854         [ -  + ]:        459 :     RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&aad, key->implicit_aad, sizeof(key->implicit_aad)));
     855         [ -  + ]:        459 :     RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&aad, key->key_name, sizeof(key->key_name)));
     856                 :            : 
     857                 :            :     /* Write version number */
     858         [ +  + ]:        459 :     RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(to, S2N_PRE_ENCRYPTED_STATE_V1));
     859                 :            : 
     860                 :            :     /* Write key name */
     861         [ -  + ]:        458 :     RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(to, key->key_name, sizeof(key->key_name)));
     862                 :            : 
     863                 :            :     /* Write parameter needed to generate unique ticket key */
     864         [ -  + ]:        458 :     RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(to, ticket_key.info, sizeof(ticket_key.info)));
     865                 :            : 
     866                 :            :     /* Write IV */
     867                 :        458 :     uint8_t iv_data[S2N_TLS_GCM_IV_LEN] = { 0 };
     868                 :        458 :     struct s2n_blob iv = { 0 };
     869         [ -  + ]:        458 :     RESULT_GUARD_POSIX(s2n_blob_init(&iv, iv_data, sizeof(iv_data)));
     870         [ -  + ]:        458 :     RESULT_GUARD(s2n_get_public_random_data(&iv));
     871         [ -  + ]:        458 :     RESULT_GUARD_POSIX(s2n_stuffer_write(to, &iv));
     872                 :            : 
     873                 :            :     /* Write serialized session state */
     874                 :        458 :     uint32_t plaintext_state_size = s2n_stuffer_data_available(to);
     875         [ -  + ]:        458 :     RESULT_GUARD(s2n_serialize_resumption_state(conn, to));
     876         [ -  + ]:        458 :     RESULT_GUARD_POSIX(s2n_stuffer_skip_write(to, S2N_TLS_GCM_TAG_LEN));
     877                 :            : 
     878                 :            :     /* Initialize blob to be encrypted */
     879                 :        458 :     struct s2n_blob state_blob = { 0 };
     880                 :        458 :     struct s2n_stuffer copy_for_encryption = *to;
     881         [ -  + ]:        458 :     RESULT_GUARD_POSIX(s2n_stuffer_skip_read(&copy_for_encryption, plaintext_state_size));
     882                 :        458 :     uint32_t state_blob_size = s2n_stuffer_data_available(&copy_for_encryption);
     883                 :        458 :     uint8_t *state_blob_data = s2n_stuffer_raw_read(&copy_for_encryption, state_blob_size);
     884 [ #  # ][ -  + ]:        458 :     RESULT_ENSURE_REF(state_blob_data);
     885         [ -  + ]:        458 :     RESULT_GUARD_POSIX(s2n_blob_init(&state_blob, state_blob_data, state_blob_size));
     886                 :            : 
     887         [ -  + ]:        458 :     RESULT_GUARD_POSIX(s2n_aes256_gcm.io.aead.encrypt(&aes_ticket_key, &iv, &aad_blob, &state_blob, &state_blob));
     888                 :            : 
     889                 :        458 :     return S2N_RESULT_OK;
     890                 :        458 : }
     891                 :            : 
     892                 :            : S2N_RESULT s2n_resume_decrypt_session(struct s2n_connection *conn, struct s2n_stuffer *from)
     893                 :        171 : {
     894 [ -  + ][ #  # ]:        171 :     RESULT_ENSURE_REF(conn);
     895 [ #  # ][ -  + ]:        171 :     RESULT_ENSURE_REF(from);
     896 [ -  + ][ #  # ]:        171 :     RESULT_ENSURE_REF(conn->config);
     897                 :            : 
     898                 :            :     /* Read version number */
     899                 :        171 :     uint8_t version = 0;
     900         [ -  + ]:        171 :     RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(from, &version));
     901 [ +  + ][ +  - ]:        171 :     RESULT_ENSURE_EQ(version, S2N_PRE_ENCRYPTED_STATE_V1);
     902                 :            : 
     903                 :            :     /* Read key name */
     904                 :        162 :     uint8_t key_name[S2N_TICKET_KEY_NAME_LEN] = { 0 };
     905         [ -  + ]:        162 :     RESULT_GUARD_POSIX(s2n_stuffer_read_bytes(from, key_name, sizeof(key_name)));
     906                 :            : 
     907                 :        162 :     struct s2n_ticket_key *key = s2n_find_ticket_key(conn->config, key_name);
     908                 :            :     /* Key has expired; do full handshake */
     909 [ +  + ][ +  - ]:        162 :     RESULT_ENSURE(key != NULL, S2N_ERR_KEY_USED_IN_SESSION_TICKET_NOT_FOUND);
     910                 :            : 
     911                 :        155 :     struct s2n_unique_ticket_key ticket_key = { 0 };
     912         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_blob_init(&ticket_key.initial_key, key->aes_key, sizeof(key->aes_key)));
     913         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_stuffer_read_bytes(from, ticket_key.info, sizeof(ticket_key.info)));
     914         [ -  + ]:        155 :     RESULT_GUARD(s2n_resume_generate_unique_ticket_key(&ticket_key));
     915                 :            : 
     916                 :            :     /* Read IV */
     917                 :        155 :     uint8_t iv_data[S2N_TLS_GCM_IV_LEN] = { 0 };
     918                 :        155 :     struct s2n_blob iv = { 0 };
     919         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_blob_init(&iv, iv_data, sizeof(iv_data)));
     920         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_stuffer_read(from, &iv));
     921                 :            : 
     922                 :            :     /* Initialize AES key */
     923                 :        155 :     struct s2n_blob aes_key_blob = { 0 };
     924         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_blob_init(&aes_key_blob, ticket_key.output_key, sizeof(ticket_key.output_key)));
     925                 :        155 :     DEFER_CLEANUP(struct s2n_session_key aes_ticket_key = { 0 }, s2n_session_key_free);
     926         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_session_key_alloc(&aes_ticket_key));
     927         [ -  + ]:        155 :     RESULT_GUARD(s2n_aes256_gcm.init(&aes_ticket_key));
     928         [ -  + ]:        155 :     RESULT_GUARD(s2n_aes256_gcm.set_decryption_key(&aes_ticket_key, &aes_key_blob));
     929                 :            : 
     930                 :            :     /* Initialize Additional Authenticated Data */
     931                 :        155 :     uint8_t aad_data[S2N_TICKET_AAD_LEN] = { 0 };
     932                 :        155 :     struct s2n_blob aad_blob = { 0 };
     933         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_blob_init(&aad_blob, aad_data, sizeof(aad_data)));
     934                 :        155 :     struct s2n_stuffer aad = { 0 };
     935         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&aad, &aad_blob));
     936         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&aad, key->implicit_aad, sizeof(key->implicit_aad)));
     937         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&aad, key->key_name, sizeof(key->key_name)));
     938                 :            : 
     939                 :            :     /* Initialize blob to be decrypted */
     940                 :        155 :     struct s2n_blob en_blob = { 0 };
     941                 :        155 :     uint32_t en_blob_size = s2n_stuffer_data_available(from);
     942                 :        155 :     uint8_t *en_blob_data = s2n_stuffer_raw_read(from, en_blob_size);
     943 [ #  # ][ -  + ]:        155 :     RESULT_ENSURE_REF(en_blob_data);
     944         [ -  + ]:        155 :     RESULT_GUARD_POSIX(s2n_blob_init(&en_blob, en_blob_data, en_blob_size));
     945                 :            : 
     946         [ +  + ]:        155 :     RESULT_GUARD_POSIX(s2n_aes256_gcm.io.aead.decrypt(&aes_ticket_key, &iv, &aad_blob, &en_blob, &en_blob));
     947                 :            : 
     948                 :            :     /* Parse decrypted state */
     949                 :        152 :     struct s2n_blob state_blob = { 0 };
     950                 :        152 :     uint32_t state_blob_size = en_blob_size - S2N_TLS_GCM_TAG_LEN;
     951         [ -  + ]:        152 :     RESULT_GUARD_POSIX(s2n_blob_init(&state_blob, en_blob.data, state_blob_size));
     952                 :        152 :     struct s2n_stuffer state_stuffer = { 0 };
     953         [ -  + ]:        152 :     RESULT_GUARD_POSIX(s2n_stuffer_init(&state_stuffer, &state_blob));
     954         [ -  + ]:        152 :     RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&state_stuffer, state_blob_size));
     955         [ +  + ]:        152 :     RESULT_GUARD(s2n_deserialize_resumption_state(conn, &from->blob, &state_stuffer));
     956                 :            : 
     957                 :        148 :     return S2N_RESULT_OK;
     958                 :        152 : }
     959                 :            : 
     960                 :            : /* This function is used to remove all or just one expired key from server config */
     961                 :            : int s2n_config_wipe_expired_ticket_crypto_keys(struct s2n_config *config, int8_t expired_key_index)
     962                 :        140 : {
     963                 :        140 :     int num_of_expired_keys = 0;
     964                 :        140 :     int expired_keys_index[S2N_MAX_TICKET_KEYS];
     965                 :        140 :     struct s2n_ticket_key *ticket_key = NULL;
     966                 :            : 
     967         [ -  + ]:        140 :     if (expired_key_index != -1) {
     968                 :          0 :         expired_keys_index[num_of_expired_keys] = expired_key_index;
     969                 :          0 :         num_of_expired_keys++;
     970                 :            : 
     971                 :          0 :         goto end;
     972                 :          0 :     }
     973                 :            : 
     974                 :        140 :     uint64_t now = 0;
     975         [ -  + ]:        140 :     POSIX_GUARD_RESULT(s2n_config_wall_clock(config, &now));
     976 [ -  + ][ #  # ]:        140 :     POSIX_ENSURE_REF(config->ticket_keys);
     977                 :            : 
     978                 :        140 :     uint32_t ticket_keys_len = 0;
     979         [ -  + ]:        140 :     POSIX_GUARD_RESULT(s2n_array_num_elements(config->ticket_keys, &ticket_keys_len));
     980         [ +  + ]:       1342 :     for (uint32_t i = 0; i < ticket_keys_len; i++) {
     981         [ -  + ]:       1202 :         POSIX_GUARD_RESULT(s2n_array_get(config->ticket_keys, i, (void **) &ticket_key));
     982         [ +  + ]:       1202 :         if (now >= ticket_key->intro_timestamp
     983                 :       1202 :                         + config->encrypt_decrypt_key_lifetime_in_nanos
     984                 :       1202 :                         + config->decrypt_key_lifetime_in_nanos) {
     985                 :          3 :             expired_keys_index[num_of_expired_keys] = i;
     986                 :          3 :             num_of_expired_keys++;
     987                 :          3 :         }
     988                 :       1202 :     }
     989                 :            : 
     990                 :        140 : end:
     991         [ +  + ]:        143 :     for (int j = 0; j < num_of_expired_keys; j++) {
     992         [ -  + ]:          3 :         POSIX_GUARD_RESULT(s2n_array_remove(config->ticket_keys, expired_keys_index[j] - j));
     993                 :          3 :     }
     994                 :            : 
     995                 :        140 :     return 0;
     996                 :        140 : }
     997                 :            : 
     998                 :            : int s2n_config_store_ticket_key(struct s2n_config *config, struct s2n_ticket_key *key)
     999                 :        136 : {
    1000                 :        136 :     uint32_t ticket_keys_len = 0;
    1001         [ -  + ]:        136 :     POSIX_GUARD_RESULT(s2n_array_num_elements(config->ticket_keys, &ticket_keys_len));
    1002                 :            : 
    1003                 :            :     /* The ticket key name and secret must both be unique. */
    1004         [ +  + ]:       1282 :     for (uint32_t i = 0; i < ticket_keys_len; i++) {
    1005                 :       1150 :         struct s2n_ticket_key *other_key = NULL;
    1006         [ -  + ]:       1150 :         POSIX_GUARD_RESULT(s2n_array_get(config->ticket_keys, i, (void **) &other_key));
    1007 [ +  + ][ +  - ]:       1150 :         POSIX_ENSURE(!s2n_constant_time_equals(key->key_name, other_key->key_name, s2n_array_len(key->key_name)),
    1008                 :       1147 :                 S2N_ERR_INVALID_TICKET_KEY_NAME_OR_NAME_LENGTH);
    1009 [ +  + ][ +  - ]:       1147 :         POSIX_ENSURE(!s2n_constant_time_equals(key->aes_key, other_key->aes_key, s2n_array_len(key->aes_key)),
    1010                 :       1147 :                 S2N_ERR_TICKET_KEY_NOT_UNIQUE);
    1011                 :       1147 :     }
    1012                 :            : 
    1013         [ -  + ]:        132 :     POSIX_GUARD_RESULT(s2n_array_insert_and_copy(config->ticket_keys, ticket_keys_len, key));
    1014                 :        132 :     return S2N_SUCCESS;
    1015                 :        132 : }
    1016                 :            : 
    1017                 :            : int s2n_config_set_initial_ticket_count(struct s2n_config *config, uint8_t num)
    1018                 :          4 : {
    1019 [ -  + ][ #  # ]:          4 :     POSIX_ENSURE_REF(config);
    1020                 :            : 
    1021                 :          4 :     config->initial_tickets_to_send = num;
    1022         [ -  + ]:          4 :     POSIX_GUARD(s2n_config_set_session_tickets_onoff(config, true));
    1023                 :            : 
    1024                 :          4 :     return S2N_SUCCESS;
    1025                 :          4 : }
    1026                 :            : 
    1027                 :            : int s2n_connection_add_new_tickets_to_send(struct s2n_connection *conn, uint8_t num)
    1028                 :        122 : {
    1029 [ -  + ][ #  # ]:        122 :     POSIX_ENSURE_REF(conn);
    1030         [ +  + ]:        122 :     POSIX_GUARD_RESULT(s2n_psk_validate_keying_material(conn));
    1031                 :            : 
    1032                 :        120 :     uint32_t out = conn->tickets_to_send + num;
    1033 [ +  - ][ +  + ]:        120 :     POSIX_ENSURE(out <= UINT16_MAX, S2N_ERR_INTEGER_OVERFLOW);
    1034                 :        119 :     conn->tickets_to_send = out;
    1035                 :            : 
    1036                 :        119 :     return S2N_SUCCESS;
    1037                 :        120 : }
    1038                 :            : 
    1039                 :            : int s2n_connection_get_tickets_sent(struct s2n_connection *conn, uint16_t *num)
    1040                 :         33 : {
    1041 [ -  + ][ #  # ]:         33 :     POSIX_ENSURE_REF(conn);
    1042 [ #  # ][ -  + ]:         33 :     POSIX_ENSURE_REF(num);
    1043 [ +  + ][ +  - ]:         33 :     POSIX_ENSURE(conn->mode == S2N_SERVER, S2N_ERR_CLIENT_MODE);
    1044                 :         32 :     *num = conn->tickets_sent;
    1045                 :         32 :     return S2N_SUCCESS;
    1046                 :         33 : }
    1047                 :            : 
    1048                 :            : int s2n_connection_set_server_keying_material_lifetime(struct s2n_connection *conn, uint32_t lifetime_in_secs)
    1049                 :          9 : {
    1050 [ +  + ][ +  - ]:          9 :     POSIX_ENSURE_REF(conn);
    1051                 :          8 :     conn->server_keying_material_lifetime = lifetime_in_secs;
    1052                 :          8 :     return S2N_SUCCESS;
    1053                 :          9 : }
    1054                 :            : 
    1055                 :            : int s2n_config_set_session_ticket_cb(struct s2n_config *config, s2n_session_ticket_fn callback, void *ctx)
    1056                 :         37 : {
    1057 [ +  + ][ +  - ]:         37 :     POSIX_ENSURE_MUT(config);
    1058                 :            : 
    1059                 :         36 :     config->session_ticket_cb = callback;
    1060                 :         36 :     config->session_ticket_ctx = ctx;
    1061                 :         36 :     return S2N_SUCCESS;
    1062                 :         37 : }
    1063                 :            : 
    1064                 :            : int s2n_session_ticket_get_data_len(struct s2n_session_ticket *ticket, size_t *data_len)
    1065                 :        257 : {
    1066 [ +  + ][ +  - ]:        257 :     POSIX_ENSURE_REF(ticket);
    1067 [ +  + ][ +  - ]:        256 :     POSIX_ENSURE_MUT(data_len);
    1068                 :            : 
    1069                 :        255 :     *data_len = ticket->ticket_data.size;
    1070                 :        255 :     return S2N_SUCCESS;
    1071                 :        256 : }
    1072                 :            : 
    1073                 :            : int s2n_session_ticket_get_data(struct s2n_session_ticket *ticket, size_t max_data_len, uint8_t *data)
    1074                 :        257 : {
    1075 [ +  - ][ +  + ]:        257 :     POSIX_ENSURE_REF(ticket);
    1076 [ +  + ][ +  - ]:        256 :     POSIX_ENSURE_MUT(data);
    1077                 :            : 
    1078 [ +  + ][ +  - ]:        255 :     POSIX_ENSURE(ticket->ticket_data.size <= max_data_len, S2N_ERR_SERIALIZED_SESSION_STATE_TOO_LONG);
    1079 [ -  + ][ #  # ]:        254 :     POSIX_CHECKED_MEMCPY(data, ticket->ticket_data.data, ticket->ticket_data.size);
                 [ +  - ]
    1080                 :            : 
    1081                 :        254 :     return S2N_SUCCESS;
    1082                 :        254 : }
    1083                 :            : 
    1084                 :            : int s2n_session_ticket_get_lifetime(struct s2n_session_ticket *ticket, uint32_t *session_lifetime)
    1085                 :         22 : {
    1086 [ +  + ][ +  - ]:         22 :     POSIX_ENSURE_REF(ticket);
    1087 [ +  - ][ +  + ]:         21 :     POSIX_ENSURE_REF(session_lifetime);
    1088                 :            : 
    1089                 :         20 :     *session_lifetime = ticket->session_lifetime;
    1090                 :            : 
    1091                 :         20 :     return S2N_SUCCESS;
    1092                 :         21 : }

Generated by: LCOV version 1.14