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

Generated by: LCOV version 1.14