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 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 "crypto/tlscredspriv.h" 24 #include "crypto/secret.h" 25 #include "qom/object_interfaces.h" 26 #include "trace.h" 27 28 29 #ifdef CONFIG_GNUTLS 30 31 #include <gnutls/x509.h> 32 33 34 static int 35 qcrypto_tls_creds_check_cert_times(gnutls_x509_crt_t cert, 36 const char *certFile, 37 bool isServer, 38 bool isCA, 39 Error **errp) 40 { 41 time_t now = time(NULL); 42 43 if (now == ((time_t)-1)) { 44 error_setg_errno(errp, errno, "cannot get current time"); 45 return -1; 46 } 47 48 if (gnutls_x509_crt_get_expiration_time(cert) < now) { 49 error_setg(errp, 50 (isCA ? 51 "The CA certificate %s has expired" : 52 (isServer ? 53 "The server certificate %s has expired" : 54 "The client certificate %s has expired")), 55 certFile); 56 return -1; 57 } 58 59 if (gnutls_x509_crt_get_activation_time(cert) > now) { 60 error_setg(errp, 61 (isCA ? 62 "The CA certificate %s is not yet active" : 63 (isServer ? 64 "The server certificate %s is not yet active" : 65 "The client certificate %s is not yet active")), 66 certFile); 67 return -1; 68 } 69 70 return 0; 71 } 72 73 74 #if LIBGNUTLS_VERSION_NUMBER >= 2 75 /* 76 * The gnutls_x509_crt_get_basic_constraints function isn't 77 * available in GNUTLS 1.0.x branches. This isn't critical 78 * though, since gnutls_certificate_verify_peers2 will do 79 * pretty much the same check at runtime, so we can just 80 * disable this code 81 */ 82 static int 83 qcrypto_tls_creds_check_cert_basic_constraints(QCryptoTLSCredsX509 *creds, 84 gnutls_x509_crt_t cert, 85 const char *certFile, 86 bool isServer, 87 bool isCA, 88 Error **errp) 89 { 90 int status; 91 92 status = gnutls_x509_crt_get_basic_constraints(cert, NULL, NULL, NULL); 93 trace_qcrypto_tls_creds_x509_check_basic_constraints( 94 creds, certFile, status); 95 96 if (status > 0) { /* It is a CA cert */ 97 if (!isCA) { 98 error_setg(errp, isServer ? 99 "The certificate %s basic constraints show a CA, " 100 "but we need one for a server" : 101 "The certificate %s basic constraints show a CA, " 102 "but we need one for a client", 103 certFile); 104 return -1; 105 } 106 } else if (status == 0) { /* It is not a CA cert */ 107 if (isCA) { 108 error_setg(errp, 109 "The certificate %s basic constraints do not " 110 "show a CA", 111 certFile); 112 return -1; 113 } 114 } else if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { 115 /* Missing basicConstraints */ 116 if (isCA) { 117 error_setg(errp, 118 "The certificate %s is missing basic constraints " 119 "for a CA", 120 certFile); 121 return -1; 122 } 123 } else { /* General error */ 124 error_setg(errp, 125 "Unable to query certificate %s basic constraints: %s", 126 certFile, gnutls_strerror(status)); 127 return -1; 128 } 129 130 return 0; 131 } 132 #endif 133 134 135 static int 136 qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 *creds, 137 gnutls_x509_crt_t cert, 138 const char *certFile, 139 bool isCA, 140 Error **errp) 141 { 142 int status; 143 unsigned int usage = 0; 144 unsigned int critical = 0; 145 146 status = gnutls_x509_crt_get_key_usage(cert, &usage, &critical); 147 trace_qcrypto_tls_creds_x509_check_key_usage( 148 creds, certFile, status, usage, critical); 149 150 if (status < 0) { 151 if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { 152 usage = isCA ? GNUTLS_KEY_KEY_CERT_SIGN : 153 GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT; 154 } else { 155 error_setg(errp, 156 "Unable to query certificate %s key usage: %s", 157 certFile, gnutls_strerror(status)); 158 return -1; 159 } 160 } 161 162 if (isCA) { 163 if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) { 164 if (critical) { 165 error_setg(errp, 166 "Certificate %s usage does not permit " 167 "certificate signing", certFile); 168 return -1; 169 } 170 } 171 } else { 172 if (!(usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { 173 if (critical) { 174 error_setg(errp, 175 "Certificate %s usage does not permit digital " 176 "signature", certFile); 177 return -1; 178 } 179 } 180 if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) { 181 if (critical) { 182 error_setg(errp, 183 "Certificate %s usage does not permit key " 184 "encipherment", certFile); 185 return -1; 186 } 187 } 188 } 189 190 return 0; 191 } 192 193 194 static int 195 qcrypto_tls_creds_check_cert_key_purpose(QCryptoTLSCredsX509 *creds, 196 gnutls_x509_crt_t cert, 197 const char *certFile, 198 bool isServer, 199 Error **errp) 200 { 201 int status; 202 size_t i; 203 unsigned int purposeCritical; 204 unsigned int critical; 205 char *buffer = NULL; 206 size_t size; 207 bool allowClient = false, allowServer = false; 208 209 critical = 0; 210 for (i = 0; ; i++) { 211 size = 0; 212 status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer, 213 &size, NULL); 214 215 if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { 216 217 /* If there is no data at all, then we must allow 218 client/server to pass */ 219 if (i == 0) { 220 allowServer = allowClient = true; 221 } 222 break; 223 } 224 if (status != GNUTLS_E_SHORT_MEMORY_BUFFER) { 225 error_setg(errp, 226 "Unable to query certificate %s key purpose: %s", 227 certFile, gnutls_strerror(status)); 228 return -1; 229 } 230 231 buffer = g_new0(char, size); 232 233 status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer, 234 &size, &purposeCritical); 235 236 if (status < 0) { 237 trace_qcrypto_tls_creds_x509_check_key_purpose( 238 creds, certFile, status, "<none>", purposeCritical); 239 g_free(buffer); 240 error_setg(errp, 241 "Unable to query certificate %s key purpose: %s", 242 certFile, gnutls_strerror(status)); 243 return -1; 244 } 245 trace_qcrypto_tls_creds_x509_check_key_purpose( 246 creds, certFile, status, buffer, purposeCritical); 247 if (purposeCritical) { 248 critical = true; 249 } 250 251 if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_SERVER)) { 252 allowServer = true; 253 } else if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_CLIENT)) { 254 allowClient = true; 255 } else if (g_str_equal(buffer, GNUTLS_KP_ANY)) { 256 allowServer = allowClient = true; 257 } 258 259 g_free(buffer); 260 buffer = NULL; 261 } 262 263 if (isServer) { 264 if (!allowServer) { 265 if (critical) { 266 error_setg(errp, 267 "Certificate %s purpose does not allow " 268 "use with a TLS server", certFile); 269 return -1; 270 } 271 } 272 } else { 273 if (!allowClient) { 274 if (critical) { 275 error_setg(errp, 276 "Certificate %s purpose does not allow use " 277 "with a TLS client", certFile); 278 return -1; 279 } 280 } 281 } 282 283 return 0; 284 } 285 286 287 static int 288 qcrypto_tls_creds_check_cert(QCryptoTLSCredsX509 *creds, 289 gnutls_x509_crt_t cert, 290 const char *certFile, 291 bool isServer, 292 bool isCA, 293 Error **errp) 294 { 295 if (qcrypto_tls_creds_check_cert_times(cert, certFile, 296 isServer, isCA, 297 errp) < 0) { 298 return -1; 299 } 300 301 #if LIBGNUTLS_VERSION_NUMBER >= 2 302 if (qcrypto_tls_creds_check_cert_basic_constraints(creds, 303 cert, certFile, 304 isServer, isCA, 305 errp) < 0) { 306 return -1; 307 } 308 #endif 309 310 if (qcrypto_tls_creds_check_cert_key_usage(creds, 311 cert, certFile, 312 isCA, errp) < 0) { 313 return -1; 314 } 315 316 if (!isCA && 317 qcrypto_tls_creds_check_cert_key_purpose(creds, 318 cert, certFile, 319 isServer, errp) < 0) { 320 return -1; 321 } 322 323 return 0; 324 } 325 326 327 static int 328 qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t cert, 329 const char *certFile, 330 gnutls_x509_crt_t *cacerts, 331 size_t ncacerts, 332 const char *cacertFile, 333 bool isServer, 334 Error **errp) 335 { 336 unsigned int status; 337 338 if (gnutls_x509_crt_list_verify(&cert, 1, 339 cacerts, ncacerts, 340 NULL, 0, 341 0, &status) < 0) { 342 error_setg(errp, isServer ? 343 "Unable to verify server certificate %s against " 344 "CA certificate %s" : 345 "Unable to verify client certificate %s against " 346 "CA certificate %s", 347 certFile, cacertFile); 348 return -1; 349 } 350 351 if (status != 0) { 352 const char *reason = "Invalid certificate"; 353 354 if (status & GNUTLS_CERT_INVALID) { 355 reason = "The certificate is not trusted"; 356 } 357 358 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { 359 reason = "The certificate hasn't got a known issuer"; 360 } 361 362 if (status & GNUTLS_CERT_REVOKED) { 363 reason = "The certificate has been revoked"; 364 } 365 366 #ifndef GNUTLS_1_0_COMPAT 367 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { 368 reason = "The certificate uses an insecure algorithm"; 369 } 370 #endif 371 372 error_setg(errp, 373 "Our own certificate %s failed validation against %s: %s", 374 certFile, cacertFile, reason); 375 return -1; 376 } 377 378 return 0; 379 } 380 381 382 static gnutls_x509_crt_t 383 qcrypto_tls_creds_load_cert(QCryptoTLSCredsX509 *creds, 384 const char *certFile, 385 bool isServer, 386 Error **errp) 387 { 388 gnutls_datum_t data; 389 gnutls_x509_crt_t cert = NULL; 390 char *buf = NULL; 391 gsize buflen; 392 GError *gerr; 393 int ret = -1; 394 395 trace_qcrypto_tls_creds_x509_load_cert(creds, isServer, certFile); 396 397 if (gnutls_x509_crt_init(&cert) < 0) { 398 error_setg(errp, "Unable to initialize certificate"); 399 goto cleanup; 400 } 401 402 if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) { 403 error_setg(errp, "Cannot load CA cert list %s: %s", 404 certFile, gerr->message); 405 g_error_free(gerr); 406 goto cleanup; 407 } 408 409 data.data = (unsigned char *)buf; 410 data.size = strlen(buf); 411 412 if (gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM) < 0) { 413 error_setg(errp, isServer ? 414 "Unable to import server certificate %s" : 415 "Unable to import client certificate %s", 416 certFile); 417 goto cleanup; 418 } 419 420 ret = 0; 421 422 cleanup: 423 if (ret != 0) { 424 gnutls_x509_crt_deinit(cert); 425 cert = NULL; 426 } 427 g_free(buf); 428 return cert; 429 } 430 431 432 static int 433 qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 *creds, 434 const char *certFile, 435 gnutls_x509_crt_t *certs, 436 unsigned int certMax, 437 size_t *ncerts, 438 Error **errp) 439 { 440 gnutls_datum_t data; 441 char *buf = NULL; 442 gsize buflen; 443 int ret = -1; 444 GError *gerr = NULL; 445 446 *ncerts = 0; 447 trace_qcrypto_tls_creds_x509_load_cert_list(creds, certFile); 448 449 if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) { 450 error_setg(errp, "Cannot load CA cert list %s: %s", 451 certFile, gerr->message); 452 g_error_free(gerr); 453 goto cleanup; 454 } 455 456 data.data = (unsigned char *)buf; 457 data.size = strlen(buf); 458 459 if (gnutls_x509_crt_list_import(certs, &certMax, &data, 460 GNUTLS_X509_FMT_PEM, 0) < 0) { 461 error_setg(errp, 462 "Unable to import CA certificate list %s", 463 certFile); 464 goto cleanup; 465 } 466 *ncerts = certMax; 467 468 ret = 0; 469 470 cleanup: 471 g_free(buf); 472 return ret; 473 } 474 475 476 #define MAX_CERTS 16 477 static int 478 qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds, 479 bool isServer, 480 const char *cacertFile, 481 const char *certFile, 482 Error **errp) 483 { 484 gnutls_x509_crt_t cert = NULL; 485 gnutls_x509_crt_t cacerts[MAX_CERTS]; 486 size_t ncacerts = 0; 487 size_t i; 488 int ret = -1; 489 490 memset(cacerts, 0, sizeof(cacerts)); 491 if (certFile && 492 access(certFile, R_OK) == 0) { 493 cert = qcrypto_tls_creds_load_cert(creds, 494 certFile, isServer, 495 errp); 496 if (!cert) { 497 goto cleanup; 498 } 499 } 500 if (access(cacertFile, R_OK) == 0) { 501 if (qcrypto_tls_creds_load_ca_cert_list(creds, 502 cacertFile, cacerts, 503 MAX_CERTS, &ncacerts, 504 errp) < 0) { 505 goto cleanup; 506 } 507 } 508 509 if (cert && 510 qcrypto_tls_creds_check_cert(creds, 511 cert, certFile, isServer, 512 false, errp) < 0) { 513 goto cleanup; 514 } 515 516 for (i = 0; i < ncacerts; i++) { 517 if (qcrypto_tls_creds_check_cert(creds, 518 cacerts[i], cacertFile, 519 isServer, true, errp) < 0) { 520 goto cleanup; 521 } 522 } 523 524 if (cert && ncacerts && 525 qcrypto_tls_creds_check_cert_pair(cert, certFile, cacerts, 526 ncacerts, cacertFile, 527 isServer, errp) < 0) { 528 goto cleanup; 529 } 530 531 ret = 0; 532 533 cleanup: 534 if (cert) { 535 gnutls_x509_crt_deinit(cert); 536 } 537 for (i = 0; i < ncacerts; i++) { 538 gnutls_x509_crt_deinit(cacerts[i]); 539 } 540 return ret; 541 } 542 543 544 static int 545 qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds, 546 Error **errp) 547 { 548 char *cacert = NULL, *cacrl = NULL, *cert = NULL, 549 *key = NULL, *dhparams = NULL; 550 int ret; 551 int rv = -1; 552 553 trace_qcrypto_tls_creds_x509_load(creds, 554 creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>"); 555 556 if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { 557 if (qcrypto_tls_creds_get_path(&creds->parent_obj, 558 QCRYPTO_TLS_CREDS_X509_CA_CERT, 559 true, &cacert, errp) < 0 || 560 qcrypto_tls_creds_get_path(&creds->parent_obj, 561 QCRYPTO_TLS_CREDS_X509_CA_CRL, 562 false, &cacrl, errp) < 0 || 563 qcrypto_tls_creds_get_path(&creds->parent_obj, 564 QCRYPTO_TLS_CREDS_X509_SERVER_CERT, 565 true, &cert, errp) < 0 || 566 qcrypto_tls_creds_get_path(&creds->parent_obj, 567 QCRYPTO_TLS_CREDS_X509_SERVER_KEY, 568 true, &key, errp) < 0 || 569 qcrypto_tls_creds_get_path(&creds->parent_obj, 570 QCRYPTO_TLS_CREDS_DH_PARAMS, 571 false, &dhparams, errp) < 0) { 572 goto cleanup; 573 } 574 } else { 575 if (qcrypto_tls_creds_get_path(&creds->parent_obj, 576 QCRYPTO_TLS_CREDS_X509_CA_CERT, 577 true, &cacert, errp) < 0 || 578 qcrypto_tls_creds_get_path(&creds->parent_obj, 579 QCRYPTO_TLS_CREDS_X509_CLIENT_CERT, 580 false, &cert, errp) < 0 || 581 qcrypto_tls_creds_get_path(&creds->parent_obj, 582 QCRYPTO_TLS_CREDS_X509_CLIENT_KEY, 583 false, &key, errp) < 0) { 584 goto cleanup; 585 } 586 } 587 588 if (creds->sanityCheck && 589 qcrypto_tls_creds_x509_sanity_check(creds, 590 creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, 591 cacert, cert, errp) < 0) { 592 goto cleanup; 593 } 594 595 ret = gnutls_certificate_allocate_credentials(&creds->data); 596 if (ret < 0) { 597 error_setg(errp, "Cannot allocate credentials: '%s'", 598 gnutls_strerror(ret)); 599 goto cleanup; 600 } 601 602 ret = gnutls_certificate_set_x509_trust_file(creds->data, 603 cacert, 604 GNUTLS_X509_FMT_PEM); 605 if (ret < 0) { 606 error_setg(errp, "Cannot load CA certificate '%s': %s", 607 cacert, gnutls_strerror(ret)); 608 goto cleanup; 609 } 610 611 if (cert != NULL && key != NULL) { 612 #if GNUTLS_VERSION_NUMBER >= 0x030111 613 char *password = NULL; 614 if (creds->passwordid) { 615 password = qcrypto_secret_lookup_as_utf8(creds->passwordid, 616 errp); 617 if (!password) { 618 goto cleanup; 619 } 620 } 621 ret = gnutls_certificate_set_x509_key_file2(creds->data, 622 cert, key, 623 GNUTLS_X509_FMT_PEM, 624 password, 625 0); 626 g_free(password); 627 #else /* GNUTLS_VERSION_NUMBER < 0x030111 */ 628 if (creds->passwordid) { 629 error_setg(errp, "PKCS8 decryption requires GNUTLS >= 3.1.11"); 630 goto cleanup; 631 } 632 ret = gnutls_certificate_set_x509_key_file(creds->data, 633 cert, key, 634 GNUTLS_X509_FMT_PEM); 635 #endif /* GNUTLS_VERSION_NUMBER < 0x030111 */ 636 if (ret < 0) { 637 error_setg(errp, "Cannot load certificate '%s' & key '%s': %s", 638 cert, key, gnutls_strerror(ret)); 639 goto cleanup; 640 } 641 } 642 643 if (cacrl != NULL) { 644 ret = gnutls_certificate_set_x509_crl_file(creds->data, 645 cacrl, 646 GNUTLS_X509_FMT_PEM); 647 if (ret < 0) { 648 error_setg(errp, "Cannot load CRL '%s': %s", 649 cacrl, gnutls_strerror(ret)); 650 goto cleanup; 651 } 652 } 653 654 if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { 655 if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams, 656 &creds->parent_obj.dh_params, 657 errp) < 0) { 658 goto cleanup; 659 } 660 gnutls_certificate_set_dh_params(creds->data, 661 creds->parent_obj.dh_params); 662 } 663 664 rv = 0; 665 cleanup: 666 g_free(cacert); 667 g_free(cacrl); 668 g_free(cert); 669 g_free(key); 670 g_free(dhparams); 671 return rv; 672 } 673 674 675 static void 676 qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds) 677 { 678 if (creds->data) { 679 gnutls_certificate_free_credentials(creds->data); 680 creds->data = NULL; 681 } 682 if (creds->parent_obj.dh_params) { 683 gnutls_dh_params_deinit(creds->parent_obj.dh_params); 684 creds->parent_obj.dh_params = NULL; 685 } 686 } 687 688 689 #else /* ! CONFIG_GNUTLS */ 690 691 692 static void 693 qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED, 694 Error **errp) 695 { 696 error_setg(errp, "TLS credentials support requires GNUTLS"); 697 } 698 699 700 static void 701 qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED) 702 { 703 /* nada */ 704 } 705 706 707 #endif /* ! CONFIG_GNUTLS */ 708 709 710 static void 711 qcrypto_tls_creds_x509_prop_set_loaded(Object *obj, 712 bool value, 713 Error **errp) 714 { 715 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 716 717 if (value) { 718 qcrypto_tls_creds_x509_load(creds, errp); 719 } else { 720 qcrypto_tls_creds_x509_unload(creds); 721 } 722 } 723 724 725 #ifdef CONFIG_GNUTLS 726 727 728 static bool 729 qcrypto_tls_creds_x509_prop_get_loaded(Object *obj, 730 Error **errp G_GNUC_UNUSED) 731 { 732 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 733 734 return creds->data != NULL; 735 } 736 737 738 #else /* ! CONFIG_GNUTLS */ 739 740 741 static bool 742 qcrypto_tls_creds_x509_prop_get_loaded(Object *obj G_GNUC_UNUSED, 743 Error **errp G_GNUC_UNUSED) 744 { 745 return false; 746 } 747 748 749 #endif /* ! CONFIG_GNUTLS */ 750 751 752 static void 753 qcrypto_tls_creds_x509_prop_set_sanity(Object *obj, 754 bool value, 755 Error **errp G_GNUC_UNUSED) 756 { 757 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 758 759 creds->sanityCheck = value; 760 } 761 762 763 static void 764 qcrypto_tls_creds_x509_prop_set_passwordid(Object *obj, 765 const char *value, 766 Error **errp G_GNUC_UNUSED) 767 { 768 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 769 770 creds->passwordid = g_strdup(value); 771 } 772 773 774 static char * 775 qcrypto_tls_creds_x509_prop_get_passwordid(Object *obj, 776 Error **errp G_GNUC_UNUSED) 777 { 778 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 779 780 return g_strdup(creds->passwordid); 781 } 782 783 784 static bool 785 qcrypto_tls_creds_x509_prop_get_sanity(Object *obj, 786 Error **errp G_GNUC_UNUSED) 787 { 788 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 789 790 return creds->sanityCheck; 791 } 792 793 794 static void 795 qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp) 796 { 797 object_property_set_bool(OBJECT(uc), true, "loaded", errp); 798 } 799 800 801 static void 802 qcrypto_tls_creds_x509_init(Object *obj) 803 { 804 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 805 806 creds->sanityCheck = true; 807 808 object_property_add_bool(obj, "loaded", 809 qcrypto_tls_creds_x509_prop_get_loaded, 810 qcrypto_tls_creds_x509_prop_set_loaded, 811 NULL); 812 object_property_add_bool(obj, "sanity-check", 813 qcrypto_tls_creds_x509_prop_get_sanity, 814 qcrypto_tls_creds_x509_prop_set_sanity, 815 NULL); 816 object_property_add_str(obj, "passwordid", 817 qcrypto_tls_creds_x509_prop_get_passwordid, 818 qcrypto_tls_creds_x509_prop_set_passwordid, 819 NULL); 820 } 821 822 823 static void 824 qcrypto_tls_creds_x509_finalize(Object *obj) 825 { 826 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 827 828 g_free(creds->passwordid); 829 qcrypto_tls_creds_x509_unload(creds); 830 } 831 832 833 static void 834 qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data) 835 { 836 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 837 838 ucc->complete = qcrypto_tls_creds_x509_complete; 839 } 840 841 842 static const TypeInfo qcrypto_tls_creds_x509_info = { 843 .parent = TYPE_QCRYPTO_TLS_CREDS, 844 .name = TYPE_QCRYPTO_TLS_CREDS_X509, 845 .instance_size = sizeof(QCryptoTLSCredsX509), 846 .instance_init = qcrypto_tls_creds_x509_init, 847 .instance_finalize = qcrypto_tls_creds_x509_finalize, 848 .class_size = sizeof(QCryptoTLSCredsX509Class), 849 .class_init = qcrypto_tls_creds_x509_class_init, 850 .interfaces = (InterfaceInfo[]) { 851 { TYPE_USER_CREATABLE }, 852 { } 853 } 854 }; 855 856 857 static void 858 qcrypto_tls_creds_x509_register_types(void) 859 { 860 type_register_static(&qcrypto_tls_creds_x509_info); 861 } 862 863 864 type_init(qcrypto_tls_creds_x509_register_types); 865