~ubuntu-dev/ubuntu/lucid/mutt/lucid-201002110857

« back to all changes in this revision

Viewing changes to mutt_ssl_gnutls.c

  • Committer: Bazaar Package Importer
  • Author(s): أحمد المحمودي (Ahmed El-Mahmoudy)
  • Date: 2009-06-17 17:17:28 UTC
  • mfrom: (1.3.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 22.
  • Revision ID: james.westby@ubuntu.com-20090617171728-61dkl7w5fgn7ybdq
Tags: upstream-1.5.20
Import upstream version 1.5.20

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
#include "mutt_ssl.h"
34
34
#include "mutt_regex.h"
35
35
 
 
36
/* certificate error bitmap values */
 
37
#define CERTERR_VALID       0
 
38
#define CERTERR_EXPIRED     1
 
39
#define CERTERR_NOTYETVALID 2
 
40
#define CERTERR_REVOKED     4
 
41
#define CERTERR_NOTTRUSTED  8
 
42
#define CERTERR_HOSTNAME    16
 
43
#define CERTERR_SIGNERNOTCA 32
 
44
#define CERTERR_INSECUREALG 64
 
45
 
36
46
typedef struct _tlssockdata
37
47
{
38
48
  gnutls_session state;
265
275
                                          SslClientCert, GNUTLS_X509_FMT_PEM);
266
276
  }
267
277
 
 
278
#if HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS
 
279
  /* disable checking certificate activation/expiration times
 
280
     in gnutls, we do the checks ourselves */
 
281
  gnutls_certificate_set_verify_flags(data->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
 
282
#endif
 
283
 
268
284
  gnutls_init(&data->state, GNUTLS_CLIENT);
269
285
 
270
286
  /* set socket */
408
424
  }
409
425
 
410
426
  b64_data.size = fread(b64_data.data, 1, b64_data.size, fd1);
411
 
  fclose(fd1);
 
427
  safe_fclose (&fd1);
412
428
 
413
429
  do {
414
430
    ret = gnutls_pem_base64_decode_alloc(NULL, &b64_data, &cert);
504
520
 
505
521
    buf[0] = '\0';
506
522
    tls_fingerprint (GNUTLS_DIG_MD5, buf, sizeof (buf), cert);
507
 
    while ((linestr = mutt_read_line(linestr, &linestrsize, fp, &linenum)) != NULL)
 
523
    while ((linestr = mutt_read_line(linestr, &linestrsize, fp, &linenum, 0)) != NULL)
508
524
    {
509
525
      if(linestr[0] == '#' && linestr[1] == 'H')
510
526
      {
517
533
          {
518
534
            regfree(&preg);
519
535
            FREE(&linestr);
520
 
            fclose(fp);
 
536
            safe_fclose (&fp);
521
537
            return 1;
522
538
          }
523
539
        }
525
541
    }
526
542
 
527
543
    regfree(&preg);
528
 
    fclose(fp);
 
544
    safe_fclose (&fp);
529
545
  }
530
546
 
531
547
  /* not found a matching name */
532
548
  return 0;
533
549
}
534
550
 
 
551
static int tls_check_preauth (const gnutls_datum_t *certdata,
 
552
                              gnutls_certificate_status certstat,
 
553
                              const char *hostname, int chainidx, int* certerr,
 
554
                              int* savedcert)
 
