1 |
grobian 09/06/18 09:20:37 |
2 |
|
3 |
Added: |
4 |
mutt-1.5.19-mutt_ssl-3af7e8af1983-dc9ec900c657.patch |
5 |
mutt-1.5.19-mutt-gnutls-7d0583e0315d-0b13183e40e0.patch |
6 |
Log: |
7 |
Revision bump for CVE-2009-1390, add related patches |
8 |
(Portage version: 2.1.6.13/cvs/Linux x86_64) |
9 |
|
10 |
Revision Changes Path |
11 |
1.1 mail-client/mutt/files/mutt-1.5.19-mutt_ssl-3af7e8af1983-dc9ec900c657.patch |
12 |
|
13 |
file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/mail-client/mutt/files/mutt-1.5.19-mutt_ssl-3af7e8af1983-dc9ec900c657.patch?rev=1.1&view=markup |
14 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/mail-client/mutt/files/mutt-1.5.19-mutt_ssl-3af7e8af1983-dc9ec900c657.patch?rev=1.1&content-type=text/plain |
15 |
|
16 |
Index: mutt-1.5.19-mutt_ssl-3af7e8af1983-dc9ec900c657.patch |
17 |
=================================================================== |
18 |
http://thread.gmane.org/gmane.comp.security.oss.general/1847 |
19 |
http://bugs.gentoo.org/show_bug.cgi?id=274488 |
20 |
|
21 |
whitespace-only hunks removed |
22 |
|
23 |
Index: mutt_ssl.c |
24 |
=================================================================== |
25 |
--- mutt_ssl.c (revision 5622:3af7e8af1983) |
26 |
+++ mutt_ssl.c (revision 5870:dc9ec900c657) |
27 |
@@ -565,17 +565,20 @@ |
28 |
|
29 |
/* expiration check */ |
30 |
- if (X509_cmp_current_time (X509_get_notBefore (peercert)) >= 0) |
31 |
- { |
32 |
- dprint (2, (debugfile, "Server certificate is not yet valid\n")); |
33 |
- mutt_error (_("Server certificate is not yet valid")); |
34 |
- mutt_sleep (2); |
35 |
- return 0; |
36 |
- } |
37 |
- if (X509_cmp_current_time (X509_get_notAfter (peercert)) <= 0) |
38 |
- { |
39 |
- dprint (2, (debugfile, "Server certificate has expired")); |
40 |
- mutt_error (_("Server certificate has expired")); |
41 |
- mutt_sleep (2); |
42 |
- return 0; |
43 |
+ if (option (OPTSSLVERIFYDATES) != M_NO) |
44 |
+ { |
45 |
+ if (X509_cmp_current_time (X509_get_notBefore (peercert)) >= 0) |
46 |
+ { |
47 |
+ dprint (2, (debugfile, "Server certificate is not yet valid\n")); |
48 |
+ mutt_error (_("Server certificate is not yet valid")); |
49 |
+ mutt_sleep (2); |
50 |
+ return 0; |
51 |
+ } |
52 |
+ if (X509_cmp_current_time (X509_get_notAfter (peercert)) <= 0) |
53 |
+ { |
54 |
+ dprint (2, (debugfile, "Server certificate has expired")); |
55 |
+ mutt_error (_("Server certificate has expired")); |
56 |
+ mutt_sleep (2); |
57 |
+ return 0; |
58 |
+ } |
59 |
} |
60 |
|
61 |
@@ -585,5 +588,5 @@ |
62 |
if (!X509_digest (peercert, EVP_sha1(), peermd, &peermdlen)) |
63 |
{ |
64 |
- fclose (fp); |
65 |
+ safe_fclose (&fp); |
66 |
return 0; |
67 |
} |
68 |
@@ -592,10 +595,10 @@ |
69 |
{ |
70 |
pass = compare_certificates (cert, peercert, peermd, peermdlen) ? 0 : 1; |
71 |
- |
72 |
+ |
73 |
if (pass) |
74 |
break; |
75 |
} |
76 |
X509_free (cert); |
77 |
- fclose (fp); |
78 |
+ safe_fclose (&fp); |
79 |
|
80 |
return pass; |
81 |
@@ -737,6 +740,8 @@ |
82 |
} |
83 |
|
84 |
-/* check whether cert is preauthorized */ |
85 |
-static int ssl_check_preauth (X509 *cert, CONNECTION *conn) |
86 |
+/* check whether cert is preauthorized. If host is not null, verify that |
87 |
+ * it matches the certificate. |
88 |
+ * Return > 0: authorized, < 0: problems, 0: unknown validity */ |
89 |
+static int ssl_check_preauth (X509 *cert, const char* host) |
90 |
{ |
91 |
char buf[SHORT_STRING]; |
92 |
@@ -750,11 +755,14 @@ |
93 |
|
94 |
buf[0] = 0; |
95 |
- if (!check_host (cert, conn->account.host, buf, sizeof (buf))) |
96 |
- { |
97 |
- mutt_error (_("Certificate host check failed: %s"), buf); |
98 |
- mutt_sleep (2); |
99 |
- return -1; |
100 |
- } |
101 |
- dprint (2, (debugfile, "ssl_check_preauth: hostname check passed\n")); |
102 |
+ if (host && option (OPTSSLVERIFYHOST) != M_NO) |
103 |
+ { |
104 |
+ if (!check_host (cert, host, buf, sizeof (buf))) |
105 |
+ { |
106 |
+ mutt_error (_("Certificate host check failed: %s"), buf); |
107 |
+ mutt_sleep (2); |
108 |
+ return -1; |
109 |
+ } |
110 |
+ dprint (2, (debugfile, "ssl_check_preauth: hostname check passed\n")); |
111 |
+ } |
112 |
|
113 |
if (check_certificate_by_signer (cert)) |
114 |
@@ -780,42 +788,28 @@ |
115 |
X509 *cert; |
116 |
|
117 |
- if ((preauthrc = ssl_check_preauth (data->cert, conn)) > 0) |
118 |
+ if ((preauthrc = ssl_check_preauth (data->cert, conn->account.host)) > 0) |
119 |
return preauthrc; |
120 |
|
121 |
chain = SSL_get_peer_cert_chain (data->ssl); |
122 |
chain_len = sk_X509_num (chain); |
123 |
- if (!chain || (chain_len < 1)) |
124 |
+ /* negative preauthrc means the certificate won't be accepted without |
125 |
+ * manual override. */ |
126 |
+ if (preauthrc < 0 || !chain || (chain_len <= 1)) |
127 |
return interactive_check_cert (data->cert, 0, 0); |
128 |
|
129 |
- /* check the chain from root to peer */ |
130 |
+ /* check the chain from root to peer. */ |
131 |
for (i = chain_len-1; i >= 0; i--) |
132 |
{ |
133 |
cert = sk_X509_value (chain, i); |
134 |
- if (check_certificate_cache (cert)) |
135 |
- dprint (2, (debugfile, "ssl chain: already cached: %s\n", cert->name)); |
136 |
- else if (i /* 0 is the peer */ || !preauthrc) |
137 |
- { |
138 |
- if (check_certificate_by_signer (cert)) |
139 |
- { |
140 |
- dprint (2, (debugfile, "ssl chain: checked by signer: %s\n", cert->name)); |
141 |
- ssl_cache_trusted_cert (cert); |
142 |
+ |
143 |
+ /* if the certificate validates or is manually accepted, then add it to |
144 |
+ * the trusted set and recheck the peer certificate */ |
145 |
+ if (ssl_check_preauth (cert, NULL) |
146 |
+ || interactive_check_cert (cert, i, chain_len)) |
147 |
+ { |
148 |
+ ssl_cache_trusted_cert (cert); |
149 |
+ if (ssl_check_preauth (data->cert, conn->account.host)) |
150 |
return 1; |
151 |
- } |
152 |
- else if (SslCertFile && check_certificate_by_digest (cert)) |
153 |
- { |
154 |
- dprint (2, (debugfile, "ssl chain: trusted with file: %s\n", cert->name)); |
155 |
- ssl_cache_trusted_cert (cert); |
156 |
- return 1; |
157 |
- } |
158 |
- else /* allow users to shoot their foot */ |
159 |
- { |
160 |
- dprint (2, (debugfile, "ssl chain: check failed: %s\n", cert->name)); |
161 |
- if (interactive_check_cert (cert, i, chain_len)) |
162 |
- return 1; |
163 |
- } |
164 |
- } |
165 |
- else /* highly suspicious because (i==0 && preauthrc < 0) */ |
166 |
- if (interactive_check_cert (cert, i, chain_len)) |
167 |
- return 1; |
168 |
+ } |
169 |
} |
170 |
|
171 |
@@ -882,6 +876,8 @@ |
172 |
len - idx, len); |
173 |
menu->title = title; |
174 |
- if (SslCertFile && X509_cmp_current_time (X509_get_notAfter (cert)) >= 0 |
175 |
- && X509_cmp_current_time (X509_get_notBefore (cert)) < 0) |
176 |
+ if (SslCertFile |
177 |
+ && (option (OPTSSLVERIFYDATES) == M_NO |
178 |
+ || (X509_cmp_current_time (X509_get_notAfter (cert)) >= 0 |
179 |
+ && X509_cmp_current_time (X509_get_notBefore (cert)) < 0))) |
180 |
{ |
181 |
menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always"); |
182 |
@@ -893,5 +889,5 @@ |
183 |
menu->keys = _("ro"); |
184 |
} |
185 |
- |
186 |
+ |
187 |
helpstr[0] = '\0'; |
188 |
mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT); |
189 |
@@ -918,5 +914,5 @@ |
190 |
if (PEM_write_X509 (fp, cert)) |
191 |
done = 1; |
192 |
- fclose (fp); |
193 |
+ safe_fclose (&fp); |
194 |
} |
195 |
if (!done) |
196 |
|
197 |
|
198 |
|
199 |
1.1 mail-client/mutt/files/mutt-1.5.19-mutt-gnutls-7d0583e0315d-0b13183e40e0.patch |
200 |
|
201 |
file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/mail-client/mutt/files/mutt-1.5.19-mutt-gnutls-7d0583e0315d-0b13183e40e0.patch?rev=1.1&view=markup |
202 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/mail-client/mutt/files/mutt-1.5.19-mutt-gnutls-7d0583e0315d-0b13183e40e0.patch?rev=1.1&content-type=text/plain |
203 |
|
204 |
Index: mutt-1.5.19-mutt-gnutls-7d0583e0315d-0b13183e40e0.patch |
205 |
=================================================================== |
206 |
http://thread.gmane.org/gmane.comp.security.oss.general/1847 |
207 |
http://bugs.gentoo.org/show_bug.cgi?id=274488 |
208 |
|
209 |
whitespace-only hunks removed |
210 |
|
211 |
Index: mutt_ssl_gnutls.c |
212 |
=================================================================== |
213 |
--- mutt_ssl_gnutls.c (revision 5623:7d0583e0315d) |
214 |
+++ mutt_ssl_gnutls.c (revision 5853:0b13183e40e0) |
215 |
@@ -34,4 +34,13 @@ |
216 |
#include "mutt_regex.h" |
217 |
|
218 |
+/* certificate error bitmap values */ |
219 |
+#define CERTERR_VALID 0 |
220 |
+#define CERTERR_EXPIRED 1 |
221 |
+#define CERTERR_NOTYETVALID 2 |
222 |
+#define CERTERR_REVOKED 4 |
223 |
+#define CERTERR_NOTTRUSTED 8 |
224 |
+#define CERTERR_HOSTNAME 16 |
225 |
+#define CERTERR_SIGNERNOTCA 32 |
226 |
+ |
227 |
typedef struct _tlssockdata |
228 |
{ |
229 |
@@ -409,5 +418,5 @@ |
230 |
|
231 |
b64_data.size = fread(b64_data.data, 1, b64_data.size, fd1); |
232 |
- fclose(fd1); |
233 |
+ safe_fclose (&fd1); |
234 |
|
235 |
do { |
236 |
@@ -505,5 +514,5 @@ |
237 |
buf[0] = '\0'; |
238 |
tls_fingerprint (GNUTLS_DIG_MD5, buf, sizeof (buf), cert); |
239 |
- while ((linestr = mutt_read_line(linestr, &linestrsize, fp, &linenum)) != NULL) |
240 |
+ while ((linestr = mutt_read_line(linestr, &linestrsize, fp, &linenum, 0)) != NULL) |
241 |
{ |
242 |
if(linestr[0] == '#' && linestr[1] == 'H') |
243 |
@@ -518,5 +527,5 @@ |
244 |
regfree(&preg); |
245 |
FREE(&linestr); |
246 |
- fclose(fp); |
247 |
+ safe_fclose (&fp); |
248 |
return 1; |
249 |
} |
250 |
@@ -526,9 +535,113 @@ |
251 |
|
252 |
regfree(&preg); |
253 |
- fclose(fp); |
254 |
+ safe_fclose (&fp); |
255 |
} |
256 |
|
257 |
/* not found a matching name */ |
258 |
return 0; |
259 |
+} |
260 |
+ |
261 |
+static int tls_check_preauth (const gnutls_datum_t *certdata, |
262 |
+ gnutls_certificate_status certstat, |
263 |
+ const char *hostname, int chainidx, int* certerr, |
264 |
+ int* savedcert) |
265 |
+{ |
266 |
+ gnutls_x509_crt cert; |
267 |
+ |
268 |
+ *certerr = CERTERR_VALID; |
269 |
+ *savedcert = 0; |
270 |
+ |
271 |
+ if (gnutls_x509_crt_init (&cert) < 0) |
272 |
+ { |
273 |
+ mutt_error (_("Error initialising gnutls certificate data")); |
274 |
+ mutt_sleep (2); |
275 |
+ return -1; |
276 |
+ } |
277 |
+ |
278 |
+ if (gnutls_x509_crt_import (cert, certdata, GNUTLS_X509_FMT_DER) < 0) |
279 |
+ { |
280 |
+ mutt_error (_("Error processing certificate data")); |
281 |
+ mutt_sleep (2); |
282 |
+ gnutls_x509_crt_deinit (cert); |
283 |
+ return -1; |
284 |
+ } |
285 |
+ |
286 |
+ if (option (OPTSSLVERIFYDATES) != M_NO) |
287 |
+ { |
288 |
+ if (gnutls_x509_crt_get_expiration_time (cert) < time(NULL)) |
289 |
+ *certerr |= CERTERR_EXPIRED; |
290 |
+ if (gnutls_x509_crt_get_activation_time (cert) > time(NULL)) |
291 |
+ *certerr |= CERTERR_NOTYETVALID; |
292 |
+ } |
293 |
+ |
294 |
+ if (chainidx == 0 && option (OPTSSLVERIFYHOST) != M_NO |
295 |
+ && !gnutls_x509_crt_check_hostname (cert, hostname) |
296 |
+ && !tls_check_stored_hostname (certdata, hostname)) |
297 |
+ *certerr |= CERTERR_HOSTNAME; |
298 |
+ |
299 |
+ /* see whether certificate is in our cache (certificates file) */ |
300 |
+ if (tls_compare_certificates (certdata)) |
301 |
+ { |
302 |
+ *savedcert = 1; |
303 |
+ |
304 |
+ if (chainidx == 0 && certstat & GNUTLS_CERT_INVALID) |
305 |
+ { |
306 |
+ /* doesn't matter - have decided is valid because server |
307 |
+ certificate is in our trusted cache */ |
308 |
+ certstat ^= GNUTLS_CERT_INVALID; |
309 |
+ } |
310 |
+ |
311 |
+ if (chainidx == 0 && certstat & GNUTLS_CERT_SIGNER_NOT_FOUND) |
312 |
+ { |
313 |
+ /* doesn't matter that we haven't found the signer, since |
314 |
+ certificate is in our trusted cache */ |
315 |
+ certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND; |
316 |
+ } |
317 |
+ |
318 |
+ if (chainidx <= 1 && certstat & GNUTLS_CERT_SIGNER_NOT_CA) |
319 |
+ { |
320 |
+ /* Hmm. Not really sure how to handle this, but let's say |
321 |
+ that we don't care if the CA certificate hasn't got the |
322 |
+ correct X.509 basic constraints if server or first signer |
323 |
+ certificate is in our cache. */ |
324 |
+ certstat ^= GNUTLS_CERT_SIGNER_NOT_CA; |
325 |
+ } |
326 |
+ } |
327 |
+ |
328 |
+ if (certstat & GNUTLS_CERT_REVOKED) |
329 |
+ { |
330 |
+ *certerr |= CERTERR_REVOKED; |
331 |
+ certstat ^= GNUTLS_CERT_REVOKED; |
332 |
+ } |
333 |
+ |
334 |
+ if (certstat & GNUTLS_CERT_INVALID) |
335 |
+ { |
336 |
+ *certerr |= CERTERR_NOTTRUSTED; |
337 |
+ certstat ^= GNUTLS_CERT_INVALID; |
338 |
+ } |
339 |
+ |
340 |
+ if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND) |
341 |
+ { |
342 |
+ /* NB: already cleared if cert in cache */ |
343 |
+ *certerr |= CERTERR_NOTTRUSTED; |
344 |
+ certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND; |
345 |
+ } |
346 |
+ |
347 |
+ if (certstat & GNUTLS_CERT_SIGNER_NOT_CA) |
348 |
+ { |
349 |
+ /* NB: already cleared if cert in cache */ |
350 |
+ *certerr |= CERTERR_SIGNERNOTCA; |
351 |
+ certstat ^= GNUTLS_CERT_SIGNER_NOT_CA; |
352 |
+ } |
353 |
+ |
354 |
+ gnutls_x509_crt_deinit (cert); |
355 |
+ |
356 |
+ /* we've been zeroing the interesting bits in certstat - |
357 |
+ don't return OK if there are any unhandled bits we don't |
358 |
+ understand */ |
359 |
+ if (*certerr == CERTERR_VALID && certstat == 0) |
360 |
+ return 0; |
361 |
+ |
362 |
+ return -1; |
363 |
} |
364 |
|
365 |
@@ -537,11 +650,6 @@ |
366 |
const char* hostname, int idx, int len) |
367 |
{ |
368 |
+ int certerr, savedcert; |
369 |
gnutls_x509_crt cert; |
370 |
- int certerr_hostname = 0; |
371 |
- int certerr_expired = 0; |
372 |
- int certerr_notyetvalid = 0; |
373 |
- int certerr_nottrusted = 0; |
374 |
- int certerr_revoked = 0; |
375 |
- int certerr_signernotca = 0; |
376 |
char buf[SHORT_STRING]; |
377 |
char fpbuf[SHORT_STRING]; |
378 |
@@ -563,4 +671,9 @@ |
379 |
int i, row, done, ret; |
380 |
|
381 |
+ if (!tls_check_preauth (certdata, certstat, hostname, idx, &certerr, |
382 |
+ &savedcert)) |
383 |
+ return 1; |
384 |
+ |
385 |
+ /* interactive check from user */ |
386 |
if (gnutls_x509_crt_init (&cert) < 0) |
387 |
{ |
388 |
@@ -569,5 +682,5 @@ |
389 |
return 0; |
390 |
} |
391 |
- |
392 |
+ |
393 |
if (gnutls_x509_crt_import (cert, certdata, GNUTLS_X509_FMT_DER) < 0) |
394 |
{ |
395 |
@@ -577,82 +690,5 @@ |
396 |
return -1; |
397 |
} |
398 |
- |
399 |
- if (gnutls_x509_crt_get_expiration_time (cert) < time(NULL)) |
400 |
- certerr_expired = 1; |
401 |
- if (gnutls_x509_crt_get_activation_time (cert) > time(NULL)) |
402 |
- certerr_notyetvalid = 1; |
403 |
- |
404 |
- if (!idx) |
405 |
- { |
406 |
- if (!gnutls_x509_crt_check_hostname (cert, hostname) && |
407 |
- !tls_check_stored_hostname (certdata, hostname)) |
408 |
- certerr_hostname = 1; |
409 |
- } |
410 |
- |
411 |
- /* see whether certificate is in our cache (certificates file) */ |
412 |
- if (tls_compare_certificates (certdata)) |
413 |
- { |
414 |
- if (certstat & GNUTLS_CERT_INVALID) |
415 |
- { |
416 |
- /* doesn't matter - have decided is valid because server |
417 |
- certificate is in our trusted cache */ |
418 |
- certstat ^= GNUTLS_CERT_INVALID; |
419 |
- } |
420 |
- |
421 |
- if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND) |
422 |
- { |
423 |
- /* doesn't matter that we haven't found the signer, since |
424 |
- certificate is in our trusted cache */ |
425 |
- certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND; |
426 |
- } |
427 |
- |
428 |
- if (certstat & GNUTLS_CERT_SIGNER_NOT_CA) |
429 |
- { |
430 |
- /* Hmm. Not really sure how to handle this, but let's say |
431 |
- that we don't care if the CA certificate hasn't got the |
432 |
- correct X.509 basic constraints if server certificate is |
433 |
- in our cache. */ |
434 |
- certstat ^= GNUTLS_CERT_SIGNER_NOT_CA; |
435 |
- } |
436 |
- } |
437 |
- |
438 |
- if (certstat & GNUTLS_CERT_REVOKED) |
439 |
- { |
440 |
- certerr_revoked = 1; |
441 |
- certstat ^= GNUTLS_CERT_REVOKED; |
442 |
- } |
443 |
- |
444 |
- if (certstat & GNUTLS_CERT_INVALID) |
445 |
- { |
446 |
- certerr_nottrusted = 1; |
447 |
- certstat ^= GNUTLS_CERT_INVALID; |
448 |
- } |
449 |
- |
450 |
- if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND) |
451 |
- { |
452 |
- /* NB: already cleared if cert in cache */ |
453 |
- certerr_nottrusted = 1; |
454 |
- certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND; |
455 |
- } |
456 |
- |
457 |
- if (certstat & GNUTLS_CERT_SIGNER_NOT_CA) |
458 |
- { |
459 |
- /* NB: already cleared if cert in cache */ |
460 |
- certerr_signernotca = 1; |
461 |
- certstat ^= GNUTLS_CERT_SIGNER_NOT_CA; |
462 |
- } |
463 |
- |
464 |
- /* OK if signed by (or is) a trusted certificate */ |
465 |
- /* we've been zeroing the interesting bits in certstat - |
466 |
- don't return OK if there are any unhandled bits we don't |
467 |
- understand */ |
468 |
- if (!(certerr_expired || certerr_notyetvalid || |
469 |
- certerr_hostname || certerr_nottrusted) && certstat == 0) |
470 |
- { |
471 |
- gnutls_x509_crt_deinit (cert); |
472 |
- return 1; |
473 |
- } |
474 |
- |
475 |
- /* interactive check from user */ |
476 |
+ |
477 |
menu = mutt_new_menu (-1); |
478 |
menu->max = 25; |
479 |
@@ -756,26 +792,26 @@ |
480 |
tls_fingerprint (GNUTLS_DIG_MD5, fpbuf, sizeof (fpbuf), certdata); |
481 |
snprintf (menu->dialog[row++], SHORT_STRING, _("MD5 Fingerprint: %s"), fpbuf); |
482 |
- |
483 |
- if (certerr_notyetvalid) |
484 |
+ |
485 |
+ if (certerr & CERTERR_NOTYETVALID) |
486 |
{ |
487 |
row++; |
488 |
strfcpy (menu->dialog[row], _("WARNING: Server certificate is not yet valid"), SHORT_STRING); |
489 |
} |
490 |
- if (certerr_expired) |
491 |
+ if (certerr & CERTERR_EXPIRED) |
492 |
{ |
493 |
row++; |
494 |
strfcpy (menu->dialog[row], _("WARNING: Server certificate has expired"), SHORT_STRING); |
495 |
} |
496 |
- if (certerr_revoked) |
497 |
+ if (certerr & CERTERR_REVOKED) |
498 |
{ |
499 |
row++; |
500 |
strfcpy (menu->dialog[row], _("WARNING: Server certificate has been revoked"), SHORT_STRING); |
501 |
} |
502 |
- if (certerr_hostname) |
503 |
+ if (certerr & CERTERR_HOSTNAME) |
504 |
{ |
505 |
row++; |
506 |
strfcpy (menu->dialog[row], _("WARNING: Server hostname does not match certificate"), SHORT_STRING); |
507 |
} |
508 |
- if (certerr_signernotca) |
509 |
+ if (certerr & CERTERR_SIGNERNOTCA) |
510 |
{ |
511 |
row++; |
512 |
@@ -789,5 +825,7 @@ |
513 |
/* certificates with bad dates, or that are revoked, must be |
514 |
accepted manually each and every time */ |
515 |
- if (SslCertFile && !certerr_expired && !certerr_notyetvalid && !certerr_revoked) |
516 |
+ if (SslCertFile && !savedcert |
517 |
+ && !(certerr & (CERTERR_EXPIRED | CERTERR_NOTYETVALID |
518 |
+ | CERTERR_REVOKED))) |
519 |
{ |
520 |
menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always"); |
521 |
@@ -823,10 +861,10 @@ |
522 |
{ |
523 |
/* save hostname if necessary */ |
524 |
- if (certerr_hostname) |
525 |
+ if (certerr & CERTERR_HOSTNAME) |
526 |
{ |
527 |
fprintf(fp, "#H %s %s\n", hostname, fpbuf); |
528 |
done = 1; |
529 |
} |
530 |
- if (certerr_nottrusted) |
531 |
+ if (certerr & CERTERR_NOTTRUSTED) |
532 |
{ |
533 |
done = 0; |
534 |
@@ -842,5 +880,5 @@ |
535 |
} |
536 |
} |
537 |
- fclose (fp); |
538 |
+ safe_fclose (&fp); |
539 |
} |
540 |
if (!done) |
541 |
@@ -867,4 +905,38 @@ |
542 |
} |
543 |
|
544 |
+/* sanity-checking wrapper for gnutls_certificate_verify_peers */ |
545 |
+static gnutls_certificate_status tls_verify_peers (gnutls_session tlsstate) |
546 |
+{ |
547 |
+ gnutls_certificate_status certstat; |
548 |
+ |
549 |
+ certstat = gnutls_certificate_verify_peers (tlsstate); |
550 |
+ if (!certstat) |
551 |
+ return certstat; |
552 |
+ |
553 |
+ if (certstat == GNUTLS_E_NO_CERTIFICATE_FOUND) |
554 |
+ { |
555 |
+ mutt_error (_("Unable to get certificate from peer")); |
556 |
+ mutt_sleep (2); |
557 |
+ return 0; |
558 |
+ } |
559 |
+ if (certstat < 0) |
560 |
+ { |
561 |
+ mutt_error (_("Certificate verification error (%s)"), |
562 |
+ gnutls_strerror (certstat)); |
563 |
+ mutt_sleep (2); |
564 |
+ return 0; |
565 |
+ } |
566 |
+ |
567 |
+ /* We only support X.509 certificates (not OpenPGP) at the moment */ |
568 |
+ if (gnutls_certificate_type_get (tlsstate) != GNUTLS_CRT_X509) |
569 |
+ { |
570 |
+ mutt_error (_("Certificate is not X.509")); |
571 |
+ mutt_sleep (2); |
572 |
+ return 0; |
573 |
+ } |
574 |
+ |
575 |
+ return certstat; |
576 |
+} |
577 |
+ |
578 |
static int tls_check_certificate (CONNECTION* conn) |
579 |
{ |
580 |
@@ -874,5 +946,5 @@ |
581 |
unsigned int cert_list_size = 0; |
582 |
gnutls_certificate_status certstat; |
583 |
- int i, rc; |
584 |
+ int certerr, i, preauthrc, savedcert, rc = 0; |
585 |
|
586 |
if (gnutls_auth_get_type (state) != GNUTLS_CRD_CERTIFICATE) |
587 |
@@ -883,27 +955,5 @@ |
588 |
} |
589 |
|
590 |
- certstat = gnutls_certificate_verify_peers (state); |
591 |
- |
592 |
- if (certstat == GNUTLS_E_NO_CERTIFICATE_FOUND) |
593 |
- { |
594 |
- mutt_error (_("Unable to get certificate from peer")); |
595 |
- mutt_sleep (2); |
596 |
- return 0; |
597 |
- } |
598 |
- if (certstat < 0) |
599 |
- { |
600 |
- mutt_error (_("Certificate verification error (%s)"), |
601 |
- gnutls_strerror (certstat)); |
602 |
- mutt_sleep (2); |
603 |
- return 0; |
604 |
- } |
605 |
- |
606 |
- /* We only support X.509 certificates (not OpenPGP) at the moment */ |
607 |
- if (gnutls_certificate_type_get (state) != GNUTLS_CRT_X509) |
608 |
- { |
609 |
- mutt_error (_("Certificate is not X.509")); |
610 |
- mutt_sleep (2); |
611 |
- return 0; |
612 |
- } |
613 |
+ certstat = tls_verify_peers (state); |
614 |
|
615 |
cert_list = gnutls_certificate_get_peers (state, &cert_list_size); |
616 |
@@ -915,12 +965,41 @@ |
617 |
} |
618 |
|
619 |
+ /* tls_verify_peers doesn't check hostname or expiration, so walk |
620 |
+ * from most specific to least checking these. If we see a saved certificate, |
621 |
+ * its status short-circuits the remaining checks. */ |
622 |
+ preauthrc = 0; |
623 |
+ for (i = 0; i < cert_list_size; i++) { |
624 |
+ rc = tls_check_preauth(&cert_list[i], certstat, conn->account.host, i, |
625 |
+ &certerr, &savedcert); |
626 |
+ preauthrc += rc; |
627 |
+ |
628 |
+ if (savedcert) |
629 |
+ { |
630 |
+ if (!preauthrc) |
631 |
+ return 1; |
632 |
+ else |
633 |
+ break; |
634 |
+ } |
635 |
+ } |
636 |
+ |
637 |
+ /* then check interactively, starting from chain root */ |
638 |
for (i = cert_list_size - 1; i >= 0; i--) |
639 |
{ |
640 |
rc = tls_check_one_certificate (&cert_list[i], certstat, conn->account.host, |
641 |
i, cert_list_size); |
642 |
- if (rc) |
643 |
- return rc; |
644 |
- } |
645 |
- |
646 |
- return 0; |
647 |
-} |
648 |
+ |
649 |
+ /* add signers to trust set, then reverify */ |
650 |
+ if (i && rc) { |
651 |
+ rc = gnutls_certificate_set_x509_trust_mem (data->xcred, &cert_list[i], |
652 |
+ GNUTLS_X509_FMT_DER); |
653 |
+ if (rc != 1) |
654 |
+ dprint (1, (debugfile, "error trusting certificate %d: %d\n", i, rc)); |
655 |
+ |
656 |
+ certstat = tls_verify_peers (state); |
657 |
+ if (!certstat) |
658 |
+ return 1; |
659 |
+ } |
660 |
+ } |
661 |
+ |
662 |
+ return rc; |
663 |
+} |