int buflen;
size_t buflen;
static int tls_check_certificate (CONNECTION* conn){  tlssockdata *data = conn->sockdata;  gnutls_session state = data->state;  char helpstr[SHORT_STRING];  char buf[SHORT_STRING];  char fpbuf[SHORT_STRING];  int buflen;  char dn_common_name[SHORT_STRING];  char dn_email[SHORT_STRING];  char dn_organization[SHORT_STRING];  char dn_organizational_unit[SHORT_STRING];  char dn_locality[SHORT_STRING];  char dn_province[SHORT_STRING];  char dn_country[SHORT_STRING];  MUTTMENU *menu;  int done, row, i, ret;  FILE *fp;  gnutls_x509_dn dn;  time_t t;  const gnutls_datum *cert_list;  int cert_list_size = 0;  gnutls_certificate_status certstat;  char datestr[30];  gnutls_x509_crt cert;  gnutls_datum pemdata;  int certerr_expired = 0;  int certerr_notyetvalid = 0;  int certerr_hostname = 0;  int certerr_nottrusted = 0;  int certerr_revoked = 0;  int certerr_signernotca = 0;  if (gnutls_auth_get_type(state) != GNUTLS_CRD_CERTIFICATE)  {    mutt_error (_("Unable to get certificate from peer"));    mutt_sleep (2);    return 0;  }  certstat = gnutls_certificate_verify_peers(state);  if (certstat == GNUTLS_E_NO_CERTIFICATE_FOUND)  {    mutt_error (_("Unable to get certificate from peer"));    mutt_sleep (2);    return 0;  }  if (certstat < 0)  {    mutt_error (_("Certificate verification error (%s)"), gnutls_strerror(certstat));    mutt_sleep (2);    return 0;  }  /* We only support X.509 certificates (not OpenPGP) at the moment */  if (gnutls_certificate_type_get(state) != GNUTLS_CRT_X509)  {    mutt_error (_("Error certificate is not X.509"));    mutt_sleep (2);    return 0;  }  if (gnutls_x509_crt_init(&cert) < 0)  {    mutt_error (_("Error initialising gnutls certificate data"));    mutt_sleep (2);    return 0;  }  cert_list = gnutls_certificate_get_peers(state, &cert_list_size);  if (!cert_list)  {    mutt_error (_("Unable to get certificate from peer"));    mutt_sleep (2);    return 0;  }  /* FIXME: Currently only check first certificate in chain. */  if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)  {    mutt_error (_("Error processing certificate data"));    mutt_sleep (2);    return 0;  }  if (gnutls_x509_crt_get_expiration_time(cert) < time(NULL))  {    certerr_expired = 1;  }  if (gnutls_x509_crt_get_activation_time(cert) > time(NULL))  {    certerr_notyetvalid = 1;  }  if (!gnutls_x509_crt_check_hostname(cert, conn->account.host) &&      !tls_check_stored_hostname (&cert_list[0], conn->account.host))  {    certerr_hostname = 1;  }  /* see whether certificate is in our cache (certificates file) */  if (tls_compare_certificates (&cert_list[0]))  {    if (certstat & GNUTLS_CERT_INVALID)    {      /* doesn't matter - have decided is valid because server         certificate is in our trusted cache */      certstat ^= GNUTLS_CERT_INVALID;    }    if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)    {      /* doesn't matter that we haven't found the signer, since         certificate is in our trusted cache */      certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;    }    if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)    {      /* Hmm. Not really sure how to handle this, but let's say         that we don't care if the CA certificate hasn't got the         correct X.509 basic constraints if server certificate is         in our cache. */      certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;    }  }  if (certstat & GNUTLS_CERT_REVOKED)  {    certerr_revoked = 1;    certstat ^= GNUTLS_CERT_REVOKED;  }  if (certstat & GNUTLS_CERT_INVALID)  {    certerr_nottrusted = 1;    certstat ^= GNUTLS_CERT_INVALID;  }  if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)  {    /* NB: already cleared if cert in cache */    certerr_nottrusted = 1;    certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;  }  if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)  {    /* NB: already cleared if cert in cache */    certerr_signernotca = 1;    certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;  }  /* OK if signed by (or is) a trusted certificate */  /* we've been zeroing the interesting bits in certstat -      don't return OK if there are any unhandled bits we don't     understand */  if (!(certerr_expired || certerr_notyetvalid || 	certerr_hostname || certerr_nottrusted) && certstat == 0)  {    gnutls_x509_crt_deinit(cert);    return 1;  }  /* interactive check from user */  menu = mutt_new_menu ();  menu->max = 25;  menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *));  for (i = 0; i < menu->max; i++)    menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char));  row = 0;  strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING);  row++;  buflen = sizeof(dn_common_name);  if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,                                    dn_common_name, &buflen) != 0)    dn_common_name[0] = '\0';  buflen = sizeof(dn_email);  if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0,                                    dn_email, &buflen) != 0)    dn_email[0] = '\0';  buflen = sizeof(dn_organization);  if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0,                                    dn_organization, &buflen) != 0)    dn_organization[0] = '\0';  buflen = sizeof(dn_organizational_unit);  if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0,                                    dn_organizational_unit, &buflen) != 0)    dn_organizational_unit[0] = '\0';  buflen = sizeof(dn_locality);  if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0,                                    dn_locality, &buflen) != 0)    dn_locality[0] = '\0';  buflen = sizeof(dn_province);  if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0,                                    dn_province, &buflen) != 0)    dn_province[0] = '\0';  buflen = sizeof(dn_country);  if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0,                                    dn_country, &buflen) != 0)    dn_country[0] = '\0';  snprintf (menu->dialog[row++], SHORT_STRING, "   %s  %s", dn_common_name, dn_email);  snprintf (menu->dialog[row++], SHORT_STRING, "   %s", dn_organization);  snprintf (menu->dialog[row++], SHORT_STRING, "   %s", dn_organizational_unit);  snprintf (menu->dialog[row++], SHORT_STRING, "   %s  %s  %s",            dn_locality, dn_province, dn_country);  row++;    strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING);  row++;  buflen = sizeof(dn_common_name);  if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,                                    dn_common_name, &buflen) != 0)    dn_common_name[0] = '\0';  buflen = sizeof(dn_email);  if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0,                                    dn_email, &buflen) != 0)    dn_email[0] = '\0';  buflen = sizeof(dn_organization);  if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0,                                    dn_organization, &buflen) != 0)    dn_organization[0] = '\0';  buflen = sizeof(dn_organizational_unit);  if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0,                                    dn_organizational_unit, &buflen) != 0)    dn_organizational_unit[0] = '\0';  buflen = sizeof(dn_locality);  if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0,                                    dn_locality, &buflen) != 0)    dn_locality[0] = '\0';  buflen = sizeof(dn_province);  if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0,                                    dn_province, &buflen) != 0)    dn_province[0] = '\0';  buflen = sizeof(dn_country);  if (gnutls_x509_crt_get_issuer_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0,                                    dn_country, &buflen) != 0)    dn_country[0] = '\0';  snprintf (menu->dialog[row++], SHORT_STRING, "   %s  %s", dn_common_name, dn_email);  snprintf (menu->dialog[row++], SHORT_STRING, "   %s", dn_organization);  snprintf (menu->dialog[row++], SHORT_STRING, "   %s", dn_organizational_unit);  snprintf (menu->dialog[row++], SHORT_STRING, "   %s  %s  %s",            dn_locality, dn_province, dn_country);  row++;  snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid"));  t = gnutls_x509_crt_get_activation_time(cert);  snprintf (menu->dialog[row++], SHORT_STRING, _("   from %s"), 	    tls_make_date(t, datestr, 30));  t = gnutls_x509_crt_get_expiration_time(cert);  snprintf (menu->dialog[row++], SHORT_STRING, _("     to %s"), 	    tls_make_date(t, datestr, 30));  fpbuf[0] = '\0';  tls_fingerprint (GNUTLS_DIG_SHA, fpbuf, sizeof (fpbuf), &cert_list[0]);  snprintf (menu->dialog[row++], SHORT_STRING, _("SHA1 Fingerprint: %s"), fpbuf);  fpbuf[0] = '\0';  tls_fingerprint (GNUTLS_DIG_MD5, fpbuf, sizeof (fpbuf), &cert_list[0]);  snprintf (menu->dialog[row++], SHORT_STRING, _("MD5 Fingerprint: %s"), fpbuf);  if (certerr_notyetvalid)  {    row++;    strfcpy (menu->dialog[row], _("WARNING: Server certificate is not yet valid"), SHORT_STRING);  }  if (certerr_expired)  {    row++;    strfcpy (menu->dialog[row], _("WARNING: Server certificate has expired"), SHORT_STRING);  }  if (certerr_revoked)  {    row++;    strfcpy (menu->dialog[row], _("WARNING: Server certificate has been revoked"), SHORT_STRING);  }  if (certerr_hostname)  {    row++;    strfcpy (menu->dialog[row], _("WARNING: Server hostname does not match certificate"), SHORT_STRING);  }  if (certerr_signernotca)  {    row++;    strfcpy (menu->dialog[row], _("WARNING: Signer of server certificate is not a CA"), SHORT_STRING);  }  menu->title = _("TLS/SSL Certificate check");  /* certificates with bad dates, or that are revoked, must be     accepted manually each and every time */  if (SslCertFile && !certerr_expired && !certerr_notyetvalid && !certerr_revoked)  {    menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always");    menu->keys = _("roa");  }  else  {    menu->prompt = _("(r)eject, accept (o)nce");    menu->keys = _("ro");  }    helpstr[0] = '\0';  mutt_make_help (buf, sizeof (buf), _("Exit  "), MENU_GENERIC, OP_EXIT);  safe_strcat (helpstr, sizeof (helpstr), buf);  mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP);  safe_strcat (helpstr, sizeof (helpstr), buf);  menu->help = helpstr;  done = 0;  while (!done)  {    switch (mutt_menuLoop (menu))    {      case -1:			/* abort */      case OP_MAX + 1:		/* reject */      case OP_EXIT:        done = 1;        break;      case OP_MAX + 3:		/* accept always */        done = 0;        if ((fp = fopen (SslCertFile, "a")))	{	  /* save hostname if necessary */	  if (certerr_hostname)	  {	    fprintf(fp, "#H %s %s\n", conn->account.host, fpbuf);	    done = 1;	  }	  if (certerr_nottrusted)	  {            done = 0;	    ret = gnutls_pem_base64_encode_alloc ("CERTIFICATE", &cert_list[0],                                                  &pemdata);	    if (ret == 0)	    {	      if (fwrite(pemdata.data, pemdata.size, 1, fp) == 1)	      {		done = 1;	      }              gnutls_free(pemdata.data);	    }	  }	  fclose (fp);	}	if (!done)        {	  mutt_error (_("Warning: Couldn't save certificate"));	  mutt_sleep (2);	}	else        {	  mutt_message (_("Certificate saved"));	  mutt_sleep (0);	}        /* fall through */      case OP_MAX + 2:		/* accept once */        done = 2;        break;    }  }  mutt_menuDestroy (&menu);  gnutls_x509_crt_deinit(cert);  return (done == 2);}