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