LCOV - code coverage report
Current view: top level - tls - s2n_resume.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 676 703 96.2 %
Date: 2026-10-06 07:26:09 Functions: 42 42 100.0 %
Branches: 457 900 50.8 %

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

Generated by: LCOV version 1.14