1 /*
2 * mtls-libtls.c
3 *
4 * This file is part of msmtp, an SMTP client, and of mpop, a POP3 client.
5 *
6 * Copyright (C) 2020 Nihal Jere <nihal@nihaljere.xyz>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <stdlib.h>
30 #include <errno.h>
31
32 #include <tls.h>
33
34 #include "gettext.h"
35 #define _(string) gettext(string)
36 #define N_(string) gettext_noop(string)
37
38 #include "xalloc.h"
39 #include "readbuf.h"
40 #include "tools.h"
41 #include "mtls.h"
42
43
44 struct mtls_internals_t
45 {
46 struct tls *tls_ctx;
47 };
48
49 /*
50 * mtls_lib_init()
51 *
52 * see mtls.h
53 */
54
mtls_lib_init(char ** errstr)55 int mtls_lib_init(char **errstr)
56 {
57 if (tls_init() == -1)
58 {
59 *errstr = xasprintf(_("cannot initialize libtls"));
60 return TLS_ELIBFAILED;
61 }
62
63 return TLS_EOK;
64 }
65
66 /*
67 * libtls gives certificate fingerprints in a string formatted as
68 * type:hex_fingerprint. This function decodes this into binary.
69 */
decode_sha256(unsigned char * dest,const char * src)70 int decode_sha256(unsigned char *dest, const char *src)
71 {
72 char prefix[] = "SHA256:";
73 unsigned char msn, lsn;
74
75 if (dest == NULL || src == NULL)
76 {
77 return -1;
78 }
79
80 if (memcmp(src, prefix, sizeof(prefix)-1) != 0)
81 {
82 return -1;
83 }
84
85 for (int i = 0; i < 32; i++)
86 {
87 msn = src[2*i + sizeof(prefix)-1];
88 lsn = src[2*i + sizeof(prefix)];
89
90 dest[i] = (isdigit(lsn) ? lsn - '0' : lsn - 'a' + 10)
91 + ((isdigit(msn) ? (msn - '0') : (msn - 'a' + 10)) << 4);
92 }
93
94 return 0;
95 }
96
97 /*
98 * mtls_cert_info_get()
99 *
100 * see mtls.h
101 */
102
mtls_cert_info_get(mtls_t * mtls,mtls_cert_info_t * mtci,char ** errstr)103 int mtls_cert_info_get(mtls_t *mtls, mtls_cert_info_t *mtci, char **errstr)
104 {
105 const char *errmsg = _("cannot get TLS certificate info");
106 const char *sha256_fingerprint;
107 const char *s;
108
109 if ((sha256_fingerprint =
110 tls_peer_cert_hash(mtls->internals->tls_ctx))
111 == NULL)
112 {
113 *errstr = xasprintf(_("%s: error getting SHA256 fingerprint"), errmsg);
114 return TLS_ECERT;
115 }
116
117 if (decode_sha256(mtci->sha256_fingerprint, sha256_fingerprint) != 0)
118 {
119 *errstr = xasprintf("%s", errmsg);
120 return TLS_ECERT;
121 }
122
123 if ((mtci->activation_time =
124 tls_peer_cert_notbefore(mtls->internals->tls_ctx)) == -1)
125 {
126 *errstr = xasprintf(_("%s: cannot get activation time"), errmsg);
127 return TLS_ECERT;
128 }
129
130 if ((mtci->expiration_time =
131 tls_peer_cert_notafter(mtls->internals->tls_ctx)) == -1)
132 {
133 *errstr = xasprintf(_("%s: cannot get expiration time"), errmsg);
134 return TLS_ECERT;
135 }
136
137 s = tls_peer_cert_subject(mtls->internals->tls_ctx);
138 if (s)
139 {
140 mtci->subject_info = xstrdup(s);
141 }
142 s = tls_peer_cert_issuer(mtls->internals->tls_ctx);
143 if (s)
144 {
145 mtci->issuer_info = xstrdup(s);
146 }
147
148 return TLS_EOK;
149 }
150
151 /*
152 * mtls_check_cert()
153 *
154 * If the 'mtls->have_trust_file' flag is set, nothing needs to be done, as
155 * libtls will perform a full certificate verification automatically.
156 *
157 * If 'mtls->have_sha256_fingerprint' flags is set, compare the
158 * 'mtls->fingerprint' data with the peer certificate's fingerprint. If this
159 * succeeds, the connection can be considered secure.
160 *
161 * Used error codes: TLS_ECERT
162 */
163
mtls_check_cert(mtls_t * mtls,char ** errstr)164 static int mtls_check_cert(mtls_t *mtls, char **errstr)
165 {
166 const char *error_msg = _("TLS certificate verification failed");
167 const char *sha256_fingerprint_raw;
168 unsigned char sha256_fingerprint[32];
169
170 if (mtls->have_trust_file)
171 {
172 return TLS_EOK;
173 }
174
175 if (mtls->have_sha256_fingerprint)
176 {
177 if (!(sha256_fingerprint_raw = tls_peer_cert_hash(mtls->internals->tls_ctx)))
178 {
179 *errstr = xasprintf(_("%s: error getting SHA256 fingerprint"), error_msg);
180 return TLS_ECERT;
181 }
182
183 if (decode_sha256(sha256_fingerprint, sha256_fingerprint_raw) == -1)
184 {
185 *errstr = xasprintf("%s", error_msg);
186 return TLS_ECERT;
187 }
188
189 if (memcmp(sha256_fingerprint, mtls->fingerprint, 32) != 0)
190 {
191 *errstr = xasprintf(_("%s: the certificate fingerprint "
192 "does not match"), error_msg);
193 return TLS_ECERT;
194 }
195 }
196
197 return TLS_EOK;
198 }
199
200
201 /*
202 * mtls_init()
203 *
204 * see mtls.h
205 */
206
mtls_init(mtls_t * mtls,const char * key_file,const char * cert_file,const char * pin,const char * trust_file,const char * crl_file,const unsigned char * sha256_fingerprint,const unsigned char * sha1_fingerprint,const unsigned char * md5_fingerprint,int min_dh_prime_bits,const char * priorities,const char * hostname,int no_certcheck,char ** errstr)207 int mtls_init(mtls_t *mtls,
208 const char *key_file, const char *cert_file, const char *pin,
209 const char *trust_file, const char *crl_file,
210 const unsigned char *sha256_fingerprint,
211 const unsigned char *sha1_fingerprint,
212 const unsigned char *md5_fingerprint,
213 int min_dh_prime_bits, const char *priorities,
214 const char *hostname,
215 int no_certcheck,
216 char **errstr)
217 {
218 struct tls_config *config;
219
220 if (sha1_fingerprint || md5_fingerprint)
221 {
222 *errstr = xasprintf(
223 _("cannot use deprecated fingerprints, please update to SHA256"));
224 return TLS_ELIBFAILED;
225 }
226 if (min_dh_prime_bits >= 0)
227 {
228 /* This will never need to be implemented because it is deprecated.
229 * But we should report it and not just silently ignore it. */
230 *errstr = xasprintf(
231 _("cannot set minimum number of DH prime bits for TLS: %s"),
232 _("feature not yet implemented for libtls"));
233 return TLS_ELIBFAILED;
234 }
235
236 if ((config = tls_config_new()) == NULL)
237 {
238 *errstr = xasprintf(_("cannot initialize TLS session: %s"), strerror(ENOMEM));
239 return TLS_ELIBFAILED;
240 }
241
242 if (priorities)
243 {
244 char *prio_copy = xstrdup(priorities); /* for modification by strtok() */
245 const char *key;
246 char *value;
247 uint32_t protocol_flags;
248
249 if ((key = strstr(priorities, "ECDHECURVES=")) != NULL)
250 {
251 value = prio_copy + (key + strlen("ECDHECURVES=") - priorities);
252 strtok(value, " ");
253
254 if (tls_config_set_ecdhecurves(config, value) == -1)
255 {
256 *errstr = xasprintf(
257 _("cannot set priorities for TLS session: %s"),
258 tls_config_error(config));
259 tls_config_free(config);
260 free(prio_copy);
261 return TLS_ELIBFAILED;
262 }
263 }
264 if ((key = strstr(priorities, "CIPHERS=")) != NULL)
265 {
266 value = prio_copy + (key + strlen("CIPHERS=") - priorities);
267 strtok(value, " ");
268
269 if (tls_config_set_ciphers(config, value) == -1)
270 {
271 *errstr = xasprintf(
272 _("cannot set priorities for TLS session: %s"),
273 tls_config_error(config));
274 tls_config_free(config);
275 free(prio_copy);
276 return TLS_ELIBFAILED;
277 }
278 }
279 if ((key = strstr(priorities, "PROTOCOLS=")) != NULL)
280 {
281 value = prio_copy + (key + strlen("PROTOCOLS=") - priorities);
282 strtok(value, " ");
283
284 if (tls_config_parse_protocols(&protocol_flags, value) == -1)
285 {
286 *errstr = xasprintf(
287 _("cannot set priorities for TLS session: %s"),
288 _("could not parse protocols"));
289 tls_config_free(config);
290 free(prio_copy);
291 return TLS_ELIBFAILED;
292 }
293
294 if (tls_config_set_protocols(config, protocol_flags) == -1)
295 {
296 *errstr = xasprintf(
297 _("cannot set priorities for TLS session: %s"),
298 tls_config_error(config));
299 tls_config_free(config);
300 free(prio_copy);
301 return TLS_ELIBFAILED;
302 }
303 }
304 free(prio_copy);
305 }
306
307 if (key_file && cert_file)
308 {
309 if (tls_config_set_key_file(config, key_file) == -1
310 || tls_config_set_cert_file(config, cert_file) == -1)
311 {
312 *errstr = xasprintf(_("cannot set X509 key file %s and/or "
313 "X509 cert file %s for TLS session: %s"),
314 key_file, cert_file, tls_config_error(config));
315 tls_config_free(config);
316 return TLS_EFILE;
317 }
318 }
319
320 if (no_certcheck)
321 {
322 tls_config_insecure_noverifycert(config);
323 tls_config_insecure_noverifyname(config);
324 tls_config_insecure_noverifytime(config);
325 }
326 else if (sha256_fingerprint && !no_certcheck)
327 {
328 tls_config_insecure_noverifycert(config);
329 tls_config_insecure_noverifyname(config);
330 tls_config_insecure_noverifytime(config);
331 memcpy(mtls->fingerprint, sha256_fingerprint, 32);
332 mtls->have_sha256_fingerprint = 1;
333 }
334 else if (trust_file && !no_certcheck)
335 {
336 /* leaving ca_file unset makes libtls use system default trust */
337 if (strcmp(trust_file, "system") != 0)
338 {
339 if (tls_config_set_ca_file(config, trust_file) == -1)
340 {
341 *errstr = xasprintf(
342 _("cannot set X509 trust file %s for TLS session: %s"),
343 trust_file, tls_config_error(config));
344 tls_config_free(config);
345 return TLS_EFILE;
346 }
347 }
348
349 mtls->have_trust_file = 1;
350 }
351
352 if (crl_file && tls_config_set_crl_file(config, crl_file) == -1)
353 {
354 *errstr = xasprintf(
355 _("cannot set X509 CRL file %s for TLS session: %s"),
356 crl_file, tls_config_error(config));
357 tls_config_free(config);
358 return TLS_EFILE;
359 }
360
361 mtls->internals = xmalloc(sizeof(struct mtls_internals_t));
362
363 if ((mtls->internals->tls_ctx = tls_client()) == NULL)
364 {
365 *errstr = xasprintf(_("cannot create a TLS structure: %s"), strerror(ENOMEM));
366 tls_config_free(config);
367 free(mtls->internals);
368 mtls->internals = NULL;
369 return TLS_ELIBFAILED;
370 }
371
372 if (tls_configure(mtls->internals->tls_ctx, config) == -1)
373 {
374 *errstr = xasprintf(_("cannot initialize TLS session: %s"),
375 tls_config_error(config));
376 tls_free(mtls->internals->tls_ctx);
377 tls_config_free(config);
378 free(mtls->internals);
379 mtls->internals = NULL;
380 return TLS_ELIBFAILED;
381 }
382
383 tls_config_free(config);
384 mtls->hostname = xstrdup(hostname);
385 mtls->no_certcheck = no_certcheck;
386 return TLS_EOK;
387 }
388
389 /*
390 * mtls_start()
391 *
392 * see mtls.h
393 */
394
mtls_start(mtls_t * mtls,int fd,mtls_cert_info_t * mtci,char ** mtls_parameter_description,char ** errstr)395 int mtls_start(mtls_t *mtls, int fd,
396 mtls_cert_info_t *mtci, char **mtls_parameter_description, char **errstr)
397 {
398 int error_code;
399
400 if (tls_connect_socket(mtls->internals->tls_ctx, fd, mtls->hostname) == -1)
401 {
402 *errstr = xasprintf(_("cannot set the file descriptor for TLS: %s"),
403 tls_error(mtls->internals->tls_ctx));
404 tls_free(mtls->internals->tls_ctx);
405 return TLS_EHANDSHAKE;
406 }
407
408 if (tls_handshake(mtls->internals->tls_ctx) == -1)
409 {
410 *errstr = xasprintf(_("TLS handshake failed: %s"),
411 tls_error(mtls->internals->tls_ctx));
412 tls_close(mtls->internals->tls_ctx);
413 tls_free(mtls->internals->tls_ctx);
414 return TLS_EHANDSHAKE;
415 }
416
417 if (!mtls->no_certcheck)
418 {
419 if ((error_code = mtls_check_cert(mtls, errstr)) != TLS_EOK)
420 {
421 tls_close(mtls->internals->tls_ctx);
422 tls_free(mtls->internals->tls_ctx);
423 return error_code;
424 }
425 }
426
427 if (mtls_parameter_description)
428 {
429 const char *cv = tls_conn_version(mtls->internals->tls_ctx);
430 const char *cc = tls_conn_cipher(mtls->internals->tls_ctx);
431 size_t cvl = (cv ? strlen(cv) : 0);
432 size_t ccl = (cc ? strlen(cc) : 0);
433 if (cvl > 0 || ccl > 0)
434 {
435 size_t pdl = cvl + ccl;
436 if (cvl > 0 && ccl > 0)
437 pdl++; /* for ' ' between them */
438 *mtls_parameter_description = xmalloc(pdl + 1);
439 (*mtls_parameter_description)[0] = '\0';
440 if (cvl > 0)
441 {
442 strcpy(*mtls_parameter_description, cv);
443 }
444 if (ccl > 0)
445 {
446 if (cvl > 0)
447 {
448 strcat(*mtls_parameter_description, " ");
449 }
450 strcat(*mtls_parameter_description, cc);
451 }
452 }
453 else
454 {
455 *mtls_parameter_description = NULL;
456 }
457 }
458
459 if (mtci)
460 {
461 if ((error_code = mtls_cert_info_get(mtls, mtci, errstr)) != TLS_EOK)
462 {
463 /* mtls_cert_info_get() already sets *errstr */
464 tls_close(mtls->internals->tls_ctx);
465 tls_free(mtls->internals->tls_ctx);
466 return error_code;
467 }
468 }
469
470 mtls->is_active = 1;
471 return TLS_EOK;
472 }
473
474
475 /*
476 * mtls_readbuf_read()
477 *
478 * Wraps TLS read function to provide buffering for mtls_gets().
479 */
480
mtls_readbuf_read(mtls_t * mtls,readbuf_t * readbuf,char * ptr,char ** errstr)481 int mtls_readbuf_read(mtls_t *mtls, readbuf_t *readbuf, char *ptr,
482 char **errstr)
483 {
484 int ret;
485
486 /* immediately run `tls_read` again for TLS_WANT* */
487 while (readbuf->count <= 0)
488 {
489 ret = tls_read(mtls->internals->tls_ctx, readbuf->buf,
490 sizeof(readbuf->buf));
491 if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT)
492 {
493 continue;
494 }
495 else if (ret == -1)
496 {
497 *errstr = xasprintf(_("cannot read from TLS connection: %s"),
498 tls_error(mtls->internals->tls_ctx));
499 return TLS_EIO;
500 }
501 readbuf->count = ret;
502 readbuf->ptr = readbuf->buf;
503 }
504 readbuf->count--;
505 *ptr = *((readbuf->ptr)++);
506 return 1;
507 }
508
509
510 /*
511 * mtls_puts()
512 *
513 * see mtls.h
514 */
515
mtls_puts(mtls_t * mtls,const char * s,size_t len,char ** errstr)516 int mtls_puts(mtls_t *mtls, const char *s, size_t len, char **errstr)
517 {
518 while (len > 0)
519 {
520 ssize_t ret;
521 ret = tls_write(mtls->internals->tls_ctx, s, len);
522
523 if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT)
524 {
525 continue;
526 }
527 if (ret == -1)
528 {
529 *errstr = xasprintf(_("cannot write to TLS connection: %s"),
530 tls_error(mtls->internals->tls_ctx));
531 return TLS_EIO;
532 }
533 s += ret;
534 len -= ret;
535 }
536
537 return TLS_EOK;
538 }
539
540
541 /*
542 * mtls_close()
543 *
544 * see mtls.h
545 */
546
mtls_close(mtls_t * mtls)547 void mtls_close(mtls_t *mtls)
548 {
549 if (mtls->is_active)
550 {
551 tls_close(mtls->internals->tls_ctx);
552 tls_free(mtls->internals->tls_ctx);
553 mtls->internals->tls_ctx = NULL;
554 }
555 free(mtls->internals);
556 mtls->internals = NULL;
557 if (mtls->hostname)
558 {
559 free(mtls->hostname);
560 }
561 mtls_clear(mtls);
562 }
563
564
565 /*
566 * mtls_lib_deinit()
567 *
568 * see mtls.h
569 */
570
mtls_lib_deinit(void)571 void mtls_lib_deinit(void)
572 {
573 }
574