NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 <time.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "lib.h"
#include "connaccount.h"
#include "connection.h"
#include "globals.h"
#include "muttlib.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
 Certificate is valid.
 
#define CERTERR_EXPIRED   (1 << 0)
 Certificate is expired.
 
#define CERTERR_NOTYETVALID   (1 << 1)
 Certificate is not yet valid.
 
#define CERTERR_REVOKED   (1 << 2)
 Certificate has been revoked.
 
#define CERTERR_NOTTRUSTED   (1 << 3)
 Certificate issuer is not trusted.
 
#define CERTERR_HOSTNAME   (1 << 4)
 Certificate hostname does not match.
 
#define CERTERR_SIGNERNOTCA   (1 << 5)
 Certificate signer is not a CA.
 
#define CERTERR_INSECUREALG   (1 << 6)
 Certificate uses insecure algorithm.
 
#define CERTERR_OTHER   (1 << 7)
 Other certificate error.
 
#define CERT_SEP   "-----BEGIN"
 Certificate separator string.
 

Functions

int gnutls_protocol_set_priority (gnutls_session_t session, const int *list)
 
static int tls_init (void)
 Set up Gnu TLS.
 
static int tls_verify_peers (gnutls_session_t tlsstate, gnutls_certificate_status_t *certstat)
 Wrapper for gnutls_certificate_verify_peers()
 
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 bool tls_check_stored_hostname (const gnutls_datum_t *cert, const char *hostname)
 Does the hostname match a stored certificate?
 
static bool tls_compare_certificates (const gnutls_datum_t *peercert)
 Compare certificates against $certificate_file
 
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 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 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_check_certificate (struct Connection *conn)
 Check a connection's certificate.
 
static void tls_get_client_cert (struct Connection *conn)
 Get the client certificate for a TLS connection.
 
static int tls_set_priority (struct TlsSockData *data)
 Set the priority of various protocols.
 
static bool tls_socket_poll_with_timeout (struct Connection *conn)
 Poll a socket with configured timeout.
 
static int tls_negotiate (struct Connection *conn)
 Negotiate TLS connection.
 
static int tls_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_close (struct Connection *conn)
 Close a TLS socket - Implements Connection::close() -.
 
static int tls_socket_open (struct Connection *conn)
 Open a TLS socket - Implements Connection::open() -.
 
static int tls_socket_read (struct Connection *conn, char *buf, size_t count)
 Read data from a TLS socket - Implements Connection::read() -.
 
static int tls_socket_write (struct Connection *conn, const char *buf, size_t count)
 Write data to a TLS socket - Implements Connection::write() -.
 
static int tls_starttls_close (struct Connection *conn)
 Close a TLS connection - Implements Connection::close() -.
 
int mutt_ssl_socket_setup (struct Connection *conn)
 Set up SSL socket mulitplexor.
 
int mutt_ssl_starttls (struct Connection *conn)
 Negotiate TLS over an already opened connection.
 

Variables

static int ProtocolPriority [] = { GNUTLS_TLS1_2, GNUTLS_TLS1_1, GNUTLS_TLS1, GNUTLS_SSL3, 0 }
 This array needs to be large enough to hold all the possible values support by NeoMutt.
 

Detailed Description

Handling of GnuTLS encryption.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Alejandro Colomar

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

Certificate is valid.

Definition at line 53 of file gnutls.c.

◆ CERTERR_EXPIRED

#define CERTERR_EXPIRED   (1 << 0)

Certificate is expired.

Definition at line 54 of file gnutls.c.

◆ CERTERR_NOTYETVALID

#define CERTERR_NOTYETVALID   (1 << 1)

Certificate is not yet valid.

Definition at line 55 of file gnutls.c.

◆ CERTERR_REVOKED

#define CERTERR_REVOKED   (1 << 2)

Certificate has been revoked.

Definition at line 56 of file gnutls.c.

◆ CERTERR_NOTTRUSTED

#define CERTERR_NOTTRUSTED   (1 << 3)

Certificate issuer is not trusted.

Definition at line 57 of file gnutls.c.

◆ CERTERR_HOSTNAME

#define CERTERR_HOSTNAME   (1 << 4)

Certificate hostname does not match.

Definition at line 58 of file gnutls.c.

◆ CERTERR_SIGNERNOTCA

#define CERTERR_SIGNERNOTCA   (1 << 5)

Certificate signer is not a CA.

Definition at line 59 of file gnutls.c.

◆ CERTERR_INSECUREALG

#define CERTERR_INSECUREALG   (1 << 6)

Certificate uses insecure algorithm.

Definition at line 60 of file gnutls.c.

◆ CERTERR_OTHER

#define CERTERR_OTHER   (1 << 7)

Other certificate error.

Definition at line 61 of file gnutls.c.

◆ CERT_SEP

#define CERT_SEP   "-----BEGIN"

Certificate separator string.

Definition at line 65 of file gnutls.c.

Function Documentation

◆ gnutls_protocol_set_priority()

int gnutls_protocol_set_priority ( gnutls_session_t session,
const int * list )
+ Here is the caller graph for this function:

