Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2000-2012 Free Software Foundation, Inc. |
3 | | * |
4 | | * Author: Nikos Mavrogiannopoulos |
5 | | * |
6 | | * This file is part of GnuTLS. |
7 | | * |
8 | | * The GnuTLS is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public License |
10 | | * as published by the Free Software Foundation; either version 2.1 of |
11 | | * the License, or (at your option) any later version. |
12 | | * |
13 | | * This library is distributed in the hope that it will be useful, but |
14 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public License |
19 | | * along with this program. If not, see <https://www.gnu.org/licenses/> |
20 | | * |
21 | | */ |
22 | | |
23 | | #include "gnutls_int.h" |
24 | | #include "errors.h" |
25 | | #include "record.h" |
26 | | #include "debug.h" |
27 | | #include "str.h" |
28 | | #include "system/ktls.h" |
29 | | |
30 | | typedef struct { |
31 | | gnutls_alert_description_t alert; |
32 | | const char *name; |
33 | | const char *desc; |
34 | | } gnutls_alert_entry; |
35 | | |
36 | | #define ALERT_ENTRY(x, y) \ |
37 | | { \ |
38 | | x, #x, y \ |
39 | | } |
40 | | |
41 | | static const gnutls_alert_entry sup_alerts[] = { |
42 | | ALERT_ENTRY(GNUTLS_A_CLOSE_NOTIFY, N_("Close notify")), |
43 | | ALERT_ENTRY(GNUTLS_A_UNEXPECTED_MESSAGE, N_("Unexpected message")), |
44 | | ALERT_ENTRY(GNUTLS_A_BAD_RECORD_MAC, N_("Bad record MAC")), |
45 | | ALERT_ENTRY(GNUTLS_A_DECRYPTION_FAILED, N_("Decryption failed")), |
46 | | ALERT_ENTRY(GNUTLS_A_RECORD_OVERFLOW, N_("Record overflow")), |
47 | | ALERT_ENTRY(GNUTLS_A_DECOMPRESSION_FAILURE, N_("Decompression failed")), |
48 | | ALERT_ENTRY(GNUTLS_A_HANDSHAKE_FAILURE, N_("Handshake failed")), |
49 | | ALERT_ENTRY(GNUTLS_A_BAD_CERTIFICATE, N_("Certificate is bad")), |
50 | | ALERT_ENTRY(GNUTLS_A_UNSUPPORTED_CERTIFICATE, |
51 | | N_("Certificate is not supported")), |
52 | | ALERT_ENTRY(GNUTLS_A_CERTIFICATE_REVOKED, |
53 | | N_("Certificate was revoked")), |
54 | | ALERT_ENTRY(GNUTLS_A_CERTIFICATE_EXPIRED, N_("Certificate is expired")), |
55 | | ALERT_ENTRY(GNUTLS_A_CERTIFICATE_UNKNOWN, N_("Unknown certificate")), |
56 | | ALERT_ENTRY(GNUTLS_A_ILLEGAL_PARAMETER, N_("Illegal parameter")), |
57 | | ALERT_ENTRY(GNUTLS_A_UNKNOWN_CA, N_("CA is unknown")), |
58 | | ALERT_ENTRY(GNUTLS_A_ACCESS_DENIED, N_("Access was denied")), |
59 | | ALERT_ENTRY(GNUTLS_A_DECODE_ERROR, N_("Decode error")), |
60 | | ALERT_ENTRY(GNUTLS_A_DECRYPT_ERROR, N_("Decrypt error")), |
61 | | ALERT_ENTRY(GNUTLS_A_EXPORT_RESTRICTION, N_("Export restriction")), |
62 | | ALERT_ENTRY(GNUTLS_A_PROTOCOL_VERSION, N_("Error in protocol version")), |
63 | | ALERT_ENTRY(GNUTLS_A_INSUFFICIENT_SECURITY, |
64 | | N_("Insufficient security")), |
65 | | ALERT_ENTRY(GNUTLS_A_USER_CANCELED, N_("User canceled")), |
66 | | ALERT_ENTRY(GNUTLS_A_SSL3_NO_CERTIFICATE, |
67 | | N_("No certificate (SSL 3.0)")), |
68 | | ALERT_ENTRY(GNUTLS_A_INTERNAL_ERROR, N_("Internal error")), |
69 | | ALERT_ENTRY(GNUTLS_A_INAPPROPRIATE_FALLBACK, |
70 | | N_("Inappropriate fallback")), |
71 | | ALERT_ENTRY(GNUTLS_A_NO_RENEGOTIATION, |
72 | | N_("No renegotiation is allowed")), |
73 | | ALERT_ENTRY(GNUTLS_A_CERTIFICATE_UNOBTAINABLE, |
74 | | N_("Could not retrieve the specified certificate")), |
75 | | ALERT_ENTRY(GNUTLS_A_UNSUPPORTED_EXTENSION, |
76 | | N_("An unsupported extension was sent")), |
77 | | ALERT_ENTRY(GNUTLS_A_UNRECOGNIZED_NAME, |
78 | | N_("The server name sent was not recognized")), |
79 | | ALERT_ENTRY(GNUTLS_A_UNKNOWN_PSK_IDENTITY, |
80 | | N_("The SRP/PSK username is missing or not known")), |
81 | | ALERT_ENTRY(GNUTLS_A_MISSING_EXTENSION, |
82 | | N_("An extension was expected but was not seen")), |
83 | | ALERT_ENTRY(GNUTLS_A_NO_APPLICATION_PROTOCOL, |
84 | | N_("No supported application protocol could be negotiated")), |
85 | | ALERT_ENTRY(GNUTLS_A_CERTIFICATE_REQUIRED, |
86 | | N_("Certificate is required")), |
87 | | { 0, NULL, NULL } |
88 | | }; |
89 | | |
90 | | /** |
91 | | * gnutls_alert_get_name: |
92 | | * @alert: is an alert number. |
93 | | * |
94 | | * This function will return a string that describes the given alert |
95 | | * number, or %NULL. See gnutls_alert_get(). |
96 | | * |
97 | | * Returns: string corresponding to #gnutls_alert_description_t value. |
98 | | **/ |
99 | | const char *gnutls_alert_get_name(gnutls_alert_description_t alert) |
100 | 0 | { |
101 | 0 | const gnutls_alert_entry *p; |
102 | |
|
103 | 0 | for (p = sup_alerts; p->desc != NULL; p++) |
104 | 0 | if (p->alert == alert) |
105 | 0 | return _(p->desc); |
106 | | |
107 | 0 | return NULL; |
108 | 0 | } |
109 | | |
110 | | /** |
111 | | * gnutls_alert_get_strname: |
112 | | * @alert: is an alert number. |
113 | | * |
114 | | * This function will return a string of the name of the alert. |
115 | | * |
116 | | * Returns: string corresponding to #gnutls_alert_description_t value. |
117 | | * |
118 | | * Since: 3.0 |
119 | | **/ |
120 | | const char *gnutls_alert_get_strname(gnutls_alert_description_t alert) |
121 | 0 | { |
122 | 0 | const gnutls_alert_entry *p; |
123 | |
|
124 | 0 | for (p = sup_alerts; p->name != NULL; p++) |
125 | 0 | if (p->alert == alert) |
126 | 0 | return p->name; |
127 | | |
128 | 0 | return NULL; |
129 | 0 | } |
130 | | |
131 | | /** |
132 | | * gnutls_alert_send: |
133 | | * @session: is a #gnutls_session_t type. |
134 | | * @level: is the level of the alert |
135 | | * @desc: is the alert description |
136 | | * |
137 | | * This function will send an alert to the peer in order to inform |
138 | | * him of something important (eg. his Certificate could not be verified). |
139 | | * If the alert level is Fatal then the peer is expected to close the |
140 | | * connection, otherwise he may ignore the alert and continue. |
141 | | * |
142 | | * The error code of the underlying record send function will be |
143 | | * returned, so you may also receive %GNUTLS_E_INTERRUPTED or |
144 | | * %GNUTLS_E_AGAIN as well. |
145 | | * |
146 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise |
147 | | * an error code is returned. |
148 | | **/ |
149 | | int gnutls_alert_send(gnutls_session_t session, gnutls_alert_level_t level, |
150 | | gnutls_alert_description_t desc) |
151 | 0 | { |
152 | 0 | uint8_t data[2]; |
153 | 0 | int ret; |
154 | 0 | const char *name; |
155 | |
|
156 | 0 | data[0] = (uint8_t)level; |
157 | 0 | data[1] = (uint8_t)desc; |
158 | |
|
159 | 0 | name = gnutls_alert_get_name((gnutls_alert_description_t)data[1]); |
160 | 0 | if (name == NULL) |
161 | 0 | name = "(unknown)"; |
162 | 0 | _gnutls_record_log("REC: Sending Alert[%d|%d] - %s\n", data[0], data[1], |
163 | 0 | name); |
164 | |
|
165 | 0 | if (session->internals.alert_read_func) { |
166 | 0 | record_parameters_st *params; |
167 | |
|
168 | 0 | ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, ¶ms); |
169 | 0 | if (ret < 0) |
170 | 0 | return gnutls_assert_val(ret); |
171 | 0 | ret = session->internals.alert_read_func( |
172 | 0 | session, params->write.level, level, desc); |
173 | 0 | if (ret < 0) |
174 | 0 | return gnutls_assert_val(ret); |
175 | | |
176 | 0 | return ret; |
177 | 0 | } |
178 | | |
179 | 0 | ret = _gnutls_send_int(session, GNUTLS_ALERT, -1, EPOCH_WRITE_CURRENT, |
180 | 0 | data, 2, MBUFFER_FLUSH); |
181 | |
|
182 | 0 | return (ret < 0) ? ret : 0; |
183 | 0 | } |
184 | | |
185 | | /** |
186 | | * gnutls_error_to_alert: |
187 | | * @err: is a negative integer |
188 | | * @level: the alert level will be stored there |
189 | | * |
190 | | * Get an alert depending on the error code returned by a gnutls |
191 | | * function. All alerts sent by this function should be considered |
192 | | * fatal. The only exception is when @err is %GNUTLS_E_REHANDSHAKE, |
193 | | * where a warning alert should be sent to the peer indicating that no |
194 | | * renegotiation will be performed. |
195 | | * |
196 | | * If there is no mapping to a valid alert the alert to indicate |
197 | | * internal error (%GNUTLS_A_INTERNAL_ERROR) is returned. |
198 | | * |
199 | | * Returns: the alert code to use for a particular error code. |
200 | | **/ |
201 | | int gnutls_error_to_alert(int err, int *level) |
202 | 0 | { |
203 | 0 | int ret, _level = -1; |
204 | |
|
205 | 0 | switch (err) { /* send appropriate alert */ |
206 | 0 | case GNUTLS_E_PK_SIG_VERIFY_FAILED: |
207 | 0 | case GNUTLS_E_ERROR_IN_FINISHED_PACKET: |
208 | 0 | ret = GNUTLS_A_DECRYPT_ERROR; |
209 | 0 | _level = GNUTLS_AL_FATAL; |
210 | 0 | break; |
211 | 0 | case GNUTLS_E_DECRYPTION_FAILED: |
212 | | /* GNUTLS_A_DECRYPTION_FAILED is not sent, because |
213 | | * it is not defined in SSL3. Note that we must |
214 | | * not distinguish Decryption failures from mac |
215 | | * check failures, due to the possibility of some |
216 | | * attacks. |
217 | | */ |
218 | 0 | ret = GNUTLS_A_BAD_RECORD_MAC; |
219 | 0 | _level = GNUTLS_AL_FATAL; |
220 | 0 | break; |
221 | 0 | case GNUTLS_E_UNEXPECTED_PACKET_LENGTH: |
222 | 0 | case GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH: |
223 | 0 | case GNUTLS_E_NO_CERTIFICATE_FOUND: |
224 | 0 | case GNUTLS_E_HANDSHAKE_TOO_LARGE: |
225 | 0 | ret = GNUTLS_A_DECODE_ERROR; |
226 | 0 | _level = GNUTLS_AL_FATAL; |
227 | 0 | break; |
228 | 0 | case GNUTLS_E_DECOMPRESSION_FAILED: |
229 | 0 | ret = GNUTLS_A_DECOMPRESSION_FAILURE; |
230 | 0 | _level = GNUTLS_AL_FATAL; |
231 | 0 | break; |
232 | 0 | case GNUTLS_E_ILLEGAL_PARAMETER: |
233 | 0 | case GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER: |
234 | 0 | case GNUTLS_E_ILLEGAL_SRP_USERNAME: |
235 | 0 | case GNUTLS_E_PK_INVALID_PUBKEY: |
236 | 0 | case GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM: |
237 | 0 | case GNUTLS_E_RECEIVED_DISALLOWED_NAME: |
238 | 0 | case GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY: |
239 | 0 | ret = GNUTLS_A_ILLEGAL_PARAMETER; |
240 | 0 | _level = GNUTLS_AL_FATAL; |
241 | 0 | break; |
242 | 0 | case GNUTLS_E_UNKNOWN_SRP_USERNAME: |
243 | 0 | ret = GNUTLS_A_UNKNOWN_PSK_IDENTITY; |
244 | 0 | _level = GNUTLS_AL_FATAL; |
245 | 0 | break; |
246 | 0 | case GNUTLS_E_ASN1_ELEMENT_NOT_FOUND: |
247 | 0 | case GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND: |
248 | 0 | case GNUTLS_E_ASN1_DER_ERROR: |
249 | 0 | case GNUTLS_E_ASN1_VALUE_NOT_FOUND: |
250 | 0 | case GNUTLS_E_ASN1_GENERIC_ERROR: |
251 | 0 | case GNUTLS_E_ASN1_VALUE_NOT_VALID: |
252 | 0 | case GNUTLS_E_ASN1_TAG_ERROR: |
253 | 0 | case GNUTLS_E_ASN1_TAG_IMPLICIT: |
254 | 0 | case GNUTLS_E_ASN1_TYPE_ANY_ERROR: |
255 | 0 | case GNUTLS_E_ASN1_SYNTAX_ERROR: |
256 | 0 | case GNUTLS_E_ASN1_DER_OVERFLOW: |
257 | 0 | case GNUTLS_E_CERTIFICATE_ERROR: |
258 | 0 | case GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR: |
259 | 0 | ret = GNUTLS_A_BAD_CERTIFICATE; |
260 | 0 | _level = GNUTLS_AL_FATAL; |
261 | 0 | break; |
262 | 0 | case GNUTLS_E_UNKNOWN_CIPHER_SUITE: |
263 | 0 | case GNUTLS_E_INSUFFICIENT_CREDENTIALS: |
264 | 0 | case GNUTLS_E_NO_CIPHER_SUITES: |
265 | 0 | case GNUTLS_E_NO_COMPRESSION_ALGORITHMS: |
266 | 0 | case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM: |
267 | 0 | case GNUTLS_E_SAFE_RENEGOTIATION_FAILED: |
268 | 0 | case GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOL: |
269 | 0 | case GNUTLS_E_UNKNOWN_PK_ALGORITHM: |
270 | 0 | case GNUTLS_E_UNWANTED_ALGORITHM: |
271 | 0 | case GNUTLS_E_NO_COMMON_KEY_SHARE: |
272 | 0 | case GNUTLS_E_ECC_NO_SUPPORTED_CURVES: |
273 | 0 | case GNUTLS_E_ECC_UNSUPPORTED_CURVE: |
274 | 0 | ret = GNUTLS_A_HANDSHAKE_FAILURE; |
275 | 0 | _level = GNUTLS_AL_FATAL; |
276 | 0 | break; |
277 | 0 | case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION: |
278 | 0 | ret = GNUTLS_A_UNSUPPORTED_EXTENSION; |
279 | 0 | _level = GNUTLS_AL_FATAL; |
280 | 0 | break; |
281 | 0 | case GNUTLS_E_MISSING_EXTENSION: |
282 | 0 | ret = GNUTLS_A_MISSING_EXTENSION; |
283 | 0 | _level = GNUTLS_AL_FATAL; |
284 | 0 | break; |
285 | 0 | case GNUTLS_E_USER_ERROR: |
286 | 0 | ret = GNUTLS_A_USER_CANCELED; |
287 | 0 | _level = GNUTLS_AL_FATAL; |
288 | 0 | break; |
289 | 0 | case GNUTLS_E_UNEXPECTED_PACKET: |
290 | 0 | case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET: |
291 | 0 | case GNUTLS_E_PREMATURE_TERMINATION: |
292 | 0 | ret = GNUTLS_A_UNEXPECTED_MESSAGE; |
293 | 0 | _level = GNUTLS_AL_FATAL; |
294 | 0 | break; |
295 | 0 | case GNUTLS_E_REHANDSHAKE: |
296 | 0 | case GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED: |
297 | 0 | ret = GNUTLS_A_NO_RENEGOTIATION; |
298 | 0 | _level = GNUTLS_AL_WARNING; |
299 | 0 | break; |
300 | 0 | case GNUTLS_E_UNSUPPORTED_VERSION_PACKET: |
301 | 0 | ret = GNUTLS_A_PROTOCOL_VERSION; |
302 | 0 | _level = GNUTLS_AL_FATAL; |
303 | 0 | break; |
304 | 0 | case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE: |
305 | 0 | ret = GNUTLS_A_UNSUPPORTED_CERTIFICATE; |
306 | 0 | _level = GNUTLS_AL_FATAL; |
307 | 0 | break; |
308 | 0 | case GNUTLS_E_RECORD_OVERFLOW: |
309 | 0 | ret = GNUTLS_A_RECORD_OVERFLOW; |
310 | 0 | _level = GNUTLS_AL_FATAL; |
311 | 0 | break; |
312 | 0 | case GNUTLS_E_INTERNAL_ERROR: |
313 | 0 | case GNUTLS_E_NO_TEMPORARY_DH_PARAMS: |
314 | 0 | case GNUTLS_E_NO_TEMPORARY_RSA_PARAMS: |
315 | 0 | ret = GNUTLS_A_INTERNAL_ERROR; |
316 | 0 | _level = GNUTLS_AL_FATAL; |
317 | 0 | break; |
318 | 0 | case GNUTLS_E_INAPPROPRIATE_FALLBACK: |
319 | 0 | ret = GNUTLS_A_INAPPROPRIATE_FALLBACK; |
320 | 0 | _level = GNUTLS_AL_FATAL; |
321 | 0 | break; |
322 | 0 | case GNUTLS_E_OPENPGP_GETKEY_FAILED: |
323 | 0 | ret = GNUTLS_A_CERTIFICATE_UNOBTAINABLE; |
324 | 0 | _level = GNUTLS_AL_FATAL; |
325 | 0 | break; |
326 | 0 | case GNUTLS_E_DH_PRIME_UNACCEPTABLE: |
327 | 0 | case GNUTLS_E_SESSION_USER_ID_CHANGED: |
328 | 0 | case GNUTLS_E_INSUFFICIENT_SECURITY: |
329 | 0 | ret = GNUTLS_A_INSUFFICIENT_SECURITY; |
330 | 0 | _level = GNUTLS_AL_FATAL; |
331 | 0 | break; |
332 | 0 | case GNUTLS_E_NO_APPLICATION_PROTOCOL: |
333 | 0 | ret = GNUTLS_A_NO_APPLICATION_PROTOCOL; |
334 | 0 | _level = GNUTLS_AL_FATAL; |
335 | 0 | break; |
336 | 0 | case GNUTLS_E_UNRECOGNIZED_NAME: |
337 | 0 | ret = GNUTLS_A_UNRECOGNIZED_NAME; |
338 | 0 | _level = GNUTLS_AL_FATAL; |
339 | 0 | break; |
340 | 0 | case GNUTLS_E_CERTIFICATE_REQUIRED: |
341 | 0 | ret = GNUTLS_A_CERTIFICATE_REQUIRED; |
342 | 0 | _level = GNUTLS_AL_FATAL; |
343 | 0 | break; |
344 | 0 | default: |
345 | 0 | ret = GNUTLS_A_INTERNAL_ERROR; |
346 | 0 | _level = GNUTLS_AL_FATAL; |
347 | 0 | break; |
348 | 0 | } |
349 | | |
350 | 0 | if (level != NULL) |
351 | 0 | *level = _level; |
352 | |
|
353 | 0 | return ret; |
354 | 0 | } |
355 | | |
356 | | /** |
357 | | * gnutls_alert_send_appropriate: |
358 | | * @session: is a #gnutls_session_t type. |
359 | | * @err: is an error code returned by another GnuTLS function |
360 | | * |
361 | | * Sends an alert to the peer depending on the error code returned by |
362 | | * a gnutls function. This function will call gnutls_error_to_alert() |
363 | | * to determine the appropriate alert to send. |
364 | | * |
365 | | * This function may also return %GNUTLS_E_AGAIN, or |
366 | | * %GNUTLS_E_INTERRUPTED. |
367 | | * |
368 | | * This function historically was always sending an alert to the |
369 | | * peer, even if @err was inappropriate to respond with an alert |
370 | | * (e.g., %GNUTLS_E_SUCCESS). Since 3.6.6 this function returns |
371 | | * success without transmitting any data on error codes that |
372 | | * should not result to an alert. |
373 | | * |
374 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise |
375 | | * an error code is returned. |
376 | | */ |
377 | | int gnutls_alert_send_appropriate(gnutls_session_t session, int err) |
378 | 0 | { |
379 | 0 | int alert; |
380 | 0 | int level; |
381 | |
|
382 | 0 | if (err != GNUTLS_E_REHANDSHAKE && |
383 | 0 | (!gnutls_error_is_fatal(err) || |
384 | 0 | err == GNUTLS_E_FATAL_ALERT_RECEIVED)) |
385 | 0 | return gnutls_assert_val(0); |
386 | | |
387 | 0 | alert = gnutls_error_to_alert(err, &level); |
388 | |
|
389 | 0 | return gnutls_alert_send(session, (gnutls_alert_level_t)level, alert); |
390 | 0 | } |
391 | | |
392 | | /** |
393 | | * gnutls_alert_get: |
394 | | * @session: is a #gnutls_session_t type. |
395 | | * |
396 | | * This function will return the last alert number received. This |
397 | | * function should be called when %GNUTLS_E_WARNING_ALERT_RECEIVED or |
398 | | * %GNUTLS_E_FATAL_ALERT_RECEIVED errors are returned by a gnutls |
399 | | * function. The peer may send alerts if he encounters an error. |
400 | | * If no alert has been received the returned value is undefined. |
401 | | * |
402 | | * Returns: the last alert received, a |
403 | | * #gnutls_alert_description_t value. |
404 | | **/ |
405 | | gnutls_alert_description_t gnutls_alert_get(gnutls_session_t session) |
406 | 0 | { |
407 | 0 | return (gnutls_alert_description_t)session->internals.last_alert; |
408 | 0 | } |