master
c 1,066 lines 32.4 KB
Raw
1 /*
2 * QEMU crypto TLS x509 credential support
3 *
4 * Copyright (c) 2015 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 <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "qemu/osdep.h"
22 #include "crypto/tlscredsx509.h"
23 #include "tlscredspriv.h"
24 #include "crypto/secret.h"
25 #include "qapi/error.h"
26 #include "qemu/module.h"
27 #include "qom/object_interfaces.h"
28 #include "trace.h"
29
30
31 struct QCryptoTLSCredsX509 {
32 QCryptoTLSCreds parent_obj;
33 bool sanityCheck;
34 char *passwordid;
35 };
36
37 #ifdef CONFIG_GNUTLS
38
39 #include <gnutls/gnutls.h>
40 #include <gnutls/x509.h>
41
42
43 typedef struct QCryptoTLSCredsX509IdentFiles QCryptoTLSCredsX509IdentFiles;
44 struct QCryptoTLSCredsX509IdentFiles {
45 char *certpath;
46 char *keypath;
47 gnutls_x509_crt_t *certs;
48 unsigned int ncerts;
49 gnutls_x509_privkey_t key;
50 };
51
52 typedef struct QCryptoTLSCredsX509Files QCryptoTLSCredsX509Files;
53 struct QCryptoTLSCredsX509Files {
54 char *cacertpath;
55 gnutls_x509_crt_t *cacerts;
56 unsigned int ncacerts;
57
58 QCryptoTLSCredsX509IdentFiles **identities;
59 size_t nidentities;
60 };
61
62 static QCryptoTLSCredsX509Files *
63 qcrypto_tls_creds_x509_files_new(void)
64 {
65 return g_new0(QCryptoTLSCredsX509Files, 1);
66 }
67
68
69 static void
70 qcrypto_tls_creds_x509_ident_files_free(QCryptoTLSCredsX509IdentFiles *files)
71 {
72 size_t i;
73 for (i = 0; i < files->ncerts; i++) {
74 gnutls_x509_crt_deinit(files->certs[i]);
75 }
76 gnutls_x509_privkey_deinit(files->key);
77 g_free(files->certs);
78 g_free(files->certpath);
79 g_free(files->keypath);
80 g_free(files);
81 }
82
83 G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509IdentFiles,
84 qcrypto_tls_creds_x509_ident_files_free);
85
86
87 static void
88 qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
89 {
90 size_t i;
91 for (i = 0; i < files->ncacerts; i++) {
92 gnutls_x509_crt_deinit(files->cacerts[i]);
93 }
94 g_free(files->cacerts);
95 g_free(files->cacertpath);
96 for (i = 0; i < files->nidentities; i++) {
97 qcrypto_tls_creds_x509_ident_files_free(files->identities[i]);
98 }
99 g_free(files->identities);
100 g_free(files);
101 }
102
103 G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509Files,
104 qcrypto_tls_creds_x509_files_free);
105
106 static int
107 qcrypto_tls_creds_check_cert_times(gnutls_x509_crt_t cert,
108 const char *certFile,
109 bool isServer,
110 bool isCA,
111 Error **errp)
112 {
113 time_t now = time(NULL);
114
115 if (now == ((time_t)-1)) {
116 error_setg_errno(errp, errno, "cannot get current time");
117 return -1;
118 }
119
120 if (gnutls_x509_crt_get_expiration_time(cert) < now) {
121 error_setg(errp,
122 (isCA ?
123 "The CA certificate %s has expired" :
124 (isServer ?
125 "The server certificate %s has expired" :
126 "The client certificate %s has expired")),
127 certFile);
128 return -1;
129 }
130
131 if (gnutls_x509_crt_get_activation_time(cert) > now) {
132 error_setg(errp,
133 (isCA ?
134 "The CA certificate %s is not yet active" :
135 (isServer ?
136 "The server certificate %s is not yet active" :
137 "The client certificate %s is not yet active")),
138 certFile);
139 return -1;
140 }
141
142 return 0;
143 }
144
145
146 static int
147 qcrypto_tls_creds_check_cert_basic_constraints(QCryptoTLSCredsX509 *creds,
148 gnutls_x509_crt_t cert,
149 const char *certFile,
150 bool isServer,
151 bool isCA,
152 Error **errp)
153 {
154 int status;
155
156 status = gnutls_x509_crt_get_basic_constraints(cert, NULL, NULL, NULL);
157 trace_qcrypto_tls_creds_x509_check_basic_constraints(
158 creds, certFile, status);
159
160 if (status > 0) { /* It is a CA cert */
161 if (!isCA) {
162 error_setg(errp, isServer ?
163 "The certificate %s basic constraints show a CA, "
164 "but we need one for a server" :
165 "The certificate %s basic constraints show a CA, "
166 "but we need one for a client",
167 certFile);
168 return -1;
169 }
170 } else if (status == 0) { /* It is not a CA cert */
171 if (isCA) {
172 error_setg(errp,
173 "The certificate %s basic constraints do not "
174 "show a CA",
175 certFile);
176 return -1;
177 }
178 } else if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
179 /* Missing basicConstraints */
180 if (isCA) {
181 error_setg(errp,
182 "The certificate %s is missing basic constraints "
183 "for a CA",
184 certFile);
185 return -1;
186 }
187 } else { /* General error */
188 error_setg(errp,
189 "Unable to query certificate %s basic constraints: %s",
190 certFile, gnutls_strerror(status));
191 return -1;
192 }
193
194 return 0;
195 }
196
197
198 static int
199 qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 *creds,
200 gnutls_x509_crt_t cert,
201 const char *certFile,
202 bool isCA,
203 Error **errp)
204 {
205 int status;
206 unsigned int usage = 0;
207 unsigned int critical = 0;
208
209 status = gnutls_x509_crt_get_key_usage(cert, &usage, &critical);
210 trace_qcrypto_tls_creds_x509_check_key_usage(
211 creds, certFile, status, usage, critical);
212
213 if (status < 0) {
214 if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
215 usage = isCA ? GNUTLS_KEY_KEY_CERT_SIGN :
216 GNUTLS_KEY_DIGITAL_SIGNATURE;
217 } else {
218 error_setg(errp,
219 "Unable to query certificate %s key usage: %s",
220 certFile, gnutls_strerror(status));
221 return -1;
222 }
223 }
224
225 if (isCA) {
226 if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) {
227 if (critical) {
228 error_setg(errp,
229 "Certificate %s usage does not permit "
230 "certificate signing", certFile);
231 return -1;
232 }
233 }
234 } else {
235 if (!(usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) {
236 if (critical) {
237 error_setg(errp,
238 "Certificate %s usage does not permit digital "
239 "signature", certFile);
240 return -1;
241 }
242 }
243 }
244
245 return 0;
246 }
247
248
249 static int
250 qcrypto_tls_creds_check_cert_key_purpose(QCryptoTLSCredsX509 *creds,
251 gnutls_x509_crt_t cert,
252 const char *certFile,
253 bool isServer,
254 Error **errp)
255 {
256 int status;
257 size_t i;
258 unsigned int purposeCritical;
259 unsigned int critical;
260 char *buffer = NULL;
261 size_t size;
262 bool allowClient = false, allowServer = false;
263
264 critical = 0;
265 for (i = 0; ; i++) {
266 size = 0;
267 status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer,
268 &size, NULL);
269
270 if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
271
272 /* If there is no data at all, then we must allow
273 client/server to pass */
274 if (i == 0) {
275 allowServer = allowClient = true;
276 }
277 break;
278 }
279 if (status != GNUTLS_E_SHORT_MEMORY_BUFFER) {
280 error_setg(errp,
281 "Unable to query certificate %s key purpose: %s",
282 certFile, gnutls_strerror(status));
283 return -1;
284 }
285
286 buffer = g_new0(char, size);
287
288 status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer,
289 &size, &purposeCritical);
290
291 if (status < 0) {
292 trace_qcrypto_tls_creds_x509_check_key_purpose(
293 creds, certFile, status, "<none>", purposeCritical);
294 g_free(buffer);
295 error_setg(errp,
296 "Unable to query certificate %s key purpose: %s",
297 certFile, gnutls_strerror(status));
298 return -1;
299 }
300 trace_qcrypto_tls_creds_x509_check_key_purpose(
301 creds, certFile, status, buffer, purposeCritical);
302 if (purposeCritical) {
303 critical = true;
304 }
305
306 if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_SERVER)) {
307 allowServer = true;
308 } else if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_CLIENT)) {
309 allowClient = true;
310 } else if (g_str_equal(buffer, GNUTLS_KP_ANY)) {
311 allowServer = allowClient = true;
312 }
313
314 g_free(buffer);
315 buffer = NULL;
316 }
317
318 if (isServer) {
319 if (!allowServer) {
320 if (critical) {
321 error_setg(errp,
322 "Certificate %s purpose does not allow "
323 "use with a TLS server", certFile);
324 return -1;
325 }
326 }
327 } else {
328 if (!allowClient) {
329 if (critical) {
330 error_setg(errp,
331 "Certificate %s purpose does not allow use "
332 "with a TLS client", certFile);
333 return -1;
334 }
335 }
336 }
337
338 return 0;
339 }
340
341
342 static int
343 qcrypto_tls_creds_check_cert(QCryptoTLSCredsX509 *creds,
344 gnutls_x509_crt_t cert,
345 const char *certFile,
346 bool isServer,
347 bool isCA,
348 Error **errp)
349 {
350 if (qcrypto_tls_creds_check_cert_times(cert, certFile,
351 isServer, isCA,
352 errp) < 0) {
353 return -1;
354 }
355
356 if (qcrypto_tls_creds_check_cert_basic_constraints(creds,
357 cert, certFile,
358 isServer, isCA,
359 errp) < 0) {
360 return -1;
361 }
362
363 if (qcrypto_tls_creds_check_cert_key_usage(creds,
364 cert, certFile,
365 isCA, errp) < 0) {
366 return -1;
367 }
368
369 if (!isCA &&
370 qcrypto_tls_creds_check_cert_key_purpose(creds,
371 cert, certFile,
372 isServer, errp) < 0) {
373 return -1;
374 }
375
376 return 0;
377 }
378
379 static int
380 qcrypto_tls_creds_check_authority_chain(QCryptoTLSCredsX509 *creds,
381 QCryptoTLSCredsX509Files *files,
382 gnutls_x509_crt_t *certs,
383 unsigned int ncerts,
384 bool isServer,
385 Error **errp)
386 {
387 gnutls_x509_crt_t cert_to_check = certs[ncerts - 1];
388 int retval = 0;
389 gnutls_datum_t dn = {}, dnissuer = {};
390
391 for (int i = 0; i < (ncerts - 1); i++) {
392 if (!gnutls_x509_crt_check_issuer(certs[i], certs[i + 1])) {
393 retval = gnutls_x509_crt_get_dn2(certs[i], &dn);
394 if (retval < 0) {
395 error_setg(errp, "Unable to fetch cert DN: %s",
396 gnutls_strerror(retval));
397 return -1;
398 }
399 retval = gnutls_x509_crt_get_dn2(certs[i + 1], &dnissuer);
400 if (retval < 0) {
401 g_free(dn.data);
402 error_setg(errp, "Unable to fetch cert DN: %s",
403 gnutls_strerror(retval));
404 return -1;
405 }
406 error_setg(errp, "Cert '%s' does not match issuer of cert '%s'",
407 dnissuer.data, dn.data);
408 g_free(dn.data);
409 g_free(dnissuer.data);
410 return -1;
411 }
412 }
413
414 for (;;) {
415 gnutls_x509_crt_t cert_issuer = NULL;
416
417 if (gnutls_x509_crt_check_issuer(cert_to_check,
418 cert_to_check)) {
419 /*
420 * The cert is self-signed indicating we have
421 * reached the root of trust.
422 */
423 return qcrypto_tls_creds_check_cert(
424 creds, cert_to_check, files->cacertpath,
425 isServer, true, errp);
426 }
427 for (int i = 0; i < files->ncacerts; i++) {
428 if (gnutls_x509_crt_check_issuer(cert_to_check,
429 files->cacerts[i])) {
430 cert_issuer = files->cacerts[i];
431 break;
432 }
433 }
434 if (!cert_issuer) {
435 break;
436 }
437
438 if (qcrypto_tls_creds_check_cert(creds, cert_issuer, files->cacertpath,
439 isServer, true, errp) < 0) {
440 return -1;
441 }
442
443 cert_to_check = cert_issuer;
444 }
445
446 retval = gnutls_x509_crt_get_dn2(cert_to_check, &dn);
447 if (retval < 0) {
448 error_setg(errp, "Unable to fetch cert DN: %s",
449 gnutls_strerror(retval));
450 return -1;
451 }
452 error_setg(errp, "Cert '%s' has no issuer in CA chain", dn.data);
453 g_free(dn.data);
454 return -1;
455 }
456
457 static int
458 qcrypto_tls_creds_check_cert_pair(QCryptoTLSCredsX509Files *files,
459 gnutls_x509_crt_t *certs,
460 size_t ncerts,
461 const char *certFile,
462 bool isServer,
463 Error **errp)
464 {
465 unsigned int status;
466
467 if (gnutls_x509_crt_list_verify(certs, ncerts,
468 files->cacerts, files->ncacerts,
469 NULL, 0,
470 0, &status) < 0) {
471 error_setg(errp, isServer ?
472 "Unable to verify server certificate %s against "
473 "CA certificate %s" :
474 "Unable to verify client certificate %s against "
475 "CA certificate %s",
476 certFile, files->cacertpath);
477 return -1;
478 }
479
480 if (status != 0) {
481 const char *reason = "Invalid certificate";
482
483 if (status & GNUTLS_CERT_INVALID) {
484 reason = "The certificate is not trusted";
485 }
486
487 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
488 reason = "The certificate hasn't got a known issuer";
489 }
490
491 if (status & GNUTLS_CERT_REVOKED) {
492 reason = "The certificate has been revoked";
493 }
494
495 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
496 reason = "The certificate uses an insecure algorithm";
497 }
498
499 error_setg(errp,
500 "Our own certificate %s failed validation against %s: %s",
501 certFile, files->cacertpath, reason);
502 return -1;
503 }
504
505 return 0;
506 }
507
508
509 static int
510 qcrypto_tls_creds_load_cert_list(QCryptoTLSCredsX509 *creds,
511 const char *certFile,
512 gnutls_x509_crt_t **certs,
513 unsigned int *ncerts,
514 Error **errp)
515 {
516 gnutls_datum_t data;
517 g_autofree char *buf = NULL;
518 gsize buflen;
519 GError *gerr = NULL;
520 int ret;
521
522 *ncerts = 0;
523 trace_qcrypto_tls_creds_x509_load_cert_list(creds, certFile);
524
525 if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) {
526 error_setg(errp, "Cannot load CA cert list %s: %s",
527 certFile, gerr->message);
528 g_error_free(gerr);
529 return -1;
530 }
531
532 data.data = (unsigned char *)buf;
533 data.size = strlen(buf);
534
535 ret = gnutls_x509_crt_list_import2(certs, ncerts, &data,
536 GNUTLS_X509_FMT_PEM, 0);
537 if (ret < 0) {
538 error_setg(errp, "Unable to import certificate %s: %s",
539 certFile, gnutls_strerror(ret));
540 return -1;
541 }
542
543 return 0;
544 }
545
546
547 static int
548 qcrypto_tls_creds_load_privkey(QCryptoTLSCredsX509 *creds,
549 const char *keyFile,
550 gnutls_x509_privkey_t *key,
551 Error **errp)
552 {
553 gnutls_datum_t data;
554 g_autofree char *buf = NULL;
555 g_autofree char *password = NULL;
556 gsize buflen;
557 GError *gerr = NULL;
558 int ret;
559
560 ret = gnutls_x509_privkey_init(key);
561 if (ret < 0) {
562 error_setg(errp, "Unable to initialize private key: %s",
563 gnutls_strerror(ret));
564 return -1;
565 }
566
567 if (!g_file_get_contents(keyFile, &buf, &buflen, &gerr)) {
568 error_setg(errp, "Cannot load private key %s: %s",
569 keyFile, gerr->message);
570 g_error_free(gerr);
571 return -1;
572 }
573
574 data.data = (unsigned char *)buf;
575 data.size = strlen(buf);
576
577 if (creds->passwordid) {
578 password = qcrypto_secret_lookup_as_utf8(creds->passwordid,
579 errp);
580 if (!password) {
581 return -1;
582 }
583 }
584
585 if (gnutls_x509_privkey_import2(*key, &data,
586 GNUTLS_X509_FMT_PEM,
587 password, 0) < 0) {
588 error_setg(errp, "Unable to import private key %s", keyFile);
589 return -1;
590 }
591
592 return 0;
593 }
594
595
596 static int
597 qcrypto_tls_creds_x509_sanity_check_identity(QCryptoTLSCredsX509 *creds,
598 QCryptoTLSCredsX509Files *files,
599 QCryptoTLSCredsX509IdentFiles *ifiles,
600 bool isServer,
601 Error **errp)
602 {
603 size_t i;
604
605 for (i = 0; i < ifiles->ncerts; i++) {
606 if (qcrypto_tls_creds_check_cert(creds,
607 ifiles->certs[i], ifiles->certpath,
608 isServer, i != 0, errp) < 0) {
609 return -1;
610 }
611 }
612
613 if (ifiles->ncerts &&
614 qcrypto_tls_creds_check_authority_chain(creds, files,
615 ifiles->certs, ifiles->ncerts,
616 isServer, errp) < 0) {
617 return -1;
618 }
619
620 if (ifiles->ncerts &&
621 qcrypto_tls_creds_check_cert_pair(files, ifiles->certs, ifiles->ncerts,
622 ifiles->certpath, isServer, errp) < 0) {
623 return -1;
624 }
625
626 return 0;
627 }
628
629
630 static int
631 qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
632 QCryptoTLSCredsX509Files *files,
633 bool isServer,
634 Error **errp)
635 {
636 size_t i;
637 for (i = 0; i < files->nidentities; i++) {
638 if (qcrypto_tls_creds_x509_sanity_check_identity(creds,
639 files,
640 files->identities[i],
641 isServer,
642 errp) < 0) {
643 return -1;
644 }
645 }
646 return 0;
647 }
648
649
650 static int
651 qcrypto_tls_creds_x509_load_ca(QCryptoTLSCredsX509 *creds,
652 QCryptoTLSCredsBox *box,
653 QCryptoTLSCredsX509Files *files,
654 bool isServer,
655 Error **errp)
656 {
657 int ret;
658
659 if (qcrypto_tls_creds_get_path(&creds->parent_obj,
660 QCRYPTO_TLS_CREDS_X509_CA_CERT,
661 true, &files->cacertpath, errp) < 0) {
662 return -1;
663 }
664
665 if (qcrypto_tls_creds_load_cert_list(creds,
666 files->cacertpath,
667 &files->cacerts,
668 &files->ncacerts,
669 errp) < 0) {
670 return -1;
671 }
672
673 ret = gnutls_certificate_set_x509_trust(box->data.cert,
674 files->cacerts, files->ncacerts);
675 if (ret < 0) {
676 error_setg(errp, "Cannot set CA certificate '%s': %s",
677 files->cacertpath, gnutls_strerror(ret));
678 return -1;
679 }
680
681 return 0;
682 }
683
684
685 static QCryptoTLSCredsX509IdentFiles *
686 qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
687 QCryptoTLSCredsBox *box,
688 const char *certbase,
689 const char *keybase,
690 Error **errp)
691 {
692 g_autoptr(QCryptoTLSCredsX509IdentFiles) files =
693 g_new0(QCryptoTLSCredsX509IdentFiles, 1);
694 int ret;
695
696 if (qcrypto_tls_creds_get_path(&creds->parent_obj, certbase,
697 false, &files->certpath, errp) < 0 ||
698 qcrypto_tls_creds_get_path(&creds->parent_obj, keybase,
699 false, &files->keypath, errp) < 0) {
700 return NULL;
701 }
702
703 if (!files->certpath &&
704 !files->keypath) {
705 return NULL;
706 }
707 if (files->certpath && !files->keypath) {
708 g_autofree char *keypath =
709 qcrypto_tls_creds_build_path(&creds->parent_obj, keybase);
710 error_setg(errp, "Cert '%s' without corresponding key '%s'",
711 files->certpath, keypath);
712 return NULL;
713 }
714 if (!files->certpath && files->keypath) {
715 g_autofree char *certpath =
716 qcrypto_tls_creds_build_path(&creds->parent_obj, certbase);
717 error_setg(errp, "Key '%s' without corresponding cert '%s'",
718 files->keypath, certpath);
719 return NULL;
720 }
721
722 if (qcrypto_tls_creds_load_cert_list(creds,
723 files->certpath,
724 &files->certs,
725 &files->ncerts,
726 errp) < 0) {
727 return NULL;
728 }
729
730 if (qcrypto_tls_creds_load_privkey(creds,
731 files->keypath,
732 &files->key,
733 errp) < 0) {
734 return NULL;
735 }
736
737 ret = gnutls_certificate_set_x509_key(box->data.cert,
738 files->certs,
739 files->ncerts,
740 files->key);
741 if (ret < 0) {
742 error_setg(errp, "Cannot set certificate '%s' & key '%s': %s",
743 files->certpath, files->keypath, gnutls_strerror(ret));
744 return NULL;
745 }
746 return g_steal_pointer(&files);
747 }
748
749
750 static int
751 qcrypto_tls_creds_x509_load_identities(QCryptoTLSCredsX509 *creds,
752 QCryptoTLSCredsBox *box,
753 QCryptoTLSCredsX509Files *files,
754 bool isServer,
755 Error **errp)
756 {
757 ERRP_GUARD();
758 QCryptoTLSCredsX509IdentFiles *ifiles;
759 size_t i;
760
761 ifiles = qcrypto_tls_creds_x509_load_identity(
762 creds, box,
763 isServer ?
764 QCRYPTO_TLS_CREDS_X509_SERVER_CERT :
765 QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
766 isServer ?
767 QCRYPTO_TLS_CREDS_X509_SERVER_KEY :
768 QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
769 errp);
770 if (!ifiles && *errp) {
771 return -1;
772 }
773
774 if (ifiles) {
775 files->identities = g_renew(QCryptoTLSCredsX509IdentFiles *,
776 files->identities,
777 files->nidentities + 1);
778 files->identities[files->nidentities++] = ifiles;
779 }
780
781 for (i = 0; i < QCRYPTO_TLS_CREDS_X509_IDENTITY_MAX; i++) {
782 g_autofree char *cert = g_strdup_printf(
783 isServer ?
784 QCRYPTO_TLS_CREDS_X509_SERVER_CERT_N :
785 QCRYPTO_TLS_CREDS_X509_CLIENT_CERT_N, i);
786 g_autofree char *key = g_strdup_printf(
787 isServer ?
788 QCRYPTO_TLS_CREDS_X509_SERVER_KEY_N :
789 QCRYPTO_TLS_CREDS_X509_CLIENT_KEY_N, i);
790
791 ifiles = qcrypto_tls_creds_x509_load_identity(creds, box,
792 cert, key, errp);
793 if (!ifiles && *errp) {
794 return -1;
795 }
796 if (!ifiles) {
797 break;
798 }
799
800 files->identities = g_renew(QCryptoTLSCredsX509IdentFiles *,
801 files->identities,
802 files->nidentities + 1);
803 files->identities[files->nidentities++] = ifiles;
804 }
805
806 if (files->nidentities == 0 && isServer) {
807 g_autofree char *certpath = qcrypto_tls_creds_build_path(
808 &creds->parent_obj, QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
809 g_autofree char *keypath = qcrypto_tls_creds_build_path(
810 &creds->parent_obj, QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
811 error_setg(errp, "Missing server cert '%s' & key '%s'",
812 certpath, keypath);
813 return -1;
814 }
815
816 return 0;
817 }
818
819
820 static int
821 qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
822 Error **errp)
823 {
824 g_autoptr(QCryptoTLSCredsBox) box = NULL;
825 g_autoptr(QCryptoTLSCredsX509Files) files = NULL;
826 g_autofree char *cacrl = NULL;
827 g_autofree char *dhparams = NULL;
828 bool isServer = (creds->parent_obj.endpoint ==
829 QCRYPTO_TLS_CREDS_ENDPOINT_SERVER);
830 int ret;
831
832 if (!creds->parent_obj.dir) {
833 error_setg(errp, "Missing 'dir' property value");
834 return -1;
835 }
836
837 trace_qcrypto_tls_creds_x509_load(creds, creds->parent_obj.dir);
838
839 if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
840 box = qcrypto_tls_creds_box_new_server(GNUTLS_CRD_CERTIFICATE);
841 } else {
842 box = qcrypto_tls_creds_box_new_client(GNUTLS_CRD_CERTIFICATE);
843 }
844
845 ret = gnutls_certificate_allocate_credentials(&box->data.cert);
846 if (ret < 0) {
847 error_setg(errp, "Cannot allocate credentials: '%s'",
848 gnutls_strerror(ret));
849 return -1;
850 }
851
852 files = qcrypto_tls_creds_x509_files_new();
853
854 if (qcrypto_tls_creds_x509_load_ca(creds, box, files, isServer, errp) < 0) {
855 return -1;
856 }
857
858 if (qcrypto_tls_creds_x509_load_identities(creds, box, files,
859 isServer, errp) < 0) {
860 return -1;
861 }
862
863 if (isServer) {
864 if (qcrypto_tls_creds_get_path(&creds->parent_obj,
865 QCRYPTO_TLS_CREDS_X509_CA_CRL,
866 false, &cacrl, errp) < 0 ||
867 qcrypto_tls_creds_get_path(&creds->parent_obj,
868 QCRYPTO_TLS_CREDS_DH_PARAMS,
869 false, &dhparams, errp) < 0) {
870 return -1;
871 }
872 }
873
874 if (creds->sanityCheck &&
875 qcrypto_tls_creds_x509_sanity_check(creds, files, isServer, errp) < 0) {
876 return -1;
877 }
878
879 if (cacrl != NULL) {
880 ret = gnutls_certificate_set_x509_crl_file(box->data.cert,
881 cacrl,
882 GNUTLS_X509_FMT_PEM);
883 if (ret < 0) {
884 error_setg(errp, "Cannot load CRL '%s': %s",
885 cacrl, gnutls_strerror(ret));
886 return -1;
887 }
888 }
889
890 if (isServer) {
891 if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
892 &box->dh_params,
893 errp) < 0) {
894 return -1;
895 }
896 if (box->dh_params) {
897 gnutls_certificate_set_dh_params(box->data.cert, box->dh_params);
898 }
899 }
900 creds->parent_obj.box = g_steal_pointer(&box);
901
902 return 0;
903 }
904
905
906 #else /* ! CONFIG_GNUTLS */
907
908
909 static void
910 qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED,
911 Error **errp)
912 {
913 error_setg(errp, "TLS credentials support requires GNUTLS");
914 }
915
916
917 #endif /* ! CONFIG_GNUTLS */
918
919
920 static void
921 qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp)
922 {
923 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(uc);
924
925 qcrypto_tls_creds_x509_load(creds, errp);
926 }
927
928
929 static void
930 qcrypto_tls_creds_x509_prop_set_sanity(Object *obj,
931 bool value,
932 Error **errp G_GNUC_UNUSED)
933 {
934 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
935
936 creds->sanityCheck = value;
937 }
938
939
940 static void
941 qcrypto_tls_creds_x509_prop_set_passwordid(Object *obj,
942 const char *value,
943 Error **errp G_GNUC_UNUSED)
944 {
945 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
946
947 creds->passwordid = g_strdup(value);
948 }
949
950
951 static char *
952 qcrypto_tls_creds_x509_prop_get_passwordid(Object *obj,
953 Error **errp G_GNUC_UNUSED)
954 {
955 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
956
957 return g_strdup(creds->passwordid);
958 }
959
960
961 static bool
962 qcrypto_tls_creds_x509_prop_get_sanity(Object *obj,
963 Error **errp G_GNUC_UNUSED)
964 {
965 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
966
967 return creds->sanityCheck;
968 }
969
970
971 #ifdef CONFIG_GNUTLS
972
973
974 static bool
975 qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
976 {
977 QCryptoTLSCredsX509 *x509_creds = QCRYPTO_TLS_CREDS_X509(creds);
978 Error *local_err = NULL;
979 QCryptoTLSCredsBox *creds_box = creds->box;
980
981 creds->box = NULL;
982 qcrypto_tls_creds_x509_load(x509_creds, &local_err);
983 if (local_err) {
984 creds->box = creds_box;
985 error_propagate(errp, local_err);
986 return false;
987 }
988
989 qcrypto_tls_creds_box_unref(creds_box);
990 return true;
991 }
992
993
994 #else /* ! CONFIG_GNUTLS */
995
996
997 static bool
998 qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
999 {
1000 return false;
1001 }
1002
1003
1004 #endif /* ! CONFIG_GNUTLS */
1005
1006
1007 static void
1008 qcrypto_tls_creds_x509_init(Object *obj)
1009 {
1010 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
1011
1012 creds->sanityCheck = true;
1013 }
1014
1015
1016 static void
1017 qcrypto_tls_creds_x509_finalize(Object *obj)
1018 {
1019 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
1020
1021 g_free(creds->passwordid);
1022 }
1023
1024
1025 static void
1026 qcrypto_tls_creds_x509_class_init(ObjectClass *oc, const void *data)
1027 {
1028 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
1029 QCryptoTLSCredsClass *ctcc = QCRYPTO_TLS_CREDS_CLASS(oc);
1030
1031 ctcc->reload = qcrypto_tls_creds_x509_reload;
1032
1033 ucc->complete = qcrypto_tls_creds_x509_complete;
1034
1035 object_class_property_add_bool(oc, "sanity-check",
1036 qcrypto_tls_creds_x509_prop_get_sanity,
1037 qcrypto_tls_creds_x509_prop_set_sanity);
1038 object_class_property_add_str(oc, "passwordid",
1039 qcrypto_tls_creds_x509_prop_get_passwordid,
1040 qcrypto_tls_creds_x509_prop_set_passwordid);
1041 }
1042
1043
1044 static const TypeInfo qcrypto_tls_creds_x509_info = {
1045 .parent = TYPE_QCRYPTO_TLS_CREDS,
1046 .name = TYPE_QCRYPTO_TLS_CREDS_X509,
1047 .instance_size = sizeof(QCryptoTLSCredsX509),
1048 .instance_init = qcrypto_tls_creds_x509_init,
1049 .instance_finalize = qcrypto_tls_creds_x509_finalize,
1050 .class_size = sizeof(QCryptoTLSCredsX509Class),
1051 .class_init = qcrypto_tls_creds_x509_class_init,
1052 .interfaces = (const InterfaceInfo[]) {
1053 { TYPE_USER_CREATABLE },
1054 { }
1055 }
1056 };
1057
1058
1059 static void
1060 qcrypto_tls_creds_x509_register_types(void)
1061 {
1062 type_register_static(&qcrypto_tls_creds_x509_info);
1063 }
1064
1065
1066 type_init(qcrypto_tls_creds_x509_register_types);