NeoMutt  2020-06-26-30-g76c339
Teaching an old dog new tricks
DOXYGEN
gnutls.c File Reference

Handling of GnuTLS encryption. More...

#include "config.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "lib.h"
#include "muttlib.h"
#include "options.h"
#include "ssl.h"
+ Include dependency graph for gnutls.c:

Go to the source code of this file.

Data Structures

struct  TlsSockData
 TLS socket data. More...
 

Macros

#define CERTERR_VALID   0
 
#define CERTERR_EXPIRED   (1 << 0)
 
#define CERTERR_NOTYETVALID   (1 << 1)
 
#define CERTERR_REVOKED   (1 << 2)
 
#define CERTERR_NOTTRUSTED   (1 << 3)
 
#define CERTERR_HOSTNAME   (1 << 4)
 
#define CERTERR_SIGNERNOTCA   (1 << 5)
 
#define CERTERR_INSECUREALG   (1 << 6)
 
#define CERTERR_OTHER   (1 << 7)
 
#define CERT_SEP   "-----BEGIN"
 

Functions

static int tls_init (void)
 Set up Gnu TLS. More...
 
static int tls_verify_peers (gnutls_session_t tlsstate, gnutls_certificate_status_t *certstat)
 Wrapper for gnutls_certificate_verify_peers() More...
 
static void tls_fingerprint (gnutls_digest_algorithm_t algo, char *buf, size_t buflen, const gnutls_datum_t *data)
 Create a fingerprint of a TLS Certificate. More...
 
static int tls_check_stored_hostname (const gnutls_datum_t *cert, const char *hostname)
 Does the hostname match a stored certificate? More...
 
static int tls_compare_certificates (const gnutls_datum_t *peercert)
 Compare certificates against C_CertificateFile. More...
 
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. More...
 
static void add_cert (const char *title, gnutls_x509_crt_t cert, bool issuer, struct ListHead *list)
 Look up certificate info and save it to a list. More...
 
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. More...
 
static int tls_check_certificate (struct Connection *conn)
 Check a connection's certificate. More...
 
static void tls_get_client_cert (struct Connection *conn)
 Get the client certificate for a TLS connection. More...
 
static int tls_set_priority (struct TlsSockData *data)
 Set the priority of various protocols. More...
 
static int tls_negotiate (struct Connection *conn)
 Negotiate TLS connection. More...
 
static int tls_socket_poll (struct Connection *conn, time_t wait_secs)
 Check whether a socket read would block - Implements Connection::poll() More...
 
static int tls_socket_close (struct Connection *conn)
 Close a TLS socket - Implements Connection::close() More...
 
static int tls_socket_open (struct Connection *conn)
 Open a TLS socket - Implements Connection::open() More...
 
static int tls_socket_read (struct Connection *conn, char *buf, size_t count)
 Read data from a TLS socket - Implements Connection::read() More...
 
static int tls_socket_write (struct Connection *conn, const char *buf, size_t count)
 Write data to a TLS socket - Implements Connection::write() More...
 
static int tls_starttls_close (struct Connection *conn)
 Close a TLS connection - Implements Connection::close() More...
 
int mutt_ssl_socket_setup (struct Connection *conn)
 Set up SSL socket mulitplexor. More...
 
int mutt_ssl_starttls (struct Connection *conn)
 Negotiate TLS over an already opened connection. More...
 

Variables

const int dialog_row_len = 128
 
static int protocol_priority []
 

Detailed Description

Handling of GnuTLS encryption.

Authors
  • Marco d'Itri
  • Andrew McDonald

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file gnutls.c.

Macro Definition Documentation

◆ CERTERR_VALID

#define CERTERR_VALID   0

Definition at line 47 of file gnutls.c.

◆ CERTERR_EXPIRED

#define CERTERR_EXPIRED   (1 << 0)

Definition at line 48 of file gnutls.c.

◆ CERTERR_NOTYETVALID

#define CERTERR_NOTYETVALID   (1 << 1)

Definition at line 49 of file gnutls.c.

◆ CERTERR_REVOKED

#define CERTERR_REVOKED   (1 << 2)

Definition at line 50 of file gnutls.c.

◆ CERTERR_NOTTRUSTED

#define CERTERR_NOTTRUSTED   (1 << 3)

Definition at line 51 of file gnutls.c.

◆ CERTERR_HOSTNAME

#define CERTERR_HOSTNAME   (1 << 4)

Definition at line 52 of file gnutls.c.

◆ CERTERR_SIGNERNOTCA

#define CERTERR_SIGNERNOTCA   (1 << 5)

Definition at line 53 of file gnutls.c.

◆ CERTERR_INSECUREALG

#define CERTERR_INSECUREALG   (1 << 6)

Definition at line 54 of file gnutls.c.

◆ CERTERR_OTHER

#define CERTERR_OTHER   (1 << 7)

Definition at line 55 of file gnutls.c.

◆ CERT_SEP

#define CERT_SEP   "-----BEGIN"

Definition at line 60 of file gnutls.c.

Function Documentation

◆ tls_init()

static int tls_init ( void  )
static

Set up Gnu TLS.

Return values
0Success
-1Error

Definition at line 89 of file gnutls.c.

90 {
91  static bool init_complete = false;
92  int err;
93 
94  if (init_complete)
95  return 0;
96 
97  err = gnutls_global_init();
98  if (err < 0)
99  {
100  mutt_error("gnutls_global_init: %s", gnutls_strerror(err));
101  return -1;
102  }
103 
104  init_complete = true;
105  return 0;
106 }
#define mutt_error(...)
Definition: logging.h:84
+ Here is the caller graph for this function:

◆ tls_verify_peers()

static int tls_verify_peers ( gnutls_session_t  tlsstate,
gnutls_certificate_status_t *  certstat 
)
static

Wrapper for gnutls_certificate_verify_peers()

Parameters
tlsstateTLS state
certstatCertificate state, e.g. GNUTLS_CERT_INVALID
Return values
0Success If certstat was set. note: this does not mean success
>0Error

Wrapper with sanity-checking.

certstat is technically a bitwise-or of gnutls_certificate_status_t values.

Definition at line 119 of file gnutls.c.

120 {
121  /* gnutls_certificate_verify_peers2() chains to
122  * gnutls_x509_trust_list_verify_crt2(). That function's documentation says:
123  *
124  * When a certificate chain of cert_list_size with more than one
125  * certificates is provided, the verification status will apply to
126  * the first certificate in the chain that failed
127  * verification. The verification process starts from the end of
128  * the chain(from CA to end certificate). The first certificate
129  * in the chain must be the end-certificate while the rest of the
130  * members may be sorted or not.
131  *
132  * This is why tls_check_certificate() loops from CA to host in that order,
133  * calling the menu, and recalling tls_verify_peers() for each approved
134  * cert in the chain.
135  */
136  int rc = gnutls_certificate_verify_peers2(tlsstate, certstat);
137 
138  /* certstat was set */
139  if (rc == 0)
140  return 0;
141 
142  if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND)
143  mutt_error(_("Unable to get certificate from peer"));
144  else
145  mutt_error(_("Certificate verification error (%s)"), gnutls_strerror(rc));
146 
147  return rc;
148 }
#define _(a)
Definition: message.h:28
#define mutt_error(...)
Definition: logging.h:84
+ Here is the caller graph for this function:

