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