xref: /qemu/crypto/tlscredsx509.c (revision 954a6c4f7862b45617ff3b65609f0f290dcd5077)
1  /*
2   * QEMU crypto TLS x509 credential support
3   *
4   * Copyright (c) 2015 Red Hat, Inc.
5   *
6   * This library is free software; you can redistribute it and/or
7   * modify it under the terms of the GNU Lesser General Public
8   * License as published by the Free Software Foundation; either
9   * version 2.1 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18   *
19   */
20  
21  #include "qemu/osdep.h"
22  #include "crypto/tlscredsx509.h"
23  #include "tlscredspriv.h"
24  #include "crypto/secret.h"
25  #include "qapi/error.h"
26  #include "qemu/module.h"
27  #include "qom/object_interfaces.h"
28  #include "trace.h"
29  
30  
31  #ifdef CONFIG_GNUTLS
32  
33  #include <gnutls/gnutls.h>
34  #include <gnutls/x509.h>
35  
36  
37  static int
38  qcrypto_tls_creds_check_cert_times(gnutls_x509_crt_t cert,
39                                     const char *certFile,
40                                     bool isServer,
41                                     bool isCA,
42                                     Error **errp)
43  {
44      time_t now = time(NULL);
45  
46      if (now == ((time_t)-1)) {
47          error_setg_errno(errp, errno, "cannot get current time");
48          return -1;
49      }
50  
51      if (gnutls_x509_crt_get_expiration_time(cert) < now) {
52          error_setg(errp,
53                     (isCA ?
54                      "The CA certificate %s has expired" :
55                      (isServer ?
56                       "The server certificate %s has expired" :
57                       "The client certificate %s has expired")),
58                     certFile);
59          return -1;
60      }
61  
62      if (gnutls_x509_crt_get_activation_time(cert) > now) {
63          error_setg(errp,
64                     (isCA ?
65                      "The CA certificate %s is not yet active" :
66                      (isServer ?
67                       "The server certificate %s is not yet active" :
68                       "The client certificate %s is not yet active")),
69                     certFile);
70          return -1;
71      }
72  
73      return 0;
74  }
75  
76  
77  static int
78  qcrypto_tls_creds_check_cert_basic_constraints(QCryptoTLSCredsX509 *creds,
79                                                 gnutls_x509_crt_t cert,
80                                                 const char *certFile,
81                                                 bool isServer,
82                                                 bool isCA,
83                                                 Error **errp)
84  {
85      int status;
86  
87      status = gnutls_x509_crt_get_basic_constraints(cert, NULL, NULL, NULL);
88      trace_qcrypto_tls_creds_x509_check_basic_constraints(
89          creds, certFile, status);
90  
91      if (status > 0) { /* It is a CA cert */
92          if (!isCA) {
93              error_setg(errp, isServer ?
94                         "The certificate %s basic constraints show a CA, "
95                         "but we need one for a server" :
96                         "The certificate %s basic constraints show a CA, "
97                         "but we need one for a client",
98                         certFile);
99              return -1;
100          }
101      } else if (status == 0) { /* It is not a CA cert */
102          if (isCA) {
103              error_setg(errp,
104                         "The certificate %s basic constraints do not "
105                         "show a CA",
106                         certFile);
107              return -1;
108          }
109      } else if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
110          /* Missing basicConstraints */
111          if (isCA) {
112              error_setg(errp,
113                         "The certificate %s is missing basic constraints "
114                         "for a CA",
115                         certFile);
116              return -1;
117          }
118      } else { /* General error */
119          error_setg(errp,
120                     "Unable to query certificate %s basic constraints: %s",
121                     certFile, gnutls_strerror(status));
122          return -1;
123      }
124  
125      return 0;
126  }
127  
128  
129  static int
130  qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 *creds,
131                                         gnutls_x509_crt_t cert,
132                                         const char *certFile,
133                                         bool isCA,
134                                         Error **errp)
135  {
136      int status;
137      unsigned int usage = 0;
138      unsigned int critical = 0;
139  
140      status = gnutls_x509_crt_get_key_usage(cert, &usage, &critical);
141      trace_qcrypto_tls_creds_x509_check_key_usage(
142          creds, certFile, status, usage, critical);
143  
144      if (status < 0) {
145          if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
146              usage = isCA ? GNUTLS_KEY_KEY_CERT_SIGN :
147                  GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT;
148          } else {
149              error_setg(errp,
150                         "Unable to query certificate %s key usage: %s",
151                         certFile, gnutls_strerror(status));
152              return -1;
153          }
154      }
155  
156      if (isCA) {
157          if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) {
158              if (critical) {
159                  error_setg(errp,
160                             "Certificate %s usage does not permit "
161                             "certificate signing", certFile);
162                  return -1;
163              }
164          }
165      } else {
166          if (!(usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) {
167              if (critical) {
168                  error_setg(errp,
169                             "Certificate %s usage does not permit digital "
170                             "signature", certFile);
171                  return -1;
172              }
173          }
174          if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) {
175              if (critical) {
176                  error_setg(errp,
177                             "Certificate %s usage does not permit key "
178                             "encipherment", certFile);
179                  return -1;
180              }
181          }
182      }
183  
184      return 0;
185  }
186  
187  
188  static int
189  qcrypto_tls_creds_check_cert_key_purpose(QCryptoTLSCredsX509 *creds,
190                                           gnutls_x509_crt_t cert,
191                                           const char *certFile,
192                                           bool isServer,
193                                           Error **errp)
194  {
195      int status;
196      size_t i;
197      unsigned int purposeCritical;
198      unsigned int critical;
199      char *buffer = NULL;
200      size_t size;
201      bool allowClient = false, allowServer = false;
202  
203      critical = 0;
204      for (i = 0; ; i++) {
205          size = 0;
206          status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer,
207                                                       &size, NULL);
208  
209          if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
210  
211              /* If there is no data at all, then we must allow
212                 client/server to pass */
213              if (i == 0) {
214                  allowServer = allowClient = true;
215              }
216              break;
217          }
218          if (status != GNUTLS_E_SHORT_MEMORY_BUFFER) {
219              error_setg(errp,
220                         "Unable to query certificate %s key purpose: %s",
221                         certFile, gnutls_strerror(status));
222              return -1;
223          }
224  
225          buffer = g_new0(char, size);
226  
227          status = gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer,
228                                                       &size, &purposeCritical);
229  
230          if (status < 0) {
231              trace_qcrypto_tls_creds_x509_check_key_purpose(
232                  creds, certFile, status, "<none>", purposeCritical);
233              g_free(buffer);
234              error_setg(errp,
235                         "Unable to query certificate %s key purpose: %s",
236                         certFile, gnutls_strerror(status));
237              return -1;
238          }
239          trace_qcrypto_tls_creds_x509_check_key_purpose(
240              creds, certFile, status, buffer, purposeCritical);
241          if (purposeCritical) {
242              critical = true;
243          }
244  
245          if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_SERVER)) {
246              allowServer = true;
247          } else if (g_str_equal(buffer, GNUTLS_KP_TLS_WWW_CLIENT)) {
248              allowClient = true;
249          } else if (g_str_equal(buffer, GNUTLS_KP_ANY)) {
250              allowServer = allowClient = true;
251          }
252  
253          g_free(buffer);
254          buffer = NULL;
255      }
256  
257      if (isServer) {
258          if (!allowServer) {
259              if (critical) {
260                  error_setg(errp,
261                             "Certificate %s purpose does not allow "
262                             "use with a TLS server", certFile);
263                  return -1;
264              }
265          }
266      } else {
267          if (!allowClient) {
268              if (critical) {
269                  error_setg(errp,
270                             "Certificate %s purpose does not allow use "
271                             "with a TLS client", certFile);
272                  return -1;
273              }
274          }
275      }
276  
277      return 0;
278  }
279  
280  
281  static int
282  qcrypto_tls_creds_check_cert(QCryptoTLSCredsX509 *creds,
283                               gnutls_x509_crt_t cert,
284                               const char *certFile,
285                               bool isServer,
286                               bool isCA,
287                               Error **errp)
288  {
289      if (qcrypto_tls_creds_check_cert_times(cert, certFile,
290                                             isServer, isCA,
291                                             errp) < 0) {
292          return -1;
293      }
294  
295      if (qcrypto_tls_creds_check_cert_basic_constraints(creds,
296                                                         cert, certFile,
297                                                         isServer, isCA,
298                                                         errp) < 0) {
299          return -1;
300      }
301  
302      if (qcrypto_tls_creds_check_cert_key_usage(creds,
303                                                 cert, certFile,
304                                                 isCA, errp) < 0) {
305          return -1;
306      }
307  
308      if (!isCA &&
309          qcrypto_tls_creds_check_cert_key_purpose(creds,
310                                                   cert, certFile,
311                                                   isServer, errp) < 0) {
312          return -1;
313      }
314  
315      return 0;
316  }
317  
318  
319  static int
320  qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t cert,
321                                    const char *certFile,
322                                    gnutls_x509_crt_t *cacerts,
323                                    size_t ncacerts,
324                                    const char *cacertFile,
325                                    bool isServer,
326                                    Error **errp)
327  {
328      unsigned int status;
329  
330      if (gnutls_x509_crt_list_verify(&cert, 1,
331                                      cacerts, ncacerts,
332                                      NULL, 0,
333                                      0, &status) < 0) {
334          error_setg(errp, isServer ?
335                     "Unable to verify server certificate %s against "
336                     "CA certificate %s" :
337                     "Unable to verify client certificate %s against "
338                     "CA certificate %s",
339                     certFile, cacertFile);
340          return -1;
341      }
342  
343      if (status != 0) {
344          const char *reason = "Invalid certificate";
345  
346          if (status & GNUTLS_CERT_INVALID) {
347              reason = "The certificate is not trusted";
348          }
349  
350          if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
351              reason = "The certificate hasn't got a known issuer";
352          }
353  
354          if (status & GNUTLS_CERT_REVOKED) {
355              reason = "The certificate has been revoked";
356          }
357  
358          if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
359              reason = "The certificate uses an insecure algorithm";
360          }
361  
362          error_setg(errp,
363                     "Our own certificate %s failed validation against %s: %s",
364                     certFile, cacertFile, reason);
365          return -1;
366      }
367  
368      return 0;
369  }
370  
371  
372  static gnutls_x509_crt_t
373  qcrypto_tls_creds_load_cert(QCryptoTLSCredsX509 *creds,
374                              const char *certFile,
375                              bool isServer,
376                              Error **errp)
377  {
378      gnutls_datum_t data;
379      gnutls_x509_crt_t cert = NULL;
380      g_autofree char *buf = NULL;
381      gsize buflen;
382      GError *gerr = NULL;
383      int ret = -1;
384      int err;
385  
386      trace_qcrypto_tls_creds_x509_load_cert(creds, isServer, certFile);
387  
388      err = gnutls_x509_crt_init(&cert);
389      if (err < 0) {
390          error_setg(errp, "Unable to initialize certificate: %s",
391                     gnutls_strerror(err));
392          goto cleanup;
393      }
394  
395      if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) {
396          error_setg(errp, "Cannot load CA cert list %s: %s",
397                     certFile, gerr->message);
398          g_error_free(gerr);
399          goto cleanup;
400      }
401  
402      data.data = (unsigned char *)buf;
403      data.size = strlen(buf);
404  
405      err = gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM);
406      if (err < 0) {
407          error_setg(errp, isServer ?
408                     "Unable to import server certificate %s: %s" :
409                     "Unable to import client certificate %s: %s",
410                     certFile,
411                     gnutls_strerror(err));
412          goto cleanup;
413      }
414  
415      ret = 0;
416  
417   cleanup:
418      if (ret != 0) {
419          gnutls_x509_crt_deinit(cert);
420          cert = NULL;
421      }
422      return cert;
423  }
424  
425  
426  static int
427  qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 *creds,
428                                      const char *certFile,
429                                      gnutls_x509_crt_t *certs,
430                                      unsigned int certMax,
431                                      size_t *ncerts,
432                                      Error **errp)
433  {
434      gnutls_datum_t data;
435      g_autofree char *buf = NULL;
436      gsize buflen;
437      GError *gerr = NULL;
438  
439      *ncerts = 0;
440      trace_qcrypto_tls_creds_x509_load_cert_list(creds, certFile);
441  
442      if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) {
443          error_setg(errp, "Cannot load CA cert list %s: %s",
444                     certFile, gerr->message);
445          g_error_free(gerr);
446          return -1;
447      }
448  
449      data.data = (unsigned char *)buf;
450      data.size = strlen(buf);
451  
452      if (gnutls_x509_crt_list_import(certs, &certMax, &data,
453                                      GNUTLS_X509_FMT_PEM, 0) < 0) {
454          error_setg(errp,
455                     "Unable to import CA certificate list %s",
456                     certFile);
457          return -1;
458      }
459      *ncerts = certMax;
460  
461      return 0;
462  }
463  
464  
465  #define MAX_CERTS 16
466  static int
467  qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
468                                      bool isServer,
469                                      const char *cacertFile,
470                                      const char *certFile,
471                                      Error **errp)
472  {
473      gnutls_x509_crt_t cert = NULL;
474      gnutls_x509_crt_t cacerts[MAX_CERTS];
475      size_t ncacerts = 0;
476      size_t i;
477      int ret = -1;
478  
479      memset(cacerts, 0, sizeof(cacerts));
480      if (certFile &&
481          access(certFile, R_OK) == 0) {
482          cert = qcrypto_tls_creds_load_cert(creds,
483                                             certFile, isServer,
484                                             errp);
485          if (!cert) {
486              goto cleanup;
487          }
488      }
489      if (access(cacertFile, R_OK) == 0) {
490          if (qcrypto_tls_creds_load_ca_cert_list(creds,
491                                                  cacertFile, cacerts,
492                                                  MAX_CERTS, &ncacerts,
493                                                  errp) < 0) {
494              goto cleanup;
495          }
496      }
497  
498      if (cert &&
499          qcrypto_tls_creds_check_cert(creds,
500                                       cert, certFile, isServer,
501                                       false, errp) < 0) {
502          goto cleanup;
503      }
504  
505      for (i = 0; i < ncacerts; i++) {
506          if (qcrypto_tls_creds_check_cert(creds,
507                                           cacerts[i], cacertFile,
508                                           isServer, true, errp) < 0) {
509              goto cleanup;
510          }
511      }
512  
513      if (cert && ncacerts &&
514          qcrypto_tls_creds_check_cert_pair(cert, certFile, cacerts,
515                                            ncacerts, cacertFile,
516                                            isServer, errp) < 0) {
517          goto cleanup;
518      }
519  
520      ret = 0;
521  
522   cleanup:
523      if (cert) {
524          gnutls_x509_crt_deinit(cert);
525      }
526      for (i = 0; i < ncacerts; i++) {
527          gnutls_x509_crt_deinit(cacerts[i]);
528      }
529      return ret;
530  }
531  
532  
533  static int
534  qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
535                              Error **errp)
536  {
537      char *cacert = NULL, *cacrl = NULL, *cert = NULL,
538          *key = NULL, *dhparams = NULL;
539      int ret;
540      int rv = -1;
541  
542      trace_qcrypto_tls_creds_x509_load(creds,
543              creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
544  
545      if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
546          if (qcrypto_tls_creds_get_path(&creds->parent_obj,
547                                         QCRYPTO_TLS_CREDS_X509_CA_CERT,
548                                         true, &cacert, errp) < 0 ||
549              qcrypto_tls_creds_get_path(&creds->parent_obj,
550                                         QCRYPTO_TLS_CREDS_X509_CA_CRL,
551                                         false, &cacrl, errp) < 0 ||
552              qcrypto_tls_creds_get_path(&creds->parent_obj,
553                                         QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
554                                         true, &cert, errp) < 0 ||
555              qcrypto_tls_creds_get_path(&creds->parent_obj,
556                                         QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
557                                         true, &key, errp) < 0 ||
558              qcrypto_tls_creds_get_path(&creds->parent_obj,
559                                         QCRYPTO_TLS_CREDS_DH_PARAMS,
560                                         false, &dhparams, errp) < 0) {
561              goto cleanup;
562          }
563      } else {
564          if (qcrypto_tls_creds_get_path(&creds->parent_obj,
565                                         QCRYPTO_TLS_CREDS_X509_CA_CERT,
566                                         true, &cacert, errp) < 0 ||
567              qcrypto_tls_creds_get_path(&creds->parent_obj,
568                                         QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
569                                         false, &cert, errp) < 0 ||
570              qcrypto_tls_creds_get_path(&creds->parent_obj,
571                                         QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
572                                         false, &key, errp) < 0) {
573              goto cleanup;
574          }
575      }
576  
577      if (creds->sanityCheck &&
578          qcrypto_tls_creds_x509_sanity_check(creds,
579              creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
580              cacert, cert, errp) < 0) {
581          goto cleanup;
582      }
583  
584      ret = gnutls_certificate_allocate_credentials(&creds->data);
585      if (ret < 0) {
586          error_setg(errp, "Cannot allocate credentials: '%s'",
587                     gnutls_strerror(ret));
588          goto cleanup;
589      }
590  
591      ret = gnutls_certificate_set_x509_trust_file(creds->data,
592                                                   cacert,
593                                                   GNUTLS_X509_FMT_PEM);
594      if (ret < 0) {
595          error_setg(errp, "Cannot load CA certificate '%s': %s",
596                     cacert, gnutls_strerror(ret));
597          goto cleanup;
598      }
599  
600      if (cert != NULL && key != NULL) {
601          char *password = NULL;
602          if (creds->passwordid) {
603              password = qcrypto_secret_lookup_as_utf8(creds->passwordid,
604                                                       errp);
605              if (!password) {
606                  goto cleanup;
607              }
608          }
609          ret = gnutls_certificate_set_x509_key_file2(creds->data,
610                                                      cert, key,
611                                                      GNUTLS_X509_FMT_PEM,
612                                                      password,
613                                                      0);
614          g_free(password);
615          if (ret < 0) {
616              error_setg(errp, "Cannot load certificate '%s' & key '%s': %s",
617                         cert, key, gnutls_strerror(ret));
618              goto cleanup;
619          }
620      }
621  
622      if (cacrl != NULL) {
623          ret = gnutls_certificate_set_x509_crl_file(creds->data,
624                                                     cacrl,
625                                                     GNUTLS_X509_FMT_PEM);
626          if (ret < 0) {
627              error_setg(errp, "Cannot load CRL '%s': %s",
628                         cacrl, gnutls_strerror(ret));
629              goto cleanup;
630          }
631      }
632  
633      if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
634          if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
635                                                   &creds->parent_obj.dh_params,
636                                                   errp) < 0) {
637              goto cleanup;
638          }
639          gnutls_certificate_set_dh_params(creds->data,
640                                           creds->parent_obj.dh_params);
641      }
642  
643      rv = 0;
644   cleanup:
645      g_free(cacert);
646      g_free(cacrl);
647      g_free(cert);
648      g_free(key);
649      g_free(dhparams);
650      return rv;
651  }
652  
653  
654  static void
655  qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds)
656  {
657      if (creds->data) {
658          gnutls_certificate_free_credentials(creds->data);
659          creds->data = NULL;
660      }
661      if (creds->parent_obj.dh_params) {
662          gnutls_dh_params_deinit(creds->parent_obj.dh_params);
663          creds->parent_obj.dh_params = NULL;
664      }
665  }
666  
667  
668  #else /* ! CONFIG_GNUTLS */
669  
670  
671  static void
672  qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED,
673                              Error **errp)
674  {
675      error_setg(errp, "TLS credentials support requires GNUTLS");
676  }
677  
678  
679  static void
680  qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED)
681  {
682      /* nada */
683  }
684  
685  
686  #endif /* ! CONFIG_GNUTLS */
687  
688  
689  static void
690  qcrypto_tls_creds_x509_complete(UserCreatable *uc, Error **errp)
691  {
692      QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(uc);
693  
694      qcrypto_tls_creds_x509_load(creds, errp);
695  }
696  
697  
698  #ifdef CONFIG_GNUTLS
699  
700  
701  static bool
702  qcrypto_tls_creds_x509_prop_get_loaded(Object *obj,
703                                         Error **errp G_GNUC_UNUSED)
704  {
705      QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
706  
707      return creds->data != NULL;
708  }
709  
710  
711  #else /* ! CONFIG_GNUTLS */
712  
713  
714  static bool
715  qcrypto_tls_creds_x509_prop_get_loaded(Object *obj G_GNUC_UNUSED,
716                                         Error **errp G_GNUC_UNUSED)
717  {
718      return false;
719  }
720  
721  
722  #endif /* ! CONFIG_GNUTLS */
723  
724  
725  static void
726  qcrypto_tls_creds_x509_prop_set_sanity(Object *obj,
727                                         bool value,
728                                         Error **errp G_GNUC_UNUSED)
729  {
730      QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
731  
732      creds->sanityCheck = value;
733  }
734  
735  
736  static void
737  qcrypto_tls_creds_x509_prop_set_passwordid(Object *obj,
738                                             const char *value,
739                                             Error **errp G_GNUC_UNUSED)
740  {
741      QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
742  
743      creds->passwordid = g_strdup(value);
744  }
745  
746  
747  static char *
748  qcrypto_tls_creds_x509_prop_get_passwordid(Object *obj,
749                                             Error **errp G_GNUC_UNUSED)
750  {
751      QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
752  
753      return g_strdup(creds->passwordid);
754  }
755  
756  
757  static bool
758  qcrypto_tls_creds_x509_prop_get_sanity(Object *obj,
759                                         Error **errp G_GNUC_UNUSED)
760  {
761      QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
762  
763      return creds->sanityCheck;
764  }
765  
766  
767  #ifdef CONFIG_GNUTLS
768  
769  
770  static bool
771  qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
772  {
773      QCryptoTLSCredsX509 *x509_creds = QCRYPTO_TLS_CREDS_X509(creds);
774      Error *local_err = NULL;
775      gnutls_certificate_credentials_t creds_data = x509_creds->data;
776      gnutls_dh_params_t creds_dh_params = x509_creds->parent_obj.dh_params;
777  
778      x509_creds->data = NULL;
779      x509_creds->parent_obj.dh_params = NULL;
780      qcrypto_tls_creds_x509_load(x509_creds, &local_err);
781      if (local_err) {
782          qcrypto_tls_creds_x509_unload(x509_creds);
783          x509_creds->data = creds_data;
784          x509_creds->parent_obj.dh_params = creds_dh_params;
785          error_propagate(errp, local_err);
786          return false;
787      }
788  
789      if (creds_data) {
790          gnutls_certificate_free_credentials(creds_data);
791      }
792      if (creds_dh_params) {
793          gnutls_dh_params_deinit(creds_dh_params);
794      }
795      return true;
796  }
797  
798  
799  #else /* ! CONFIG_GNUTLS */
800  
801  
802  static bool
803  qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
804  {
805      return false;
806  }
807  
808  
809  #endif /* ! CONFIG_GNUTLS */
810  
811  
812  static void
813  qcrypto_tls_creds_x509_init(Object *obj)
814  {
815      QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
816  
817      creds->sanityCheck = true;
818  }
819  
820  
821  static void
822  qcrypto_tls_creds_x509_finalize(Object *obj)
823  {
824      QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
825  
826      g_free(creds->passwordid);
827      qcrypto_tls_creds_x509_unload(creds);
828  }
829  
830  
831  static void
832  qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data)
833  {
834      UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
835      QCryptoTLSCredsClass *ctcc = QCRYPTO_TLS_CREDS_CLASS(oc);
836  
837      ctcc->reload = qcrypto_tls_creds_x509_reload;
838  
839      ucc->complete = qcrypto_tls_creds_x509_complete;
840  
841      object_class_property_add_bool(oc, "loaded",
842                                     qcrypto_tls_creds_x509_prop_get_loaded,
843                                     NULL);
844      object_class_property_add_bool(oc, "sanity-check",
845                                     qcrypto_tls_creds_x509_prop_get_sanity,
846                                     qcrypto_tls_creds_x509_prop_set_sanity);
847      object_class_property_add_str(oc, "passwordid",
848                                    qcrypto_tls_creds_x509_prop_get_passwordid,
849                                    qcrypto_tls_creds_x509_prop_set_passwordid);
850  }
851  
852  
853  static const TypeInfo qcrypto_tls_creds_x509_info = {
854      .parent = TYPE_QCRYPTO_TLS_CREDS,
855      .name = TYPE_QCRYPTO_TLS_CREDS_X509,
856      .instance_size = sizeof(QCryptoTLSCredsX509),
857      .instance_init = qcrypto_tls_creds_x509_init,
858      .instance_finalize = qcrypto_tls_creds_x509_finalize,
859      .class_size = sizeof(QCryptoTLSCredsX509Class),
860      .class_init = qcrypto_tls_creds_x509_class_init,
861      .interfaces = (InterfaceInfo[]) {
862          { TYPE_USER_CREATABLE },
863          { }
864      }
865  };
866  
867  
868  static void
869  qcrypto_tls_creds_x509_register_types(void)
870  {
871      type_register_static(&qcrypto_tls_creds_x509_info);
872  }
873  
874  
875  type_init(qcrypto_tls_creds_x509_register_types);
876