master
c 317 lines 8.59 KB
Raw
1 /*
2 * QEMU crypto TLS 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 "qapi/error.h"
23 #include "qapi-types-crypto.h"
24 #include "qemu/module.h"
25 #include "qemu/error-report.h"
26 #include "tlscredspriv.h"
27 #include "trace.h"
28
29 #define DH_BITS 2048
30
31 #ifdef CONFIG_GNUTLS
32 int
33 qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
34 const char *filename,
35 gnutls_dh_params_t *dh_params,
36 Error **errp)
37 {
38 int ret;
39
40 trace_qcrypto_tls_creds_load_dh(creds, filename ? filename : "<generated>");
41
42 if (filename != NULL) {
43 GError *gerr = NULL;
44 gchar *contents;
45 gsize len;
46 gnutls_datum_t data;
47 if (!g_file_get_contents(filename,
48 &contents,
49 &len,
50 &gerr)) {
51
52 error_setg(errp, "%s", gerr->message);
53 g_error_free(gerr);
54 return -1;
55 }
56 warn_report_once("Use of an external DH parameters file '%s' is "
57 "deprecated and will be removed in a future release",
58 filename);
59
60 data.data = (unsigned char *)contents;
61 data.size = len;
62 ret = gnutls_dh_params_init(dh_params);
63 if (ret < 0) {
64 g_free(contents);
65 error_setg(errp, "Unable to initialize DH parameters: %s",
66 gnutls_strerror(ret));
67 return -1;
68 }
69 ret = gnutls_dh_params_import_pkcs3(*dh_params,
70 &data,
71 GNUTLS_X509_FMT_PEM);
72 g_free(contents);
73 if (ret < 0) {
74 gnutls_dh_params_deinit(*dh_params);
75 *dh_params = NULL;
76 error_setg(errp, "Unable to load DH parameters from %s: %s",
77 filename, gnutls_strerror(ret));
78 return -1;
79 }
80 } else {
81 *dh_params = NULL;
82 }
83
84 return 0;
85 }
86
87
88 char *
89 qcrypto_tls_creds_build_path(QCryptoTLSCreds *creds,
90 const char *filename)
91 {
92 return g_strdup_printf("%s/%s", creds->dir, filename);
93 }
94
95
96 int
97 qcrypto_tls_creds_get_path(QCryptoTLSCreds *creds,
98 const char *filename,
99 bool required,
100 char **cred,
101 Error **errp)
102 {
103 int ret = -1;
104
105 *cred = qcrypto_tls_creds_build_path(creds, filename);
106
107 if (access(*cred, R_OK) < 0) {
108 if (errno == ENOENT && !required) {
109 ret = 0;
110 } else {
111 error_setg_errno(errp, errno,
112 "Unable to access credentials %s",
113 *cred);
114 }
115 g_free(*cred);
116 *cred = NULL;
117 goto cleanup;
118 }
119
120 ret = 0;
121 cleanup:
122 trace_qcrypto_tls_creds_get_path(creds, filename,
123 *cred ? *cred : "<none>");
124 return ret;
125 }
126
127
128 #endif /* ! CONFIG_GNUTLS */
129
130
131 static void
132 qcrypto_tls_creds_prop_set_verify(Object *obj,
133 bool value,
134 Error **errp G_GNUC_UNUSED)
135 {
136 QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
137
138 creds->verifyPeer = value;
139 }
140
141
142 static bool
143 qcrypto_tls_creds_prop_get_verify(Object *obj,
144 Error **errp G_GNUC_UNUSED)
145 {
146 QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
147
148 return creds->verifyPeer;
149 }
150
151
152 static void
153 qcrypto_tls_creds_prop_set_dir(Object *obj,
154 const char *value,
155 Error **errp G_GNUC_UNUSED)
156 {
157 QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
158
159 creds->dir = g_strdup(value);
160 }
161
162
163 static char *
164 qcrypto_tls_creds_prop_get_dir(Object *obj,
165 Error **errp G_GNUC_UNUSED)
166 {
167 QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
168
169 return g_strdup(creds->dir);
170 }
171
172
173 static void
174 qcrypto_tls_creds_prop_set_priority(Object *obj,
175 const char *value,
176 Error **errp G_GNUC_UNUSED)
177 {
178 QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
179
180 creds->priority = g_strdup(value);
181 }
182
183
184 static char *
185 qcrypto_tls_creds_prop_get_priority(Object *obj,
186 Error **errp G_GNUC_UNUSED)
187 {
188 QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
189
190 return g_strdup(creds->priority);
191 }
192
193
194 static void
195 qcrypto_tls_creds_prop_set_endpoint(Object *obj,
196 int value,
197 Error **errp G_GNUC_UNUSED)
198 {
199 QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
200
201 creds->endpoint = value;
202 }
203
204
205 static int
206 qcrypto_tls_creds_prop_get_endpoint(Object *obj,
207 Error **errp G_GNUC_UNUSED)
208 {
209 QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
210
211 return creds->endpoint;
212 }
213
214
215 static void
216 qcrypto_tls_creds_class_init(ObjectClass *oc, const void *data)
217 {
218 object_class_property_add_bool(oc, "verify-peer",
219 qcrypto_tls_creds_prop_get_verify,
220 qcrypto_tls_creds_prop_set_verify);
221 object_class_property_add_str(oc, "dir",
222 qcrypto_tls_creds_prop_get_dir,
223 qcrypto_tls_creds_prop_set_dir);
224 object_class_property_add_enum(oc, "endpoint",
225 "QCryptoTLSCredsEndpoint",
226 &QCryptoTLSCredsEndpoint_lookup,
227 qcrypto_tls_creds_prop_get_endpoint,
228 qcrypto_tls_creds_prop_set_endpoint);
229 object_class_property_add_str(oc, "priority",
230 qcrypto_tls_creds_prop_get_priority,
231 qcrypto_tls_creds_prop_set_priority);
232 }
233
234
235 static void
236 qcrypto_tls_creds_init(Object *obj)
237 {
238 QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
239
240 creds->verifyPeer = true;
241 }
242
243
244 static void
245 qcrypto_tls_creds_finalize(Object *obj)
246 {
247 QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
248
249 #ifdef CONFIG_GNUTLS
250 qcrypto_tls_creds_box_unref(creds->box);
251 #endif
252 g_free(creds->dir);
253 g_free(creds->priority);
254 }
255
256 bool qcrypto_tls_creds_check_endpoint(QCryptoTLSCreds *creds,
257 QCryptoTLSCredsEndpoint endpoint,
258 Error **errp)
259 {
260 if (creds->endpoint != endpoint) {
261 error_setg(errp, "Expected TLS credentials for a %s endpoint",
262 QCryptoTLSCredsEndpoint_str(endpoint));
263 return false;
264 }
265 return true;
266 }
267
268
269 char *qcrypto_tls_creds_get_priority(QCryptoTLSCreds *creds)
270 {
271 QCryptoTLSCredsClass *tcc = QCRYPTO_TLS_CREDS_GET_CLASS(creds);
272 const char *priorityBase =
273 creds->priority ? creds->priority : CONFIG_TLS_PRIORITY;
274
275 if (tcc->prioritySuffix) {
276 return g_strdup_printf("%s:%s", priorityBase, tcc->prioritySuffix);
277 } else {
278 return g_strdup(priorityBase);
279 }
280 }
281
282
283 bool qcrypto_tls_creds_reload(QCryptoTLSCreds *creds,
284 Error **errp)
285 {
286 QCryptoTLSCredsClass *credscls = QCRYPTO_TLS_CREDS_GET_CLASS(creds);
287
288 if (credscls->reload) {
289 return credscls->reload(creds, errp);
290 }
291
292 error_setg(errp, "%s does not support reloading credentials",
293 object_get_typename(OBJECT(creds)));
294 return false;
295 }
296
297
298 static const TypeInfo qcrypto_tls_creds_info = {
299 .parent = TYPE_OBJECT,
300 .name = TYPE_QCRYPTO_TLS_CREDS,
301 .instance_size = sizeof(QCryptoTLSCreds),
302 .instance_init = qcrypto_tls_creds_init,
303 .instance_finalize = qcrypto_tls_creds_finalize,
304 .class_init = qcrypto_tls_creds_class_init,
305 .class_size = sizeof(QCryptoTLSCredsClass),
306 .abstract = true,
307 };
308
309
310 static void
311 qcrypto_tls_creds_register_types(void)
312 {
313 type_register_static(&qcrypto_tls_creds_info);
314 }
315
316
317 type_init(qcrypto_tls_creds_register_types);