Commit 2c1bb0b7 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

tls: accept abstract transport layer stream for client sessions

Instead of a socket file descriptor, client sessions are now run on
top of an abstract I/O stream. This enables e.g. TLS over TLS, which
would be required for HTTPS through HTTPS proxy.
parent 32c3a603
/***************************************************************************** /*****************************************************************************
* vlc_tls.h: Transport Layer Security API * vlc_tls.h: Transport Layer Security API
***************************************************************************** *****************************************************************************
* Copyright (C) 2004-2011 Rémi Denis-Courmont * Copyright (C) 2004-2016 Rémi Denis-Courmont
* Copyright (C) 2005-2006 VLC authors and VideoLAN * Copyright (C) 2005-2006 VLC authors and VideoLAN
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
...@@ -53,25 +53,33 @@ struct vlc_tls ...@@ -53,25 +53,33 @@ struct vlc_tls
/** /**
* Initiates a client TLS session. * Initiates a client TLS session.
* *
* Performs client side of TLS handshake through a connected socket, and * Initiates a Transport Layer Security (TLS) session as the client side, using
* establishes a secure channel. This is a blocking network operation and may * trusted root CAs previously loaded with vlc_tls_ClientCreate().
* be a thread cancellation point.
* *
* @param fd socket through which to establish the secure channel * This is a blocking network operation and may be a thread cancellation point.
*
* @param creds X.509 credentials, i.e. set of root certificates of trusted
* certificate authorities
* @param sock socket through which to establish the secure channel
* @param hostname expected server name, used both as Server Name Indication * @param hostname expected server name, used both as Server Name Indication
* and as expected Common Name of the peer certificate * and as expected Common Name of the peer certificate [IN]
* @param service unique identifier for the service to connect to * @param service unique identifier for the service to connect to
* (only used locally for certificates database) * (only used locally for certificates database) [IN]
* @param alpn NULL-terminated list of Application Layer Protocols * @param alpn NULL-terminated list of Application Layer Protocols
* to negotiate, or NULL to not negotiate protocols * to negotiate, or NULL to not negotiate protocols [IN]
* @param alp storage space for the negotiated Application Layer * @param alp storage space for the negotiated Application Layer
* Protocol or NULL if negotiation was not performed[OUT] * Protocol or NULL if negotiation was not performed [OUT]
*
* @note The credentials must remain valid until the session is finished.
* *
* @return TLS session, or NULL on error. * @return TLS session, or NULL on error.
**/ **/
VLC_API vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *, int fd, VLC_API vlc_tls_t *vlc_tls_ClientSessionCreate(vlc_tls_creds_t *creds,
const char *host, const char *service, vlc_tls_t *sock,
const char *const *alpn, char **alp); const char *host,
const char *service,
const char *const *alpn,
char **alp);
/** /**
* Creates a TLS server session. * Creates a TLS server session.
...@@ -224,6 +232,23 @@ VLC_API void vlc_tls_Delete (vlc_tls_creds_t *); ...@@ -224,6 +232,23 @@ VLC_API void vlc_tls_Delete (vlc_tls_creds_t *);
*/ */
VLC_API vlc_tls_t *vlc_tls_SocketOpen(vlc_object_t *obj, int fd); VLC_API vlc_tls_t *vlc_tls_SocketOpen(vlc_object_t *obj, int fd);
VLC_DEPRECATED
static inline vlc_tls_t *
vlc_tls_ClientSessionCreateFD(vlc_tls_creds_t *crd, int fd, const char *host,
const char *srv, const char *const *lp, char **p)
{
vlc_tls_t *sock = vlc_tls_SocketOpen(VLC_OBJECT(crd), fd);
if (unlikely(sock == NULL))
return NULL;
vlc_tls_t *tls = vlc_tls_ClientSessionCreate(crd, sock, host, srv, lp, p);
if (unlikely(tls == NULL))
vlc_tls_SessionDelete(sock);
else
tls->p = sock;
return tls;
}
/** @} */ /** @} */
#endif #endif
...@@ -309,10 +309,10 @@ static int createCmdTLS( vlc_object_t *p_access, access_sys_t *p_sys, int fd, ...@@ -309,10 +309,10 @@ static int createCmdTLS( vlc_object_t *p_access, access_sys_t *p_sys, int fd,
const char *psz_session_name ) const char *psz_session_name )
{ {
/* TLS/SSL handshake */ /* TLS/SSL handshake */
p_sys->cmd.p_tls = vlc_tls_ClientSessionCreate( p_sys->p_creds, fd, p_sys->cmd.p_tls = vlc_tls_ClientSessionCreateFD( p_sys->p_creds, fd,
p_sys->url.psz_host, p_sys->url.psz_host,
psz_session_name, psz_session_name,
NULL, NULL ); NULL, NULL );
if( p_sys->cmd.p_tls == NULL ) if( p_sys->cmd.p_tls == NULL )
{ {
msg_Err( p_access, "cannot establish FTP/TLS session on command channel" ); msg_Err( p_access, "cannot establish FTP/TLS session on command channel" );
...@@ -1118,7 +1118,7 @@ static int ftp_StartStream( vlc_object_t *p_access, access_sys_t *p_sys, ...@@ -1118,7 +1118,7 @@ static int ftp_StartStream( vlc_object_t *p_access, access_sys_t *p_sys,
{ {
/* FIXME: Do Reuse TLS Session */ /* FIXME: Do Reuse TLS Session */
/* TLS/SSL handshake */ /* TLS/SSL handshake */
p_sys->data.p_tls = vlc_tls_ClientSessionCreate( p_sys->p_creds, p_sys->data.p_tls = vlc_tls_ClientSessionCreateFD( p_sys->p_creds,
p_sys->data.fd, p_sys->url.psz_host, p_sys->data.fd, p_sys->url.psz_host,
( p_sys->tlsmode == EXPLICIT ) ? "ftpes-data" ( p_sys->tlsmode == EXPLICIT ) ? "ftpes-data"
: "ftps-data", : "ftps-data",
......
...@@ -1005,9 +1005,9 @@ static int Connect( access_t *p_access, uint64_t i_tell ) ...@@ -1005,9 +1005,9 @@ static int Connect( access_t *p_access, uint64_t i_tell )
/* TLS/SSL handshake */ /* TLS/SSL handshake */
const char *alpn[] = { "http/1.1", NULL }; const char *alpn[] = { "http/1.1", NULL };
p_sys->p_tls = vlc_tls_ClientSessionCreate( p_sys->p_creds, p_sys->fd, p_sys->p_tls = vlc_tls_ClientSessionCreateFD( p_sys->p_creds, p_sys->fd,
p_sys->url.psz_host, p_sys->url.psz_host,
"https", alpn, NULL ); "https", alpn, NULL );
if( p_sys->p_tls == NULL ) if( p_sys->p_tls == NULL )
{ {
msg_Err( p_access, "cannot establish HTTP/TLS session" ); msg_Err( p_access, "cannot establish HTTP/TLS session" );
......
...@@ -135,7 +135,7 @@ vlc_tls_t *vlc_https_connect(vlc_tls_creds_t *creds, const char *name, ...@@ -135,7 +135,7 @@ vlc_tls_t *vlc_https_connect(vlc_tls_creds_t *creds, const char *name,
const char *alpn[] = { "h2", "http/1.1", NULL }; const char *alpn[] = { "h2", "http/1.1", NULL };
char *alp; char *alp;
vlc_tls_t *tls = vlc_tls_ClientSessionCreate(creds, fd, name, "https", vlc_tls_t *tls = vlc_tls_ClientSessionCreateFD(creds, fd, name, "https",
alpn, &alp); alpn, &alp);
if (tls == NULL) if (tls == NULL)
{ {
......
...@@ -168,7 +168,7 @@ vlc_tls_t *vlc_https_connect_proxy(vlc_tls_creds_t *creds, ...@@ -168,7 +168,7 @@ vlc_tls_t *vlc_https_connect_proxy(vlc_tls_creds_t *creds,
session->close = vlc_http_tls_close_ignore; session->close = vlc_http_tls_close_ignore;
vlc_http_msg_destroy(resp); /* <- session is destroyed here */ vlc_http_msg_destroy(resp); /* <- session is destroyed here */
session = vlc_tls_ClientSessionCreate(creds, fd, hostname, "https", alpn, session = vlc_tls_ClientSessionCreateFD(creds, fd, hostname, "https", alpn,
&alp); &alp);
#endif #endif
if (session == NULL) if (session == NULL)
......
...@@ -120,7 +120,7 @@ bool TLSSocket::connect(vlc_object_t *stream, const std::string &hostname, int p ...@@ -120,7 +120,7 @@ bool TLSSocket::connect(vlc_object_t *stream, const std::string &hostname, int p
return false; return false;
} }
tls = vlc_tls_ClientSessionCreate(creds, netfd, hostname.c_str(), "https", NULL, NULL); tls = vlc_tls_ClientSessionCreateFD(creds, netfd, hostname.c_str(), "https", NULL, NULL);
if(!tls) if(!tls)
{ {
disconnect(); disconnect();
......
...@@ -126,7 +126,7 @@ int intf_sys_t::connectChromecast(char *psz_ipChromecast) ...@@ -126,7 +126,7 @@ int intf_sys_t::connectChromecast(char *psz_ipChromecast)
return -1; return -1;
} }
p_tls = vlc_tls_ClientSessionCreate(p_creds, fd, psz_ipChromecast, p_tls = vlc_tls_ClientSessionCreateFD(p_creds, fd, psz_ipChromecast,
"tcps", NULL, NULL); "tcps", NULL, NULL);
if (p_tls == NULL) if (p_tls == NULL)
......
/***************************************************************************** /*****************************************************************************
* tls.c * tls.c
***************************************************************************** *****************************************************************************
* Copyright © 2004-2007 Rémi Denis-Courmont * Copyright © 2004-2016 Rémi Denis-Courmont
* $Id$ * $Id$
* *
* Authors: Rémi Denis-Courmont <rem # videolan.org>
*
* This program is free software; you can redistribute it and/or modify it * 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 * 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 * the Free Software Foundation; either version 2.1 of the License, or
...@@ -128,23 +126,17 @@ void vlc_tls_Delete (vlc_tls_creds_t *crd) ...@@ -128,23 +126,17 @@ void vlc_tls_Delete (vlc_tls_creds_t *crd)
/*** TLS session ***/ /*** TLS session ***/
static vlc_tls_t *vlc_tls_SessionCreate(vlc_tls_creds_t *crd, int fd, static vlc_tls_t *vlc_tls_SessionCreate(vlc_tls_creds_t *crd,
vlc_tls_t *sock,
const char *host, const char *host,
const char *const *alpn) const char *const *alpn)
{ {
vlc_tls_t *sock = vlc_tls_SocketOpen(VLC_OBJECT(crd), fd);
if (unlikely(sock == NULL))
return NULL;
vlc_tls_t *session = malloc(sizeof (*session)); vlc_tls_t *session = malloc(sizeof (*session));
if (unlikely(session == NULL)) if (unlikely(session == NULL))
{
vlc_tls_SessionDelete(sock);
return NULL; return NULL;
}
session->obj = crd->p_parent; session->obj = crd->p_parent;
session->p = sock; session->p = NULL;
int canc = vlc_savecancel(); int canc = vlc_savecancel();
...@@ -180,13 +172,14 @@ static void cleanup_tls(void *data) ...@@ -180,13 +172,14 @@ static void cleanup_tls(void *data)
vlc_tls_SessionDelete (session); vlc_tls_SessionDelete (session);
} }
vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *crd, int fd, #undef vlc_tls_ClientSessionCreate
const char *host, const char *service, vlc_tls_t *vlc_tls_ClientSessionCreate(vlc_tls_creds_t *crd, vlc_tls_t *sock,
const char *const *alpn, char **alp) const char *host, const char *service,
const char *const *alpn, char **alp)
{ {
int val; int val;
vlc_tls_t *session = vlc_tls_SessionCreate(crd, fd, host, alpn); vlc_tls_t *session = vlc_tls_SessionCreate(crd, sock, host, alpn);
if (session == NULL) if (session == NULL)
return NULL; return NULL;
...@@ -195,7 +188,7 @@ vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *crd, int fd, ...@@ -195,7 +188,7 @@ vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *crd, int fd,
deadline += var_InheritInteger (crd, "ipv4-timeout") * 1000; deadline += var_InheritInteger (crd, "ipv4-timeout") * 1000;
struct pollfd ufd[1]; struct pollfd ufd[1];
ufd[0].fd = fd; ufd[0].fd = vlc_tls_GetFD(sock);
vlc_cleanup_push (cleanup_tls, session); vlc_cleanup_push (cleanup_tls, session);
while ((val = crd->handshake(crd, session, host, service, alp)) != 0) while ((val = crd->handshake(crd, session, host, service, alp)) != 0)
...@@ -233,7 +226,16 @@ error: ...@@ -233,7 +226,16 @@ error:
vlc_tls_t *vlc_tls_ServerSessionCreate(vlc_tls_creds_t *crd, int fd, vlc_tls_t *vlc_tls_ServerSessionCreate(vlc_tls_creds_t *crd, int fd,
const char *const *alpn) const char *const *alpn)
{ {
return vlc_tls_SessionCreate(crd, fd, NULL, alpn); vlc_tls_t *sock = vlc_tls_SocketOpen(VLC_OBJECT(crd), fd);
if (unlikely(sock == NULL))
return NULL;
vlc_tls_t *tls = vlc_tls_SessionCreate(crd, sock, NULL, alpn);
if (unlikely(tls == NULL))
vlc_tls_SessionDelete(sock);
else
tls->p = sock;
return tls;
} }
ssize_t vlc_tls_Read(vlc_tls_t *session, void *buf, size_t len, bool waitall) ssize_t vlc_tls_Read(vlc_tls_t *session, void *buf, size_t len, bool waitall)
......
...@@ -119,7 +119,7 @@ static int securepair(vlc_thread_t *th, vlc_tls_t **restrict client, ...@@ -119,7 +119,7 @@ static int securepair(vlc_thread_t *th, vlc_tls_t **restrict client,
val = vlc_clone(th, tls_echo, server, VLC_THREAD_PRIORITY_LOW); val = vlc_clone(th, tls_echo, server, VLC_THREAD_PRIORITY_LOW);
assert(val == 0); assert(val == 0);
*client = vlc_tls_ClientSessionCreate(client_creds, insecurev[1], *client = vlc_tls_ClientSessionCreateFD(client_creds, insecurev[1],
"localhost", "vlc-tls-test", "localhost", "vlc-tls-test",
alpnv[1], alp); alpnv[1], alp);
if (*client == NULL) if (*client == NULL)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment