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