gnutls.c 17.7 KB
Newer Older
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1
/*****************************************************************************
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
2
 * gnutls.c
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
3
 *****************************************************************************
4
 * Copyright (C) 2004-2014 Rémi Denis-Courmont
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
5
6
 *
 * This program is free software; you can redistribute it and/or modify
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
7
8
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
9
10
11
12
13
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
14
 * GNU Lesser General Public License for more details.
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
15
 *
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
16
17
18
 * You should have received a copy of the GNU Öesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
19
20
 *****************************************************************************/

21
22
23
24
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

25
#include <time.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
26
#include <errno.h>
27
#include <assert.h>
28

29
30
#include <vlc_common.h>
#include <vlc_plugin.h>
31
#include <vlc_tls.h>
32
#include <vlc_block.h>
33
#include <vlc_dialog.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
34
35

#include <gnutls/gnutls.h>
36
#include <gnutls/x509.h>
37
38
#include "dhparams.h"

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#if (GNUTLS_VERSION_NUMBER >= 0x030300)
static int gnutls_Init (vlc_object_t *obj)
{
    const char *version = gnutls_check_version ("3.3.0");
    if (version == NULL)
    {
        msg_Err (obj, "unsupported GnuTLS version");
        return -1;
    }
    msg_Dbg (p_this, "using GnuTLS verson %s", version);
    return 0;
}

# define gnutls_Deinit() (void)0
#else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
54
55
static vlc_mutex_t gnutls_mutex = VLC_STATIC_MUTEX;

56
57
58
59
/**
 * Initializes GnuTLS with proper locking.
 * @return VLC_SUCCESS on success, a VLC error code otherwise.
 */
60
static int gnutls_Init (vlc_object_t *obj)
61
{
62
63
    const char *version = gnutls_check_version ("3.1.9");
    if (version == NULL)
64
    {
65
66
        msg_Err (obj, "unsupported GnuTLS version");
        return -1;
67
    }
68
    msg_Dbg (obj, "using GnuTLS verson %s", version);
69

70
    if (gnutls_check_version ("3.3.0") == NULL)
71
    {
72
         int val;
73

74
75
76
         vlc_mutex_lock (&gnutls_mutex);
         val = gnutls_global_init ();
         vlc_mutex_unlock (&gnutls_mutex);
77

78
79
80
81
82
83
84
         if (val)
         {
             msg_Err (obj, "cannot initialize GnuTLS");
             return -1;
         }
    }
    return 0;
85
86
87
88
89
}

/**
 * Deinitializes GnuTLS.
 */
90
static void gnutls_Deinit (void)
91
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
92
    vlc_mutex_lock (&gnutls_mutex);
93
    gnutls_global_deinit ();
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
94
    vlc_mutex_unlock (&gnutls_mutex);
95
}
96
#endif
97

98
99
100
101
102
static int gnutls_Error (vlc_object_t *obj, int val)
{
    switch (val)
    {
        case GNUTLS_E_AGAIN:
103
#ifdef _WIN32
104
105
            WSASetLastError (WSAEWOULDBLOCK);
#else
106
            errno = EAGAIN;
107
#endif
108
            break;
109
110

        case GNUTLS_E_INTERRUPTED:
111
#ifdef _WIN32
112
            WSASetLastError (WSAEINTR);
113
#else
114
            errno = EINTR;
115
#endif
116
117
118
119
            break;

        default:
            msg_Err (obj, "%s", gnutls_strerror (val));
120
#ifndef NDEBUG
121
122
123
            if (!gnutls_error_is_fatal (val))
                msg_Err (obj, "Error above should be handled");
#endif
124
#ifdef _WIN32
125
            WSASetLastError (WSAECONNRESET);
126
#else
127
            errno = ECONNRESET;
128
#endif
129
130
131
    }
    return -1;
}
132
#define gnutls_Error(o, val) gnutls_Error(VLC_OBJECT(o), val)
133

134
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
135
 * Sends data through a TLS session.
136
 */
137
static int gnutls_Send (void *opaque, const void *buf, size_t length)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
138
{
139
140
141
142
    assert (opaque != NULL);

    vlc_tls_t *tls = opaque;
    gnutls_session_t session = tls->sys;
143

144
145
    int val = gnutls_record_send (session, buf, length);
    return (val < 0) ? gnutls_Error (tls, val) : val;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
146
147
148
}


149
/**
150
 * Receives data through a TLS session.
151
 */