555
{
 
556
  gnutls_x509_crt cert;
 
557
 
 
558
  *certerr = CERTERR_VALID;
 
559
  *savedcert = 0;
 
560
 
 
561
  if (gnutls_x509_crt_init (&cert) < 0)
 
562
  {
 
563
    mutt_error (_("Error initialising gnutls certificate data"));
 
564
    mutt_sleep (2);
 
565
    return -1;
 
566
  }
 
567
 
 
568
  if (gnutls_x509_crt_import (cert, certdata, GNUTLS_X509_FMT_DER) < 0)
 
569
  {
 
570
    mutt_error (_("Error processing certificate data"));
 
571
    mutt_sleep (2);
 
572
    gnutls_x509_crt_deinit (cert);
 
573
    return -1;
 
574
  }
 
575
 
 
576
  if (option (OPTSSLVERIFYDATES) != M_NO)
 
577
  {
 
578
    if (gnutls_x509_crt_get_expiration_time (cert) < time(NULL))
 
579
      *certerr |= CERTERR_EXPIRED;
 
580
    if (gnutls_x509_crt_get_activation_time (cert) > time(NULL))
 
581
      *certerr |= CERTERR_NOTYETVALID;
 
582
  }
 
583
 
 
584
  if (chainidx == 0 && option (OPTSSLVERIFYHOST) != M_NO
 
585
      && !gnutls_x509_crt_check_hostname (cert, hostname)
 
586
      && !tls_check_stored_hostname (certdata, hostname))
 
587
    *certerr |= CERTERR_HOSTNAME;
 
588
 
 
589
  /* see whether certificate is in our cache (certificates file) */
 
590
  if (tls_compare_certificates (certdata))
 
591
  {
 
592
    *savedcert = 1;
 
593
 
 
594
    if (chainidx == 0 && certstat & GNUTLS_CERT_INVALID)
 
595
    {
 
596
      /* doesn't matter - have decided is valid because server
 
597
       certificate is in our trusted cache */
 
598
      certstat ^= GNUTLS_CERT_INVALID;
 
599
    }
 
600
 
 
601
    if (chainidx == 0 && certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
 
602
    {
 
603
      /* doesn't matter that we haven't found the signer, since
 
604
       certificate is in our trusted cache */
 
605
      certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
 
606
    }
 
607
 
 
608
    if (chainidx <= 1 && certstat & GNUTLS_CERT_SIGNER_NOT_CA)
 
609
    {
 
610
      /* Hmm. Not really sure how to handle this, but let's say
 
611
       that we don't care if the CA certificate hasn't got the
 
612
       correct X.509 basic constraints if server or first signer
 
613
       certificate is in our cache. */
 
614
      certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
 
615
    }
 
616
 
 
617
    if (chainidx == 0 && certstat & GNUTLS_CERT_INSECURE_ALGORITHM)
 
618
    {
 
619
      /* doesn't matter that it was signed using an insecure
 
620
         algorithm, since certificate is in our trusted cache */
 
621
      certstat ^= GNUTLS_CERT_INSECURE_ALGORITHM;
 
622
    }
 
623
  }
 
624
 
 
625
  if (certstat & GNUTLS_CERT_REVOKED)
 
626
  {
 
627
    *certerr |= CERTERR_REVOKED;
 
628
    certstat ^= GNUTLS_CERT_REVOKED;
 
629
  }
 
630
 
 
631
  if (certstat & GNUTLS_CERT_INVALID)
 
632
  {
 
633
    *certerr |= CERTERR_NOTTRUSTED;
 
634
    certstat ^= GNUTLS_CERT_INVALID;
 
635
  }
 
636
 
 
637
  if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
 
638
  {
 
639
    /* NB: already cleared if cert in cache */
 
640
    *certerr |= CERTERR_NOTTRUSTED;
 
641
    certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
 
642
  }
 
643
 
 
644
  if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
 
645
  {
 
646
    /* NB: already cleared if cert in cache */
 
647
    *certerr |= CERTERR_SIGNERNOTCA;
 
648
    certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
 
649
  }
 
650
 
 
651
  if (certstat & GNUTLS_CERT_INSECURE_ALGORITHM)
 
652
  {
 
653
    /* NB: already cleared if cert in cache */
 
654
    *certerr |= CERTERR_INSECUREALG;
 
655
    certstat ^= GNUTLS_CERT_INSECURE_ALGORITHM;
 
656
  }
 
657
 
 
658
  gnutls_x509_crt_deinit (cert);
 
659
 
 
660
  /* we've been zeroing the interesting bits in certstat -
 
661
   don't return OK if there are any unhandled bits we don't
 
662
   understand */
 
663
  if (*certerr == CERTERR_VALID && certstat == 0)
 
664
    return 0;
 
665
 
 
666
  return -1;
 
667
}
 
668
 
535
669
static int tls_check_one_certificate (const gnutls_datum_t *certdata,
536
670
                                      gnutls_certificate_status certstat,
537
671
                                      const char* hostname, int idx, int len)
538
672
{
 
673
  int certerr, savedcert;
539
674
  gnutls_x509_crt cert;
540
 
  int certerr_hostname = 0;
541
 
  int certerr_expired = 0;
542
 
  int certerr_notyetvalid = 0;
543
 
  int certerr_nottrusted = 0;
544
 
  int certerr_revoked = 0;
545
 
  int certerr_signernotca = 0;
546
675
  char buf[SHORT_STRING];
547
676
  char fpbuf[SHORT_STRING];
548
677
  size_t buflen;
562
691
  gnutls_datum pemdata;
563
692
  int i, row, done, ret;
564
693
 
565
 
  if (gnutls_x509_crt_init (&cert) < 0)
566
 
  {
567
 
    mutt_error (_("Error initialising gnutls certificate data"));
568
 
    mutt_sleep (2);
569
 
    return 0;
570
 
  }
571
 
  
572
 
  if (gnutls_x509_crt_import (cert, certdata, GNUTLS_X509_FMT_DER) < 0)
573
 
  {
574
 
    mutt_error (_("Error processing certificate data"));
575
 
    mutt_sleep (2);
576
 
    gnutls_x509_crt_deinit (cert);
577
 
    return -1;
578
 
  }
579
 
  
580
 
  if (gnutls_x509_crt_get_expiration_time (cert) < time(NULL))
581
 
    certerr_expired = 1;
582
 
  if (gnutls_x509_crt_get_activation_time (cert) > time(NULL))
583
 
    certerr_notyetvalid = 1;
584
 
 
585
 
  if (!idx)
586
 
  {
587
 
    if (!gnutls_x509_crt_check_hostname (cert, hostname) &&
588
 
        !tls_check_stored_hostname (certdata, hostname))
589
 
      certerr_hostname = 1;
590
 
  }
591
 
  
592
 
  /* see whether certificate is in our cache (certificates file) */
593
 
  if (tls_compare_certificates (certdata))
594
 
  {
595
 
    if (certstat & GNUTLS_CERT_INVALID)
596
 
    {
597
 
      /* doesn't matter - have decided is valid because server
598
 
       certificate is in our trusted cache */
599
 
      certstat ^= GNUTLS_CERT_INVALID;
600
 
    }
601
 
    
602
 
    if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
603
 
    {
604
 
      /* doesn't matter that we haven't found the signer, since
605
 
       certificate is in our trusted cache */
606
 
      certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
607
 
    }
608
 
    
609
 
    if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
610
 
    {
611
 
      /* Hmm. Not really sure how to handle this, but let's say
612
 
       that we don't care if the CA certificate hasn't got the
613
 
       correct X.509 basic constraints if server certificate is
614
 
       in our cache. */
615
 
      certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
616
 
    }
617
 
  }
618
 
 
619
 
  if (certstat & GNUTLS_CERT_REVOKED)
620
 
  {
621
 
    certerr_revoked = 1;
622
 
    certstat ^= GNUTLS_CERT_REVOKED;
623
 
  }
624
 
  
625
 
  if (certstat & GNUTLS_CERT_INVALID)
626
 
  {
627
 
    certerr_nottrusted = 1;
628
 
    certstat ^= GNUTLS_CERT_INVALID;
629
 
  }
630
 
  
631
 
  if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
632
 
  {
633
 
    /* NB: already cleared if cert in cache */
634
 
    certerr_nottrusted = 1;
635
 
    certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
636
 
  }
637
 
  
638
 
  if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
639
 
  {
640
 
    /* NB: already cleared if cert in cache */
641
 
    certerr_signernotca = 1;
642
 
    certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
643
 
  }
644
 
 
645
 
  /* OK if signed by (or is) a trusted certificate */
646
 
  /* we've been zeroing the interesting bits in certstat - 
647
 
   don't return OK if there are any unhandled bits we don't
648
 
   understand */
649
 
  if (!(certerr_expired || certerr_notyetvalid || 
650
 
        certerr_hostname || certerr_nottrusted) && certstat == 0)
651
 
  {
652
 
    gnutls_x509_crt_deinit (cert);
 
694
  if (!tls_check_preauth (certdata, certstat, hostname, idx, &certerr,
 
695
      &savedcert))
653
696
    return 1;
 
697
 
 
698
  /* skip signers if insecure algorithm was used */
 
699
  if (idx && (certerr & CERTERR_INSECUREALG))
 
700
  {
 
701
    if (idx == 1)
 
702
    {
 
703
      mutt_error (_("Warning: Server certificate was signed using an insecure algorithm"));
 
704
      mutt_sleep (2);
 
705
    }
 
706
    return 0;
654
707
  }
655
708
 
656
709
  /* interactive check from user */
 
710
  if (gnutls_x509_crt_init (&cert) < 0)
 
711
  {
 
712
    mutt_error (_("Error initialising gnutls certificate data"));
 
713
    mutt_sleep (2);
 
714
    return 0;
 
715
  }
 
716
 
 
717
  if (gnutls_x509_crt_import (cert, certdata, GNUTLS_X509_FMT_DER) < 0)
 
718
  {
 
719
    mutt_error (_("Error processing certificate data"));
 
720
    mutt_sleep (2);
 
721
    gnutls_x509_crt_deinit (cert);
 
722
    return -1;
 
723
  }
 
724
 
657
725
  menu = mutt_new_menu (-1);
658
726
  menu->max = 25;
659
727
  menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *));
660
728
  for (i = 0; i < menu->max; i++)
661
729
    menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char));
