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 "utils/s2n_safety.h"
19 : :
20 : : S2N_RESULT s2n_protocol_preferences_read(struct s2n_stuffer *protocol_preferences, struct s2n_blob *protocol)
21 : 120 : {
22 [ + + ][ + - ]: 120 : RESULT_ENSURE_REF(protocol_preferences);
23 [ + - ][ + + ]: 119 : RESULT_ENSURE_REF(protocol);
24 : :
25 : 118 : uint8_t length = 0;
26 [ + + ]: 118 : RESULT_GUARD_POSIX(s2n_stuffer_read_uint8(protocol_preferences, &length));
27 [ + + ][ + - ]: 117 : RESULT_ENSURE_GT(length, 0);
28 : :
29 : 115 : uint8_t *data = s2n_stuffer_raw_read(protocol_preferences, length);
30 [ - + ][ # # ]: 115 : RESULT_ENSURE_REF(data);
31 : :
32 [ - + ]: 115 : RESULT_GUARD_POSIX(s2n_blob_init(protocol, data, length));
33 : 115 : return S2N_RESULT_OK;
34 : 115 : }
35 : :
36 : : S2N_RESULT s2n_protocol_preferences_contain(struct s2n_blob *protocol_preferences, struct s2n_blob *protocol, bool *contains)
37 : 51 : {
38 [ + + ][ + - ]: 51 : RESULT_ENSURE_REF(contains);
39 : 50 : *contains = false;
40 [ + + ][ + - ]: 50 : RESULT_ENSURE_REF(protocol_preferences);
41 [ + + ][ + - ]: 49 : RESULT_ENSURE_REF(protocol);
42 : :
43 : 48 : struct s2n_stuffer app_protocols_stuffer = { 0 };
44 [ - + ]: 48 : RESULT_GUARD_POSIX(s2n_stuffer_init(&app_protocols_stuffer, protocol_preferences));
45 [ - + ]: 48 : RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&app_protocols_stuffer, protocol_preferences->size));
46 : :
47 [ + + ]: 72 : while (s2n_stuffer_data_available(&app_protocols_stuffer) > 0) {
48 : 60 : struct s2n_blob match_against = { 0 };
49 [ - + ]: 60 : RESULT_GUARD(s2n_protocol_preferences_read(&app_protocols_stuffer, &match_against));
50 : :
51 [ + + ][ + + ]: 60 : if (match_against.size == protocol->size && memcmp(match_against.data, protocol->data, protocol->size) == 0) {
52 : 36 : *contains = true;
53 : 36 : return S2N_RESULT_OK;
54 : 36 : }
55 : 60 : }
56 : 12 : return S2N_RESULT_OK;
57 : 48 : }
58 : :
59 : : S2N_RESULT s2n_protocol_preferences_append(struct s2n_blob *application_protocols, const uint8_t *protocol, uint8_t protocol_len)
60 : 124 : {
61 [ - + ][ # # ]: 124 : RESULT_ENSURE_MUT(application_protocols);
62 [ # # ][ - + ]: 124 : RESULT_ENSURE_REF(protocol);
63 : :
64 : : /**
65 : : *= https://www.rfc-editor.org/rfc/rfc7301#section-3.1
66 : : *# Empty strings
67 : : *# MUST NOT be included and byte strings MUST NOT be truncated.
68 : : */
69 [ + + ][ + - ]: 124 : RESULT_ENSURE(protocol_len != 0, S2N_ERR_INVALID_APPLICATION_PROTOCOL);
70 : :
71 : 122 : uint32_t prev_len = application_protocols->size;
72 : 122 : uint32_t new_len = prev_len + /* len prefix */ 1 + protocol_len;
73 [ - + ][ # # ]: 122 : RESULT_ENSURE(new_len <= UINT16_MAX, S2N_ERR_INVALID_APPLICATION_PROTOCOL);
74 : :
75 [ - + ]: 122 : RESULT_GUARD_POSIX(s2n_realloc(application_protocols, new_len));
76 : :
77 : 122 : struct s2n_stuffer protocol_stuffer = { 0 };
78 [ - + ]: 122 : RESULT_GUARD_POSIX(s2n_stuffer_init(&protocol_stuffer, application_protocols));
79 [ - + ]: 122 : RESULT_GUARD_POSIX(s2n_stuffer_skip_write(&protocol_stuffer, prev_len));
80 [ - + ]: 122 : RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(&protocol_stuffer, protocol_len));
81 [ - + ]: 122 : RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&protocol_stuffer, protocol, protocol_len));
82 : :
83 : 122 : return S2N_RESULT_OK;
84 : 122 : }
85 : :
86 : : S2N_RESULT s2n_protocol_preferences_set(struct s2n_blob *application_protocols, const char *const *protocols, int protocol_count)
87 : 68 : {
88 [ - + ][ # # ]: 68 : RESULT_ENSURE_MUT(application_protocols);
89 : :
90 : : /* NULL value indicates no preference so free the previous blob */
91 [ + + ][ + + ]: 68 : if (protocols == NULL || protocol_count == 0) {
92 [ - + ]: 6 : RESULT_GUARD_POSIX(s2n_free(application_protocols));
93 : 6 : return S2N_RESULT_OK;
94 : 6 : }
95 : :
96 : 62 : DEFER_CLEANUP(struct s2n_blob new_protocols = { 0 }, s2n_free);
97 : :
98 : : /* Allocate enough space to avoid a reallocation for every entry
99 : : *
100 : : * We assume that each protocol is most likely 8 bytes or less.
101 : : * If it ends up being larger, we will expand the blob automatically
102 : : * in the append method.
103 : : */
104 [ - + ]: 62 : RESULT_GUARD_POSIX(s2n_realloc(&new_protocols, protocol_count * 8));
105 : :
106 : : /* set the size back to 0 so we start at the beginning.
107 : : * s2n_realloc will just update the size field here
108 : : */
109 [ - + ]: 62 : RESULT_GUARD_POSIX(s2n_realloc(&new_protocols, 0));
110 [ - + ][ # # ]: 62 : RESULT_ENSURE_GTE(protocol_count, 0);
111 : :
112 [ + + ]: 167 : for (size_t i = 0; i < (size_t) protocol_count; i++) {
113 : 107 : const uint8_t *protocol = (const uint8_t *) protocols[i];
114 : 107 : size_t length = strlen(protocols[i]);
115 : :
116 : : /**
117 : : *= https://www.rfc-editor.org/rfc/rfc7301#section-3.1
118 : : *# Empty strings
119 : : *# MUST NOT be included and byte strings MUST NOT be truncated.
120 : : */
121 [ + + ][ + - ]: 107 : RESULT_ENSURE(length < 256, S2N_ERR_INVALID_APPLICATION_PROTOCOL);
122 : :
123 [ - + ]: 105 : RESULT_GUARD(s2n_protocol_preferences_append(&new_protocols, protocol, (uint8_t) length));
124 : 105 : }
125 : :
126 : : /* now we can free the previous list since we've validated all new input */
127 [ - + ]: 60 : RESULT_GUARD_POSIX(s2n_free(application_protocols));
128 : :
129 : : /* update the connection/config application_protocols with the newly allocated blob */
130 : 60 : *application_protocols = new_protocols;
131 : :
132 : 60 : ZERO_TO_DISABLE_DEFER_CLEANUP(new_protocols);
133 : :
134 : 60 : return S2N_RESULT_OK;
135 : 60 : }
136 : :
137 : : S2N_RESULT s2n_select_server_preference_protocol(struct s2n_connection *conn, struct s2n_stuffer *server_list,
138 : : struct s2n_blob *client_list)
139 : 37 : {
140 [ # # ][ - + ]: 37 : RESULT_ENSURE_REF(conn);
141 [ # # ][ - + ]: 37 : RESULT_ENSURE_REF(server_list);
142 [ # # ][ - + ]: 37 : RESULT_ENSURE_REF(client_list);
143 : :
144 [ + + ]: 44 : while (s2n_stuffer_data_available(server_list) > 0) {
145 : 41 : struct s2n_blob protocol = { 0 };
146 [ - + ][ # # ]: 41 : RESULT_ENSURE_OK(s2n_protocol_preferences_read(server_list, &protocol), S2N_ERR_BAD_MESSAGE);
147 : :
148 : 41 : bool match_found = false;
149 [ - + ][ # # ]: 41 : RESULT_ENSURE_OK(s2n_protocol_preferences_contain(client_list, &protocol, &match_found), S2N_ERR_BAD_MESSAGE);
150 : :
151 [ + + ]: 41 : if (match_found) {
152 [ - + ][ # # ]: 34 : RESULT_ENSURE_LT(protocol.size, sizeof(conn->application_protocol));
153 [ - + ][ # # ]: 34 : RESULT_CHECKED_MEMCPY(conn->application_protocol, protocol.data, protocol.size);
[ + - ]
154 : 34 : conn->application_protocol[protocol.size] = '\0';
155 : 34 : return S2N_RESULT_OK;
156 : 34 : }
157 : 41 : }
158 : :
159 : 3 : return S2N_RESULT_OK;
160 : 37 : }
161 : :
162 : : int s2n_config_set_protocol_preferences(struct s2n_config *config, const char *const *protocols, int protocol_count)
163 : 57 : {
164 [ + + ]: 57 : POSIX_GUARD_RESULT(s2n_protocol_preferences_set(&config->application_protocols, protocols, protocol_count));
165 : 56 : return S2N_SUCCESS;
166 : 57 : }
167 : :
168 : : int s2n_config_append_protocol_preference(struct s2n_config *config, const uint8_t *protocol, uint8_t protocol_len)
169 : 4 : {
170 [ + + ]: 4 : POSIX_GUARD_RESULT(s2n_protocol_preferences_append(&config->application_protocols, protocol, protocol_len));
171 : 3 : return S2N_SUCCESS;
172 : 4 : }
173 : :
174 : : int s2n_connection_set_protocol_preferences(struct s2n_connection *conn, const char *const *protocols, int protocol_count)
175 : 11 : {
176 [ + + ]: 11 : POSIX_GUARD_RESULT(s2n_protocol_preferences_set(&conn->application_protocols_overridden, protocols, protocol_count));
177 : 10 : return S2N_SUCCESS;
178 : 11 : }
179 : :
180 : : int s2n_connection_append_protocol_preference(struct s2n_connection *conn, const uint8_t *protocol, uint8_t protocol_len)
181 : 15 : {
182 [ + + ]: 15 : POSIX_GUARD_RESULT(s2n_protocol_preferences_append(&conn->application_protocols_overridden, protocol, protocol_len));
183 : 14 : return S2N_SUCCESS;
184 : 15 : }
|