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