662
 
  
 
730
 
663
731
  row = 0;
664
732
  strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING);
665
733
  row++;
666
 
  
 
734
 
667
735
  buflen = sizeof (dn_common_name);
668
736
  if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
669
737
                                     dn_common_name, &buflen) != 0)
692
760
  if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0,
693
761
                                     dn_country, &buflen) != 0)
694
762
    dn_country[0] = '\0';
695
 
  
 
763
 
696
764
  snprintf (menu->dialog[row++], SHORT_STRING, "   %s  %s", dn_common_name, dn_email);
697
765
  snprintf (menu->dialog[row++], SHORT_STRING, "   %s", dn_organization);
698
766
  snprintf (menu->dialog[row++], SHORT_STRING, "   %s", dn_organizational_unit);
699
767
  snprintf (menu->dialog[row++], SHORT_STRING, "   %s  %s  %s",
700
768
            dn_locality, dn_province, dn_country);
701
769
  row++;
702
 
  
 
770
 
703
771
  strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING);
704
772
  row++;
705
 
  
 
773
 
706
774
  buflen = sizeof (dn_common_name);
707
775
  if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
708
776
                                            dn_common_name, &buflen) != 0)
731
799
  if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0,
732
800
                                            dn_country, &buflen) != 0)
733
801
    dn_country[0] = '\0';
