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 <sys/param.h>
17 : :
18 : : #include "error/s2n_errno.h"
19 : : #include "tls/s2n_connection.h"
20 : : #include "tls/s2n_key_update.h"
21 : : #include "tls/s2n_tls.h"
22 : : #include "utils/s2n_safety.h"
23 : :
24 : : S2N_RESULT s2n_post_handshake_process(struct s2n_connection *conn, struct s2n_stuffer *in, uint8_t message_type)
25 : 1468 : {
26 [ # # ][ - + ]: 1468 : RESULT_ENSURE_REF(conn);
27 : :
28 : 1468 : switch (message_type) {
29 [ + + ]: 894 : case TLS_KEY_UPDATE:
30 [ + + ]: 894 : RESULT_GUARD_POSIX(s2n_key_update_recv(conn, in));
31 : 893 : break;
32 [ + + ]: 893 : case TLS_SERVER_NEW_SESSION_TICKET:
33 [ + + ]: 460 : RESULT_GUARD(s2n_tls13_server_nst_recv(conn, in));
34 : 457 : break;
35 [ + + ]: 457 : case TLS_HELLO_REQUEST:
36 [ + + ]: 80 : RESULT_GUARD(s2n_client_hello_request_recv(conn));
37 : 78 : break;
38 [ + + ]: 78 : case TLS_CERT_REQ:
39 : : /*
40 : : * s2n-tls does not support post-handshake authentication.
41 : : *
42 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.6.2
43 : : *# A client that receives a CertificateRequest message without having
44 : : *# sent the "post_handshake_auth" extension MUST send an
45 : : *# "unexpected_message" fatal alert.
46 : : */
47 [ + - ]: 1 : RESULT_BAIL(S2N_ERR_BAD_MESSAGE);
48 [ + + ]: 33 : default:
49 : : /* All other messages are unexpected */
50 [ + - ]: 33 : RESULT_BAIL(S2N_ERR_BAD_MESSAGE);
51 : 1468 : }
52 : :
53 : 1428 : return S2N_RESULT_OK;
54 : 1468 : }
55 : :
56 : : /*
57 : : * Read a handshake message from conn->in.
58 : : *
59 : : * Handshake messages can be fragmented, meaning that a single message
60 : : * may be split between multiple records. conn->in only holds a single
61 : : * record at a time, so we may need to call this method multiple
62 : : * times to construct the complete message. We store the partial message
63 : : * in conn->post_handshake.in between calls.
64 : : */
65 : : S2N_RESULT s2n_post_handshake_message_recv(struct s2n_connection *conn)
66 : 24834 : {
67 [ # # ][ - + ]: 24834 : RESULT_ENSURE_REF(conn);
68 : :
69 : 24834 : struct s2n_stuffer *in = &conn->in;
70 : 24834 : struct s2n_stuffer *message = &conn->post_handshake.in;
71 : 24834 : uint8_t message_type = 0;
72 : 24834 : uint32_t message_len = 0;
73 : :
74 : : /* We always start reading from the beginning of the message.
75 : : * Reset the read progress, but keep the write progress since
76 : : * there may already be a partial message stored in `message`.
77 : : */
78 [ - + ]: 24834 : RESULT_GUARD_POSIX(s2n_stuffer_reread(message));
79 : :
80 : : /* At minimum, the message stuffer needs to have enough space to read the header.
81 : : * For small messages like KeyUpdate and HelloRequest, this is all the space we will need.
82 : : */
83 [ + + ]: 24834 : if (s2n_stuffer_is_freed(message)) {
84 : 1077 : struct s2n_blob b = { 0 };
85 [ - + ]: 1077 : RESULT_GUARD_POSIX(s2n_blob_init(&b, conn->post_handshake.header_in,
86 : 1077 : sizeof(conn->post_handshake.header_in)));
87 [ - + ]: 1077 : RESULT_GUARD_POSIX(s2n_stuffer_init(message, &b));
88 : 1077 : }
89 : :
90 : : /* Try to copy the header into the message stuffer.
91 : : * The message stuffer may already contain some or all of the header if
92 : : * we have read fragments of this message from previous records.
93 : : */
94 [ + + ]: 24834 : if (s2n_stuffer_data_available(message) < TLS_HANDSHAKE_HEADER_LENGTH) {
95 : 1746 : uint32_t remaining = TLS_HANDSHAKE_HEADER_LENGTH - s2n_stuffer_data_available(message);
96 : 1746 : uint32_t to_read = MIN(remaining, s2n_stuffer_data_available(in));
97 [ - + ]: 1746 : RESULT_GUARD_POSIX(s2n_stuffer_copy(in, message, to_read));
98 : 1746 : }
99 [ + + ][ + - ]: 24834 : RESULT_ENSURE(s2n_stuffer_data_available(message) >= TLS_HANDSHAKE_HEADER_LENGTH, S2N_ERR_IO_BLOCKED);
100 : :
101 : : /* Parse the header */
102 [ - + ]: 24552 : RESULT_GUARD(s2n_handshake_parse_header(message, &message_type, &message_len));
103 [ + - ][ + + ]: 24552 : RESULT_ENSURE(message_len == 0 || s2n_stuffer_data_available(in), S2N_ERR_IO_BLOCKED);
[ + + ]
104 [ - + ][ # # ]: 24442 : RESULT_ENSURE(message_len <= S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH, S2N_ERR_BAD_MESSAGE);
105 : :
106 : : /* If the message body is not fragmented, just process it directly from conn->in.
107 : : * This will be the most common case, and does not require us to allocate any new memory.
108 : : */
109 [ + + ][ + + ]: 24442 : if (s2n_stuffer_data_available(message) == 0 && s2n_stuffer_data_available(in) >= message_len) {
110 : 1296 : struct s2n_stuffer full_message = { 0 };
111 : 1296 : struct s2n_blob full_message_blob = { 0 };
112 [ - + ]: 1296 : RESULT_GUARD_POSIX(s2n_blob_init(&full_message_blob, s2n_stuffer_raw_read(in, message_len), message_len));
113 [ - + ]: 1296 : RESULT_GUARD_POSIX(s2n_stuffer_init(&full_message, &full_message_blob));
114 [ - + ]: 1296 : RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&full_message, message_len));
115 [ + + ]: 1296 : RESULT_GUARD(s2n_post_handshake_process(conn, &full_message, message_type));
116 : 1266 : return S2N_RESULT_OK;
117 : 1296 : }
118 : :
119 : : /* If the message body is fragmented, then the current fragment will be wiped from conn->in
120 : : * in order to read the next record. So the message stuffer needs enough space to store
121 : : * the full message as we reconstruct it from multiple records.
122 : : * For large messages like NewSessionTicket, this will require allocating new memory.
123 : : */
124 [ + + ]: 23146 : if (s2n_stuffer_space_remaining(message) < message_len) {
125 : : /* We want to avoid servers allocating memory in response to post-handshake messages
126 : : * to avoid a potential DDOS / resource exhaustion attack.
127 : : *
128 : : * Currently, s2n-tls servers only support the KeyUpdate message,
129 : : * which should never require additional memory to parse.
130 : : */
131 [ + + ][ + - ]: 22972 : RESULT_ENSURE(conn->mode == S2N_CLIENT, S2N_ERR_BAD_MESSAGE);
132 : :
133 : 22956 : uint32_t total_size = message_len + TLS_HANDSHAKE_HEADER_LENGTH;
134 [ + + ]: 22956 : if (message->alloced) {
135 [ - + ]: 22916 : RESULT_GUARD_POSIX(s2n_stuffer_resize(message, total_size));
136 : 22916 : } else {
137 : : /* Manually convert our static stuffer to a growable stuffer */
138 [ - + ]: 40 : RESULT_GUARD_POSIX(s2n_stuffer_growable_alloc(message, total_size));
139 [ - + ]: 40 : RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(message, conn->post_handshake.header_in, TLS_HANDSHAKE_HEADER_LENGTH));
140 [ - + ]: 40 : RESULT_GUARD_POSIX(s2n_stuffer_skip_read(message, TLS_HANDSHAKE_HEADER_LENGTH));
141 : 40 : }
142 : 22956 : }
143 : :
144 : : /* Try to copy the message body into the message stuffer.
145 : : * The message stuffer may already contain some of the message body if
146 : : * we have already read fragments from previous records.
147 : : */
148 [ + - ]: 23130 : if (s2n_stuffer_data_available(message) < message_len) {
149 : 23130 : uint32_t remaining = message_len - s2n_stuffer_data_available(message);
150 : 23130 : uint32_t to_read = MIN(remaining, s2n_stuffer_data_available(in));
151 [ - + ]: 23130 : RESULT_GUARD_POSIX(s2n_stuffer_copy(in, message, to_read));
152 : 23130 : }
153 [ + + ][ + - ]: 23130 : RESULT_ENSURE(s2n_stuffer_data_available(message) == message_len, S2N_ERR_IO_BLOCKED);
154 : :
155 : : /* Now that the full message body is available, process it. */
156 [ + + ]: 150 : RESULT_GUARD(s2n_post_handshake_process(conn, message, message_type));
157 : 140 : return S2N_RESULT_OK;
158 : 150 : }
159 : :
160 : : S2N_RESULT s2n_post_handshake_recv(struct s2n_connection *conn)
161 : 24706 : {
162 [ - + ][ # # ]: 24706 : RESULT_ENSURE_REF(conn);
163 [ + + ]: 26112 : while (s2n_stuffer_data_available(&conn->in)) {
164 [ + + ]: 24834 : RESULT_GUARD(s2n_post_handshake_message_recv(conn));
165 [ - + ]: 1406 : RESULT_GUARD_POSIX(s2n_stuffer_wipe(&conn->post_handshake.in));
166 : 1406 : }
167 : 1278 : return S2N_RESULT_OK;
168 : 24706 : }
169 : :
170 : : S2N_RESULT s2n_post_handshake_write_records(struct s2n_connection *conn, s2n_blocked_status *blocked)
171 : 50648 : {
172 : 50648 : struct s2n_stuffer *message = &conn->handshake.io;
173 : :
174 : : /* Flush any existing records before we write a new handshake record.
175 : : * We do not support buffering multiple handshake records.
176 : : */
177 [ + + ]: 50648 : if (s2n_stuffer_data_available(message)) {
178 [ - + ]: 1331 : RESULT_GUARD_POSIX(s2n_flush(conn, blocked));
179 : 1331 : }
180 : :
181 [ + + ]: 50648 : RESULT_GUARD(s2n_handshake_message_send(conn, TLS_HANDSHAKE, blocked));
182 [ - + ]: 49613 : RESULT_GUARD_POSIX(s2n_stuffer_wipe(message));
183 : 49613 : return S2N_RESULT_OK;
184 : 49613 : }
185 : :
186 : : int s2n_post_handshake_send(struct s2n_connection *conn, s2n_blocked_status *blocked)
187 : 155177 : {
188 [ - + ][ # # ]: 155177 : POSIX_ENSURE_REF(conn);
189 : :
190 : : /* Currently, we only support TLS1.3 post-handshake messages. */
191 [ + + ]: 155177 : if (conn->actual_protocol_version < S2N_TLS13) {
192 : 104846 : return S2N_SUCCESS;
193 : 104846 : }
194 : :
195 [ + + ]: 50331 : POSIX_GUARD_RESULT(s2n_post_handshake_write_records(conn, blocked));
196 : :
197 [ + + ]: 49317 : POSIX_GUARD(s2n_key_update_send(conn, blocked));
198 [ + + ]: 49121 : POSIX_GUARD_RESULT(s2n_tls13_server_nst_send(conn, blocked));
199 : :
200 [ - + ]: 49100 : POSIX_GUARD(s2n_stuffer_resize(&conn->handshake.io, 0));
201 : 49100 : return S2N_SUCCESS;
202 : 49100 : }
|