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