152
static int gnutls_Recv (void *opaque, void *buf, size_t length)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
153
{
154
    assert (opaque != NULL);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
155

156
157
    vlc_tls_t *tls = opaque;
    gnutls_session_t session = tls->sys;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
158

159
160
    int val = gnutls_record_recv (session, buf, length);
    return (val < 0) ? gnutls_Error (tls, val) : val;
161
162
163
164
165
}

static int gnutls_SessionOpen (vlc_tls_t *tls, int type,
                               gnutls_certificate_credentials_t x509, int fd)
{
166
    gnutls_session_t session;
167
168
169
    const char *errp;
    int val;

170
    val = gnutls_init (&session, type);
171
172
173
174
175
176
177
178
179
180
181
    if (val != 0)
    {
        msg_Err (tls, "cannot initialize TLS session: %s",
                 gnutls_strerror (val));
        return VLC_EGENERIC;
    }

    char *priorities = var_InheritString (tls, "gnutls-priorities");
    if (unlikely(priorities == NULL))
        goto error;

182
    val = gnutls_priority_set_direct (session, priorities, &errp);
183
184
185
186
187
188
189
    if (val < 0)
        msg_Err (tls, "cannot set TLS priorities \"%s\": %s", errp,
                 gnutls_strerror (val));
    free (priorities);
    if (val < 0)
        goto error;

190
    val = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509);
191
192
193
194
195
196
197
    if (val < 0)
    {
        msg_Err (tls, "cannot set TLS session credentials: %s",
                 gnutls_strerror (val));
        goto error;
    }

198
    gnutls_transport_set_int (session, fd);
199

200
201
    tls->sys = session;
    tls->sock.p_sys = NULL;
202
203
204
205
206
    tls->sock.pf_send = gnutls_Send;
    tls->sock.pf_recv = gnutls_Recv;
    return VLC_SUCCESS;

error:
207
    gnutls_deinit (session);
208
209
    return VLC_EGENERIC;
}
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
210

211
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
212
213
 * Starts or continues the TLS handshake.
 *
Rémi Denis-Courmont's avatar
Typos    
Rémi Denis-Courmont committed
214
 * @return -1 on fatal error, 0 on successful handshake completion,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
215
216
 * 1 if more would-be blocking recv is needed,
 * 2 if more would-be blocking send is required.
217
 */
218
static int gnutls_ContinueHandshake (vlc_tls_t *tls)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
219
{
220
    gnutls_session_t session = tls->sys;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
221
222
    int val;

223
#ifdef _WIN32
224
    WSASetLastError (0);
225
#endif
226
227
    do
    {
228
        val = gnutls_handshake (session);
229
230
231
232
233
234
235
236
237
        msg_Dbg (tls, "TLS handshake: %s", gnutls_strerror (val));

        switch (val)
        {
            case GNUTLS_E_SUCCESS:
                return 0;
            case GNUTLS_E_AGAIN:
            case GNUTLS_E_INTERRUPTED:
                /* I/O event: return to caller's poll() loop */
238
                return 1 + gnutls_record_get_direction (session);
239
        }
240
    }
241
    while (!gnutls_error_is_fatal (val));
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
242

243
#ifdef _WIN32
244
    msg_Dbg (tls, "Winsock error %d", WSAGetLastError ());
245
#endif
246
247
248
249
    msg_Err (tls, "TLS handshake error: %s", gnutls_strerror (val));
    return -1;
}

250
251
252
253
254
255
256
257
258
259
260
261
262
263
/**
 * Terminates TLS session and releases session data.
 * You still have to close the socket yourself.
 */
static void gnutls_SessionClose (vlc_tls_t *tls)
{
    gnutls_session_t session = tls->sys;

    if (tls->sock.p_sys != NULL)
        gnutls_bye (session, GNUTLS_SHUT_WR);

    gnutls_deinit (session);
}

264
265
266
267
268
269
270
static int gnutls_ClientSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls,
                                     int fd, const char *hostname)
{
    int val = gnutls_SessionOpen (tls, GNUTLS_CLIENT, crd->sys, fd);
    if (val != VLC_SUCCESS)
        return val;

271
    gnutls_session_t session = tls->sys;
272
273

    /* minimum DH prime bits */
274
    gnutls_dh_set_prime_bits (session, 1024);
275
276
277

    if (likely(hostname != NULL))
        /* fill Server Name Indication */
278
        gnutls_server_name_set (session, GNUTLS_NAME_DNS,
279
280
281
282
283
284
285
286
287
288
289
290
291
                                hostname, strlen (hostname));

    return VLC_SUCCESS;
}

