gnutls: retry handshake if it returns a non-fatal error
[vlc.git] / modules / misc / gnutls.c
blobe4702809bcfc23bc5bfd1b3a5ec6d0ab0973220e
1 /*****************************************************************************
2 * gnutls.c
3 *****************************************************************************
4 * Copyright (C) 2004-2012 Rémi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Öesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 /*****************************************************************************
22 * Preamble
23 *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include <time.h>
30 #include <errno.h>
31 #include <assert.h>
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_tls.h>
36 #include <vlc_block.h>
37 #include <vlc_dialog.h>
39 #include <gnutls/gnutls.h>
40 #include <gnutls/x509.h>
41 #if (GNUTLS_VERSION_NUMBER < 0x030014)
42 # define gnutls_certificate_set_x509_system_trust(c) \
43 (c, GNUTLS_E_UNIMPLEMENTED_FEATURE)
44 #endif
45 #if (GNUTLS_VERSION_NUMBER < 0x03000D)
46 # define gnutls_verify_stored_pubkey(db,tdb,host,serv,ctype,cert,fl) \
47 (db, host, serv, ctype, cert, fl, GNUTLS_E_NO_CERTIFICATE_FOUND)
48 # define gnutls_store_pubkey(db,tdb,host,serv,ctype,cert,e,fl) \
49 (db, host, serv, ctype, cert, fl, GNUTLS_E_UNIMPLEMENTED_FEATURE)
50 #endif
51 #include "dhparams.h"
53 /*****************************************************************************
54 * Module descriptor
55 *****************************************************************************/
56 static int OpenClient (vlc_tls_creds_t *);
57 static void CloseClient (vlc_tls_creds_t *);
58 static int OpenServer (vlc_tls_creds_t *, const char *, const char *);
59 static void CloseServer (vlc_tls_creds_t *);
61 #define PRIORITIES_TEXT N_("TLS cipher priorities")
62 #define PRIORITIES_LONGTEXT N_("Ciphers, key exchange methods, " \
63 "hash functions and compression methods can be selected. " \
64 "Refer to GNU TLS documentation for detailed syntax.")
65 static const char *const priorities_values[] = {
66 "PERFORMANCE",
67 "NORMAL",
68 "SECURE128",
69 "SECURE256",
70 "EXPORT",
72 static const char *const priorities_text[] = {
73 N_("Performance (prioritize faster ciphers)"),
74 N_("Normal"),
75 N_("Secure 128-bits (exclude 256-bits ciphers)"),
76 N_("Secure 256-bits (prioritize 256-bits ciphers)"),
77 N_("Export (include insecure ciphers)"),
80 vlc_module_begin ()
81 set_shortname( "GNU TLS" )
82 set_description( N_("GNU TLS transport layer security") )
83 set_capability( "tls client", 1 )
84 set_callbacks( OpenClient, CloseClient )
85 set_category( CAT_ADVANCED )
86 set_subcategory( SUBCAT_ADVANCED_NETWORK )
88 add_submodule ()
89 set_description( N_("GNU TLS server") )
90 set_capability( "tls server", 1 )
91 set_category( CAT_ADVANCED )
92 set_subcategory( SUBCAT_ADVANCED_NETWORK )
93 set_callbacks( OpenServer, CloseServer )
95 add_string ("gnutls-priorities", "NORMAL", PRIORITIES_TEXT,
96 PRIORITIES_LONGTEXT, false)
97 change_string_list (priorities_values, priorities_text)
98 vlc_module_end ()
100 static vlc_mutex_t gnutls_mutex = VLC_STATIC_MUTEX;
103 * Initializes GnuTLS with proper locking.
104 * @return VLC_SUCCESS on success, a VLC error code otherwise.
106 static int gnutls_Init (vlc_object_t *p_this)
108 int ret = VLC_EGENERIC;
110 vlc_mutex_lock (&gnutls_mutex);
111 if (gnutls_global_init ())
113 msg_Err (p_this, "cannot initialize GnuTLS");
114 goto error;
117 const char *psz_version = gnutls_check_version ("2.6.6");
118 if (psz_version == NULL)
120 msg_Err (p_this, "unsupported GnuTLS version");
121 gnutls_global_deinit ();
122 goto error;
125 msg_Dbg (p_this, "GnuTLS v%s initialized", psz_version);
126 ret = VLC_SUCCESS;
128 error:
129 vlc_mutex_unlock (&gnutls_mutex);
130 return ret;
135 * Deinitializes GnuTLS.
137 static void gnutls_Deinit (vlc_object_t *p_this)
139 vlc_mutex_lock (&gnutls_mutex);
141 gnutls_global_deinit ();
142 msg_Dbg (p_this, "GnuTLS deinitialized");
143 vlc_mutex_unlock (&gnutls_mutex);
147 static int gnutls_Error (vlc_object_t *obj, int val)
149 switch (val)
151 case GNUTLS_E_AGAIN:
152 #ifdef WIN32
153 WSASetLastError (WSAEWOULDBLOCK);
154 #else
155 errno = EAGAIN;
156 #endif
157 break;
159 case GNUTLS_E_INTERRUPTED:
160 #ifdef WIN32
161 WSASetLastError (WSAEINTR);
162 #else
163 errno = EINTR;
164 #endif
165 break;
167 default:
168 msg_Err (obj, "%s", gnutls_strerror (val));
169 #ifndef NDEBUG
170 if (!gnutls_error_is_fatal (val))
171 msg_Err (obj, "Error above should be handled");
172 #endif
173 #ifdef WIN32
174 WSASetLastError (WSAECONNRESET);
175 #else
176 errno = ECONNRESET;
177 #endif
179 return -1;
181 #define gnutls_Error(o, val) gnutls_Error(VLC_OBJECT(o), val)
183 struct vlc_tls_sys
185 gnutls_session_t session;
186 bool handshaked;
191 * Sends data through a TLS session.
193 static int gnutls_Send (void *opaque, const void *buf, size_t length)
195 vlc_tls_t *session = opaque;
196 vlc_tls_sys_t *sys = session->sys;
198 int val = gnutls_record_send (sys->session, buf, length);
199 return (val < 0) ? gnutls_Error (session, val) : val;
204 * Receives data through a TLS session.
206 static int gnutls_Recv (void *opaque, void *buf, size_t length)
208 vlc_tls_t *session = opaque;
209 vlc_tls_sys_t *sys = session->sys;
211 int val = gnutls_record_recv (sys->session, buf, length);
212 return (val < 0) ? gnutls_Error (session, val) : val;
217 * Starts or continues the TLS handshake.
219 * @return -1 on fatal error, 0 on successful handshake completion,
220 * 1 if more would-be blocking recv is needed,
221 * 2 if more would-be blocking send is required.
223 static int gnutls_ContinueHandshake (vlc_tls_t *session, const char *host,
224 const char *service)
226 vlc_tls_sys_t *sys = session->sys;
227 int val;
229 #ifdef WIN32
230 WSASetLastError (0);
231 #endif
234 val = gnutls_handshake (sys->session);
235 msg_Dbg (session, "TLS handshake: %s", gnutls_strerror (val));
237 if ((val == GNUTLS_E_AGAIN) || (val == GNUTLS_E_INTERRUPTED))
238 /* I/O event: return to caller's poll() loop */
239 return 1 + gnutls_record_get_direction (sys->session);
241 while (val < 0 && !gnutls_error_is_fatal (val));
243 if (val < 0)
245 #ifdef WIN32
246 msg_Dbg (session, "Winsock error %d", WSAGetLastError ());
247 #endif
248 msg_Err (session, "TLS handshake error: %s", gnutls_strerror (val));
249 return -1;
252 sys->handshaked = true;
253 (void) host; (void) service;
254 return 0;
259 * Looks up certificate in known hosts data base.
260 * @return 0 on success, -1 on failure.
262 static int gnutls_CertSearch (vlc_tls_t *obj, const char *host,
263 const char *service,
264 const gnutls_datum_t *restrict datum)
266 assert (host != NULL);
268 /* Look up mismatching certificate in store */
269 int val = gnutls_verify_stored_pubkey (NULL, NULL, host, service,
270 GNUTLS_CRT_X509, datum, 0);
271 const char *msg;
272 switch (val)
274 case 0:
275 msg_Dbg (obj, "certificate key match for %s", host);
276 return 0;
277 case GNUTLS_E_NO_CERTIFICATE_FOUND:
278 msg_Dbg (obj, "no known certificates for %s", host);
279 msg = N_("You attempted to reach %s. "
280 "However the security certificate presented by the server "
281 "is unknown and could not be authenticated by any trusted "
282 "Certification Authority. "
283 "This problem may be caused by a configuration error "
284 "or an attempt to breach your security or your privacy.\n\n"
285 "If in doubt, abort now.\n");
286 break;
287 case GNUTLS_E_CERTIFICATE_KEY_MISMATCH:
288 msg_Dbg (obj, "certificate keys mismatch for %s", host);
289 msg = N_("You attempted to reach %s. "
290 "However the security certificate presented by the server "
291 "changed since the previous visit "
292 "and was not authenticated by any trusted "
293 "Certification Authority. "
294 "This problem may be caused by a configuration error "
295 "or an attempt to breach your security or your privacy.\n\n"
296 "If in doubt, abort now.\n");
297 break;
298 default:
299 msg_Err (obj, "certificate key match error for %s: %s", host,
300 gnutls_strerror (val));
301 return -1;
304 if (dialog_Question (obj, _("Insecure site"), vlc_gettext (msg),
305 _("Abort"), _("View certificate"), NULL, host) != 2)
306 return -1;
308 gnutls_x509_crt_t cert;
309 gnutls_datum_t desc;
311 if (gnutls_x509_crt_init (&cert))
312 return -1;
313 if (gnutls_x509_crt_import (cert, datum, GNUTLS_X509_FMT_DER)
314 || gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_ONELINE, &desc))
316 gnutls_x509_crt_deinit (cert);
317 return -1;
319 gnutls_x509_crt_deinit (cert);
321 val = dialog_Question (obj, _("Insecure site"),
322 _("This is the certificate presented by %s:\n%s\n\n"
323 "If in doubt, abort now.\n"),
324 _("Abort"), _("Accept 24 hours"),
325 _("Accept permanently"), host, desc.data);
326 gnutls_free (desc.data);
328 time_t expiry = 0;
329 switch (val)
331 case 2:
332 time (&expiry);
333 expiry += 24 * 60 * 60;
334 case 3:
335 val = gnutls_store_pubkey (NULL, NULL, host, service,
336 GNUTLS_CRT_X509, datum, expiry, 0);
337 if (val)
338 msg_Err (obj, "cannot store X.509 certificate: %s",
339 gnutls_strerror (val));
340 return 0;
342 return -1;
346 static struct
348 int flag;
349 const char msg[43];
350 bool strict;
351 } cert_errs[] =
353 { GNUTLS_CERT_INVALID,
354 "Certificate could not be verified", false },
355 { GNUTLS_CERT_REVOKED,
356 "Certificate was revoked", true },
357 { GNUTLS_CERT_SIGNER_NOT_FOUND,
358 "Certificate's signer was not found", false },
359 { GNUTLS_CERT_SIGNER_NOT_CA,
360 "Certificate's signer is not a CA", true },
361 { GNUTLS_CERT_INSECURE_ALGORITHM,
362 "Insecure certificate signature algorithm", true },
363 { GNUTLS_CERT_NOT_ACTIVATED,
364 "Certificate is not yet activated", true },
365 { GNUTLS_CERT_EXPIRED,
366 "Certificate has expired", true },
370 static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host,
371 const char *service)
373 vlc_tls_sys_t *sys = session->sys;
375 int val = gnutls_ContinueHandshake (session, host, service);
376 if (val)
377 return val;
379 /* certificates chain verification */
380 unsigned status;
382 val = gnutls_certificate_verify_peers2 (sys->session, &status);
383 if (val)
385 msg_Err (session, "Certificate verification error: %s",
386 gnutls_strerror (val));
387 return -1;
390 if (status)
392 msg_Err (session, "Certificate verification failure:");
393 for (size_t i = 0; i < sizeof (cert_errs) / sizeof (cert_errs[0]); i++)
394 if (status & cert_errs[i].flag)
396 msg_Err (session, " * %s", cert_errs[i].msg);
397 status &= ~cert_errs[i].flag;
398 if (cert_errs[i].strict)
399 val = -1;
402 if (status)
404 msg_Err (session, " * Unknown verification error 0x%04X", status);
405 val = -1;
407 status = -1;
410 /* certificate (host)name verification */
411 const gnutls_datum_t *data;
412 unsigned count;
413 data = gnutls_certificate_get_peers (sys->session, &count);
414 if (data == NULL || count == 0)
416 msg_Err (session, "Peer certificate not available");
417 return -1;
419 msg_Dbg (session, "%u certificate(s) in the list", count);
421 if (val || host == NULL)
422 return val;
423 if (status && gnutls_CertSearch (session, host, service, data))
424 return -1;
426 gnutls_x509_crt_t cert;
427 val = gnutls_x509_crt_init (&cert);
428 if (val)
430 msg_Err (session, "X.509 fatal error: %s", gnutls_strerror (val));
431 return -1;
434 val = gnutls_x509_crt_import (cert, data, GNUTLS_X509_FMT_DER);
435 if (val)
437 msg_Err (session, "Certificate import error: %s",
438 gnutls_strerror (val));
439 goto error;
442 val = !gnutls_x509_crt_check_hostname (cert, host);
443 if (val)
445 msg_Err (session, "Certificate does not match \"%s\"", host);
446 val = gnutls_CertSearch (session, host, service, data);
448 error:
449 gnutls_x509_crt_init (&cert);
450 return val ? -1 : 0;
453 static int
454 gnutls_SessionPrioritize (vlc_object_t *obj, gnutls_session_t session)
456 char *priorities = var_InheritString (obj, "gnutls-priorities");
457 if (unlikely(priorities == NULL))
458 return VLC_ENOMEM;
460 const char *errp;
461 int val = gnutls_priority_set_direct (session, priorities, &errp);
462 if (val < 0)
464 msg_Err (obj, "cannot set TLS priorities \"%s\": %s", errp,
465 gnutls_strerror (val));
466 val = VLC_EGENERIC;
468 else
469 val = VLC_SUCCESS;
470 free (priorities);
471 return val;
476 * TLS credentials private data
478 struct vlc_tls_creds_sys
480 gnutls_certificate_credentials_t x509_cred;
481 gnutls_dh_params_t dh_params; /* XXX: used for server only */
482 int (*handshake) (vlc_tls_t *, const char *, const char *);
483 /* ^^ XXX: useful for server only */
488 * Terminates TLS session and releases session data.
489 * You still have to close the socket yourself.
491 static void gnutls_SessionClose (vlc_tls_creds_t *crd, vlc_tls_t *session)
493 vlc_tls_sys_t *sys = session->sys;
495 if (sys->handshaked)
496 gnutls_bye (sys->session, GNUTLS_SHUT_WR);
497 gnutls_deinit (sys->session);
499 free (sys);
500 (void) crd;
505 * Initializes a server-side TLS session.
507 static int gnutls_SessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *session,
508 int type, int fd)
510 vlc_tls_sys_t *sys = malloc (sizeof (*session->sys));
511 if (unlikely(sys == NULL))
512 return VLC_ENOMEM;
514 session->sys = sys;
515 session->sock.p_sys = session;
516 session->sock.pf_send = gnutls_Send;
517 session->sock.pf_recv = gnutls_Recv;
518 session->handshake = crd->sys->handshake;
519 sys->handshaked = false;
521 int val = gnutls_init (&sys->session, type);
522 if (val != 0)
524 msg_Err (session, "cannot initialize TLS session: %s",
525 gnutls_strerror (val));
526 free (sys);
527 return VLC_EGENERIC;
530 if (gnutls_SessionPrioritize (VLC_OBJECT (crd), sys->session))
531 goto error;
533 val = gnutls_credentials_set (sys->session, GNUTLS_CRD_CERTIFICATE,
534 crd->sys->x509_cred);
535 if (val < 0)
537 msg_Err (session, "cannot set TLS session credentials: %s",
538 gnutls_strerror (val));
539 goto error;
542 gnutls_transport_set_ptr (sys->session,
543 (gnutls_transport_ptr_t)(intptr_t)fd);
544 return VLC_SUCCESS;
546 error:
547 gnutls_SessionClose (crd, session);
548 return VLC_EGENERIC;
551 static int gnutls_ServerSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *session,
552 int fd, const char *hostname)
554 int val = gnutls_SessionOpen (crd, session, GNUTLS_SERVER, fd);
555 if (val != VLC_SUCCESS)
556 return val;
558 if (session->handshake == gnutls_HandshakeAndValidate)
559 gnutls_certificate_server_set_request (session->sys->session,
560 GNUTLS_CERT_REQUIRE);
561 assert (hostname == NULL);
562 return VLC_SUCCESS;
565 static int gnutls_ClientSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *session,
566 int fd, const char *hostname)
568 int val = gnutls_SessionOpen (crd, session, GNUTLS_CLIENT, fd);
569 if (val != VLC_SUCCESS)
570 return val;
572 vlc_tls_sys_t *sys = session->sys;
574 /* minimum DH prime bits */
575 gnutls_dh_set_prime_bits (sys->session, 1024);
577 if (likely(hostname != NULL))
578 /* fill Server Name Indication */
579 gnutls_server_name_set (sys->session, GNUTLS_NAME_DNS,
580 hostname, strlen (hostname));
582 return VLC_SUCCESS;
587 * Adds one or more Certificate Authorities to the trusted set.
589 * @param path (UTF-8) path to an X.509 certificates list.
591 * @return -1 on error, 0 on success.
593 static int gnutls_AddCA (vlc_tls_creds_t *crd, const char *path)
595 block_t *block = block_FilePath (path);
596 if (block == NULL)
598 msg_Err (crd, "cannot read trusted CA from %s: %m", path);
599 return VLC_EGENERIC;
602 gnutls_datum_t d = {
603 .data = block->p_buffer,
604 .size = block->i_buffer,
607 int val = gnutls_certificate_set_x509_trust_mem (crd->sys->x509_cred, &d,
608 GNUTLS_X509_FMT_PEM);
609 block_Release (block);
610 if (val < 0)
612 msg_Err (crd, "cannot load trusted CA from %s: %s", path,
613 gnutls_strerror (val));
614 return VLC_EGENERIC;
616 msg_Dbg (crd, " %d trusted CA%s added from %s", val, (val != 1) ? "s" : "",
617 path);
619 /* enables peer's certificate verification */
620 crd->sys->handshake = gnutls_HandshakeAndValidate;
621 return VLC_SUCCESS;
626 * Adds a Certificates Revocation List to be sent to TLS clients.
628 * @param path (UTF-8) path of the CRL file.
630 * @return -1 on error, 0 on success.
632 static int gnutls_AddCRL (vlc_tls_creds_t *crd, const char *path)
634 block_t *block = block_FilePath (path);
635 if (block == NULL)
637 msg_Err (crd, "cannot read CRL from %s: %m", path);
638 return VLC_EGENERIC;
641 gnutls_datum_t d = {
642 .data = block->p_buffer,
643 .size = block->i_buffer,
646 int val = gnutls_certificate_set_x509_crl_mem (crd->sys->x509_cred, &d,
647 GNUTLS_X509_FMT_PEM);
648 block_Release (block);
649 if (val < 0)
651 msg_Err (crd, "cannot add CRL (%s): %s", path, gnutls_strerror (val));
652 return VLC_EGENERIC;
654 msg_Dbg (crd, "%d CRL%s added from %s", val, (val != 1) ? "s" : "", path);
655 return VLC_SUCCESS;
660 * Allocates a whole server's TLS credentials.
662 static int OpenServer (vlc_tls_creds_t *crd, const char *cert, const char *key)
664 int val;
666 if (gnutls_Init (VLC_OBJECT(crd)))
667 return VLC_EGENERIC;
669 vlc_tls_creds_sys_t *sys = malloc (sizeof (*sys));
670 if (unlikely(sys == NULL))
671 goto error;
673 crd->sys = sys;
674 crd->add_CA = gnutls_AddCA;
675 crd->add_CRL = gnutls_AddCRL;
676 crd->open = gnutls_ServerSessionOpen;
677 crd->close = gnutls_SessionClose;
678 /* No certificate validation by default */
679 sys->handshake = gnutls_ContinueHandshake;
681 /* Sets server's credentials */
682 val = gnutls_certificate_allocate_credentials (&sys->x509_cred);
683 if (val != 0)
685 msg_Err (crd, "cannot allocate credentials: %s",
686 gnutls_strerror (val));
687 goto error;
690 block_t *certblock = block_FilePath (cert);
691 if (certblock == NULL)
693 msg_Err (crd, "cannot read certificate chain from %s: %m", cert);
694 return VLC_EGENERIC;
697 block_t *keyblock = block_FilePath (key);
698 if (keyblock == NULL)
700 msg_Err (crd, "cannot read private key from %s: %m", key);
701 block_Release (certblock);
702 return VLC_EGENERIC;
705 gnutls_datum_t pub = {
706 .data = certblock->p_buffer,
707 .size = certblock->i_buffer,
708 }, priv = {
709 .data = keyblock->p_buffer,
710 .size = keyblock->i_buffer,
713 val = gnutls_certificate_set_x509_key_mem (sys->x509_cred, &pub, &priv,
714 GNUTLS_X509_FMT_PEM);
715 block_Release (keyblock);
716 block_Release (certblock);
717 if (val < 0)
719 msg_Err (crd, "cannot load X.509 key: %s", gnutls_strerror (val));
720 gnutls_certificate_free_credentials (sys->x509_cred);
721 goto error;
724 /* FIXME:
725 * - support other cipher suites
727 val = gnutls_dh_params_init (&sys->dh_params);
728 if (val >= 0)
730 const gnutls_datum_t data = {
731 .data = (unsigned char *)dh_params,
732 .size = sizeof (dh_params) - 1,
735 val = gnutls_dh_params_import_pkcs3 (sys->dh_params, &data,
736 GNUTLS_X509_FMT_PEM);
737 if (val == 0)
738 gnutls_certificate_set_dh_params (sys->x509_cred,
739 sys->dh_params);
741 if (val < 0)
743 msg_Err (crd, "cannot initialize DHE cipher suites: %s",
744 gnutls_strerror (val));
747 return VLC_SUCCESS;
749 error:
750 free (sys);
751 gnutls_Deinit (VLC_OBJECT(crd));
752 return VLC_EGENERIC;
756 * Destroys a TLS server object.
758 static void CloseServer (vlc_tls_creds_t *crd)
760 vlc_tls_creds_sys_t *sys = crd->sys;
762 /* all sessions depending on the server are now deinitialized */
763 gnutls_certificate_free_credentials (sys->x509_cred);
764 gnutls_dh_params_deinit (sys->dh_params);
765 free (sys);
767 gnutls_Deinit (VLC_OBJECT(crd));
771 * Initializes a client-side TLS credentials.
773 static int OpenClient (vlc_tls_creds_t *crd)
775 if (gnutls_Init (VLC_OBJECT(crd)))
776 return VLC_EGENERIC;
778 vlc_tls_creds_sys_t *sys = malloc (sizeof (*sys));
779 if (unlikely(sys == NULL))
780 goto error;
782 crd->sys = sys;
783 //crd->add_CA = gnutls_AddCA;
784 //crd->add_CRL = gnutls_AddCRL;
785 crd->open = gnutls_ClientSessionOpen;
786 crd->close = gnutls_SessionClose;
787 sys->handshake = gnutls_HandshakeAndValidate;
789 int val = gnutls_certificate_allocate_credentials (&sys->x509_cred);
790 if (val != 0)
792 msg_Err (crd, "cannot allocate credentials: %s",
793 gnutls_strerror (val));
794 goto error;
797 val = gnutls_certificate_set_x509_system_trust (sys->x509_cred);
798 if (val < 0)
799 msg_Err (crd, "cannot load trusted Certificate Authorities: %s",
800 gnutls_strerror (val));
801 else
802 msg_Dbg (crd, "loaded %d trusted CAs", val);
804 gnutls_certificate_set_verify_flags (sys->x509_cred,
805 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
807 return VLC_SUCCESS;
808 error:
809 free (sys);
810 gnutls_Deinit (VLC_OBJECT(crd));
811 return VLC_EGENERIC;
814 static void CloseClient (vlc_tls_creds_t *crd)
816 vlc_tls_creds_sys_t *sys = crd->sys;
818 gnutls_certificate_free_credentials (sys->x509_cred);
819 free (sys);
821 gnutls_Deinit (VLC_OBJECT(crd));