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