static int gnutls_ClientHandshake (vlc_tls_t *tls, const char *host,
                                   const char *service)
{
    int val = gnutls_ContinueHandshake (tls);
    if (val)
        return val;

    /* certificates chain verification */
292
    gnutls_session_t session = tls->sys;
293
294
    unsigned status;

295
    val = gnutls_certificate_verify_peers3 (session, host, &status);
296
297
298
299
    if (val)
    {
        msg_Err (tls, "Certificate verification error: %s",
                 gnutls_strerror (val));
300
301
failure:
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
302
        return -1;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
303
    }
304

305
    if (status == 0)
306
307
308
309
310
    {   /* Good certificate */
success:
        tls->sock.p_sys = tls;
        return 0;
    }
311

312
313
    /* Bad certificate */
    gnutls_datum_t desc;
314

315
    if (gnutls_certificate_verification_status_print(status,
316
                         gnutls_certificate_type_get (session), &desc, 0) == 0)
317
318
319
320
321
322
323
324
325
326
    {
        msg_Err (tls, "Certificate verification failure: %s", desc.data);
        gnutls_free (desc.data);
    }

    status &= ~GNUTLS_CERT_INVALID; /* always set / catch-all error */
    status &= ~GNUTLS_CERT_SIGNER_NOT_FOUND; /* unknown CA */
    status &= ~GNUTLS_CERT_UNEXPECTED_OWNER; /* mismatched hostname */

    if (status != 0 || host == NULL)
327
        goto failure; /* Really bad certificate */
328

329
    /* Look up mismatching certificate in store */
330
331
332
    const gnutls_datum_t *datum;
    unsigned count;

333
    datum = gnutls_certificate_get_peers (session, &count);
334
335
336
    if (datum == NULL || count == 0)
    {
        msg_Err (tls, "Peer certificate not available");
337
        goto failure;
338
339
340
341
342
    }

    msg_Dbg (tls, "%u certificate(s) in the list", count);
    val = gnutls_verify_stored_pubkey (NULL, NULL, host, service,
                                       GNUTLS_CRT_X509, datum, 0);
343
    const char *msg;
344
345
346
    switch (val)
    {
        case 0:
347
348
            msg_Dbg (tls, "certificate key match for %s", host);
            goto success;
349
        case GNUTLS_E_NO_CERTIFICATE_FOUND:
350
351
352
353
            msg_Dbg (tls, "no known certificates for %s", host);
            msg = N_("However the security certificate presented by the "
                "server is unknown and could not be authenticated by any "
                "trusted Certificate Authority.");
354
355
            break;
        case GNUTLS_E_CERTIFICATE_KEY_MISMATCH:
356
357
358
359
            msg_Dbg (tls, "certificate keys mismatch for %s", host);
            msg = N_("However the security certificate presented by the "
                "server changed since the previous visit and was not "
                "authenticated by any trusted Certificate Authority. ");
360
361
            break;
        default:
362
            msg_Err (tls, "certificate key match error for %s: %s", host,
363
                     gnutls_strerror (val));
364
            goto failure;
365
    }
366

367
368
369
370
371
372
373
    if (dialog_Question (tls, _("Insecure site"),
        _("You attempted to reach %s. %s\n"
          "This problem may be stem from an attempt to breach your security, "
          "compromise your privacy, or a configuration error.\n\n"
          "If in doubt, abort now.\n"),
                         _("Abort"), _("View certificate"), NULL,
                         vlc_gettext (msg), host) != 2)
374
        goto failure;
375
376
377
378

    gnutls_x509_crt_t cert;

    if (gnutls_x509_crt_init (&cert))
379
        goto failure;
380
381
382
383
    if (gnutls_x509_crt_import (cert, datum, GNUTLS_X509_FMT_DER)
     || gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_ONELINE, &desc))
    {
        gnutls_x509_crt_deinit (cert);
384
        goto failure;
385
386
387
    }
    gnutls_x509_crt_deinit (cert);

388
    val = dialog_Question (tls, _("Insecure site"),
389
390
391
392
         _("This is the certificate presented by %s:\n%s\n\n"
           "If in doubt, abort now.\n"),
                           _("Abort"), _("Accept 24 hours"),
                           _("Accept permanently"), host, desc.data);
393
394
    gnutls_free (desc.data);