◆ tls_fingerprint()

static void tls_fingerprint ( gnutls_digest_algorithm_t  algo,
char *  buf,
size_t  buflen,
const gnutls_datum_t *  data 
)
static

Create a fingerprint of a TLS Certificate.

Parameters
algoFingerprint algorithm, e.g. GNUTLS_MAC_SHA256
bufBuffer for the fingerprint
buflenLength of the buffer
dataCertificate

Definition at line 157 of file gnutls.c.

159 {
160  unsigned char md[64];
161  size_t n;
162 
163  n = 64;
164 
165  if (gnutls_fingerprint(algo, data, (char *) md, &n) < 0)
166  {
167  snprintf(buf, buflen, _("[unable to calculate]"));
168  }
169  else
170  {
171  for (int i = 0; i < (int) n; i++)
172  {
173  char ch[8];
174  snprintf(ch, 8, "%02X%s", md[i], ((i % 2) ? " " : ""));
175  mutt_str_cat(buf, buflen, ch);
176  }
177  buf[2 * n + n / 2 - 1] = '\0'; /* don't want trailing space */
178  }
179 }
#define _(a)
Definition: message.h:28
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:390
int n
Definition: acutest.h:492
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_check_stored_hostname()

static int tls_check_stored_hostname ( const gnutls_datum_t *  cert,
const char *  hostname 
)
static

Does the hostname match a stored certificate?

Parameters
certCertificate
hostnameHostname
Return values
1Hostname match found
0Error, or no match

Definition at line 188 of file gnutls.c.

