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