gnutls.c 17.6 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"

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
39 40
static vlc_mutex_t gnutls_mutex = VLC_STATIC_MUTEX;

41 42 43 44 45
/**
 * Initializes GnuTLS with proper locking.
 * @return VLC_SUCCESS on success, a VLC error code otherwise.
 */
static int gnutls_Init (vlc_object_t *p_this)
46
{
47 48
    int ret = VLC_EGENERIC;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
49
    vlc_mutex_lock (&gnutls_mutex);
50 51 52 53 54 55
    if (gnutls_global_init ())
    {
        msg_Err (p_this, "cannot initialize GnuTLS");
        goto error;
    }

56
    const char *psz_version = gnutls_check_version ("3.1.4");
57 58 59 60 61 62 63 64 65 66 67
    if (psz_version == NULL)
    {
        msg_Err (p_this, "unsupported GnuTLS version");
        gnutls_global_deinit ();
        goto error;
    }

    msg_Dbg (p_this, "GnuTLS v%s initialized", psz_version);
    ret = VLC_SUCCESS;

error:
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
68
    vlc_mutex_unlock (&gnutls_mutex);
69 70 71 72 73 74 75 76 77
    return ret;
}


/**
 * Deinitializes GnuTLS.
 */
static void gnutls_Deinit (vlc_object_t *p_this)
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
78
    vlc_mutex_lock (&gnutls_mutex);
79 80 81

    gnutls_global_deinit ();
    msg_Dbg (p_this, "GnuTLS deinitialized");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
82
    vlc_mutex_unlock (&gnutls_mutex);
83
}
84 85


86 87 88 89 90
static int gnutls_Error (vlc_object_t *obj, int val)
{
    switch (val)
    {
        case GNUTLS_E_AGAIN:
91
#ifdef _WIN32
92 93
            WSASetLastError (WSAEWOULDBLOCK);
#else
94
            errno = EAGAIN;
95
#endif
96
            break;
97 98

        case GNUTLS_E_INTERRUPTED:
99
#ifdef _WIN32
100
            WSASetLastError (WSAEINTR);
101
#else
102
            errno = EINTR;
103
#endif
104 105 106 107
            break;

        default:
            msg_Err (obj, "%s", gnutls_strerror (val));
108
#ifndef NDEBUG
109 110 111
            if (!gnutls_error_is_fatal (val))
                msg_Err (obj, "Error above should be handled");
#endif
112
#ifdef _WIN32
113
            WSASetLastError (WSAECONNRESET);
114
#else
115
            errno = ECONNRESET;
116
#endif
117 118 119
    }
    return -1;
}
120
#define gnutls_Error(o, val) gnutls_Error(VLC_OBJECT(o), val)
121

122
struct vlc_tls_sys
123
{
124
    gnutls_session_t session;
125
    bool handshaked;
126 127 128
};


129
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
130
 * Sends data through a TLS session.
131
 */
132
static int gnutls_Send (void *opaque, const void *buf, size_t length)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
133
{
134 135
    vlc_tls_t *session = opaque;
    vlc_tls_sys_t *sys = session->sys;
136

137 138
    int val = gnutls_record_send (sys->session, buf, length);
    return (val < 0) ? gnutls_Error (session, val) : val;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
139 140 141
}


142
/**
143
 * Receives data through a TLS session.
144
 */
145
static int gnutls_Recv (void *opaque, void *buf, size_t length)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
146
{
147 148
    vlc_tls_t *session = opaque;
    vlc_tls_sys_t *sys = session->sys;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
149

150 151
    int val = gnutls_record_recv (sys->session, buf, length);
    return (val < 0) ? gnutls_Error (session, val) : val;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
152 153
}

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
/**
 * Terminates TLS session and releases session data.
 * You still have to close the socket yourself.
 */
static void gnutls_SessionClose (vlc_tls_t *session)
{
    vlc_tls_sys_t *sys = session->sys;

    if (sys->handshaked)
        gnutls_bye (sys->session, GNUTLS_SHUT_WR);
    gnutls_deinit (sys->session);

    free (sys);
}