◆ tls_init()

static int tls_init ( void )
static

Set up Gnu TLS.

Return values
0Success
-1Error

Definition at line 93 of file gnutls.c.

94{
95 static bool init_complete = false;
96 int err;
97
98 if (init_complete)
99 return 0;
100
101 err = gnutls_global_init();
102 if (err < 0)
103 {
104 mutt_error("gnutls_global_init: %s", gnutls_strerror(err));
105 return -1;
106 }
107
108 init_complete = true;
109 return 0;
110}
#define mutt_error(...)
Definition logging2.h:94
+ 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 123 of file gnutls.c.

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

◆ tls_fingerprint()

static void tls_fingerprint ( gnutls_digest_algorithm_t algo,
struct Buffer * buf,
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
dataCertificate

Definition at line 160 of file gnutls.c.

162{
163 unsigned char md[128] = { 0 };
164 size_t n = 64;
165
166 if (gnutls_fingerprint(algo, data, (char *) md, &n) < 0)
167 {
168 buf_strcpy(buf, _("[unable to calculate]"));
169 return;
170 }
171
172 for (size_t i = 0; i < n; i++)
173 {
174 buf_add_printf(buf, "%02X", md[i]);
175
176 // Put a space after a pair of bytes (except for the last one)
177 if (((i % 2) == 1) && (i < (n - 1)))
178 buf_addch(buf, ' ');
179 }
180}
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_check_stored_hostname()

static bool 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
trueHostname match found
falseError, or no match

Definition at line 189 of file gnutls.c.

190{
191 char *linestr = NULL;
192 size_t linestrsize = 0;
193
194 /* try checking against names stored in stored certs file */
195 const char *const c_certificate_file = cs_subset_path(NeoMutt->sub, "certificate_file");
196 FILE *fp = mutt_file_fopen(c_certificate_file, "r");
197 if (!fp)
198 return false;
199
200 struct Buffer *buf = buf_pool_get();
201
202 tls_fingerprint(GNUTLS_DIG_MD5, buf, cert);
203 while ((linestr = mutt_file_read_line(linestr, &linestrsize, fp, NULL, MUTT_RL_NO_FLAGS)))
204 {
205 regmatch_t *match = mutt_prex_capture(PREX_GNUTLS_CERT_HOST_HASH, linestr);
206 if (match)
207 {
208 regmatch_t *mhost = &match[PREX_GNUTLS_CERT_HOST_HASH_MATCH_HOST];
209 regmatch_t *mhash = &match[PREX_GNUTLS_CERT_HOST_HASH_MATCH_HASH];
210 linestr[mutt_regmatch_end(mhost)] = '\0';
211 linestr[mutt_regmatch_end(mhash)] = '\0';
212 if ((mutt_str_equal(linestr + mutt_regmatch_start(mhost), hostname)) &&
213 (mutt_str_equal(linestr + mutt_regmatch_start(mhash), buf_string(buf))))
214 {
215 FREE(&linestr);
216 mutt_file_fclose(&fp);
217 buf_pool_release(&buf);
218 return true;
219 }
220 }
221 }
222
223 mutt_file_fclose(&fp);
224 buf_pool_release(&buf);
225
226 /* not found a matching name */
227 return false;
228}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition file.c:678
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition file.h:40
static void tls_fingerprint(gnutls_digest_algorithm_t algo, struct Buffer *buf, const gnutls_datum_t *data)
Create a fingerprint of a TLS Certificate.
Definition gnutls.c:160
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
Match a precompiled regex against a string.
Definition prex.c:301
@ PREX_GNUTLS_CERT_HOST_HASH
[#H foo.com A76D 954B EB79 1F49 5B3A 0A0E 0681 65B1]
Definition prex.h:37
@ PREX_GNUTLS_CERT_HOST_HASH_MATCH_HASH
#H foo.com [A76D ... 65B1]
Definition prex.h:112
@ PREX_GNUTLS_CERT_HOST_HASH_MATCH_HOST
#H [foo.com] A76D ... 65B1
Definition prex.h:111
static regoff_t mutt_regmatch_end(const regmatch_t *match)
Return the end of a match.
Definition regex3.h:66
static regoff_t mutt_regmatch_start(const regmatch_t *match)
Return the start of a match.
Definition regex3.h:56
String manipulation buffer.
Definition buffer.h:36
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_compare_certificates()

static bool tls_compare_certificates ( const gnutls_datum_t * peercert)
static

Compare certificates against $certificate_file

Parameters
peercertCertificate
Return values
trueCertificate matches file
falseError, or no match

Definition at line 236 of file gnutls.c.

237{
238 gnutls_datum_t cert = { 0 };
239 unsigned char *ptr = NULL;
240 gnutls_datum_t b64_data = { 0 };
241 unsigned char *b64_data_data = NULL;
242 struct stat st = { 0 };
243
244 const char *const c_certificate_file = cs_subset_path(NeoMutt->sub, "certificate_file");
245 if (stat(c_certificate_file, &st) == -1)
246 return false;
247
248 b64_data.size = st.st_size;
249 b64_data_data = MUTT_MEM_CALLOC(b64_data.size + 1, unsigned char);
250 b64_data.data = b64_data_data;
251
252 FILE *fp = mutt_file_fopen(c_certificate_file, "r");
253 if (!fp)
254 {
255 FREE(&b64_data_data);
256 return false;
257 }
258
259 b64_data.size = fread(b64_data.data, 1, b64_data.size, fp);
260 b64_data.data[b64_data.size] = '\0';
261 mutt_file_fclose(&fp);
262
263 do
264 {
265 const int rc = gnutls_pem_base64_decode_alloc(NULL, &b64_data, &cert);
266 if (rc != 0)
267 {
268 FREE(&b64_data_data);
269 return false;
270 }
271
272 /* find start of cert, skipping junk */
273 ptr = (unsigned char *) strstr((char *) b64_data.data, CERT_SEP);
274 if (!ptr)
275 {
276 gnutls_free(cert.data);
277 FREE(&b64_data_data);
278 return false;
279 }
280 /* find start of next cert */
281 ptr = (unsigned char *) strstr((char *) ptr + 1, CERT_SEP);
282
283 b64_data.size = b64_data.size - (ptr - b64_data.data);
284 b64_data.data = ptr;
285
286 if (cert.size == peercert->size)
287 {
288 if (memcmp(cert.data, peercert->data, cert.size) == 0)
289 {
290 /* match found */
291 gnutls_free(cert.data);
292 FREE(&b64_data_data);
293 return true;
294 }
295 }
296
297 gnutls_free(cert.data);
298 } while (ptr);
299
300 /* no match found */
301 FREE(&b64_data_data);
302 return false;
303}
#define CERT_SEP
Certificate separator string.
Definition gnutls.c:65
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
+ 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 316 of file gnutls.c.

319{
320 gnutls_x509_crt_t cert;
321
322 *certerr = CERTERR_VALID;
323 *savedcert = 0;
324
325 if (gnutls_x509_crt_init(&cert) < 0)
326 {
327 mutt_error(_("Error initialising gnutls certificate data"));
328 return -1;
329 }
330
331 if (gnutls_x509_crt_import(cert, certdata, GNUTLS_X509_FMT_DER) < 0)
332 {
333 mutt_error(_("Error processing certificate data"));
334 gnutls_x509_crt_deinit(cert);
335 return -1;
336 }
337
338 /* Note: tls_negotiate() contains a call to
339 * gnutls_certificate_set_verify_flags() with a flag disabling
340 * GnuTLS checking of the dates. So certstat shouldn't have the
341 * GNUTLS_CERT_EXPIRED and GNUTLS_CERT_NOT_ACTIVATED bits set. */
342 const bool c_ssl_verify_dates = cs_subset_bool(NeoMutt->sub, "ssl_verify_dates");
343 if (c_ssl_verify_dates != MUTT_NO)
344 {
345 if (gnutls_x509_crt_get_expiration_time(cert) < mutt_date_now())
346 *certerr |= CERTERR_EXPIRED;
347 if (gnutls_x509_crt_get_activation_time(cert) > mutt_date_now())
348 *certerr |= CERTERR_NOTYETVALID;
349 }
350
351 const bool c_ssl_verify_host = cs_subset_bool(NeoMutt->sub, "ssl_verify_host");
352 if ((chainidx == 0) && (c_ssl_verify_host != MUTT_NO) &&
353 !gnutls_x509_crt_check_hostname(cert, hostname) &&
354 !tls_check_stored_hostname(certdata, hostname))
355 {
356 *certerr |= CERTERR_HOSTNAME;
357 }
358
359 if (certstat & GNUTLS_CERT_REVOKED)
360 {
361 *certerr |= CERTERR_REVOKED;
362 certstat ^= GNUTLS_CERT_REVOKED;
363 }
364
365 /* see whether certificate is in our cache (certificates file) */
366 if (tls_compare_certificates(certdata))
367 {
368 *savedcert = 1;
369
370 /* We check above for certs with bad dates or that are revoked.
371 * These must be accepted manually each time. Otherwise, we
372 * accept saved certificates as valid. */
373 if (*certerr == CERTERR_VALID)
374 {
375 gnutls_x509_crt_deinit(cert);
376 return 0;
377 }
378 }
379
380 if (certstat & GNUTLS_CERT_INVALID)
381 {
382 *certerr |= CERTERR_NOTTRUSTED;
383 certstat ^= GNUTLS_CERT_INVALID;
384 }
385
386 if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
387 {
388 /* NB: already cleared if cert in cache */
389 *certerr |= CERTERR_NOTTRUSTED;
390 certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
391 }
392
393 if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
394 {
395 /* NB: already cleared if cert in cache */
396 *certerr |= CERTERR_SIGNERNOTCA;
397 certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
398 }
399
400 if (certstat & GNUTLS_CERT_INSECURE_ALGORITHM)
401 {
402 /* NB: already cleared if cert in cache */
403 *certerr |= CERTERR_INSECUREALG;
404 certstat ^= GNUTLS_CERT_INSECURE_ALGORITHM;
405 }
406
407 /* we've been zeroing the interesting bits in certstat -
408 * don't return OK if there are any unhandled bits we don't
409 * understand */
410 if (certstat != 0)
411 *certerr |= CERTERR_OTHER;
412
413 gnutls_x509_crt_deinit(cert);
414
415 if (*certerr == CERTERR_VALID)
416 return 0;
417
418 return -1;
419}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
#define CERTERR_INSECUREALG
Certificate uses insecure algorithm.
Definition gnutls.c:60
#define CERTERR_VALID
Certificate is valid.
Definition gnutls.c:53
#define CERTERR_HOSTNAME
Certificate hostname does not match.
Definition gnutls.c:58
#define CERTERR_EXPIRED
Certificate is expired.
Definition gnutls.c:54
static bool tls_check_stored_hostname(const gnutls_datum_t *cert, const char *hostname)
Does the hostname match a stored certificate?
Definition gnutls.c:189
#define CERTERR_NOTTRUSTED
Certificate issuer is not trusted.
Definition gnutls.c:57
#define CERTERR_NOTYETVALID
Certificate is not yet valid.
Definition gnutls.c:55
static bool tls_compare_certificates(const gnutls_datum_t *peercert)
Compare certificates against $certificate_file
Definition gnutls.c:236
#define CERTERR_OTHER
Other certificate error.
Definition gnutls.c:61
#define CERTERR_SIGNERNOTCA
Certificate signer is not a CA.
Definition gnutls.c:59
#define CERTERR_REVOKED
Certificate has been revoked.
Definition gnutls.c:56
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
+ 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 StringArray * carr )
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
carrArray to save info to

Definition at line 428 of file gnutls.c.

430{
431 static const char *part[] = {
432 GNUTLS_OID_X520_COMMON_NAME, // CN
433 GNUTLS_OID_PKCS9_EMAIL, // Email
434 GNUTLS_OID_X520_ORGANIZATION_NAME, // O
435 GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, // OU
436 GNUTLS_OID_X520_LOCALITY_NAME, // L
437 GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, // ST
438 GNUTLS_OID_X520_COUNTRY_NAME, // C
439 };
440
441 char buf[128] = { 0 };
442 int rc;
443
444 // Allocate formatted strings and let the array take ownership
445 ARRAY_ADD(carr, mutt_str_dup(title));
446
447 for (size_t i = 0; i < countof(part); i++)
448 {
449 size_t buflen = sizeof(buf);
450 if (issuer)
451 rc = gnutls_x509_crt_get_issuer_dn_by_oid(cert, part[i], 0, 0, buf, &buflen);
452 else
453 rc = gnutls_x509_crt_get_dn_by_oid(cert, part[i], 0, 0, buf, &buflen);
454 if (rc != 0)
455 continue;
456
457 char *line = NULL;
458 mutt_str_asprintf(&line, " %s", buf);
459 ARRAY_ADD(carr, line);
460 }
461}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define countof(x)
Definition memory.h:49
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:808
+ 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 473 of file gnutls.c.

476{
477 struct StringArray carr = ARRAY_HEAD_INITIALIZER;
478 int certerr, savedcert;
479 gnutls_x509_crt_t cert;
480 struct Buffer *fpbuf = NULL;
481 time_t t;
482 char datestr[30] = { 0 };
483 char title[256] = { 0 };
484 gnutls_datum_t pemdata = { 0 };
485
486 if (tls_check_preauth(certdata, certstat, hostname, idx, &certerr, &savedcert) == 0)
487 return 1;
488
489 if (!OptGui)
490 {
491 mutt_debug(LL_DEBUG1, "unable to prompt for certificate in batch mode\n");
492 mutt_error(_("Untrusted server certificate"));
493 return 0;
494 }
495
496 /* interactive check from user */
497 if (gnutls_x509_crt_init(&cert) < 0)
498 {
499 mutt_error(_("Error initialising gnutls certificate data"));
500 return 0;
501 }
502
503 if (gnutls_x509_crt_import(cert, certdata, GNUTLS_X509_FMT_DER) < 0)
504 {
505 mutt_error(_("Error processing certificate data"));
506 gnutls_x509_crt_deinit(cert);
507 return 0;
508 }
509
510 add_cert(_("This certificate belongs to:"), cert, false, &carr);
511 ARRAY_ADD(&carr, NULL);
512 add_cert(_("This certificate was issued by:"), cert, true, &carr);
513
514 ARRAY_ADD(&carr, NULL);
515 ARRAY_ADD(&carr, mutt_str_dup(_("This certificate is valid")));
516
517 char *line = NULL;
518 t = gnutls_x509_crt_get_activation_time(cert);
519 mutt_date_make_tls(datestr, sizeof(datestr), t);
520 mutt_str_asprintf(&line, _(" from %s"), datestr);
521 ARRAY_ADD(&carr, line);
522
523 t = gnutls_x509_crt_get_expiration_time(cert);
524 mutt_date_make_tls(datestr, sizeof(datestr), t);
525 mutt_str_asprintf(&line, _(" to %s"), datestr);
526 ARRAY_ADD(&carr, line);
527 ARRAY_ADD(&carr, NULL);
528
529 fpbuf = buf_pool_get();
530 tls_fingerprint(GNUTLS_DIG_SHA, fpbuf, certdata);
531 mutt_str_asprintf(&line, _("SHA1 Fingerprint: %s"), buf_string(fpbuf));
532 ARRAY_ADD(&carr, line);
533
534 buf_reset(fpbuf);
535 tls_fingerprint(GNUTLS_DIG_SHA256, fpbuf, certdata);
536 fpbuf->data[39] = '\0'; // Divide into two lines of output
537 mutt_str_asprintf(&line, "%s%s", _("SHA256 Fingerprint: "), buf_string(fpbuf));
538 ARRAY_ADD(&carr, line);
539 mutt_str_asprintf(&line, "%*s%s", (int) mutt_str_len(_("SHA256 Fingerprint: ")),
540 "", fpbuf->data + 40);
541 ARRAY_ADD(&carr, line);
542
543 if (certerr)
544 ARRAY_ADD(&carr, NULL);
545
546 if (certerr & CERTERR_NOTYETVALID)
547 {
548 ARRAY_ADD(&carr, mutt_str_dup(_("WARNING: Server certificate is not yet valid")));
549 }
550 if (certerr & CERTERR_EXPIRED)
551 {
552 ARRAY_ADD(&carr, mutt_str_dup(_("WARNING: Server certificate has expired")));
553 }
554 if (certerr & CERTERR_REVOKED)
555 {
556 ARRAY_ADD(&carr, mutt_str_dup(_("WARNING: Server certificate has been revoked")));
557 }
558 if (certerr & CERTERR_HOSTNAME)
559 {
560 ARRAY_ADD(&carr, mutt_str_dup(_("WARNING: Server hostname does not match certificate")));
561 }
562 if (certerr & CERTERR_SIGNERNOTCA)
563 {
564 ARRAY_ADD(&carr, mutt_str_dup(_("WARNING: Signer of server certificate is not a CA")));
565 }
566 if (certerr & CERTERR_INSECUREALG)
567 {
568 ARRAY_ADD(&carr, mutt_str_dup(_("Warning: Server certificate was signed using an insecure algorithm")));
569 }
570
571 const char **line_ptr = ARRAY_LAST(&carr);
572 if (line_ptr && !*line_ptr)
573 ARRAY_SHRINK(&carr, 1);
574
575 snprintf(title, sizeof(title),
576 _("SSL Certificate check (certificate %zu of %zu in chain)"), len - idx, len);
577
578 const char *const c_certificate_file = cs_subset_path(NeoMutt->sub, "certificate_file");
579 const bool allow_always = (c_certificate_file && !savedcert &&
581 int rc = dlg_certificate(title, &carr, allow_always, false);
582 if (rc == 3) // Accept always
583 {
584 bool saved = false;
585 FILE *fp = mutt_file_fopen(c_certificate_file, "a");
586 if (fp)
587 {
588 if (certerr & CERTERR_HOSTNAME) // Save hostname if necessary
589 {
590 buf_reset(fpbuf);
591 tls_fingerprint(GNUTLS_DIG_MD5, fpbuf, certdata);
592 fprintf(fp, "#H %s %s\n", hostname, buf_string(fpbuf));
593 saved = true;
594 }
595 if (certerr ^ CERTERR_HOSTNAME) // Save the cert for all other errors
596 {
597 int rc2 = gnutls_pem_base64_encode_alloc("CERTIFICATE", certdata, &pemdata);
598 if (rc2 == 0)
599 {
600 if (fwrite(pemdata.data, pemdata.size, 1, fp) == 1)
601 {
602 saved = true;
603 }
604 gnutls_free(pemdata.data);
605 }
606 }
607 mutt_file_fclose(&fp);
608 }
609 if (saved)
610 mutt_message(_("Certificate saved"));
611 else
612 mutt_error(_("Warning: Couldn't save certificate"));
613 }
614
615 buf_pool_release(&fpbuf);
616 string_array_clear(&carr);
617 gnutls_x509_crt_deinit(cert);
618 return (rc > 1);
619}
#define ARRAY_LAST(head)
Convenience method to get the last element.
Definition array.h:145
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
#define ARRAY_SHRINK(head, n)
Mark a number of slots at the end of the array as unused.
Definition array.h:174
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
bool OptGui
(pseudo) when the gui (and curses) are started
Definition globals.c:48
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:316
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.
Definition gnutls.c:428
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(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
int mutt_date_make_tls(char *buf, size_t buflen, time_t timestamp)
Format date in TLS certificate verification style.
Definition date.c:838
void string_array_clear(struct StringArray *arr)
Free all memory of a StringArray.
Definition string.c:936
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
char * data
Pointer to data.
Definition buffer.h:37
+ 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 627 of file gnutls.c.

628{
629 struct TlsSockData *data = conn->sockdata;
630 gnutls_session_t session = data->session;
631 const gnutls_datum_t *cert_list = NULL;
632 unsigned int cert_list_size = 0;
633 gnutls_certificate_status_t certstat;
634 int certerr, savedcert, rc = 0;
635 int max_preauth_pass = -1;
636
637 /* tls_verify_peers() calls gnutls_certificate_verify_peers2(),
638 * which verifies the auth_type is GNUTLS_CRD_CERTIFICATE
639 * and that get_certificate_type() for the server is GNUTLS_CRT_X509.
640 * If it returns 0, certstat will be set with failure codes for the first
641 * cert in the chain(from CA to host) with an error.
642 */
643 if (tls_verify_peers(session, &certstat) != 0)
644 return 0;
645
646 cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
647 if (!cert_list || (cert_list_size == 0))
648 {
649 mutt_error(_("Unable to get certificate from peer"));
650 return 0;
651 }
652
653 /* tls_verify_peers doesn't check hostname or expiration, so walk
654 * from most specific to least checking these. If we see a saved certificate,
655 * its status short-circuits the remaining checks. */
656 int preauthrc = 0;
657 for (int i = 0; i < cert_list_size; i++)
658 {
659 rc = tls_check_preauth(&cert_list[i], certstat, conn->account.host, i,
660 &certerr, &savedcert);
661 preauthrc += rc;
662 if (!preauthrc)
663 max_preauth_pass = i;
664
665 if (savedcert)
666 {
667 if (preauthrc == 0)
668 return 1;
669 break;
670 }
671 }
672
673 /* then check interactively, starting from chain root */
674 for (int i = cert_list_size - 1; i >= 0; i--)
675 {
676 rc = tls_check_one_certificate(&cert_list[i], certstat, conn->account.host,
677 i, cert_list_size);
678
679 /* Stop checking if the menu cert is aborted or rejected. */
680 if (rc == 0)
681 break;
682
683 /* add signers to trust set, then reverify */
684 if (i)
685 {
686 int rcsettrust = gnutls_certificate_set_x509_trust_mem(data->xcred, &cert_list[i],
687 GNUTLS_X509_FMT_DER);
688 if (rcsettrust != 1)
689 mutt_debug(LL_DEBUG1, "error trusting certificate %d: %d\n", i, rcsettrust);
690
691 if (tls_verify_peers(session, &certstat) != 0)
692 return 0;
693
694 /* If the cert chain now verifies, and all lower certs already
695 * passed preauth, we are done. */
696 if (!certstat && (max_preauth_pass >= (i - 1)))
697 return 1;
698 }
699 }
700
701 return rc;
702}
static int tls_verify_peers(gnutls_session_t tlsstate, gnutls_certificate_status_t *certstat)
Wrapper for gnutls_certificate_verify_peers()
Definition gnutls.c:123
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:473
char host[128]
Server to login to.
Definition connaccount.h:54
void * sockdata
Backend-specific socket data.
Definition connection.h:55
struct ConnAccount account
Account details: username, password, etc.
Definition connection.h:49
TLS socket data -.
Definition gnutls.c:83
gnutls_certificate_credentials_t xcred
GNUTLS certificate credentials.
Definition gnutls.c:85
gnutls_session_t session
GNUTLS session.
Definition gnutls.c:84
+ 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
Note
This function grabs the CN out of the client cert but appears to do nothing with it.

Definition at line 711 of file gnutls.c.

712{
713 struct TlsSockData *data = conn->sockdata;
714 gnutls_x509_crt_t clientcrt;
715 char *cn = NULL;
716 size_t cnlen = 0;
717 int rc;
718
719 /* get our cert CN if we have one */
720 const gnutls_datum_t *crtdata = gnutls_certificate_get_ours(data->session);
721 if (!crtdata)
722 return;
723
724 if (gnutls_x509_crt_init(&clientcrt) < 0)
725 {
726 mutt_debug(LL_DEBUG1, "Failed to init gnutls crt\n");
727 return;
728 }
729
730 if (gnutls_x509_crt_import(clientcrt, crtdata, GNUTLS_X509_FMT_DER) < 0)
731 {
732 mutt_debug(LL_DEBUG1, "Failed to import gnutls client crt\n");
733 goto err;
734 }
735
736 /* get length of CN, then grab it. */
737 rc = gnutls_x509_crt_get_dn_by_oid(clientcrt, GNUTLS_OID_X520_COMMON_NAME, 0,
738 0, NULL, &cnlen);
739 if (((rc >= 0) || (rc == GNUTLS_E_SHORT_MEMORY_BUFFER)) && (cnlen > 0))
740 {
741 cn = MUTT_MEM_CALLOC(cnlen, char);
742 if (gnutls_x509_crt_get_dn_by_oid(clientcrt, GNUTLS_OID_X520_COMMON_NAME, 0,
743 0, cn, &cnlen) < 0)
744 {
745 goto err;
746 }
747 mutt_debug(LL_DEBUG2, "client certificate CN: %s\n", cn);
748 }
749
750err:
751 FREE(&cn);
752 gnutls_x509_crt_deinit(clientcrt);
753}
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
+ 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 const bool c_ssl_use_tlsv1_2 = cs_subset_bool(NeoMutt->sub, "ssl_use_tlsv1_2");
826 if (c_ssl_use_tlsv1_2)
827 ProtocolPriority[nproto++] = GNUTLS_TLS1_2;
828 ProtocolPriority[nproto] = 0;
829
830 if (nproto == 0)
831 {
832 mutt_error(_("All available protocols for TLS/SSL connection disabled"));
833 return -1;
834 }
835
836 const char *const c_ssl_ciphers = cs_subset_string(NeoMutt->sub, "ssl_ciphers");
837 if (c_ssl_ciphers)
838 {
839 mutt_error(_("Explicit ciphersuite selection via $ssl_ciphers not supported"));
840 }
841
842 /* We use default priorities (see gnutls documentation),
843 * except for protocol version */
844 gnutls_set_default_priority(data->session);
846 return 0;
847}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
static int ProtocolPriority[]
This array needs to be large enough to hold all the possible values support by NeoMutt.
Definition gnutls.c:76
int gnutls_protocol_set_priority(gnutls_session_t session, const int *list)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_socket_poll_with_timeout()

static bool tls_socket_poll_with_timeout ( struct Connection * conn)
static

Poll a socket with configured timeout.

Parameters
connConnection to poll
Return values
trueSocket is ready
falseTimeout or error occurred

Definition at line 856 of file gnutls.c.

857{
858 const short c_socket_timeout = cs_subset_number(NeoMutt->sub, "socket_timeout");
859 const int poll_rc = raw_socket_poll(conn, c_socket_timeout);
860 if (poll_rc <= 0)
861 {
862 // Timeout or error
863 if (poll_rc == 0)
864 mutt_error(_("Connection to %s timed out"), conn->account.host);
865
866 return false;
867 }
868
869 return true;
870}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
int raw_socket_poll(struct Connection *conn, time_t wait_secs)
Check if any data is waiting on a socket - Implements Connection::poll() -.
Definition raw.c:355
+ Here is the call graph for this function:
+ 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 session has been initialized, attempt to negotiate TLS over the wire, including certificate checks.

Definition at line 881 of file gnutls.c.

882{
883 struct TlsSockData *data = MUTT_MEM_CALLOC(1, struct TlsSockData);
884 conn->sockdata = data;
885 int err = gnutls_certificate_allocate_credentials(&data->xcred);
886 if (err < 0)
887 {
888 FREE(&conn->sockdata);
889 mutt_error("gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
890 return -1;
891 }
892
893 const char *const c_certificate_file = cs_subset_path(NeoMutt->sub, "certificate_file");
894 gnutls_certificate_set_x509_trust_file(data->xcred, c_certificate_file, GNUTLS_X509_FMT_PEM);
895 /* ignore errors, maybe file doesn't exist yet */
896
897 const char *const c_ssl_ca_certificates_file = cs_subset_path(NeoMutt->sub, "ssl_ca_certificates_file");
898 if (c_ssl_ca_certificates_file)
899 {
900 gnutls_certificate_set_x509_trust_file(data->xcred, c_ssl_ca_certificates_file,
901 GNUTLS_X509_FMT_PEM);
902 }
903
904 const char *const c_ssl_client_cert = cs_subset_path(NeoMutt->sub, "ssl_client_cert");
905 if (c_ssl_client_cert)
906 {
907 mutt_debug(LL_DEBUG2, "Using client certificate %s\n", c_ssl_client_cert);
908 gnutls_certificate_set_x509_key_file(data->xcred, c_ssl_client_cert,
909 c_ssl_client_cert, GNUTLS_X509_FMT_PEM);
910 }
911
912#ifdef HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS
913 /* disable checking certificate activation/expiration times
914 * in gnutls, we do the checks ourselves */
915 gnutls_certificate_set_verify_flags(data->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
916#endif
917
918 err = gnutls_init(&data->session, GNUTLS_CLIENT);
919 if (err)
920 {
921 mutt_error("gnutls_init: %s", gnutls_strerror(err));
922 goto fail;
923 }
924
925 /* set socket */
926 gnutls_transport_set_ptr(data->session, (gnutls_transport_ptr_t) (long) conn->fd);
927
928 if (gnutls_server_name_set(data->session, GNUTLS_NAME_DNS, conn->account.host,
929 mutt_str_len(conn->account.host)))
930 {
931 mutt_error(_("Warning: unable to set TLS SNI host name"));
932 }
933
934 if (tls_set_priority(data) < 0)
935 {
936 goto fail;
937 }
938
939 const short c_ssl_min_dh_prime_bits = cs_subset_number(NeoMutt->sub, "ssl_min_dh_prime_bits");
940 if (c_ssl_min_dh_prime_bits > 0)
941 {
942 gnutls_dh_set_prime_bits(data->session, c_ssl_min_dh_prime_bits);
943 }
944
945 gnutls_credentials_set(data->session, GNUTLS_CRD_CERTIFICATE, data->xcred);
946
947 do
948 {
949 err = gnutls_handshake(data->session);
950 if (err == GNUTLS_E_AGAIN)
951 {
952 // Socket would block, wait for data to become available
954 goto fail;
955 }
956 } while ((err == GNUTLS_E_AGAIN) || (err == GNUTLS_E_INTERRUPTED));
957
958 if (err < 0)
959 {
960 if (err == GNUTLS_E_FATAL_ALERT_RECEIVED)
961 {
962 mutt_error("gnutls_handshake: %s(%s)", gnutls_strerror(err),
963 gnutls_alert_get_name(gnutls_alert_get(data->session)));
964 }
965 else
966 {
967 mutt_error("gnutls_handshake: %s", gnutls_strerror(err));
968 }
969 goto fail;
970 }
971
972 if (tls_check_certificate(conn) == 0)
973 goto fail;
974
975 /* set Security Strength Factor (SSF) for SASL */
976 /* NB: gnutls_cipher_get_key_size() returns key length in bytes */
977 conn->ssf = gnutls_cipher_get_key_size(gnutls_cipher_get(data->session)) * 8;
978
980
981 if (OptGui)
982 {
983 mutt_message(_("SSL/TLS connection using %s (%s/%s/%s)"),
984 gnutls_protocol_get_name(gnutls_protocol_get_version(data->session)),
985 gnutls_kx_get_name(gnutls_kx_get(data->session)),
986 gnutls_cipher_get_name(gnutls_cipher_get(data->session)),
987 gnutls_mac_get_name(gnutls_mac_get(data->session)));
988 mutt_sleep(0);
989 }
990
991 return 0;
992
993fail:
994 gnutls_certificate_free_credentials(data->xcred);
995 gnutls_deinit(data->session);
996 FREE(&conn->sockdata);
997 return -1;
998}
static int tls_check_certificate(struct Connection *conn)
Check a connection's certificate.
Definition gnutls.c:627
static bool tls_socket_poll_with_timeout(struct Connection *conn)
Poll a socket with configured timeout.
Definition gnutls.c:856
static void tls_get_client_cert(struct Connection *conn)
Get the client certificate for a TLS connection.
Definition gnutls.c:711
static int tls_set_priority(struct TlsSockData *data)
Set the priority of various protocols.
Definition gnutls.c:821
void mutt_sleep(short s)
Sleep for a while.
Definition muttlib.c:787
unsigned int ssf
Security strength factor, in bits (see notes)
Definition connection.h:50
int fd
Socket file descriptor.
Definition connection.h:53
+ 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 1152 of file gnutls.c.

1153{
1154 if (tls_init() < 0)
1155 return -1;
1156
1157 conn->open = tls_socket_open;
1158 conn->read = tls_socket_read;
1159 conn->write = tls_socket_write;
1160 conn->close = tls_socket_close;
1161 conn->poll = tls_socket_poll;
1162
1163 return 0;
1164}
static int tls_init(void)
Set up Gnu TLS.
Definition gnutls.c:93
static int tls_socket_close(struct Connection *conn)
Close a TLS socket - Implements Connection::close() -.
Definition gnutls.c:1018
static int tls_socket_open(struct Connection *conn)
Open a TLS socket - Implements Connection::open() -.
Definition gnutls.c:1043
static int tls_socket_poll(struct Connection *conn, time_t wait_secs)
Check if any data is waiting on a socket - Implements Connection::poll() -.
Definition gnutls.c:1003
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:1060
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:1093
int(* poll)(struct Connection *conn, time_t wait_secs)
Definition connection.h:105
int(* write)(struct Connection *conn, const char *buf, size_t count)
Definition connection.h:92
int(* close)(struct Connection *conn)
Definition connection.h:116
int(* open)(struct Connection *conn)
Definition connection.h:66
int(* read)(struct Connection *conn, char *buf, size_t count)
Definition connection.h:79
+ Here is the call graph for this function:
+ 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 1172 of file gnutls.c.

1173{
1174 if (tls_init() < 0)
1175 return -1;
1176
1177 if (tls_negotiate(conn) < 0)
1178 return -1;
1179
1180 conn->read = tls_socket_read;
1181 conn->write = tls_socket_write;
1182 conn->close = tls_starttls_close;
1183 conn->poll = tls_socket_poll;
1184
1185 return 0;
1186}
static int tls_negotiate(struct Connection *conn)
Negotiate TLS connection.
Definition gnutls.c:881
static int tls_starttls_close(struct Connection *conn)
Close a TLS connection - Implements Connection::close() -.
Definition gnutls.c:1133
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ ProtocolPriority

int ProtocolPriority[] = { GNUTLS_TLS1_2, GNUTLS_TLS1_1, GNUTLS_TLS1, GNUTLS_SSL3, 0 }
static

This array needs to be large enough to hold all the possible values support by NeoMutt.

The initialized values are just placeholders–the array gets overwrriten in tls_negotiate() depending on the $ssl_use_* options.

Note: gnutls_protocol_set_priority() was removed in GnuTLS version 3.4 (2015-04). TLS 1.3 support wasn't added until version 3.6.5. Therefore, no attempt is made to support $ssl_use_tlsv1_3 in this code.

Definition at line 76 of file gnutls.c.

76{ GNUTLS_TLS1_2, GNUTLS_TLS1_1, GNUTLS_TLS1, GNUTLS_SSL3, 0 };