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 396 trace_qcrypto_tls_creds_x509_load_cert(creds, isServer, certFile); 397 398 if (gnutls_x509_crt_init(&cert) < 0) { 399 error_setg(errp, "Unable to initialize certificate"); 400 goto cleanup; 401 } 402 403 if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) { 404 error_setg(errp, "Cannot load CA cert list %s: %s", 405 certFile, gerr->message); 406 g_error_free(gerr); 407 goto cleanup; 408 } 409 410 data.data = (unsigned char *)buf; 411 data.size = strlen(buf); 412 413 if (gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM) < 0) { 414 error_setg(errp, isServer ? 415 "Unable to import server certificate %s" : 416 "Unable to import client certificate %s", 417 certFile); 418 goto cleanup; 419 } 420 421 ret = 0; 422 423 cleanup: 424 if (ret != 0) { 425 gnutls_x509_crt_deinit(cert); 426 cert = NULL; 427 } 428 g_free(buf); 429 return cert; 430 } 431 432 433 static int 434 qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 *creds, 435 const char *certFile, 436 gnutls_x509_crt_t *certs, 437 unsigned int certMax, 438 size_t *ncerts, 439 Error **errp) 440 { 441 gnutls_datum_t data; 442 char *buf = NULL; 443 gsize buflen; 444 int ret = -1; 445 GError *gerr = NULL; 446 447 *ncerts = 0; 448 trace_qcrypto_tls_creds_x509_load_cert_list(creds, certFile); 449 450 if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) { 451 error_setg(errp, "Cannot load CA cert list %s: %s", 452 certFile, gerr->message); 453 g_error_free(gerr); 454 goto cleanup; 455 } 456 457 data.data = (unsigned char *)buf; 458 data.size = strlen(buf); 459 460 if (gnutls_x509_crt_list_import(certs, &certMax, &data, 461 GNUTLS_X509_FMT_PEM, 0) < 0) { 462 error_setg(errp, 463 "Unable to import CA certificate list %s", 464 certFile); 465 goto cleanup; 466 } 467 *ncerts = certMax; 468 469 ret = 0; 470 471 cleanup: 472 g_free(buf); 473 return ret; 474 } 475 476 477 #define MAX_CERTS 16 478 static int 479 qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds, 480 bool isServer, 481 const char *cacertFile, 482 const char *certFile, 483 Error **errp) 484 { 485 gnutls_x509_crt_t cert = NULL; 486 gnutls_x509_crt_t cacerts[MAX_CERTS]; 487 size_t ncacerts = 0; 488 size_t i; 489 int ret = -1; 490 491 memset(cacerts, 0, sizeof(cacerts)); 492 if (certFile && 493 access(certFile, R_OK) == 0) { 494 cert = qcrypto_tls_creds_load_cert(creds, 495 certFile, isServer, 496 errp); 497 if (!cert) { 498 goto cleanup; 499 } 500 } 501 if (access(cacertFile, R_OK) == 0) { 502 if (qcrypto_tls_creds_load_ca_cert_list(creds, 503 cacertFile, cacerts, 504 MAX_CERTS, &ncacerts, 505 errp) < 0) { 506 goto cleanup; 507 } 508 } 509 510 if (cert && 511 qcrypto_tls_creds_check_cert(creds, 512 cert, certFile, isServer, 513 false, errp) < 0) { 514 goto cleanup; 515 } 516 517 for (i = 0; i < ncacerts; i++) { 518 if (qcrypto_tls_creds_check_cert(creds, 519 cacerts[i], cacertFile, 520 isServer, true, errp) < 0) { 521 goto cleanup; 522 } 523 } 524 525 if (cert && ncacerts && 526 qcrypto_tls_creds_check_cert_pair(cert, certFile, cacerts, 527 ncacerts, cacertFile, 528 isServer, errp) < 0) { 529 goto cleanup; 530 } 531 532 ret = 0; 533 534 cleanup: 535 if (cert) { 536 gnutls_x509_crt_deinit(cert); 537 } 538 for (i = 0; i < ncacerts; i++) { 539 gnutls_x509_crt_deinit(cacerts[i]); 540 } 541 return ret; 542 } 543 544 545 static int 546 qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds, 547 Error **errp) 548 { 549 char *cacert = NULL, *cacrl = NULL, *cert = NULL, 550 *key = NULL, *dhparams = NULL; 551 int ret; 552 int rv = -1; 553 554 trace_qcrypto_tls_creds_x509_load(creds, 555 creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>"); 556 557 if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { 558 if (qcrypto_tls_creds_get_path(&creds->parent_obj, 559 QCRYPTO_TLS_CREDS_X509_CA_CERT, 560 true, &cacert, errp) < 0 || 561 qcrypto_tls_creds_get_path(&creds->parent_obj, 562 QCRYPTO_TLS_CREDS_X509_CA_CRL, 563 false, &cacrl, errp) < 0 || 564 qcrypto_tls_creds_get_path(&creds->parent_obj, 565 QCRYPTO_TLS_CREDS_X509_SERVER_CERT, 566 true, &cert, errp) < 0 || 567 qcrypto_tls_creds_get_path(&creds->parent_obj, 568 QCRYPTO_TLS_CREDS_X509_SERVER_KEY, 569 true, &key, errp) < 0 || 570 qcrypto_tls_creds_get_path(&creds->parent_obj, 571 QCRYPTO_TLS_CREDS_DH_PARAMS, 572 false, &dhparams, errp) < 0) { 573 goto cleanup; 574 } 575 } else { 576 if (qcrypto_tls_creds_get_path(&creds->parent_obj, 577 QCRYPTO_TLS_CREDS_X509_CA_CERT, 578 true, &cacert, errp) < 0 || 579 qcrypto_tls_creds_get_path(&creds->parent_obj, 580 QCRYPTO_TLS_CREDS_X509_CLIENT_CERT, 581 false, &cert, errp) < 0 || 582 qcrypto_tls_creds_get_path(&creds->parent_obj, 583 QCRYPTO_TLS_CREDS_X509_CLIENT_KEY, 584 false, &key, errp) < 0) { 585 goto cleanup; 586 } 587 } 588 589 if (creds->sanityCheck && 590 qcrypto_tls_creds_x509_sanity_check(creds, 591 creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, 592 cacert, cert, errp) < 0) { 593 goto cleanup; 594 } 595 596 ret = gnutls_certificate_allocate_credentials(&creds->data); 597 if (ret < 0) { 598 error_setg(errp, "Cannot allocate credentials: '%s'", 599 gnutls_strerror(ret)); 600 goto cleanup; 601 } 602 603 ret = gnutls_certificate_set_x509_trust_file(creds->data, 604 cacert, 605 GNUTLS_X509_FMT_PEM); 606 if (ret < 0) { 607 error_setg(errp, "Cannot load CA certificate '%s': %s", 608 cacert, gnutls_strerror(ret)); 609 goto cleanup; 610 } 611 612 if (cert != NULL && key != NULL) { 613 #if GNUTLS_VERSION_NUMBER >= 0x030111 614 char *password = NULL; 615 if (creds->passwordid) { 616 password = qcrypto_secret_lookup_as_utf8(creds->passwordid, 617 errp); 618 if (!password) { 619 goto cleanup; 620 } 621 } 622 ret = gnutls_certificate_set_x509_key_file2(creds->data, 623 cert, key, 624 GNUTLS_X509_FMT_PEM, 625 password, 626 0); 627 g_free(password); 628 #else /* GNUTLS_VERSION_NUMBER < 0x030111 */ 629 if (creds->passwordid) { 630 error_setg(errp, "PKCS8 decryption requires GNUTLS >= 3.1.11"); 631 goto cleanup; 632 } 633 ret = gnutls_certificate_set_x509_key_file(creds->data, 634 cert, key, 635 GNUTLS_X509_FMT_PEM); 636 #endif /* GNUTLS_VERSION_NUMBER < 0x030111 */ 637 if (ret < 0) { 638 error_setg(errp, "Cannot load certificate '%s' & key '%s': %s", 639 cert, key, gnutls_strerror(ret)); 640 goto cleanup; 641 } 642 } 643 644 if (cacrl != NULL) { 645 ret = gnutls_certificate_set_x509_crl_file(creds->data, 646 cacrl, 647 GNUTLS_X509_FMT_PEM); 648 if (ret < 0) { 649 error_setg(errp, "Cannot load CRL '%s': %s", 650 cacrl, gnutls_strerror(ret)); 651 goto cleanup; 652 } 653 } 654 655 if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { 656 if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams, 657 &creds->parent_obj.dh_params, 658 errp) < 0) { 659 goto cleanup; 660 } 661 gnutls_certificate_set_dh_params(creds->data, 662 creds->parent_obj.dh_params); 663 } 664 665 rv = 0; 666 cleanup: 667 g_free(cacert); 668 g_free(cacrl); 669 g_free(cert); 670 g_free(key); 671 g_free(dhparams); 672 return rv; 673 } 674 675 676 static void 677 qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds) 678 { 679 if (creds->data) { 680 gnutls_certificate_free_credentials(creds->data); 681 creds->data = NULL; 682 } 683 if (creds->parent_obj.dh_params) { 684 gnutls_dh_params_deinit(creds->parent_obj.dh_params); 685 creds->parent_obj.dh_params = NULL; 686 } 687 } 688 689 690 #else /* ! CONFIG_GNUTLS */ 691 692 693 static void 694 qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED, 695 Error **errp) 696 { 697 error_setg(errp, "TLS credentials support requires GNUTLS"); 698 } 699 700 701 static void 702 qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED) 703 { 704 /* nada */ 705 } 706 707 708 #endif /* ! CONFIG_GNUTLS */ 709 710 711 static void 712 qcrypto_tls_creds_x509_prop_set_loaded(Object *obj, 713 bool value, 714 Error **errp) 715 { 716 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 717 718 if (value) { 719 qcrypto_tls_creds_x509_load(creds, errp); 720 } else { 721 qcrypto_tls_creds_x509_unload(creds); 722 } 723 } 724 725 726 #ifdef CONFIG_GNUTLS 727 728 729 static bool 730 qcrypto_tls_creds_x509_prop_get_loaded(Object *obj, 731 Error **errp G_GNUC_UNUSED) 732 { 733 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 734 735 return creds->data != NULL; 736 } 737 738 739 #else /* ! CONFIG_GNUTLS */ 740 741 742 static bool 743 qcrypto_tls_creds_x509_prop_get_loaded(Object *obj G_GNUC_UNUSED, 744 Error **errp G_GNUC_UNUSED) 745 { 746 return false; 747 } 748 749 750 #endif /* ! CONFIG_GNUTLS */ 751 752 753 static void 754 qcrypto_tls_creds_x509_prop_set_sanity(Object *obj, 755 bool value, 756 Error **errp G_GNUC_UNUSED) 757 { 758 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 759 760 creds->sanityCheck = value; 761 } 762 763 764 static void 765 qcrypto_tls_creds_x509_prop_set_passwordid(Object *obj, 766 const char *value, 767 Error **errp G_GNUC_UNUSED) 768 { 769 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 770 771 creds->passwordid = g_strdup(value); 772 } 773 774 775 static char * 776 qcrypto_tls_creds_x509_prop_get_passwordid(Object *obj, 777 Error **errp G_GNUC_UNUSED) 778 { 779 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 780 781 return g_strdup(creds->passwordid); 782 } 783 784 785 static bool 786 qcrypto_tls_creds_x509_prop_get_sanity(Object *obj, 787 Error **errp G_GNUC_UNUSED) 788 { 789 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 790 791 return creds->sanityCheck; 792 } 793 794 795 static void 796 qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp) 797 { 798 object_property_set_bool(OBJECT(uc), true, "loaded", errp); 799 } 800 801 802 static void 803 qcrypto_tls_creds_x509_init(Object *obj) 804 { 805 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 806 807 creds->sanityCheck = true; 808 } 809 810 811 static void 812 qcrypto_tls_creds_x509_finalize(Object *obj) 813 { 814 QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj); 815 816 g_free(creds->passwordid); 817 qcrypto_tls_creds_x509_unload(creds); 818 } 819 820 821 static void 822 qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data) 823 { 824 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 825 826 ucc->complete = qcrypto_tls_creds_x509_complete; 827 828 object_class_property_add_bool(oc, "loaded", 829 qcrypto_tls_creds_x509_prop_get_loaded, 830 qcrypto_tls_creds_x509_prop_set_loaded, 831 NULL); 832 object_class_property_add_bool(oc, "sanity-check", 833 qcrypto_tls_creds_x509_prop_get_sanity, 834 qcrypto_tls_creds_x509_prop_set_sanity, 835 NULL); 836 object_class_property_add_str(oc, "passwordid", 837 qcrypto_tls_creds_x509_prop_get_passwordid, 838 qcrypto_tls_creds_x509_prop_set_passwordid, 839 NULL); 840 } 841 842 843 static const TypeInfo qcrypto_tls_creds_x509_info = { 844 .parent = TYPE_QCRYPTO_TLS_CREDS, 845 .name = TYPE_QCRYPTO_TLS_CREDS_X509, 846 .instance_size = sizeof(QCryptoTLSCredsX509), 847 .instance_init = qcrypto_tls_creds_x509_init, 848 .instance_finalize = qcrypto_tls_creds_x509_finalize, 849 .class_size = sizeof(QCryptoTLSCredsX509Class), 850 .class_init = qcrypto_tls_creds_x509_class_init, 851 .interfaces = (InterfaceInfo[]) { 852 { TYPE_USER_CREATABLE }, 853 { } 854 } 855 }; 856 857 858 static void 859 qcrypto_tls_creds_x509_register_types(void) 860 { 861 type_register_static(&qcrypto_tls_creds_x509_info); 862 } 863 864 865 type_init(qcrypto_tls_creds_x509_register_types); 866