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