]> git.sesse.net Git - vlc/blob - src/network/tls.c
tls: allocate server session in core
[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 /**
40  * Allocates a whole server's TLS credentials.
41  *
42  * @param cert_path required (Unicode) path to an x509 certificate,
43  *                  if NULL, anonymous key exchange will be used.
44  * @param key_path (UTF-8) path to the PKCS private key for the certificate,
45  *                 if NULL; cert_path will be used.
46  *
47  * @return NULL on error.
48  */
49 vlc_tls_creds_t *
50 vlc_tls_ServerCreate (vlc_object_t *obj, const char *cert_path,
51                       const char *key_path)
52 {
53     vlc_tls_creds_t *srv = vlc_custom_create (obj, sizeof (*srv), "tls creds");
54     if (unlikely(srv == NULL))
55         return NULL;
56
57     var_Create (srv, "tls-x509-cert", VLC_VAR_STRING);
58     var_Create (srv, "tls-x509-key", VLC_VAR_STRING);
59
60     if (cert_path != NULL)
61     {
62         var_SetString (srv, "tls-x509-cert", cert_path);
63
64         if (key_path == NULL)
65             key_path = cert_path;
66         var_SetString (srv, "tls-x509-key", key_path);
67     }
68
69     srv->module = module_need (srv, "tls server", NULL, false );
70     if (srv->module == NULL)
71     {
72         msg_Err (srv, "TLS server plugin not available");
73         vlc_object_release (srv);
74         return NULL;
75     }
76
77     msg_Dbg (srv, "TLS server plugin initialized");
78     return srv;
79 }
80
81
82 /**
83  * Releases data allocated with vlc_tls_ServerCreate().
84  * @param srv TLS server object to be destroyed, or NULL
85  */
86 void vlc_tls_ServerDelete (vlc_tls_creds_t *srv)
87 {
88     if (srv == NULL)
89         return;
90
91     module_unneed (srv, srv->module);
92     vlc_object_release (srv);
93 }
94
95
96 /**
97  * Adds one or more certificate authorities from a file.
98  * @return -1 on error, 0 on success.
99  */
100 int vlc_tls_ServerAddCA (vlc_tls_creds_t *srv, const char *path)
101 {
102     return srv->add_CA (srv, path);
103 }
104
105
106 /**
107  * Adds one or more certificate revocation list from a file.
108  * @return -1 on error, 0 on success.
109  */
110 int vlc_tls_ServerAddCRL (vlc_tls_creds_t *srv, const char *path)
111 {
112     return srv->add_CRL (srv, path);
113 }
114
115
116 vlc_tls_t *vlc_tls_ServerSessionCreate (vlc_tls_creds_t *crd, int fd)
117 {
118     vlc_tls_t *session = vlc_custom_create (crd, sizeof (*session),
119                                             "tls server");
120     int val = crd->open (crd, session, fd);
121     if (val == VLC_SUCCESS)
122         return session;
123     vlc_object_release (session);
124     return NULL;
125 }
126
127
128 void vlc_tls_ServerSessionDelete (vlc_tls_t *session)
129 {
130     vlc_tls_creds_t *crd = (vlc_tls_creds_t *)(session->p_parent);
131
132     crd->close (crd, session);
133     vlc_object_release (session);
134 }
135
136
137 int vlc_tls_ServerSessionHandshake (vlc_tls_t *ses)
138 {
139     int val = ses->handshake (ses);
140     if (val < 0)
141         vlc_tls_ServerSessionDelete (ses);
142     return val;
143 }
144
145
146 /*** TLS client session ***/
147 /* TODO: cache certificates for the whole VLC instance lifetime */
148
149 static int tls_client_start(void *func, va_list ap)
150 {
151     int (*activate) (vlc_tls_t *, int fd, const char *hostname) = func;
152     vlc_tls_t *session = va_arg (ap, vlc_tls_t *);
153     int fd = va_arg (ap, int);
154     const char *hostname = va_arg (ap, const char *);
155
156     return activate (session, fd, hostname);
157 }
158
159 static void tls_client_stop(void *func, va_list ap)
160 {
161     void (*deactivate) (vlc_tls_t *) = func;
162     vlc_tls_t *session = va_arg (ap, vlc_tls_t *);
163
164     deactivate (session);
165 }
166
167 /**
168  * Allocates a client's TLS credentials and shakes hands through the network.
169  * This is a blocking network operation.
170  *
171  * @param fd stream socket through which to establish the secure communication
172  * layer.
173  * @param psz_hostname Server Name Indication to pass to the server, or NULL.
174  *
175  * @return NULL on error.
176  **/
177 vlc_tls_t *
178 vlc_tls_ClientCreate (vlc_object_t *obj, int fd, const char *hostname)
179 {
180     vlc_tls_t *cl = vlc_custom_create (obj, sizeof (*cl), "tls client");
181     if (unlikely(cl == NULL))
182         return NULL;
183
184     cl->u.module = vlc_module_load (cl, "tls client", NULL, false,
185                                     tls_client_start, cl, fd, hostname);
186     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     /* TODO: do this directly in the TLS plugin */
194     int val;
195     do
196         val = cl->handshake (cl);
197     while (val > 0);
198
199     if (val != 0)
200     {
201         msg_Err (cl, "TLS client session handshake error");
202         vlc_module_unload (cl->u.module, tls_client_stop, cl);
203         vlc_object_release (cl);
204         return NULL;
205     }
206     msg_Dbg (cl, "TLS client session initialized");
207     return cl;
208 }
209
210
211 /**
212  * Releases data allocated with vlc_tls_ClientCreate().
213  * It is your job to close the underlying socket.
214  */
215 void vlc_tls_ClientDelete (vlc_tls_t *cl)
216 {
217     if (cl == NULL)
218         return;
219
220     vlc_module_unload (cl->u.module, tls_client_stop, cl);
221     vlc_object_release (cl);
222 }