xref: /qemu/crypto/tlscredsx509.c (revision 0310641c)
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