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