From 5b5eb4e1000ab9f941904a2b9cdae2965f880d89 Mon Sep 17 00:00:00 2001 From: "Alfred E. Heggestad" Date: Wed, 18 Jun 2014 23:09:46 +0200 Subject: dtls_srtp: use DTLS-api from libre v0.4.9 for the dtls_srtp module to compile, you now need libre v0.4.9 or later. also added note about dependency to libre v0.4.9 in README and Debian file --- modules/dtls_srtp/dtls.c | 212 ++--------------------- modules/dtls_srtp/dtls_srtp.c | 243 +++++++++++++++++--------- modules/dtls_srtp/dtls_srtp.h | 40 +---- modules/dtls_srtp/module.mk | 2 +- modules/dtls_srtp/srtp.c | 51 +++--- modules/dtls_srtp/tls_udp.c | 395 ------------------------------------------ 6 files changed, 213 insertions(+), 730 deletions(-) delete mode 100644 modules/dtls_srtp/tls_udp.c (limited to 'modules/dtls_srtp') diff --git a/modules/dtls_srtp/dtls.c b/modules/dtls_srtp/dtls.c index e502903..6b517f2 100644 --- a/modules/dtls_srtp/dtls.c +++ b/modules/dtls_srtp/dtls.c @@ -3,205 +3,27 @@ * * Copyright (C) 2010 Creytiv.com */ -#define OPENSSL_NO_KRB5 1 -#include -#include -#include + #include #include #include "dtls_srtp.h" -/* note: shadow struct in libre's tls module */ -struct tls { - SSL_CTX *ctx; - char *pass; /* password for private key */ - /* ... */ - EVP_PKEY *key; - X509 *x; -}; - - -static void destructor(void *data) -{ - struct tls *tls = data; - - if (tls->ctx) - SSL_CTX_free(tls->ctx); - - if (tls->x) - X509_free(tls->x); - if (tls->key) - EVP_PKEY_free(tls->key); - - mem_deref(tls->pass); -} - - -static int cert_generate(X509 *x, EVP_PKEY *privkey, const char *aor, - int expire_days) -{ - X509_EXTENSION *ext; - X509_NAME *subj; - int ret; - int err = ENOMEM; - - subj = X509_NAME_new(); - if (!subj) - goto out; - - X509_set_version(x, 2); - - ASN1_INTEGER_set(X509_get_serialNumber(x), rand_u32()); - - ret = X509_NAME_add_entry_by_txt(subj, "CN", MBSTRING_ASC, - (unsigned char *)aor, - (int)strlen(aor), -1, 0); - if (!ret) - goto out; - - if (!X509_set_issuer_name(x, subj) || - !X509_set_subject_name(x, subj)) - goto out; - - X509_gmtime_adj(X509_get_notBefore(x), 0); - X509_gmtime_adj(X509_get_notAfter(x), 60*60*24*expire_days); - - if (!X509_set_pubkey(x, privkey)) - goto out; - - ext = X509V3_EXT_conf_nid(NULL, NULL, - NID_basic_constraints, "CA:FALSE"); - if (1 != X509_add_ext(x, ext, -1)) - goto out; - X509_EXTENSION_free(ext); - - err = 0; - - out: - if (subj) - X509_NAME_free(subj); - - return err; -} - - -static int tls_gen_selfsigned_cert(struct tls *tls, const char *aor) -{ - RSA *rsa; - int err = ENOMEM; - - rsa = RSA_generate_key(1024, RSA_F4, NULL, NULL); - if (!rsa) - goto out; - - tls->key = EVP_PKEY_new(); - if (!tls->key) - goto out; - if (!EVP_PKEY_set1_RSA(tls->key, rsa)) - goto out; - - tls->x = X509_new(); - if (!tls->x) - goto out; - - if (cert_generate(tls->x, tls->key, aor, 365)) - goto out; - - /* Sign the certificate */ - if (!X509_sign(tls->x, tls->key, EVP_sha1())) - goto out; - - err = 0; - - out: - if (rsa) - RSA_free(rsa); - - return err; -} - - -int dtls_alloc_selfsigned(struct tls **tlsp, const char *aor, - const char *srtp_profiles) -{ - struct tls *tls; - int r, err; - - if (!tlsp || !aor) - return EINVAL; - - tls = mem_zalloc(sizeof(*tls), destructor); - if (!tls) - return ENOMEM; - - SSL_library_init(); - - tls->ctx = SSL_CTX_new(DTLSv1_method()); - if (!tls->ctx) { - err = ENOMEM; - goto out; - } - -#if (OPENSSL_VERSION_NUMBER < 0x00905100L) - SSL_CTX_set_verify_depth(tls->ctx, 1); -#endif - - SSL_CTX_set_read_ahead(tls->ctx, 1); - - /* Generate self-signed certificate */ - err = tls_gen_selfsigned_cert(tls, aor); - if (err) { - warning("dtls: failed to generate certificate (%s): %m\n", - aor, err); - goto out; - } - - r = SSL_CTX_use_certificate(tls->ctx, tls->x); - if (r != 1) { - err = EINVAL; - goto out; - } - - r = SSL_CTX_use_PrivateKey(tls->ctx, tls->key); - if (r != 1) { - err = EINVAL; - goto out; - } - - if (0 != SSL_CTX_set_tlsext_use_srtp(tls->ctx, srtp_profiles)) { - warning("dtls: could not enable SRTP for profiles '%s'\n", - srtp_profiles); - err = ENOSYS; - goto out; - } - - err = 0; - out: - if (err) - mem_deref(tls); - else - *tlsp = tls; - - return err; -} - - int dtls_print_sha1_fingerprint(struct re_printf *pf, const struct tls *tls) { - uint8_t md[64]; - unsigned int i, len; + uint8_t md[20]; + unsigned int i; int err = 0; - if (!pf || !tls) + if (!tls) return EINVAL; - len = sizeof(md); - if (1 != X509_digest(tls->x, EVP_sha1(), md, &len)) - return ENOENT; + err = tls_fingerprint(tls, TLS_FINGERPRINT_SHA1, md, sizeof(md)); + if (err) + return err; - for (i=0; ix, EVP_sha256(), md, &len)) - return ENOENT; + err = tls_fingerprint(tls, TLS_FINGERPRINT_SHA256, md, sizeof(md)); + if (err) + return err; - for (i=0; itmr); for (i=0; i<2; i++) { - struct sock *s = &st->sockv[i]; - - mem_deref(s->uh_srtp); - mem_deref(s->dtls); - mem_deref(s->app_sock); /* must be freed last */ - mem_deref(s->tx); - mem_deref(s->rx); + struct comp *c = &st->compv[i]; + + mem_deref(c->uh_srtp); + mem_deref(c->tls_conn); + mem_deref(c->dtls_sock); + mem_deref(c->app_sock); /* must be freed last */ + mem_deref(c->tx); + mem_deref(c->rx); } mem_deref(st->sdpm); @@ -87,75 +88,52 @@ static void destructor(void *arg) static bool verify_fingerprint(const struct sdp_session *sess, const struct sdp_media *media, - struct dtls_flow *tc) + struct tls_conn *tc) { struct pl hash; - char hashstr[32]; - uint8_t md_sdp[64]; + uint8_t md_sdp[32], md_dtls[32]; size_t sz_sdp = sizeof(md_sdp); - struct tls_fingerprint tls_fp; + size_t sz_dtls; + enum tls_fingerprint type; + int err; if (sdp_fingerprint_decode(sdp_rattr(sess, media, "fingerprint"), &hash, md_sdp, &sz_sdp)) return false; - pl_strcpy(&hash, hashstr, sizeof(hashstr)); + if (0 == pl_strcasecmp(&hash, "sha-1")) { + type = TLS_FINGERPRINT_SHA1; + sz_dtls = 20; + } + else if (0 == pl_strcasecmp(&hash, "sha-256")) { + type = TLS_FINGERPRINT_SHA256; + sz_dtls = 32; + } + else { + warning("dtls_srtp: unknown fingerprint '%r'\n", &hash); + return false; + } - if (dtls_get_remote_fingerprint(tc, hashstr, &tls_fp)) { - warning("dtls_srtp: could not get DTLS fingerprint\n"); + err = tls_peer_fingerprint(tc, type, md_dtls, sizeof(md_dtls)); + if (err) { + warning("dtls_srtp: could not get DTLS fingerprint (%m)\n", + err); return false; } - if (sz_sdp != tls_fp.len || 0 != memcmp(md_sdp, tls_fp.md, sz_sdp)) { - warning("dtls_srtp: %s fingerprint mismatch\n", hashstr); - info("DTLS: %w\n", tls_fp.md, (size_t)tls_fp.len); + if (sz_sdp != sz_dtls || 0 != memcmp(md_sdp, md_dtls, sz_sdp)) { + warning("dtls_srtp: %r fingerprint mismatch\n", &hash); info("SDP: %w\n", md_sdp, sz_sdp); + info("DTLS: %w\n", md_dtls, sz_dtls); return false; } - info("dtls_srtp: verified %s fingerprint OK\n", hashstr); + info("dtls_srtp: verified %r fingerprint OK\n", &hash); return true; } -static void dtls_established_handler(int err, struct dtls_flow *flow, - const char *profile, - const struct key *client_key, - const struct key *server_key, - void *arg) -{ - struct sock *sock = arg; - const struct dtls_srtp *ds = sock->ds; - - if (!verify_fingerprint(ds->sess->sdp, ds->sdpm, flow)) { - warning("dtls_srtp: could not verify remote fingerprint\n"); - if (ds->sess->errorh) - ds->sess->errorh(EPIPE, ds->sess->arg); - return; - } - - sock->negotiated = true; - - info("dtls_srtp: ---> DTLS-SRTP complete (%s/%s) Profile=%s\n", - sdp_media_name(ds->sdpm), - sock->is_rtp ? "RTP" : "RTCP", profile); - - err |= srtp_stream_add(&sock->tx, profile, - ds->active ? client_key : server_key, - true); - - err |= srtp_stream_add(&sock->rx, profile, - ds->active ? server_key : client_key, - false); - - err |= srtp_install(sock); - if (err) { - warning("dtls_srtp: srtp_install: %m\n", err); - } -} - - static int session_alloc(struct menc_sess **sessp, struct sdp_session *sdp, bool offerer, menc_error_h *errorh, void *arg) @@ -170,10 +148,10 @@ static int session_alloc(struct menc_sess **sessp, if (!sess) return ENOMEM; - sess->sdp = mem_ref(sdp); + sess->sdp = mem_ref(sdp); sess->offerer = offerer; - sess->errorh = errorh; - sess->arg = arg; + sess->errorh = errorh; + sess->arg = arg; /* RFC 4145 */ err = sdp_session_set_lattr(sdp, true, "setup", @@ -197,27 +175,113 @@ static int session_alloc(struct menc_sess **sessp, } -static int media_start_sock(struct sock *sock, struct sdp_media *sdpm) +static void dtls_estab_handler(void *arg) +{ + struct comp *comp = arg; + const struct dtls_srtp *ds = comp->ds; + enum srtp_suite suite; + uint8_t cli_key[30], srv_key[30]; + int err; + + if (!verify_fingerprint(ds->sess->sdp, ds->sdpm, comp->tls_conn)) { + warning("dtls_srtp: could not verify remote fingerprint\n"); + if (ds->sess->errorh) + ds->sess->errorh(EPIPE, ds->sess->arg); + return; + } + + err = tls_srtp_keyinfo(comp->tls_conn, &suite, + cli_key, sizeof(cli_key), + srv_key, sizeof(srv_key)); + if (err) { + warning("dtls_srtp: could not get SRTP keyinfo (%m)\n", err); + return; + } + + comp->negotiated = true; + + info("dtls_srtp: ---> DTLS-SRTP complete (%s/%s) Profile=%s\n", + sdp_media_name(ds->sdpm), + comp->is_rtp ? "RTP" : "RTCP", srtp_suite_name(suite)); + + err |= srtp_stream_add(&comp->tx, suite, + ds->active ? cli_key : srv_key, 30, true); + err |= srtp_stream_add(&comp->rx, suite, + ds->active ? srv_key : cli_key, 30, false); + + err |= srtp_install(comp); + if (err) { + warning("dtls_srtp: srtp_install: %m\n", err); + } + + /* todo: notify application that crypto is up and running */ +} + + +static void dtls_close_handler(int err, void *arg) +{ + struct comp *comp = arg; + + info("dtls_srtp: dtls-connection closed (%m)\n", err); + + if (!comp->negotiated) { + + if (comp->ds->sess->errorh) + comp->ds->sess->errorh(err, comp->ds->sess->arg); + } +} + + +static void dtls_conn_handler(const struct sa *peer, void *arg) +{ + struct comp *comp = arg; + int err; + (void)peer; + + err = dtls_accept(&comp->tls_conn, tls, comp->dtls_sock, + dtls_estab_handler, NULL, dtls_close_handler, comp); + if (err) { + warning("dtls_srtp: dtls_accept failed (%m)\n", err); + return; + } +} + + +static int component_start(struct comp *comp, struct sdp_media *sdpm) { struct sa raddr; int err = 0; - if (!sock->app_sock || sock->negotiated || sock->dtls) + if (!comp->app_sock || comp->negotiated || comp->dtls_sock) return 0; - if (sock->is_rtp) + if (comp->is_rtp) raddr = *sdp_media_raddr(sdpm); else sdp_media_raddr_rtcp(sdpm, &raddr); - if (sa_isset(&raddr, SA_ALL)) { + err = dtls_listen(&comp->dtls_sock, NULL, + comp->app_sock, 2, LAYER_DTLS, + dtls_conn_handler, comp); + if (err) { + warning("dtls_srtp: dtls_listen failed (%m)\n", err); + return err; + } - err = dtls_flow_alloc(&sock->dtls, tls, sock->app_sock, - dtls_established_handler, sock); - if (err) - return err; + if (sa_isset(&raddr, SA_ALL)) { - err = dtls_flow_start(sock->dtls, &raddr, sock->ds->active); + if (comp->ds->active && !comp->tls_conn) { + + err = dtls_connect(&comp->tls_conn, tls, + comp->dtls_sock, &raddr, + dtls_estab_handler, NULL, + dtls_close_handler, comp); + if (err) { + warning("dtls_srtp: dtls_connect()" + " failed (%m)\n", err); + return err; + } + } } return err; @@ -231,16 +295,16 @@ static int media_start(struct dtls_srtp *st, struct sdp_media *sdpm) if (st->started) return 0; - debug("dtls_srtp: media_start: '%s' mux=%d, active=%d\n", - sdp_media_name(sdpm), st->mux, st->active); + info("dtls_srtp: media=%s -- start DTLS %s\n", + sdp_media_name(sdpm), st->active ? "client" : "server"); if (!sdp_media_has_media(sdpm)) return 0; - err = media_start_sock(&st->sockv[0], sdpm); + err = component_start(&st->compv[0], sdpm); if (!st->mux) - err |= media_start_sock(&st->sockv[1], sdpm); + err |= component_start(&st->compv[1], sdpm); if (err) return err; @@ -283,14 +347,14 @@ static int media_alloc(struct menc_media **mp, struct menc_sess *sess, st->sess = sess; st->sdpm = mem_ref(sdpm); - st->sockv[0].app_sock = mem_ref(rtpsock); - st->sockv[1].app_sock = mem_ref(rtcpsock); + st->compv[0].app_sock = mem_ref(rtpsock); + st->compv[1].app_sock = mem_ref(rtcpsock); for (i=0; i<2; i++) - st->sockv[i].ds = st; + st->compv[i].ds = st; - st->sockv[0].is_rtp = true; - st->sockv[1].is_rtp = false; + st->compv[0].is_rtp = true; + st->compv[1].is_rtp = false; if (err) { mem_deref(st); @@ -300,7 +364,7 @@ static int media_alloc(struct menc_media **mp, struct menc_sess *sess, *mp = (struct menc_media *)st; setup: - st->mux = (rtpsock == rtcpsock); + st->mux = (rtpsock == rtcpsock) || (rtcpsock == NULL); setup = sdp_rattr(st->sess->sdp, st->sdpm, "setup"); if (setup) { @@ -369,9 +433,28 @@ static int module_init(void) return ENOSYS; } - err = dtls_alloc_selfsigned(&tls, "dtls@baresip", srtp_profiles); - if (err) + err = tls_alloc(&tls, TLS_METHOD_DTLSV1, NULL, NULL); + if (err) { + warning("dtls_srtp: failed to create DTLS context (%m)\n", + err); + return err; + } + + err = tls_set_selfsigned(tls, "dtls@baresip"); + if (err) { + warning("dtls_srtp: failed to self-sign certificate (%m)\n", + err); return err; + } + + tls_set_verify_client(tls); + + err = tls_set_srtp(tls, srtp_profiles); + if (err) { + warning("dtls_srtp: failed to enable SRTP profile (%m)\n", + err); + return err; + } menc_register(&dtls_srtpf); menc_register(&dtls_srtp); diff --git a/modules/dtls_srtp/dtls_srtp.h b/modules/dtls_srtp/dtls_srtp.h index 6f85bf3..531134c 100644 --- a/modules/dtls_srtp/dtls_srtp.h +++ b/modules/dtls_srtp/dtls_srtp.h @@ -10,9 +10,10 @@ enum { LAYER_DTLS = 20, /* must be above zero */ }; -struct sock { - const struct dtls_srtp *ds; - struct dtls_flow *dtls; +struct comp { + const struct dtls_srtp *ds; /* parent */ + struct dtls_sock *dtls_sock; + struct tls_conn *tls_conn; struct srtp_stream *tx; struct srtp_stream *rx; struct udp_helper *uh_srtp; @@ -21,39 +22,12 @@ struct sock { bool is_rtp; }; -struct key { - uint8_t key[256]; - size_t key_len; - uint8_t salt[256]; - size_t salt_len; -}; - - /* dtls.c */ -int dtls_alloc_selfsigned(struct tls **tlsp, const char *aor, - const char *srtp_profile); int dtls_print_sha1_fingerprint(struct re_printf *pf, const struct tls *tls); int dtls_print_sha256_fingerprint(struct re_printf *pf, const struct tls *tls); /* srtp.c */ -int srtp_stream_add(struct srtp_stream **sp, const char *profile, - const struct key *key, bool tx); -int srtp_install(struct sock *sock); - - -/* tls_udp.c */ -struct dtls_flow; - -typedef void (dtls_estab_h)(int err, struct dtls_flow *tc, - const char *profile, - const struct key *client_key, - const struct key *server_key, - void *arg); - -int dtls_flow_alloc(struct dtls_flow **flowp, struct tls *tls, - struct udp_sock *us, dtls_estab_h *estabh, void *arg); -int dtls_flow_start(struct dtls_flow *flow, const struct sa *peer, - bool active); -int dtls_get_remote_fingerprint(const struct dtls_flow *flow, const char *type, - struct tls_fingerprint *fp); +int srtp_stream_add(struct srtp_stream **sp, enum srtp_suite suite, + const uint8_t *key, size_t key_size, bool tx); +int srtp_install(struct comp *comp); diff --git a/modules/dtls_srtp/module.mk b/modules/dtls_srtp/module.mk index 87dc952..2e9b6d5 100644 --- a/modules/dtls_srtp/module.mk +++ b/modules/dtls_srtp/module.mk @@ -5,7 +5,7 @@ # MOD := dtls_srtp -$(MOD)_SRCS += dtls_srtp.c dtls.c srtp.c tls_udp.c +$(MOD)_SRCS += dtls_srtp.c srtp.c dtls.c $(MOD)_LFLAGS += -lsrtp include mk/mod.mk diff --git a/modules/dtls_srtp/srtp.c b/modules/dtls_srtp/srtp.c index b68ebc1..554a23d 100644 --- a/modules/dtls_srtp/srtp.c +++ b/modules/dtls_srtp/srtp.c @@ -89,7 +89,7 @@ static void destructor(void *arg) static bool send_handler(int *err, struct sa *dst, struct mbuf *mb, void *arg) { - struct sock *sock = arg; + struct comp *comp = arg; err_status_t e; int len; (void)dst; @@ -106,10 +106,10 @@ static bool send_handler(int *err, struct sa *dst, struct mbuf *mb, void *arg) } if (is_rtcp_packet(mb)) { - e = srtp_protect_rtcp(sock->tx->srtp, mbuf_buf(mb), &len); + e = srtp_protect_rtcp(comp->tx->srtp, mbuf_buf(mb), &len); } else { - e = srtp_protect(sock->tx->srtp, mbuf_buf(mb), &len); + e = srtp_protect(comp->tx->srtp, mbuf_buf(mb), &len); } if (err_status_ok != e) { @@ -129,7 +129,7 @@ static bool send_handler(int *err, struct sa *dst, struct mbuf *mb, void *arg) static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg) { - struct sock *sock = arg; + struct comp *comp = arg; err_status_t e; int len; (void)src; @@ -140,10 +140,10 @@ static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg) len = (int)mbuf_get_left(mb); if (is_rtcp_packet(mb)) { - e = srtp_unprotect_rtcp(sock->rx->srtp, mbuf_buf(mb), &len); + e = srtp_unprotect_rtcp(comp->rx->srtp, mbuf_buf(mb), &len); } else { - e = srtp_unprotect(sock->rx->srtp, mbuf_buf(mb), &len); + e = srtp_unprotect(comp->rx->srtp, mbuf_buf(mb), &len); } if (e != err_status_ok) { @@ -160,37 +160,38 @@ static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg) } -int srtp_stream_add(struct srtp_stream **sp, const char *profile, - const struct key *key, bool tx) +int srtp_stream_add(struct srtp_stream **sp, enum srtp_suite suite, + const uint8_t *key, size_t key_size, bool tx) { struct srtp_stream *s; err_status_t e; int err = 0; - if (!sp || !key || key->key_len > SRTP_MAX_KEY_LEN) + if (!sp || !key || key_size > SRTP_MAX_KEY_LEN) return EINVAL; s = mem_zalloc(sizeof(*s), destructor); if (!s) return ENOMEM; - memcpy(s->key, key->key, key->key_len); - append_salt_to_key(s->key, (unsigned int)key->key_len, - (unsigned char *)key->salt, - (unsigned int)key->salt_len); + memcpy(s->key, key, sizeof(s->key)); /* note: policy and key must be on the heap */ - if (0 == str_casecmp(profile, "SRTP_AES128_CM_SHA1_80")) { - crypto_policy_set_aes_cm_128_hmac_sha1_80(&s->policy.rtp); - crypto_policy_set_aes_cm_128_hmac_sha1_80(&s->policy.rtcp); - } - else if (0 == str_casecmp(profile, "SRTP_AES128_CM_SHA1_32")) { + switch (suite) { + + case SRTP_AES_CM_128_HMAC_SHA1_32: crypto_policy_set_aes_cm_128_hmac_sha1_32(&s->policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_32(&s->policy.rtcp); - } - else { - warning("srtp: unsupported profile: %s\n", profile); + break; + + case SRTP_AES_CM_128_HMAC_SHA1_80: + crypto_policy_set_aes_cm_128_hmac_sha1_80(&s->policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&s->policy.rtcp); + break; + + default: + warning("srtp: unsupported crypto suite: %d\n", suite); err = ENOSYS; goto out; } @@ -217,11 +218,9 @@ int srtp_stream_add(struct srtp_stream **sp, const char *profile, } -int srtp_install(struct sock *sock) +int srtp_install(struct comp *comp) { - return udp_register_helper(&sock->uh_srtp, sock->app_sock, + return udp_register_helper(&comp->uh_srtp, comp->app_sock, LAYER_SRTP, - send_handler, - recv_handler, - sock); + send_handler, recv_handler, comp); } diff --git a/modules/dtls_srtp/tls_udp.c b/modules/dtls_srtp/tls_udp.c deleted file mode 100644 index 86a6b92..0000000 --- a/modules/dtls_srtp/tls_udp.c +++ /dev/null @@ -1,395 +0,0 @@ -/** - * @file dtls_srtp/tls_udp.c DTLS socket for DTLS-SRTP - * - * Copyright (C) 2010 Creytiv.com - */ - -#define OPENSSL_NO_KRB5 1 -#include -#include -#include -#include -#include "dtls_srtp.h" - - -/* note: shadow struct in dtls.c */ -struct tls { - SSL_CTX *ctx; -}; - -struct dtls_flow { - struct udp_helper *uh; - struct udp_sock *us; - struct tls *tls; - struct tmr tmr; - struct sa peer; - SSL *ssl; - BIO *sbio_out; - BIO *sbio_in; - bool up; - dtls_estab_h *estabh; - void *arg; -}; - - -static void check_timer(struct dtls_flow *flow); - - -static int bio_create(BIO *b) -{ - b->init = 1; - b->num = 0; - b->ptr = NULL; - b->flags = 0; - - return 1; -} - - -static int bio_destroy(BIO *b) -{ - if (!b) - return 0; - - b->ptr = NULL; - b->init = 0; - b->flags = 0; - - return 1; -} - - -static int bio_write(BIO *b, const char *buf, int len) -{ - struct dtls_flow *tc = b->ptr; - struct mbuf *mb; - enum {SPACE = 4}; /* sizeof TURN channel header */ - int err; - - mb = mbuf_alloc(SPACE + len); - if (!mb) - return -1; - - (void)mbuf_fill(mb, 0x00, SPACE); - (void)mbuf_write_mem(mb, (void *)buf, len); - - mb->pos = SPACE; - - err = udp_send_helper(tc->us, &tc->peer, mb, tc->uh); - if (err) { - warning("dtls: udp_send_helper: %m\n", err); - } - - mem_deref(mb); - - return err ? -1 : len; -} - - -static long bio_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - (void)b; - (void)num; - (void)ptr; - - if (cmd == BIO_CTRL_FLUSH) { - /* The OpenSSL library needs this */ - return 1; - } - - return 0; -} - - -static struct bio_method_st bio_udp_send = { - BIO_TYPE_SOURCE_SINK, - "udp_send", - bio_write, - 0, - 0, - 0, - bio_ctrl, - bio_create, - bio_destroy, - 0 -}; - - -static int verify_callback(int ok, X509_STORE_CTX *ctx) -{ - (void)ok; - (void)ctx; - return 1; /* We trust the certificate from peer */ -} - - -#if defined (DTLS_CTRL_HANDLE_TIMEOUT) && defined(DTLS_CTRL_GET_TIMEOUT) -static void timeout(void *arg) -{ - struct dtls_flow *tc = arg; - - DTLSv1_handle_timeout(tc->ssl); - - check_timer(tc); -} -#endif - - -static void check_timer(struct dtls_flow *tc) -{ -#if defined (DTLS_CTRL_HANDLE_TIMEOUT) && defined (DTLS_CTRL_GET_TIMEOUT) - struct timeval tv = {0, 0}; - long x; - - x = DTLSv1_get_timeout(tc->ssl, &tv); - - if (x) { - uint64_t delay = tv.tv_sec * 1000 + tv.tv_usec / 1000; - - tmr_start(&tc->tmr, delay, timeout, tc); - } - -#else - (void)tc; -#endif -} - - -static int get_srtp_key_info(const struct dtls_flow *tc, char *name, size_t sz, - struct key *client_key, struct key *server_key) -{ - SRTP_PROTECTION_PROFILE *sel; - const char *keymatexportlabel = "EXTRACTOR-dtls_srtp"; - uint8_t exportedkeymat[1024], *p; - int keymatexportlen; - size_t kl = 128, sl = 112; - - sel = SSL_get_selected_srtp_profile(tc->ssl); - if (!sel) - return ENOENT; - - str_ncpy(name, sel->name, sz); - - kl /= 8; - sl /= 8; - - keymatexportlen = (int)(kl + sl)*2; - if (keymatexportlen != 60) { - warning("dtls: expected 60 bits, but keying material is %d\n", - keymatexportlen); - return EINVAL; - } - - if (!SSL_export_keying_material(tc->ssl, exportedkeymat, - keymatexportlen, - keymatexportlabel, - strlen(keymatexportlabel), - NULL, 0, 0)) { - return ENOENT; - } - - p = exportedkeymat; - - memcpy(client_key->key, p, kl); p += kl; - memcpy(server_key->key, p, kl); p += kl; - memcpy(client_key->salt, p, sl); p += sl; - memcpy(server_key->salt, p, sl); p += sl; - - client_key->key_len = server_key->key_len = kl; - client_key->salt_len = server_key->salt_len = sl; - - return 0; -} - - -static void destructor(void *arg) -{ - struct dtls_flow *flow = arg; - - if (flow->ssl) { - int r = SSL_shutdown(flow->ssl); - if (r <= 0) - ERR_clear_error(); - - SSL_free(flow->ssl); - } - - mem_deref(flow->uh); - mem_deref(flow->us); - - tmr_cancel(&flow->tmr); -} - - -static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg) -{ - struct dtls_flow *flow = arg; - uint8_t b; - int r, n; - - if (mbuf_get_left(mb) < 1) - return false; - - /* ignore non-DTLS packets */ - b = mb->buf[mb->pos]; - if (b < 20 || b > 63) - return false; - - if (!sa_cmp(src, &flow->peer, SA_ALL)) - return false; - - /* feed SSL data to the BIO */ - r = BIO_write(flow->sbio_in, mbuf_buf(mb), (int)mbuf_get_left(mb)); - if (r <= 0) - return true; - - n = SSL_read(flow->ssl, mbuf_buf(mb), (int)mbuf_get_space(mb)); - if (n <= 0) { - ERR_clear_error(); - } - - if (!flow->up && SSL_state(flow->ssl) == SSL_ST_OK) { - - struct key client_key, server_key; - char profile[256]; - int err; - - flow->up = true; - - err = get_srtp_key_info(flow, profile, sizeof(profile), - &client_key, &server_key); - if (err) { - warning("dtls: SRTP key info: %m\n", err); - return true; - } - - flow->estabh(0, flow, profile, - &client_key, &server_key, flow->arg); - } - - return true; -} - - -int dtls_flow_alloc(struct dtls_flow **flowp, struct tls *tls, - struct udp_sock *us, dtls_estab_h *estabh, void *arg) -{ - struct dtls_flow *flow; - int err = ENOMEM; - - if (!flowp || !tls || !us || !estabh) - return EINVAL; - - flow = mem_zalloc(sizeof(*flow), destructor); - if (!flow) - return ENOMEM; - - flow->tls = tls; - flow->us = mem_ref(us); - flow->estabh = estabh; - flow->arg = arg; - - err = udp_register_helper(&flow->uh, us, LAYER_DTLS, NULL, - recv_handler, flow); - if (err) - goto out; - - flow->ssl = SSL_new(tls->ctx); - if (!flow->ssl) { - ERR_clear_error(); - goto out; - } - - flow->sbio_in = BIO_new(BIO_s_mem()); - if (!flow->sbio_in) - goto out; - - flow->sbio_out = BIO_new(&bio_udp_send); - if (!flow->sbio_out) { - BIO_free(flow->sbio_in); - goto out; - } - flow->sbio_out->ptr = flow; - - SSL_set_bio(flow->ssl, flow->sbio_in, flow->sbio_out); - - tmr_init(&flow->tmr); - - err = 0; - - out: - if (err) - mem_deref(flow); - else - *flowp = flow; - - return err; -} - - -int dtls_flow_start(struct dtls_flow *flow, const struct sa *peer, bool active) -{ - int r, err = 0; - - if (!flow || !peer) - return EINVAL; - - flow->peer = *peer; - - if (active) { - r = SSL_connect(flow->ssl); - if (r < 0) { - int ssl_err = SSL_get_error(flow->ssl, r); - - ERR_clear_error(); - - if (ssl_err != SSL_ERROR_WANT_READ) { - warning("dtls: SSL_connect() failed" - " (err=%d)\n", ssl_err); - } - } - - check_timer(flow); - } - else { - SSL_set_accept_state(flow->ssl); - - SSL_set_verify_depth(flow->ssl, 0); - SSL_set_verify(flow->ssl, - SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, - verify_callback); - } - - return err; -} - - -static const EVP_MD *type2evp(const char *type) -{ - if (0 == str_casecmp(type, "SHA-1")) - return EVP_sha1(); - else if (0 == str_casecmp(type, "SHA-256")) - return EVP_sha256(); - else - return NULL; -} - - -int dtls_get_remote_fingerprint(const struct dtls_flow *flow, const char *type, - struct tls_fingerprint *fp) -{ - X509 *x; - - if (!flow || !fp) - return EINVAL; - - x = SSL_get_peer_certificate(flow->ssl); - if (!x) - return EPROTO; - - fp->len = sizeof(fp->md); - if (1 != X509_digest(x, type2evp(type), fp->md, &fp->len)) - return ENOENT; - - return 0; -} -- cgit v1.2.3