395
396
397
398
399
400
401
    time_t expiry = 0;
    switch (val)
    {
        case 2:
            time (&expiry);
            expiry += 24 * 60 * 60;
        case 3:
402
403
404
            val = gnutls_store_pubkey (NULL, NULL, host, service,
                                       GNUTLS_CRT_X509, datum, expiry, 0);
            if (val)
405
                msg_Err (tls, "cannot store X.509 certificate: %s",
406
                         gnutls_strerror (val));
407
            goto success;
408
    }
409
    goto failure;
410
411
}

412
/**
413
 * Initializes a client-side TLS credentials.
414
 */
415
static int OpenClient (vlc_tls_creds_t *crd)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
416
{
417
    gnutls_certificate_credentials_t x509;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
418

419
420
    if (gnutls_Init (VLC_OBJECT(crd)))
        return VLC_EGENERIC;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
421

422
    int val = gnutls_certificate_allocate_credentials (&x509);
423
    if (val != 0)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
424
    {
425
        msg_Err (crd, "cannot allocate credentials: %s",
426
                 gnutls_strerror (val));
427
        gnutls_Deinit ();
428
        return VLC_EGENERIC;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
429
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
430

431
    val = gnutls_certificate_set_x509_system_trust (x509);
432
    if (val < 0)
433
        msg_Err (crd, "cannot load trusted Certificate Authorities: %s",
434
                 gnutls_strerror (val));
435
436
    else
        msg_Dbg (crd, "loaded %d trusted CAs", val);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
437

438
439
440
441
442
443
444
    gnutls_certificate_set_verify_flags (x509,
                                         GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);

    crd->sys = x509;
    crd->open = gnutls_ClientSessionOpen;
    crd->handshake = gnutls_ClientHandshake;
    crd->close = gnutls_SessionClose;
445

446
    return VLC_SUCCESS;
447
}
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
448

449
450
451
452
453
static void CloseClient (vlc_tls_creds_t *crd)
{
    gnutls_certificate_credentials_t x509 = crd->sys;

    gnutls_certificate_free_credentials (x509);
454
    gnutls_Deinit ();
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
455
456
}

457
#ifdef ENABLE_SOUT
458
459
460
461
462
463
464
465
466
/**
 * Server-side TLS credentials private data
 */
typedef struct vlc_tls_creds_sys
{
    gnutls_certificate_credentials_t x509_cred;
    gnutls_dh_params_t dh_params;
} vlc_tls_creds_sys_t;

467
468
469
/**
 * Initializes a server-side TLS session.
 */
470
static int gnutls_ServerSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls,
471
472
                                     int fd, const char *hostname)
{
473
474
    vlc_tls_creds_sys_t *sys = crd->sys;

475
    assert (hostname == NULL);
476
    return gnutls_SessionOpen (tls, GNUTLS_SERVER, sys->x509_cred, fd);
477
478
}

479
480
static int gnutls_ServerHandshake (vlc_tls_t *tls, const char *host,
                                   const char *service)
481
{
482
483
    int val = gnutls_ContinueHandshake (tls);
    if (val == 0)
484
        tls->sock.p_sys = tls;
485

486
487
    (void) host; (void) service;
    return val;
488
489
}

490
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
491
 * Allocates a whole server's TLS credentials.
492
 */