static int gnutls_SessionOpen (vlc_tls_t *tls, int type,
                               gnutls_certificate_credentials_t x509, int fd)
{
    const char *errp;
    int val;

    vlc_tls_sys_t *sys = malloc (sizeof (*tls->sys));
    if (unlikely(sys == NULL))
        return VLC_ENOMEM;

    sys->handshaked = false;

    val = gnutls_init (&sys->session, type);
    if (val != 0)
    {
        msg_Err (tls, "cannot initialize TLS session: %s",
                 gnutls_strerror (val));
        free (sys);
        return VLC_EGENERIC;
    }

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

    val = gnutls_priority_set_direct (sys->session, priorities, &errp);
    if (val < 0)
        msg_Err (tls, "cannot set TLS priorities \"%s\": %s", errp,
                 gnutls_strerror (val));
    free (priorities);
    if (val < 0)
        goto error;

    val = gnutls_credentials_set (sys->session, GNUTLS_CRD_CERTIFICATE, x509);
    if (val < 0)
    {
        msg_Err (tls, "cannot set TLS session credentials: %s",
                 gnutls_strerror (val));
        goto error;
    }

    gnutls_transport_set_ptr (sys->session,
                              (gnutls_transport_ptr_t)(intptr_t)fd);

    tls->sys = sys;
    tls->sock.p_sys = tls;
    tls->sock.pf_send = gnutls_Send;
    tls->sock.pf_recv = gnutls_Recv;
    return VLC_SUCCESS;

error:
    gnutls_SessionClose (tls);
    return VLC_EGENERIC;
}
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
223

224
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
225 226
 * Starts or continues the TLS handshake.
 *
Rémi Denis-Courmont's avatar
Typos  
Rémi Denis-Courmont committed
227
 * @return -1 on fatal error, 0 on successful handshake completion,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
228 229
 * 1 if more would-be blocking recv is needed,
 * 2 if more would-be blocking send is required.
230
 */
231
static int gnutls_ContinueHandshake (vlc_tls_t *tls)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
232
{
233
    vlc_tls_sys_t *sys = tls->sys;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
234 235
    int val;

236
#ifdef _WIN32
237
    WSASetLastError (0);
238
#endif
239 240 241
    do
    {
        val = gnutls_handshake (sys->session);
242 243 244 245 246 247 248 249 250 251 252
        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 */
                return 1 + gnutls_record_get_direction (sys->session);
        }
253
    }
254
    while (!gnutls_error_is_fatal (val));
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
255

256
#ifdef _WIN32
257
    msg_Dbg (tls, "Winsock error %d", WSAGetLastError ());
258
#endif
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
    msg_Err (tls, "TLS handshake error: %s", gnutls_strerror (val));
    return -1;
}

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;

    vlc_tls_sys_t *sys = tls->sys;

    /* minimum DH prime bits */
    gnutls_dh_set_prime_bits (sys->session, 1024);

    if (likely(hostname != NULL))
        /* fill Server Name Indication */
        gnutls_server_name_set (sys->session, GNUTLS_NAME_DNS,
                                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 */
    vlc_tls_sys_t *sys = tls->sys;
    unsigned status;

    val = gnutls_certificate_verify_peers3 (sys->session, host, &status);
    if (val)
    {
        msg_Err (tls, "Certificate verification error: %s",
                 gnutls_strerror (val));
299
        return -1;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
300
    }
301

302 303
    if (status == 0)
        goto success; /* Good certificate */
304

305 306
    /* Bad certificate */
    gnutls_datum_t desc;
307

308 309 310 311 312 313 314 315 316 317 318 319 320
    if (gnutls_certificate_verification_status_print(status,
                   gnutls_certificate_type_get (sys->session), &desc, 0) == 0)
    {
        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)
        return -1; /* Really bad certificate */
321

322
    /* Look up mismatching certificate in store */
323 324 325 326 327 328 329 330 331 332 333 334 335
    const gnutls_datum_t *datum;
    unsigned count;

    datum = gnutls_certificate_get_peers (sys->session, &count);
    if (datum == NULL || count == 0)
    {
        msg_Err (tls, "Peer certificate not available");
        return -1;
    }

    msg_Dbg (tls, "%u certificate(s) in the list", count);
    val = gnutls_verify_stored_pubkey (NULL, NULL, host, service,
                                       GNUTLS_CRT_X509, datum, 0);
336
    const char *msg;
337 338 339
    switch (val)
    {
        case 0:
340 341
            msg_Dbg (tls, "certificate key match for %s", host);
            goto success;
342
        case GNUTLS_E_NO_CERTIFICATE_FOUND:
343 344 345 346
            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.");
347 348
            break;
        case GNUTLS_E_CERTIFICATE_KEY_MISMATCH:
349 350 351 352
            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. ");
353 354
            break;
        default:
355
            msg_Err (tls, "certificate key match error for %s: %s", host,
356 357 358
                     gnutls_strerror (val));
            return -1;
    }
359

360 361 362 363 364 365 366
    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)
367
        return -1;
368 369 370 371 372 373 374 375 376 377 378 379 380

    gnutls_x509_crt_t cert;

    if (gnutls_x509_crt_init (&cert))
        return -1;
    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);
        return -1;
    }
    gnutls_x509_crt_deinit (cert);

