# include "config.h"
#endif
+#include <stdlib.h>
+#include <string.h>
#include <time.h>
#include <errno.h>
#include <assert.h>
msg_Err (obj, "unsupported GnuTLS version");
return -1;
}
- msg_Dbg (p_this, "using GnuTLS verson %s", version);
+ msg_Dbg (obj, "using GnuTLS version %s", version);
return 0;
}
*/
static int gnutls_Init (vlc_object_t *obj)
{
- const char *version = gnutls_check_version ("3.1.9");
+ const char *version = gnutls_check_version ("3.1.11");
if (version == NULL)
{
msg_Err (obj, "unsupported GnuTLS version");
return -1;
}
- msg_Dbg (obj, "using GnuTLS verson %s", version);
+ msg_Dbg (obj, "using GnuTLS version %s", version);
if (gnutls_check_version ("3.3.0") == NULL)
{
}
static int gnutls_SessionOpen (vlc_tls_t *tls, int type,
- gnutls_certificate_credentials_t x509, int fd)
+ gnutls_certificate_credentials_t x509, int fd,
+ const char *const *alpn)
{
gnutls_session_t session;
const char *errp;
goto error;
}
+ if (alpn != NULL)
+ {
+ gnutls_datum_t *protv = NULL;
+ unsigned protc = 0;
+
+ while (*alpn != NULL)
+ {
+ gnutls_datum_t *n = realloc(protv, sizeof (*protv) * (protc + 1));
+ if (unlikely(n == NULL))
+ {
+ free(protv);
+ goto error;
+ }
+ protv = n;
+
+ protv[protc].data = (void *)*alpn;
+ protv[protc].size = strlen(*alpn);
+ protc++;
+ alpn++;
+ }
+
+ val = gnutls_alpn_set_protocols (session, protv, protc, 0);
+ free (protv);
+ }
+
gnutls_transport_set_int (session, fd);
tls->sys = session;
* 1 if more would-be blocking recv is needed,
* 2 if more would-be blocking send is required.
*/
-static int gnutls_ContinueHandshake (vlc_tls_t *tls)
+static int gnutls_ContinueHandshake (vlc_tls_t *tls, char **restrict alp)
{
gnutls_session_t session = tls->sys;
int val;
switch (val)
{
case GNUTLS_E_SUCCESS:
- return 0;
+ goto done;
case GNUTLS_E_AGAIN:
case GNUTLS_E_INTERRUPTED:
/* I/O event: return to caller's poll() loop */
#endif
msg_Err (tls, "TLS handshake error: %s", gnutls_strerror (val));
return -1;
+
+done:
+ if (alp != NULL)
+ {
+ gnutls_datum_t datum;
+
+ val = gnutls_alpn_get_selected_protocol (session, &datum);
+ if (val == 0)
+ {
+ if (memchr (datum.data, 0, datum.size) != NULL)
+ return -1; /* Other end is doing something fishy?! */
+
+ *alp = strndup ((char *)datum.data, datum.size);
+ if (unlikely(*alp == NULL))
+ return -1;
+ }
+ else
+ *alp = NULL;
+ }
+ return 0;
}
/**
}
static int gnutls_ClientSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls,
- int fd, const char *hostname)
+ int fd, const char *hostname,
+ const char *const *alpn)
{
- int val = gnutls_SessionOpen (tls, GNUTLS_CLIENT, crd->sys, fd);
+ int val = gnutls_SessionOpen (tls, GNUTLS_CLIENT, crd->sys, fd, alpn);
if (val != VLC_SUCCESS)
return val;
}
static int gnutls_ClientHandshake (vlc_tls_t *tls, const char *host,
- const char *service)
+ const char *service, char **restrict alp)
{
- int val = gnutls_ContinueHandshake (tls);
+ int val = gnutls_ContinueHandshake (tls, alp);
if (val)
return val;
* Initializes a server-side TLS session.
*/
static int gnutls_ServerSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls,
- int fd, const char *hostname)
+ int fd, const char *hostname,
+ const char *const *alpn)
{
vlc_tls_creds_sys_t *sys = crd->sys;
assert (hostname == NULL);
- return gnutls_SessionOpen (tls, GNUTLS_SERVER, sys->x509_cred, fd);
+ return gnutls_SessionOpen (tls, GNUTLS_SERVER, sys->x509_cred, fd, alpn);
}
static int gnutls_ServerHandshake (vlc_tls_t *tls, const char *host,
- const char *service)
+ const char *service, char **restrict alp)
{
- int val = gnutls_ContinueHandshake (tls);
+ int val = gnutls_ContinueHandshake (tls, alp);
if (val == 0)
tls->sock.p_sys = tls;
vlc_tls_creds_sys_t *sys = malloc (sizeof (*sys));
if (unlikely(sys == NULL))
- goto error;
+ {
+ gnutls_Deinit ();
+ return VLC_ENOMEM;
+ }
/* Sets server's credentials */
val = gnutls_certificate_allocate_credentials (&sys->x509_cred);
{
msg_Err (crd, "cannot allocate credentials: %s",
gnutls_strerror (val));
- goto error;
+ free (sys);
+ gnutls_Deinit ();
+ return VLC_ENOMEM;
}
block_t *certblock = block_FilePath (cert);
{
msg_Err (crd, "cannot read certificate chain from %s: %s", cert,
vlc_strerror_c(errno));
- return VLC_EGENERIC;
+ goto error;
}
block_t *keyblock = block_FilePath (key);
msg_Err (crd, "cannot read private key from %s: %s", key,
vlc_strerror_c(errno));
block_Release (certblock);
- return VLC_EGENERIC;
+ goto error;
}
gnutls_datum_t pub = {
return VLC_SUCCESS;
error:
+ gnutls_certificate_free_credentials (sys->x509_cred);
free (sys);
gnutls_Deinit ();
return VLC_EGENERIC;