734
 
  
 
802
 
735
803
  snprintf (menu->dialog[row++], SHORT_STRING, "   %s  %s", dn_common_name, dn_email);
736
804
  snprintf (menu->dialog[row++], SHORT_STRING, "   %s", dn_organization);
737
805
  snprintf (menu->dialog[row++], SHORT_STRING, "   %s", dn_organizational_unit);
738
806
  snprintf (menu->dialog[row++], SHORT_STRING, "   %s  %s  %s",
739
807
            dn_locality, dn_province, dn_country);
740
808
  row++;
741
 
  
 
809
 
742
810
  snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid"));
743
 
  
 
811
 
744
812
  t = gnutls_x509_crt_get_activation_time (cert);
745
 
  snprintf (menu->dialog[row++], SHORT_STRING, _("   from %s"), 
 
813
  snprintf (menu->dialog[row++], SHORT_STRING, _("   from %s"),
746
814
            tls_make_date (t, datestr, 30));
747
 
  
 
815
 
748
816
  t = gnutls_x509_crt_get_expiration_time (cert);
749
 
  snprintf (menu->dialog[row++], SHORT_STRING, _("     to %s"), 
 
817
  snprintf (menu->dialog[row++], SHORT_STRING, _("     to %s"),
750
818
            tls_make_date (t, datestr, 30));
751
 
  
 
819
 
752
820
  fpbuf[0] = '\0';
753
821
  tls_fingerprint (GNUTLS_DIG_SHA, fpbuf, sizeof (fpbuf), certdata);
754
822
  snprintf (menu->dialog[row++], SHORT_STRING, _("SHA1 Fingerprint: %s"), fpbuf);
755
823
  fpbuf[0] = '\0';
756
824
  tls_fingerprint (GNUTLS_DIG_MD5, fpbuf, sizeof (fpbuf), certdata);
757
825
  snprintf (menu->dialog[row++], SHORT_STRING, _("MD5 Fingerprint: %s"), fpbuf);
758
 
  
759
 
  if (certerr_notyetvalid)
 
826
 
 
827
  if (certerr & CERTERR_NOTYETVALID)
760
828
  {
761
829
    row++;
762
830
    strfcpy (menu->dialog[row], _("WARNING: Server certificate is not yet valid"), SHORT_STRING);
763
831
  }
764
 
  if (certerr_expired)
 
832
  if (certerr & CERTERR_EXPIRED)
765
833
  {
766
834
    row++;
767
835
    strfcpy (menu->dialog[row], _("WARNING: Server certificate has expired"), SHORT_STRING);
768
836
  }
769
 
  if (certerr_revoked)
 
837
  if (certerr & CERTERR_REVOKED)
770
838
  {
771
839
    row++;
772
840
    strfcpy (menu->dialog[row], _("WARNING: Server certificate has been revoked"), SHORT_STRING);
773
841
  }
774
 
  if (certerr_hostname)
 
842
  if (certerr & CERTERR_HOSTNAME)
775
843
  {
776
844
    row++;
777
845
    strfcpy (menu->dialog[row], _("WARNING: Server hostname does not match certificate"), SHORT_STRING);
778
846
  }
779
 
  if (certerr_signernotca)
 
847
  if (certerr & CERTERR_SIGNERNOTCA)
780
848
  {
781
849
    row++;
782
850
    strfcpy (menu->dialog[row], _("WARNING: Signer of server certificate is not a CA"), SHORT_STRING);
788
856
  menu->title = title;
789
857
  /* certificates with bad dates, or that are revoked, must be
790
858
   accepted manually each and every time */
791
 
  if (SslCertFile && !certerr_expired && !certerr_notyetvalid && !certerr_revoked)
 
859
  if (SslCertFile && !savedcert
 
860
        && !(certerr & (CERTERR_EXPIRED | CERTERR_NOTYETVALID
 
861
                        | CERTERR_REVOKED)))
792
862
  {
793
863
    menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always");
794
864
    menu->keys = _("roa");
798
868
    menu->prompt = _("(r)eject, accept (o)nce");
799
869
    menu->keys = _("ro");
800
870
  }
801
 
  
 
871
 
802
872
  helpstr[0] = '\0';
803
873
  mutt_make_help (buf, sizeof (buf), _("Exit  "), MENU_GENERIC, OP_EXIT);
804
874
  safe_strcat (helpstr, sizeof (helpstr), buf);
805
875
  mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP);
806
876
  safe_strcat (helpstr, sizeof (helpstr), buf);
807
877
  menu->help = helpstr;
808
 
  
 
878
 
809
879
  done = 0;
810
880
  set_option (OPTUNBUFFEREDINPUT);
811
881
  while (!done)
822
892
        if ((fp = fopen (SslCertFile, "a")))
823
893
        {
824
894
          /* save hostname if necessary */
825
 
          if (certerr_hostname)
 
895
          if (certerr & CERTERR_HOSTNAME)
826
896
          {
827
897
            fprintf(fp, "#H %s %s\n", hostname, fpbuf);
828
898
            done = 1;
829
899
          }
830
 
          if (certerr_nottrusted)
 
900
          if (certerr & CERTERR_NOTTRUSTED)
831
901
          {
832
902
            done = 0;
833
903
            ret = gnutls_pem_base64_encode_alloc ("CERTIFICATE", certdata,
841
911
              gnutls_free (pemdata.data);
842
912
            }
843
913
          }
844
 
          fclose (fp);
 
914
          safe_fclose (&fp);
845
915
        }
846
916
        if (!done)
847
917
        {
866
936
  return (done == 2);
867
937
}
868
938
 
869
 
static int tls_check_certificate (CONNECTION* conn)
 
939
/* sanity-checking wrapper for gnutls_certificate_verify_peers */
 
940
static gnutls_certificate_status tls_verify_peers (gnutls_session tlsstate)
870
941
{
871
 
  tlssockdata *data = conn->sockdata;
872
 
  gnutls_session state = data->state;
873
 
  const gnutls_datum *cert_list;
874
 
  unsigned int cert_list_size = 0;
875
942
  gnutls_certificate_status certstat;
876
 
  int i, rc;
877
 
 
878
 
  if (gnutls_auth_get_type (state) != GNUTLS_CRD_CERTIFICATE)
879
 
  {
880
 
    mutt_error (_("Unable to get certificate from peer"));
881
 
    mutt_sleep (2);
882
 
    return 0;
883
 
  }
884
 
 
885
 
  certstat = gnutls_certificate_verify_peers (state);
 
943
 
 
944
  certstat = gnutls_certificate_verify_peers (tlsstate);
 
945
  if (!certstat)
 
946
    return certstat;
886
947
 
887
948
  if (certstat == GNUTLS_E_NO_CERTIFICATE_FOUND)
888
949
  {
899
960
  }
900
961
 
901
962
  /* We only support X.509 certificates (not OpenPGP) at the moment */
902
 
  if (gnutls_certificate_type_get (state) != GNUTLS_CRT_X509)
 
963
  if (gnutls_certificate_type_get (tlsstate) != GNUTLS_CRT_X509)
903
964
  {
904
965
    mutt_error (_("Certificate is not X.509"));
905
966
    mutt_sleep (2);
906
967
    return 0;
907
968
  }
908
969
 
 
970
  return certstat;
 
971
}
 
972
 
 
973
static int tls_check_certificate (CONNECTION* conn)
 
974
{
 
975
  tlssockdata *data = conn->sockdata;
 
976
  gnutls_session state = data->state;
 
977
  const gnutls_datum *cert_list;
 
978
  unsigned int cert_list_size = 0;
 
979
  gnutls_certificate_status certstat;
 
980
  int certerr, i, preauthrc, savedcert, rc = 0;
 
981
 
 
982
  if (gnutls_auth_get_type (state) != GNUTLS_CRD_CERTIFICATE)
 
983
  {
 
984
    mutt_error (_("Unable to get certificate from peer"));
 
985
    mutt_sleep (2);
 
986
    return 0;
 
987
  }
 
988
 
 
989
  certstat = tls_verify_peers (state);
 
990
 
909
991
  cert_list = gnutls_certificate_get_peers (state, &cert_list_size);
910
992
  if (!cert_list)
911
993
  {
914
996
    return 0;
915
997
  }
916
998
 
 
999
  /* tls_verify_peers doesn't check hostname or expiration, so walk
 
1000
   * from most specific to least checking these. If we see a saved certificate,
 
1001
   * its status short-circuits the remaining checks. */
 
1002
  preauthrc = 0;
 
1003
  for (i = 0; i < cert_list_size; i++) {
 
1004
    rc = tls_check_preauth(&cert_list[i], certstat, conn->account.host, i,
 
1005
                           &certerr, &savedcert);
 
1006
    preauthrc += rc;
 
1007
 
 
1008
    if (savedcert)
 
1009
    {
 
1010
      if (!preauthrc)
 
1011
        return 1;
 
1012
      else
 
1013
        break;
 
1014
    }
 
1015
  }
 
1016
 
 
1017
  /* then check interactively, starting from chain root */
917
1018
  for (i = cert_list_size - 1; i >= 0; i--)
918
1019
  {
919
1020
    rc = tls_check_one_certificate (&cert_list[i], certstat, conn->account.host,
920
1021
                                    i, cert_list_size);
921
 
    if (rc)
922
 
      return rc;
 
1022
 
 
1023
    /* add signers to trust set, then reverify */
 
1024
    if (i && rc) {
 
1025
      rc = gnutls_certificate_set_x509_trust_mem (data->xcred, &cert_list[i],
 
1026
                                                  GNUTLS_X509_FMT_DER);
 
1027
      if (rc != 1)
 
1028
        dprint (1, (debugfile, "error trusting certificate %d: %d\n", i, rc));
 
1029
 
 
1030
      certstat = tls_verify_peers (state);
 
1031
      if (!certstat)
 
1032
        return 1;
 
1033
    }
923
1034
  }
924
1035
 
925
 
  return 0;
 
1036
  return rc;
926
1037
}