381
    val = dialog_Question (tls, _("Insecure site"),
382 383 384 385
         _("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);
386 387
    gnutls_free (desc.data);

388 389 390 391 392 393 394
    time_t expiry = 0;
    switch (val)
    {
        case 2:
            time (&expiry);
            expiry += 24 * 60 * 60;
        case 3:
395 396 397
            val = gnutls_store_pubkey (NULL, NULL, host, service,
                                       GNUTLS_CRT_X509, datum, expiry, 0);
            if (val)
398
                msg_Err (tls, "cannot store X.509 certificate: %s",
399
                         gnutls_strerror (val));
400 401 402
            break;
        default:
            return -1;
403
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
404

405 406 407
success:
    sys->handshaked = true;
    return 0;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
408 409
}

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

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

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

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

436 437 438 439 440 441 442
    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;
443

444
    return VLC_SUCCESS;
445
}
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
446

447 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);

    gnutls_Deinit (VLC_OBJECT(crd));
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
454 455
}

456
#ifdef ENABLE_SOUT
457 458 459 460 461 462 463 464 465
/**
 * 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;

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

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

478 479
static int gnutls_ServerHandshake (vlc_tls_t *tls, const char *host,
                                   const char *service)
480
{
481 482 483
    int val = gnutls_ContinueHandshake (tls);
    if (val == 0)
        tls->sys->handshaked = true;
484

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

489
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
490
 * Allocates a whole server's TLS credentials.
491
 */
492
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
493 494 495
{
    int val;

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

499 500
    vlc_tls_creds_sys_t *sys = malloc (sizeof (*sys));
    if (unlikely(sys == NULL))
501
        goto error;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
502 503

    /* Sets server's credentials */
504 505
    val = gnutls_certificate_allocate_credentials (&sys->x509_cred);
    if (val != 0)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
506
    {
507
        msg_Err (crd, "cannot allocate credentials: %s",
508
                 gnutls_strerror (val));
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
509
        goto error;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
510 511
    }

512 513 514
    block_t *certblock = block_FilePath (cert);
    if (certblock == NULL)
    {
515 516
        msg_Err (crd, "cannot read certificate chain from %s: %s", cert,
                 vlc_strerror_c(errno));
517 518 519 520 521 522
        return VLC_EGENERIC;
    }

    block_t *keyblock = block_FilePath (key);
    if (keyblock == NULL)
    {
523 524
        msg_Err (crd, "cannot read private key from %s: %s", key,
                 vlc_strerror_c(errno));
525 526 527 528 529 530 531 532 533 534 535 536 537
        block_Release (certblock);
        return VLC_EGENERIC;
    }

    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,
538
                                                GNUTLS_X509_FMT_PEM);
539 540
    block_Release (keyblock);
    block_Release (certblock);
541
    if (val < 0)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
542
    {
543
        msg_Err (crd, "cannot load X.509 key: %s", gnutls_strerror (val));
544
        gnutls_certificate_free_credentials (sys->x509_cred);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
545
        goto error;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
546 547
    }

548
    /* FIXME:
549
     * - support other cipher suites
550
     */
551
    val = gnutls_dh_params_init (&sys->dh_params);
552 553
    if (val >= 0)
    {
554 555 556 557 558
        const gnutls_datum_t data = {
            .data = (unsigned char *)dh_params,
            .size = sizeof (dh_params) - 1,
        };

559
        val = gnutls_dh_params_import_pkcs3 (sys->dh_params, &data,
560 561
                                             GNUTLS_X509_FMT_PEM);
        if (val == 0)
562 563
            gnutls_certificate_set_dh_params (sys->x509_cred,
                                              sys->dh_params);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
564
    }
565
    if (val < 0)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
566
    {
567
        msg_Err (crd, "cannot initialize DHE cipher suites: %s",
568
                 gnutls_strerror (val));
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
569 570
    }

571 572
    crd->sys = sys;
    crd->open = gnutls_ServerSessionOpen;
573
    crd->handshake = gnutls_ServerHandshake;
574 575
    crd->close = gnutls_SessionClose;

576
    return VLC_SUCCESS;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
577 578

error:
579
    free (sys);
580
    gnutls_Deinit (VLC_OBJECT(crd));
581
    return VLC_EGENERIC;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
582 583
}

584
/**
585
 * Destroys a TLS server object.
586
 */
587
static void CloseServer (vlc_tls_creds_t *crd)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
588
{
589
    vlc_tls_creds_sys_t *sys = crd->sys;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
590

591
    /* all sessions depending on the server are now deinitialized */
592 593 594
    gnutls_certificate_free_credentials (sys->x509_cred);
    gnutls_dh_params_deinit (sys->dh_params);
    free (sys);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
595

596
    gnutls_Deinit (VLC_OBJECT(crd));
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
597
}
598
#endif
599

600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
#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)"),
};
618

619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
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 ()