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