189 {
190  char *linestr = NULL;
191  size_t linestrsize = 0;
192 
193  /* try checking against names stored in stored certs file */
194  FILE *fp = mutt_file_fopen(C_CertificateFile, "r");
195  if (!fp)
196  return 0;
197 
198  char buf[80];
199  buf[0] = '\0';
200  tls_fingerprint(GNUTLS_DIG_MD5, buf, sizeof(buf), cert);
201  while ((linestr = mutt_file_read_line(linestr, &linestrsize, fp, NULL, 0)))
202  {
203  regmatch_t *match = mutt_prex_capture(PREX_GNUTLS_CERT_HOST_HASH, linestr);
204  if (match)
205  {
206  regmatch_t *mhost = &match[PREX_GNUTLS_CERT_HOST_HASH_MATCH_HOST];
207  regmatch_t *mhash = &match[PREX_GNUTLS_CERT_HOST_HASH_MATCH_HASH];
208  linestr[mutt_regmatch_end(mhost)] = '\0';
209  linestr[mutt_regmatch_end(mhash)] = '\0';
210  if ((strcmp(linestr + mutt_regmatch_start(mhost), hostname) == 0) &&
211  (strcmp(linestr + mutt_regmatch_start(mhash), buf) == 0))
212  {
213  FREE(&linestr);
214  mutt_file_fclose(&fp);
215  return 1;
216  }
217  }
218  }
219 
220  mutt_file_fclose(&fp);
221 
222  /* not found a matching name */
223  return 0;
224 }
const char * C_CertificateFile
Config: File containing trusted certificates.
Definition: conn_globals.c:37
static regoff_t mutt_regmatch_end(const regmatch_t *match)
Return the end of a match.
Definition: regex3.h:70
static void tls_fingerprint(gnutls_digest_algorithm_t algo, char *buf, size_t buflen, const gnutls_datum_t *data)
Create a fingerprint of a TLS Certificate.
Definition: gnutls.c:157
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:667
#H [foo.com] A76D ... 65B1
Definition: prex.h:109
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
match a precompiled regex against a string
Definition: prex.c:306
static regoff_t mutt_regmatch_start(const regmatch_t *match)
Return the start of a match.
Definition: regex3.h:60
[#H foo.com A76D 954B EB79 1F49 5B3A 0A0E 0681 65B1]
Definition: prex.h:36
#define FREE(x)
Definition: memory.h:40
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
#H foo.com [A76D ... 65B1]
Definition: prex.h:110
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_compare_certificates()

static int tls_compare_certificates ( const gnutls_datum_t *  peercert)
static

Compare certificates against C_CertificateFile.

Parameters
peercertCertificate
Return values
1Certificate matches file
0Error, or no match

Definition at line 232 of file gnutls.c.

233 {
234  gnutls_datum_t cert = { 0 };
235  unsigned char *ptr = NULL;
236  gnutls_datum_t b64_data = { 0 };
237  unsigned char *b64_data_data = NULL;
238  struct stat filestat;
239 
240  if (stat(C_CertificateFile, &filestat) == -1)
241  return 0;
242 
243  b64_data.size = filestat.st_size;
244  b64_data_data = mutt_mem_calloc(1, b64_data.size + 1);
245  b64_data.data = b64_data_data;
246 
247  FILE *fp = mutt_file_fopen(C_CertificateFile, "r");
248  if (!fp)
249  return 0;
250 
251  b64_data.size = fread(b64_data.data, 1, b64_data.size, fp);
252  mutt_file_fclose(&fp);
253 
254  do
255  {
256  const int ret = gnutls_pem_base64_decode_alloc(NULL, &b64_data, &cert);
257  if (ret != 0)
258  {
259  FREE(&b64_data_data);
260  return 0;
261  }
262 
263  /* find start of cert, skipping junk */
264  ptr = (unsigned char *) strstr((char *) b64_data.data, CERT_SEP);
265  if (!ptr)
266  {
267  gnutls_free(cert.data);
268  FREE(&b64_data_data);
269  return 0;
270  }
271  /* find start of next cert */
272  ptr = (unsigned char *) strstr((char *) ptr + 1, CERT_SEP);
273 
274  b64_data.size = b64_data.size - (ptr - b64_data.data);
275  b64_data.data = ptr;
276 
277  if (cert.size == peercert->size)
278  {
279  if (memcmp(cert.data, peercert->data, cert.size) == 0)
280  {
281  /* match found */
282  gnutls_free(cert.data);
283  FREE(&b64_data_data);
284  return 1;
285  }
286  }
287 
288  gnutls_free(cert.data);
289  } while (ptr);
290 
291  /* no match found */
292  FREE(&b64_data_data);
293  return 0;
294 }
const char * C_CertificateFile
Config: File containing trusted certificates.
Definition: conn_globals.c:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define CERT_SEP
Definition: gnutls.c:60
#define FREE(x)
Definition: memory.h:40
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_check_preauth()

static int tls_check_preauth ( const gnutls_datum_t *  certdata,
gnutls_certificate_status_t  certstat,
const char *  hostname,
int  chainidx,
int *  certerr,
int *  savedcert 
)
static

Prepare a certificate for authentication.

Parameters
[in]certdataList of GnuTLS certificates
[in]certstatGnuTLS certificate status
[in]hostnameHostname
[in]chainidxIndex in the certificate chain
[out]certerrResult, e.g. CERTERR_VALID
[out]savedcert1 if certificate has been saved
Return values
0Success
-1Error

Definition at line 307 of file gnutls.c.

310 {
311  gnutls_x509_crt_t cert;
312 
313  *certerr = CERTERR_VALID;
314  *savedcert = 0;
315 
316  if (gnutls_x509_crt_init(&cert) < 0)
317  {
318  mutt_error(_("Error initialising gnutls certificate data"));
319  return -1;
320  }
321 
322  if (gnutls_x509_crt_import(cert, certdata, GNUTLS_X509_FMT_DER) < 0)
323  {
324  mutt_error(_("Error processing certificate data"));
325  gnutls_x509_crt_deinit(cert);
326  return -1;
327  }
328 
329  /* Note: tls_negotiate() contains a call to
330  * gnutls_certificate_set_verify_flags() with a flag disabling
331  * GnuTLS checking of the dates. So certstat shouldn't have the
332  * GNUTLS_CERT_EXPIRED and GNUTLS_CERT_NOT_ACTIVATED bits set. */
333  if (C_SslVerifyDates != MUTT_NO)
334  {
335  if (gnutls_x509_crt_get_expiration_time(cert) < mutt_date_epoch())
336  *certerr |= CERTERR_EXPIRED;
337  if (gnutls_x509_crt_get_activation_time(cert) > mutt_date_epoch())
338  *certerr |= CERTERR_NOTYETVALID;
339  }
340 
341  if ((chainidx == 0) && (C_SslVerifyHost != MUTT_NO) &&
342  !gnutls_x509_crt_check_hostname(cert, hostname) &&
343  !tls_check_stored_hostname(certdata, hostname))
344  {
345  *certerr |= CERTERR_HOSTNAME;
346  }
347 
348  if (certstat & GNUTLS_CERT_REVOKED)
349  {
350  *certerr |= CERTERR_REVOKED;
351  certstat ^= GNUTLS_CERT_REVOKED;
352  }
353 
354  /* see whether certificate is in our cache (certificates file) */
355  if (tls_compare_certificates(certdata))
356  {
357  *savedcert = 1;
358 
359  /* We check above for certs with bad dates or that are revoked.
360  * These must be accepted manually each time. Otherwise, we
361  * accept saved certificates as valid. */
362  if (*certerr == CERTERR_VALID)
363  {
364  gnutls_x509_crt_deinit(cert);
365  return 0;
366  }
367  }
368 
369  if (certstat & GNUTLS_CERT_INVALID)
370  {
371  *certerr |= CERTERR_NOTTRUSTED;
372  certstat ^= GNUTLS_CERT_INVALID;
373  }
374 
375  if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
376  {
377  /* NB: already cleared if cert in cache */
378  *certerr |= CERTERR_NOTTRUSTED;
379  certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
380  }
381 
382  if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
383  {
384  /* NB: already cleared if cert in cache */
385  *certerr |= CERTERR_SIGNERNOTCA;
386  certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
387  }
388 
389  if (certstat & GNUTLS_CERT_INSECURE_ALGORITHM)
390  {
391  /* NB: already cleared if cert in cache */
392  *certerr |= CERTERR_INSECUREALG;
393  certstat ^= GNUTLS_CERT_INSECURE_ALGORITHM;
394  }
395 
396  /* we've been zeroing the interesting bits in certstat -
397  * don't return OK if there are any unhandled bits we don't
398  * understand */
399  if (certstat != 0)
400  *certerr |= CERTERR_OTHER;
401 
402  gnutls_x509_crt_deinit(cert);
403 
404  if (*certerr == CERTERR_VALID)
405  return 0;
406 
407  return -1;
408 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:414
#define CERTERR_INSECUREALG
Definition: gnutls.c:54
static int tls_compare_certificates(const gnutls_datum_t *peercert)
Compare certificates against C_CertificateFile.
Definition: gnutls.c:232
bool C_SslVerifyDates
Config: (ssl) Verify the dates on the server certificate.
Definition: conn_globals.c:46
#define CERTERR_REVOKED
Definition: gnutls.c:50
#define _(a)
Definition: message.h:28
#define CERTERR_EXPIRED
Definition: gnutls.c:48
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
#define CERTERR_NOTYETVALID
Definition: gnutls.c:49
#define CERTERR_HOSTNAME
Definition: gnutls.c:52
#define CERTERR_VALID
Definition: gnutls.c:47
#define mutt_error(...)
Definition: logging.h:84
bool C_SslVerifyHost
Config: (ssl) Verify the server&#39;s hostname against the certificate.
Definition: conn_globals.c:47
#define CERTERR_NOTTRUSTED
Definition: gnutls.c:51
static int tls_check_stored_hostname(const gnutls_datum_t *cert, const char *hostname)
Does the hostname match a stored certificate?
Definition: gnutls.c:188
#define CERTERR_OTHER
Definition: gnutls.c:55
#define CERTERR_SIGNERNOTCA
Definition: gnutls.c:53
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_cert()

static void add_cert ( const char *  title,
gnutls_x509_crt_t  cert,
bool  issuer,
struct ListHead *  list 
)
static

Look up certificate info and save it to a list.

Parameters
titleTitle for this block of certificate info
certCertificate
issuerIf true, look up the issuer rather than owner details
listList to save info to

Definition at line 417 of file gnutls.c.

419 {
420  static const char *part[] = {
421  GNUTLS_OID_X520_COMMON_NAME, // CN
422  GNUTLS_OID_PKCS9_EMAIL, // Email
423  GNUTLS_OID_X520_ORGANIZATION_NAME, // O
424  GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, // OU
425  GNUTLS_OID_X520_LOCALITY_NAME, // L
426  GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, // ST
427  GNUTLS_OID_X520_COUNTRY_NAME, // C
428  };
429 
430  char buf[128];
431  int rc;
432 
433  // Allocate formatted strings and let the ListHead take ownership
434  mutt_list_insert_tail(list, mutt_str_dup(title));
435 
436  for (size_t i = 0; i < mutt_array_size(part); i++)
437  {
438  size_t buflen = sizeof(buf);
439  if (issuer)
440  rc = gnutls_x509_crt_get_issuer_dn_by_oid(cert, part[i], 0, 0, buf, &buflen);
441  else
442  rc = gnutls_x509_crt_get_dn_by_oid(cert, part[i], 0, 0, buf, &buflen);
443  if (rc != 0)
444  continue;
445 
446  char *line = NULL;
447  mutt_str_asprintf(&line, " %s", buf);
448  mutt_list_insert_tail(list, line);
449  }
450 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
#define mutt_array_size(x)
Definition: memory.h:33
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1103
int const char int line
Definition: acutest.h:617
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_check_one_certificate()

static int tls_check_one_certificate ( const gnutls_datum_t *  certdata,
gnutls_certificate_status_t  certstat,
const char *  hostname,
int  idx,
size_t  len 
)
static

Check a GnuTLS certificate.

Parameters
certdataList of GnuTLS certificates
certstatGnuTLS certificate status
hostnameHostname
idxIndex into certificate list
lenLength of certificate list
Return values
1Success
0Failure

Definition at line 462 of file gnutls.c.

465 {
466  struct ListHead list = STAILQ_HEAD_INITIALIZER(list);
467  int certerr, savedcert;
468  gnutls_x509_crt_t cert;
469  char fpbuf[128];
470  time_t t;
471  char datestr[30];
472  char title[256];
473  gnutls_datum_t pemdata = { 0 };
474 
475  if (tls_check_preauth(certdata, certstat, hostname, idx, &certerr, &savedcert) == 0)
476  return 1;
477 
478  /* interactive check from user */
479  if (gnutls_x509_crt_init(&cert) < 0)
480  {
481  mutt_error(_("Error initialising gnutls certificate data"));
482  return 0;
483  }
484 
485  if (gnutls_x509_crt_import(cert, certdata, GNUTLS_X509_FMT_DER) < 0)
486  {
487  mutt_error(_("Error processing certificate data"));
488  gnutls_x509_crt_deinit(cert);
489  return 0;
490  }
491 
492  add_cert(_("This certificate belongs to:"), cert, false, &list);
493  mutt_list_insert_tail(&list, NULL);
494  add_cert(_("This certificate was issued by:"), cert, true, &list);
495 
496  mutt_list_insert_tail(&list, NULL);
497  mutt_list_insert_tail(&list, mutt_str_dup(_("This certificate is valid")));
498 
499  char *line = NULL;
500  t = gnutls_x509_crt_get_activation_time(cert);
501  mutt_date_make_tls(datestr, sizeof(datestr), t);
502  mutt_str_asprintf(&line, _(" from %s"), datestr);
503  mutt_list_insert_tail(&list, line);
504 
505  t = gnutls_x509_crt_get_expiration_time(cert);
506  mutt_date_make_tls(datestr, sizeof(datestr), t);
507  mutt_str_asprintf(&line, _(" to %s"), datestr);
508  mutt_list_insert_tail(&list, line);
509  mutt_list_insert_tail(&list, NULL);
510 
511  fpbuf[0] = '\0';
512  tls_fingerprint(GNUTLS_DIG_SHA, fpbuf, sizeof(fpbuf), certdata);
513  mutt_str_asprintf(&line, _("SHA1 Fingerprint: %s"), fpbuf);
514  mutt_list_insert_tail(&list, line);
515  fpbuf[0] = '\0';
516  fpbuf[40] = '\0'; /* Ensure the second printed line is null terminated */
517  tls_fingerprint(GNUTLS_DIG_SHA256, fpbuf, sizeof(fpbuf), certdata);
518  fpbuf[39] = '\0'; /* Divide into two lines of output */
519  mutt_str_asprintf(&line, "%s%s", _("SHA256 Fingerprint: "), fpbuf);
520  mutt_list_insert_tail(&list, line);
521  mutt_str_asprintf(&line, "%*s%s", (int) mutt_str_len(_("SHA256 Fingerprint: ")),
522  "", fpbuf + 40);
523  mutt_list_insert_tail(&list, line);
524 
525  if (certerr)
526  mutt_list_insert_tail(&list, NULL);
527 
528  if (certerr & CERTERR_NOTYETVALID)
529  {
531  &list, mutt_str_dup(_("WARNING: Server certificate is not yet valid")));
532  }
533  if (certerr & CERTERR_EXPIRED)
534  {
536  &list, mutt_str_dup(_("WARNING: Server certificate has expired")));
537  }
538  if (certerr & CERTERR_REVOKED)
539  {
541  &list, mutt_str_dup(_("WARNING: Server certificate has been revoked")));
542  }
543  if (certerr & CERTERR_HOSTNAME)
544  {
546  &list,
547  mutt_str_dup(_("WARNING: Server hostname does not match certificate")));
548  }
549  if (certerr & CERTERR_SIGNERNOTCA)
550  {
552  &list,
553  mutt_str_dup(_("WARNING: Signer of server certificate is not a CA")));
554  }
555  if (certerr & CERTERR_INSECUREALG)
556  {
558  &list, mutt_str_dup(_("Warning: Server certificate was signed using "
559  "an insecure algorithm")));
560  }
561 
562  snprintf(title, sizeof(title),
563  _("SSL Certificate check (certificate %zu of %zu in chain)"), len - idx, len);
564 
565  const bool allow_always =
566  (C_CertificateFile && !savedcert &&
567  !(certerr & (CERTERR_EXPIRED | CERTERR_NOTYETVALID | CERTERR_REVOKED)));
568  int rc = dlg_verify_cert(title, &list, allow_always, false);
569  if (rc == 3) // Accept always
570  {
571  bool saved = false;
572  FILE *fp = mutt_file_fopen(C_CertificateFile, "a");
573  if (fp)
574  {
575  if (certerr & CERTERR_HOSTNAME) // Save hostname if necessary
576  {
577  fpbuf[0] = '\0';
578  tls_fingerprint(GNUTLS_DIG_MD5, fpbuf, sizeof(fpbuf), certdata);
579  fprintf(fp, "#H %s %s\n", hostname, fpbuf);
580  saved = true;
581  }
582  if (certerr ^ CERTERR_HOSTNAME) // Save the cert for all other errors
583  {
584  int rc2 = gnutls_pem_base64_encode_alloc("CERTIFICATE", certdata, &pemdata);
585  if (rc2 == 0)
586  {
587  if (fwrite(pemdata.data, pemdata.size, 1, fp) == 1)
588  {
589  saved = true;
590  }
591  gnutls_free(pemdata.data);
592  }
593  }
594  mutt_file_fclose(&fp);
595  }
596  if (!saved)
597  mutt_message(_("Certificate saved"));
598  else
599  mutt_error(_("Warning: Couldn't save certificate"));
600  }
601 
602  mutt_list_free(&list);
603  gnutls_x509_crt_deinit(cert);
604  return (rc > 1);
605 }
const char * C_CertificateFile
Config: File containing trusted certificates.
Definition: conn_globals.c:37
#define CERTERR_INSECUREALG
Definition: gnutls.c:54
static void tls_fingerprint(gnutls_digest_algorithm_t algo, char *buf, size_t buflen, const gnutls_datum_t *data)
Create a fingerprint of a TLS Certificate.
Definition: gnutls.c:157
int dlg_verify_cert(const char *title, struct ListHead *list, bool allow_always, bool allow_skip)
Ask the user to validate the certificate.
Definition: gui.c:58
#define mutt_message(...)
Definition: logging.h:83
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
#define CERTERR_REVOKED
Definition: gnutls.c:50
#define _(a)
Definition: message.h:28
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
static void add_cert(const char *title, gnutls_x509_crt_t cert, bool issuer, struct ListHead *list)
Look up certificate info and save it to a list.
Definition: gnutls.c:417
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.
Definition: gnutls.c:307
int mutt_date_make_tls(char *buf, size_t buflen, time_t timestamp)
Format date in TLS certificate verification style.
Definition: date.c:570
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define CERTERR_EXPIRED
Definition: gnutls.c:48
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
#define CERTERR_NOTYETVALID
Definition: gnutls.c:49
#define CERTERR_HOSTNAME
Definition: gnutls.c:52
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:639
#define mutt_error(...)
Definition: logging.h:84
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1103
int const char int line
Definition: acutest.h:617
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
#define CERTERR_SIGNERNOTCA
Definition: gnutls.c:53
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_check_certificate()

