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