Gentoo Archives: gentoo-commits

From: "Fabian Groffen (grobian)" <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in mail-client/mutt/files: mutt-1.5.19-mutt_ssl-3af7e8af1983-dc9ec900c657.patch mutt-1.5.19-mutt-gnutls-7d0583e0315d-0b13183e40e0.patch
Date: Thu, 18 Jun 2009 09:20:42
Message-Id: E1MHDnR-00075J-AB@stork.gentoo.org
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 +}