NeoMutt  2025-12-11-980-ge38c27
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
 This array needs to be large enough to hold all the possible values support by NeoMutt. 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.
 

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 92 of file gnutls.c.

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

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

161{
162 unsigned char md[128] = { 0 };
163 size_t n = 64;
164
165 if (gnutls_fingerprint(algo, data, (char *) md, &n) < 0)
166 {
167 buf_strcpy(buf, _("[unable to calculate]"));
168 return;
169 }
170
171 for (size_t i = 0; i < n; i++)
172 {
173 buf_add_printf(buf, "%02X", md[i]);
174
175 // Put a space after a pair of bytes (except for the last one)
176 if (((i % 2) == 1) && (i < (n - 1)))
177 buf_addch(buf, ' ');
178 }
179}
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:211
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:248
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
+ 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 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 const char *const c_certificate_file = cs_subset_path(NeoMutt->sub, "certificate_file");
195 FILE *fp = mutt_file_fopen(c_certificate_file, "r");
196 if (!fp)
197 return false;
198
199 struct Buffer *buf = buf_pool_get();
200
201 tls_fingerprint(GNUTLS_DIG_MD5, buf, cert);
202 while ((linestr = mutt_file_read_line(linestr, &linestrsize, fp, NULL, MUTT_RL_NONE)))
203 {
204 regmatch_t *match = mutt_prex_capture(PREX_GNUTLS_CERT_HOST_HASH, linestr);
205 if (match)
206 {
207 regmatch_t *mhost = &match[PREX_GNUTLS_CERT_HOST_HASH_MATCH_HOST];
208 regmatch_t *mhash = &match[PREX_GNUTLS_CERT_HOST_HASH_MATCH_HASH];
209 linestr[mutt_regmatch_end(mhost)] = '\0';
210 linestr[mutt_regmatch_end(mhash)] = '\0';
211 if ((mutt_str_equal(linestr + mutt_regmatch_start(mhost), hostname)) &&
212 (mutt_str_equal(linestr + mutt_regmatch_start(mhash), buf_string(buf))))
213 {
214 FREE(&linestr);
215 mutt_file_fclose(&fp);
216 buf_pool_release(&buf);
217 return true;
218 }
219 }
220 }
221
222 mutt_file_fclose(&fp);
223 buf_pool_release(&buf);
224
225 /* not found a matching name */
226 return false;
227}
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:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
@ MUTT_RL_NONE
No flags are set.
Definition file.h:43
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:159
#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:666
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 235 of file gnutls.c.

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

318{
319 gnutls_x509_crt_t cert = NULL;
320
321 *certerr = CERTERR_VALID;
322 *savedcert = 0;
323
324 if (gnutls_x509_crt_init(&cert) < 0)
325 {
326 mutt_error(_("Error initialising gnutls certificate data"));
327 return -1;
328 }
329
330 if (gnutls_x509_crt_import(cert, certdata, GNUTLS_X509_FMT_DER) < 0)
331 {
332 mutt_error(_("Error processing certificate data"));
333 gnutls_x509_crt_deinit(cert);
334 return -1;
335 }
336
337 /* Note: tls_negotiate() contains a call to
338 * gnutls_certificate_set_verify_flags() with a flag disabling
339 * GnuTLS checking of the dates. So certstat shouldn't have the
340 * GNUTLS_CERT_EXPIRED and GNUTLS_CERT_NOT_ACTIVATED bits set. */
341 const bool c_ssl_verify_dates = cs_subset_bool(NeoMutt->sub, "ssl_verify_dates");
342 if (c_ssl_verify_dates != MUTT_NO)
343 {
344 if (gnutls_x509_crt_get_expiration_time(cert) < mutt_date_now())
345 *certerr |= CERTERR_EXPIRED;
346 if (gnutls_x509_crt_get_activation_time(cert) > mutt_date_now())
347 *certerr |= CERTERR_NOTYETVALID;
348 }
349
350 const bool c_ssl_verify_host = cs_subset_bool(NeoMutt->sub, "ssl_verify_host");
351 if ((chainidx == 0) && (c_ssl_verify_host != MUTT_NO) &&
352 !gnutls_x509_crt_check_hostname(cert, hostname) &&
353 !tls_check_stored_hostname(certdata, hostname))
354 {
355 *certerr |= CERTERR_HOSTNAME;
356 }
357
358 if (certstat & GNUTLS_CERT_REVOKED)
359 {
360 *certerr |= CERTERR_REVOKED;
361 certstat ^= GNUTLS_CERT_REVOKED;
362 }
363
364 /* see whether certificate is in our cache (certificates file) */
365 if (tls_compare_certificates(certdata))
366 {
367 *savedcert = 1;
368
369 /* We check above for certs with bad dates or that are revoked.
370 * These must be accepted manually each time. Otherwise, we
371 * accept saved certificates as valid. */
372 if (*certerr == CERTERR_VALID)
373 {
374 gnutls_x509_crt_deinit(cert);
375 return 0;
376 }
377 }
378
379 if (certstat & GNUTLS_CERT_INVALID)
380 {
381 *certerr |= CERTERR_NOTTRUSTED;
382 certstat ^= GNUTLS_CERT_INVALID;
383 }
384
385 if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND)
386 {
387 /* NB: already cleared if cert in cache */
388 *certerr |= CERTERR_NOTTRUSTED;
389 certstat ^= GNUTLS_CERT_SIGNER_NOT_FOUND;
390 }
391
392 if (certstat & GNUTLS_CERT_SIGNER_NOT_CA)
393 {
394 /* NB: already cleared if cert in cache */
395 *certerr |= CERTERR_SIGNERNOTCA;
396 certstat ^= GNUTLS_CERT_SIGNER_NOT_CA;
397 }
398
399 if (certstat & GNUTLS_CERT_INSECURE_ALGORITHM)
400 {
401 /* NB: already cleared if cert in cache */
402 *certerr |= CERTERR_INSECUREALG;
403 certstat ^= GNUTLS_CERT_INSECURE_ALGORITHM;
404 }
405
406 /* we've been zeroing the interesting bits in certstat -
407 * don't return OK if there are any unhandled bits we don't
408 * understand */
409 if (certstat != 0)
410 *certerr |= CERTERR_OTHER;
411
412 gnutls_x509_crt_deinit(cert);
413
414 if (*certerr == CERTERR_VALID)
415 return 0;
416
417 return -1;
418}
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:188
#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:235
#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:459
@ 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 427 of file gnutls.c.

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

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

