From 153439d434bc914bcfaac403da84e3e9f0bf1367 Mon Sep 17 00:00:00 2001 From: defanor Date: Tue, 26 Sep 2023 19:32:24 +0300 Subject: Support OpenSSL for DTLS-SRTP --- README | 2 +- src/rexmpp.c | 2 +- src/rexmpp_jingle.c | 89 ++++++++-------- src/rexmpp_jingle.h | 4 - src/rexmpp_tls.c | 284 ++++++++++++++++++++++++++++++++++++++++++---------- src/rexmpp_tls.h | 13 ++- 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 #include -#include #include #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 #include #include +#include #include "config.h" @@ -20,35 +21,39 @@ #include #elif defined(USE_OPENSSL) #include +#include +#include #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 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, -- cgit v1.2.3