493
static int OpenServer (vlc_tls_creds_t *crd, const char *cert, const char *key)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
494
495
496
{
    int val;

497
    if (gnutls_Init (VLC_OBJECT(crd)))
498
499
        return VLC_EGENERIC;

500
501
    vlc_tls_creds_sys_t *sys = malloc (sizeof (*sys));
    if (unlikely(sys == NULL))
502
503
504
505
    {
        gnutls_Deinit ();
        return VLC_ENOMEM;
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
506
507

    /* Sets server's credentials */
508
509
    val = gnutls_certificate_allocate_credentials (&sys->x509_cred);
    if (val != 0)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
510
    {
511
        msg_Err (crd, "cannot allocate credentials: %s",
512
                 gnutls_strerror (val));
513
514
515
        free (sys);
        gnutls_Deinit ();
        return VLC_ENOMEM;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
516
517
    }

518
519
520
    block_t *certblock = block_FilePath (cert);
    if (certblock == NULL)
    {
521
522
        msg_Err (crd, "cannot read certificate chain from %s: %s", cert,
                 vlc_strerror_c(errno));
523
        goto error;
524
525
526
527
528
    }

    block_t *keyblock = block_FilePath (key);
    if (keyblock == NULL)
    {
529
530
        msg_Err (crd, "cannot read private key from %s: %s", key,
                 vlc_strerror_c(errno));
531
        block_Release (certblock);
532
        goto error;
533
534
535
536
537
538
539
540
541
542
543
    }

    gnutls_datum_t pub = {
       .data = certblock->p_buffer,
       .size = certblock->i_buffer,
    }, priv = {
       .data = keyblock->p_buffer,
       .size = keyblock->i_buffer,
    };

    val = gnutls_certificate_set_x509_key_mem (sys->x509_cred, &pub, &priv,
544
                                                GNUTLS_X509_FMT_PEM);
545
546
    block_Release (keyblock);
    block_Release (certblock);
547
    if (val < 0)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
548
    {
549
        msg_Err (crd, "cannot load X.509 key: %s", gnutls_strerror (val));
550
        gnutls_certificate_free_credentials (sys->x509_cred);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
551
        goto error;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
552
553
    }

554
    /* FIXME:
555
     * - support other cipher suites
556
     */
557
    val = gnutls_dh_params_init (&sys->dh_params);
558
559
    if (val >= 0)
    {
560
561
562
563
564
        const gnutls_datum_t data = {
            .data = (unsigned char *)dh_params,
            .size = sizeof (dh_params) - 1,
        };

565
        val = gnutls_dh_params_import_pkcs3 (sys->dh_params, &data,
566
567
                                             GNUTLS_X509_FMT_PEM);
        if (val == 0)
568
569
            gnutls_certificate_set_dh_params (sys->x509_cred,
                                              sys->dh_params);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
570
    }
571
    if (val < 0)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
572
    {
573
        msg_Err (crd, "cannot initialize DHE cipher suites: %s",
574
                 gnutls_strerror (val));
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
575
576
    }

577
578
    crd->sys = sys;
    crd->open = gnutls_ServerSessionOpen;
579
    crd->handshake = gnutls_ServerHandshake;
580
581
    crd->close = gnutls_SessionClose;

582
    return VLC_SUCCESS;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
583
584

error:
585
    gnutls_certificate_free_credentials (sys->x509_cred);
586
    free (sys);
587
    gnutls_Deinit ();
588
    return VLC_EGENERIC;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
589
590
}

591
/**
592
 * Destroys a TLS server object.
593
 */
594
static void CloseServer (vlc_tls_creds_t *crd)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
595
{
596
    vlc_tls_creds_sys_t *sys = crd->sys;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
597

598
    /* all sessions depending on the server are now deinitialized */
599
600
601
    gnutls_certificate_free_credentials (sys->x509_cred);
    gnutls_dh_params_deinit (sys->dh_params);
    free (sys);
602
    gnutls_Deinit ();
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
603
}
604
#endif
605

606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
#define PRIORITIES_TEXT N_("TLS cipher priorities")
#define PRIORITIES_LONGTEXT N_("Ciphers, key exchange methods, " \
    "hash functions and compression methods can be selected. " \
    "Refer to GNU TLS documentation for detailed syntax.")
static const char *const priorities_values[] = {
    "PERFORMANCE",
    "NORMAL",
    "SECURE128",
    "SECURE256",
    "EXPORT",
};
static const char *const priorities_text[] = {
    N_("Performance (prioritize faster ciphers)"),
    N_("Normal"),
    N_("Secure 128-bits (exclude 256-bits ciphers)"),
    N_("Secure 256-bits (prioritize 256-bits ciphers)"),
    N_("Export (include insecure ciphers)"),
};
624

625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
vlc_module_begin ()
    set_shortname( "GNU TLS" )
    set_description( N_("GNU TLS transport layer security") )
    set_capability( "tls client", 1 )
    set_callbacks( OpenClient, CloseClient )
    set_category( CAT_ADVANCED )
    set_subcategory( SUBCAT_ADVANCED_NETWORK )
    add_string ("gnutls-priorities", "NORMAL", PRIORITIES_TEXT,
                PRIORITIES_LONGTEXT, false)
        change_string_list (priorities_values, priorities_text)
#ifdef ENABLE_SOUT
    add_submodule ()
        set_description( N_("GNU TLS server") )
        set_capability( "tls server", 1 )
        set_category( CAT_ADVANCED )
        set_subcategory( SUBCAT_ADVANCED_NETWORK )
        set_callbacks( OpenServer, CloseServer )
#endif
vlc_module_end ()