Example #1
0
static int interactive_check_cert (X509 *cert, int idx, int len)
{
        static const char * const part[] =
                {"/CN=", "/Email=", "/O=", "/OU=", "/L=", "/ST=", "/C="};
        char helpstr[LONG_STRING];
        char buf[STRING];
        char title[STRING];
        MUTTMENU *menu = mutt_new_menu (-1);
        int done, row, i;
        FILE *fp;
        char *name = NULL, *c;

        dprint (2, (debugfile, "interactive_check_cert: %s\n", cert->name));

        menu->max = 19;
        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++;
        name = X509_NAME_oneline (X509_get_subject_name (cert),
                buf, sizeof (buf));
        dprint (2, (debugfile, "oneline: %s\n", name));

        for (i = 0; i < 5; i++) {
                c = x509_get_part (name, part[i]);
                snprintf (menu->dialog[row++], SHORT_STRING, "   %s", c);
        }

        row++;
        strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING);
        row++;
        name = X509_NAME_oneline (X509_get_issuer_name (cert),
                buf, sizeof (buf));
        for (i = 0; i < 5; i++) {
                c = x509_get_part (name, part[i]);
                snprintf (menu->dialog[row++], SHORT_STRING, "   %s", c);
        }

        row++;
        snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid"));
        snprintf (menu->dialog[row++], SHORT_STRING, _("   from %s"),
                asn1time_to_string (X509_get_notBefore (cert)));
        snprintf (menu->dialog[row++], SHORT_STRING, _("     to %s"),
                asn1time_to_string (X509_get_notAfter (cert)));

        row++;
        buf[0] = '\0';
        x509_fingerprint (buf, sizeof (buf), cert);
        snprintf (menu->dialog[row++], SHORT_STRING, _("Fingerprint: %s"), buf);

        snprintf (title, sizeof (title),
                _("SSL Certificate check (certificate %d of %d in chain)"),
                len - idx, len);
        menu->title = title;
        if (SslCertFile
                && (option (OPTSSLVERIFYDATES) == M_NO
                || (X509_cmp_current_time (X509_get_notAfter (cert)) >= 0
        && X509_cmp_current_time (X509_get_notBefore (cert)) < 0))) {
                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;
        set_option(OPTUNBUFFEREDINPUT);
        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"))) {
                                        if (PEM_write_X509 (fp, cert))
                                                done = 1;
                                        safe_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;
                                ssl_cache_trusted_cert (cert);
                                break;
                }
        }
        unset_option(OPTUNBUFFEREDINPUT);
        mutt_menuDestroy (&menu);
        dprint (2, (debugfile, "ssl interactive_check_cert: done=%d\n", done));
        return (done == 2);
}
Example #2
0
File: ssl.c Project: darnir/neomutt
/**
 * interactive_check_cert - Ask the user if a certificate is valid
 * @param cert         Certificate
 * @param idx          Place of certificate in the chain
 * @param len          Length of the certificate chain
 * @param ssl          SSL state
 * @param allow_always If certificate may be always allowed
 * @retval true  User selected 'skip'
 * @retval false Otherwise
 */
