demux: ogg: only invalid pts on no granule interpolation
[vlc.git] / modules / misc / gnutls.c
blobdef0727a17cc0d781511778ccbf8d32f1ea5ab93
1 /*****************************************************************************
2 * gnutls.c
3 *****************************************************************************
4 * Copyright (C) 2004-2017 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 Lesser 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 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <unistd.h>
32 #ifdef HAVE_SYS_UIO_H
33 # include <sys/uio.h>
34 #endif
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_tls.h>
39 #include <vlc_block.h>
40 #include <vlc_dialog.h>
42 #include <gnutls/gnutls.h>
43 #include <gnutls/x509.h>
45 typedef struct vlc_tls_gnutls
47 vlc_tls_t tls;
48 gnutls_session_t session;
49 vlc_object_t *obj;
50 } vlc_tls_gnutls_t;
52 static void gnutls_Banner(vlc_object_t *obj)
54 msg_Dbg(obj, "using GnuTLS v%s (built with v"GNUTLS_VERSION")",
55 gnutls_check_version(NULL));
58 static int gnutls_Error(vlc_tls_gnutls_t *priv, int val)
60 switch (val)
62 case GNUTLS_E_AGAIN:
63 #ifdef _WIN32
64 WSASetLastError (WSAEWOULDBLOCK);
65 #endif
66 errno = EAGAIN;
67 break;
69 case GNUTLS_E_INTERRUPTED:
70 #ifdef _WIN32
71 WSASetLastError (WSAEINTR);
72 #endif
73 errno = EINTR;
74 break;
76 default:
77 msg_Err(priv->obj, "%s", gnutls_strerror (val));
78 #ifndef NDEBUG
79 if (!gnutls_error_is_fatal (val))
80 msg_Err(priv->obj, "Error above should be handled");
81 #endif
82 #ifdef _WIN32
83 WSASetLastError (WSAECONNRESET);
84 #endif
85 errno = ECONNRESET;
87 return -1;
90 static ssize_t vlc_gnutls_read(gnutls_transport_ptr_t ptr, void *buf,
91 size_t length)
93 vlc_tls_t *sock = ptr;
94 struct iovec iov = {
95 .iov_base = buf,
96 .iov_len = length,
99 return sock->ops->readv(sock, &iov, 1);
102 static ssize_t vlc_gnutls_writev(gnutls_transport_ptr_t ptr,
103 const giovec_t *giov, int iovcnt)
105 #ifdef IOV_MAX
106 const long iovmax = IOV_MAX;
107 #else
108 const long iovmax = sysconf(_SC_IOV_MAX);
109 #endif
110 if (unlikely(iovcnt > iovmax))
112 errno = EINVAL;
113 return -1;
115 if (unlikely(iovcnt == 0))
116 return 0;
118 vlc_tls_t *sock = ptr;
119 struct iovec iov[iovcnt];
121 for (int i = 0; i < iovcnt; i++)
123 iov[i].iov_base = giov[i].iov_base;
124 iov[i].iov_len = giov[i].iov_len;
127 return sock->ops->writev(sock, iov, iovcnt);
130 static int gnutls_GetFD(vlc_tls_t *tls, short *restrict events)
132 vlc_tls_gnutls_t *priv = (vlc_tls_gnutls_t *)tls;
133 vlc_tls_t *sock = gnutls_transport_get_ptr(priv->session);
135 return vlc_tls_GetPollFD(sock, events);
138 static ssize_t gnutls_Recv(vlc_tls_t *tls, struct iovec *iov, unsigned count)
140 vlc_tls_gnutls_t *priv = (vlc_tls_gnutls_t *)tls;
141 gnutls_session_t session = priv->session;
142 size_t rcvd = 0;
144 while (count > 0)
146 ssize_t val = gnutls_record_recv(session, iov->iov_base, iov->iov_len);
147 if (val < 0)
148 return rcvd ? (ssize_t)rcvd : gnutls_Error(priv, val);
150 rcvd += val;
152 if ((size_t)val < iov->iov_len)
153 break;
155 iov++;
156 count--;
159 return rcvd;
162 static ssize_t gnutls_Send (vlc_tls_t *tls, const struct iovec *iov,
163 unsigned count)
165 vlc_tls_gnutls_t *priv = (vlc_tls_gnutls_t *)tls;
166 gnutls_session_t session = priv->session;
167 ssize_t val;
169 if (!gnutls_record_check_corked(session))
171 gnutls_record_cork(session);
173 while (count > 0)
175 val = gnutls_record_send(session, iov->iov_base, iov->iov_len);
176 if (val < (ssize_t)iov->iov_len)
177 break;
179 iov++;
180 count--;
184 val = gnutls_record_uncork(session, 0);
185 return (val < 0) ? gnutls_Error(priv, val) : val;
188 static int gnutls_Shutdown(vlc_tls_t *tls, bool duplex)
190 vlc_tls_gnutls_t *priv = (vlc_tls_gnutls_t *)tls;
191 gnutls_session_t session = priv->session;
192 ssize_t val;
194 /* Flush any pending data */
195 val = gnutls_record_uncork(session, 0);
196 if (val < 0)
197 return gnutls_Error(priv, val);
199 val = gnutls_bye(session, duplex ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
200 if (val < 0)
201 return gnutls_Error(priv, val);
203 return 0;
206 static void gnutls_Close (vlc_tls_t *tls)
208 vlc_tls_gnutls_t *priv = (vlc_tls_gnutls_t *)tls;
210 gnutls_deinit(priv->session);
211 free(priv);
214 static const struct vlc_tls_operations gnutls_ops =
216 gnutls_GetFD,
217 gnutls_Recv,
218 gnutls_Send,
219 gnutls_Shutdown,
220 gnutls_Close,
223 static vlc_tls_gnutls_t *gnutls_SessionOpen(vlc_object_t *obj, int type,
224 gnutls_certificate_credentials_t x509,
225 vlc_tls_t *sock,
226 const char *const *alpn)
228 vlc_tls_gnutls_t *priv = malloc(sizeof (*priv));
229 if (unlikely(priv == NULL))
230 return NULL;
232 gnutls_session_t session;
233 const char *errp;
234 int val;
236 type |= GNUTLS_NONBLOCK;
237 #if (GNUTLS_VERSION_NUMBER >= 0x030500)
238 type |= GNUTLS_ENABLE_FALSE_START;
239 #endif
241 val = gnutls_init(&session, type);
242 if (val != 0)
244 msg_Err(obj, "cannot initialize TLS session: %s",
245 gnutls_strerror(val));
246 free(priv);
247 return NULL;
250 char *priorities = var_InheritString(obj, "gnutls-priorities");
251 if (unlikely(priorities == NULL))
252 goto error;
254 val = gnutls_priority_set_direct (session, priorities, &errp);
255 if (val < 0)
256 msg_Err(obj, "cannot set TLS priorities \"%s\": %s", errp,
257 gnutls_strerror(val));
258 free (priorities);
259 if (val < 0)
260 goto error;
262 val = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509);
263 if (val < 0)
265 msg_Err(obj, "cannot set TLS session credentials: %s",
266 gnutls_strerror(val));
267 goto error;
270 if (alpn != NULL)
272 gnutls_datum_t *protv = NULL;
273 unsigned protc = 0;
275 while (*alpn != NULL)
277 gnutls_datum_t *n = realloc(protv, sizeof (*protv) * (protc + 1));
278 if (unlikely(n == NULL))
280 free(protv);
281 goto error;
283 protv = n;
285 protv[protc].data = (void *)*alpn;
286 protv[protc].size = strlen(*alpn);
287 protc++;
288 alpn++;
291 val = gnutls_alpn_set_protocols (session, protv, protc, 0);
292 free (protv);
295 gnutls_transport_set_ptr(session, sock);
296 gnutls_transport_set_vec_push_function(session, vlc_gnutls_writev);
297 gnutls_transport_set_pull_function(session, vlc_gnutls_read);
299 priv->session = session;
300 priv->obj = obj;
302 vlc_tls_t *tls = &priv->tls;
304 tls->ops = &gnutls_ops;
305 return priv;
307 error:
308 gnutls_deinit (session);
309 free(priv);
310 return NULL;
314 * Starts or continues the TLS handshake.
316 * @return -1 on fatal error, 0 on successful handshake completion,
317 * 1 if more would-be blocking recv is needed,
318 * 2 if more would-be blocking send is required.
320 static int gnutls_Handshake(vlc_tls_t *tls, char **restrict alp)
322 vlc_tls_gnutls_t *priv = (vlc_tls_gnutls_t *)tls;
323 vlc_object_t *obj = priv->obj;
324 gnutls_session_t session = priv->session;
325 int val = gnutls_handshake(session);
327 if (gnutls_error_is_fatal(val))
329 msg_Err(obj, "TLS handshake error: %s", gnutls_strerror(val));
330 return -1;
333 switch (val)
335 case GNUTLS_E_SUCCESS:
336 break;
337 case GNUTLS_E_AGAIN:
338 case GNUTLS_E_INTERRUPTED:
339 /* I/O event: return to caller's poll() loop */
340 return 1 + gnutls_record_get_direction(session);
341 default:
342 msg_Warn(obj, "TLS handshake error: %s", gnutls_strerror(val));
343 return 1;
346 msg_Dbg(obj, "TLS handshake complete");
347 #if (GNUTLS_VERSION_NUMBER >= 0x030500)
348 /* intentionally left blank */;
350 unsigned flags = gnutls_session_get_flags(session);
352 if (flags & GNUTLS_SFLAGS_SAFE_RENEGOTIATION)
353 msg_Dbg(obj, " - safe renegotiation (RFC5746) enabled");
354 if (flags & GNUTLS_SFLAGS_EXT_MASTER_SECRET)
355 msg_Dbg(obj, " - extended master secret (RFC7627) enabled");
356 if (flags & GNUTLS_SFLAGS_ETM)
357 msg_Dbg(obj, " - encrypt then MAC (RFC7366) enabled");
358 if (flags & GNUTLS_SFLAGS_FALSE_START)
359 msg_Dbg(obj, " - false start (RFC7918) enabled");
360 #endif
362 if (alp != NULL)
364 gnutls_datum_t datum;
366 val = gnutls_alpn_get_selected_protocol (session, &datum);
367 if (val == 0)
369 if (memchr (datum.data, 0, datum.size) != NULL)
370 return -1; /* Other end is doing something fishy?! */
372 *alp = strndup ((char *)datum.data, datum.size);
373 if (unlikely(*alp == NULL))
374 return -1;
376 else
377 *alp = NULL;
379 return 0;
382 static vlc_tls_t *gnutls_ClientSessionOpen(vlc_tls_client_t *crd,
383 vlc_tls_t *sk, const char *hostname,
384 const char *const *alpn)
386 vlc_tls_gnutls_t *priv = gnutls_SessionOpen(VLC_OBJECT(crd), GNUTLS_CLIENT,
387 crd->sys, sk, alpn);
388 if (priv == NULL)
389 return NULL;
391 gnutls_session_t session = priv->session;
393 /* minimum DH prime bits */
394 gnutls_dh_set_prime_bits (session, 1024);
396 if (likely(hostname != NULL))
397 /* fill Server Name Indication */
398 gnutls_server_name_set (session, GNUTLS_NAME_DNS,
399 hostname, strlen (hostname));
401 return &priv->tls;
404 static int gnutls_ClientHandshake(vlc_tls_t *tls,
405 const char *host, const char *service,
406 char **restrict alp)
408 vlc_tls_gnutls_t *priv = (vlc_tls_gnutls_t *)tls;
409 vlc_object_t *obj = priv->obj;
411 int val = gnutls_Handshake(tls, alp);
412 if (val)
413 return val;
415 /* certificates chain verification */
416 gnutls_session_t session = priv->session;
417 unsigned status;
419 val = gnutls_certificate_verify_peers3 (session, host, &status);
420 if (val)
422 msg_Err(obj, "Certificate verification error: %s",
423 gnutls_strerror(val));
424 goto error;
427 if (status == 0) /* Good certificate */
428 return 0;
430 /* Bad certificate */
431 gnutls_datum_t desc;
433 if (gnutls_certificate_verification_status_print(status,
434 gnutls_certificate_type_get (session), &desc, 0) == 0)
436 msg_Err(obj, "Certificate verification failure: %s", desc.data);
437 gnutls_free (desc.data);
440 status &= ~GNUTLS_CERT_INVALID; /* always set / catch-all error */
441 status &= ~GNUTLS_CERT_SIGNER_NOT_FOUND; /* unknown CA */
442 status &= ~GNUTLS_CERT_UNEXPECTED_OWNER; /* mismatched hostname */
444 if (status != 0 || host == NULL)
445 goto error; /* Really bad certificate */
447 /* Look up mismatching certificate in store */
448 const gnutls_datum_t *datum;
449 unsigned count;
451 datum = gnutls_certificate_get_peers (session, &count);
452 if (datum == NULL || count == 0)
454 msg_Err(obj, "Peer certificate not available");
455 goto error;
458 msg_Dbg(obj, "%u certificate(s) in the list", count);
459 val = gnutls_verify_stored_pubkey (NULL, NULL, host, service,
460 GNUTLS_CRT_X509, datum, 0);
461 const char *msg;
462 switch (val)
464 case 0:
465 msg_Dbg(obj, "certificate key match for %s", host);
466 return 0;
467 case GNUTLS_E_NO_CERTIFICATE_FOUND:
468 msg_Dbg(obj, "no known certificates for %s", host);
469 msg = N_("However, the security certificate presented by the "
470 "server is unknown and could not be authenticated by any "
471 "trusted Certificate Authority.");
472 break;
473 case GNUTLS_E_CERTIFICATE_KEY_MISMATCH:
474 msg_Dbg(obj, "certificate keys mismatch for %s", host);
475 msg = N_("However, the security certificate presented by the "
476 "server changed since the previous visit and was not "
477 "authenticated by any trusted Certificate Authority.");
478 break;
479 default:
480 msg_Err(obj, "certificate key match error for %s: %s", host,
481 gnutls_strerror(val));
482 goto error;
485 if (vlc_dialog_wait_question(obj, VLC_DIALOG_QUESTION_WARNING,
486 _("Abort"), _("View certificate"), NULL,
487 _("Insecure site"),
488 _("You attempted to reach %s. %s\n"
489 "This problem may be stem from an attempt to breach your security, "
490 "compromise your privacy, or a configuration error.\n\n"
491 "If in doubt, abort now.\n"), host, vlc_gettext(msg)) != 1)
492 goto error;
494 gnutls_x509_crt_t cert;
496 if (gnutls_x509_crt_init (&cert))
497 goto error;
498 if (gnutls_x509_crt_import (cert, datum, GNUTLS_X509_FMT_DER)
499 || gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_ONELINE, &desc))
501 gnutls_x509_crt_deinit (cert);
502 goto error;
504 gnutls_x509_crt_deinit (cert);
506 val = vlc_dialog_wait_question(obj, VLC_DIALOG_QUESTION_WARNING,
507 _("Abort"), _("Accept 24 hours"), _("Accept permanently"),
508 _("Insecure site"),
509 _("This is the certificate presented by %s:\n%s\n\n"
510 "If in doubt, abort now.\n"), host, desc.data);
511 gnutls_free (desc.data);
513 time_t expiry = 0;
514 switch (val)
516 case 1:
517 time (&expiry);
518 expiry += 24 * 60 * 60;
519 /* fall through */
520 case 2:
521 val = gnutls_store_pubkey (NULL, NULL, host, service,
522 GNUTLS_CRT_X509, datum, expiry, 0);
523 if (val)
524 msg_Err(obj, "cannot store X.509 certificate: %s",
525 gnutls_strerror (val));
526 break;
527 default:
528 goto error;
530 return 0;
532 error:
533 if (alp != NULL)
534 free(*alp);
535 return -1;
538 static void gnutls_ClientDestroy(vlc_tls_client_t *crd)
540 gnutls_certificate_credentials_t x509 = crd->sys;
542 gnutls_certificate_free_credentials(x509);
545 static const struct vlc_tls_client_operations gnutls_ClientOps =
547 .open = gnutls_ClientSessionOpen,
548 .handshake = gnutls_ClientHandshake,
549 .destroy = gnutls_ClientDestroy,
553 * Initializes a client-side TLS credentials.
555 static int OpenClient(vlc_tls_client_t *crd)
557 gnutls_certificate_credentials_t x509;
559 gnutls_Banner(VLC_OBJECT(crd));
561 int val = gnutls_certificate_allocate_credentials (&x509);
562 if (val != 0)
564 msg_Err (crd, "cannot allocate credentials: %s",
565 gnutls_strerror (val));
566 return VLC_EGENERIC;
569 if (var_InheritBool(crd, "gnutls-system-trust"))
571 val = gnutls_certificate_set_x509_system_trust(x509);
572 if (val < 0)
573 msg_Err(crd, "cannot load trusted Certificate Authorities "
574 "from %s: %s", "system", gnutls_strerror(val));
575 else
576 msg_Dbg(crd, "loaded %d trusted CAs from %s", val, "system");
579 char *dir = var_InheritString(crd, "gnutls-dir-trust");
580 if (dir != NULL)
582 val = gnutls_certificate_set_x509_trust_dir(x509, dir,
583 GNUTLS_X509_FMT_PEM);
584 if (val < 0)
585 msg_Err(crd, "cannot load trusted Certificate Authorities "
586 "from %s: %s", dir, gnutls_strerror(val));
587 else
588 msg_Dbg(crd, "loaded %d trusted CAs from %s", val, dir);
589 free(dir);
592 gnutls_certificate_set_verify_flags (x509,
593 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
595 crd->ops = &gnutls_ClientOps;
596 crd->sys = x509;
597 return VLC_SUCCESS;
600 #ifdef ENABLE_SOUT
602 * Server-side TLS credentials private data
604 typedef struct vlc_tls_creds_sys
606 gnutls_certificate_credentials_t x509_cred;
607 gnutls_dh_params_t dh_params;
608 } vlc_tls_creds_sys_t;
611 * Initializes a server-side TLS session.
613 static vlc_tls_t *gnutls_ServerSessionOpen(vlc_tls_server_t *crd,
614 vlc_tls_t *sk,
615 const char *const *alpn)
617 vlc_tls_creds_sys_t *sys = crd->sys;
618 vlc_tls_gnutls_t *priv = gnutls_SessionOpen(VLC_OBJECT(crd), GNUTLS_SERVER,
619 sys->x509_cred, sk, alpn);
620 return (priv != NULL) ? &priv->tls : NULL;
623 static void gnutls_ServerDestroy(vlc_tls_server_t *crd)
625 vlc_tls_creds_sys_t *sys = crd->sys;
627 /* all sessions depending on the server are now deinitialized */
628 gnutls_certificate_free_credentials(sys->x509_cred);
629 gnutls_dh_params_deinit(sys->dh_params);
630 free(sys);
633 static const struct vlc_tls_server_operations gnutls_ServerOps =
635 .open = gnutls_ServerSessionOpen,
636 .handshake = gnutls_Handshake,
637 .destroy = gnutls_ServerDestroy,
641 * Allocates a whole server's TLS credentials.
643 static int OpenServer(vlc_tls_server_t *crd, const char *cert, const char *key)
645 gnutls_Banner(VLC_OBJECT(crd));
647 vlc_tls_creds_sys_t *sys = malloc (sizeof (*sys));
648 if (unlikely(sys == NULL))
649 return VLC_ENOMEM;
651 /* Sets server's credentials */
652 int val = gnutls_certificate_allocate_credentials (&sys->x509_cred);
653 if (val != 0)
655 msg_Err (crd, "cannot allocate credentials: %s",
656 gnutls_strerror (val));
657 free (sys);
658 return VLC_ENOMEM;
661 block_t *certblock = block_FilePath(cert, false);
662 if (certblock == NULL)
664 msg_Err (crd, "cannot read certificate chain from %s: %s", cert,
665 vlc_strerror_c(errno));
666 goto error;
669 block_t *keyblock = block_FilePath(key, false);
670 if (keyblock == NULL)
672 msg_Err (crd, "cannot read private key from %s: %s", key,
673 vlc_strerror_c(errno));
674 block_Release (certblock);
675 goto error;
678 gnutls_datum_t pub = {
679 .data = certblock->p_buffer,
680 .size = certblock->i_buffer,
681 }, priv = {
682 .data = keyblock->p_buffer,
683 .size = keyblock->i_buffer,
686 val = gnutls_certificate_set_x509_key_mem (sys->x509_cred, &pub, &priv,
687 GNUTLS_X509_FMT_PEM);
688 block_Release (keyblock);
689 block_Release (certblock);
690 if (val < 0)
692 msg_Err (crd, "cannot load X.509 key: %s", gnutls_strerror (val));
693 goto error;
696 /* FIXME:
697 * - regenerate these regularly
698 * - support other cipher suites
700 val = gnutls_dh_params_init (&sys->dh_params);
701 if (val >= 0)
703 gnutls_sec_param_t sec = GNUTLS_SEC_PARAM_MEDIUM;
704 unsigned bits = gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, sec);
706 msg_Dbg (crd, "generating Diffie-Hellman %u-bits parameters...", bits);
707 val = gnutls_dh_params_generate2 (sys->dh_params, bits);
708 if (val == 0)
709 gnutls_certificate_set_dh_params (sys->x509_cred,
710 sys->dh_params);
712 if (val < 0)
714 msg_Err (crd, "cannot initialize DHE cipher suites: %s",
715 gnutls_strerror (val));
718 msg_Dbg (crd, "ciphers parameters loaded");
720 crd->ops = &gnutls_ServerOps;
721 crd->sys = sys;
722 return VLC_SUCCESS;
724 error:
725 gnutls_certificate_free_credentials (sys->x509_cred);
726 free (sys);
727 return VLC_EGENERIC;
729 #endif
731 #define SYSTEM_TRUST_TEXT N_("Use system trust database")
732 #define SYSTEM_TRUST_LONGTEXT N_( \
733 "Trust the root certificates of Certificate Authorities stored in " \
734 "the operating system trust database to authenticate TLS sessions.")
736 #define DIR_TRUST_TEXT N_("Trust directory")
737 #define DIR_TRUST_LONGTEXT N_( \
738 "Trust the root certificates of Certificate Authorities stored in " \
739 "the specified directory to authenticate TLS sessions.")
741 #define PRIORITIES_TEXT N_("TLS cipher priorities")
742 #define PRIORITIES_LONGTEXT N_("Ciphers, key exchange methods, " \
743 "hash functions and compression methods can be selected. " \
744 "Refer to GNU TLS documentation for detailed syntax.")
745 static const char *const priorities_values[] = {
746 "PERFORMANCE",
747 "NORMAL",
748 "SECURE128",
749 "SECURE256",
750 "EXPORT",
752 static const char *const priorities_text[] = {
753 N_("Performance (prioritize faster ciphers)"),
754 N_("Normal"),
755 N_("Secure 128-bits (exclude 256-bits ciphers)"),
756 N_("Secure 256-bits (prioritize 256-bits ciphers)"),
757 N_("Export (include insecure ciphers)"),
760 vlc_module_begin ()
761 set_shortname( "GNU TLS" )
762 set_description( N_("GNU TLS transport layer security") )
763 set_capability( "tls client", 1 )
764 set_callbacks(OpenClient, NULL)
765 set_category( CAT_ADVANCED )
766 set_subcategory( SUBCAT_ADVANCED_NETWORK )
767 add_bool("gnutls-system-trust", true, SYSTEM_TRUST_TEXT,
768 SYSTEM_TRUST_LONGTEXT, true)
769 add_string("gnutls-dir-trust", NULL, DIR_TRUST_TEXT,
770 DIR_TRUST_TEXT, true)
771 add_string ("gnutls-priorities", "NORMAL", PRIORITIES_TEXT,
772 PRIORITIES_LONGTEXT, false)
773 change_string_list (priorities_values, priorities_text)
774 #ifdef ENABLE_SOUT
775 add_submodule ()
776 set_description( N_("GNU TLS server") )
777 set_capability( "tls server", 1 )
778 set_category( CAT_ADVANCED )
779 set_subcategory( SUBCAT_ADVANCED_NETWORK )
780 set_callbacks(OpenServer, NULL)
781 #endif
782 vlc_module_end ()