31#include <gnutls/gnutls.h> 
   32#include <gnutls/x509.h> 
   53#define CERTERR_VALID              0 
   54#define CERTERR_EXPIRED      (1 << 0) 
   55#define CERTERR_NOTYETVALID  (1 << 1) 
   56#define CERTERR_REVOKED      (1 << 2) 
   57#define CERTERR_NOTTRUSTED   (1 << 3) 
   58#define CERTERR_HOSTNAME     (1 << 4) 
   59#define CERTERR_SIGNERNOTCA  (1 << 5) 
   60#define CERTERR_INSECUREALG  (1 << 6) 
   61#define CERTERR_OTHER        (1 << 7) 
   64#define CERT_SEP "-----BEGIN" 
   66#ifndef HAVE_GNUTLS_PRIORITY_SET_DIRECT 
   75static int ProtocolPriority[] = { GNUTLS_TLS1_2, GNUTLS_TLS1_1, GNUTLS_TLS1, GNUTLS_SSL3, 0 };
 
   84  gnutls_certificate_credentials_t 
xcred;
 
 
   94  static bool init_complete = 
false;
 
  100  err = gnutls_global_init();
 
  103    mutt_error(
"gnutls_global_init: %s", gnutls_strerror(err));
 
  107  init_complete = 
true;
 
 
  122static int tls_verify_peers(gnutls_session_t tlsstate, gnutls_certificate_status_t *certstat)
 
  139  int rc = gnutls_certificate_verify_peers2(tlsstate, certstat);
 
  145  if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND)
 
  146    mutt_error(
_(
"Unable to get certificate from peer"));
 
  148    mutt_error(
_(
"Certificate verification error (%s)"), gnutls_strerror(rc));
 
 
  160                            const gnutls_datum_t *data)
 
  162  unsigned char md[128] = { 0 };
 
  165  if (gnutls_fingerprint(algo, data, (
char *) md, &n) < 0)
 
  171  for (
size_t i = 0; i < n; i++)
 
  176    if (((i % 2) == 1) && (i < (n - 1)))
 
 
  190  char *linestr = NULL;
 
  191  size_t linestrsize = 0;
 
 
  237  gnutls_datum_t cert = { 0 };
 
  238  unsigned char *ptr = NULL;
 
  239  gnutls_datum_t b64_data = { 0 };
 
  240  unsigned char *b64_data_data = NULL;
 
  241  struct stat st = { 0 };
 
  244  if (stat(c_certificate_file, &st) == -1)
 
  247  b64_data.size = st.st_size;
 
  249  b64_data.data = b64_data_data;
 
  254    FREE(&b64_data_data);
 
  258  b64_data.size = fread(b64_data.data, 1, b64_data.size, fp);
 
  259  b64_data.data[b64_data.size] = 
'\0';
 
  264    const int rc = gnutls_pem_base64_decode_alloc(NULL, &b64_data, &cert);
 
  267      FREE(&b64_data_data);
 
  272    ptr = (
unsigned char *) strstr((
char *) b64_data.data, 
CERT_SEP);
 
  275      gnutls_free(cert.data);
 
  276      FREE(&b64_data_data);
 
  280    ptr = (
unsigned char *) strstr((
char *) ptr + 1, 
CERT_SEP);
 
  282    b64_data.size = b64_data.size - (ptr - b64_data.data);
 
  285    if (cert.size == peercert->size)
 
  287      if (memcmp(cert.data, peercert->data, cert.size) == 0)
 
  290        gnutls_free(cert.data);
 
  291        FREE(&b64_data_data);
 
  296    gnutls_free(cert.data);
 
  300  FREE(&b64_data_data);
 
 
  316                             gnutls_certificate_status_t certstat, 
const char *hostname,
 
  317                             int chainidx, 
