Branch data Line data Source code
1 : : /*
2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License").
5 : : * You may not use this file except in compliance with the License.
6 : : * A copy of the License is located at
7 : : *
8 : : * http://aws.amazon.com/apache2.0
9 : : *
10 : : * or in the "license" file accompanying this file. This file is distributed
11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 : : * express or implied. See the License for the specific language governing
13 : : * permissions and limitations under the License.
14 : : */
15 : :
16 : : #include "error/s2n_errno.h"
17 : : #include "tls/s2n_connection.h"
18 : : #include "tls/s2n_key_update.h"
19 : : #include "tls/s2n_tls.h"
20 : : #include "utils/s2n_safety.h"
21 : :
22 : : S2N_RESULT s2n_post_handshake_process(struct s2n_connection *conn, struct s2n_stuffer *in, uint8_t message_type)
23 : 1471 : {
24 [ # # ][ - + ]: 1471 : RESULT_ENSURE_REF(conn);
25 : :
26 : 1471 : switch (message_type) {
27 [ + + ]: 889 : case TLS_KEY_UPDATE:
28 [ + + ]: 889 : RESULT_GUARD_POSIX(s2n_key_update_recv(conn, in));
29 : 888 : break;
30 [ + + ]: 888 : case TLS_SERVER_NEW_SESSION_TICKET:
31 [ + + ]: 468 : RESULT_GUARD(s2n_tls13_server_nst_recv(conn, in));
32 : 465 : break;
33 [ + + ]: 465 : case TLS_HELLO_REQUEST:
34 [ + + ]: 80 : RESULT_GUARD(s2n_client_hello_request_recv(conn));
35 : 78 : break;
36 [ + + ]: 78 : case TLS_CERT_REQ:
37 : : /*
38 : : * s2n-tls does not support post-handshake authentication.
39 : : *
40 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.6.2
41 : : *# A client that receives a CertificateRequest message without having
42 : : *# sent the "post_handshake_auth" extension MUST send an
43 : : *# "unexpected_message" fatal alert.
44 : : */
45 [ + - ]: 1 : RESULT_BAIL(S2N_ERR_BAD_MESSAGE);
46 [ + + ]: 33 : default:
47 : : /* All other messages are unexpected */
48 [ + - ]: 33 : RESULT_BAIL(S2N_ERR_BAD_MESSAGE);
49 : 1471 : }
50 : :
51 : 1431 : return S2N_RESULT_OK;
52 : 1471 : }
53 : :
54 : : /*
55 : : * Read a handshake message from conn->in.
56 : : *
57 : : * Handshake messages can be fragmented, meaning that a single message
58 : : * may be split between multiple records. conn->in only holds a single
59 : : * record at a time, so we may need to call this method multiple
60 : : * times to construct the complete message. We store the partial message
61 : : * in conn->post_handshake.in between calls.
62 : : */
63 : : S2N_RESULT s2n_post_handshake_message_recv(struct s2n_connection *conn)
64 : 24829 : {
65 [ # # ][ - + ]: 24829 : RESULT_ENSURE_REF(conn);
66 : :
67 : 24829 : struct s2n_stuffer *in = &conn->in;
68 : 24829 : struct s2n_stuffer *message = &conn->post_handshake.in;
69 : 24829 : uint8_t message_type = 0;
70 : 24829 : uint32_t message_len = 0;
71 : :
72 : : /* We always start reading from the beginning of the message.
73 : : * Reset the read progress, but keep the write progress since
74 : : * there may already be a partial message stored in `message`.
75 : : */
76 [ - + ]: 24829 : RESULT_GUARD_POSIX(s2n_stuffer_reread(message));
77 : :
78 : : /* At minimum, the message stuffer needs to have enough space to read the header.
79 : : * For small messages like KeyUpdate and HelloRequest, this is all the space we will need.
80 : : */
81 [ + + ]: 24829 : if (s2n_stuffer_is_freed(message)) {
82 : 1073 : struct s2n_blob b = { 0 };
83 [ - + ]: 1073 : RESULT_GUARD_POSIX(s2n_blob_init(&b, conn->post_handshake.header_in,
84 : 1073 : sizeof(conn->post_handshake.header_in)));
85 [ - + ]: 1073 : RESULT_GUARD_POSIX(s2n_stuffer_init(message, &b));
86 : 1073 : }
87 : :
88 : : /* Try to copy the header into the message stuffer.
89 : : * The message stuffer may already contain some or all of the header if
90 : : * we have read fragments of this message from previous records.
91 : : */
92 [ + + ]: 24829 : if (s2n_stuffer_data_available(message) < TLS_HANDSHAKE_HEADER_LENGTH) {
93 : 1741 : uint32_t remaining = TLS_HANDSHAKE_HEADER_LENGTH - s2n_stuffer_data_available(message);
94 [ + + ]: 1741 : uint32_t to_read = S2N_MIN(remaining, s2n_stuffer_data_available(in));
95 [ - + ]: 1741 : RESULT_GUARD_POSIX(s2n_stuffer_copy(in, message, to_read));
96 : 1741 : }
97 [ + + ][ + - ]: 24829 : RESULT_ENSURE(s2n_stuffer_data_available(message) >= TLS_HANDSHAKE_HEADER_LENGTH, S2N_ERR_IO_BLOCKED);
98 : :
99 : : /* Parse the header */
100 [ - + ]: 24547 : RESULT_GUARD(s2n_handshake_parse_header(message, &message_type, &message_len));
101 [ + - ][ + + ]: 24547 : RESULT_ENSURE(message_len == 0 || s2n_stuffer_data_available(in), S2N_ERR_IO_BLOCKED);
[ + + ]
102 [ - + ][ # # ]: 24437 : RESULT_ENSURE(message_len <= S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH, S2N_ERR_BAD_MESSAGE);
103 : :
104 : : /* If the message body is not fragmented, just process it directly from conn->in.
105 : : * This will be the most common case, and does not require us to allocate any new memory.
106 : : */
107 [ + + ][ + + ]: 24437 : if (s2n_stuffer_data_available(message) == 0 && s2n_stuffer_data_available(in) >= message_len) {
108 : 1291 : struct s2n_stuffer full_message = { 0 };
109 : 1291 : struct s2n_blob full_message_blob = { 0 };
110 [ - + ]: 1291 : RESULT_GUARD_POSIX(s2n_blob_init(&full_message_blob, s2n_stuffer_raw_read(in, message_len), message_len));
111 [ - + ]: 1291 : RESULT_GUARD_POSIX(s2n_stuffer_init(&full_message, &full_message_blob));
112 [ - + ]: 1291 : RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&full_message, message_len));
113 [ + + ]: 1291 : RESULT_GUARD(s2n_post_handshake_process(conn, &full_message, message_type));
114 : 1261 : return S2N_RESULT_OK;
115 : 1291 : }
116 : :
117 : : /* If the message body is fragmented, then the current fragment will be wiped from conn->in
118 : : * in order to read the next record. So the message stuffer needs enough space to store
119 : : * the full message as we reconstruct it from multiple records.
120 : : * For large messages like NewSessionTicket, this will require allocating new memory.
121 : : */
122 [ + + ]: 23146 : if (s2n_stuffer_space_remaining(message) < message_len) {
123 : : /* We want to avoid servers allocating memory in response to post-handshake messages
124 : : * to avoid a potential DDOS / resource exhaustion attack.
125 : : *
126 : : * Currently, s2n-tls servers only support the KeyUpdate message,
127 : : * which should never require additional memory to parse.
128 : : */
129 [ + + ][ + - ]: 22972 : RESULT_ENSURE(conn->mode == S2N_CLIENT, S2N_ERR_BAD_MESSAGE);
130 : :
131 : 22956 : uint32_t total_size = message_len + TLS_HANDSHAKE_HEADER_LENGTH;
132 [ + + ]: 22956 : if (message->alloced) {
133 [ - + ]: 22916 : RESULT_GUARD_POSIX(s2n_stuffer_resize(message, total_size));
134 : 22916 : } else {
135 : : /* Manually convert our static stuffer to a growable stuffer */
136 [ - + ]: 40 : RESULT_GUARD_POSIX(s2n_stuffer_growable_alloc(message, total_size));
137 [ - + ]: 40 : RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(message, conn->post_handshake.header_in, TLS_HANDSHAKE_HEADER_LENGTH));
138 [ - + ]: 40 : RESULT_GUARD_POSIX(s2n_stuffer_skip_read(message, TLS_HANDSHAKE_HEADER_LENGTH));
139 : 40 : }
140 : 22956 : }
141 : :
142 : : /* Try to copy the message body into the message stuffer.
143 : : * The message stuffer may already contain some of the message body if
144 : : * we have already read fragments from previous records.
145 : : */
146 [ + - ]: 23130 : if (s2n_stuffer_data_available(message) < message_len) {
147 : 23130 : uint32_t remaining = message_len - s2n_stuffer_data_available(message);
148 [ + + ]: 23130 : uint32_t to_read = S2N_MIN(remaining, s2n_stuffer_data_available(in));
149 [ - + ]: 23130 : RESULT_GUARD_POSIX(s2n_stuffer_copy(in, message, to_read));
150 : 23130 : }
151 [ + + ][ + - ]: 23130 : RESULT_ENSURE(s2n_stuffer_data_available(message) == message_len, S2N_ERR_IO_BLOCKED);
152 : :
153 : : /* Now that the full message body is available, process it. */
154 [ + + ]: 150 : RESULT_GUARD(s2n_post_handshake_process(conn, message, message_type));
155 : 140 : return S2N_RESULT_OK;
156 : 150 : }
157 : :
158 : : S2N_RESULT s2n_post_handshake_recv(struct s2n_connection *conn)
159 : 24701 : {
160 [ - + ][ # # ]: 24701 : RESULT_ENSURE_REF(conn);
161 [ + + ]: 26102 : while (s2n_stuffer_data_available(&conn->in)) {
162 [ + + ]: 24829 : RESULT_GUARD(s2n_post_handshake_message_recv(conn));
163 [ - + ]: 1401 : RESULT_GUARD_POSIX(s2n_stuffer_wipe(&conn->post_handshake.in));
164 : 1401 : }
165 : 1273 : return S2N_RESULT_OK;
166 : 24701 : }
167 : :
168 : : S2N_RESULT s2n_post_handshake_write_records(struct s2n_connection *conn, s2n_blocked_status *blocked)
169 : 51899 : {
170 : 51899 : struct s2n_stuffer *message = &conn->handshake.io;
171 : :
172 : : /* Flush any existing records before we write a new handshake record.
173 : : * We do not support buffering multiple handshake records.
174 : : */
175 [ + + ]: 51899 : if (s2n_stuffer_data_available(message)) {
176 [ - + ]: 1331 : RESULT_GUARD_POSIX(s2n_flush(conn, blocked));
177 : 1331 : }
178 : :
179 [ + + ]: 51899 : RESULT_GUARD(s2n_handshake_message_send(conn, TLS_HANDSHAKE, blocked));
180 [ - + ]: 50864 : RESULT_GUARD_POSIX(s2n_stuffer_wipe(message));
181 : 50864 : return S2N_RESULT_OK;
182 : 50864 : }
183 : :
184 : : int s2n_post_handshake_send(struct s2n_connection *conn, s2n_blocked_status *blocked)
185 : 157960 : {
186 [ - + ][ # # ]: 157960 : POSIX_ENSURE_REF(conn);
187 : :
188 : : /* Currently, we only support TLS1.3 post-handshake messages. */
189 [ + + ]: 157960 : if (conn->actual_protocol_version < S2N_TLS13) {
190 : 106378 : return S2N_SUCCESS;
191 : 106378 : }
192 : :
193 [ + + ]: 51582 : POSIX_GUARD_RESULT(s2n_post_handshake_write_records(conn, blocked));
194 : :
195 [ + + ]: 50568 : POSIX_GUARD(s2n_key_update_send(conn, blocked));
196 [ + + ]: 50549 : POSIX_GUARD_RESULT(s2n_tls13_server_nst_send(conn, blocked));
197 : :
198 [ - + ]: 50528 : POSIX_GUARD(s2n_stuffer_resize(&conn->handshake.io, 0));
199 : 50528 : return S2N_SUCCESS;
200 : 50528 : }
|