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.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
  37static int
  38qcrypto_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
  77static int
  78qcrypto_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
 129static int
 130qcrypto_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 | GNUTLS_KEY_KEY_ENCIPHERMENT;
 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        if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) {
 175            if (critical) {
 176                error_setg(errp,
 177                           "Certificate %s usage does not permit key "
 178                           "encipherment", certFile);
 179                return -1;
 180            }
 181        }
 182    }
 183
 184    return 0;
 185}
 186
 187
 188static int
 189qcrypto_tls_creds_check_cert_key_purpose(QCryptoTLSCredsX509 *creds,
 190                                         gnutls_x509_crt_t cert,
 191                                         const char *certFile,
 192                                         bool isServer,
 193                                         Error **errp)
 194{
 195    int status;
 196    size_t i;
 197    unsigned int purposeCritical;
 198    unsigned int critical;
 199    char *buffer = NULL;
 200    size_t size;
 201    bool allowClient = false, allowServer = false;
 202
 203    critical = 0;
 204    for (i = 0; ; i++) {
 205        size = 0;
 206        status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer,
 207                                                     &size, NULL);
 208
 209        if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
 210
 211            /* If there is no data at all, then we must allow
 212               client/server to pass */
 213            if (i == 0) {
 214                allowServer = allowClient = true;
 215            }
 216            break;
 217        }
 218        if (status != GNUTLS_E_SHORT_MEMORY_BUFFER) {
 219            error_setg(errp,
 220                       "Unable to query certificate %s key purpose: %s",
 221                       certFile, gnutls_strerror(status));
 222            return -1;
 223        }
 224
 225        buffer = g_new0(char, size);
 226
 227        status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer,
 228                                                     &size, &purposeCritical);
 229
 230        if (status < 0) {
 231            trace_qcrypto_tls_creds_x509_check_key_purpose(
 232                creds, certFile, status, "<none>", purposeCritical);
 233            g_free(buffer);
 234            error_setg(errp,
 235                       "Unable to query certificate %s key purpose: %s",
 236                       certFile, gnutls_strerror(status));
 237            return -1;
 238        }
 239        trace_qcrypto_tls_creds_x509_check_key_purpose(
 240            creds, certFile, status, buffer, purposeCritical);
 241        if (purposeCritical) {
 242            critical = true;
 243        }
 244
 245        if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_SERVER)) {
 246            allowServer = true;
 247        } else if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_CLIENT)) {
 248            allowClient = true;
 249        } else if (g_str_equal(buffer, GNUTLS_KP_ANY)) {
 250            allowServer = allowClient = true;
 251        }
 252
 253        g_free(buffer);
 254        buffer = NULL;
 255    }
 256
 257    if (isServer) {
 258        if (!allowServer) {
 259            if (critical) {
 260                error_setg(errp,
 261                           "Certificate %s purpose does not allow "
 262                           "use with a TLS server", certFile);
 263                return -1;
 264            }
 265        }
 266    } else {
 267        if (!allowClient) {
 268            if (critical) {
 269                error_setg(errp,
 270                           "Certificate %s purpose does not allow use "
 271                           "with a TLS client", certFile);
 272                return -1;
 273            }
 274        }
 275    }
 276
 277    return 0;
 278}
 279
 280
 281static int
 282qcrypto_tls_creds_check_cert(QCryptoTLSCredsX509 *creds,
 283                             gnutls_x509_crt_t cert,
 284                             const char *certFile,
 285                             bool isServer,
 286                             bool isCA,
 287                             Error **errp)
 288{
 289    if (qcrypto_tls_creds_check_cert_times(cert, certFile,
 290                                           isServer, isCA,
 291                                           errp) < 0) {
 292        return -1;
 293    }
 294
 295    if (qcrypto_tls_creds_check_cert_basic_constraints(creds,
 296                                                       cert, certFile,
 297                                                       isServer, isCA,
 298                                                       errp) < 0) {
 299        return -1;
 300    }
 301
 302    if (qcrypto_tls_creds_check_cert_key_usage(creds,
 303                                               cert, certFile,
 304                                               isCA, errp) < 0) {
 305        return -1;
 306    }
 307
 308    if (!isCA &&
 309        qcrypto_tls_creds_check_cert_key_purpose(creds,
 310                                                 cert, certFile,
 311                                                 isServer, errp) < 0) {
 312        return -1;
 313    }
 314
 315    return 0;
 316}
 317
 318
 319static int
 320qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t cert,
 321                                  const char *certFile,
 322                                  gnutls_x509_crt_t *cacerts,
 323                                  size_t ncacerts,
 324                                  const char *cacertFile,
 325                                  bool isServer,
 326                                  Error **errp)
 327{
 328    unsigned int status;
 329
 330    if (gnutls_x509_crt_list_verify(&cert, 1,
 331                                    cacerts, ncacerts,
 332                                    NULL, 0,
 333                                    0, &status) < 0) {
 334        error_setg(errp, isServer ?
 335                   "Unable to verify server certificate %s against "
 336                   "CA certificate %s" :
 337                   "Unable to verify client certificate %s against "
 338                   "CA certificate %s",
 339                   certFile, cacertFile);
 340        return -1;
 341    }
 342
 343    if (status != 0) {
 344        const char *reason = "Invalid certificate";
 345
 346        if (status & GNUTLS_CERT_INVALID) {
 347            reason = "The certificate is not trusted";
 348        }
 349
 350        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
 351            reason = "The certificate hasn't got a known issuer";
 352        }
 353
 354        if (status & GNUTLS_CERT_REVOKED) {
 355            reason = "The certificate has been revoked";
 356        }
 357
 358#ifndef GNUTLS_1_0_COMPAT
 359        if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
 360            reason = "The certificate uses an insecure algorithm";
 361        }
 362#endif
 363
 364        error_setg(errp,
 365                   "Our own certificate %s failed validation against %s: %s",
 366                   certFile, cacertFile, reason);
 367        return -1;
 368    }
 369
 370    return 0;
 371}
 372
 373
 374static gnutls_x509_crt_t
 375qcrypto_tls_creds_load_cert(QCryptoTLSCredsX509 *creds,
 376                            const char *certFile,
 377                            bool isServer,
 378                            Error **errp)
 379{
 380    gnutls_datum_t data;
 381    gnutls_x509_crt_t cert = NULL;
 382    g_autofree char *buf = NULL;
 383    gsize buflen;
 384    GError *gerr = NULL;
 385    int ret = -1;
 386    int err;
 387
 388    trace_qcrypto_tls_creds_x509_load_cert(creds, isServer, certFile);
 389
 390    err = gnutls_x509_crt_init(&cert);
 391    if (err < 0) {
 392        error_setg(errp, "Unable to initialize certificate: %s",
 393                   gnutls_strerror(err));
 394        goto cleanup;
 395    }
 396
 397    if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) {
 398        error_setg(errp, "Cannot load CA cert list %s: %s",
 399                   certFile, gerr->message);
 400        g_error_free(gerr);
 401        goto cleanup;
 402    }
 403
 404    data.data = (unsigned char *)buf;
 405    data.size = strlen(buf);
 406
 407    err = gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM);
 408    if (err < 0) {
 409        error_setg(errp, isServer ?
 410                   "Unable to import server certificate %s: %s" :
 411                   "Unable to import client certificate %s: %s",
 412                   certFile,
 413                   gnutls_strerror(err));
 414        goto cleanup;
 415    }
 416
 417    ret = 0;
 418
 419 cleanup:
 420    if (ret != 0) {
 421        gnutls_x509_crt_deinit(cert);
 422        cert = NULL;
 423    }
 424    return cert;
 425}
 426
 427
 428static int
 429qcrypto_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    g_autofree char *buf = NULL;
 438    gsize buflen;
 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        return -1;
 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        return -1;
 460    }
 461    *ncerts = certMax;
 462
 463    return 0;
 464}
 465
 466
 467#define MAX_CERTS 16
 468static int
 469qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
 470                                    bool isServer,
 471                                    const char *cacertFile,
 472                                    const char *certFile,
 473                                    Error **errp)
 474{
 475    gnutls_x509_crt_t cert = NULL;
 476    gnutls_x509_crt_t cacerts[MAX_CERTS];
 477    size_t ncacerts = 0;
 478    size_t i;
 479    int ret = -1;
 480
 481    memset(cacerts, 0, sizeof(cacerts));
 482    if (certFile &&
 483        access(certFile, R_OK) == 0) {
 484        cert = qcrypto_tls_creds_load_cert(creds,
 485                                           certFile, isServer,
 486                                           errp);
 487        if (!cert) {
 488            goto cleanup;
 489        }
 490    }
 491    if (access(cacertFile, R_OK) == 0) {
 492        if (qcrypto_tls_creds_load_ca_cert_list(creds,
 493                                                cacertFile, cacerts,
 494                                                MAX_CERTS, &ncacerts,
 495                                                errp) < 0) {
 496            goto cleanup;
 497        }
 498    }
 499
 500    if (cert &&
 501        qcrypto_tls_creds_check_cert(creds,
 502                                     cert, certFile, isServer,
 503                                     false, errp) < 0) {
 504        goto cleanup;
 505    }
 506
 507    for (i = 0; i < ncacerts; i++) {
 508        if (qcrypto_tls_creds_check_cert(creds,
 509                                         cacerts[i], cacertFile,
 510                                         isServer, true, errp) < 0) {
 511            goto cleanup;
 512        }
 513    }
 514
 515    if (cert && ncacerts &&
 516        qcrypto_tls_creds_check_cert_pair(cert, certFile, cacerts,
 517                                          ncacerts, cacertFile,
 518                                          isServer, errp) < 0) {
 519        goto cleanup;
 520    }
 521
 522    ret = 0;
 523
 524 cleanup:
 525    if (cert) {
 526        gnutls_x509_crt_deinit(cert);
 527    }
 528    for (i = 0; i < ncacerts; i++) {
 529        gnutls_x509_crt_deinit(cacerts[i]);
 530    }
 531    return ret;
 532}
 533
 534
 535static int
 536qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
 537                            Error **errp)
 538{
 539    char *cacert = NULL, *cacrl = NULL, *cert = NULL,
 540        *key = NULL, *dhparams = NULL;
 541    int ret;
 542    int rv = -1;
 543
 544    trace_qcrypto_tls_creds_x509_load(creds,
 545            creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
 546
 547    if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
 548        if (qcrypto_tls_creds_get_path(&creds->parent_obj,
 549                                       QCRYPTO_TLS_CREDS_X509_CA_CERT,
 550                                       true, &cacert, errp) < 0 ||
 551            qcrypto_tls_creds_get_path(&creds->parent_obj,
 552                                       QCRYPTO_TLS_CREDS_X509_CA_CRL,
 553                                       false, &cacrl, errp) < 0 ||
 554            qcrypto_tls_creds_get_path(&creds->parent_obj,
 555                                       QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
 556                                       true, &cert, errp) < 0 ||
 557            qcrypto_tls_creds_get_path(&creds->parent_obj,
 558                                       QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
 559                                       true, &key, errp) < 0 ||
 560            qcrypto_tls_creds_get_path(&creds->parent_obj,
 561                                       QCRYPTO_TLS_CREDS_DH_PARAMS,
 562                                       false, &dhparams, errp) < 0) {
 563            goto cleanup;
 564        }
 565    } else {
 566        if (qcrypto_tls_creds_get_path(&creds->parent_obj,
 567                                       QCRYPTO_TLS_CREDS_X509_CA_CERT,
 568                                       true, &cacert, errp) < 0 ||
 569            qcrypto_tls_creds_get_path(&creds->parent_obj,
 570                                       QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
 571                                       false, &cert, errp) < 0 ||
 572            qcrypto_tls_creds_get_path(&creds->parent_obj,
 573                                       QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
 574                                       false, &key, errp) < 0) {
 575            goto cleanup;
 576        }
 577    }
 578
 579    if (creds->sanityCheck &&
 580        qcrypto_tls_creds_x509_sanity_check(creds,
 581            creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
 582            cacert, cert, errp) < 0) {
 583        goto cleanup;
 584    }
 585
 586    ret = gnutls_certificate_allocate_credentials(&creds->data);
 587    if (ret < 0) {
 588        error_setg(errp, "Cannot allocate credentials: '%s'",
 589                   gnutls_strerror(ret));
 590        goto cleanup;
 591    }
 592
 593    ret = gnutls_certificate_set_x509_trust_file(creds->data,
 594                                                 cacert,
 595                                                 GNUTLS_X509_FMT_PEM);
 596    if (ret < 0) {
 597        error_setg(errp, "Cannot load CA certificate '%s': %s",
 598                   cacert, gnutls_strerror(ret));
 599        goto cleanup;
 600    }
 601
 602    if (cert != NULL && key != NULL) {
 603        char *password = NULL;
 604        if (creds->passwordid) {
 605            password = qcrypto_secret_lookup_as_utf8(creds->passwordid,
 606                                                     errp);
 607            if (!password) {
 608                goto cleanup;
 609            }
 610        }
 611        ret = gnutls_certificate_set_x509_key_file2(creds->data,
 612                                                    cert, key,
 613                                                    GNUTLS_X509_FMT_PEM,
 614                                                    password,
 615                                                    0);
 616        g_free(password);
 617        if (ret < 0) {
 618            error_setg(errp, "Cannot load certificate '%s' & key '%s': %s",
 619                       cert, key, gnutls_strerror(ret));
 620            goto cleanup;
 621        }
 622    }
 623
 624    if (cacrl != NULL) {
 625        ret = gnutls_certificate_set_x509_crl_file(creds->data,
 626                                                   cacrl,
 627                                                   GNUTLS_X509_FMT_PEM);
 628        if (ret < 0) {
 629            error_setg(errp, "Cannot load CRL '%s': %s",
 630                       cacrl, gnutls_strerror(ret));
 631            goto cleanup;
 632        }
 633    }
 634
 635    if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
 636        if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
 637                                                 &creds->parent_obj.dh_params,
 638                                                 errp) < 0) {
 639            goto cleanup;
 640        }
 641        gnutls_certificate_set_dh_params(creds->data,
 642                                         creds->parent_obj.dh_params);
 643    }
 644
 645    rv = 0;
 646 cleanup:
 647    g_free(cacert);
 648    g_free(cacrl);
 649    g_free(cert);
 650    g_free(key);
 651    g_free(dhparams);
 652    return rv;
 653}
 654
 655
 656static void
 657qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds)
 658{
 659    if (creds->data) {
 660        gnutls_certificate_free_credentials(creds->data);
 661        creds->data = NULL;
 662    }
 663    if (creds->parent_obj.dh_params) {
 664        gnutls_dh_params_deinit(creds->parent_obj.dh_params);
 665        creds->parent_obj.dh_params = NULL;
 666    }
 667}
 668
 669
 670#else /* ! CONFIG_GNUTLS */
 671
 672
 673static void
 674qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED,
 675                            Error **errp)
 676{
 677    error_setg(errp, "TLS credentials support requires GNUTLS");
 678}
 679
 680
 681static void
 682qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED)
 683{
 684    /* nada */
 685}
 686
 687
 688#endif /* ! CONFIG_GNUTLS */
 689
 690
 691static void
 692qcrypto_tls_creds_x509_prop_set_loaded(Object *obj,
 693                                       bool value,
 694                                       Error **errp)
 695{
 696    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
 697
 698    qcrypto_tls_creds_x509_unload(creds);
 699    if (value) {
 700        qcrypto_tls_creds_x509_load(creds, errp);
 701    }
 702}
 703
 704
 705#ifdef CONFIG_GNUTLS
 706
 707
 708static bool
 709qcrypto_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
 721static bool
 722qcrypto_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
 732static void
 733qcrypto_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
 743static void
 744qcrypto_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
 754static char *
 755qcrypto_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
 764static bool
 765qcrypto_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#ifdef CONFIG_GNUTLS
 775
 776
 777static bool
 778qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
 779{
 780    QCryptoTLSCredsX509 *x509_creds = QCRYPTO_TLS_CREDS_X509(creds);
 781    Error *local_err = NULL;
 782    gnutls_certificate_credentials_t creds_data = x509_creds->data;
 783    gnutls_dh_params_t creds_dh_params = x509_creds->parent_obj.dh_params;
 784
 785    x509_creds->data = NULL;
 786    x509_creds->parent_obj.dh_params = NULL;
 787    qcrypto_tls_creds_x509_load(x509_creds, &local_err);
 788    if (local_err) {
 789        qcrypto_tls_creds_x509_unload(x509_creds);
 790        x509_creds->data = creds_data;
 791        x509_creds->parent_obj.dh_params = creds_dh_params;
 792        error_propagate(errp, local_err);
 793        return false;
 794    }
 795
 796    if (creds_data) {
 797        gnutls_certificate_free_credentials(creds_data);
 798    }
 799    if (creds_dh_params) {
 800        gnutls_dh_params_deinit(creds_dh_params);
 801    }
 802    return true;
 803}
 804
 805
 806#else /* ! CONFIG_GNUTLS */
 807
 808
 809static bool
 810qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
 811{
 812    return false;
 813}
 814
 815
 816#endif /* ! CONFIG_GNUTLS */
 817
 818
 819static void
 820qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp)
 821{
 822    object_property_set_bool(OBJECT(uc), "loaded", true, errp);
 823}
 824
 825
 826static void
 827qcrypto_tls_creds_x509_init(Object *obj)
 828{
 829    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
 830
 831    creds->sanityCheck = true;
 832}
 833
 834
 835static void
 836qcrypto_tls_creds_x509_finalize(Object *obj)
 837{
 838    QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
 839
 840    g_free(creds->passwordid);
 841    qcrypto_tls_creds_x509_unload(creds);
 842}
 843
 844
 845static void
 846qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data)
 847{
 848    UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 849    QCryptoTLSCredsClass *ctcc = QCRYPTO_TLS_CREDS_CLASS(oc);
 850
 851    ctcc->reload = qcrypto_tls_creds_x509_reload;
 852
 853    ucc->complete = qcrypto_tls_creds_x509_complete;
 854
 855    object_class_property_add_bool(oc, "loaded",
 856                                   qcrypto_tls_creds_x509_prop_get_loaded,
 857                                   qcrypto_tls_creds_x509_prop_set_loaded);
 858    object_class_property_add_bool(oc, "sanity-check",
 859                                   qcrypto_tls_creds_x509_prop_get_sanity,
 860                                   qcrypto_tls_creds_x509_prop_set_sanity);
 861    object_class_property_add_str(oc, "passwordid",
 862                                  qcrypto_tls_creds_x509_prop_get_passwordid,
 863                                  qcrypto_tls_creds_x509_prop_set_passwordid);
 864}
 865
 866
 867static const TypeInfo qcrypto_tls_creds_x509_info = {
 868    .parent = TYPE_QCRYPTO_TLS_CREDS,
 869    .name = TYPE_QCRYPTO_TLS_CREDS_X509,
 870    .instance_size = sizeof(QCryptoTLSCredsX509),
 871    .instance_init = qcrypto_tls_creds_x509_init,
 872    .instance_finalize = qcrypto_tls_creds_x509_finalize,
 873    .class_size = sizeof(QCryptoTLSCredsX509Class),
 874    .class_init = qcrypto_tls_creds_x509_class_init,
 875    .interfaces = (InterfaceInfo[]) {
 876        { TYPE_USER_CREATABLE },
 877        { }
 878    }
 879};
 880
 881
 882static void
 883qcrypto_tls_creds_x509_register_types(void)
 884{
 885    type_register_static(&qcrypto_tls_creds_x509_info);
 886}
 887
 888
 889type_init(qcrypto_tls_creds_x509_register_types);
 890