1 /*
2  * virnettlscontext.c: TLS encryption/x509 handling
3  *
4  * Copyright (C) 2010-2014 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library.  If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include <unistd.h>
24 
25 #include <gnutls/gnutls.h>
26 #include <gnutls/crypto.h>
27 #include <gnutls/x509.h>
28 
29 #include "virnettlscontext.h"
30 #include "virstring.h"
31 
32 #include "viralloc.h"
33 #include "virerror.h"
34 #include "virfile.h"
35 #include "virutil.h"
36 #include "virlog.h"
37 #include "virprobe.h"
38 #include "virthread.h"
39 #include "configmake.h"
40 
41 #define DH_BITS 2048
42 
43 #define LIBVIRT_PKI_DIR SYSCONFDIR "/pki"
44 #define LIBVIRT_CACERT LIBVIRT_PKI_DIR "/CA/cacert.pem"
45 #define LIBVIRT_CACRL LIBVIRT_PKI_DIR "/CA/cacrl.pem"
46 #define LIBVIRT_CLIENTKEY LIBVIRT_PKI_DIR "/libvirt/private/clientkey.pem"
47 #define LIBVIRT_CLIENTCERT LIBVIRT_PKI_DIR "/libvirt/clientcert.pem"
48 #define LIBVIRT_SERVERKEY LIBVIRT_PKI_DIR "/libvirt/private/serverkey.pem"
49 #define LIBVIRT_SERVERCERT LIBVIRT_PKI_DIR "/libvirt/servercert.pem"
50 
51 #define VIR_FROM_THIS VIR_FROM_RPC
52 
53 VIR_LOG_INIT("rpc.nettlscontext");
54 
55 struct _virNetTLSContext {
56     virObjectLockable parent;
57 
58     gnutls_certificate_credentials_t x509cred;
59     gnutls_dh_params_t dhParams;
60 
61     bool isServer;
62     bool requireValidCert;
63     const char *const *x509dnACL;
64     char *priority;
65 };
66 
67 struct _virNetTLSSession {
68     virObjectLockable parent;
69 
70     bool handshakeComplete;
71 
72     bool isServer;
73     char *hostname;
74     gnutls_session_t session;
75     virNetTLSSessionWriteFunc writeFunc;
76     virNetTLSSessionReadFunc readFunc;
77     void *opaque;
78     char *x509dname;
79 };
80 
81 static virClass *virNetTLSContextClass;
82 static virClass *virNetTLSSessionClass;
83 static void virNetTLSContextDispose(void *obj);
84 static void virNetTLSSessionDispose(void *obj);
85 
86 
virNetTLSContextOnceInit(void)87 static int virNetTLSContextOnceInit(void)
88 {
89     if (!VIR_CLASS_NEW(virNetTLSContext, virClassForObjectLockable()))
90         return -1;
91 
92     if (!VIR_CLASS_NEW(virNetTLSSession, virClassForObjectLockable()))
93         return -1;
94 
95     return 0;
96 }
97 
98 VIR_ONCE_GLOBAL_INIT(virNetTLSContext);
99 
100 
101 static int
virNetTLSContextCheckCertFile(const char * type,const char * file,bool allowMissing)102 virNetTLSContextCheckCertFile(const char *type, const char *file, bool allowMissing)
103 {
104     if (!virFileExists(file)) {
105         if (allowMissing)
106             return 1;
107 
108         virReportSystemError(errno,
109                              _("Cannot read %s '%s'"),
110                              type, file);
111         return -1;
112     }
113     return 0;
114 }
115 
116 
virNetTLSLog(int level G_GNUC_UNUSED,const char * str G_GNUC_UNUSED)117 static void virNetTLSLog(int level G_GNUC_UNUSED,
118                          const char *str G_GNUC_UNUSED)
119 {
120     VIR_DEBUG("%d %s", level, str);
121 }
122 
123 
virNetTLSContextCheckCertTimes(gnutls_x509_crt_t cert,const char * certFile,bool isServer,bool isCA)124 static int virNetTLSContextCheckCertTimes(gnutls_x509_crt_t cert,
125                                           const char *certFile,
126                                           bool isServer,
127                                           bool isCA)
128 {
129     time_t now;
130 
131     if ((now = time(NULL)) == ((time_t)-1)) {
132         virReportSystemError(errno, "%s",
133                              _("cannot get current time"));
134         return -1;
135     }
136 
137     if (gnutls_x509_crt_get_expiration_time(cert) < now) {
138         virReportError(VIR_ERR_SYSTEM_ERROR,
139                        (isCA ?
140                         _("The CA certificate %s has expired") :
141                         (isServer ?
142                          _("The server certificate %s has expired") :
143                          _("The client certificate %s has expired"))),
144                        certFile);
145         return -1;
146     }
147 
148     if (gnutls_x509_crt_get_activation_time(cert) > now) {
149         virReportError(VIR_ERR_SYSTEM_ERROR,
150                        (isCA ?
151                         _("The CA certificate %s is not yet active") :
152                         (isServer ?
153                          _("The server certificate %s is not yet active") :
154                          _("The client certificate %s is not yet active"))),
155                        certFile);
156         return -1;
157     }
158 
159     return 0;
160 }
161 
162 
virNetTLSContextCheckCertBasicConstraints(gnutls_x509_crt_t cert,const char * certFile,bool isServer,bool isCA)163 static int virNetTLSContextCheckCertBasicConstraints(gnutls_x509_crt_t cert,
164                                                      const char *certFile,
165                                                      bool isServer,
166                                                      bool isCA)
167 {
168     int status;
169 
170     status = gnutls_x509_crt_get_basic_constraints(cert, NULL, NULL, NULL);
171     VIR_DEBUG("Cert %s basic constraints %d", certFile, status);
172 
173     if (status > 0) { /* It is a CA cert */
174         if (!isCA) {
175             virReportError(VIR_ERR_SYSTEM_ERROR, isServer ?
176                            _("The certificate %s basic constraints show a CA, but we need one for a server") :
177                            _("The certificate %s basic constraints show a CA, but we need one for a client"),
178                            certFile);
179             return -1;
180         }
181     } else if (status == 0) { /* It is not a CA cert */
182         if (isCA) {
183             virReportError(VIR_ERR_SYSTEM_ERROR,
184                            _("The certificate %s basic constraints do not show a CA"),
185                            certFile);
186             return -1;
187         }
188     } else if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { /* Missing basicConstraints */
189         if (isCA) {
190             virReportError(VIR_ERR_SYSTEM_ERROR,
191                            _("The certificate %s is missing basic constraints for a CA"),
192                            certFile);
193             return -1;
194         }
195     } else { /* General error */
196         virReportError(VIR_ERR_SYSTEM_ERROR,
197                        _("Unable to query certificate %s basic constraints %s"),
198                        certFile, gnutls_strerror(status));
199         return -1;
200     }
201 
202     return 0;
203 }
204 
205 
virNetTLSContextCheckCertKeyUsage(gnutls_x509_crt_t cert,const char * certFile,bool isCA)206 static int virNetTLSContextCheckCertKeyUsage(gnutls_x509_crt_t cert,
207                                              const char *certFile,
208                                              bool isCA)
209 {
210     int status;
211     unsigned int usage = 0;
212     unsigned int critical = 0;
213 
214     status = gnutls_x509_crt_get_key_usage(cert, &usage, &critical);
215 
216     VIR_DEBUG("Cert %s key usage status %d usage %d critical %u", certFile, status, usage, critical);
217     if (status < 0) {
218         if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
219             usage = isCA ? GNUTLS_KEY_KEY_CERT_SIGN :
220                 GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT;
221         } else {
222             virReportError(VIR_ERR_SYSTEM_ERROR,
223                            _("Unable to query certificate %s key usage %s"),
224                            certFile, gnutls_strerror(status));
225             return -1;
226         }
227     }
228 
229     if (isCA) {
230         if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) {
231             if (critical) {
232                 virReportError(VIR_ERR_SYSTEM_ERROR,
233                                _("Certificate %s usage does not permit certificate signing"),
234                                certFile);
235                 return -1;
236             } else {
237                 VIR_WARN("Certificate %s usage does not permit certificate signing",
238                          certFile);
239             }
240         }
241     } else {
242         if (!(usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) {
243             if (critical) {
244                 virReportError(VIR_ERR_SYSTEM_ERROR,
245                                _("Certificate %s usage does not permit digital signature"),
246                                certFile);
247                 return -1;
248             } else {
249                 VIR_WARN("Certificate %s usage does not permit digital signature",
250                          certFile);
251             }
252         }
253         if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) {
254             if (critical) {
255                 virReportError(VIR_ERR_SYSTEM_ERROR,
256                                _("Certificate %s usage does not permit key encipherment"),
257                                certFile);
258                 return -1;
259             } else {
260                 VIR_WARN("Certificate %s usage does not permit key encipherment",
261                          certFile);
262             }
263         }
264     }
265 
266     return 0;
267 }
268 
269 
virNetTLSContextCheckCertKeyPurpose(gnutls_x509_crt_t cert,const char * certFile,bool isServer)270 static int virNetTLSContextCheckCertKeyPurpose(gnutls_x509_crt_t cert,
271                                                const char *certFile,
272                                                bool isServer)
273 {
274     int status;
275     size_t i;
276     unsigned int purposeCritical;
277     unsigned int critical;
278     char *buffer = NULL;
279     size_t size;
280     bool allowClient = false, allowServer = false;
281 
282     critical = 0;
283     for (i = 0; ; i++) {
284         size = 0;
285         status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer, &size, NULL);
286 
287         if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
288             VIR_DEBUG("No key purpose data available at slot %zu", i);
289 
290             /* If there is no data at all, then we must allow client/server to pass */
291             if (i == 0)
292                 allowServer = allowClient = true;
293             break;
294         }
295         if (status != GNUTLS_E_SHORT_MEMORY_BUFFER) {
296             virReportError(VIR_ERR_SYSTEM_ERROR,
297                            _("Unable to query certificate %s key purpose %s"),
298                            certFile, gnutls_strerror(status));
299             return -1;
300         }
301 
302         buffer = g_new0(char, size);
303         status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer, &size, &purposeCritical);
304         if (status < 0) {
305             VIR_FREE(buffer);
306             virReportError(VIR_ERR_SYSTEM_ERROR,
307                            _("Unable to query certificate %s key purpose %s"),
308                            certFile, gnutls_strerror(status));
309             return -1;
310         }
311         if (purposeCritical)
312             critical = true;
313 
314         VIR_DEBUG("Key purpose %d %s critical %u", status, buffer, purposeCritical);
315         if (STREQ(buffer, GNUTLS_KP_TLS_WWW_SERVER)) {
316             allowServer = true;
317         } else if (STREQ(buffer, GNUTLS_KP_TLS_WWW_CLIENT)) {
318             allowClient = true;
319         } else if (STRNEQ(buffer, GNUTLS_KP_ANY)) {
320             allowServer = allowClient = true;
321         }
322 
323         VIR_FREE(buffer);
324     }
325 
326     if (isServer) {
327         if (!allowServer) {
328             if (critical) {
329                 virReportError(VIR_ERR_SYSTEM_ERROR,
330                                _("Certificate %s purpose does not allow use for with a TLS server"),
331                                certFile);
332                 return -1;
333             } else {
334                 VIR_WARN("Certificate %s purpose does not allow use for with a TLS server",
335                          certFile);
336             }
337         }
338     } else {
339         if (!allowClient) {
340             if (critical) {
341                 virReportError(VIR_ERR_SYSTEM_ERROR,
342                                _("Certificate %s purpose does not allow use for with a TLS client"),
343                                certFile);
344                 return -1;
345             } else {
346                 VIR_WARN("Certificate %s purpose does not allow use for with a TLS client",
347                          certFile);
348             }
349         }
350     }
351 
352     return 0;
353 }
354 
355 /* Check DN is on tls_allowed_dn_list. */
356 static int
virNetTLSContextCheckCertDNACL(const char * dname,const char * const * wildcards)357 virNetTLSContextCheckCertDNACL(const char *dname,
358                                const char *const *wildcards)
359 {
360     while (*wildcards) {
361         if (g_pattern_match_simple(*wildcards, dname))
362             return 1;
363 
364         wildcards++;
365     }
366 
367     /* Log the client's DN for debugging */
368     VIR_DEBUG("Failed ACL check for client DN '%s'", dname);
369 
370     /* This is the most common error: make it informative. */
371     virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
372                    _("Client's Distinguished Name is not on the list "
373                      "of allowed clients (tls_allowed_dn_list).  Use "
374                      "'virt-pki-query-dn clientcert.pem' to view the "
375                      "Distinguished Name field in the client certificate, "
376                      "or run this daemon with --verbose option."));
377     return 0;
378 }
379 
380 
381 static int
virNetTLSContextCheckCertDN(gnutls_x509_crt_t cert,const char * certFile,const char * hostname,const char * dname,const char * const * acl)382 virNetTLSContextCheckCertDN(gnutls_x509_crt_t cert,
383                             const char *certFile,
384                             const char *hostname,
385                             const char *dname,
386                             const char *const *acl)
387 {
388     if (acl && dname &&
389         virNetTLSContextCheckCertDNACL(dname, acl) <= 0)
390         return -1;
391 
392     if (hostname &&
393         !gnutls_x509_crt_check_hostname(cert, hostname)) {
394         virReportError(VIR_ERR_RPC,
395                        _("Certificate %s owner does not match the hostname %s"),
396                        certFile, hostname);
397         return -1;
398     }
399 
400     return 0;
401 }
402 
403 
virNetTLSContextCheckCert(gnutls_x509_crt_t cert,const char * certFile,bool isServer,bool isCA)404 static int virNetTLSContextCheckCert(gnutls_x509_crt_t cert,
405                                      const char *certFile,
406                                      bool isServer,
407                                      bool isCA)
408 {
409     if (virNetTLSContextCheckCertTimes(cert, certFile,
410                                        isServer, isCA) < 0)
411         return -1;
412 
413     if (virNetTLSContextCheckCertBasicConstraints(cert, certFile,
414                                                   isServer, isCA) < 0)
415         return -1;
416 
417     if (virNetTLSContextCheckCertKeyUsage(cert, certFile,
418                                           isCA) < 0)
419         return -1;
420 
421     if (!isCA &&
422         virNetTLSContextCheckCertKeyPurpose(cert, certFile,
423                                             isServer) < 0)
424         return -1;
425 
426     return 0;
427 }
428 
429 
virNetTLSContextCheckCertPair(gnutls_x509_crt_t cert,const char * certFile,gnutls_x509_crt_t * cacerts,size_t ncacerts,const char * cacertFile,bool isServer)430 static int virNetTLSContextCheckCertPair(gnutls_x509_crt_t cert,
431                                          const char *certFile,
432                                          gnutls_x509_crt_t *cacerts,
433                                          size_t ncacerts,
434                                          const char *cacertFile,
435                                          bool isServer)
436 {
437     unsigned int status;
438 
439     if (gnutls_x509_crt_list_verify(&cert, 1,
440                                     cacerts, ncacerts,
441                                     NULL, 0,
442                                     0, &status) < 0) {
443         virReportError(VIR_ERR_SYSTEM_ERROR, isServer ?
444                        _("Unable to verify server certificate %s against CA certificate %s") :
445                        _("Unable to verify client certificate %s against CA certificate %s"),
446                        certFile, cacertFile);
447         return -1;
448     }
449 
450     if (status != 0) {
451         const char *reason = _("Invalid certificate");
452 
453         if (status & GNUTLS_CERT_INVALID)
454             reason = _("The certificate is not trusted.");
455 
456         if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
457             reason = _("The certificate hasn't got a known issuer.");
458 
459         if (status & GNUTLS_CERT_REVOKED)
460             reason = _("The certificate has been revoked.");
461 
462         if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
463             reason = _("The certificate uses an insecure algorithm");
464 
465         virReportError(VIR_ERR_SYSTEM_ERROR,
466                        _("Our own certificate %s failed validation against %s: %s"),
467                        certFile, cacertFile, reason);
468         return -1;
469     }
470 
471     return 0;
472 }
473 
474 
virNetTLSContextLoadCertFromFile(const char * certFile,bool isServer)475 static gnutls_x509_crt_t virNetTLSContextLoadCertFromFile(const char *certFile,
476                                                           bool isServer)
477 {
478     gnutls_datum_t data;
479     gnutls_x509_crt_t cert = NULL;
480     char *buf = NULL;
481     int ret = -1;
482 
483     VIR_DEBUG("isServer %d certFile %s",
484               isServer, certFile);
485 
486     if (gnutls_x509_crt_init(&cert) < 0) {
487         virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
488                        _("Unable to initialize certificate"));
489         goto cleanup;
490     }
491 
492     if (virFileReadAll(certFile, (1<<16), &buf) < 0)
493         goto cleanup;
494 
495     data.data = (unsigned char *)buf;
496     data.size = strlen(buf);
497 
498     if (gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM) < 0) {
499         virReportError(VIR_ERR_SYSTEM_ERROR, isServer ?
500                        _("Unable to import server certificate %s") :
501                        _("Unable to import client certificate %s"),
502                        certFile);
503         goto cleanup;
504     }
505 
506     ret = 0;
507 
508  cleanup:
509     if (ret != 0) {
510         gnutls_x509_crt_deinit(cert);
511         cert = NULL;
512     }
513     VIR_FREE(buf);
514     return cert;
515 }
516 
517 
virNetTLSContextLoadCACertListFromFile(const char * certFile,gnutls_x509_crt_t * certs,unsigned int certMax,size_t * ncerts)518 static int virNetTLSContextLoadCACertListFromFile(const char *certFile,
519                                                   gnutls_x509_crt_t *certs,
520                                                   unsigned int certMax,
521                                                   size_t *ncerts)
522 {
523     gnutls_datum_t data;
524     char *buf = NULL;
525     int ret = -1;
526 
527     *ncerts = 0;
528     VIR_DEBUG("certFile %s", certFile);
529 
530     if (virFileReadAll(certFile, (1<<16), &buf) < 0)
531         goto cleanup;
532 
533     data.data = (unsigned char *)buf;
534     data.size = strlen(buf);
535 
536     if (gnutls_x509_crt_list_import(certs, &certMax, &data, GNUTLS_X509_FMT_PEM, 0) < 0) {
537         virReportError(VIR_ERR_SYSTEM_ERROR,
538                        _("Unable to import CA certificate list %s"),
539                        certFile);
540         goto cleanup;
541     }
542     *ncerts = certMax;
543 
544     ret = 0;
545 
546  cleanup:
547     VIR_FREE(buf);
548     return ret;
549 }
550 
551 
552 #define MAX_CERTS 16
virNetTLSContextSanityCheckCredentials(bool isServer,const char * cacertFile,const char * certFile)553 static int virNetTLSContextSanityCheckCredentials(bool isServer,
554                                                   const char *cacertFile,
555                                                   const char *certFile)
556 {
557     gnutls_x509_crt_t cert = NULL;
558     gnutls_x509_crt_t cacerts[MAX_CERTS];
559     size_t ncacerts = 0;
560     size_t i;
561     int ret = -1;
562 
563     memset(cacerts, 0, sizeof(cacerts));
564     if ((access(certFile, R_OK) == 0) &&
565         !(cert = virNetTLSContextLoadCertFromFile(certFile, isServer)))
566         goto cleanup;
567     if ((access(cacertFile, R_OK) == 0) &&
568         virNetTLSContextLoadCACertListFromFile(cacertFile, cacerts,
569                                                MAX_CERTS, &ncacerts) < 0)
570         goto cleanup;
571 
572     if (cert &&
573         virNetTLSContextCheckCert(cert, certFile, isServer, false) < 0)
574         goto cleanup;
575 
576     for (i = 0; i < ncacerts; i++) {
577         if (virNetTLSContextCheckCert(cacerts[i], cacertFile, isServer, true) < 0)
578             goto cleanup;
579     }
580 
581     if (cert && ncacerts &&
582         virNetTLSContextCheckCertPair(cert, certFile, cacerts, ncacerts, cacertFile, isServer) < 0)
583         goto cleanup;
584 
585     ret = 0;
586 
587  cleanup:
588     if (cert)
589         gnutls_x509_crt_deinit(cert);
590     for (i = 0; i < ncacerts; i++)
591         gnutls_x509_crt_deinit(cacerts[i]);
592     return ret;
593 }
594 
595 
virNetTLSContextLoadCredentials(virNetTLSContext * ctxt,bool isServer,const char * cacert,const char * cacrl,const char * cert,const char * key)596 static int virNetTLSContextLoadCredentials(virNetTLSContext *ctxt,
597                                            bool isServer,
598                                            const char *cacert,
599                                            const char *cacrl,
600                                            const char *cert,
601                                            const char *key)
602 {
603     int err;
604 
605     if (cacert && cacert[0] != '\0') {
606         if (virNetTLSContextCheckCertFile("CA certificate", cacert, false) < 0)
607             return -1;
608 
609         VIR_DEBUG("loading CA cert from %s", cacert);
610         err = gnutls_certificate_set_x509_trust_file(ctxt->x509cred,
611                                                      cacert,
612                                                      GNUTLS_X509_FMT_PEM);
613         if (err < 0) {
614             virReportError(VIR_ERR_SYSTEM_ERROR,
615                            _("Unable to set x509 CA certificate: %s: %s"),
616                            cacert, gnutls_strerror(err));
617             return -1;
618         }
619     }
620 
621     if (cacrl && cacrl[0] != '\0') {
622         int rv;
623         if ((rv = virNetTLSContextCheckCertFile("CA revocation list", cacrl, true)) < 0)
624             return -1;
625 
626         if (rv == 0) {
627             VIR_DEBUG("loading CRL from %s", cacrl);
628             err = gnutls_certificate_set_x509_crl_file(ctxt->x509cred,
629                                                        cacrl,
630                                                        GNUTLS_X509_FMT_PEM);
631             if (err < 0) {
632                 virReportError(VIR_ERR_SYSTEM_ERROR,
633                                _("Unable to set x509 certificate revocation list: %s: %s"),
634                                cacrl, gnutls_strerror(err));
635                 return -1;
636             }
637         } else {
638             VIR_DEBUG("Skipping non-existent CA CRL %s", cacrl);
639         }
640     }
641 
642     if (cert && cert[0] != '\0' && key && key[0] != '\0') {
643         int rv;
644         if ((rv = virNetTLSContextCheckCertFile("certificate", cert, !isServer)) < 0)
645             return -1;
646         if (rv == 0 &&
647             (rv = virNetTLSContextCheckCertFile("private key", key, !isServer)) < 0)
648             return -1;
649 
650         if (rv == 0) {
651             VIR_DEBUG("loading cert and key from %s and %s", cert, key);
652             err =
653                 gnutls_certificate_set_x509_key_file(ctxt->x509cred,
654                                                      cert, key,
655                                                      GNUTLS_X509_FMT_PEM);
656             if (err < 0) {
657                 virReportError(VIR_ERR_SYSTEM_ERROR,
658                                _("Unable to set x509 key and certificate: %s, %s: %s"),
659                                key, cert, gnutls_strerror(err));
660                 return -1;
661             }
662         } else {
663             VIR_DEBUG("Skipping non-existent cert %s key %s on client",
664                       cert, key);
665         }
666     }
667 
668     return 0;
669 }
670 
671 
virNetTLSContextNew(const char * cacert,const char * cacrl,const char * cert,const char * key,const char * const * x509dnACL,const char * priority,bool sanityCheckCert,bool requireValidCert,bool isServer)672 static virNetTLSContext *virNetTLSContextNew(const char *cacert,
673                                                const char *cacrl,
674                                                const char *cert,
675                                                const char *key,
676                                                const char *const *x509dnACL,
677                                                const char *priority,
678                                                bool sanityCheckCert,
679                                                bool requireValidCert,
680                                                bool isServer)
681 {
682     virNetTLSContext *ctxt;
683     int err;
684 
685     if (virNetTLSContextInitialize() < 0)
686         return NULL;
687 
688     if (!(ctxt = virObjectLockableNew(virNetTLSContextClass)))
689         return NULL;
690 
691     ctxt->priority = g_strdup(priority);
692 
693     err = gnutls_certificate_allocate_credentials(&ctxt->x509cred);
694     if (err) {
695         /* While gnutls_certificate_credentials_t will free any
696          * partially allocated credentials struct, it does not
697          * set the returned pointer back to NULL after it is
698          * freed in an error path.
699          */
700         ctxt->x509cred = NULL;
701 
702         virReportError(VIR_ERR_SYSTEM_ERROR,
703                        _("Unable to allocate x509 credentials: %s"),
704                        gnutls_strerror(err));
705         goto error;
706     }
707 
708     if (sanityCheckCert &&
709         virNetTLSContextSanityCheckCredentials(isServer, cacert, cert) < 0)
710         goto error;
711 
712     if (virNetTLSContextLoadCredentials(ctxt, isServer, cacert, cacrl, cert, key) < 0)
713         goto error;
714 
715     /* Generate Diffie Hellman parameters - for use with DHE
716      * kx algorithms. These should be discarded and regenerated
717      * once a day, once a week or once a month. Depending on the
718      * security requirements.
719      */
720     if (isServer) {
721         err = gnutls_dh_params_init(&ctxt->dhParams);
722         if (err < 0) {
723             virReportError(VIR_ERR_SYSTEM_ERROR,
724                            _("Unable to initialize diffie-hellman parameters: %s"),
725                            gnutls_strerror(err));
726             goto error;
727         }
728         err = gnutls_dh_params_generate2(ctxt->dhParams, DH_BITS);
729         if (err < 0) {
730             virReportError(VIR_ERR_SYSTEM_ERROR,
731                            _("Unable to generate diffie-hellman parameters: %s"),
732                            gnutls_strerror(err));
733             goto error;
734         }
735 
736         gnutls_certificate_set_dh_params(ctxt->x509cred,
737                                          ctxt->dhParams);
738     }
739 
740     ctxt->requireValidCert = requireValidCert;
741     ctxt->x509dnACL = x509dnACL;
742     ctxt->isServer = isServer;
743 
744     PROBE(RPC_TLS_CONTEXT_NEW,
745           "ctxt=%p cacert=%s cacrl=%s cert=%s key=%s sanityCheckCert=%d requireValidCert=%d isServer=%d",
746           ctxt, cacert, NULLSTR(cacrl), cert, key, sanityCheckCert, requireValidCert, isServer);
747 
748     return ctxt;
749 
750  error:
751     if (isServer)
752         gnutls_dh_params_deinit(ctxt->dhParams);
753     virObjectUnref(ctxt);
754     return NULL;
755 }
756 
757 
virNetTLSContextLocateCredentials(const char * pkipath,bool tryUserPkiPath,bool isServer,char ** cacert,char ** cacrl,char ** cert,char ** key)758 static int virNetTLSContextLocateCredentials(const char *pkipath,
759                                              bool tryUserPkiPath,
760                                              bool isServer,
761                                              char **cacert,
762                                              char **cacrl,
763                                              char **cert,
764                                              char **key)
765 {
766     char *userdir = NULL;
767     char *user_pki_path = NULL;
768 
769     *cacert = NULL;
770     *cacrl = NULL;
771     *key = NULL;
772     *cert = NULL;
773 
774     VIR_DEBUG("pkipath=%s isServer=%d tryUserPkiPath=%d",
775               pkipath, isServer, tryUserPkiPath);
776 
777     /* Explicit path, then use that no matter whether the
778      * files actually exist there
779      */
780     if (pkipath) {
781         VIR_DEBUG("Told to use TLS credentials in %s", pkipath);
782         *cacert = g_strdup_printf("%s/%s", pkipath, "cacert.pem");
783         *cacrl = g_strdup_printf("%s/%s", pkipath, "cacrl.pem");
784         *key = g_strdup_printf("%s/%s", pkipath,
785                                isServer ? "serverkey.pem" : "clientkey.pem");
786 
787         *cert = g_strdup_printf("%s/%s", pkipath,
788                                 isServer ? "servercert.pem" : "clientcert.pem");
789     } else if (tryUserPkiPath) {
790         /* Check to see if $HOME/.pki contains at least one of the
791          * files and if so, use that
792          */
793         userdir = virGetUserDirectory();
794 
795         user_pki_path = g_strdup_printf("%s/.pki/libvirt", userdir);
796 
797         VIR_DEBUG("Trying to find TLS user credentials in %s", user_pki_path);
798 
799         *cacert = g_strdup_printf("%s/%s", user_pki_path, "cacert.pem");
800 
801         *cacrl = g_strdup_printf("%s/%s", user_pki_path, "cacrl.pem");
802 
803         *key = g_strdup_printf("%s/%s", user_pki_path,
804                                isServer ? "serverkey.pem" : "clientkey.pem");
805 
806         *cert = g_strdup_printf("%s/%s", user_pki_path,
807                                 isServer ? "servercert.pem" : "clientcert.pem");
808 
809         /*
810          * If some of the files can't be found, fallback
811          * to the global location for them
812          */
813         if (!virFileExists(*cacert))
814             VIR_FREE(*cacert);
815         if (!virFileExists(*cacrl))
816             VIR_FREE(*cacrl);
817 
818         /* Check these as a pair, since it they are
819          * mutually dependent
820          */
821         if (!virFileExists(*key) || !virFileExists(*cert)) {
822             VIR_FREE(*key);
823             VIR_FREE(*cert);
824         }
825     }
826 
827     /* No explicit path, or user path didn't exist, so
828      * fallback to global defaults
829      */
830     if (!*cacert) {
831         VIR_DEBUG("Using default TLS CA certificate path");
832         *cacert = g_strdup(LIBVIRT_CACERT);
833     }
834 
835     if (!*cacrl) {
836         VIR_DEBUG("Using default TLS CA revocation list path");
837         *cacrl = g_strdup(LIBVIRT_CACRL);
838     }
839 
840     if (!*key && !*cert) {
841         VIR_DEBUG("Using default TLS key/certificate path");
842         *key = g_strdup(isServer ? LIBVIRT_SERVERKEY : LIBVIRT_CLIENTKEY);
843 
844         *cert = g_strdup(isServer ? LIBVIRT_SERVERCERT : LIBVIRT_CLIENTCERT);
845     }
846 
847     VIR_FREE(user_pki_path);
848     VIR_FREE(userdir);
849 
850     return 0;
851 }
852 
853 
virNetTLSContextNewPath(const char * pkipath,bool tryUserPkiPath,const char * const * x509dnACL,const char * priority,bool sanityCheckCert,bool requireValidCert,bool isServer)854 static virNetTLSContext *virNetTLSContextNewPath(const char *pkipath,
855                                                    bool tryUserPkiPath,
856                                                    const char *const *x509dnACL,
857                                                    const char *priority,
858                                                    bool sanityCheckCert,
859                                                    bool requireValidCert,
860                                                    bool isServer)
861 {
862     char *cacert = NULL, *cacrl = NULL, *key = NULL, *cert = NULL;
863     virNetTLSContext *ctxt = NULL;
864 
865     if (virNetTLSContextLocateCredentials(pkipath, tryUserPkiPath, isServer,
866                                           &cacert, &cacrl, &cert, &key) < 0)
867         return NULL;
868 
869     ctxt = virNetTLSContextNew(cacert, cacrl, cert, key,
870                                x509dnACL, priority, sanityCheckCert,
871                                requireValidCert, isServer);
872 
873     VIR_FREE(cacert);
874     VIR_FREE(cacrl);
875     VIR_FREE(key);
876     VIR_FREE(cert);
877 
878     return ctxt;
879 }
880 
virNetTLSContextNewServerPath(const char * pkipath,bool tryUserPkiPath,const char * const * x509dnACL,const char * priority,bool sanityCheckCert,bool requireValidCert)881 virNetTLSContext *virNetTLSContextNewServerPath(const char *pkipath,
882                                                   bool tryUserPkiPath,
883                                                   const char *const *x509dnACL,
884                                                   const char *priority,
885                                                   bool sanityCheckCert,
886                                                   bool requireValidCert)
887 {
888     return virNetTLSContextNewPath(pkipath, tryUserPkiPath, x509dnACL, priority,
889                                    sanityCheckCert, requireValidCert, true);
890 }
891 
virNetTLSContextNewClientPath(const char * pkipath,bool tryUserPkiPath,const char * priority,bool sanityCheckCert,bool requireValidCert)892 virNetTLSContext *virNetTLSContextNewClientPath(const char *pkipath,
893                                                   bool tryUserPkiPath,
894                                                   const char *priority,
895                                                   bool sanityCheckCert,
896                                                   bool requireValidCert)
897 {
898     return virNetTLSContextNewPath(pkipath, tryUserPkiPath, NULL, priority,
899                                    sanityCheckCert, requireValidCert, false);
900 }
901 
902 
virNetTLSContextNewServer(const char * cacert,const char * cacrl,const char * cert,const char * key,const char * const * x509dnACL,const char * priority,bool sanityCheckCert,bool requireValidCert)903 virNetTLSContext *virNetTLSContextNewServer(const char *cacert,
904                                               const char *cacrl,
905                                               const char *cert,
906                                               const char *key,
907                                               const char *const *x509dnACL,
908                                               const char *priority,
909                                               bool sanityCheckCert,
910                                               bool requireValidCert)
911 {
912     return virNetTLSContextNew(cacert, cacrl, cert, key, x509dnACL, priority,
913                                sanityCheckCert, requireValidCert, true);
914 }
915 
916 
virNetTLSContextReloadForServer(virNetTLSContext * ctxt,bool tryUserPkiPath)917 int virNetTLSContextReloadForServer(virNetTLSContext *ctxt,
918                                     bool tryUserPkiPath)
919 {
920     gnutls_certificate_credentials_t x509credBak;
921     int err;
922     g_autofree char *cacert = NULL;
923     g_autofree char *cacrl = NULL;
924     g_autofree char *cert = NULL;
925     g_autofree char *key = NULL;
926 
927     x509credBak = g_steal_pointer(&ctxt->x509cred);
928 
929     if (virNetTLSContextLocateCredentials(NULL, tryUserPkiPath, true,
930                                           &cacert, &cacrl, &cert, &key))
931         goto error;
932 
933     err = gnutls_certificate_allocate_credentials(&ctxt->x509cred);
934     if (err) {
935         virReportError(VIR_ERR_SYSTEM_ERROR,
936                        _("Unable to allocate x509 credentials: %s"),
937                        gnutls_strerror(err));
938         goto error;
939     }
940 
941     if (virNetTLSContextSanityCheckCredentials(true, cacert, cert))
942         goto error;
943 
944     if (virNetTLSContextLoadCredentials(ctxt, true, cacert, cacrl, cert, key))
945         goto error;
946 
947     gnutls_certificate_set_dh_params(ctxt->x509cred,
948                                      ctxt->dhParams);
949 
950     gnutls_certificate_free_credentials(x509credBak);
951 
952     return 0;
953 
954  error:
955     if (ctxt->x509cred)
956         gnutls_certificate_free_credentials(ctxt->x509cred);
957     ctxt->x509cred = x509credBak;
958     return -1;
959 }
960 
961 
virNetTLSContextNewClient(const char * cacert,const char * cacrl,const char * cert,const char * key,const char * priority,bool sanityCheckCert,bool requireValidCert)962 virNetTLSContext *virNetTLSContextNewClient(const char *cacert,
963                                               const char *cacrl,
964                                               const char *cert,
965                                               const char *key,
966                                               const char *priority,
967                                               bool sanityCheckCert,
968                                               bool requireValidCert)
969 {
970     return virNetTLSContextNew(cacert, cacrl, cert, key, NULL, priority,
971                                sanityCheckCert, requireValidCert, false);
972 }
973 
974 
virNetTLSContextValidCertificate(virNetTLSContext * ctxt,virNetTLSSession * sess)975 static int virNetTLSContextValidCertificate(virNetTLSContext *ctxt,
976                                             virNetTLSSession *sess)
977 {
978     int ret;
979     unsigned int status;
980     const gnutls_datum_t *certs;
981     unsigned int nCerts;
982     size_t i;
983     size_t dnamesize = 256;
984     g_autofree char *dname = g_new0(char, dnamesize);
985     char *dnameptr = dname;
986 
987     if ((ret = gnutls_certificate_verify_peers2(sess->session, &status)) < 0) {
988         virReportError(VIR_ERR_SYSTEM_ERROR,
989                        _("Unable to verify TLS peer: %s"),
990                        gnutls_strerror(ret));
991         goto authdeny;
992     }
993 
994     if (status != 0) {
995         const char *reason = _("Invalid certificate");
996 
997         if (status & GNUTLS_CERT_INVALID)
998             reason = _("The certificate is not trusted.");
999 
1000         if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
1001             reason = _("The certificate hasn't got a known issuer.");
1002 
1003         if (status & GNUTLS_CERT_REVOKED)
1004             reason = _("The certificate has been revoked.");
1005 
1006         if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
1007             reason = _("The certificate uses an insecure algorithm");
1008 
1009         virReportError(VIR_ERR_SYSTEM_ERROR,
1010                        _("Certificate failed validation: %s"),
1011                        reason);
1012         goto authdeny;
1013     }
1014 
1015     if (gnutls_certificate_type_get(sess->session) != GNUTLS_CRT_X509) {
1016         virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
1017                        _("Only x509 certificates are supported"));
1018         goto authdeny;
1019     }
1020 
1021     if (!(certs = gnutls_certificate_get_peers(sess->session, &nCerts))) {
1022         virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
1023                        _("The certificate has no peers"));
1024         goto authdeny;
1025     }
1026 
1027     for (i = 0; i < nCerts; i++) {
1028         gnutls_x509_crt_t cert;
1029 
1030         if (gnutls_x509_crt_init(&cert) < 0) {
1031             virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
1032                            _("Unable to initialize certificate"));
1033             goto authfail;
1034         }
1035 
1036         if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
1037             virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
1038                            _("Unable to load certificate"));
1039             gnutls_x509_crt_deinit(cert);
1040             goto authfail;
1041         }
1042 
1043         if (virNetTLSContextCheckCertTimes(cert, "[session]",
1044                                            sess->isServer, i > 0) < 0) {
1045             gnutls_x509_crt_deinit(cert);
1046             goto authdeny;
1047         }
1048 
1049         if (i == 0) {
1050             ret = gnutls_x509_crt_get_dn(cert, dname, &dnamesize);
1051             if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
1052                 VIR_DEBUG("Reallocating dname to fit %zu bytes", dnamesize);
1053                 dname = g_realloc(dname, dnamesize);
1054                 dnameptr = dname;
1055                 ret = gnutls_x509_crt_get_dn(cert, dname, &dnamesize);
1056             }
1057             if (ret != 0) {
1058                 virReportError(VIR_ERR_SYSTEM_ERROR,
1059                                _("Failed to get certificate %s distinguished name: %s"),
1060                                "[session]", gnutls_strerror(ret));
1061                 goto authfail;
1062             }
1063             sess->x509dname = g_steal_pointer(&dname);
1064             VIR_DEBUG("Peer DN is %s", dnameptr);
1065 
1066             if (virNetTLSContextCheckCertDN(cert, "[session]", sess->hostname,
1067                                             dnameptr, ctxt->x509dnACL) < 0) {
1068                 gnutls_x509_crt_deinit(cert);
1069                 goto authdeny;
1070             }
1071 
1072             /* !sess->isServer, since on the client, we're validating the
1073              * server's cert, and on the server, the client's cert
1074              */
1075             if (virNetTLSContextCheckCertBasicConstraints(cert, "[session]",
1076                                                           !sess->isServer, false) < 0) {
1077                 gnutls_x509_crt_deinit(cert);
1078                 goto authdeny;
1079             }
1080 
1081             if (virNetTLSContextCheckCertKeyUsage(cert, "[session]",
1082                                                   false) < 0) {
1083                 gnutls_x509_crt_deinit(cert);
1084                 goto authdeny;
1085             }
1086 
1087             /* !sess->isServer - as above */
1088             if (virNetTLSContextCheckCertKeyPurpose(cert, "[session]",
1089                                                     !sess->isServer) < 0) {
1090                 gnutls_x509_crt_deinit(cert);
1091                 goto authdeny;
1092             }
1093         }
1094         gnutls_x509_crt_deinit(cert);
1095     }
1096 
1097     PROBE(RPC_TLS_CONTEXT_SESSION_ALLOW,
1098           "ctxt=%p sess=%p dname=%s",
1099           ctxt, sess, dnameptr);
1100 
1101     return 0;
1102 
1103  authdeny:
1104     PROBE(RPC_TLS_CONTEXT_SESSION_DENY,
1105           "ctxt=%p sess=%p dname=%s",
1106           ctxt, sess, dnameptr);
1107 
1108     return -1;
1109 
1110  authfail:
1111     PROBE(RPC_TLS_CONTEXT_SESSION_FAIL,
1112           "ctxt=%p sess=%p",
1113           ctxt, sess);
1114 
1115     return -1;
1116 }
1117 
virNetTLSContextCheckCertificate(virNetTLSContext * ctxt,virNetTLSSession * sess)1118 int virNetTLSContextCheckCertificate(virNetTLSContext *ctxt,
1119                                      virNetTLSSession *sess)
1120 {
1121     int ret = -1;
1122 
1123     virObjectLock(ctxt);
1124     virObjectLock(sess);
1125     if (virNetTLSContextValidCertificate(ctxt, sess) < 0) {
1126         VIR_WARN("Certificate check failed %s", virGetLastErrorMessage());
1127         if (ctxt->requireValidCert) {
1128             virReportError(VIR_ERR_AUTH_FAILED, "%s",
1129                            _("Failed to verify peer's certificate"));
1130             goto cleanup;
1131         }
1132         virResetLastError();
1133         VIR_INFO("Ignoring bad certificate at user request");
1134     }
1135 
1136     ret = 0;
1137 
1138  cleanup:
1139     virObjectUnlock(ctxt);
1140     virObjectUnlock(sess);
1141 
1142     return ret;
1143 }
1144 
virNetTLSContextDispose(void * obj)1145 void virNetTLSContextDispose(void *obj)
1146 {
1147     virNetTLSContext *ctxt = obj;
1148 
1149     PROBE(RPC_TLS_CONTEXT_DISPOSE,
1150           "ctxt=%p", ctxt);
1151 
1152     g_free(ctxt->priority);
1153     gnutls_dh_params_deinit(ctxt->dhParams);
1154     gnutls_certificate_free_credentials(ctxt->x509cred);
1155 }
1156 
1157 
1158 static ssize_t
virNetTLSSessionPush(void * opaque,const void * buf,size_t len)1159 virNetTLSSessionPush(void *opaque, const void *buf, size_t len)
1160 {
1161     virNetTLSSession *sess = opaque;
1162     if (!sess->writeFunc) {
1163         VIR_WARN("TLS session push with missing write function");
1164         errno = EIO;
1165         return -1;
1166     };
1167 
1168     return sess->writeFunc(buf, len, sess->opaque);
1169 }
1170 
1171 
1172 static ssize_t
virNetTLSSessionPull(void * opaque,void * buf,size_t len)1173 virNetTLSSessionPull(void *opaque, void *buf, size_t len)
1174 {
1175     virNetTLSSession *sess = opaque;
1176     if (!sess->readFunc) {
1177         VIR_WARN("TLS session pull with missing read function");
1178         errno = EIO;
1179         return -1;
1180     };
1181 
1182     return sess->readFunc(buf, len, sess->opaque);
1183 }
1184 
1185 
virNetTLSSessionNew(virNetTLSContext * ctxt,const char * hostname)1186 virNetTLSSession *virNetTLSSessionNew(virNetTLSContext *ctxt,
1187                                         const char *hostname)
1188 {
1189     virNetTLSSession *sess;
1190     int err;
1191     const char *priority;
1192 
1193     VIR_DEBUG("ctxt=%p hostname=%s isServer=%d",
1194               ctxt, NULLSTR(hostname), ctxt->isServer);
1195 
1196     if (!(sess = virObjectLockableNew(virNetTLSSessionClass)))
1197         return NULL;
1198 
1199     sess->hostname = g_strdup(hostname);
1200 
1201     if ((err = gnutls_init(&sess->session,
1202                            ctxt->isServer ? GNUTLS_SERVER : GNUTLS_CLIENT)) != 0) {
1203         virReportError(VIR_ERR_SYSTEM_ERROR,
1204                        _("Failed to initialize TLS session: %s"),
1205                        gnutls_strerror(err));
1206         goto error;
1207     }
1208 
1209     /* avoid calling all the priority functions, since the defaults
1210      * are adequate.
1211      */
1212     priority = ctxt->priority ? ctxt->priority : TLS_PRIORITY;
1213     VIR_DEBUG("Setting priority string '%s'", priority);
1214     if ((err = gnutls_priority_set_direct(sess->session,
1215                                           priority,
1216                                           NULL)) != 0) {
1217         virReportError(VIR_ERR_SYSTEM_ERROR,
1218                        _("Failed to set TLS session priority to %s: %s"),
1219                        priority, gnutls_strerror(err));
1220         goto error;
1221     }
1222 
1223     if ((err = gnutls_credentials_set(sess->session,
1224                                       GNUTLS_CRD_CERTIFICATE,
1225                                       ctxt->x509cred)) != 0) {
1226         virReportError(VIR_ERR_SYSTEM_ERROR,
1227                        _("Failed set TLS x509 credentials: %s"),
1228                        gnutls_strerror(err));
1229         goto error;
1230     }
1231 
1232     /* request client certificate if any.
1233      */
1234     if (ctxt->isServer) {
1235         gnutls_certificate_server_set_request(sess->session, GNUTLS_CERT_REQUEST);
1236 
1237         gnutls_dh_set_prime_bits(sess->session, DH_BITS);
1238     }
1239 
1240     gnutls_transport_set_ptr(sess->session, sess);
1241     gnutls_transport_set_push_function(sess->session,
1242                                        virNetTLSSessionPush);
1243     gnutls_transport_set_pull_function(sess->session,
1244                                        virNetTLSSessionPull);
1245 
1246     sess->isServer = ctxt->isServer;
1247 
1248     PROBE(RPC_TLS_SESSION_NEW,
1249           "sess=%p ctxt=%p hostname=%s isServer=%d",
1250           sess, ctxt, hostname, sess->isServer);
1251 
1252     return sess;
1253 
1254  error:
1255     virObjectUnref(sess);
1256     return NULL;
1257 }
1258 
1259 
virNetTLSSessionSetIOCallbacks(virNetTLSSession * sess,virNetTLSSessionWriteFunc writeFunc,virNetTLSSessionReadFunc readFunc,void * opaque)1260 void virNetTLSSessionSetIOCallbacks(virNetTLSSession *sess,
1261                                     virNetTLSSessionWriteFunc writeFunc,
1262                                     virNetTLSSessionReadFunc readFunc,
1263                                     void *opaque)
1264 {
1265     virObjectLock(sess);
1266     sess->writeFunc = writeFunc;
1267     sess->readFunc = readFunc;
1268     sess->opaque = opaque;
1269     virObjectUnlock(sess);
1270 }
1271 
1272 
virNetTLSSessionWrite(virNetTLSSession * sess,const char * buf,size_t len)1273 ssize_t virNetTLSSessionWrite(virNetTLSSession *sess,
1274                               const char *buf, size_t len)
1275 {
1276     ssize_t ret;
1277 
1278     virObjectLock(sess);
1279     ret = gnutls_record_send(sess->session, buf, len);
1280 
1281     if (ret >= 0)
1282         goto cleanup;
1283 
1284     switch (ret) {
1285     case GNUTLS_E_AGAIN:
1286         errno = EAGAIN;
1287         break;
1288     case GNUTLS_E_INTERRUPTED:
1289         errno = EINTR;
1290         break;
1291     case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
1292         errno = ENOMSG;
1293         break;
1294     default:
1295         errno = EIO;
1296         break;
1297     }
1298 
1299     ret = -1;
1300 
1301  cleanup:
1302     virObjectUnlock(sess);
1303     return ret;
1304 }
1305 
virNetTLSSessionRead(virNetTLSSession * sess,char * buf,size_t len)1306 ssize_t virNetTLSSessionRead(virNetTLSSession *sess,
1307                              char *buf, size_t len)
1308 {
1309     ssize_t ret;
1310 
1311     virObjectLock(sess);
1312     ret = gnutls_record_recv(sess->session, buf, len);
1313 
1314     if (ret >= 0)
1315         goto cleanup;
1316 
1317     switch (ret) {
1318     case GNUTLS_E_AGAIN:
1319         errno = EAGAIN;
1320         break;
1321     case GNUTLS_E_INTERRUPTED:
1322         errno = EINTR;
1323         break;
1324     default:
1325         errno = EIO;
1326         break;
1327     }
1328 
1329     ret = -1;
1330 
1331  cleanup:
1332     virObjectUnlock(sess);
1333     return ret;
1334 }
1335 
virNetTLSSessionHandshake(virNetTLSSession * sess)1336 int virNetTLSSessionHandshake(virNetTLSSession *sess)
1337 {
1338     int ret;
1339     VIR_DEBUG("sess=%p", sess);
1340     virObjectLock(sess);
1341     ret = gnutls_handshake(sess->session);
1342     VIR_DEBUG("Ret=%d", ret);
1343     if (ret == 0) {
1344         sess->handshakeComplete = true;
1345         VIR_DEBUG("Handshake is complete");
1346         goto cleanup;
1347     }
1348     if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
1349         ret = 1;
1350         goto cleanup;
1351     }
1352 
1353 #if 0
1354     PROBE(CLIENT_TLS_FAIL, "fd=%d",
1355           virNetServerClientGetFD(client));
1356 #endif
1357 
1358     virReportError(VIR_ERR_AUTH_FAILED,
1359                    _("TLS handshake failed %s"),
1360                    gnutls_strerror(ret));
1361     ret = -1;
1362 
1363  cleanup:
1364     virObjectUnlock(sess);
1365     return ret;
1366 }
1367 
1368 virNetTLSSessionHandshakeStatus
virNetTLSSessionGetHandshakeStatus(virNetTLSSession * sess)1369 virNetTLSSessionGetHandshakeStatus(virNetTLSSession *sess)
1370 {
1371     virNetTLSSessionHandshakeStatus ret;
1372     virObjectLock(sess);
1373     if (sess->handshakeComplete)
1374         ret = VIR_NET_TLS_HANDSHAKE_COMPLETE;
1375     else if (gnutls_record_get_direction(sess->session) == 0)
1376         ret = VIR_NET_TLS_HANDSHAKE_RECVING;
1377     else
1378         ret = VIR_NET_TLS_HANDSHAKE_SENDING;
1379     virObjectUnlock(sess);
1380     return ret;
1381 }
1382 
virNetTLSSessionGetKeySize(virNetTLSSession * sess)1383 int virNetTLSSessionGetKeySize(virNetTLSSession *sess)
1384 {
1385     gnutls_cipher_algorithm_t cipher;
1386     int ssf;
1387     virObjectLock(sess);
1388     cipher = gnutls_cipher_get(sess->session);
1389     if (!(ssf = gnutls_cipher_get_key_size(cipher))) {
1390         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1391                        _("invalid cipher size for TLS session"));
1392         ssf = -1;
1393         goto cleanup;
1394     }
1395 
1396  cleanup:
1397     virObjectUnlock(sess);
1398     return ssf;
1399 }
1400 
virNetTLSSessionGetX509DName(virNetTLSSession * sess)1401 const char *virNetTLSSessionGetX509DName(virNetTLSSession *sess)
1402 {
1403     const char *ret = NULL;
1404 
1405     virObjectLock(sess);
1406 
1407     ret = sess->x509dname;
1408 
1409     virObjectUnlock(sess);
1410 
1411     return ret;
1412 }
1413 
virNetTLSSessionDispose(void * obj)1414 void virNetTLSSessionDispose(void *obj)
1415 {
1416     virNetTLSSession *sess = obj;
1417 
1418     PROBE(RPC_TLS_SESSION_DISPOSE,
1419           "sess=%p", sess);
1420 
1421     g_free(sess->x509dname);
1422     g_free(sess->hostname);
1423     gnutls_deinit(sess->session);
1424 }
1425 
1426 /*
1427  * This function MUST be called before any
1428  * virNetTLS* because it initializes
1429  * underlying GnuTLS library. According to
1430  * it's documentation, it's safe to be called
1431  * many times, but is not thread safe.
1432  *
1433  * There is no corresponding "Deinit" / "Cleanup"
1434  * function because there is no safe way to call
1435  * 'gnutls_global_deinit' from a multi-threaded
1436  * library, where other libraries linked into the
1437  * application may also be using gnutls.
1438  */
virNetTLSInit(void)1439 void virNetTLSInit(void)
1440 {
1441     const char *gnutlsdebug;
1442     if ((gnutlsdebug = getenv("LIBVIRT_GNUTLS_DEBUG")) != NULL) {
1443         int val;
1444         if (virStrToLong_i(gnutlsdebug, NULL, 10, &val) < 0)
1445             val = 10;
1446         gnutls_global_set_log_level(val);
1447         gnutls_global_set_log_function(virNetTLSLog);
1448         VIR_DEBUG("Enabled GNUTLS debug");
1449     }
1450 
1451     gnutls_global_init();
1452 }
1453