1a090187dSDaniel P. Berrange /*
2a090187dSDaniel P. Berrange * QEMU crypto TLS credential support
3a090187dSDaniel P. Berrange *
4a090187dSDaniel P. Berrange * Copyright (c) 2015 Red Hat, Inc.
5a090187dSDaniel P. Berrange *
6a090187dSDaniel P. Berrange * This library is free software; you can redistribute it and/or
7a090187dSDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public
8a090187dSDaniel 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.
10a090187dSDaniel P. Berrange *
11a090187dSDaniel P. Berrange * This library is distributed in the hope that it will be useful,
12a090187dSDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of
13a090187dSDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14a090187dSDaniel P. Berrange * Lesser General Public License for more details.
15a090187dSDaniel P. Berrange *
16a090187dSDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public
17a090187dSDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18a090187dSDaniel P. Berrange *
19a090187dSDaniel P. Berrange */
20a090187dSDaniel P. Berrange
2142f7a448SPeter Maydell #include "qemu/osdep.h"
22da34e65cSMarkus Armbruster #include "qapi/error.h"
23*e9ac6808SPhilippe Mathieu-Daudé #include "qapi-types-crypto.h"
240b8fa32fSMarkus Armbruster #include "qemu/module.h"
25986bc8deSMichael S. Tsirkin #include "tlscredspriv.h"
26a090187dSDaniel P. Berrange #include "trace.h"
27a090187dSDaniel P. Berrange
28a090187dSDaniel P. Berrange #define DH_BITS 2048
29a090187dSDaniel P. Berrange
30a090187dSDaniel P. Berrange #ifdef CONFIG_GNUTLS
31a090187dSDaniel P. Berrange int
qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds * creds,const char * filename,gnutls_dh_params_t * dh_params,Error ** errp)32a090187dSDaniel P. Berrange qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
33a090187dSDaniel P. Berrange const char *filename,
34a090187dSDaniel P. Berrange gnutls_dh_params_t *dh_params,
35a090187dSDaniel P. Berrange Error **errp)
36a090187dSDaniel P. Berrange {
37a090187dSDaniel P. Berrange int ret;
38a090187dSDaniel P. Berrange
39a090187dSDaniel P. Berrange trace_qcrypto_tls_creds_load_dh(creds, filename ? filename : "<generated>");
40a090187dSDaniel P. Berrange
41a090187dSDaniel P. Berrange if (filename == NULL) {
42a090187dSDaniel P. Berrange ret = gnutls_dh_params_init(dh_params);
43a090187dSDaniel P. Berrange if (ret < 0) {
44a090187dSDaniel P. Berrange error_setg(errp, "Unable to initialize DH parameters: %s",
45a090187dSDaniel P. Berrange gnutls_strerror(ret));
46a090187dSDaniel P. Berrange return -1;
47a090187dSDaniel P. Berrange }
48a090187dSDaniel P. Berrange ret = gnutls_dh_params_generate2(*dh_params, DH_BITS);
49a090187dSDaniel P. Berrange if (ret < 0) {
50a090187dSDaniel P. Berrange gnutls_dh_params_deinit(*dh_params);
51a090187dSDaniel P. Berrange *dh_params = NULL;
52a090187dSDaniel P. Berrange error_setg(errp, "Unable to generate DH parameters: %s",
53a090187dSDaniel P. Berrange gnutls_strerror(ret));
54a090187dSDaniel P. Berrange return -1;
55a090187dSDaniel P. Berrange }
56a090187dSDaniel P. Berrange } else {
57a090187dSDaniel P. Berrange GError *gerr = NULL;
58a090187dSDaniel P. Berrange gchar *contents;
59a090187dSDaniel P. Berrange gsize len;
60a090187dSDaniel P. Berrange gnutls_datum_t data;
61a090187dSDaniel P. Berrange if (!g_file_get_contents(filename,
62a090187dSDaniel P. Berrange &contents,
63a090187dSDaniel P. Berrange &len,
64a090187dSDaniel P. Berrange &gerr)) {
65a090187dSDaniel P. Berrange
66a090187dSDaniel P. Berrange error_setg(errp, "%s", gerr->message);
67a090187dSDaniel P. Berrange g_error_free(gerr);
68a090187dSDaniel P. Berrange return -1;
69a090187dSDaniel P. Berrange }
70a090187dSDaniel P. Berrange data.data = (unsigned char *)contents;
71a090187dSDaniel P. Berrange data.size = len;
72a090187dSDaniel P. Berrange ret = gnutls_dh_params_init(dh_params);
73a090187dSDaniel P. Berrange if (ret < 0) {
74a090187dSDaniel P. Berrange g_free(contents);
75a090187dSDaniel P. Berrange error_setg(errp, "Unable to initialize DH parameters: %s",
76a090187dSDaniel P. Berrange gnutls_strerror(ret));
77a090187dSDaniel P. Berrange return -1;
78a090187dSDaniel P. Berrange }
79a090187dSDaniel P. Berrange ret = gnutls_dh_params_import_pkcs3(*dh_params,
80a090187dSDaniel P. Berrange &data,
81a090187dSDaniel P. Berrange GNUTLS_X509_FMT_PEM);
82a090187dSDaniel P. Berrange g_free(contents);
83a090187dSDaniel P. Berrange if (ret < 0) {
84a090187dSDaniel P. Berrange gnutls_dh_params_deinit(*dh_params);
85a090187dSDaniel P. Berrange *dh_params = NULL;
86a090187dSDaniel P. Berrange error_setg(errp, "Unable to load DH parameters from %s: %s",
87a090187dSDaniel P. Berrange filename, gnutls_strerror(ret));
88a090187dSDaniel P. Berrange return -1;
89a090187dSDaniel P. Berrange }
90a090187dSDaniel P. Berrange }
91a090187dSDaniel P. Berrange
92a090187dSDaniel P. Berrange return 0;
93a090187dSDaniel P. Berrange }
94a090187dSDaniel P. Berrange
95a090187dSDaniel P. Berrange
96a090187dSDaniel P. Berrange int
qcrypto_tls_creds_get_path(QCryptoTLSCreds * creds,const char * filename,bool required,char ** cred,Error ** errp)97a090187dSDaniel P. Berrange qcrypto_tls_creds_get_path(QCryptoTLSCreds *creds,
98a090187dSDaniel P. Berrange const char *filename,
99a090187dSDaniel P. Berrange bool required,
100a090187dSDaniel P. Berrange char **cred,
101a090187dSDaniel P. Berrange Error **errp)
102a090187dSDaniel P. Berrange {
103a090187dSDaniel P. Berrange struct stat sb;
104a090187dSDaniel P. Berrange int ret = -1;
105a090187dSDaniel P. Berrange
106a090187dSDaniel P. Berrange if (!creds->dir) {
107a090187dSDaniel P. Berrange if (required) {
108a090187dSDaniel P. Berrange error_setg(errp, "Missing 'dir' property value");
109a090187dSDaniel P. Berrange return -1;
110a090187dSDaniel P. Berrange } else {
111a090187dSDaniel P. Berrange return 0;
112a090187dSDaniel P. Berrange }
113a090187dSDaniel P. Berrange }
114a090187dSDaniel P. Berrange
115a090187dSDaniel P. Berrange *cred = g_strdup_printf("%s/%s", creds->dir, filename);
116a090187dSDaniel P. Berrange
117a090187dSDaniel P. Berrange if (stat(*cred, &sb) < 0) {
118a090187dSDaniel P. Berrange if (errno == ENOENT && !required) {
119a090187dSDaniel P. Berrange ret = 0;
120a090187dSDaniel P. Berrange } else {
121a090187dSDaniel P. Berrange error_setg_errno(errp, errno,
122a090187dSDaniel P. Berrange "Unable to access credentials %s",
123a090187dSDaniel P. Berrange *cred);
124a090187dSDaniel P. Berrange }
125a090187dSDaniel P. Berrange g_free(*cred);
126a090187dSDaniel P. Berrange *cred = NULL;
127a090187dSDaniel P. Berrange goto cleanup;
128a090187dSDaniel P. Berrange }
129a090187dSDaniel P. Berrange
130a090187dSDaniel P. Berrange ret = 0;
131a090187dSDaniel P. Berrange cleanup:
1320e1d0245SDaniel P. Berrange trace_qcrypto_tls_creds_get_path(creds, filename,
1330e1d0245SDaniel P. Berrange *cred ? *cred : "<none>");
134a090187dSDaniel P. Berrange return ret;
135a090187dSDaniel P. Berrange }
136a090187dSDaniel P. Berrange
137a090187dSDaniel P. Berrange
138a090187dSDaniel P. Berrange #endif /* ! CONFIG_GNUTLS */
139a090187dSDaniel P. Berrange
140a090187dSDaniel P. Berrange
141a090187dSDaniel P. Berrange static void
qcrypto_tls_creds_prop_set_verify(Object * obj,bool value,Error ** errp G_GNUC_UNUSED)142a090187dSDaniel P. Berrange qcrypto_tls_creds_prop_set_verify(Object *obj,
143a090187dSDaniel P. Berrange bool value,
144a090187dSDaniel P. Berrange Error **errp G_GNUC_UNUSED)
145a090187dSDaniel P. Berrange {
146a090187dSDaniel P. Berrange QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
147a090187dSDaniel P. Berrange
148a090187dSDaniel P. Berrange creds->verifyPeer = value;
149a090187dSDaniel P. Berrange }
150a090187dSDaniel P. Berrange
151a090187dSDaniel P. Berrange
152a090187dSDaniel P. Berrange static bool
qcrypto_tls_creds_prop_get_verify(Object * obj,Error ** errp G_GNUC_UNUSED)153a090187dSDaniel P. Berrange qcrypto_tls_creds_prop_get_verify(Object *obj,
154a090187dSDaniel P. Berrange Error **errp G_GNUC_UNUSED)
155a090187dSDaniel P. Berrange {
156a090187dSDaniel P. Berrange QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
157a090187dSDaniel P. Berrange
158a090187dSDaniel P. Berrange return creds->verifyPeer;
159a090187dSDaniel P. Berrange }
160a090187dSDaniel P. Berrange
161a090187dSDaniel P. Berrange
162a090187dSDaniel P. Berrange static void
qcrypto_tls_creds_prop_set_dir(Object * obj,const char * value,Error ** errp G_GNUC_UNUSED)163a090187dSDaniel P. Berrange qcrypto_tls_creds_prop_set_dir(Object *obj,
164a090187dSDaniel P. Berrange const char *value,
165a090187dSDaniel P. Berrange Error **errp G_GNUC_UNUSED)
166a090187dSDaniel P. Berrange {
167a090187dSDaniel P. Berrange QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
168a090187dSDaniel P. Berrange
169a090187dSDaniel P. Berrange creds->dir = g_strdup(value);
170a090187dSDaniel P. Berrange }
171a090187dSDaniel P. Berrange
172a090187dSDaniel P. Berrange
173a090187dSDaniel P. Berrange static char *
qcrypto_tls_creds_prop_get_dir(Object * obj,Error ** errp G_GNUC_UNUSED)174a090187dSDaniel P. Berrange qcrypto_tls_creds_prop_get_dir(Object *obj,
175a090187dSDaniel P. Berrange Error **errp G_GNUC_UNUSED)
176a090187dSDaniel P. Berrange {
177a090187dSDaniel P. Berrange QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
178a090187dSDaniel P. Berrange
179a090187dSDaniel P. Berrange return g_strdup(creds->dir);
180a090187dSDaniel P. Berrange }
181a090187dSDaniel P. Berrange
182a090187dSDaniel P. Berrange
183a090187dSDaniel P. Berrange static void
qcrypto_tls_creds_prop_set_priority(Object * obj,const char * value,Error ** errp G_GNUC_UNUSED)18413f12430SDaniel P. Berrange qcrypto_tls_creds_prop_set_priority(Object *obj,
18513f12430SDaniel P. Berrange const char *value,
18613f12430SDaniel P. Berrange Error **errp G_GNUC_UNUSED)
18713f12430SDaniel P. Berrange {
18813f12430SDaniel P. Berrange QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
18913f12430SDaniel P. Berrange
19013f12430SDaniel P. Berrange creds->priority = g_strdup(value);
19113f12430SDaniel P. Berrange }
19213f12430SDaniel P. Berrange
19313f12430SDaniel P. Berrange
19413f12430SDaniel P. Berrange static char *
qcrypto_tls_creds_prop_get_priority(Object * obj,Error ** errp G_GNUC_UNUSED)19513f12430SDaniel P. Berrange qcrypto_tls_creds_prop_get_priority(Object *obj,
19613f12430SDaniel P. Berrange Error **errp G_GNUC_UNUSED)
19713f12430SDaniel P. Berrange {
19813f12430SDaniel P. Berrange QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
19913f12430SDaniel P. Berrange
20013f12430SDaniel P. Berrange return g_strdup(creds->priority);
20113f12430SDaniel P. Berrange }
20213f12430SDaniel P. Berrange
20313f12430SDaniel P. Berrange
20413f12430SDaniel P. Berrange static void
qcrypto_tls_creds_prop_set_endpoint(Object * obj,int value,Error ** errp G_GNUC_UNUSED)205a090187dSDaniel P. Berrange qcrypto_tls_creds_prop_set_endpoint(Object *obj,
206a090187dSDaniel P. Berrange int value,
207a090187dSDaniel P. Berrange Error **errp G_GNUC_UNUSED)
208a090187dSDaniel P. Berrange {
209a090187dSDaniel P. Berrange QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
210a090187dSDaniel P. Berrange
211a090187dSDaniel P. Berrange creds->endpoint = value;
212a090187dSDaniel P. Berrange }
213a090187dSDaniel P. Berrange
214a090187dSDaniel P. Berrange
215a090187dSDaniel P. Berrange static int
qcrypto_tls_creds_prop_get_endpoint(Object * obj,Error ** errp G_GNUC_UNUSED)216a090187dSDaniel P. Berrange qcrypto_tls_creds_prop_get_endpoint(Object *obj,
217a090187dSDaniel P. Berrange Error **errp G_GNUC_UNUSED)
218a090187dSDaniel P. Berrange {
219a090187dSDaniel P. Berrange QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
220a090187dSDaniel P. Berrange
221a090187dSDaniel P. Berrange return creds->endpoint;
222a090187dSDaniel P. Berrange }
223a090187dSDaniel P. Berrange
224a090187dSDaniel P. Berrange
225a090187dSDaniel P. Berrange static void
qcrypto_tls_creds_class_init(ObjectClass * oc,void * data)2269884abeeSDaniel P. Berrange qcrypto_tls_creds_class_init(ObjectClass *oc, void *data)
227a090187dSDaniel P. Berrange {
2289884abeeSDaniel P. Berrange object_class_property_add_bool(oc, "verify-peer",
229a090187dSDaniel P. Berrange qcrypto_tls_creds_prop_get_verify,
230d2623129SMarkus Armbruster qcrypto_tls_creds_prop_set_verify);
2319884abeeSDaniel P. Berrange object_class_property_add_str(oc, "dir",
232a090187dSDaniel P. Berrange qcrypto_tls_creds_prop_get_dir,
233d2623129SMarkus Armbruster qcrypto_tls_creds_prop_set_dir);
2349884abeeSDaniel P. Berrange object_class_property_add_enum(oc, "endpoint",
235a090187dSDaniel P. Berrange "QCryptoTLSCredsEndpoint",
236f7abe0ecSMarc-André Lureau &QCryptoTLSCredsEndpoint_lookup,
237a090187dSDaniel P. Berrange qcrypto_tls_creds_prop_get_endpoint,
238d2623129SMarkus Armbruster qcrypto_tls_creds_prop_set_endpoint);
23913f12430SDaniel P. Berrange object_class_property_add_str(oc, "priority",
24013f12430SDaniel P. Berrange qcrypto_tls_creds_prop_get_priority,
241d2623129SMarkus Armbruster qcrypto_tls_creds_prop_set_priority);
242a090187dSDaniel P. Berrange }
243a090187dSDaniel P. Berrange
244a090187dSDaniel P. Berrange
245a090187dSDaniel P. Berrange static void
qcrypto_tls_creds_init(Object * obj)2469884abeeSDaniel P. Berrange qcrypto_tls_creds_init(Object *obj)
2479884abeeSDaniel P. Berrange {
2489884abeeSDaniel P. Berrange QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
2499884abeeSDaniel P. Berrange
2509884abeeSDaniel P. Berrange creds->verifyPeer = true;
2519884abeeSDaniel P. Berrange }
2529884abeeSDaniel P. Berrange
2539884abeeSDaniel P. Berrange
2549884abeeSDaniel P. Berrange static void
qcrypto_tls_creds_finalize(Object * obj)255a090187dSDaniel P. Berrange qcrypto_tls_creds_finalize(Object *obj)
256a090187dSDaniel P. Berrange {
257a090187dSDaniel P. Berrange QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
258a090187dSDaniel P. Berrange
259a090187dSDaniel P. Berrange g_free(creds->dir);
26013f12430SDaniel P. Berrange g_free(creds->priority);
261a090187dSDaniel P. Berrange }
262a090187dSDaniel P. Berrange
qcrypto_tls_creds_check_endpoint(QCryptoTLSCreds * creds,QCryptoTLSCredsEndpoint endpoint,Error ** errp)263*e9ac6808SPhilippe Mathieu-Daudé bool qcrypto_tls_creds_check_endpoint(QCryptoTLSCreds *creds,
264*e9ac6808SPhilippe Mathieu-Daudé QCryptoTLSCredsEndpoint endpoint,
265*e9ac6808SPhilippe Mathieu-Daudé Error **errp)
266*e9ac6808SPhilippe Mathieu-Daudé {
267*e9ac6808SPhilippe Mathieu-Daudé if (creds->endpoint != endpoint) {
268*e9ac6808SPhilippe Mathieu-Daudé error_setg(errp, "Expected TLS credentials for a %s endpoint",
269*e9ac6808SPhilippe Mathieu-Daudé QCryptoTLSCredsEndpoint_str(endpoint));
270*e9ac6808SPhilippe Mathieu-Daudé return false;
271*e9ac6808SPhilippe Mathieu-Daudé }
272*e9ac6808SPhilippe Mathieu-Daudé return true;
273*e9ac6808SPhilippe Mathieu-Daudé }
274a090187dSDaniel P. Berrange
275a090187dSDaniel P. Berrange static const TypeInfo qcrypto_tls_creds_info = {
276a090187dSDaniel P. Berrange .parent = TYPE_OBJECT,
277a090187dSDaniel P. Berrange .name = TYPE_QCRYPTO_TLS_CREDS,
278a090187dSDaniel P. Berrange .instance_size = sizeof(QCryptoTLSCreds),
279a090187dSDaniel P. Berrange .instance_init = qcrypto_tls_creds_init,
280a090187dSDaniel P. Berrange .instance_finalize = qcrypto_tls_creds_finalize,
2819884abeeSDaniel P. Berrange .class_init = qcrypto_tls_creds_class_init,
282a090187dSDaniel P. Berrange .class_size = sizeof(QCryptoTLSCredsClass),
283a090187dSDaniel P. Berrange .abstract = true,
284a090187dSDaniel P. Berrange };
285a090187dSDaniel P. Berrange
286a090187dSDaniel P. Berrange
287a090187dSDaniel P. Berrange static void
qcrypto_tls_creds_register_types(void)288a090187dSDaniel P. Berrange qcrypto_tls_creds_register_types(void)
289a090187dSDaniel P. Berrange {
290a090187dSDaniel P. Berrange type_register_static(&qcrypto_tls_creds_info);
291a090187dSDaniel P. Berrange }
292a090187dSDaniel P. Berrange
293a090187dSDaniel P. Berrange
294a090187dSDaniel P. Berrange type_init(qcrypto_tls_creds_register_types);
295