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