static int cert_callback(gnutls_session_t session) { const gnutls_datum_t *cert_list; unsigned int cert_list_size = 0; int ret; unsigned i; gnutls_datum_t t; struct priv_st *priv; cert_list = gnutls_certificate_get_peers(session, &cert_list_size); if (cert_list_size == 0) { fprintf(stderr, "no certificates sent by server!\n"); return -1; } priv = gnutls_session_get_ptr(session); for (i=0;i<cert_list_size;i++) { ret = gnutls_pem_base64_encode_alloc("CERTIFICATE", &cert_list[i], &t); if (ret < 0) { fprintf(stderr, "error[%d]: %s\n", __LINE__, gnutls_strerror(ret)); exit(1); } write(priv->fd, t.data, t.size); gnutls_free(t.data); } priv->found = 1; return -1; }
static int tls_check_one_certificate (const gnutls_datum_t *certdata, gnutls_certificate_status certstat, const char* hostname, int idx, int len) { int certerr, savedcert; gnutls_x509_crt cert; char buf[SHORT_STRING]; char fpbuf[SHORT_STRING]; size_t 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]; time_t t; char datestr[30]; MUTTMENU *menu; char helpstr[LONG_STRING]; char title[STRING]; FILE *fp; gnutls_datum pemdata; int i, row, done, ret; if (!tls_check_preauth (certdata, certstat, hostname, idx, &certerr, &savedcert)) return 1; /* skip signers if insecure algorithm was used */ if (idx && (certerr & CERTERR_INSECUREALG)) { if (idx == 1) { mutt_error (_("Warning: Server certificate was signed using an insecure algorithm")); mutt_sleep (2); } return 0; } /* interactive check from user */ if (gnutls_x509_crt_init (&cert) < 0) { mutt_error (_("Error initialising gnutls certificate data")); mutt_sleep (2); return 0; } if (gnutls_x509_crt_import (cert, certdata, GNUTLS_X509_FMT_DER) < 0) { mutt_error (_("Error processing certificate data")); mutt_sleep (2); gnutls_x509_crt_deinit (cert); return -1; } menu = mutt_new_menu (-1); 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), certdata); snprintf (menu->dialog[row++], SHORT_STRING, _("SHA1 Fingerprint: %s"), fpbuf); fpbuf[0] = '\0'; tls_fingerprint (GNUTLS_DIG_MD5, fpbuf, sizeof (fpbuf), certdata); snprintf (menu->dialog[row++], SHORT_STRING, _("MD5 Fingerprint: %s"), fpbuf); if (certerr & CERTERR_NOTYETVALID) { row++; strfcpy (menu->dialog[row], _("WARNING: Server certificate is not yet valid"), SHORT_STRING); } if (certerr & CERTERR_EXPIRED) { row++; strfcpy (menu->dialog[row], _("WARNING: Server certificate has expired"), SHORT_STRING); } if (certerr & CERTERR_REVOKED) { row++; strfcpy (menu->dialog[row], _("WARNING: Server certificate has been revoked"), SHORT_STRING); } if (certerr & CERTERR_HOSTNAME) { row++; strfcpy (menu->dialog[row], _("WARNING: Server hostname does not match certificate"), SHORT_STRING); } if (certerr & CERTERR_SIGNERNOTCA) { row++; strfcpy (menu->dialog[row], _("WARNING: Signer of server certificate is not a CA"), SHORT_STRING); } snprintf (title, sizeof (title), _("SSL Certificate check (certificate %d of %d in chain)"), len - idx, len); menu->title = title; /* certificates with bad dates, or that are revoked, must be accepted manually each and every time */ if (SslCertFile && !savedcert && !(certerr & (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; 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"))) { /* save hostname if necessary */ if (certerr & CERTERR_HOSTNAME) { fprintf(fp, "#H %s %s\n", hostname, fpbuf); done = 1; } if (certerr & CERTERR_NOTTRUSTED) { done = 0; ret = gnutls_pem_base64_encode_alloc ("CERTIFICATE", certdata, &pemdata); if (ret == 0) { if (fwrite (pemdata.data, pemdata.size, 1, fp) == 1) { done = 1; } gnutls_free (pemdata.data); } } 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; break; } } unset_option (OPTUNBUFFEREDINPUT); mutt_menuDestroy (&menu); gnutls_x509_crt_deinit (cert); return (done == 2); }
void pkcs11_export (FILE * outfile, const char *url, unsigned int login, common_info_st * info) { gnutls_pkcs11_obj_t crt; gnutls_x509_crt_t xcrt; gnutls_pubkey_t pubkey; int ret; size_t size; unsigned int obj_flags = 0; if (login) obj_flags = GNUTLS_PKCS11_OBJ_FLAG_LOGIN; pkcs11_common (); if (url == NULL) url = "pkcs11:"; ret = gnutls_pkcs11_obj_init (&crt); if (ret < 0) { fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror (ret)); exit (1); } ret = gnutls_pkcs11_obj_import_url (crt, url, obj_flags); if (ret < 0) { fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror (ret)); exit (1); } switch (gnutls_pkcs11_obj_get_type (crt)) { case GNUTLS_PKCS11_OBJ_X509_CRT: ret = gnutls_x509_crt_init (&xcrt); if (ret < 0) { fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror (ret)); exit (1); } ret = gnutls_x509_crt_import_pkcs11 (xcrt, crt); if (ret < 0) { fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror (ret)); exit (1); } size = buffer_size; ret = gnutls_x509_crt_export (xcrt, GNUTLS_X509_FMT_PEM, buffer, &size); if (ret < 0) { fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror (ret)); exit (1); } fwrite (buffer, 1, size, outfile); gnutls_x509_crt_deinit (xcrt); break; case GNUTLS_PKCS11_OBJ_PUBKEY: ret = gnutls_pubkey_init (&pubkey); if (ret < 0) { fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror (ret)); exit (1); } ret = gnutls_pubkey_import_pkcs11 (pubkey, crt, 0); if (ret < 0) { fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror (ret)); exit (1); } size = buffer_size; ret = gnutls_pubkey_export (pubkey, GNUTLS_X509_FMT_PEM, buffer, &size); if (ret < 0) { fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror (ret)); exit (1); } fwrite (buffer, 1, size, outfile); gnutls_pubkey_deinit (pubkey); break; default: { gnutls_datum_t data, enc; size = buffer_size; ret = gnutls_pkcs11_obj_export (crt, buffer, &size); if (ret < 0) { break; } data.data = buffer; data.size = size; ret = gnutls_pem_base64_encode_alloc ("DATA", &data, &enc); if (ret < 0) { fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror (ret)); exit (1); } fwrite (enc.data, 1, enc.size, outfile); gnutls_free (enc.data); break; } } fputs ("\n\n", outfile); gnutls_pkcs11_obj_deinit (crt); return; }
/** * gnutls_pkcs7_crt_print: * @pkcs7: The PKCS7 struct to be printed * @format: Indicate the format to use * @out: Newly allocated datum with null terminated string. * * This function will pretty print a signed PKCS #7 structure, suitable for * display to a human. * * Currently the supported formats are %GNUTLS_CRT_PRINT_FULL and * %GNUTLS_CRT_PRINT_COMPACT. * * The output @out needs to be deallocated using gnutls_free(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs7_print(gnutls_pkcs7_t pkcs7, gnutls_certificate_print_formats_t format, gnutls_datum_t * out) { int count, ret, i; gnutls_pkcs7_signature_info_st info; gnutls_buffer_st str; const char *oid; _gnutls_buffer_init(&str); /* For backwards compatibility with structures using the default OID, * we don't print the eContent Type explicitly */ oid = gnutls_pkcs7_get_embedded_data_oid(pkcs7); if (oid) { if (strcmp(oid, DATA_OID) != 0 && strcmp(oid, DIGESTED_DATA_OID) != 0) { addf(&str, "eContent Type: %s\n", oid); } } for (i = 0;; i++) { if (i == 0) addf(&str, "Signers:\n"); ret = gnutls_pkcs7_get_signature_info(pkcs7, i, &info); if (ret < 0) break; print_pkcs7_info(&info, &str, format); gnutls_pkcs7_signature_info_deinit(&info); } if (format == GNUTLS_CRT_PRINT_FULL) { gnutls_datum_t data, b64; count = gnutls_pkcs7_get_crt_count(pkcs7); if (count > 0) { addf(&str, "Number of certificates: %u\n\n", count); for (i = 0; i < count; i++) { ret = gnutls_pkcs7_get_crt_raw2(pkcs7, i, &data); if (ret < 0) { addf(&str, "Error: cannot print certificate %d\n", i); continue; } ret = gnutls_pem_base64_encode_alloc ("CERTIFICATE", &data, &b64); if (ret < 0) { gnutls_free(data.data); continue; } adds(&str, (char*)b64.data); adds(&str, "\n"); gnutls_free(b64.data); gnutls_free(data.data); } } count = gnutls_pkcs7_get_crl_count(pkcs7); if (count > 0) { addf(&str, "Number of CRLs: %u\n\n", count); for (i = 0; i < count; i++) { ret = gnutls_pkcs7_get_crl_raw2(pkcs7, i, &data); if (ret < 0) { addf(&str, "Error: cannot print certificate %d\n", i); continue; } ret = gnutls_pem_base64_encode_alloc("X509 CRL", &data, &b64); if (ret < 0) { gnutls_free(data.data); continue; } adds(&str, (char*)b64.data); adds(&str, "\n"); gnutls_free(b64.data); gnutls_free(data.data); } } } return _gnutls_buffer_to_datum(&str, out, 1); }
/** * tls_check_one_certificate - Check a GnuTLS certificate * @param certdata List of GnuTLS certificates * @param certstat GnuTLS certificate status * @param hostname Hostname * @param idx Index into certificate list * @param len Length of certificate list * @retval 0 Failure * @retval >0 Success */ static int tls_check_one_certificate(const gnutls_datum_t *certdata, gnutls_certificate_status_t certstat, const char *hostname, int idx, size_t len) { int certerr, savedcert; gnutls_x509_crt_t cert; char buf[128]; char fpbuf[128]; size_t buflen; char dn_common_name[128]; char dn_email[128]; char dn_organization[128]; char dn_organizational_unit[128]; char dn_locality[128]; char dn_province[128]; char dn_country[128]; time_t t; char datestr[30]; struct Menu *menu = NULL; char helpstr[1024]; char title[256]; FILE *fp = NULL; gnutls_datum_t pemdata; int row, done, ret; if (tls_check_preauth(certdata, certstat, hostname, idx, &certerr, &savedcert) == 0) return 1; /* interactive check from user */ if (gnutls_x509_crt_init(&cert) < 0) { mutt_error(_("Error initialising gnutls certificate data")); return 0; } if (gnutls_x509_crt_import(cert, certdata, GNUTLS_X509_FMT_DER) < 0) { mutt_error(_("Error processing certificate data")); gnutls_x509_crt_deinit(cert); return 0; } menu = mutt_menu_new(MENU_GENERIC); menu->max = 27; 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)); mutt_menu_push_current(menu); row = 0; mutt_str_strfcpy(menu->dialog[row], _("This certificate belongs to:"), dialog_row_len); 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++], dialog_row_len, " %s %s", dn_common_name, dn_email); snprintf(menu->dialog[row++], dialog_row_len, " %s", dn_organization); snprintf(menu->dialog[row++], dialog_row_len, " %s", dn_organizational_unit); snprintf(menu->dialog[row++], dialog_row_len, " %s %s %s", dn_locality, dn_province, dn_country); row++; mutt_str_strfcpy(menu->dialog[row], _("This certificate was issued by:"), dialog_row_len); 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++], dialog_row_len, " %s %s", dn_common_name, dn_email); snprintf(menu->dialog[row++], dialog_row_len, " %s", dn_organization); snprintf(menu->dialog[row++], dialog_row_len, " %s", dn_organizational_unit); snprintf(menu->dialog[row++], dialog_row_len, " %s %s %s", dn_locality, dn_province, dn_country); row++; snprintf(menu->dialog[row++], dialog_row_len, _("This certificate is valid")); t = gnutls_x509_crt_get_activation_time(cert); mutt_date_make_tls(datestr, sizeof(datestr), t); snprintf(menu->dialog[row++], dialog_row_len, _(" from %s"), datestr); t = gnutls_x509_crt_get_expiration_time(cert); mutt_date_make_tls(datestr, sizeof(datestr), t); snprintf(menu->dialog[row++], dialog_row_len, _(" to %s"), datestr); fpbuf[0] = '\0'; tls_fingerprint(GNUTLS_DIG_SHA, fpbuf, sizeof(fpbuf), certdata); snprintf(menu->dialog[row++], dialog_row_len, _("SHA1 Fingerprint: %s"), fpbuf); fpbuf[0] = '\0'; fpbuf[40] = '\0'; /* Ensure the second printed line is null terminated */ tls_fingerprint(GNUTLS_DIG_SHA256, fpbuf, sizeof(fpbuf), certdata); fpbuf[39] = '\0'; /* Divide into two lines of output */ snprintf(menu->dialog[row++], dialog_row_len, "%s%s", _("SHA256 Fingerprint: "), fpbuf); snprintf(menu->dialog[row++], dialog_row_len, "%*s%s", (int) mutt_str_strlen(_("SHA256 Fingerprint: ")), "", fpbuf + 40); if (certerr & CERTERR_NOTYETVALID) { row++; mutt_str_strfcpy(menu->dialog[row], _("WARNING: Server certificate is not yet valid"), dialog_row_len); } if (certerr & CERTERR_EXPIRED) { row++; mutt_str_strfcpy(menu->dialog[row], _("WARNING: Server certificate has expired"), dialog_row_len); } if (certerr & CERTERR_REVOKED) { row++; mutt_str_strfcpy(menu->dialog[row], _("WARNING: Server certificate has been revoked"), dialog_row_len); } if (certerr & CERTERR_HOSTNAME) { row++; mutt_str_strfcpy(menu->dialog[row], _("WARNING: Server hostname does not match certificate"), dialog_row_len); } if (certerr & CERTERR_SIGNERNOTCA) { row++; mutt_str_strfcpy(menu->dialog[row], _("WARNING: Signer of server certificate is not a CA"), dialog_row_len); } snprintf(title, sizeof(title), _("SSL Certificate check (certificate %zu of %zu in chain)"), len - idx, len); menu->title = title; /* certificates with bad dates, or that are revoked, must be * accepted manually each and every time */ if (C_CertificateFile && !savedcert && !(certerr & (CERTERR_EXPIRED | CERTERR_NOTYETVALID | CERTERR_REVOKED))) { menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always"); /* L10N: These three letters correspond to the choices in the string: (r)eject, accept (o)nce, (a)ccept always. This is an interactive certificate confirmation prompt for a GNUTLS connection. */ menu->keys = _("roa"); } else { menu->prompt = _("(r)eject, accept (o)nce"); /* L10N: These two letters correspond to the choices in the string: (r)eject, accept (o)nce. These is an interactive certificate confirmation prompt for a GNUTLS connection. */ menu->keys = _("ro"); } 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 */ done = 0; fp = mutt_file_fopen(C_CertificateFile, "a"); if (fp) { /* save hostname if necessary */ if (certerr & CERTERR_HOSTNAME) { fpbuf[0] = '\0'; tls_fingerprint(GNUTLS_DIG_MD5, fpbuf, sizeof(fpbuf), certdata); fprintf(fp, "#H %s %s\n", hostname, fpbuf); done = 1; } /* Save the cert for all other errors */ if (certerr ^ CERTERR_HOSTNAME) { done = 0; ret = gnutls_pem_base64_encode_alloc("CERTIFICATE", certdata, &pemdata); if (ret == 0) { if (fwrite(pemdata.data, pemdata.size, 1, fp) == 1) { done = 1; } gnutls_free(pemdata.data); } } 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; break; } } OptIgnoreMacroEvents = false; mutt_menu_pop_current(menu); mutt_menu_destroy(&menu); gnutls_x509_crt_deinit(cert); return done == 2; }