int *certerr, 
int *savedcert)
 
  319  gnutls_x509_crt_t cert;
 
  324  if (gnutls_x509_crt_init(&cert) < 0)
 
  326    mutt_error(
_(
"Error initialising gnutls certificate data"));
 
  330  if (gnutls_x509_crt_import(cert, certdata, GNUTLS_X509_FMT_DER) < 0)
 
  332    mutt_error(
_(
"Error processing certificate data"));
 
  333    gnutls_x509_crt_deinit(cert);
 
  342  if (c_ssl_verify_dates != 
MUTT_NO)
 
  344    if (gnutls_x509_crt_get_expiration_time(cert) < 
mutt_date_now())
 
  346    if (gnutls_x509_crt_get_activation_time(cert) > 
mutt_date_now())
 
  351  if ((chainidx == 0) && (c_ssl_verify_host != 
MUTT_NO) &&
 
  352      !gnutls_x509_crt_check_hostname(cert, hostname) &&
 
  358  if (certstat & GNUTLS_CERT_REVOKED)
 
  361    certstat ^= GNUTLS_CERT_REVOKED;
 
  374      gnutls_x509_crt_deinit(cert);
 
  379  if (certstat & GNUTLS_CERT_INVALID)
 
  382    certstat ^= GNUTLS_CERT_INVALID;
 
  385  if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
 
  389    certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
 
  392  if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
 
  396    certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
 
  399  if (certstat & GNUTLS_CERT_INSECURE_ALGORITHM)
 
  403    certstat ^= GNUTLS_CERT_INSECURE_ALGORITHM;
 
  412  gnutls_x509_crt_deinit(cert);
 
 
  427static void add_cert(
const char *title, gnutls_x509_crt_t cert, 
bool issuer,
 
  428                     struct StringArray *carr)
 
  430  static const char *part[] = {
 
  431    GNUTLS_OID_X520_COMMON_NAME,              
 
  432    GNUTLS_OID_PKCS9_EMAIL,                   
 
  433    GNUTLS_OID_X520_ORGANIZATION_NAME,        
 
  434    GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 
 
  435    GNUTLS_OID_X520_LOCALITY_NAME,            
 
  436    GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME,   
 
  437    GNUTLS_OID_X520_COUNTRY_NAME,             
 
  440  char buf[128] = { 0 };
 
  446  for (
size_t i = 0; i < 
countof(part); i++)
 
  448    size_t buflen = 
sizeof(buf);
 
  450      rc = gnutls_x509_crt_get_issuer_dn_by_oid(cert, part[i], 0, 0, buf, &buflen);
 
  452      rc = gnutls_x509_crt_get_dn_by_oid(cert, part[i], 0, 0, buf, &buflen);
 
 
  473                                     gnutls_certificate_status_t certstat,
 
  474                                     const char *hostname, 
int idx, 
size_t len)
 
  477  int certerr, savedcert;
 
  478  gnutls_x509_crt_t cert;
 
  479  struct Buffer *fpbuf = NULL;
 
  481  char datestr[30] = { 0 };
 
  482  char title[256] = { 0 };
 
  483  gnutls_datum_t pemdata = { 0 };
 
  485  if (
tls_check_preauth(certdata, certstat, hostname, idx, &certerr, &savedcert) == 0)
 
  496  if (gnutls_x509_crt_init(&cert) < 0)
 
  498    mutt_error(
_(
"Error initialising gnutls certificate data"));
 
  502  if (gnutls_x509_crt_import(cert, certdata, GNUTLS_X509_FMT_DER) < 0)
 
  504    mutt_error(
_(
"Error processing certificate data"));
 
  505    gnutls_x509_crt_deinit(cert);
 
  509  add_cert(
_(
"This certificate belongs to:"), cert, 
false, &carr);
 
  511  add_cert(
_(
"This certificate was issued by:"), cert, 
true, &carr);
 
  517  t = gnutls_x509_crt_get_activation_time(cert);
 
  522  t = gnutls_x509_crt_get_expiration_time(cert);
 
  535  fpbuf->
data[39] = 
'\0'; 
 
  539                    "", fpbuf->
data + 40);
 
  570  snprintf(title, 
sizeof(title),
 
  571           _(
"SSL Certificate check (certificate %zu of %zu in chain)"), len - idx, len);
 
  574  const bool allow_always = (c_certificate_file && !savedcert &&
 
  587        fprintf(fp, 
"#H %s %s\n", hostname, 
buf_string(fpbuf));
 
  592        int rc2 = gnutls_pem_base64_encode_alloc(
"CERTIFICATE", certdata, &pemdata);
 
  595          if (fwrite(pemdata.data, pemdata.size, 1, fp) == 1)
 
  599          gnutls_free(pemdata.data);
 
  607      mutt_error(
_(
"Warning: Couldn't save certificate"));
 
  612  gnutls_x509_crt_deinit(cert);
 
 
  626  const gnutls_datum_t *cert_list = NULL;
 
  627  unsigned int cert_list_size = 0;
 
  628  gnutls_certificate_status_t certstat;
 
  629  int certerr, savedcert, rc = 0;
 
  630  int max_preauth_pass = -1;
 
  641  cert_list = gnutls_certificate_get_peers(
session, &cert_list_size);
 
  642  if (!cert_list || (cert_list_size == 0))
 
  644    mutt_error(
_(
"Unable to get certificate from peer"));
 
  652  for (
int i = 0; i < cert_list_size; i++)
 
  655                           &certerr, &savedcert);
 
  658      max_preauth_pass = i;
 
  669  for (
int i = cert_list_size - 1; i >= 0; i--)
 
  681      int rcsettrust = gnutls_certificate_set_x509_trust_mem(data->
xcred, &cert_list[i],
 
  682                                                             GNUTLS_X509_FMT_DER);
 
  691      if (!certstat && (max_preauth_pass >= (i - 1)))
 
 
  709  gnutls_x509_crt_t clientcrt;
 
  715  const gnutls_datum_t *crtdata = gnutls_certificate_get_ours(data->
session);
 
  719  if (gnutls_x509_crt_init(&clientcrt) < 0)
 
  725  if (gnutls_x509_crt_import(clientcrt, crtdata, GNUTLS_X509_FMT_DER) < 0)
 
  732  rc = gnutls_x509_crt_get_dn_by_oid(clientcrt, GNUTLS_OID_X520_COMMON_NAME, 0,
 
  734  if (((rc >= 0) || (rc == GNUTLS_E_SHORT_MEMORY_BUFFER)) && (cnlen > 0))
 
  737    if (gnutls_x509_crt_get_dn_by_oid(clientcrt, GNUTLS_OID_X520_COMMON_NAME, 0,
 
  747  gnutls_x509_crt_deinit(clientcrt);
 
 
  750#ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT 
  771  if (!c_ssl_use_tlsv1_3)
 
  777  if (!c_ssl_use_tlsv1_2)
 
  783  if (!c_ssl_use_tlsv1_1)
 
  789  if (!c_ssl_use_tlsv1)
 
  795  if (!c_ssl_use_sslv3)
 
  803    mutt_error(
_(
"All available protocols for TLS/SSL connection disabled"));
 
  807  int err = gnutls_priority_set_direct(
data->session, 
buf_string(priority), NULL);
 
  811               gnutls_strerror(err));
 
  834  if (c_ssl_use_tlsv1_2)
 
  837  if (c_ssl_use_tlsv1_1)
 
  849    mutt_error(
_(
"All available protocols for TLS/SSL connection disabled"));
 
  856    mutt_error(
_(
"Explicit ciphersuite selection via $ssl_ciphers not supported"));
 
  861  gnutls_set_default_priority(
data->session);
 
 
  880  int err = gnutls_certificate_allocate_credentials(&data->
xcred);
 
  884    mutt_error(
"gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
 
  889  gnutls_certificate_set_x509_trust_file(data->
xcred, c_certificate_file, GNUTLS_X509_FMT_PEM);
 
  893  if (c_ssl_ca_certificates_file)
 
  895    gnutls_certificate_set_x509_trust_file(data->
xcred, c_ssl_ca_certificates_file,
 
  896                                           GNUTLS_X509_FMT_PEM);
 
  900  if (c_ssl_client_cert)
 
  903    gnutls_certificate_set_x509_key_file(data->
xcred, c_ssl_client_cert,
 
  904                                         c_ssl_client_cert, GNUTLS_X509_FMT_PEM);
 
  907#ifdef HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS 
  910  gnutls_certificate_set_verify_flags(data->
xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
 
  913  err = gnutls_init(&data->
session, GNUTLS_CLIENT);
 
  916    mutt_error(
"gnutls_init: %s", gnutls_strerror(err));
 
  921  gnutls_transport_set_ptr(data->
session, (gnutls_transport_ptr_t) (
long) conn->
fd);
 
  926    mutt_error(
_(
"Warning: unable to set TLS SNI host name"));
 
  935  if (c_ssl_min_dh_prime_bits > 0)
 
  937    gnutls_dh_set_prime_bits(data->
session, c_ssl_min_dh_prime_bits);
 
  940  gnutls_credentials_set(data->
session, GNUTLS_CRD_CERTIFICATE, data->
xcred);
 
  944    err = gnutls_handshake(data->
session);
 
  945  } 
while ((err == GNUTLS_E_AGAIN) || (err == GNUTLS_E_INTERRUPTED));
 
  949    if (err == GNUTLS_E_FATAL_ALERT_RECEIVED)
 
  951      mutt_error(
"gnutls_handshake: %s(%s)", gnutls_strerror(err),
 
  952                 gnutls_alert_get_name(gnutls_alert_get(data->
session)));
 
  956      mutt_error(
"gnutls_handshake: %s", gnutls_strerror(err));
 
  966  conn->
ssf = gnutls_cipher_get_key_size(gnutls_cipher_get(data->
session)) * 8;
 
  973                 gnutls_protocol_get_name(gnutls_protocol_get_version(data->
session)),
 
  974                 gnutls_kx_get_name(gnutls_kx_get(data->
session)),
 
  975                 gnutls_cipher_get_name(gnutls_cipher_get(data->
session)),
 
  976                 gnutls_mac_get_name(gnutls_mac_get(data->
session)));
 
  983  gnutls_certificate_free_credentials(data->
xcred);
 
 
  998  if (gnutls_record_check_pending(data->
session))
 
 
 1019    gnutls_bye(data->
session, GNUTLS_SHUT_WR);
 
 1021    gnutls_certificate_free_credentials(data->
xcred);
 
 
 1061    rc = gnutls_record_recv(data->
session, buf, count);
 
 1062  } 
while ((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED));
 
 1066    mutt_error(
"tls_socket_read (%s)", gnutls_strerror(rc));
 
 
 1092      rc = gnutls_record_send(data->
session, buf + sent, count - sent);
 
 1093    } 