static int tls_check_certificate ( struct Connection conn)
static

Check a connection's certificate.

Parameters
connConnection to a server
Return values
1Certificate is valid
0Error, or certificate is invalid

Definition at line 613 of file gnutls.c.

614 {
615  struct TlsSockData *data = conn->sockdata;
616  gnutls_session_t state = data->state;
617  const gnutls_datum_t *cert_list = NULL;
618  unsigned int cert_list_size = 0;
619  gnutls_certificate_status_t certstat;
620  int certerr, savedcert, rc = 0;
621  int max_preauth_pass = -1;
622 
623  /* tls_verify_peers() calls gnutls_certificate_verify_peers2(),
624  * which verifies the auth_type is GNUTLS_CRD_CERTIFICATE
625  * and that get_certificate_type() for the server is GNUTLS_CRT_X509.
626  * If it returns 0, certstat will be set with failure codes for the first
627  * cert in the chain(from CA to host) with an error.
628  */
629  if (tls_verify_peers(state, &certstat) != 0)
630  return 0;
631 
632  cert_list = gnutls_certificate_get_peers(state, &cert_list_size);
633  if (!cert_list)
634  {
635  mutt_error(_("Unable to get certificate from peer"));
636  return 0;
637  }
638 
639  /* tls_verify_peers doesn't check hostname or expiration, so walk
640  * from most specific to least checking these. If we see a saved certificate,
641  * its status short-circuits the remaining checks. */
642  int preauthrc = 0;
643  for (int i = 0; i < cert_list_size; i++)
644  {
645  rc = tls_check_preauth(&cert_list[i], certstat, conn->account.host, i,
646  &certerr, &savedcert);
647  preauthrc += rc;
648  if (!preauthrc)
649  max_preauth_pass = i;
650 
651  if (savedcert)
652  {
653  if (preauthrc == 0)
654  return 1;
655  break;
656  }
657  }
658 
659  /* then check interactively, starting from chain root */
660  for (int i = cert_list_size - 1; i >= 0; i--)
661  {
662  rc = tls_check_one_certificate(&cert_list[i], certstat, conn->account.host,
663  i, cert_list_size);
664 
665  /* Stop checking if the menu cert is aborted or rejected. */
666  if (rc == 0)
667  break;
668 
669  /* add signers to trust set, then reverify */
670  if (i)
671  {
672  int rcsettrust = gnutls_certificate_set_x509_trust_mem(
673  data->xcred, &cert_list[i], GNUTLS_X509_FMT_DER);
674  if (rcsettrust != 1)
675  mutt_debug(LL_DEBUG1, "error trusting certificate %d: %d\n", i, rcsettrust);
676 
677  if (tls_verify_peers(state, &certstat) != 0)
678  return 0;
679 
680  /* If the cert chain now verifies, and all lower certs already
681  * passed preauth, we are done. */
682  if (!certstat && (max_preauth_pass >= (i - 1)))
683  return 1;
684  }
685  }
686 
687  return rc;
688 }
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
#define _(a)
Definition: message.h:28
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.
Definition: gnutls.c:462
gnutls_session_t state
Definition: gnutls.c:80
char host[128]
Server to login to.
Definition: connaccount.h:53
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.
Definition: gnutls.c:307
gnutls_certificate_credentials_t xcred
Definition: gnutls.c:81
TLS socket data.
Definition: gnutls.c:78
Log at debug level 1.
Definition: logging.h:40
#define mutt_error(...)
Definition: logging.h:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static int tls_verify_peers(gnutls_session_t tlsstate, gnutls_certificate_status_t *certstat)
Wrapper for gnutls_certificate_verify_peers()
Definition: gnutls.c:119
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_get_client_cert()

