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