while ((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED));
 
 1097      mutt_error(
"tls_socket_write (%s)", gnutls_strerror(rc));
 
 1102  } 
while (sent < count);
 
 
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Convenience wrapper for the config headers.
Shared functions that are private to Connections.
An open network connection (socket)
Convenience wrapper for the core headers.
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
#define mutt_file_fclose(FP)
#define mutt_file_fopen(PATH, MODE)
#define MUTT_RL_NO_FLAGS
No flags are set.
bool OptGui
(pseudo) when the gui (and curses) are started
#define CERTERR_INSECUREALG
static int tls_check_preauth(const gnutls_datum_t *certdata, gnutls_certificate_status_t certstat, const char *hostname, int chainidx, int *certerr, int *savedcert)
Prepare a certificate for authentication.
static int tls_check_certificate(struct Connection *conn)
Check a connection's certificate.
int mutt_ssl_starttls(struct Connection *conn)
Negotiate TLS over an already opened connection.
static bool tls_check_stored_hostname(const gnutls_datum_t *cert, const char *hostname)
Does the hostname match a stored certificate?
#define CERTERR_NOTTRUSTED
static int tls_verify_peers(gnutls_session_t tlsstate, gnutls_certificate_status_t *certstat)
Wrapper for gnutls_certificate_verify_peers()
#define CERTERR_NOTYETVALID
static void add_cert(const char *title, gnutls_x509_crt_t cert, bool issuer, struct StringArray *carr)
Look up certificate info and save it to a list.
static int ProtocolPriority[]
This array needs to be large enough to hold all the possible values support by NeoMutt.
int gnutls_protocol_set_priority(gnutls_session_t session, const int *list)
static bool tls_compare_certificates(const gnutls_datum_t *peercert)
Compare certificates against $certificate_file
static void tls_fingerprint(gnutls_digest_algorithm_t algo, struct Buffer *buf, const gnutls_datum_t *data)
Create a fingerprint of a TLS Certificate.
static int tls_init(void)
Set up Gnu TLS.
static void tls_get_client_cert(struct Connection *conn)
Get the client certificate for a TLS connection.
static int tls_check_one_certificate(const gnutls_datum_t *certdata, gnutls_certificate_status_t certstat, const char *hostname, int idx, size_t len)
Check a GnuTLS certificate.
static int tls_negotiate(struct Connection *conn)
Negotiate TLS connection.
int mutt_ssl_socket_setup(struct Connection *conn)
Set up SSL socket mulitplexor.
#define CERTERR_SIGNERNOTCA
static int tls_set_priority(struct TlsSockData *data)
Set the priority of various protocols.
static int tls_starttls_close(struct Connection *conn)
Close a TLS connection - Implements Connection::close() -.
static int tls_socket_close(struct Connection *conn)
Close a TLS socket - Implements Connection::close() -.
int raw_socket_close(struct Connection *conn)
Close a socket - Implements Connection::close() -.
static int tls_socket_open(struct Connection *conn)
Open a TLS socket - Implements Connection::open() -.
int raw_socket_open(struct Connection *conn)
Open a socket - Implements Connection::open() -.
static int tls_socket_poll(struct Connection *conn, time_t wait_secs)
Check if any data is waiting on a socket - Implements Connection::poll() -.
int raw_socket_poll(struct Connection *conn, time_t wait_secs)
Check if any data is waiting on a socket - Implements Connection::poll() -.
static int tls_socket_read(struct Connection *conn, char *buf, size_t count)
Read data from a TLS socket - Implements Connection::read() -.
int raw_socket_read(struct Connection *conn, char *buf, size_t len)
Read data from a socket - Implements Connection::read() -.
int raw_socket_write(struct Connection *conn, const char *buf, size_t count)
Write data to a socket - Implements Connection::write() -.
static int tls_socket_write(struct Connection *conn, const char *buf, size_t count)
Write data to a TLS socket - Implements Connection::write() -.
int dlg_certificate(const char *title, struct StringArray *carr, bool allow_always, bool allow_skip)
Ask the user to validate the certificate -.
#define mutt_message(...)
#define mutt_debug(LEVEL,...)
@ LL_DEBUG2
Log at debug level 2.
@ LL_DEBUG1
Log at debug level 1.
#define MUTT_MEM_CALLOC(n, type)
int mutt_date_make_tls(char *buf, size_t buflen, time_t timestamp)
Format date in TLS certificate verification style.
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Convenience wrapper for the library headers.
char * mutt_str_dup(const char *str)
Copy a string, safely.
int mutt_str_asprintf(char **strp, const char *fmt,...)
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
void string_array_clear(struct StringArray *arr)
Free all memory of a StringArray.
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
void mutt_sleep(short s)
Sleep for a while.
Some miscellaneous functions.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
Match a precompiled regex against a string.
@ PREX_GNUTLS_CERT_HOST_HASH
[#H foo.com A76D 954B EB79 1F49 5B3A 0A0E 0681 65B1]
@ PREX_GNUTLS_CERT_HOST_HASH_MATCH_HASH
#H foo.com [A76D ... 65B1]
@ PREX_GNUTLS_CERT_HOST_HASH_MATCH_HOST
#H [foo.com] A76D ... 65B1
@ MUTT_NO
User answered 'No', or assume 'No'.
static regoff_t mutt_regmatch_end(const regmatch_t *match)
Return the end of a match.
static regoff_t mutt_regmatch_start(const regmatch_t *match)
Return the start of a match.
Handling of SSL encryption.
String manipulation buffer.
char * data
Pointer to data.
char host[128]
Server to login to.
void * sockdata
Backend-specific socket data.
int(* poll)(struct Connection *conn, time_t wait_secs)
int(* write)(struct Connection *conn, const char *buf, size_t count)
unsigned int ssf
Security strength factor, in bits (see notes)
int(* close)(struct Connection *conn)
struct ConnAccount account
Account details: username, password, etc.
int(* open)(struct Connection *conn)
int fd
Socket file descriptor.
int(* read)(struct Connection *conn, char *buf, size_t count)
Container for Accounts, Notifications.
struct ConfigSubset * sub
Inherited config items.
gnutls_certificate_credentials_t xcred