]> git.sesse.net Git - vlc/blob - src/network/tls.c
tls: keep credentials when HTTP reconnects
[vlc] / src / network / tls.c
1 /*****************************************************************************
2  * tls.c
3  *****************************************************************************
4  * Copyright © 2004-2007 Rémi Denis-Courmont
5  * $Id$
6  *
7  * Authors: Rémi Denis-Courmont <rem # videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /**
25  * @file
26  * libvlc interface to the Transport Layer Security (TLS) plugins.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include "libvlc.h"
35
36 #include <vlc_tls.h>
37 #include <vlc_modules.h>
38
39 /*** TLS credentials ***/
40
41 static int tls_server_load(void *func, va_list ap)
42 {
43     int (*activate) (vlc_tls_creds_t *, const char *, const char *) = func;
44     vlc_tls_creds_t *crd = va_arg (ap, vlc_tls_creds_t *);
45     const char *cert = va_arg (ap, const char *);
46     const char *key = va_arg (ap, const char *);
47
48     return activate (crd, cert, key);
49 }
50
51 static int tls_client_load(void *func, va_list ap)
52 {
53     int (*activate) (vlc_tls_creds_t *) = func;
54     vlc_tls_creds_t *crd = va_arg (ap, vlc_tls_creds_t *);
55
56     return activate (crd);
57 }
58
59 static void tls_unload(void *func, va_list ap)
60 {
61     void (*deactivate) (vlc_tls_creds_t *) = func;
62     vlc_tls_creds_t *crd = va_arg (ap, vlc_tls_creds_t *);
63
64     deactivate (crd);
65 }
66
67 /**
68  * Allocates a whole server's TLS credentials.
69  *
70  * @param cert_path required (Unicode) path to an x509 certificate,
71  *                  if NULL, anonymous key exchange will be used.
72  * @param key_path (UTF-8) path to the PKCS private key for the certificate,
73  *                 if NULL; cert_path will be used.
74  *
75  * @return NULL on error.
76  */
77 vlc_tls_creds_t *
78 vlc_tls_ServerCreate (vlc_object_t *obj, const char *cert_path,
79                       const char *key_path)
80 {
81     vlc_tls_creds_t *srv = vlc_custom_create (obj, sizeof (*srv),
82                                               "tls server");
83     if (unlikely(srv == NULL))
84         return NULL;
85
86     if (key_path == NULL)
87         key_path = cert_path;
88
89     srv->module = vlc_module_load (srv, "tls server", NULL, false,
90                                    tls_server_load, srv, cert_path, key_path);
91     if (srv->module == NULL)
92     {
93         msg_Err (srv, "TLS server plugin not available");
94         vlc_object_release (srv);
95         return NULL;
96     }
97
98     return srv;
99 }
100
101 /**
102  * Allocates TLS credentials for a client.
103  * Credentials can be cached and reused across multiple TLS sessions.
104  *
105  * @return TLS credentials object, or NULL on error.
106  **/
107 vlc_tls_creds_t *vlc_tls_ClientCreate (vlc_object_t *obj)
108 {
109     vlc_tls_creds_t *crd = vlc_custom_create (obj, sizeof (*crd),
110                                               "tls client");
111     if (unlikely(crd == NULL))
112         return NULL;
113
114     crd->module = vlc_module_load (crd, "tls client", NULL, false,
115                                    tls_client_load, crd);
116     if (crd->module == NULL)
117     {
118         msg_Err (crd, "TLS client plugin not available");
119         vlc_object_release (crd);
120         return NULL;
121     }
122
123     return crd;
124 }
125
126 /**
127  * Releases data allocated with vlc_tls_ClientCreate() or
128  * vlc_tls_ServerCreate().
129  * @param srv TLS server object to be destroyed, or NULL
130  */
131 void vlc_tls_Delete (vlc_tls_creds_t *crd)
132 {
133     if (crd == NULL)
134         return;
135
136     vlc_module_unload (crd->module, tls_unload, crd);
137     vlc_object_release (crd);
138 }
139
140
141 /**
142  * Adds one or more certificate authorities from a file.
143  * @return -1 on error, 0 on success.
144  */
145 int vlc_tls_ServerAddCA (vlc_tls_creds_t *srv, const char *path)
146 {
147     return srv->add_CA (srv, path);
148 }
149
150
151 /**
152  * Adds one or more certificate revocation list from a file.
153  * @return -1 on error, 0 on success.
154  */
155 int vlc_tls_ServerAddCRL (vlc_tls_creds_t *srv, const char *path)
156 {
157     return srv->add_CRL (srv, path);
158 }
159
160
161 /*** TLS  session ***/
162
163 static vlc_tls_t *vlc_tls_SessionCreate (vlc_tls_creds_t *crd, int fd,
164                                          const char *hostname)
165 {
166     vlc_tls_t *session = vlc_custom_create (crd, sizeof (*session),
167                                             "tls session");
168     int val = crd->open (crd, session, fd, hostname);
169     if (val == VLC_SUCCESS)
170         return session;
171     vlc_object_release (session);
172     return NULL;
173 }
174
175 void vlc_tls_SessionDelete (vlc_tls_t *session)
176 {
177     vlc_tls_creds_t *crd = (vlc_tls_creds_t *)(session->p_parent);
178
179     crd->close (crd, session);
180     vlc_object_release (session);
181 }
182
183 vlc_tls_t *vlc_tls_ServerSessionCreate (vlc_tls_creds_t *crd, int fd)
184 {
185     return vlc_tls_SessionCreate (crd, fd, NULL);
186 }
187
188 int vlc_tls_ServerSessionHandshake (vlc_tls_t *ses)
189 {
190     int val = ses->handshake (ses);
191     if (val < 0)
192         vlc_tls_ServerSessionDelete (ses);
193     return val;
194 }
195
196 /**
197  * Performs client side of TLS handshake through a connected socket, and
198  * establishes a secure channel. This is a blocking network operation.
199  *
200  * @param fd stream socket through which to establish the secure communication
201  * layer.
202  * @param hostname expected server name, used both as Server Name Indication
203  *                 and as expected Common Name of the peer's certificate.
204  *
205  * @return NULL on error.
206  **/
207 vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *crd, int fd,
208                                         const char *hostname)
209 {
210     vlc_tls_t *session = vlc_tls_SessionCreate (crd, fd, hostname);
211     if (session == NULL)
212         return NULL;
213
214     /* TODO: do this directly in the TLS plugin */
215     int val;
216     do
217         val = session->handshake (session);
218     while (val > 0);
219
220     if (val != 0)
221     {
222         msg_Err (session, "TLS client session handshake error");
223         vlc_tls_SessionDelete (session);
224         session = NULL;
225     }
226     return session;
227 }