1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include <stdint.h>
#include <sys/param.h>
#include "error/s2n_errno.h"
#include "tls/s2n_tls_parameters.h"
#include "tls/s2n_connection.h"
#include "tls/s2n_record.h"
#include "tls/s2n_resume.h"
#include "tls/s2n_alerts.h"
#include "utils/s2n_safety.h"
#include "utils/s2n_blob.h"
#define S2N_TLS_ALERT_CLOSE_NOTIFY 0
#define S2N_TLS_ALERT_UNEXPECTED_MSG 10
#define S2N_TLS_ALERT_BAD_RECORD_MAC 20
#define S2N_TLS_ALERT_DECRYPT_FAILED 21
#define S2N_TLS_ALERT_RECORD_OVERFLOW 22
#define S2N_TLS_ALERT_DECOMP_FAILED 30
#define S2N_TLS_ALERT_HANDSHAKE_FAILURE 40
#define S2N_TLS_ALERT_NO_CERTIFICATE 41
#define S2N_TLS_ALERT_BAD_CERTIFICATE 42
#define S2N_TLS_ALERT_UNSUPPORTED_CERT 43
#define S2N_TLS_ALERT_CERT_REVOKED 44
#define S2N_TLS_ALERT_CERT_EXPIRED 45
#define S2N_TLS_ALERT_CERT_UNKNOWN 46
#define S2N_TLS_ALERT_ILLEGAL_PARAMETER 47
#define S2N_TLS_ALERT_UNKNOWN_CA 48
#define S2N_TLS_ALERT_ACCESS_DENIED 49
#define S2N_TLS_ALERT_DECODE_ERROR 50
#define S2N_TLS_ALERT_DECRYPT_ERROR 51
#define S2N_TLS_ALERT_EXPORT_RESTRICTED 60
#define S2N_TLS_ALERT_PROTOCOL_VERSION 70
#define S2N_TLS_ALERT_INSUFFICIENT_SECURITY 71
#define S2N_TLS_ALERT_INTERNAL_ERROR 80
#define S2N_TLS_ALERT_USER_CANCELED 90
#define S2N_TLS_ALERT_NO_RENEGOTIATION 100
#define S2N_TLS_ALERT_UNSUPPORTED_EXTENSION 110
#define S2N_TLS_ALERT_LEVEL_WARNING 1
#define S2N_TLS_ALERT_LEVEL_FATAL 2
static bool s2n_alerts_supported(struct s2n_connection *conn)
{
/* If running in QUIC mode, QUIC handles alerting.
* S2N should not send or receive alerts. */
return conn && conn->config && !conn->config->quic_enabled;
}
static bool s2n_handle_as_warning(struct s2n_connection *conn, uint8_t level, uint8_t type)
{
/* Only TLS1.2 considers the alert level. The alert level field is
* considered deprecated in TLS1.3. */
if (s2n_connection_get_protocol_version(conn) < S2N_TLS13) {
return level == S2N_TLS_ALERT_LEVEL_WARNING
&& conn->config->alert_behavior == S2N_ALERT_IGNORE_WARNINGS;
}
/* user_canceled is the only alert currently treated as a warning in TLS1.3.
* We need to treat it as a warning regardless of alert_behavior to avoid marking
* correctly-closed connections as failed. */
return type == S2N_TLS_ALERT_USER_CANCELED;
}
int s2n_process_alert_fragment(struct s2n_connection *conn)
{
notnull_check(conn);
S2N_ERROR_IF(s2n_stuffer_data_available(&conn->in) == 0, S2N_ERR_BAD_MESSAGE);
S2N_ERROR_IF(s2n_stuffer_data_available(&conn->alert_in) == 2, S2N_ERR_ALERT_PRESENT);
ENSURE_POSIX(s2n_alerts_supported(conn), S2N_ERR_BAD_MESSAGE);
while (s2n_stuffer_data_available(&conn->in)) {
uint8_t bytes_required = 2;
/* Alerts are two bytes long, but can still be fragmented or coalesced */
if (s2n_stuffer_data_available(&conn->alert_in) == 1) {
bytes_required = 1;
}
int bytes_to_read = MIN(bytes_required, s2n_stuffer_data_available(&conn->in));
GUARD(s2n_stuffer_copy(&conn->in, &conn->alert_in, bytes_to_read));
if (s2n_stuffer_data_available(&conn->alert_in) == 2) {
/* Close notifications are handled as shutdowns */
if (conn->alert_in_data[1] == S2N_TLS_ALERT_CLOSE_NOTIFY) {
conn->closed = 1;
return 0;
}
/* Ignore warning-level alerts if we're in warning-tolerant mode */
if (s2n_handle_as_warning(conn, conn->alert_in_data[0], conn->alert_in_data[1])) {
GUARD(s2n_stuffer_wipe(&conn->alert_in));
return 0;
}
/* RFC 5077 5.1 - Expire any cached session on an error alert */
if (s2n_allowed_to_cache_connection(conn) && conn->session_id_len) {
conn->config->cache_delete(conn, conn->config->cache_delete_data, conn->session_id, conn->session_id_len);
}
/* All other alerts are treated as fatal errors */
conn->closed = 1;
S2N_ERROR(S2N_ERR_ALERT);
}
}
return 0;
}
int s2n_queue_writer_close_alert_warning(struct s2n_connection *conn)
{
notnull_check(conn);
uint8_t alert[2];
alert[0] = S2N_TLS_ALERT_LEVEL_WARNING;
alert[1] = S2N_TLS_ALERT_CLOSE_NOTIFY;
struct s2n_blob out = {.data = alert,.size = sizeof(alert) };
/* If there is an alert pending or we've already sent a close_notify, do nothing */
if (s2n_stuffer_data_available(&conn->writer_alert_out) || conn->close_notify_queued) {
return S2N_SUCCESS;
}
if (!s2n_alerts_supported(conn)) {
return S2N_SUCCESS;
}
GUARD(s2n_stuffer_write(&conn->writer_alert_out, &out));
conn->close_notify_queued = 1;
return S2N_SUCCESS;
}
static int s2n_queue_reader_alert(struct s2n_connection *conn, uint8_t level, uint8_t error_code)
{
notnull_check(conn);
uint8_t alert[2];
alert[0] = level;
alert[1] = error_code;
struct s2n_blob out = {.data = alert,.size = sizeof(alert) };
/* If there is an alert pending, do nothing */
if (s2n_stuffer_data_available(&conn->reader_alert_out)) {
return S2N_SUCCESS;
}
if (!s2n_alerts_supported(conn)) {
return S2N_SUCCESS;
}
GUARD(s2n_stuffer_write(&conn->reader_alert_out, &out));
return S2N_SUCCESS;
}
int s2n_queue_reader_unsupported_protocol_version_alert(struct s2n_connection *conn)
{
return s2n_queue_reader_alert(conn, S2N_TLS_ALERT_LEVEL_FATAL, S2N_TLS_ALERT_PROTOCOL_VERSION);
}
int s2n_queue_reader_handshake_failure_alert(struct s2n_connection *conn)
{
return s2n_queue_reader_alert(conn, S2N_TLS_ALERT_LEVEL_FATAL, S2N_TLS_ALERT_HANDSHAKE_FAILURE);
}
|