trap-manager: Wait for install to finish before uninstalling
[strongswan.git] / src / libtls / tls_alert.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tls_alert.h"
17
18 #include <utils/debug.h>
19 #include <collections/linked_list.h>
20
21 ENUM_BEGIN(tls_alert_desc_names, TLS_CLOSE_NOTIFY, TLS_CLOSE_NOTIFY,
22 "close notify",
23 );
24 ENUM_NEXT(tls_alert_desc_names, TLS_UNEXPECTED_MESSAGE, TLS_UNEXPECTED_MESSAGE,
25 TLS_CLOSE_NOTIFY,
26 "unexpected message",
27 );
28 ENUM_NEXT(tls_alert_desc_names, TLS_BAD_RECORD_MAC, TLS_RECORD_OVERFLOW,
29 TLS_UNEXPECTED_MESSAGE,
30 "bad record mac",
31 "decryption failed",
32 "record overflow",
33 );
34 ENUM_NEXT(tls_alert_desc_names, TLS_DECOMPRESSION_FAILURE, TLS_DECOMPRESSION_FAILURE,
35 TLS_RECORD_OVERFLOW,
36 "decompression_failure",
37 );
38 ENUM_NEXT(tls_alert_desc_names, TLS_HANDSHAKE_FAILURE, TLS_DECRYPT_ERROR,
39 TLS_DECOMPRESSION_FAILURE,
40 "handshake failure",
41 "no certificate",
42 "bad certificate",
43 "unsupported certificate",
44 "certificate revoked",
45 "certificate expired",
46 "certificate unknown",
47 "illegal parameter",
48 "unknown ca",
49 "access denied",
50 "decode error",
51 "decrypt error",
52 );
53 ENUM_NEXT(tls_alert_desc_names, TLS_EXPORT_RESTRICTION, TLS_EXPORT_RESTRICTION,
54 TLS_DECRYPT_ERROR,
55 "export restriction",
56 );
57 ENUM_NEXT(tls_alert_desc_names, TLS_PROTOCOL_VERSION, TLS_INSUFFICIENT_SECURITY,
58 TLS_EXPORT_RESTRICTION,
59 "protocol version",
60 "insufficient security",
61 );
62 ENUM_NEXT(tls_alert_desc_names, TLS_INTERNAL_ERROR, TLS_INTERNAL_ERROR,
63 TLS_INSUFFICIENT_SECURITY,
64 "internal error",
65 );
66 ENUM_NEXT(tls_alert_desc_names, TLS_USER_CANCELED, TLS_USER_CANCELED,
67 TLS_INTERNAL_ERROR,
68 "user canceled",
69 );
70 ENUM_NEXT(tls_alert_desc_names, TLS_NO_RENEGOTIATION, TLS_NO_RENEGOTIATION,
71 TLS_USER_CANCELED,
72 "no renegotiation",
73 );
74 ENUM_NEXT(tls_alert_desc_names, TLS_UNSUPPORTED_EXTENSION, TLS_UNSUPPORTED_EXTENSION,
75 TLS_NO_RENEGOTIATION,
76 "unsupported extension",
77 );
78 ENUM_END(tls_alert_desc_names, TLS_UNSUPPORTED_EXTENSION);
79
80
81 typedef struct private_tls_alert_t private_tls_alert_t;
82
83 /**
84 * Private data of an tls_alert_t object.
85 */
86 struct private_tls_alert_t {
87
88 /**
89 * Public tls_alert_t interface.
90 */
91 tls_alert_t public;
92
93 /**
94 * Warning queue
95 */
96 linked_list_t *warnings;
97
98 /**
99 * Do we have a fatal alert?
100 */
101 bool fatal;
102
103 /**
104 * Has the fatal alert been consumed?
105 */
106 bool consumed;
107
108 /**
109 * Fatal alert description
110 */
111 tls_alert_desc_t desc;
112 };
113
114 METHOD(tls_alert_t, add, void,
115 private_tls_alert_t *this, tls_alert_level_t level,
116 tls_alert_desc_t desc)
117 {
118 if (level == TLS_FATAL)
119 {
120 if (!this->fatal)
121 {
122 this->desc = desc;
123 this->fatal = TRUE;
124 }
125 }
126 else
127 {
128 this->warnings->insert_last(this->warnings, (void*)(uintptr_t)desc);
129 }
130 }
131
132 METHOD(tls_alert_t, get, bool,
133 private_tls_alert_t *this, tls_alert_level_t *level,
134 tls_alert_desc_t *desc)
135 {
136 if (this->fatal && !this->consumed)
137 {
138 this->consumed = TRUE;
139 *level = TLS_FATAL;
140 *desc = this->desc;
141 if (this->desc == TLS_CLOSE_NOTIFY)
142 {
143 DBG1(DBG_TLS, "sending TLS close notify");
144 }
145 else
146 {
147 DBG1(DBG_TLS, "sending fatal TLS alert '%N'",
148 tls_alert_desc_names, this->desc);
149 }
150 return TRUE;
151 }
152 else
153 {
154 uintptr_t warning;
155
156 if (this->warnings->remove_first(this->warnings,
157 (void**)&warning) == SUCCESS)
158 {
159 *level = TLS_WARNING;
160 *desc = warning;
161 DBG1(DBG_TLS, "sending TLS alert warning '%N'",
162 tls_alert_desc_names, warning);
163 return TRUE;
164 }
165 }
166 return FALSE;
167 }
168
169 METHOD(tls_alert_t, fatal, bool,
170 private_tls_alert_t *this)
171 {
172 return this->fatal;
173 }
174
175 METHOD(tls_alert_t, process, status_t,
176 private_tls_alert_t *this, tls_alert_level_t level,
177 tls_alert_desc_t desc)
178 {
179 if (desc == TLS_CLOSE_NOTIFY)
180 {
181 DBG1(DBG_TLS, "received TLS close notify");
182 add(this, TLS_FATAL, TLS_CLOSE_NOTIFY);
183 return NEED_MORE;
184 }
185 switch (level)
186 {
187 case TLS_WARNING:
188 DBG1(DBG_TLS, "received TLS alert warning '%N'",
189 tls_alert_desc_names, desc);
190 return NEED_MORE;
191 case TLS_FATAL:
192 DBG1(DBG_TLS, "received fatal TLS alert '%N'",
193 tls_alert_desc_names, desc);
194 return FAILED;
195 default:
196 DBG1(DBG_TLS, "received unknown TLS alert '%N'",
197 tls_alert_desc_names, desc);
198 return FAILED;
199 }
200 }
201
202 METHOD(tls_alert_t, destroy, void,
203 private_tls_alert_t *this)
204 {
205 this->warnings->destroy(this->warnings);
206 free(this);
207 }
208
209 /**
210 * See header
211 */
212 tls_alert_t *tls_alert_create()
213 {
214 private_tls_alert_t *this;
215
216 INIT(this,
217 .public = {
218 .add = _add,
219 .get = _get,
220 .fatal = _fatal,
221 .process = _process,
222 .destroy = _destroy,
223 },
224 .warnings = linked_list_create(),
225 );
226
227 return &this->public;
228 }