static void tls_get_client_cert ( struct Connection conn)
static

Get the client certificate for a TLS connection.

Parameters
connConnection to a server

Definition at line 694 of file gnutls.c.

695 {
696  struct TlsSockData *data = conn->sockdata;
697  gnutls_x509_crt_t clientcrt;
698  char *dn = NULL;
699  char *cn = NULL;
700  char *cnend = NULL;
701  size_t dnlen;
702 
703  /* get our cert CN if we have one */
704  const gnutls_datum_t *crtdata = gnutls_certificate_get_ours(data->state);
705  if (!crtdata)
706  return;
707 
708  if (gnutls_x509_crt_init(&clientcrt) < 0)
709  {
710  mutt_debug(LL_DEBUG1, "Failed to init gnutls crt\n");
711  return;
712  }
713  if (gnutls_x509_crt_import(clientcrt, crtdata, GNUTLS_X509_FMT_DER) < 0)
714  {
715  mutt_debug(LL_DEBUG1, "Failed to import gnutls client crt\n");
716  goto err_crt;
717  }
718  /* get length of DN */
719  dnlen = 0;
720  gnutls_x509_crt_get_dn(clientcrt, NULL, &dnlen);
721  dn = mutt_mem_calloc(1, dnlen);
722 
723  gnutls_x509_crt_get_dn(clientcrt, dn, &dnlen);
724  mutt_debug(LL_DEBUG2, "client certificate DN: %s\n", dn);
725 
726  /* extract CN to use as external user name */
727  cn = strstr(dn, "CN=");
728  if (!cn)
729  {
730  mutt_debug(LL_DEBUG1, "no CN found in DN\n");
731  goto err_dn;
732  }
733 
734  cnend = strstr(dn, ",EMAIL=");
735  if (cnend)
736  *cnend = '\0';
737 
738  /* if we are using a client cert, SASL may expect an external auth name */
739  if (mutt_account_getuser(&conn->account) < 0)
740  mutt_debug(LL_DEBUG1, "Couldn't get user info\n");
741 
742 err_dn:
743  FREE(&dn);
744 err_crt:
745  gnutls_x509_crt_deinit(clientcrt);
746 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
int mutt_account_getuser(struct ConnAccount *cac)
Retrieve username into ConnAccount, if necessary.
Definition: connaccount.c:47
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
gnutls_session_t state
Definition: gnutls.c:80
Log at debug level 2.
Definition: logging.h:41
TLS socket data.
Definition: gnutls.c:78
Log at debug level 1.
Definition: logging.h:40
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_set_priority()

static int tls_set_priority ( struct TlsSockData data)
static

Set the priority of various protocols.

Parameters
dataTLS socket data
Return values
0Success
-1Error

Definition at line 821 of file gnutls.c.

822 {
823  size_t nproto = 0; /* number of tls/ssl protocols */
824 
825  if (C_SslUseTlsv12)
826  protocol_priority[nproto++] = GNUTLS_TLS1_2;
827  if (C_SslUseTlsv11)
828  protocol_priority[nproto++] = GNUTLS_TLS1_1;
829  if (C_SslUseTlsv1)
830  protocol_priority[nproto++] = GNUTLS_TLS1;
831  if (C_SslUseSslv3)
832  protocol_priority[nproto++] = GNUTLS_SSL3;
833  protocol_priority[nproto] = 0;
834 
835  if (nproto == 0)
836  {
837  mutt_error(_("All available protocols for TLS/SSL connection disabled"));
838  return -1;
839  }
840 
841  if (C_SslCiphers)
842  {
843  mutt_error(
844  _("Explicit ciphersuite selection via $ssl_ciphers not supported"));
845  }
846  if (certerr & CERTERR_INSECUREALG)
847  {
848  row++;
849  strfcpy(menu->dialog[row], _("Warning: Server certificate was signed using an insecure algorithm"),
851  }
852 
853  /* We use default priorities (see gnutls documentation),
854  * except for protocol version */
855  gnutls_set_default_priority(data->state);
856  gnutls_protocol_set_priority(data->state, protocol_priority);
857  return 0;
858 }
#define CERTERR_INSECUREALG
Definition: gnutls.c:54
bool C_SslUseTlsv11
Config: (ssl) Use TLSv1.1 for authentication.
Definition: conn_globals.c:43
const char * C_SslCiphers
Config: Ciphers to use when using SSL.
Definition: conn_globals.c:39
#define _(a)
Definition: message.h:28
gnutls_session_t state
Definition: gnutls.c:80
bool C_SslUseTlsv12
Config: (ssl) Use TLSv1.2 for authentication.
Definition: conn_globals.c:44
bool C_SslUseSslv3
Config: (ssl) INSECURE: Use SSLv3 for authentication.
Definition: conn_globals.c:41
static int protocol_priority[]
Definition: gnutls.c:71
const int dialog_row_len
Definition: gnutls.c:58
bool C_SslUseTlsv1
Config: (ssl) Use TLSv1 for authentication.
Definition: conn_globals.c:42
#define mutt_error(...)
Definition: logging.h:84
+ Here is the caller graph for this function:

◆ tls_negotiate()

static int tls_negotiate ( struct Connection conn)
static

Negotiate TLS connection.

Parameters
connConnection to a server
Return values
0Success
-1Error

After TLS state has been initialized, attempt to negotiate TLS over the wire, including certificate checks.

Definition at line 870 of file gnutls.c.

871 {
872  struct TlsSockData *data = mutt_mem_calloc(1, sizeof(struct TlsSockData));
873  conn->sockdata = data;
874  int err = gnutls_certificate_allocate_credentials(&data->xcred);
875  if (err < 0)
876  {
877  FREE(&conn->sockdata);
878  mutt_error("gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
879  return -1;
880  }
881 
882  gnutls_certificate_set_x509_trust_file(data->xcred, C_CertificateFile, GNUTLS_X509_FMT_PEM);
883  /* ignore errors, maybe file doesn't exist yet */
884 
886  {
887  gnutls_certificate_set_x509_trust_file(data->xcred, C_SslCaCertificatesFile,
888  GNUTLS_X509_FMT_PEM);
889  }
890 
891  if (C_SslClientCert)
892  {
893  mutt_debug(LL_DEBUG2, "Using client certificate %s\n", C_SslClientCert);
894  gnutls_certificate_set_x509_key_file(data->xcred, C_SslClientCert,
895  C_SslClientCert, GNUTLS_X509_FMT_PEM);
896  }
897 
898 #ifdef HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS
899  /* disable checking certificate activation/expiration times
900  * in gnutls, we do the checks ourselves */
901  gnutls_certificate_set_verify_flags(data->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
902 #endif
903 
904  err = gnutls_init(&data->state, GNUTLS_CLIENT);
905  if (err)
906  {
907  mutt_error("gnutls_handshake: %s", gnutls_strerror(err));
908  goto fail;
909  }
910 
911  /* set socket */
912  gnutls_transport_set_ptr(data->state, (gnutls_transport_ptr_t)(long) conn->fd);
913 
914  if (gnutls_server_name_set(data->state, GNUTLS_NAME_DNS, conn->account.host,
915  mutt_str_len(conn->account.host)))
916  {
917  mutt_error(_("Warning: unable to set TLS SNI host name"));
918  }
919 
920  if (tls_set_priority(data) < 0)
921  {
922  goto fail;
923  }
924 
925  if (C_SslMinDhPrimeBits > 0)
926  {
927  gnutls_dh_set_prime_bits(data->state, C_SslMinDhPrimeBits);
928  }
929 
930  /* gnutls_set_cred (data->state, GNUTLS_ANON, NULL); */
931 
932  gnutls_credentials_set(data->state, GNUTLS_CRD_CERTIFICATE, data->xcred);
933 
934  err = gnutls_handshake(data->state);
935 
936  while (err == GNUTLS_E_AGAIN)
937  {
938  err = gnutls_handshake(data->state);
939  }
940  if (err < 0)
941  {
942  if (err == GNUTLS_E_FATAL_ALERT_RECEIVED)
943  {
944  mutt_error("gnutls_handshake: %s(%s)", gnutls_strerror(err),
945  gnutls_alert_get_name(gnutls_alert_get(data->state)));
946  }
947  else
948  {
949  mutt_error("gnutls_handshake: %s", gnutls_strerror(err));
950  }
951  goto fail;
952  }
953 
954  if (tls_check_certificate(conn) == 0)
955  goto fail;
956 
957  /* set Security Strength Factor (SSF) for SASL */
958  /* NB: gnutls_cipher_get_key_size() returns key length in bytes */
959  conn->ssf = gnutls_cipher_get_key_size(gnutls_cipher_get(data->state)) * 8;
960 
961  tls_get_client_cert(conn);
962 
963  if (!OptNoCurses)
964  {
965  mutt_message(_("SSL/TLS connection using %s (%s/%s/%s)"),
966  gnutls_protocol_get_name(gnutls_protocol_get_version(data->state)),
967  gnutls_kx_get_name(gnutls_kx_get(data->state)),
968  gnutls_cipher_get_name(gnutls_cipher_get(data->state)),
969  gnutls_mac_get_name(gnutls_mac_get(data->state)));
970  mutt_sleep(0);
971  }
972 
973  return 0;
974 
975 fail:
976  gnutls_certificate_free_credentials(data->xcred);
977  gnutls_deinit(data->state);
978  FREE(&conn->sockdata);
979  return -1;
980 }
const char * C_CertificateFile
Config: File containing trusted certificates.
Definition: conn_globals.c:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
const char * C_SslCaCertificatesFile
Config: File containing trusted CA certificates.
Definition: conn_globals.c:51
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
unsigned int ssf
Security strength factor, in bits (see below)
Definition: connection.h:37
#define mutt_message(...)
Definition: logging.h:83
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
static void tls_get_client_cert(struct Connection *conn)
Get the client certificate for a TLS connection.
Definition: gnutls.c:694
const char * C_SslClientCert
Config: File containing client certificates.
Definition: conn_globals.c:40
#define _(a)
Definition: message.h:28
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:48
gnutls_session_t state
Definition: gnutls.c:80
static int tls_set_priority(struct TlsSockData *data)
Set the priority of various protocols.
Definition: gnutls.c:821
static int tls_check_certificate(struct Connection *conn)
Check a connection&#39;s certificate.
Definition: gnutls.c:613
char host[128]
Server to login to.
Definition: connaccount.h:53
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1536
Log at debug level 2.
Definition: logging.h:41
gnutls_certificate_credentials_t xcred
Definition: gnutls.c:81
TLS socket data.
Definition: gnutls.c:78
int fd
Socket file descriptor.
Definition: connection.h:40
short C_SslMinDhPrimeBits
Config: Minimum keysize for Diffie-Hellman key exchange.
Definition: conn_globals.c:52
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:639
#define mutt_error(...)
Definition: logging.h:84
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_socket_poll()

static int tls_socket_poll ( struct Connection conn,
time_t  wait_secs 
)
static

Check whether a socket read would block - Implements Connection::poll()

Definition at line 985 of file gnutls.c.

986 {
987  struct TlsSockData *data = conn->sockdata;
988  if (!data)
989  return -1;
990 
991  if (gnutls_record_check_pending(data->state))
992  return 1;
993 
994  return raw_socket_poll(conn, wait_secs);
995 }
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
int raw_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block - Implements Connection::poll()
Definition: raw.c:330
gnutls_session_t state
Definition: gnutls.c:80
TLS socket data.
Definition: gnutls.c:78
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_socket_close()

static int tls_socket_close ( struct Connection conn)
static

Close a TLS socket - Implements Connection::close()

Definition at line 1000 of file gnutls.c.

1001 {
1002  struct TlsSockData *data = conn->sockdata;
1003  if (data)
1004  {
1005  /* shut down only the write half to avoid hanging waiting for the remote to respond.
1006  *
1007  * RFC5246 7.2.1. "Closure Alerts"
1008  *
1009  * It is not required for the initiator of the close to wait for the
1010  * responding close_notify alert before closing the read side of the
1011  * connection. */
1012  gnutls_bye(data->state, GNUTLS_SHUT_WR);
1013 
1014  gnutls_certificate_free_credentials(data->xcred);
1015  gnutls_deinit(data->state);
1016  FREE(&conn->sockdata);
1017  }
1018 
1019  return raw_socket_close(conn);
1020 }
int raw_socket_close(struct Connection *conn)
Close a socket - Implements Connection::close()
Definition: raw.c:368
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
gnutls_session_t state
Definition: gnutls.c:80
gnutls_certificate_credentials_t xcred
Definition: gnutls.c:81
TLS socket data.
Definition: gnutls.c:78
#define FREE(x)
Definition: memory.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_socket_open()

static int tls_socket_open ( struct Connection conn)
static

Open a TLS socket - Implements Connection::open()

Definition at line 1025 of file gnutls.c.

1026 {
1027  if (raw_socket_open(conn) < 0)
1028  return -1;
1029 
1030  if (tls_negotiate(conn) < 0)
1031  {
1032  tls_socket_close(conn);
1033  return -1;
1034  }
1035 
1036  return 0;
1037 }
static int tls_negotiate(struct Connection *conn)
Negotiate TLS connection.
Definition: gnutls.c:870
int raw_socket_open(struct Connection *conn)
Open a socket - Implements Connection::open()
Definition: raw.c:124
static int tls_socket_close(struct Connection *conn)
Close a TLS socket - Implements Connection::close()
Definition: gnutls.c:1000
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_socket_read()

static int tls_socket_read ( struct Connection conn,
char *  buf,
size_t  count 
)
static

Read data from a TLS socket - Implements Connection::read()

Definition at line 1042 of file gnutls.c.

1043 {
1044  struct TlsSockData *data = conn->sockdata;
1045  if (!data)
1046  {
1047  mutt_error(_("Error: no TLS socket open"));
1048  return -1;
1049  }
1050 
1051  int rc;
1052  do
1053  {
1054  rc = gnutls_record_recv(data->state, buf, count);
1055  } while ((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED));
1056 
1057  if (rc < 0)
1058  {
1059  mutt_error("tls_socket_read (%s)", gnutls_strerror(rc));
1060  return -1;
1061  }
1062 
1063  return rc;
1064 }
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
#define _(a)
Definition: message.h:28
gnutls_session_t state
Definition: gnutls.c:80
TLS socket data.
Definition: gnutls.c:78
#define mutt_error(...)
Definition: logging.h:84
+ Here is the caller graph for this function:

◆ tls_socket_write()

static int tls_socket_write ( struct Connection conn,
const char *  buf,
size_t  count 
)
static

Write data to a TLS socket - Implements Connection::write()

Definition at line 1069 of file gnutls.c.

1070 {
1071  struct TlsSockData *data = conn->sockdata;
1072  size_t sent = 0;
1073 
1074  if (!data)
1075  {
1076  mutt_error(_("Error: no TLS socket open"));
1077  return -1;
1078  }
1079 
1080  do
1081  {
1082  int ret;
1083  do
1084  {
1085  ret = gnutls_record_send(data->state, buf + sent, count - sent);
1086  } while ((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED));
1087 
1088  if (ret < 0)
1089  {
1090  mutt_error("tls_socket_write (%s)", gnutls_strerror(ret));
1091  return -1;
1092  }
1093 
1094  sent += ret;
1095  } while (sent < count);
1096 
1097  return sent;
1098 }
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
#define _(a)
Definition: message.h:28
gnutls_session_t state
Definition: gnutls.c:80
TLS socket data.
Definition: gnutls.c:78
#define mutt_error(...)
Definition: logging.h:84
+ Here is the caller graph for this function:

◆ tls_starttls_close()

static int tls_starttls_close ( struct Connection conn)
static

Close a TLS connection - Implements Connection::close()

Definition at line 1103 of file gnutls.c.

1104 {
1105  int rc;
1106 
1107  rc = tls_socket_close(conn);
1108  conn->read = raw_socket_read;
1109  conn->write = raw_socket_write;
1110  conn->close = raw_socket_close;
1111  conn->poll = raw_socket_poll;
1112 
1113  return rc;
1114 }
int raw_socket_close(struct Connection *conn)
Close a socket - Implements Connection::close()
Definition: raw.c:368
int(* read)(struct Connection *conn, char *buf, size_t count)
Read from a socket Connection.
Definition: connection.h:72
int raw_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block - Implements Connection::poll()
Definition: raw.c:330
int raw_socket_write(struct Connection *conn, const char *buf, size_t count)
Write data to a socket - Implements Connection::write()
Definition: raw.c:300
int(* close)(struct Connection *conn)
Close a socket Connection.
Definition: connection.h:100
int raw_socket_read(struct Connection *conn, char *buf, size_t len)
Read data from a socket - Implements Connection::read()
Definition: raw.c:270
int(* poll)(struct Connection *conn, time_t wait_secs)
Check whether a socket read would block.
Definition: connection.h:92
int(* write)(struct Connection *conn, const char *buf, size_t count)
Write to a socket Connection.
Definition: connection.h:82
static int tls_socket_close(struct Connection *conn)
Close a TLS socket - Implements Connection::close()
Definition: gnutls.c:1000
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_ssl_socket_setup()

int mutt_ssl_socket_setup ( struct Connection conn)

Set up SSL socket mulitplexor.

Parameters
connConnection to a server
Return values
0Success
-1Error

Definition at line 1122 of file gnutls.c.

1123 {
1124  if (tls_init() < 0)
1125  return -1;
1126 
1127  conn->open = tls_socket_open;
1128  conn->read = tls_socket_read;
1129  conn->write = tls_socket_write;
1130  conn->close = tls_socket_close;
1131  conn->poll = tls_socket_poll;
1132 
1133  return 0;
1134 }
int(* read)(struct Connection *conn, char *buf, size_t count)
Read from a socket Connection.
Definition: connection.h:72
static int tls_socket_write(struct Connection *conn, const char *buf, size_t count)
Write data to a TLS socket - Implements Connection::write()
Definition: gnutls.c:1069
static int tls_socket_read(struct Connection *conn, char *buf, size_t count)
Read data from a TLS socket - Implements Connection::read()
Definition: gnutls.c:1042
int(* open)(struct Connection *conn)
Note about ssf: in actuality, NeoMutt uses this as a boolean to determine if the connection is "secur...
Definition: connection.h:62
static int tls_socket_poll(struct Connection *conn, time_t wait_secs)
Check whether a socket read would block - Implements Connection::poll()
Definition: gnutls.c:985
int(* close)(struct Connection *conn)
Close a socket Connection.
Definition: connection.h:100
static int tls_socket_open(struct Connection *conn)
Open a TLS socket - Implements Connection::open()
Definition: gnutls.c:1025
static int tls_init(void)
Set up Gnu TLS.
Definition: gnutls.c:89
int(* poll)(struct Connection *conn, time_t wait_secs)
Check whether a socket read would block.
Definition: connection.h:92
int(* write)(struct Connection *conn, const char *buf, size_t count)
Write to a socket Connection.
Definition: connection.h:82
static int tls_socket_close(struct Connection *conn)
Close a TLS socket - Implements Connection::close()
Definition: gnutls.c:1000
+ Here is the caller graph for this function:

◆ mutt_ssl_starttls()

int mutt_ssl_starttls ( struct Connection conn)

Negotiate TLS over an already opened connection.

Parameters
connConnection to a server
Return values
0Success
-1Error

Definition at line 1142 of file gnutls.c.

1143 {
1144  if (tls_init() < 0)
1145  return -1;
1146 
1147  if (tls_negotiate(conn) < 0)
1148  return -1;
1149 
1150  conn->read = tls_socket_read;
1151  conn->write = tls_socket_write;
1152  conn->close = tls_starttls_close;
1153  conn->poll = tls_socket_poll;
1154 
1155  return 0;
1156 }
int(* read)(struct Connection *conn, char *buf, size_t count)
Read from a socket Connection.
Definition: connection.h:72
static int tls_socket_write(struct Connection *conn, const char *buf, size_t count)
Write data to a TLS socket - Implements Connection::write()
Definition: gnutls.c:1069
static int tls_negotiate(struct Connection *conn)
Negotiate TLS connection.
Definition: gnutls.c:870
static int tls_socket_read(struct Connection *conn, char *buf, size_t count)
Read data from a TLS socket - Implements Connection::read()
Definition: gnutls.c:1042
static int tls_socket_poll(struct Connection *conn, time_t wait_secs)
Check whether a socket read would block - Implements Connection::poll()
Definition: gnutls.c:985
int(* close)(struct Connection *conn)
Close a socket Connection.
Definition: connection.h:100
static int tls_starttls_close(struct Connection *conn)
Close a TLS connection - Implements Connection::close()
Definition: gnutls.c:1103
static int tls_init(void)
Set up Gnu TLS.
Definition: gnutls.c:89
int(* poll)(struct Connection *conn, time_t wait_secs)
Check whether a socket read would block.
Definition: connection.h:92
int(* write)(struct Connection *conn, const char *buf, size_t count)
Write to a socket Connection.
Definition: connection.h:82
+ Here is the caller graph for this function:

Variable Documentation

◆ dialog_row_len

const int dialog_row_len = 128

Definition at line 58 of file gnutls.c.

◆ protocol_priority

int protocol_priority[]
static
Initial value:
= { GNUTLS_TLS1_2, GNUTLS_TLS1_1, GNUTLS_TLS1,
GNUTLS_SSL3, 0 }

Definition at line 71 of file gnutls.c.