tls.c 5.95 KB
Newer Older
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1 2 3
/*****************************************************************************
 * tls.c
 *****************************************************************************
4
 * Copyright © 2004-2007 Rémi Denis-Courmont
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
5
 * $Id$
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
6
 *
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
7
 * Authors: Rémi Denis-Courmont <rem # videolan.org>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
8
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
9 10 11
 * This program is free software; you can redistribute it and/or modify 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
12 13 14 15
 * (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
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
18
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
19 20 21
 * You should have received a copy of the GNU Lesser 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
22 23
 *****************************************************************************/

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
24 25 26 27 28
/**
 * @file
 * libvlc interface to the Transport Layer Security (TLS) plugins.
 */

29 30 31 32
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33
#include <vlc_common.h>
34
#include "libvlc.h"
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
35

Clément Stenac's avatar
Clément Stenac committed
36
#include <vlc_tls.h>
37
#include <vlc_modules.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
38

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
39
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
40
 * Allocates a whole server's TLS credentials.
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
41
 *
42 43 44 45
 * @param cert_path required (Unicode) path to an x509 certificate,
 *                  if NULL, anonymous key exchange will be used.
 * @param key_path (UTF-8) path to the PKCS private key for the certificate,
 *                 if NULL; cert_path will be used.
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
46 47 48
 *
 * @return NULL on error.
 */
49 50 51
vlc_tls_creds_t *
vlc_tls_ServerCreate (vlc_object_t *obj, const char *cert_path,
                      const char *key_path)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
52
{
53 54
    vlc_tls_creds_t *srv = vlc_custom_create (obj, sizeof (*srv), "tls creds");
    if (unlikely(srv == NULL))
55
        return NULL;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
56

57 58
    var_Create (srv, "tls-x509-cert", VLC_VAR_STRING);
    var_Create (srv, "tls-x509-key", VLC_VAR_STRING);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
59

60
    if (cert_path != NULL)
61
    {
62 63 64 65 66
        var_SetString (srv, "tls-x509-cert", cert_path);

        if (key_path == NULL)
            key_path = cert_path;
        var_SetString (srv, "tls-x509-key", key_path);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
67 68
    }

69 70
    srv->module = module_need (srv, "tls server", NULL, false );
    if (srv->module == NULL)
71 72
    {
        msg_Err (srv, "TLS server plugin not available");
73
        vlc_object_release (srv);
74 75 76 77 78
        return NULL;
    }

    msg_Dbg (srv, "TLS server plugin initialized");
    return srv;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
79 80 81
}


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
82
/**
83
 * Releases data allocated with vlc_tls_ServerCreate().
84
 * @param srv TLS server object to be destroyed, or NULL
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
85
 */
86
void vlc_tls_ServerDelete (vlc_tls_creds_t *srv)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
87
{
88 89
    if (srv == NULL)
        return;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
90

91
    module_unneed (srv, srv->module);
92
    vlc_object_release (srv);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
93 94
}

95

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
96 97 98 99
/**
 * Adds one or more certificate authorities from a file.
 * @return -1 on error, 0 on success.
 */
100
int vlc_tls_ServerAddCA (vlc_tls_creds_t *srv, const char *path)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
101
{
102
    return srv->add_CA (srv, path);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
103 104 105 106 107 108 109
}


/**
 * Adds one or more certificate revocation list from a file.
 * @return -1 on error, 0 on success.
 */
110
int vlc_tls_ServerAddCRL (vlc_tls_creds_t *srv, const char *path)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
111
{
112
    return srv->add_CRL (srv, path);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
113 114 115
}


116
vlc_tls_t *vlc_tls_ServerSessionCreate (vlc_tls_creds_t *crd, int fd)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
117
{
118 119 120 121 122 123 124
    vlc_tls_t *session = vlc_custom_create (crd, sizeof (*session),
                                            "tls server");
    int val = crd->open (crd, session, fd);
    if (val == VLC_SUCCESS)
        return session;
    vlc_object_release (session);
    return NULL;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
125 126 127
}


128
void vlc_tls_ServerSessionDelete (vlc_tls_t *session)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
129
{
130 131 132 133
    vlc_tls_creds_t *crd = (vlc_tls_creds_t *)(session->p_parent);

    crd->close (crd, session);
    vlc_object_release (session);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
134 135 136
}


137
int vlc_tls_ServerSessionHandshake (vlc_tls_t *ses)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
138
{
139
    int val = ses->handshake (ses);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
140
    if (val < 0)
141
        vlc_tls_ServerSessionDelete (ses);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
142 143 144 145
    return val;
}


146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
/*** TLS client session ***/
/* TODO: cache certificates for the whole VLC instance lifetime */

static int tls_client_start(void *func, va_list ap)
{
    int (*activate) (vlc_tls_t *, int fd, const char *hostname) = func;
    vlc_tls_t *session = va_arg (ap, vlc_tls_t *);
    int fd = va_arg (ap, int);
    const char *hostname = va_arg (ap, const char *);

    return activate (session, fd, hostname);
}

static void tls_client_stop(void *func, va_list ap)
{
    void (*deactivate) (vlc_tls_t *) = func;
    vlc_tls_t *session = va_arg (ap, vlc_tls_t *);

    deactivate (session);
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
167
/**
168
 * Allocates a client's TLS credentials and shakes hands through the network.
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
169 170 171 172 173 174 175 176
 * This is a blocking network operation.
 *
 * @param fd stream socket through which to establish the secure communication
 * layer.
 * @param psz_hostname Server Name Indication to pass to the server, or NULL.
 *
 * @return NULL on error.
 **/
177 178
vlc_tls_t *
vlc_tls_ClientCreate (vlc_object_t *obj, int fd, const char *hostname)
179
{
180 181
    vlc_tls_t *cl = vlc_custom_create (obj, sizeof (*cl), "tls client");
    if (unlikely(cl == NULL))
182
        return NULL;
183

184 185 186
    cl->u.module = vlc_module_load (cl, "tls client", NULL, false,
                                    tls_client_start, cl, fd, hostname);
    if (cl->u.module == NULL)
187 188
    {
        msg_Err (cl, "TLS client plugin not available");
189
        vlc_object_release (cl);
190
        return NULL;
191 192
    }

193 194
    /* TODO: do this directly in the TLS plugin */
    int val;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
195
    do
196
        val = cl->handshake (cl);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
197
    while (val > 0);
198

199
    if (val != 0)
200
    {
201 202 203 204
        msg_Err (cl, "TLS client session handshake error");
        vlc_module_unload (cl->u.module, tls_client_stop, cl);
        vlc_object_release (cl);
        return NULL;
205
    }
206 207
    msg_Dbg (cl, "TLS client session initialized");
    return cl;
208 209 210
}


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
211
/**
212
 * Releases data allocated with vlc_tls_ClientCreate().
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
213 214
 * It is your job to close the underlying socket.
 */
215
void vlc_tls_ClientDelete (vlc_tls_t *cl)
216
{
217 218
    if (cl == NULL)
        return;
219

220
    vlc_module_unload (cl->u.module, tls_client_stop, cl);
221
    vlc_object_release (cl);
222
}