summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2023-09-26 19:32:24 +0300
committerdefanor <defanor@uberspace.net>2023-09-26 19:32:24 +0300
commit153439d434bc914bcfaac403da84e3e9f0bf1367 (patch)
tree9f71a2a9e6beb5cfc6483b84159e56b19a757637
parent7a63d327772dc64978e9159d49885a9ae7dd9b4e (diff)
Support OpenSSL for DTLS-SRTP
-rw-r--r--README2
-rw-r--r--src/rexmpp.c2
-rw-r--r--src/rexmpp_jingle.c89
-rw-r--r--src/rexmpp_jingle.h4
-rw-r--r--src/rexmpp_tls.c284
-rw-r--r--src/rexmpp_tls.h13
6 files changed, 283 insertions, 111 deletions
diff --git a/README b/README
index ba4e8dd..3f9f1b7 100644
--- a/README
+++ b/README
@@ -29,7 +29,7 @@ Optional dependencies:
For Jingle calls:
- libnice (with glib)
-- gnutls
+- gnutls or openssl
- libsrtp2
- portaudio
- opus (optional)
diff --git a/src/rexmpp.c b/src/rexmpp.c
index 435fda2..60d138f 100644
--- a/src/rexmpp.c
+++ b/src/rexmpp.c
@@ -2540,7 +2540,7 @@ rexmpp_err_t rexmpp_run (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
if (s->tcp_state == REXMPP_TCP_CONNECTED &&
s->stream_state == REXMPP_STREAM_CLOSED &&
s->tls_state == REXMPP_TLS_CLOSING) {
- rexmpp_tls_err_t err = rexmpp_tls_disconnect(s);
+ rexmpp_tls_err_t err = rexmpp_tls_disconnect(s, s->tls);
if (err == REXMPP_TLS_SUCCESS) {
s->tls_state = REXMPP_TLS_INACTIVE;
rexmpp_cleanup(s);
diff --git a/src/rexmpp_jingle.c b/src/rexmpp_jingle.c
index 848d787..42d0099 100644
--- a/src/rexmpp_jingle.c
+++ b/src/rexmpp_jingle.c
@@ -347,6 +347,10 @@ void rexmpp_jingle_session_destroy (rexmpp_jingle_session_t *session) {
comp->dtls_state == REXMPP_TLS_ACTIVE ||
comp->dtls_state == REXMPP_TLS_CLOSING ||
comp->dtls_state == REXMPP_TLS_CLOSED) {
+ if (comp->dtls_state == REXMPP_TLS_HANDSHAKE ||
+ comp->dtls_state == REXMPP_TLS_ACTIVE) {
+ rexmpp_tls_disconnect(comp->s, comp->dtls);
+ }
rexmpp_tls_session_free(comp->dtls);
rexmpp_tls_ctx_free(comp->dtls);
comp->dtls = NULL;
@@ -1015,14 +1019,9 @@ rexmpp_jingle_candidate_gathering_done_cb (NiceAgent *agent,
/* We'll need a fingerprint a bit later, but checking it before
allocating other things. */
-
- /* TODO: should use DTLS credentials, not regular TLS ones. Using
- these for now because DTLS ones are not allocated yet, and they
- are the same anyway. */
char fp[32], fp_str[32 * 3 + 1];
size_t fp_size = 32;
-
- if (rexmpp_tls_session_fp(sess->s, sess->s->tls, "sha-256", fp, fp_str, &fp_size)) {
+ if (rexmpp_tls_my_fp(sess->s, fp, fp_str, &fp_size)) {
return;
}
@@ -1247,35 +1246,9 @@ rexmpp_jingle_dtls_push_func (void *p, const void *data, size_t size)
comp->component_id, size, data);
}
-rexmpp_tls_err_t
-rexmpp_jingle_dtls_pull_func (void *p,
- void *data,
- size_t size,
- ssize_t *received)
-{
+rexmpp_tls_t *rexmpp_jingle_component_dtls(void *p) {
rexmpp_jingle_component_t *comp = p;
- char *tls_buf = comp->dtls->dtls_buf;
- size_t *tls_buf_len = &(comp->dtls->dtls_buf_len);
-
- rexmpp_tls_err_t ret = REXMPP_TLS_SUCCESS;
- if (*tls_buf_len > 0) {
- if (size >= *tls_buf_len) {
- memcpy(data, tls_buf, *tls_buf_len);
- *received = *tls_buf_len;
- *tls_buf_len = 0;
- } else {
- if (size > DTLS_SRTP_BUF_SIZE) {
- size = DTLS_SRTP_BUF_SIZE;
- }
- memcpy(data, tls_buf, size);
- memmove(tls_buf, tls_buf + size, DTLS_SRTP_BUF_SIZE - size);
- *received = size;
- *tls_buf_len = *tls_buf_len - size;
- }
- } else {
- ret = REXMPP_TLS_E_AGAIN;
- }
- return ret;
+ return comp->dtls;
}
/* The timeout is always zero for DTLS. */
@@ -1284,9 +1257,9 @@ int rexmpp_jingle_dtls_pull_timeout_func (void *p,
{
rexmpp_jingle_component_t *comp = p;
rexmpp_jingle_session_t *sess = comp->session;
- if (comp->dtls->dtls_buf_len > 0) {
- return comp->dtls->dtls_buf_len;
- }
+ /* if (comp->dtls->dtls_buf_len > 0) { */
+ /* return comp->dtls->dtls_buf_len; */
+ /* } */
fd_set rfds;
struct timeval tv;
@@ -1312,7 +1285,6 @@ int rexmpp_jingle_dtls_pull_timeout_func (void *p,
}
g_ptr_array_unref(sockets);
-
tv.tv_sec = ms / 1000;
tv.tv_usec = (ms % 1000) * 1000;
@@ -1605,12 +1577,7 @@ rexmpp_jingle_ice_recv_cb (NiceAgent *agent, guint stream_id, guint component_id
}
}
} else {
- if (comp->dtls->dtls_buf_len + len < DTLS_SRTP_BUF_SIZE) {
- memcpy(comp->dtls->dtls_buf + comp->dtls->dtls_buf_len, buf, len);
- comp->dtls->dtls_buf_len += len;
- } else {
- rexmpp_log(comp->s, LOG_WARNING, "Dropping a DTLS packet");
- }
+ rexmpp_dtls_feed(comp->s, comp->dtls, buf, len);
}
}
@@ -2206,8 +2173,9 @@ rexmpp_jingle_run (rexmpp_t *s,
#ifdef ENABLE_CALLS
rexmpp_jingle_session_t *sess;
int err;
- unsigned char client_sess_key[SRTP_AES_ICM_128_KEY_LEN_WSALT * 2],
- server_sess_key[SRTP_AES_ICM_128_KEY_LEN_WSALT * 2];
+ unsigned char key_mat[2 * (SRTP_AES_ICM_128_KEY_LEN_WSALT)],
+ client_sess_key[SRTP_AES_ICM_128_KEY_LEN_WSALT],
+ server_sess_key[SRTP_AES_ICM_128_KEY_LEN_WSALT];
for (sess = s->jingle->sessions; sess != NULL; sess = sess->next) {
char input[4096 + SRTP_MAX_TRAILER_LEN];
int input_len;
@@ -2290,7 +2258,20 @@ rexmpp_jingle_run (rexmpp_t *s,
rexmpp_tls_srtp_get_keys(s, comp->dtls,
SRTP_AES_128_KEY_LEN, SRTP_SALT_LEN,
- client_sess_key, server_sess_key);
+ key_mat);
+ /* client key */
+ memcpy(client_sess_key, key_mat, SRTP_AES_128_KEY_LEN);
+ /* server key */
+ memcpy(server_sess_key, key_mat + SRTP_AES_128_KEY_LEN,
+ SRTP_AES_128_KEY_LEN);
+ /* client salt */
+ memcpy(client_sess_key + SRTP_AES_128_KEY_LEN,
+ key_mat + SRTP_AES_128_KEY_LEN * 2,
+ SRTP_SALT_LEN);
+ /* server salt */
+ memcpy(server_sess_key + SRTP_AES_128_KEY_LEN,
+ key_mat + SRTP_AES_128_KEY_LEN * 2 + SRTP_SALT_LEN,
+ SRTP_SALT_LEN);
int active_role = rexmpp_jingle_dtls_is_active(sess, 0);
@@ -2342,7 +2323,19 @@ rexmpp_jingle_run (rexmpp_t *s,
/* Check on the DTLS session, too. */
if (comp->dtls_state == REXMPP_TLS_ACTIVE) {
ssize_t received;
- rexmpp_tls_recv(s, comp->dtls, input, 4096, &received);
+ rexmpp_tls_err_t err =
+ rexmpp_tls_recv(s, comp->dtls, input, 4096, &received);
+ if (err != REXMPP_TLS_SUCCESS && err != REXMPP_TLS_E_AGAIN) {
+ rexmpp_log(s, LOG_ERR,
+ "Error on rexmpp_tls_recv (component id %d), "
+ "terminating Jingle session %s",
+ comp->component_id, sess->sid);
+ rexmpp_jingle_session_terminate
+ (s, sess->sid,
+ rexmpp_xml_new_elem("connectivity-error", "urn:xmpp:jingle:1"),
+ "TLS reading error");
+ return REXMPP_E_TLS;
+ }
}
}
diff --git a/src/rexmpp_jingle.h b/src/rexmpp_jingle.h
index 57fe324..189614a 100644
--- a/src/rexmpp_jingle.h
+++ b/src/rexmpp_jingle.h
@@ -16,7 +16,6 @@
#ifdef ENABLE_CALLS
#include <glib.h>
#include <agent.h>
-#include <gnutls/gnutls.h>
#include <srtp2/srtp.h>
#include "portaudio.h"
#ifdef HAVE_OPUS
@@ -78,9 +77,6 @@ struct rexmpp_jingle_component {
rexmpp_jingle_session_t *session;
int component_id;
rexmpp_tls_t *dtls;
- /* gnutls_session_t dtls_session; */
- /* char dtls_buf[DTLS_SRTP_BUF_SIZE]; */
- /* size_t dtls_buf_len; */
enum tls_st dtls_state;
srtp_t srtp_in;
srtp_t srtp_out;
diff --git a/src/rexmpp_tls.c b/src/rexmpp_tls.c
index 803cae8..3d77927 100644
--- a/src/rexmpp_tls.c
+++ b/src/rexmpp_tls.c
@@ -9,6 +9,7 @@
#include <syslog.h>
#include <string.h>
#include <stdlib.h>
+#include <gcrypt.h>
#include "config.h"
@@ -20,35 +21,39 @@
#include <gnutls/dtls.h>
#elif defined(USE_OPENSSL)
#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/err.h>
#endif
#include "rexmpp.h"
#include "rexmpp_tls.h"
+rexmpp_tls_t *rexmpp_jingle_component_dtls(void *p);
ssize_t
rexmpp_jingle_dtls_push_func (void *p, const void *data, size_t size);
-rexmpp_tls_err_t
-rexmpp_jingle_dtls_pull_func (void *comp,
- void *data,
- size_t size,
- ssize_t *received);
int rexmpp_jingle_dtls_pull_timeout_func (void *p,
unsigned int ms);
#if defined(USE_OPENSSL)
-rexmpp_tls_err_t rexmpp_process_openssl_ret (rexmpp_t *s, int ret) {
- int err = SSL_get_error(s->tls->openssl_conn, ret);
- s->tls->openssl_direction = REXMPP_OPENSSL_NONE;
+rexmpp_tls_err_t rexmpp_process_openssl_ret (rexmpp_t *s,
+ rexmpp_tls_t *tls_ctx,
+ const char *func,
+ int ret)
+{
+ int err = SSL_get_error(tls_ctx->openssl_conn, ret);
+ tls_ctx->openssl_direction = REXMPP_OPENSSL_NONE;
if (ret == 1) {
return REXMPP_TLS_SUCCESS;
} else if (err == SSL_ERROR_WANT_READ) {
- s->tls->openssl_direction = REXMPP_OPENSSL_READ;
+ tls_ctx->openssl_direction = REXMPP_OPENSSL_READ;
return REXMPP_TLS_E_AGAIN;
} else if (err == SSL_ERROR_WANT_WRITE) {
- s->tls->openssl_direction = REXMPP_OPENSSL_WRITE;
+ tls_ctx->openssl_direction = REXMPP_OPENSSL_WRITE;
return REXMPP_TLS_E_AGAIN;
} else {
- rexmpp_log(s, LOG_ERR, "OpenSSL error %d", err);
+ rexmpp_log(s, LOG_ERR, "OpenSSL error %d (ret %d) in %s",
+ err, ret, func);
+ ERR_print_errors_fp(stderr);
return REXMPP_TLS_E_OTHER;
}
}
@@ -135,6 +140,12 @@ void rexmpp_tls_session_free (rexmpp_tls_t *tls_ctx) {
if (tls_ctx->openssl_conn != NULL) {
SSL_free(tls_ctx->openssl_conn);
tls_ctx->openssl_conn = NULL;
+ /* bio_conn is freed implicitly by SSL_free. */
+ tls_ctx->bio_conn = NULL;
+ }
+ if (tls_ctx->bio_io != NULL) {
+ BIO_free(tls_ctx->bio_io);
+ tls_ctx->bio_io = NULL;
}
tls_ctx->openssl_direction = REXMPP_OPENSSL_NONE;
#else
@@ -162,19 +173,64 @@ rexmpp_dtls_jingle_pull_func_gnutls (gnutls_transport_ptr_t p,
void *data,
size_t size)
{
- rexmpp_jingle_component_t *comp = p;
+ rexmpp_tls_t *tls_ctx = rexmpp_jingle_component_dtls(p);
ssize_t received;
- rexmpp_tls_err_t err =
- rexmpp_jingle_dtls_pull_func(comp, data, size, &received);
- if (err == REXMPP_TLS_SUCCESS) {
+
+ char *tls_buf = tls_ctx->dtls_buf;
+ size_t *tls_buf_len = &(tls_ctx->dtls_buf_len);
+
+ rexmpp_tls_err_t ret = REXMPP_TLS_SUCCESS;
+ if (*tls_buf_len > 0) {
+ if (size >= *tls_buf_len) {
+ memcpy(data, tls_buf, *tls_buf_len);
+ received = *tls_buf_len;
+ *tls_buf_len = 0;
+ } else {
+ if (size > DTLS_SRTP_BUF_SIZE) {
+ size = DTLS_SRTP_BUF_SIZE;
+ }
+ memcpy(data, tls_buf, size);
+ memmove(tls_buf, tls_buf + size, DTLS_SRTP_BUF_SIZE - size);
+ received = size;
+ *tls_buf_len = *tls_buf_len - size;
+ }
+ } else {
+ ret = REXMPP_TLS_E_AGAIN;
+ }
+
+ if (ret == REXMPP_TLS_SUCCESS) {
return received;
- } else if (err == REXMPP_TLS_E_AGAIN) {
- gnutls_transport_set_errno(comp->dtls->gnutls_session, EAGAIN);
+ } else if (ret == REXMPP_TLS_E_AGAIN) {
+ gnutls_transport_set_errno(tls_ctx->gnutls_session, EAGAIN);
}
return -1;
}
#endif
+#if defined(USE_OPENSSL)
+long rexmpp_dtls_openssl_bio_cb(BIO *b, int oper, const char *argp,
+ size_t len, int argi,
+ long argl, int ret, size_t *processed) {
+ (void)argi;
+ (void)argl;
+ (void)processed;
+ if (oper == BIO_CB_WRITE) {
+ rexmpp_jingle_dtls_push_func(BIO_get_callback_arg(b), argp, len);
+ }
+ return ret;
+}
+#endif
+
+#if defined(USE_OPENSSL)
+int rexmpp_openssl_verify_accept_all (int preverify_ok,
+ X509_STORE_CTX *x509_ctx)
+{
+ (void)preverify_ok;
+ (void)x509_ctx;
+ return 1;
+}
+#endif
+
rexmpp_tls_err_t
rexmpp_dtls_connect (rexmpp_t *s,
rexmpp_tls_t *tls_ctx,
@@ -195,15 +251,48 @@ rexmpp_dtls_connect (rexmpp_t *s,
tls_ctx->gnutls_cred);
gnutls_transport_set_ptr(*tls_session, user_data);
- gnutls_transport_set_push_function(*tls_session, rexmpp_jingle_dtls_push_func);
- gnutls_transport_set_pull_function(*tls_session, rexmpp_dtls_jingle_pull_func_gnutls);
- gnutls_transport_set_pull_timeout_function(*tls_session,
- rexmpp_jingle_dtls_pull_timeout_func);
+ gnutls_transport_set_push_function
+ (*tls_session, rexmpp_jingle_dtls_push_func);
+ gnutls_transport_set_pull_function
+ (*tls_session, rexmpp_dtls_jingle_pull_func_gnutls);
+ gnutls_transport_set_pull_timeout_function
+ (*tls_session, rexmpp_jingle_dtls_pull_timeout_func);
/* todo: use the profile/crypto-suite from <crypto/> element */
gnutls_srtp_set_profile(*tls_session, GNUTLS_SRTP_AES128_CM_HMAC_SHA1_80);
return REXMPP_TLS_SUCCESS;
+#elif defined(USE_OPENSSL)
+ (void)client;
+ int err;
+ /* Setup credentials */
+ rexmpp_tls_set_x509_key_file(s, tls_ctx, NULL, NULL);
+ /* Create a connection. */
+ tls_ctx->openssl_conn = SSL_new(tls_ctx->openssl_ctx);
+ SSL_set_verify(tls_ctx->openssl_conn,
+ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ rexmpp_openssl_verify_accept_all);
+ /* Set a BIO */
+ BIO_new_bio_pair(&(tls_ctx->bio_conn), 4096, &(tls_ctx->bio_io), 4096);
+ BIO_up_ref(tls_ctx->bio_conn);
+ SSL_set0_rbio(tls_ctx->openssl_conn, tls_ctx->bio_conn);
+ SSL_set0_wbio(tls_ctx->openssl_conn, tls_ctx->bio_conn);
+ /* Set a callback to track writes */
+ BIO_set_callback_ex(tls_ctx->bio_conn, rexmpp_dtls_openssl_bio_cb);
+ BIO_set_callback_arg(tls_ctx->bio_conn, user_data);
+ BIO_set_ssl(tls_ctx->bio_conn, tls_ctx->openssl_conn, BIO_NOCLOSE);
+ /* Enable SRTP (TODO: support different profiles) */
+ err = SSL_set_tlsext_use_srtp(tls_ctx->openssl_conn,
+ "SRTP_AES128_CM_SHA1_80");
+ if (err) {
+ rexmpp_log(s, LOG_ERR, "Failed to setup SRTP for the DTLS connection");
+ return REXMPP_TLS_E_OTHER;
+ }
+ if (client) {
+ err = SSL_connect(tls_ctx->openssl_conn);
+ } else {
+ err = SSL_accept(tls_ctx->openssl_conn);
+ }
+ return rexmpp_process_openssl_ret(s, tls_ctx, "rexmpp_dtls_connect", err);
#else
- /* TODO: OpenSSL */
(void)s;
(void)tls_ctx;
(void)user_data;
@@ -212,6 +301,25 @@ rexmpp_dtls_connect (rexmpp_t *s,
#endif
}
+void rexmpp_dtls_feed(rexmpp_t *s, rexmpp_tls_t *tls_ctx, uint8_t *buf, size_t len) {
+#if defined(USE_GNUTLS)
+ if (tls_ctx->dtls_buf_len + len < DTLS_SRTP_BUF_SIZE) {
+ memcpy(tls_ctx->dtls_buf + tls_ctx->dtls_buf_len, buf, len);
+ tls_ctx->dtls_buf_len += len;
+ } else {
+ rexmpp_log(s, LOG_WARNING, "Dropping a DTLS packet");
+ }
+#elif defined(USE_OPENSSL)
+ (void)s;
+ BIO_write(tls_ctx->bio_io, buf, len);
+#else
+ (void)s;
+ (void)tls_ctx;
+ (void)buf;
+ (void)len;
+#endif
+}
+
rexmpp_tls_err_t rexmpp_tls_handshake (rexmpp_t *s, rexmpp_tls_t *tls_ctx) {
#if defined(USE_GNUTLS)
int ret = gnutls_handshake(tls_ctx->gnutls_session);
@@ -224,11 +332,12 @@ rexmpp_tls_err_t rexmpp_tls_handshake (rexmpp_t *s, rexmpp_tls_t *tls_ctx) {
gnutls_strerror(ret));
return REXMPP_TLS_E_OTHER;
}
+#elif defined(USE_OPENSSL)
+ return rexmpp_process_openssl_ret(s, tls_ctx, "rexmpp_tls_handshake",
+ SSL_do_handshake(tls_ctx->openssl_conn));
#else
(void)s;
(void)tls_ctx;
- /* TODO: OpenSSL */
- /* SSL_do_handshake */
return REXMPP_TLS_E_OTHER;
#endif
}
@@ -381,7 +490,8 @@ rexmpp_tls_connect (rexmpp_t *s) {
return REXMPP_TLS_E_OTHER;
}
}
- return rexmpp_process_openssl_ret(s, SSL_connect(s->tls->openssl_conn));
+ return rexmpp_process_openssl_ret(s, s->tls, "rexmpp_tls_connect",
+ SSL_connect(s->tls->openssl_conn));
#else
rexmpp_log(s, LOG_ERR, "rexmpp is compiled without TLS support");
return REXMPP_TLS_E_OTHER;
@@ -389,9 +499,9 @@ rexmpp_tls_connect (rexmpp_t *s) {
}
rexmpp_tls_err_t
-rexmpp_tls_disconnect (rexmpp_t *s) {
+rexmpp_tls_disconnect (rexmpp_t *s, rexmpp_tls_t *tls_ctx) {
#if defined(USE_GNUTLS)
- int ret = gnutls_bye(s->tls->gnutls_session, GNUTLS_SHUT_RDWR);
+ int ret = gnutls_bye(tls_ctx->gnutls_session, GNUTLS_SHUT_RDWR);
if (ret == GNUTLS_E_SUCCESS) {
return REXMPP_TLS_SUCCESS;
} else {
@@ -400,12 +510,13 @@ rexmpp_tls_disconnect (rexmpp_t *s) {
return REXMPP_TLS_E_OTHER;
}
#elif defined(USE_OPENSSL)
- int ret = SSL_shutdown(s->tls->openssl_conn);
+ int ret = SSL_shutdown(tls_ctx->openssl_conn);
if (ret == 0) {
- s->tls->openssl_direction = REXMPP_OPENSSL_READ;
+ tls_ctx->openssl_direction = REXMPP_OPENSSL_READ;
return REXMPP_TLS_E_AGAIN;
} else {
- return rexmpp_process_openssl_ret(s, ret);
+ return rexmpp_process_openssl_ret(s, tls_ctx,
+ "rexmpp_tls_disconnect", ret);
}
#else
rexmpp_log(s, LOG_ERR, "rexmpp is compiled without TLS support");
@@ -418,27 +529,31 @@ rexmpp_tls_srtp_get_keys (rexmpp_t *s,
rexmpp_tls_t *tls_ctx,
size_t key_len,
size_t salt_len,
- unsigned char *client_key_wsalt,
- unsigned char *server_key_wsalt)
+ unsigned char *key_mat)
{
#if defined(USE_GNUTLS)
int key_mat_size;
- char key_mat[4096];
- gnutls_datum_t client_key, client_salt, server_key, server_salt;
key_mat_size =
gnutls_srtp_get_keys(tls_ctx->gnutls_session,
key_mat, (key_len + salt_len) * 2,
- &client_key, &client_salt,
- &server_key, &server_salt);
- rexmpp_log(s, LOG_DEBUG, "SRTP key material size: %d",
- key_mat_size);
- memcpy(client_key_wsalt, client_key.data, key_len);
- memcpy(client_key_wsalt + key_len, client_salt.data, salt_len);
- memcpy(server_key_wsalt, server_key.data, key_len);
- memcpy(server_key_wsalt + key_len, server_salt.data, salt_len);
+ NULL, NULL, NULL, NULL);
+ if (key_mat_size == GNUTLS_E_SHORT_MEMORY_BUFFER ||
+ key_mat_size < 0) {
+ rexmpp_log(s, LOG_ERR,
+ "Failed to retrieve DTLS key material for SRTP: %s",
+ gnutls_strerror(key_mat_size));
+ }
return 0;
+#elif defined(USE_OPENSSL)
+ /* https://www.rfc-editor.org/rfc/rfc5764.html */
+ const char *extractor = "EXTRACTOR-dtls_srtp";
+ int err = SSL_export_keying_material(tls_ctx->openssl_conn,
+ key_mat, 2 * (key_len + salt_len),
+ extractor, strlen(extractor),
+ NULL, 0, 0);
+ return rexmpp_process_openssl_ret(s, tls_ctx,
+ "rexmpp_tls_srtp_get_keys", err);
#else
- /* TODO: OpenSSL */
(void)s;
(void)tls_ctx;
(void)key_len;
@@ -477,7 +592,7 @@ rexmpp_tls_send (rexmpp_t *s,
if (ret > 0) {
return REXMPP_TLS_SUCCESS;
} else {
- return rexmpp_process_openssl_ret(s, ret);
+ return rexmpp_process_openssl_ret(s, tls_ctx, "rexmpp_tls_send", ret);
}
#else
(void)data;
@@ -514,7 +629,7 @@ rexmpp_tls_recv (rexmpp_t *s,
if (ret > 0) {
return REXMPP_TLS_SUCCESS;
} else {
- return rexmpp_process_openssl_ret(s, ret);
+ return rexmpp_process_openssl_ret(s, tls_ctx, "rexmpp_tls_recv", ret);
}
#else
(void)data;
@@ -581,7 +696,7 @@ rexmpp_tls_set_x509_key_file (rexmpp_t *s,
int ret = gnutls_certificate_set_x509_key_file(tls_ctx->gnutls_cred,
cert_file,
key_file,
- GNUTLS_X509_FMT_PEM);
+ GNUTLS_X509_FMT_DER);
if (ret == 0) {
return REXMPP_TLS_SUCCESS;
} else {
@@ -592,13 +707,13 @@ rexmpp_tls_set_x509_key_file (rexmpp_t *s,
#elif defined(USE_OPENSSL)
if (SSL_CTX_use_certificate_file(tls_ctx->openssl_ctx,
cert_file,
- SSL_FILETYPE_PEM) != 1) {
+ SSL_FILETYPE_ASN1) != 1) {
rexmpp_log(s, LOG_ERR, "Failed to set a certificate file");
return REXMPP_TLS_E_OTHER;
}
if (SSL_CTX_use_PrivateKey_file(tls_ctx->openssl_ctx,
key_file,
- SSL_FILETYPE_PEM) != 1) {
+ SSL_FILETYPE_ASN1) != 1) {
rexmpp_log(s, LOG_ERR, "Failed to set a key file");
return REXMPP_TLS_E_OTHER;
}
@@ -626,7 +741,7 @@ rexmpp_tls_set_x509_trust_file (rexmpp_t *s,
#if defined(USE_GNUTLS)
gnutls_certificate_set_x509_trust_file(tls_ctx->gnutls_cred,
trust_file,
- GNUTLS_X509_FMT_PEM);
+ GNUTLS_X509_FMT_DER);
return REXMPP_TLS_SUCCESS;
#elif defined(USE_OPENSSL)
if (SSL_CTX_load_verify_locations(tls_ctx->openssl_ctx, trust_file, NULL) != 1) {
@@ -662,18 +777,82 @@ int rexmpp_tls_peer_fp (rexmpp_t *s,
}
return rexmpp_x509_raw_cert_fp(s, algo_str, cert_list,
raw_fp, fp_str, fp_size);
+#elif defined(USE_OPENSSL)
+ if (strcmp(algo_str, "sha-256") != 0) {
+ rexmpp_log(s, LOG_ERR,
+ "Unsupported hash function algorithm: %s", algo_str);
+ return -1;
+ }
+ X509 *peer_cert = SSL_get0_peer_certificate(tls_ctx->openssl_conn);
+ if (peer_cert == NULL) {
+ rexmpp_log(s, LOG_ERR, "No peer certificate found");
+ return -1;
+ }
+ unsigned int len;
+ X509_digest(peer_cert, EVP_sha256(), (unsigned char*)raw_fp, &len);
+ *fp_size = len;
+ size_t i;
+ for (i = 0; i < *fp_size; i++) {
+ snprintf(fp_str + i * 3, 4, "%02X:", raw_fp[i] & 0xFF);
+ }
+ fp_str[*fp_size * 3 - 1] = 0;
+ return 0;
#else
- /* TODO: OpenSSL */
(void)s;
(void)tls_ctx;
(void)algo_str;
(void)raw_fp;
(void)fp_str;
(void)fp_size;
- return -1;
#endif
}
+/* TODO: handle different algorithms, and maybe apply this to
+ arbitrary files. */
+int rexmpp_tls_my_fp (rexmpp_t *s,
+ char *raw_fp,
+ char *fp_str,
+ size_t *fp_size)
+{
+ gcry_md_hd_t hd;
+ gcry_error_t err = gcry_md_open(&hd, GCRY_MD_SHA256, 0);
+ if (err != GPG_ERR_NO_ERROR) {
+ rexmpp_log(s, LOG_ERR, "Failed to create an MD object: %s",
+ gcry_strerror(err));
+ return -1;
+ }
+
+ if (s->x509_cert_file == NULL) {
+ rexmpp_log(s, LOG_WARNING, "No X.509 certificate file defined");
+ return -1;
+ }
+ FILE *fh = fopen(s->x509_cert_file, "r");
+ if (fh == NULL) {
+ rexmpp_log(s, LOG_ERR, "Failed to open the X.509 certificate file");
+ return -1;
+ }
+ unsigned char *buf[4096];
+ size_t len = fread(buf, 1, 4096, fh);
+ while (len > 0) {
+ gcry_md_write(hd, buf, len);
+ len = fread(buf, 1, 4096, fh);
+ }
+ gcry_md_final(hd);
+ fclose(fh);
+
+ *fp_size = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
+
+ memcpy(raw_fp, gcry_md_read(hd, GCRY_MD_SHA256), *fp_size);
+
+ size_t i;
+ for (i = 0; i < (*fp_size); i++) {
+ snprintf(fp_str + i * 3, 4, "%02X:", raw_fp[i] & 0xFF);
+ }
+ fp_str[(*fp_size) * 3 - 1] = 0;
+ gcry_md_close(hd);
+ return 0;
+}
+
int rexmpp_tls_session_fp (rexmpp_t *s,
rexmpp_tls_t *tls_ctx,
const char *algo_str,
@@ -703,7 +882,6 @@ int rexmpp_tls_session_fp (rexmpp_t *s,
gnutls_free(cert_list);
return err;
#else
- /* TODO: OpenSSL */
(void)s;
(void)tls_ctx;
(void)algo_str;
@@ -733,7 +911,6 @@ int rexmpp_x509_cert_fp (rexmpp_t *s,
gnutls_free(raw_cert.data);
return err;
#else
- /* TODO: OpenSSL */
(void)s;
(void)algo_str;
(void)cert;
@@ -790,7 +967,6 @@ int rexmpp_x509_raw_cert_fp (rexmpp_t *s,
}
return 0;
#else
- /* TODO: OpenSSL */
(void)s;
(void)algo_str;
(void)raw_cert;
diff --git a/src/rexmpp_tls.h b/src/rexmpp_tls.h
index 3c16049..4a966ca 100644
--- a/src/rexmpp_tls.h
+++ b/src/rexmpp_tls.h
@@ -58,6 +58,8 @@ enum rexmpp_openssl_direction {
struct rexmpp_tls {
SSL_CTX *openssl_ctx;
SSL *openssl_conn;
+ BIO *bio_conn;
+ BIO *bio_io;
enum rexmpp_openssl_direction openssl_direction;
};
#else
@@ -77,20 +79,20 @@ void rexmpp_tls_session_free (rexmpp_tls_t *tls_ctx);
rexmpp_tls_err_t rexmpp_tls_connect (rexmpp_t *s);
rexmpp_tls_err_t rexmpp_tls_handshake (rexmpp_t *s, rexmpp_tls_t *tls_ctx);
-rexmpp_tls_err_t rexmpp_tls_disconnect (rexmpp_t *s);
+rexmpp_tls_err_t rexmpp_tls_disconnect (rexmpp_t *s, rexmpp_tls_t *tls_ctx);
rexmpp_tls_err_t
rexmpp_dtls_connect (rexmpp_t *s,
rexmpp_tls_t *tls_ctx,
void *user_data,
int client);
+void rexmpp_dtls_feed(rexmpp_t *s, rexmpp_tls_t *tls_ctx, uint8_t *buf, size_t len);
int
rexmpp_tls_srtp_get_keys (rexmpp_t *s,
rexmpp_tls_t *tls_ctx,
size_t key_len,
size_t salt_len,
- unsigned char *client_key_wsalt,
- unsigned char *server_key_wsalt);
+ unsigned char *key_mat);
rexmpp_tls_err_t
rexmpp_tls_send (rexmpp_t *s,
@@ -130,6 +132,11 @@ int rexmpp_tls_peer_fp (rexmpp_t *s,
char *fp_str,
size_t *fp_size);
+int rexmpp_tls_my_fp (rexmpp_t *s,
+ char *raw_fp,
+ char *fp_str,
+ size_t *fp_size);
+
int rexmpp_tls_session_fp (rexmpp_t *s,
rexmpp_tls_t *tls_ctx,
const char *algo_str,