static bool interactive_check_cert(X509 *cert, int idx, size_t len, SSL *ssl, bool allow_always)
{
  static const int part[] = {
    NID_commonName,             /* CN */
    NID_pkcs9_emailAddress,     /* Email */
    NID_organizationName,       /* O */
    NID_organizationalUnitName, /* OU */
    NID_localityName,           /* L */
    NID_stateOrProvinceName,    /* ST */
    NID_countryName,            /* C */
  };
  X509_NAME *x509_subject = NULL;
  X509_NAME *x509_issuer = NULL;
  char helpstr[1024];
  char buf[256];
  char title[256];
  struct Menu *menu = mutt_menu_new(MENU_GENERIC);
  int done, row;
  FILE *fp = NULL;
  int ALLOW_SKIP = 0; /* All caps tells Coverity that this is effectively a preproc condition */

  mutt_menu_push_current(menu);

  menu->max = mutt_array_size(part) * 2 + 11;
  menu->dialog = mutt_mem_calloc(1, menu->max * sizeof(char *));
  for (int i = 0; i < menu->max; i++)
    menu->dialog[i] = mutt_mem_calloc(1, dialog_row_len * sizeof(char));

  row = 0;
  mutt_str_strfcpy(menu->dialog[row], _("This certificate belongs to:"), dialog_row_len);
  row++;
  x509_subject = X509_get_subject_name(cert);
  for (unsigned int u = 0; u < mutt_array_size(part); u++)
  {
    snprintf(menu->dialog[row++], dialog_row_len, "   %s",
             x509_get_part(x509_subject, part[u]));
  }

  row++;
  mutt_str_strfcpy(menu->dialog[row], _("This certificate was issued by:"), dialog_row_len);
  row++;
  x509_issuer = X509_get_issuer_name(cert);
  for (unsigned int u = 0; u < mutt_array_size(part); u++)
  {
    snprintf(menu->dialog[row++], dialog_row_len, "   %s",
             x509_get_part(x509_issuer, part[u]));
  }

  row++;
  snprintf(menu->dialog[row++], dialog_row_len, "%s", _("This certificate is valid"));
  snprintf(menu->dialog[row++], dialog_row_len, _("   from %s"),
           asn1time_to_string(X509_getm_notBefore(cert)));
  snprintf(menu->dialog[row++], dialog_row_len, _("     to %s"),
           asn1time_to_string(X509_getm_notAfter(cert)));

  row++;
  buf[0] = '\0';
  x509_fingerprint(buf, sizeof(buf), cert, EVP_sha1);
  snprintf(menu->dialog[row++], dialog_row_len, _("SHA1 Fingerprint: %s"), buf);
  buf[0] = '\0';
  buf[40] = '\0'; /* Ensure the second printed line is null terminated */
  x509_fingerprint(buf, sizeof(buf), cert, EVP_sha256);
  buf[39] = '\0'; /* Divide into two lines of output */
  snprintf(menu->dialog[row++], dialog_row_len, "%s%s", _("SHA256 Fingerprint: "), buf);
  snprintf(menu->dialog[row++], dialog_row_len, "%*s%s",
           (int) mutt_str_strlen(_("SHA256 Fingerprint: ")), "", buf + 40);

  snprintf(title, sizeof(title),
           _("SSL Certificate check (certificate %zu of %zu in chain)"), len - idx, len);
  menu->title = title;

/* The leaf/host certificate can't be skipped. */
#ifdef HAVE_SSL_PARTIAL_CHAIN
  if ((idx != 0) && C_SslVerifyPartialChains)
    ALLOW_SKIP = 1;
#endif

  /* Inside ssl_verify_callback(), this function is guarded by a call to
   * check_certificate_by_digest().  This means if check_certificate_expiration() is
   * true, then check_certificate_file() must be false.  Therefore we don't need
   * to also scan the certificate file here.  */
  allow_always = allow_always && C_CertificateFile &&
                 check_certificate_expiration(cert, true);

  /* L10N: These four letters correspond to the choices in the next four strings:
     (r)eject, accept (o)nce, (a)ccept always, (s)kip.
     These prompts are the interactive certificate confirmation prompts for
     an OpenSSL connection. */
  menu->keys = _("roas");
  if (allow_always)
  {
    if (ALLOW_SKIP)
      menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always, (s)kip");
    else
      menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always");
  }
  else
  {
    if (ALLOW_SKIP)
      menu->prompt = _("(r)eject, accept (o)nce, (s)kip");
    else
      menu->prompt = _("(r)eject, accept (o)nce");
  }

  helpstr[0] = '\0';
  mutt_make_help(buf, sizeof(buf), _("Exit  "), MENU_GENERIC, OP_EXIT);
  mutt_str_strcat(helpstr, sizeof(helpstr), buf);
  mutt_make_help(buf, sizeof(buf), _("Help"), MENU_GENERIC, OP_HELP);
  mutt_str_strcat(helpstr, sizeof(helpstr), buf);
  menu->help = helpstr;

  done = 0;
  OptIgnoreMacroEvents = true;
  while (done == 0)
  {
    switch (mutt_menu_loop(menu))
    {
      case -1:         /* abort */
      case OP_MAX + 1: /* reject */
      case OP_EXIT:
        done = 1;
        break;
      case OP_MAX + 3: /* accept always */
        if (!allow_always)
          break;
        done = 0;
        fp = fopen(C_CertificateFile, "a");
        if (fp)
        {
          if (PEM_write_X509(fp, cert))
            done = 1;
          mutt_file_fclose(&fp);
        }
        if (done == 0)
        {
          mutt_error(_("Warning: Couldn't save certificate"));
        }
        else
        {
          mutt_message(_("Certificate saved"));
          mutt_sleep(0);
        }
      /* fallthrough */
      case OP_MAX + 2: /* accept once */
        done = 2;
        SSL_set_ex_data(ssl, SkipModeExDataIndex, NULL);
        ssl_cache_trusted_cert(cert);
        break;
      case OP_MAX + 4: /* skip */
        if (!ALLOW_SKIP)
          break;
        done = 2;
        SSL_set_ex_data(ssl, SkipModeExDataIndex, &SkipModeExDataIndex);
        break;
    }
  }
  OptIgnoreMacroEvents = false;
  mutt_menu_pop_current(menu);
  mutt_menu_destroy(&menu);
  mutt_debug(LL_DEBUG2, "done=%d\n", done);
  return done == 2;
}