|
|
|
@ -35,6 +35,32 @@
|
|
|
|
|
|
|
|
|
|
#define CERT_EXPIRY_TIME (60*60*24*30) /* 30 days */
|
|
|
|
|
|
|
|
|
|
INLINE struct stream_fd *dtls_primary(struct packet_stream *ps) {
|
|
|
|
|
if (!ps->sfds.length)
|
|
|
|
|
return NULL;
|
|
|
|
|
return ps->sfds.head->data;
|
|
|
|
|
}
|
|
|
|
|
// determine the sfd to hold our DTLS context if we don't know the sfd.
|
|
|
|
|
// it's either the "selected_sfd" for regular multi-homed streams, or
|
|
|
|
|
// the first sfd in the list in case ICE is in use
|
|
|
|
|
struct stream_fd *dtls_sfd(struct packet_stream *ps) {
|
|
|
|
|
if (!ps)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (PS_ISSET(ps, ICE))
|
|
|
|
|
return dtls_primary(ps);
|
|
|
|
|
return ps->selected_sfd;
|
|
|
|
|
}
|
|
|
|
|
// determine the DTLS context if we do have an sfd. can be sfd->dtls,
|
|
|
|
|
// or in case ICE is in use, the first sfd's context.
|
|
|
|
|
struct dtls_connection *dtls_ptr(struct stream_fd *sfd) {
|
|
|
|
|
if (!sfd)
|
|
|
|
|
return NULL;
|
|
|
|
|
struct packet_stream *ps = sfd->stream;
|
|
|
|
|
if (PS_ISSET(ps, ICE)) // ignore which sfd we were given
|
|
|
|
|
sfd = dtls_primary(ps);
|
|
|
|
|
return &sfd->dtls;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -477,13 +503,13 @@ int dtls_connection_init(struct packet_stream *ps, int active, struct dtls_cert
|
|
|
|
|
struct dtls_connection *d;
|
|
|
|
|
unsigned long err;
|
|
|
|
|
|
|
|
|
|
if (!ps || !ps->selected_sfd)
|
|
|
|
|
struct stream_fd *sfd = dtls_sfd(ps);
|
|
|
|
|
if (!sfd)
|
|
|
|
|
return 0;
|
|
|
|
|
d = &sfd->dtls;
|
|
|
|
|
|
|
|
|
|
__DBG("dtls_connection_init(%i)", active);
|
|
|
|
|
|
|
|
|
|
d = &ps->selected_sfd->dtls;
|
|
|
|
|
|
|
|
|
|
if (d->init) {
|
|
|
|
|
if ((d->active && active) || (!d->active && !active))
|
|
|
|
|
goto done;
|
|
|
|
@ -522,7 +548,7 @@ int dtls_connection_init(struct packet_stream *ps, int active, struct dtls_cert
|
|
|
|
|
if (!d->r_bio || !d->w_bio)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
SSL_set_app_data(d->ssl, ps->selected_sfd); /* XXX obj reference here? */
|
|
|
|
|
SSL_set_app_data(d->ssl, sfd); /* XXX obj reference here? */
|
|
|
|
|
SSL_set_bio(d->ssl, d->r_bio, d->w_bio);
|
|
|
|
|
d->init = 1;
|
|
|
|
|
SSL_set_mode(d->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
|
|
|
@ -618,15 +644,18 @@ found:
|
|
|
|
|
|
|
|
|
|
ilog(LOG_INFO, "DTLS-SRTP successfully negotiated");
|
|
|
|
|
|
|
|
|
|
if (d->active) {
|
|
|
|
|
/* we're the client */
|
|
|
|
|
crypto_init(&ps->crypto, &client);
|
|
|
|
|
crypto_init(&ps->selected_sfd->crypto, &server);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* we're the server */
|
|
|
|
|
crypto_init(&ps->crypto, &server);
|
|
|
|
|
crypto_init(&ps->selected_sfd->crypto, &client);
|
|
|
|
|
for (GList *l = ps->sfds.head; l; l = l->next) {
|
|
|
|
|
struct stream_fd *sfd = l->data;
|
|
|
|
|
if (d->active) {
|
|
|
|
|
/* we're the client */
|
|
|
|
|
crypto_init(&ps->crypto, &client);
|
|
|
|
|
crypto_init(&sfd->crypto, &server);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* we're the server */
|
|
|
|
|
crypto_init(&ps->crypto, &server);
|
|
|
|
|
crypto_init(&sfd->crypto, &client);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
crypto_dump_keys(&ps->crypto, &ps->selected_sfd->crypto);
|
|
|
|
@ -643,17 +672,18 @@ error:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* called with call locked in W or R with ps->in_lock held */
|
|
|
|
|
int dtls(struct packet_stream *ps, const str *s, const endpoint_t *fsin) {
|
|
|
|
|
struct dtls_connection *d;
|
|
|
|
|
int dtls(struct stream_fd *sfd, const str *s, const endpoint_t *fsin) {
|
|
|
|
|
struct packet_stream *ps = sfd->stream;
|
|
|
|
|
int ret;
|
|
|
|
|
unsigned char buf[0x10000];
|
|
|
|
|
|
|
|
|
|
if (!ps || !ps->selected_sfd)
|
|
|
|
|
if (!ps)
|
|
|
|
|
return 0;
|
|
|
|
|
if (!MEDIA_ISSET(ps->media, DTLS))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
d = &ps->selected_sfd->dtls;
|
|
|
|
|
struct dtls_connection *d = dtls_ptr(sfd);
|
|
|
|
|
if (!d)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (s)
|
|
|
|
|
__DBG("dtls packet input: len %u %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
|
|
|
@ -675,7 +705,7 @@ int dtls(struct packet_stream *ps, const str *s, const endpoint_t *fsin) {
|
|
|
|
|
|
|
|
|
|
ret = try_connect(d);
|
|
|
|
|
if (ret == -1) {
|
|
|
|
|
ilog(LOG_ERROR, "DTLS error on local port %u", ps->selected_sfd->socket.local.port);
|
|
|
|
|
ilog(LOG_ERROR, "DTLS error on local port %u", sfd->socket.local.port);
|
|
|
|
|
/* fatal error */
|
|
|
|
|
dtls_connection_cleanup(d);
|
|
|
|
|
return 0;
|
|
|
|
@ -727,7 +757,7 @@ int dtls(struct packet_stream *ps, const str *s, const endpoint_t *fsin) {
|
|
|
|
|
fsin = &ps->endpoint;
|
|
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Sending DTLS packet");
|
|
|
|
|
socket_sendto(&ps->selected_sfd->socket, buf, ret, fsin);
|
|
|
|
|
socket_sendto(&sfd->socket, buf, ret, fsin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
@ -735,23 +765,29 @@ int dtls(struct packet_stream *ps, const str *s, const endpoint_t *fsin) {
|
|
|
|
|
|
|
|
|
|
/* call must be locked */
|
|
|
|
|
void dtls_shutdown(struct packet_stream *ps) {
|
|
|
|
|
struct dtls_connection *d;
|
|
|
|
|
|
|
|
|
|
if (!ps || !ps->selected_sfd)
|
|
|
|
|
if (!ps)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
__DBG("dtls_shutdown");
|
|
|
|
|
|
|
|
|
|
d = &ps->selected_sfd->dtls;
|
|
|
|
|
if (!d->init)
|
|
|
|
|
return;
|
|
|
|
|
for (GList *l = ps->sfds.head; l; l = l->next) {
|
|
|
|
|
struct stream_fd *sfd = l->data;
|
|
|
|
|
|
|
|
|
|
struct dtls_connection *d = &sfd->dtls;
|
|
|
|
|
if (!d->init)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (d->connected && d->ssl) {
|
|
|
|
|
SSL_shutdown(d->ssl);
|
|
|
|
|
dtls(sfd, NULL, &ps->endpoint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dtls_connection_cleanup(d);
|
|
|
|
|
|
|
|
|
|
if (d->connected && d->ssl) {
|
|
|
|
|
SSL_shutdown(d->ssl);
|
|
|
|
|
dtls(ps, NULL, &ps->endpoint);
|
|
|
|
|
crypto_reset(&sfd->crypto);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dtls_connection_cleanup(d);
|
|
|
|
|
|
|
|
|
|
if (ps->dtls_cert) {
|
|
|
|
|
X509_free(ps->dtls_cert);
|
|
|
|
@ -759,7 +795,6 @@ void dtls_shutdown(struct packet_stream *ps) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
crypto_reset(&ps->crypto);
|
|
|
|
|
crypto_reset(&ps->selected_sfd->crypto);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dtls_connection_cleanup(struct dtls_connection *c) {
|
|
|
|
|