185bcbc78SDaniel P. Berrange /*
285bcbc78SDaniel P. Berrange * QEMU crypto TLS x509 credential support
385bcbc78SDaniel P. Berrange *
485bcbc78SDaniel P. Berrange * Copyright (c) 2015 Red Hat, Inc.
585bcbc78SDaniel P. Berrange *
685bcbc78SDaniel P. Berrange * This library is free software; you can redistribute it and/or
785bcbc78SDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public
885bcbc78SDaniel P. Berrange * License as published by the Free Software Foundation; either
9b7cbb874SThomas Huth * version 2.1 of the License, or (at your option) any later version.
1085bcbc78SDaniel P. Berrange *
1185bcbc78SDaniel P. Berrange * This library is distributed in the hope that it will be useful,
1285bcbc78SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of
1385bcbc78SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1485bcbc78SDaniel P. Berrange * Lesser General Public License for more details.
1585bcbc78SDaniel P. Berrange *
1685bcbc78SDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public
1785bcbc78SDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1885bcbc78SDaniel P. Berrange *
1985bcbc78SDaniel P. Berrange */
2085bcbc78SDaniel P. Berrange
2142f7a448SPeter Maydell #include "qemu/osdep.h"
2285bcbc78SDaniel P. Berrange #include "crypto/tlscredsx509.h"
23986bc8deSMichael S. Tsirkin #include "tlscredspriv.h"
241d7b5b4aSDaniel P. Berrange #include "crypto/secret.h"
25da34e65cSMarkus Armbruster #include "qapi/error.h"
260b8fa32fSMarkus Armbruster #include "qemu/module.h"
2785bcbc78SDaniel P. Berrange #include "qom/object_interfaces.h"
2885bcbc78SDaniel P. Berrange #include "trace.h"
2985bcbc78SDaniel P. Berrange
3085bcbc78SDaniel P. Berrange
3185bcbc78SDaniel P. Berrange #ifdef CONFIG_GNUTLS
3285bcbc78SDaniel P. Berrange
33678bcc3cSPhilippe Mathieu-Daudé #include <gnutls/gnutls.h>
349a2fd434SDaniel P. Berrange #include <gnutls/x509.h>
359a2fd434SDaniel P. Berrange
369a2fd434SDaniel P. Berrange
379a2fd434SDaniel P. Berrange static int
qcrypto_tls_creds_check_cert_times(gnutls_x509_crt_t cert,const char * certFile,bool isServer,bool isCA,Error ** errp)389a2fd434SDaniel P. Berrange qcrypto_tls_creds_check_cert_times(gnutls_x509_crt_t cert,
399a2fd434SDaniel P. Berrange const char *certFile,
409a2fd434SDaniel P. Berrange bool isServer,
419a2fd434SDaniel P. Berrange bool isCA,
429a2fd434SDaniel P. Berrange Error **errp)
439a2fd434SDaniel P. Berrange {
449a2fd434SDaniel P. Berrange time_t now = time(NULL);
459a2fd434SDaniel P. Berrange
469a2fd434SDaniel P. Berrange if (now == ((time_t)-1)) {
479a2fd434SDaniel P. Berrange error_setg_errno(errp, errno, "cannot get current time");
489a2fd434SDaniel P. Berrange return -1;
499a2fd434SDaniel P. Berrange }
509a2fd434SDaniel P. Berrange
519a2fd434SDaniel P. Berrange if (gnutls_x509_crt_get_expiration_time(cert) < now) {
529a2fd434SDaniel P. Berrange error_setg(errp,
539a2fd434SDaniel P. Berrange (isCA ?
549a2fd434SDaniel P. Berrange "The CA certificate %s has expired" :
559a2fd434SDaniel P. Berrange (isServer ?
569a2fd434SDaniel P. Berrange "The server certificate %s has expired" :
579a2fd434SDaniel P. Berrange "The client certificate %s has expired")),
589a2fd434SDaniel P. Berrange certFile);
599a2fd434SDaniel P. Berrange return -1;
609a2fd434SDaniel P. Berrange }
619a2fd434SDaniel P. Berrange
629a2fd434SDaniel P. Berrange if (gnutls_x509_crt_get_activation_time(cert) > now) {
639a2fd434SDaniel P. Berrange error_setg(errp,
649a2fd434SDaniel P. Berrange (isCA ?
659a2fd434SDaniel P. Berrange "The CA certificate %s is not yet active" :
669a2fd434SDaniel P. Berrange (isServer ?
679a2fd434SDaniel P. Berrange "The server certificate %s is not yet active" :
689a2fd434SDaniel P. Berrange "The client certificate %s is not yet active")),
699a2fd434SDaniel P. Berrange certFile);
709a2fd434SDaniel P. Berrange return -1;
719a2fd434SDaniel P. Berrange }
729a2fd434SDaniel P. Berrange
739a2fd434SDaniel P. Berrange return 0;
749a2fd434SDaniel P. Berrange }
759a2fd434SDaniel P. Berrange
769a2fd434SDaniel P. Berrange
779a2fd434SDaniel P. Berrange static int
qcrypto_tls_creds_check_cert_basic_constraints(QCryptoTLSCredsX509 * creds,gnutls_x509_crt_t cert,const char * certFile,bool isServer,bool isCA,Error ** errp)789a2fd434SDaniel P. Berrange qcrypto_tls_creds_check_cert_basic_constraints(QCryptoTLSCredsX509 *creds,
799a2fd434SDaniel P. Berrange gnutls_x509_crt_t cert,
809a2fd434SDaniel P. Berrange const char *certFile,
819a2fd434SDaniel P. Berrange bool isServer,
829a2fd434SDaniel P. Berrange bool isCA,
839a2fd434SDaniel P. Berrange Error **errp)
849a2fd434SDaniel P. Berrange {
859a2fd434SDaniel P. Berrange int status;
869a2fd434SDaniel P. Berrange
879a2fd434SDaniel P. Berrange status = gnutls_x509_crt_get_basic_constraints(cert, NULL, NULL, NULL);
889a2fd434SDaniel P. Berrange trace_qcrypto_tls_creds_x509_check_basic_constraints(
899a2fd434SDaniel P. Berrange creds, certFile, status);
909a2fd434SDaniel P. Berrange
919a2fd434SDaniel P. Berrange if (status > 0) { /* It is a CA cert */
929a2fd434SDaniel P. Berrange if (!isCA) {
939a2fd434SDaniel P. Berrange error_setg(errp, isServer ?
949a2fd434SDaniel P. Berrange "The certificate %s basic constraints show a CA, "
959a2fd434SDaniel P. Berrange "but we need one for a server" :
969a2fd434SDaniel P. Berrange "The certificate %s basic constraints show a CA, "
979a2fd434SDaniel P. Berrange "but we need one for a client",
989a2fd434SDaniel P. Berrange certFile);
999a2fd434SDaniel P. Berrange return -1;
1009a2fd434SDaniel P. Berrange }
1019a2fd434SDaniel P. Berrange } else if (status == 0) { /* It is not a CA cert */
1029a2fd434SDaniel P. Berrange if (isCA) {
1039a2fd434SDaniel P. Berrange error_setg(errp,
1049a2fd434SDaniel P. Berrange "The certificate %s basic constraints do not "
1059a2fd434SDaniel P. Berrange "show a CA",
1069a2fd434SDaniel P. Berrange certFile);
1079a2fd434SDaniel P. Berrange return -1;
1089a2fd434SDaniel P. Berrange }
1099a2fd434SDaniel P. Berrange } else if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1109a2fd434SDaniel P. Berrange /* Missing basicConstraints */
1119a2fd434SDaniel P. Berrange if (isCA) {
1129a2fd434SDaniel P. Berrange error_setg(errp,
1139a2fd434SDaniel P. Berrange "The certificate %s is missing basic constraints "
1149a2fd434SDaniel P. Berrange "for a CA",
1159a2fd434SDaniel P. Berrange certFile);
1169a2fd434SDaniel P. Berrange return -1;
1179a2fd434SDaniel P. Berrange }
1189a2fd434SDaniel P. Berrange } else { /* General error */
1199a2fd434SDaniel P. Berrange error_setg(errp,
1209a2fd434SDaniel P. Berrange "Unable to query certificate %s basic constraints: %s",
1219a2fd434SDaniel P. Berrange certFile, gnutls_strerror(status));
1229a2fd434SDaniel P. Berrange return -1;
1239a2fd434SDaniel P. Berrange }
1249a2fd434SDaniel P. Berrange
1259a2fd434SDaniel P. Berrange return 0;
1269a2fd434SDaniel P. Berrange }
1279a2fd434SDaniel P. Berrange
1289a2fd434SDaniel P. Berrange
1299a2fd434SDaniel P. Berrange static int
qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 * creds,gnutls_x509_crt_t cert,const char * certFile,bool isCA,Error ** errp)1309a2fd434SDaniel P. Berrange qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 *creds,
1319a2fd434SDaniel P. Berrange gnutls_x509_crt_t cert,
1329a2fd434SDaniel P. Berrange const char *certFile,
1339a2fd434SDaniel P. Berrange bool isCA,
1349a2fd434SDaniel P. Berrange Error **errp)
1359a2fd434SDaniel P. Berrange {
1369a2fd434SDaniel P. Berrange int status;
1379a2fd434SDaniel P. Berrange unsigned int usage = 0;
1389a2fd434SDaniel P. Berrange unsigned int critical = 0;
1399a2fd434SDaniel P. Berrange
1409a2fd434SDaniel P. Berrange status = gnutls_x509_crt_get_key_usage(cert, &usage, &critical);
1419a2fd434SDaniel P. Berrange trace_qcrypto_tls_creds_x509_check_key_usage(
1429a2fd434SDaniel P. Berrange creds, certFile, status, usage, critical);
1439a2fd434SDaniel P. Berrange
1449a2fd434SDaniel P. Berrange if (status < 0) {
1459a2fd434SDaniel P. Berrange if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1469a2fd434SDaniel P. Berrange usage = isCA ? GNUTLS_KEY_KEY_CERT_SIGN :
1479a2fd434SDaniel P. Berrange GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT;
1489a2fd434SDaniel P. Berrange } else {
1499a2fd434SDaniel P. Berrange error_setg(errp,
1509a2fd434SDaniel P. Berrange "Unable to query certificate %s key usage: %s",
1519a2fd434SDaniel P. Berrange certFile, gnutls_strerror(status));
1529a2fd434SDaniel P. Berrange return -1;
1539a2fd434SDaniel P. Berrange }
1549a2fd434SDaniel P. Berrange }
1559a2fd434SDaniel P. Berrange
1569a2fd434SDaniel P. Berrange if (isCA) {
1579a2fd434SDaniel P. Berrange if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) {
1589a2fd434SDaniel P. Berrange if (critical) {
1599a2fd434SDaniel P. Berrange error_setg(errp,
1609a2fd434SDaniel P. Berrange "Certificate %s usage does not permit "
1619a2fd434SDaniel P. Berrange "certificate signing", certFile);
1629a2fd434SDaniel P. Berrange return -1;
1639a2fd434SDaniel P. Berrange }
1649a2fd434SDaniel P. Berrange }
1659a2fd434SDaniel P. Berrange } else {
1669a2fd434SDaniel P. Berrange if (!(usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) {
1679a2fd434SDaniel P. Berrange if (critical) {
1689a2fd434SDaniel P. Berrange error_setg(errp,
1699a2fd434SDaniel P. Berrange "Certificate %s usage does not permit digital "
1709a2fd434SDaniel P. Berrange "signature", certFile);
1719a2fd434SDaniel P. Berrange return -1;
1729a2fd434SDaniel P. Berrange }
1739a2fd434SDaniel P. Berrange }
1749a2fd434SDaniel P. Berrange if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) {
1759a2fd434SDaniel P. Berrange if (critical) {
1769a2fd434SDaniel P. Berrange error_setg(errp,
1779a2fd434SDaniel P. Berrange "Certificate %s usage does not permit key "
1789a2fd434SDaniel P. Berrange "encipherment", certFile);
1799a2fd434SDaniel P. Berrange return -1;
1809a2fd434SDaniel P. Berrange }
1819a2fd434SDaniel P. Berrange }
1829a2fd434SDaniel P. Berrange }
1839a2fd434SDaniel P. Berrange
1849a2fd434SDaniel P. Berrange return 0;
1859a2fd434SDaniel P. Berrange }
1869a2fd434SDaniel P. Berrange
1879a2fd434SDaniel P. Berrange
1889a2fd434SDaniel P. Berrange static int
qcrypto_tls_creds_check_cert_key_purpose(QCryptoTLSCredsX509 * creds,gnutls_x509_crt_t cert,const char * certFile,bool isServer,Error ** errp)1899a2fd434SDaniel P. Berrange qcrypto_tls_creds_check_cert_key_purpose(QCryptoTLSCredsX509 *creds,
1909a2fd434SDaniel P. Berrange gnutls_x509_crt_t cert,
1919a2fd434SDaniel P. Berrange const char *certFile,
1929a2fd434SDaniel P. Berrange bool isServer,
1939a2fd434SDaniel P. Berrange Error **errp)
1949a2fd434SDaniel P. Berrange {
1959a2fd434SDaniel P. Berrange int status;
1969a2fd434SDaniel P. Berrange size_t i;
1979a2fd434SDaniel P. Berrange unsigned int purposeCritical;
1989a2fd434SDaniel P. Berrange unsigned int critical;
1999a2fd434SDaniel P. Berrange char *buffer = NULL;
2009a2fd434SDaniel P. Berrange size_t size;
2019a2fd434SDaniel P. Berrange bool allowClient = false, allowServer = false;
2029a2fd434SDaniel P. Berrange
2039a2fd434SDaniel P. Berrange critical = 0;
2049a2fd434SDaniel P. Berrange for (i = 0; ; i++) {
2059a2fd434SDaniel P. Berrange size = 0;
2069a2fd434SDaniel P. Berrange status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer,
2079a2fd434SDaniel P. Berrange &size, NULL);
2089a2fd434SDaniel P. Berrange
2099a2fd434SDaniel P. Berrange if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
2109a2fd434SDaniel P. Berrange
2119a2fd434SDaniel P. Berrange /* If there is no data at all, then we must allow
2129a2fd434SDaniel P. Berrange client/server to pass */
2139a2fd434SDaniel P. Berrange if (i == 0) {
2149a2fd434SDaniel P. Berrange allowServer = allowClient = true;
2159a2fd434SDaniel P. Berrange }
2169a2fd434SDaniel P. Berrange break;
2179a2fd434SDaniel P. Berrange }
2189a2fd434SDaniel P. Berrange if (status != GNUTLS_E_SHORT_MEMORY_BUFFER) {
2199a2fd434SDaniel P. Berrange error_setg(errp,
2209a2fd434SDaniel P. Berrange "Unable to query certificate %s key purpose: %s",
2219a2fd434SDaniel P. Berrange certFile, gnutls_strerror(status));
2229a2fd434SDaniel P. Berrange return -1;
2239a2fd434SDaniel P. Berrange }
2249a2fd434SDaniel P. Berrange
2259a2fd434SDaniel P. Berrange buffer = g_new0(char, size);
2269a2fd434SDaniel P. Berrange
2279a2fd434SDaniel P. Berrange status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer,
2289a2fd434SDaniel P. Berrange &size, &purposeCritical);
2299a2fd434SDaniel P. Berrange
2309a2fd434SDaniel P. Berrange if (status < 0) {
2319a2fd434SDaniel P. Berrange trace_qcrypto_tls_creds_x509_check_key_purpose(
2329a2fd434SDaniel P. Berrange creds, certFile, status, "<none>", purposeCritical);
2339a2fd434SDaniel P. Berrange g_free(buffer);
2349a2fd434SDaniel P. Berrange error_setg(errp,
2359a2fd434SDaniel P. Berrange "Unable to query certificate %s key purpose: %s",
2369a2fd434SDaniel P. Berrange certFile, gnutls_strerror(status));
2379a2fd434SDaniel P. Berrange return -1;
2389a2fd434SDaniel P. Berrange }
2399a2fd434SDaniel P. Berrange trace_qcrypto_tls_creds_x509_check_key_purpose(
2409a2fd434SDaniel P. Berrange creds, certFile, status, buffer, purposeCritical);
2419a2fd434SDaniel P. Berrange if (purposeCritical) {
2429a2fd434SDaniel P. Berrange critical = true;
2439a2fd434SDaniel P. Berrange }
2449a2fd434SDaniel P. Berrange
2459a2fd434SDaniel P. Berrange if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_SERVER)) {
2469a2fd434SDaniel P. Berrange allowServer = true;
2479a2fd434SDaniel P. Berrange } else if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_CLIENT)) {
2489a2fd434SDaniel P. Berrange allowClient = true;
2499a2fd434SDaniel P. Berrange } else if (g_str_equal(buffer, GNUTLS_KP_ANY)) {
2509a2fd434SDaniel P. Berrange allowServer = allowClient = true;
2519a2fd434SDaniel P. Berrange }
2529a2fd434SDaniel P. Berrange
2539a2fd434SDaniel P. Berrange g_free(buffer);
2540e1d0245SDaniel P. Berrange buffer = NULL;
2559a2fd434SDaniel P. Berrange }
2569a2fd434SDaniel P. Berrange
2579a2fd434SDaniel P. Berrange if (isServer) {
2589a2fd434SDaniel P. Berrange if (!allowServer) {
2599a2fd434SDaniel P. Berrange if (critical) {
2609a2fd434SDaniel P. Berrange error_setg(errp,
2619a2fd434SDaniel P. Berrange "Certificate %s purpose does not allow "
2629a2fd434SDaniel P. Berrange "use with a TLS server", certFile);
2639a2fd434SDaniel P. Berrange return -1;
2649a2fd434SDaniel P. Berrange }
2659a2fd434SDaniel P. Berrange }
2669a2fd434SDaniel P. Berrange } else {
2679a2fd434SDaniel P. Berrange if (!allowClient) {
2689a2fd434SDaniel P. Berrange if (critical) {
2699a2fd434SDaniel P. Berrange error_setg(errp,
2709a2fd434SDaniel P. Berrange "Certificate %s purpose does not allow use "
2719a2fd434SDaniel P. Berrange "with a TLS client", certFile);
2729a2fd434SDaniel P. Berrange return -1;
2739a2fd434SDaniel P. Berrange }
2749a2fd434SDaniel P. Berrange }
2759a2fd434SDaniel P. Berrange }
2769a2fd434SDaniel P. Berrange
2779a2fd434SDaniel P. Berrange return 0;
2789a2fd434SDaniel P. Berrange }
2799a2fd434SDaniel P. Berrange
2809a2fd434SDaniel P. Berrange
2819a2fd434SDaniel P. Berrange static int
qcrypto_tls_creds_check_cert(QCryptoTLSCredsX509 * creds,gnutls_x509_crt_t cert,const char * certFile,bool isServer,bool isCA,Error ** errp)2829a2fd434SDaniel P. Berrange qcrypto_tls_creds_check_cert(QCryptoTLSCredsX509 *creds,
2839a2fd434SDaniel P. Berrange gnutls_x509_crt_t cert,
2849a2fd434SDaniel P. Berrange const char *certFile,
2859a2fd434SDaniel P. Berrange bool isServer,
2869a2fd434SDaniel P. Berrange bool isCA,
2879a2fd434SDaniel P. Berrange Error **errp)
2889a2fd434SDaniel P. Berrange {
2899a2fd434SDaniel P. Berrange if (qcrypto_tls_creds_check_cert_times(cert, certFile,
2909a2fd434SDaniel P. Berrange isServer, isCA,
2919a2fd434SDaniel P. Berrange errp) < 0) {
2929a2fd434SDaniel P. Berrange return -1;
2939a2fd434SDaniel P. Berrange }
2949a2fd434SDaniel P. Berrange
2959a2fd434SDaniel P. Berrange if (qcrypto_tls_creds_check_cert_basic_constraints(creds,
2969a2fd434SDaniel P. Berrange cert, certFile,
2979a2fd434SDaniel P. Berrange isServer, isCA,
2989a2fd434SDaniel P. Berrange errp) < 0) {
2999a2fd434SDaniel P. Berrange return -1;
3009a2fd434SDaniel P. Berrange }
3019a2fd434SDaniel P. Berrange
3029a2fd434SDaniel P. Berrange if (qcrypto_tls_creds_check_cert_key_usage(creds,
3039a2fd434SDaniel P. Berrange cert, certFile,
3049a2fd434SDaniel P. Berrange isCA, errp) < 0) {
3059a2fd434SDaniel P. Berrange return -1;
3069a2fd434SDaniel P. Berrange }
3079a2fd434SDaniel P. Berrange
3089a2fd434SDaniel P. Berrange if (!isCA &&
3099a2fd434SDaniel P. Berrange qcrypto_tls_creds_check_cert_key_purpose(creds,
3109a2fd434SDaniel P. Berrange cert, certFile,
3119a2fd434SDaniel P. Berrange isServer, errp) < 0) {
3129a2fd434SDaniel P. Berrange return -1;
3139a2fd434SDaniel P. Berrange }
3149a2fd434SDaniel P. Berrange
3159a2fd434SDaniel P. Berrange return 0;
3169a2fd434SDaniel P. Berrange }
3179a2fd434SDaniel P. Berrange
3189a2fd434SDaniel P. Berrange
3199a2fd434SDaniel P. Berrange static int
qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t cert,const char * certFile,gnutls_x509_crt_t * cacerts,size_t ncacerts,const char * cacertFile,bool isServer,Error ** errp)3209a2fd434SDaniel P. Berrange qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t cert,
3219a2fd434SDaniel P. Berrange const char *certFile,
3229a2fd434SDaniel P. Berrange gnutls_x509_crt_t *cacerts,
3239a2fd434SDaniel P. Berrange size_t ncacerts,
3249a2fd434SDaniel P. Berrange const char *cacertFile,
3259a2fd434SDaniel P. Berrange bool isServer,
3269a2fd434SDaniel P. Berrange Error **errp)
3279a2fd434SDaniel P. Berrange {
3289a2fd434SDaniel P. Berrange unsigned int status;
3299a2fd434SDaniel P. Berrange
3309a2fd434SDaniel P. Berrange if (gnutls_x509_crt_list_verify(&cert, 1,
3319a2fd434SDaniel P. Berrange cacerts, ncacerts,
3329a2fd434SDaniel P. Berrange NULL, 0,
3339a2fd434SDaniel P. Berrange 0, &status) < 0) {
3349a2fd434SDaniel P. Berrange error_setg(errp, isServer ?
3359a2fd434SDaniel P. Berrange "Unable to verify server certificate %s against "
3369a2fd434SDaniel P. Berrange "CA certificate %s" :
3379a2fd434SDaniel P. Berrange "Unable to verify client certificate %s against "
3389a2fd434SDaniel P. Berrange "CA certificate %s",
3399a2fd434SDaniel P. Berrange certFile, cacertFile);
3409a2fd434SDaniel P. Berrange return -1;
3419a2fd434SDaniel P. Berrange }
3429a2fd434SDaniel P. Berrange
3439a2fd434SDaniel P. Berrange if (status != 0) {
3449a2fd434SDaniel P. Berrange const char *reason = "Invalid certificate";
3459a2fd434SDaniel P. Berrange
3469a2fd434SDaniel P. Berrange if (status & GNUTLS_CERT_INVALID) {
3479a2fd434SDaniel P. Berrange reason = "The certificate is not trusted";
3489a2fd434SDaniel P. Berrange }
3499a2fd434SDaniel P. Berrange
3509a2fd434SDaniel P. Berrange if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
3519a2fd434SDaniel P. Berrange reason = "The certificate hasn't got a known issuer";
3529a2fd434SDaniel P. Berrange }
3539a2fd434SDaniel P. Berrange
3549a2fd434SDaniel P. Berrange if (status & GNUTLS_CERT_REVOKED) {
3559a2fd434SDaniel P. Berrange reason = "The certificate has been revoked";
3569a2fd434SDaniel P. Berrange }
3579a2fd434SDaniel P. Berrange
3589a2fd434SDaniel P. Berrange if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
3599a2fd434SDaniel P. Berrange reason = "The certificate uses an insecure algorithm";
3609a2fd434SDaniel P. Berrange }
3619a2fd434SDaniel P. Berrange
3629a2fd434SDaniel P. Berrange error_setg(errp,
3639a2fd434SDaniel P. Berrange "Our own certificate %s failed validation against %s: %s",
3649a2fd434SDaniel P. Berrange certFile, cacertFile, reason);
3659a2fd434SDaniel P. Berrange return -1;
3669a2fd434SDaniel P. Berrange }
3679a2fd434SDaniel P. Berrange
3689a2fd434SDaniel P. Berrange return 0;
3699a2fd434SDaniel P. Berrange }
3709a2fd434SDaniel P. Berrange
3719a2fd434SDaniel P. Berrange
3729a2fd434SDaniel P. Berrange static gnutls_x509_crt_t
qcrypto_tls_creds_load_cert(QCryptoTLSCredsX509 * creds,const char * certFile,bool isServer,Error ** errp)3739a2fd434SDaniel P. Berrange qcrypto_tls_creds_load_cert(QCryptoTLSCredsX509 *creds,
3749a2fd434SDaniel P. Berrange const char *certFile,
3759a2fd434SDaniel P. Berrange bool isServer,
3769a2fd434SDaniel P. Berrange Error **errp)
3779a2fd434SDaniel P. Berrange {
3789a2fd434SDaniel P. Berrange gnutls_datum_t data;
3799a2fd434SDaniel P. Berrange gnutls_x509_crt_t cert = NULL;
38057b9f113SDaniel P. Berrangé g_autofree char *buf = NULL;
3819a2fd434SDaniel P. Berrange gsize buflen;
3828cb846dbSMarkus Armbruster GError *gerr = NULL;
3839a2fd434SDaniel P. Berrange int ret = -1;
384b7b68166SAlex Bligh int err;
3859a2fd434SDaniel P. Berrange
3869a2fd434SDaniel P. Berrange trace_qcrypto_tls_creds_x509_load_cert(creds, isServer, certFile);
3879a2fd434SDaniel P. Berrange
388b7b68166SAlex Bligh err = gnutls_x509_crt_init(&cert);
389b7b68166SAlex Bligh if (err < 0) {
390b7b68166SAlex Bligh error_setg(errp, "Unable to initialize certificate: %s",
391b7b68166SAlex Bligh gnutls_strerror(err));
3929a2fd434SDaniel P. Berrange goto cleanup;
3939a2fd434SDaniel P. Berrange }
3949a2fd434SDaniel P. Berrange
3959a2fd434SDaniel P. Berrange if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) {
3969a2fd434SDaniel P. Berrange error_setg(errp, "Cannot load CA cert list %s: %s",
3979a2fd434SDaniel P. Berrange certFile, gerr->message);
3989a2fd434SDaniel P. Berrange g_error_free(gerr);
3999a2fd434SDaniel P. Berrange goto cleanup;
4009a2fd434SDaniel P. Berrange }
4019a2fd434SDaniel P. Berrange
4029a2fd434SDaniel P. Berrange data.data = (unsigned char *)buf;
4039a2fd434SDaniel P. Berrange data.size = strlen(buf);
4049a2fd434SDaniel P. Berrange
405b7b68166SAlex Bligh err = gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM);
406b7b68166SAlex Bligh if (err < 0) {
4079a2fd434SDaniel P. Berrange error_setg(errp, isServer ?
408b7b68166SAlex Bligh "Unable to import server certificate %s: %s" :
409b7b68166SAlex Bligh "Unable to import client certificate %s: %s",
410b7b68166SAlex Bligh certFile,
411b7b68166SAlex Bligh gnutls_strerror(err));
4129a2fd434SDaniel P. Berrange goto cleanup;
4139a2fd434SDaniel P. Berrange }
4149a2fd434SDaniel P. Berrange
4159a2fd434SDaniel P. Berrange ret = 0;
4169a2fd434SDaniel P. Berrange
4179a2fd434SDaniel P. Berrange cleanup:
4189a2fd434SDaniel P. Berrange if (ret != 0) {
4199a2fd434SDaniel P. Berrange gnutls_x509_crt_deinit(cert);
4209a2fd434SDaniel P. Berrange cert = NULL;
4219a2fd434SDaniel P. Berrange }
4229a2fd434SDaniel P. Berrange return cert;
4239a2fd434SDaniel P. Berrange }
4249a2fd434SDaniel P. Berrange
4259a2fd434SDaniel P. Berrange
4269a2fd434SDaniel P. Berrange static int
qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 * creds,const char * certFile,gnutls_x509_crt_t * certs,unsigned int certMax,size_t * ncerts,Error ** errp)4279a2fd434SDaniel P. Berrange qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 *creds,
4289a2fd434SDaniel P. Berrange const char *certFile,
4299a2fd434SDaniel P. Berrange gnutls_x509_crt_t *certs,
4309a2fd434SDaniel P. Berrange unsigned int certMax,
4319a2fd434SDaniel P. Berrange size_t *ncerts,
4329a2fd434SDaniel P. Berrange Error **errp)
4339a2fd434SDaniel P. Berrange {
4349a2fd434SDaniel P. Berrange gnutls_datum_t data;
43557b9f113SDaniel P. Berrangé g_autofree char *buf = NULL;
4369a2fd434SDaniel P. Berrange gsize buflen;
4379a2fd434SDaniel P. Berrange GError *gerr = NULL;
4389a2fd434SDaniel P. Berrange
4399a2fd434SDaniel P. Berrange *ncerts = 0;
4409a2fd434SDaniel P. Berrange trace_qcrypto_tls_creds_x509_load_cert_list(creds, certFile);
4419a2fd434SDaniel P. Berrange
4429a2fd434SDaniel P. Berrange if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) {
4439a2fd434SDaniel P. Berrange error_setg(errp, "Cannot load CA cert list %s: %s",
4449a2fd434SDaniel P. Berrange certFile, gerr->message);
4459a2fd434SDaniel P. Berrange g_error_free(gerr);
44657b9f113SDaniel P. Berrangé return -1;
4479a2fd434SDaniel P. Berrange }
4489a2fd434SDaniel P. Berrange
4499a2fd434SDaniel P. Berrange data.data = (unsigned char *)buf;
4509a2fd434SDaniel P. Berrange data.size = strlen(buf);
4519a2fd434SDaniel P. Berrange
4529a2fd434SDaniel P. Berrange if (gnutls_x509_crt_list_import(certs, &certMax, &data,
4539a2fd434SDaniel P. Berrange GNUTLS_X509_FMT_PEM, 0) < 0) {
4549a2fd434SDaniel P. Berrange error_setg(errp,
4559a2fd434SDaniel P. Berrange "Unable to import CA certificate list %s",
4569a2fd434SDaniel P. Berrange certFile);
45757b9f113SDaniel P. Berrangé return -1;
4589a2fd434SDaniel P. Berrange }
4599a2fd434SDaniel P. Berrange *ncerts = certMax;
4609a2fd434SDaniel P. Berrange
46157b9f113SDaniel P. Berrangé return 0;
4629a2fd434SDaniel P. Berrange }
4639a2fd434SDaniel P. Berrange
4649a2fd434SDaniel P. Berrange
4659a2fd434SDaniel P. Berrange #define MAX_CERTS 16
4669a2fd434SDaniel P. Berrange static int
qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 * creds,bool isServer,const char * cacertFile,const char * certFile,Error ** errp)4679a2fd434SDaniel P. Berrange qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
4689a2fd434SDaniel P. Berrange bool isServer,
4699a2fd434SDaniel P. Berrange const char *cacertFile,
4709a2fd434SDaniel P. Berrange const char *certFile,
4719a2fd434SDaniel P. Berrange Error **errp)
4729a2fd434SDaniel P. Berrange {
4739a2fd434SDaniel P. Berrange gnutls_x509_crt_t cert = NULL;
4749a2fd434SDaniel P. Berrange gnutls_x509_crt_t cacerts[MAX_CERTS];
4759a2fd434SDaniel P. Berrange size_t ncacerts = 0;
4769a2fd434SDaniel P. Berrange size_t i;
4779a2fd434SDaniel P. Berrange int ret = -1;
4789a2fd434SDaniel P. Berrange
4799a2fd434SDaniel P. Berrange memset(cacerts, 0, sizeof(cacerts));
48008cb175aSDaniel P. Berrange if (certFile &&
48108cb175aSDaniel P. Berrange access(certFile, R_OK) == 0) {
4829a2fd434SDaniel P. Berrange cert = qcrypto_tls_creds_load_cert(creds,
4839a2fd434SDaniel P. Berrange certFile, isServer,
4849a2fd434SDaniel P. Berrange errp);
4859a2fd434SDaniel P. Berrange if (!cert) {
4869a2fd434SDaniel P. Berrange goto cleanup;
4879a2fd434SDaniel P. Berrange }
4889a2fd434SDaniel P. Berrange }
4899a2fd434SDaniel P. Berrange if (access(cacertFile, R_OK) == 0) {
4909a2fd434SDaniel P. Berrange if (qcrypto_tls_creds_load_ca_cert_list(creds,
4919a2fd434SDaniel P. Berrange cacertFile, cacerts,
4929a2fd434SDaniel P. Berrange MAX_CERTS, &ncacerts,
4939a2fd434SDaniel P. Berrange errp) < 0) {
4949a2fd434SDaniel P. Berrange goto cleanup;
4959a2fd434SDaniel P. Berrange }
4969a2fd434SDaniel P. Berrange }
4979a2fd434SDaniel P. Berrange
4989a2fd434SDaniel P. Berrange if (cert &&
4999a2fd434SDaniel P. Berrange qcrypto_tls_creds_check_cert(creds,
5009a2fd434SDaniel P. Berrange cert, certFile, isServer,
5019a2fd434SDaniel P. Berrange false, errp) < 0) {
5029a2fd434SDaniel P. Berrange goto cleanup;
5039a2fd434SDaniel P. Berrange }
5049a2fd434SDaniel P. Berrange
5059a2fd434SDaniel P. Berrange for (i = 0; i < ncacerts; i++) {
5069a2fd434SDaniel P. Berrange if (qcrypto_tls_creds_check_cert(creds,
5079a2fd434SDaniel P. Berrange cacerts[i], cacertFile,
5089a2fd434SDaniel P. Berrange isServer, true, errp) < 0) {
5099a2fd434SDaniel P. Berrange goto cleanup;
5109a2fd434SDaniel P. Berrange }
5119a2fd434SDaniel P. Berrange }
5129a2fd434SDaniel P. Berrange
5139a2fd434SDaniel P. Berrange if (cert && ncacerts &&
5149a2fd434SDaniel P. Berrange qcrypto_tls_creds_check_cert_pair(cert, certFile, cacerts,
5159a2fd434SDaniel P. Berrange ncacerts, cacertFile,
5169a2fd434SDaniel P. Berrange isServer, errp) < 0) {
5179a2fd434SDaniel P. Berrange goto cleanup;
5189a2fd434SDaniel P. Berrange }
5199a2fd434SDaniel P. Berrange
5209a2fd434SDaniel P. Berrange ret = 0;
5219a2fd434SDaniel P. Berrange
5229a2fd434SDaniel P. Berrange cleanup:
5239a2fd434SDaniel P. Berrange if (cert) {
5249a2fd434SDaniel P. Berrange gnutls_x509_crt_deinit(cert);
5259a2fd434SDaniel P. Berrange }
5269a2fd434SDaniel P. Berrange for (i = 0; i < ncacerts; i++) {
5279a2fd434SDaniel P. Berrange gnutls_x509_crt_deinit(cacerts[i]);
5289a2fd434SDaniel P. Berrange }
5299a2fd434SDaniel P. Berrange return ret;
5309a2fd434SDaniel P. Berrange }
5319a2fd434SDaniel P. Berrange
53285bcbc78SDaniel P. Berrange
53385bcbc78SDaniel P. Berrange static int
qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 * creds,Error ** errp)53485bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
53585bcbc78SDaniel P. Berrange Error **errp)
53685bcbc78SDaniel P. Berrange {
53785bcbc78SDaniel P. Berrange char *cacert = NULL, *cacrl = NULL, *cert = NULL,
53885bcbc78SDaniel P. Berrange *key = NULL, *dhparams = NULL;
53985bcbc78SDaniel P. Berrange int ret;
54085bcbc78SDaniel P. Berrange int rv = -1;
54185bcbc78SDaniel P. Berrange
54285bcbc78SDaniel P. Berrange trace_qcrypto_tls_creds_x509_load(creds,
54385bcbc78SDaniel P. Berrange creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
54485bcbc78SDaniel P. Berrange
54585bcbc78SDaniel P. Berrange if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
54685bcbc78SDaniel P. Berrange if (qcrypto_tls_creds_get_path(&creds->parent_obj,
54785bcbc78SDaniel P. Berrange QCRYPTO_TLS_CREDS_X509_CA_CERT,
54885bcbc78SDaniel P. Berrange true, &cacert, errp) < 0 ||
54985bcbc78SDaniel P. Berrange qcrypto_tls_creds_get_path(&creds->parent_obj,
55085bcbc78SDaniel P. Berrange QCRYPTO_TLS_CREDS_X509_CA_CRL,
55185bcbc78SDaniel P. Berrange false, &cacrl, errp) < 0 ||
55285bcbc78SDaniel P. Berrange qcrypto_tls_creds_get_path(&creds->parent_obj,
55385bcbc78SDaniel P. Berrange QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
55485bcbc78SDaniel P. Berrange true, &cert, errp) < 0 ||
55585bcbc78SDaniel P. Berrange qcrypto_tls_creds_get_path(&creds->parent_obj,
55685bcbc78SDaniel P. Berrange QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
55785bcbc78SDaniel P. Berrange true, &key, errp) < 0 ||
55885bcbc78SDaniel P. Berrange qcrypto_tls_creds_get_path(&creds->parent_obj,
55985bcbc78SDaniel P. Berrange QCRYPTO_TLS_CREDS_DH_PARAMS,
56085bcbc78SDaniel P. Berrange false, &dhparams, errp) < 0) {
56185bcbc78SDaniel P. Berrange goto cleanup;
56285bcbc78SDaniel P. Berrange }
56385bcbc78SDaniel P. Berrange } else {
56485bcbc78SDaniel P. Berrange if (qcrypto_tls_creds_get_path(&creds->parent_obj,
56585bcbc78SDaniel P. Berrange QCRYPTO_TLS_CREDS_X509_CA_CERT,
56685bcbc78SDaniel P. Berrange true, &cacert, errp) < 0 ||
56785bcbc78SDaniel P. Berrange qcrypto_tls_creds_get_path(&creds->parent_obj,
56885bcbc78SDaniel P. Berrange QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
56985bcbc78SDaniel P. Berrange false, &cert, errp) < 0 ||
57085bcbc78SDaniel P. Berrange qcrypto_tls_creds_get_path(&creds->parent_obj,
57185bcbc78SDaniel P. Berrange QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
57285bcbc78SDaniel P. Berrange false, &key, errp) < 0) {
57385bcbc78SDaniel P. Berrange goto cleanup;
57485bcbc78SDaniel P. Berrange }
57585bcbc78SDaniel P. Berrange }
57685bcbc78SDaniel P. Berrange
5779a2fd434SDaniel P. Berrange if (creds->sanityCheck &&
5789a2fd434SDaniel P. Berrange qcrypto_tls_creds_x509_sanity_check(creds,
5799a2fd434SDaniel P. Berrange creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
5809a2fd434SDaniel P. Berrange cacert, cert, errp) < 0) {
5819a2fd434SDaniel P. Berrange goto cleanup;
5829a2fd434SDaniel P. Berrange }
5839a2fd434SDaniel P. Berrange
58485bcbc78SDaniel P. Berrange ret = gnutls_certificate_allocate_credentials(&creds->data);
58585bcbc78SDaniel P. Berrange if (ret < 0) {
58685bcbc78SDaniel P. Berrange error_setg(errp, "Cannot allocate credentials: '%s'",
58785bcbc78SDaniel P. Berrange gnutls_strerror(ret));
58885bcbc78SDaniel P. Berrange goto cleanup;
58985bcbc78SDaniel P. Berrange }
59085bcbc78SDaniel P. Berrange
59185bcbc78SDaniel P. Berrange ret = gnutls_certificate_set_x509_trust_file(creds->data,
59285bcbc78SDaniel P. Berrange cacert,
59385bcbc78SDaniel P. Berrange GNUTLS_X509_FMT_PEM);
59485bcbc78SDaniel P. Berrange if (ret < 0) {
59585bcbc78SDaniel P. Berrange error_setg(errp, "Cannot load CA certificate '%s': %s",
59685bcbc78SDaniel P. Berrange cacert, gnutls_strerror(ret));
59785bcbc78SDaniel P. Berrange goto cleanup;
59885bcbc78SDaniel P. Berrange }
59985bcbc78SDaniel P. Berrange
60085bcbc78SDaniel P. Berrange if (cert != NULL && key != NULL) {
6011d7b5b4aSDaniel P. Berrange char *password = NULL;
6021d7b5b4aSDaniel P. Berrange if (creds->passwordid) {
6031d7b5b4aSDaniel P. Berrange password = qcrypto_secret_lookup_as_utf8(creds->passwordid,
6041d7b5b4aSDaniel P. Berrange errp);
6051d7b5b4aSDaniel P. Berrange if (!password) {
6061d7b5b4aSDaniel P. Berrange goto cleanup;
6071d7b5b4aSDaniel P. Berrange }
6081d7b5b4aSDaniel P. Berrange }
6091d7b5b4aSDaniel P. Berrange ret = gnutls_certificate_set_x509_key_file2(creds->data,
6101d7b5b4aSDaniel P. Berrange cert, key,
6111d7b5b4aSDaniel P. Berrange GNUTLS_X509_FMT_PEM,
6121d7b5b4aSDaniel P. Berrange password,
6131d7b5b4aSDaniel P. Berrange 0);
6141d7b5b4aSDaniel P. Berrange g_free(password);
61585bcbc78SDaniel P. Berrange if (ret < 0) {
61685bcbc78SDaniel P. Berrange error_setg(errp, "Cannot load certificate '%s' & key '%s': %s",
61785bcbc78SDaniel P. Berrange cert, key, gnutls_strerror(ret));
61885bcbc78SDaniel P. Berrange goto cleanup;
61985bcbc78SDaniel P. Berrange }
62085bcbc78SDaniel P. Berrange }
62185bcbc78SDaniel P. Berrange
62285bcbc78SDaniel P. Berrange if (cacrl != NULL) {
62385bcbc78SDaniel P. Berrange ret = gnutls_certificate_set_x509_crl_file(creds->data,
62485bcbc78SDaniel P. Berrange cacrl,
62585bcbc78SDaniel P. Berrange GNUTLS_X509_FMT_PEM);
62685bcbc78SDaniel P. Berrange if (ret < 0) {
62785bcbc78SDaniel P. Berrange error_setg(errp, "Cannot load CRL '%s': %s",
62885bcbc78SDaniel P. Berrange cacrl, gnutls_strerror(ret));
62985bcbc78SDaniel P. Berrange goto cleanup;
63085bcbc78SDaniel P. Berrange }
63185bcbc78SDaniel P. Berrange }
63285bcbc78SDaniel P. Berrange
63385bcbc78SDaniel P. Berrange if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
63485bcbc78SDaniel P. Berrange if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
63585bcbc78SDaniel P. Berrange &creds->parent_obj.dh_params,
63685bcbc78SDaniel P. Berrange errp) < 0) {
63785bcbc78SDaniel P. Berrange goto cleanup;
63885bcbc78SDaniel P. Berrange }
63985bcbc78SDaniel P. Berrange gnutls_certificate_set_dh_params(creds->data,
64085bcbc78SDaniel P. Berrange creds->parent_obj.dh_params);
64185bcbc78SDaniel P. Berrange }
64285bcbc78SDaniel P. Berrange
64385bcbc78SDaniel P. Berrange rv = 0;
64485bcbc78SDaniel P. Berrange cleanup:
64585bcbc78SDaniel P. Berrange g_free(cacert);
64685bcbc78SDaniel P. Berrange g_free(cacrl);
64785bcbc78SDaniel P. Berrange g_free(cert);
64885bcbc78SDaniel P. Berrange g_free(key);
64985bcbc78SDaniel P. Berrange g_free(dhparams);
65085bcbc78SDaniel P. Berrange return rv;
65185bcbc78SDaniel P. Berrange }
65285bcbc78SDaniel P. Berrange
65385bcbc78SDaniel P. Berrange
65485bcbc78SDaniel P. Berrange static void
qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 * creds)65585bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds)
65685bcbc78SDaniel P. Berrange {
65785bcbc78SDaniel P. Berrange if (creds->data) {
65885bcbc78SDaniel P. Berrange gnutls_certificate_free_credentials(creds->data);
65985bcbc78SDaniel P. Berrange creds->data = NULL;
66085bcbc78SDaniel P. Berrange }
66161b9251aSDaniel P. Berrange if (creds->parent_obj.dh_params) {
66261b9251aSDaniel P. Berrange gnutls_dh_params_deinit(creds->parent_obj.dh_params);
66361b9251aSDaniel P. Berrange creds->parent_obj.dh_params = NULL;
66461b9251aSDaniel P. Berrange }
66585bcbc78SDaniel P. Berrange }
66685bcbc78SDaniel P. Berrange
66785bcbc78SDaniel P. Berrange
66885bcbc78SDaniel P. Berrange #else /* ! CONFIG_GNUTLS */
66985bcbc78SDaniel P. Berrange
67085bcbc78SDaniel P. Berrange
67185bcbc78SDaniel P. Berrange static void
qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 * creds G_GNUC_UNUSED,Error ** errp)67285bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED,
67385bcbc78SDaniel P. Berrange Error **errp)
67485bcbc78SDaniel P. Berrange {
67585bcbc78SDaniel P. Berrange error_setg(errp, "TLS credentials support requires GNUTLS");
67685bcbc78SDaniel P. Berrange }
67785bcbc78SDaniel P. Berrange
67885bcbc78SDaniel P. Berrange
67985bcbc78SDaniel P. Berrange static void
qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 * creds G_GNUC_UNUSED)68085bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED)
68185bcbc78SDaniel P. Berrange {
68285bcbc78SDaniel P. Berrange /* nada */
68385bcbc78SDaniel P. Berrange }
68485bcbc78SDaniel P. Berrange
68585bcbc78SDaniel P. Berrange
68685bcbc78SDaniel P. Berrange #endif /* ! CONFIG_GNUTLS */
68785bcbc78SDaniel P. Berrange
68885bcbc78SDaniel P. Berrange
68985bcbc78SDaniel P. Berrange static void
qcrypto_tls_creds_x509_complete(UserCreatable * uc,Error ** errp)6900310641cSPaolo Bonzini qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp)
69185bcbc78SDaniel P. Berrange {
6920310641cSPaolo Bonzini QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(uc);
69385bcbc78SDaniel P. Berrange
69485bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_load(creds, errp);
69585bcbc78SDaniel P. Berrange }
69685bcbc78SDaniel P. Berrange
69785bcbc78SDaniel P. Berrange
69885bcbc78SDaniel P. Berrange #ifdef CONFIG_GNUTLS
69985bcbc78SDaniel P. Berrange
70085bcbc78SDaniel P. Berrange
70185bcbc78SDaniel P. Berrange static bool
qcrypto_tls_creds_x509_prop_get_loaded(Object * obj,Error ** errp G_GNUC_UNUSED)70285bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_prop_get_loaded(Object *obj,
70385bcbc78SDaniel P. Berrange Error **errp G_GNUC_UNUSED)
70485bcbc78SDaniel P. Berrange {
70585bcbc78SDaniel P. Berrange QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
70685bcbc78SDaniel P. Berrange
70785bcbc78SDaniel P. Berrange return creds->data != NULL;
70885bcbc78SDaniel P. Berrange }
70985bcbc78SDaniel P. Berrange
71085bcbc78SDaniel P. Berrange
71185bcbc78SDaniel P. Berrange #else /* ! CONFIG_GNUTLS */
71285bcbc78SDaniel P. Berrange
71385bcbc78SDaniel P. Berrange
71485bcbc78SDaniel P. Berrange static bool
qcrypto_tls_creds_x509_prop_get_loaded(Object * obj G_GNUC_UNUSED,Error ** errp G_GNUC_UNUSED)71585bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_prop_get_loaded(Object *obj G_GNUC_UNUSED,
71685bcbc78SDaniel P. Berrange Error **errp G_GNUC_UNUSED)
71785bcbc78SDaniel P. Berrange {
71885bcbc78SDaniel P. Berrange return false;
71985bcbc78SDaniel P. Berrange }
72085bcbc78SDaniel P. Berrange
72185bcbc78SDaniel P. Berrange
72285bcbc78SDaniel P. Berrange #endif /* ! CONFIG_GNUTLS */
72385bcbc78SDaniel P. Berrange
72485bcbc78SDaniel P. Berrange
72585bcbc78SDaniel P. Berrange static void
qcrypto_tls_creds_x509_prop_set_sanity(Object * obj,bool value,Error ** errp G_GNUC_UNUSED)7269a2fd434SDaniel P. Berrange qcrypto_tls_creds_x509_prop_set_sanity(Object *obj,
7279a2fd434SDaniel P. Berrange bool value,
7289a2fd434SDaniel P. Berrange Error **errp G_GNUC_UNUSED)
7299a2fd434SDaniel P. Berrange {
7309a2fd434SDaniel P. Berrange QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
7319a2fd434SDaniel P. Berrange
7329a2fd434SDaniel P. Berrange creds->sanityCheck = value;
7339a2fd434SDaniel P. Berrange }
7349a2fd434SDaniel P. Berrange
7359a2fd434SDaniel P. Berrange
7361d7b5b4aSDaniel P. Berrange static void
qcrypto_tls_creds_x509_prop_set_passwordid(Object * obj,const char * value,Error ** errp G_GNUC_UNUSED)7371d7b5b4aSDaniel P. Berrange qcrypto_tls_creds_x509_prop_set_passwordid(Object *obj,
7381d7b5b4aSDaniel P. Berrange const char *value,
7391d7b5b4aSDaniel P. Berrange Error **errp G_GNUC_UNUSED)
7401d7b5b4aSDaniel P. Berrange {
7411d7b5b4aSDaniel P. Berrange QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
7421d7b5b4aSDaniel P. Berrange
7431d7b5b4aSDaniel P. Berrange creds->passwordid = g_strdup(value);
7441d7b5b4aSDaniel P. Berrange }
7451d7b5b4aSDaniel P. Berrange
7461d7b5b4aSDaniel P. Berrange
7471d7b5b4aSDaniel P. Berrange static char *
qcrypto_tls_creds_x509_prop_get_passwordid(Object * obj,Error ** errp G_GNUC_UNUSED)7481d7b5b4aSDaniel P. Berrange qcrypto_tls_creds_x509_prop_get_passwordid(Object *obj,
7491d7b5b4aSDaniel P. Berrange Error **errp G_GNUC_UNUSED)
7501d7b5b4aSDaniel P. Berrange {
7511d7b5b4aSDaniel P. Berrange QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
7521d7b5b4aSDaniel P. Berrange
7531d7b5b4aSDaniel P. Berrange return g_strdup(creds->passwordid);
7541d7b5b4aSDaniel P. Berrange }
7551d7b5b4aSDaniel P. Berrange
7561d7b5b4aSDaniel P. Berrange
7579a2fd434SDaniel P. Berrange static bool
qcrypto_tls_creds_x509_prop_get_sanity(Object * obj,Error ** errp G_GNUC_UNUSED)7589a2fd434SDaniel P. Berrange qcrypto_tls_creds_x509_prop_get_sanity(Object *obj,
7599a2fd434SDaniel P. Berrange Error **errp G_GNUC_UNUSED)
7609a2fd434SDaniel P. Berrange {
7619a2fd434SDaniel P. Berrange QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
7629a2fd434SDaniel P. Berrange
7639a2fd434SDaniel P. Berrange return creds->sanityCheck;
7649a2fd434SDaniel P. Berrange }
7659a2fd434SDaniel P. Berrange
7669a2fd434SDaniel P. Berrange
767a29acc9cSZihao Chang #ifdef CONFIG_GNUTLS
768a29acc9cSZihao Chang
769a29acc9cSZihao Chang
770a29acc9cSZihao Chang static bool
qcrypto_tls_creds_x509_reload(QCryptoTLSCreds * creds,Error ** errp)771a29acc9cSZihao Chang qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
772a29acc9cSZihao Chang {
773a29acc9cSZihao Chang QCryptoTLSCredsX509 *x509_creds = QCRYPTO_TLS_CREDS_X509(creds);
774a29acc9cSZihao Chang Error *local_err = NULL;
775a29acc9cSZihao Chang gnutls_certificate_credentials_t creds_data = x509_creds->data;
776a29acc9cSZihao Chang gnutls_dh_params_t creds_dh_params = x509_creds->parent_obj.dh_params;
777a29acc9cSZihao Chang
778a29acc9cSZihao Chang x509_creds->data = NULL;
779a29acc9cSZihao Chang x509_creds->parent_obj.dh_params = NULL;
780a29acc9cSZihao Chang qcrypto_tls_creds_x509_load(x509_creds, &local_err);
781a29acc9cSZihao Chang if (local_err) {
782a29acc9cSZihao Chang qcrypto_tls_creds_x509_unload(x509_creds);
783a29acc9cSZihao Chang x509_creds->data = creds_data;
784a29acc9cSZihao Chang x509_creds->parent_obj.dh_params = creds_dh_params;
785a29acc9cSZihao Chang error_propagate(errp, local_err);
786a29acc9cSZihao Chang return false;
787a29acc9cSZihao Chang }
788a29acc9cSZihao Chang
789a29acc9cSZihao Chang if (creds_data) {
790a29acc9cSZihao Chang gnutls_certificate_free_credentials(creds_data);
791a29acc9cSZihao Chang }
792a29acc9cSZihao Chang if (creds_dh_params) {
793a29acc9cSZihao Chang gnutls_dh_params_deinit(creds_dh_params);
794a29acc9cSZihao Chang }
795a29acc9cSZihao Chang return true;
796a29acc9cSZihao Chang }
797a29acc9cSZihao Chang
798a29acc9cSZihao Chang
799a29acc9cSZihao Chang #else /* ! CONFIG_GNUTLS */
800a29acc9cSZihao Chang
801a29acc9cSZihao Chang
802a29acc9cSZihao Chang static bool
qcrypto_tls_creds_x509_reload(QCryptoTLSCreds * creds,Error ** errp)803a29acc9cSZihao Chang qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
804a29acc9cSZihao Chang {
805a29acc9cSZihao Chang return false;
806a29acc9cSZihao Chang }
807a29acc9cSZihao Chang
808a29acc9cSZihao Chang
809a29acc9cSZihao Chang #endif /* ! CONFIG_GNUTLS */
810a29acc9cSZihao Chang
811a29acc9cSZihao Chang
8129a2fd434SDaniel P. Berrange static void
qcrypto_tls_creds_x509_init(Object * obj)81385bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_init(Object *obj)
81485bcbc78SDaniel P. Berrange {
8159a2fd434SDaniel P. Berrange QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
8169a2fd434SDaniel P. Berrange
8179a2fd434SDaniel P. Berrange creds->sanityCheck = true;
81885bcbc78SDaniel P. Berrange }
81985bcbc78SDaniel P. Berrange
82085bcbc78SDaniel P. Berrange
82185bcbc78SDaniel P. Berrange static void
qcrypto_tls_creds_x509_finalize(Object * obj)82285bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_finalize(Object *obj)
82385bcbc78SDaniel P. Berrange {
82485bcbc78SDaniel P. Berrange QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
82585bcbc78SDaniel P. Berrange
8261d7b5b4aSDaniel P. Berrange g_free(creds->passwordid);
82785bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_unload(creds);
82885bcbc78SDaniel P. Berrange }
82985bcbc78SDaniel P. Berrange
83085bcbc78SDaniel P. Berrange
83185bcbc78SDaniel P. Berrange static void
qcrypto_tls_creds_x509_class_init(ObjectClass * oc,void * data)83285bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data)
83385bcbc78SDaniel P. Berrange {
83485bcbc78SDaniel P. Berrange UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
835a29acc9cSZihao Chang QCryptoTLSCredsClass *ctcc = QCRYPTO_TLS_CREDS_CLASS(oc);
836a29acc9cSZihao Chang
837a29acc9cSZihao Chang ctcc->reload = qcrypto_tls_creds_x509_reload;
83885bcbc78SDaniel P. Berrange
83985bcbc78SDaniel P. Berrange ucc->complete = qcrypto_tls_creds_x509_complete;
8409884abeeSDaniel P. Berrange
8419884abeeSDaniel P. Berrange object_class_property_add_bool(oc, "loaded",
8429884abeeSDaniel P. Berrange qcrypto_tls_creds_x509_prop_get_loaded,
8430310641cSPaolo Bonzini NULL);
8449884abeeSDaniel P. Berrange object_class_property_add_bool(oc, "sanity-check",
8459884abeeSDaniel P. Berrange qcrypto_tls_creds_x509_prop_get_sanity,
846d2623129SMarkus Armbruster qcrypto_tls_creds_x509_prop_set_sanity);
8479884abeeSDaniel P. Berrange object_class_property_add_str(oc, "passwordid",
8489884abeeSDaniel P. Berrange qcrypto_tls_creds_x509_prop_get_passwordid,
849d2623129SMarkus Armbruster qcrypto_tls_creds_x509_prop_set_passwordid);
85085bcbc78SDaniel P. Berrange }
85185bcbc78SDaniel P. Berrange
85285bcbc78SDaniel P. Berrange
85385bcbc78SDaniel P. Berrange static const TypeInfo qcrypto_tls_creds_x509_info = {
85485bcbc78SDaniel P. Berrange .parent = TYPE_QCRYPTO_TLS_CREDS,
85585bcbc78SDaniel P. Berrange .name = TYPE_QCRYPTO_TLS_CREDS_X509,
85685bcbc78SDaniel P. Berrange .instance_size = sizeof(QCryptoTLSCredsX509),
85785bcbc78SDaniel P. Berrange .instance_init = qcrypto_tls_creds_x509_init,
85885bcbc78SDaniel P. Berrange .instance_finalize = qcrypto_tls_creds_x509_finalize,
85985bcbc78SDaniel P. Berrange .class_size = sizeof(QCryptoTLSCredsX509Class),
86085bcbc78SDaniel P. Berrange .class_init = qcrypto_tls_creds_x509_class_init,
86185bcbc78SDaniel P. Berrange .interfaces = (InterfaceInfo[]) {
86285bcbc78SDaniel P. Berrange { TYPE_USER_CREATABLE },
86385bcbc78SDaniel P. Berrange { }
86485bcbc78SDaniel P. Berrange }
86585bcbc78SDaniel P. Berrange };
86685bcbc78SDaniel P. Berrange
86785bcbc78SDaniel P. Berrange
86885bcbc78SDaniel P. Berrange static void
qcrypto_tls_creds_x509_register_types(void)86985bcbc78SDaniel P. Berrange qcrypto_tls_creds_x509_register_types(void)
87085bcbc78SDaniel P. Berrange {
87185bcbc78SDaniel P. Berrange type_register_static(&qcrypto_tls_creds_x509_info);
87285bcbc78SDaniel P. Berrange }
87385bcbc78SDaniel P. Berrange
87485bcbc78SDaniel P. Berrange
87585bcbc78SDaniel P. Berrange type_init(qcrypto_tls_creds_x509_register_types);
876