714{
715 struct TlsSockData *data = conn->sockdata;
716 gnutls_x509_crt_t clientcrt = NULL;
717 char *cn = NULL;
718 size_t cnlen = 0;
719 int rc;
720
721 /* get our cert CN if we have one */
722 const gnutls_datum_t *crtdata = gnutls_certificate_get_ours(data->session);
723 if (!crtdata)
724 return;
725
726 if (gnutls_x509_crt_init(&clientcrt) < 0)
727 {
728 mutt_debug(LL_DEBUG1, "Failed to init gnutls crt\n");
729 return;
730 }
731
732 if (gnutls_x509_crt_import(clientcrt, crtdata, GNUTLS_X509_FMT_DER) < 0)
733 {
734 mutt_debug(LL_DEBUG1, "Failed to import gnutls client crt\n");
735 goto err;
736 }
737
738 /* get length of CN, then grab it. */
739 rc = gnutls_x509_crt_get_dn_by_oid(clientcrt, GNUTLS_OID_X520_COMMON_NAME, 0,
740 0, NULL, &cnlen);
741 if (((rc >= 0) || (rc == GNUTLS_E_SHORT_MEMORY_BUFFER)) && (cnlen > 0))
742 {
743 cn = MUTT_MEM_CALLOC(cnlen, char);
744 if (gnutls_x509_crt_get_dn_by_oid(clientcrt, GNUTLS_OID_X520_COMMON_NAME, 0,
745 0, cn, &cnlen) < 0)
746 {
747 goto err;
748 }
749 mutt_debug(LL_DEBUG2, "client certificate CN: %s\n", cn);
750 }
751
752err:
753 FREE(&cn);
754 gnutls_x509_crt_deinit(clientcrt);
755}
@ 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 823 of file gnutls.c.

824{
826 size_t nproto = 0; /* number of tls/ssl protocols */
827
828 const bool c_ssl_use_tlsv1_2 = cs_subset_bool(NeoMutt->sub, "ssl_use_tlsv1_2");
829 if (c_ssl_use_tlsv1_2)
830 mod_data->protocol_priority[nproto++] = GNUTLS_TLS1_2;
831 mod_data->protocol_priority[nproto] = 0;
832
833 if (nproto == 0)
834 {
835 mutt_error(_("All available protocols for TLS/SSL connection disabled"));
836 return -1;
837 }
838
839 const char *const c_ssl_ciphers = cs_subset_string(NeoMutt->sub, "ssl_ciphers");
840 if (c_ssl_ciphers)
841 {
842 mutt_error(_("Explicit ciphersuite selection via $ssl_ciphers not supported"));
843 }
844
845 /* We use default priorities (see gnutls documentation),
846 * except for protocol version */
847 gnutls_set_default_priority(data->session);
849 return 0;
850}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
int gnutls_protocol_set_priority(gnutls_session_t session, const int *list)
@ MODULE_ID_CONN
ModuleConn, Network connections
Definition module_api.h:60
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
Conn private Module data.
Definition module_data.h:38
int protocol_priority[5]
GnuTLS protocol priority.
Definition module_data.h:42
+ 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 859 of file gnutls.c.

860{
861 const short c_socket_timeout = cs_subset_number(NeoMutt->sub, "socket_timeout");
862 const int poll_rc = raw_socket_poll(conn, c_socket_timeout);
863 if (poll_rc <= 0)
864 {
865 // Timeout or error
866 if (poll_rc == 0)
867 mutt_error(_("Connection to %s timed out"), conn->account.host);
868
869 return false;
870 }
871
872 return true;
873}
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:354
+ 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 884 of file gnutls.c.

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

1156{
1157 if (tls_init() < 0)
1158 return -1;
1159
1160 conn->open = tls_socket_open;
1161 conn->read = tls_socket_read;
1162 conn->write = tls_socket_write;
1163 conn->close = tls_socket_close;
1164 conn->poll = tls_socket_poll;
1165
1166 return 0;
1167}
static int tls_init(void)
Set up Gnu TLS.
Definition gnutls.c:92
static int tls_socket_close(struct Connection *conn)
Close a TLS socket - Implements Connection::close() -.
Definition gnutls.c:1021
static int tls_socket_open(struct Connection *conn)
Open a TLS socket - Implements Connection::open() -.
Definition gnutls.c:1046
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:1006
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:1063
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:1096
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 1175 of file gnutls.c.

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