qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

tlscredsx509.c (26772B)


      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 | 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 
    188 static int
    189 qcrypto_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 
    281 static int
    282 qcrypto_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 
    319 static int
    320 qcrypto_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 
    372 static gnutls_x509_crt_t
    373 qcrypto_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 
    426 static int
    427 qcrypto_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
    466 static int
    467 qcrypto_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 
    533 static int
    534 qcrypto_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 
    654 static void
    655 qcrypto_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 
    671 static void
    672 qcrypto_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 
    679 static void
    680 qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED)
    681 {
    682     /* nada */
    683 }
    684 
    685 
    686 #endif /* ! CONFIG_GNUTLS */
    687 
    688 
    689 static void
    690 qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp)
    691 {
    692     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(uc);
    693 
    694     qcrypto_tls_creds_x509_load(creds, errp);
    695 }
    696 
    697 
    698 #ifdef CONFIG_GNUTLS
    699 
    700 
    701 static bool
    702 qcrypto_tls_creds_x509_prop_get_loaded(Object *obj,
    703                                        Error **errp G_GNUC_UNUSED)
    704 {
    705     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
    706 
    707     return creds->data != NULL;
    708 }
    709 
    710 
    711 #else /* ! CONFIG_GNUTLS */
    712 
    713 
    714 static bool
    715 qcrypto_tls_creds_x509_prop_get_loaded(Object *obj G_GNUC_UNUSED,
    716                                        Error **errp G_GNUC_UNUSED)
    717 {
    718     return false;
    719 }
    720 
    721 
    722 #endif /* ! CONFIG_GNUTLS */
    723 
    724 
    725 static void
    726 qcrypto_tls_creds_x509_prop_set_sanity(Object *obj,
    727                                        bool value,
    728                                        Error **errp G_GNUC_UNUSED)
    729 {
    730     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
    731 
    732     creds->sanityCheck = value;
    733 }
    734 
    735 
    736 static void
    737 qcrypto_tls_creds_x509_prop_set_passwordid(Object *obj,
    738                                            const char *value,
    739                                            Error **errp G_GNUC_UNUSED)
    740 {
    741     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
    742 
    743     creds->passwordid = g_strdup(value);
    744 }
    745 
    746 
    747 static char *
    748 qcrypto_tls_creds_x509_prop_get_passwordid(Object *obj,
    749                                            Error **errp G_GNUC_UNUSED)
    750 {
    751     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
    752 
    753     return g_strdup(creds->passwordid);
    754 }
    755 
    756 
    757 static bool
    758 qcrypto_tls_creds_x509_prop_get_sanity(Object *obj,
    759                                        Error **errp G_GNUC_UNUSED)
    760 {
    761     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
    762 
    763     return creds->sanityCheck;
    764 }
    765 
    766 
    767 #ifdef CONFIG_GNUTLS
    768 
    769 
    770 static bool
    771 qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
    772 {
    773     QCryptoTLSCredsX509 *x509_creds = QCRYPTO_TLS_CREDS_X509(creds);
    774     Error *local_err = NULL;
    775     gnutls_certificate_credentials_t creds_data = x509_creds->data;
    776     gnutls_dh_params_t creds_dh_params = x509_creds->parent_obj.dh_params;
    777 
    778     x509_creds->data = NULL;
    779     x509_creds->parent_obj.dh_params = NULL;
    780     qcrypto_tls_creds_x509_load(x509_creds, &local_err);
    781     if (local_err) {
    782         qcrypto_tls_creds_x509_unload(x509_creds);
    783         x509_creds->data = creds_data;
    784         x509_creds->parent_obj.dh_params = creds_dh_params;
    785         error_propagate(errp, local_err);
    786         return false;
    787     }
    788 
    789     if (creds_data) {
    790         gnutls_certificate_free_credentials(creds_data);
    791     }
    792     if (creds_dh_params) {
    793         gnutls_dh_params_deinit(creds_dh_params);
    794     }
    795     return true;
    796 }
    797 
    798 
    799 #else /* ! CONFIG_GNUTLS */
    800 
    801 
    802 static bool
    803 qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
    804 {
    805     return false;
    806 }
    807 
    808 
    809 #endif /* ! CONFIG_GNUTLS */
    810 
    811 
    812 static void
    813 qcrypto_tls_creds_x509_init(Object *obj)
    814 {
    815     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
    816 
    817     creds->sanityCheck = true;
    818 }
    819 
    820 
    821 static void
    822 qcrypto_tls_creds_x509_finalize(Object *obj)
    823 {
    824     QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
    825 
    826     g_free(creds->passwordid);
    827     qcrypto_tls_creds_x509_unload(creds);
    828 }
    829 
    830 
    831 static void
    832 qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data)
    833 {
    834     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
    835     QCryptoTLSCredsClass *ctcc = QCRYPTO_TLS_CREDS_CLASS(oc);
    836 
    837     ctcc->reload = qcrypto_tls_creds_x509_reload;
    838 
    839     ucc->complete = qcrypto_tls_creds_x509_complete;
    840 
    841     object_class_property_add_bool(oc, "loaded",
    842                                    qcrypto_tls_creds_x509_prop_get_loaded,
    843                                    NULL);
    844     object_class_property_add_bool(oc, "sanity-check",
    845                                    qcrypto_tls_creds_x509_prop_get_sanity,
    846                                    qcrypto_tls_creds_x509_prop_set_sanity);
    847     object_class_property_add_str(oc, "passwordid",
    848                                   qcrypto_tls_creds_x509_prop_get_passwordid,
    849                                   qcrypto_tls_creds_x509_prop_set_passwordid);
    850 }
    851 
    852 
    853 static const TypeInfo qcrypto_tls_creds_x509_info = {
    854     .parent = TYPE_QCRYPTO_TLS_CREDS,
    855     .name = TYPE_QCRYPTO_TLS_CREDS_X509,
    856     .instance_size = sizeof(QCryptoTLSCredsX509),
    857     .instance_init = qcrypto_tls_creds_x509_init,
    858     .instance_finalize = qcrypto_tls_creds_x509_finalize,
    859     .class_size = sizeof(QCryptoTLSCredsX509Class),
    860     .class_init = qcrypto_tls_creds_x509_class_init,
    861     .interfaces = (InterfaceInfo[]) {
    862         { TYPE_USER_CREATABLE },
    863         { }
    864     }
    865 };
    866 
    867 
    868 static void
    869 qcrypto_tls_creds_x509_register_types(void)
    870 {
    871     type_register_static(&qcrypto_tls_creds_x509_info);
    872 }
    873 
    874 
    875 type_init(qcrypto_tls_creds_x509_register_types);