Prosody Datagram Transport Layer Security (DTLS) library

The Prosody DTLS library contains source code which can be integrated into an application and used in combination with Prosody and an OpenSSL library installed on the system to obtain cipher keys for encrypting/authenticating audio conveyed in SRTP packets.

The DTLS protocol and its use with SRTP is described in: IETF RFC 5764 and IETF RFC 4347.

Use of DTLS is a UDP based alternative to the coneyance of cipher keys within SIP/SDP sent over a TLS session. Use of DTLS for this purpose is normal for WebRTC sessions.

A sequence of Prosody DTLS library calls will invoke a DTLS handshake with a peer entity and on successful completion will result in two 240 bit (30 octet) vectors of combined master key and salt being made available to the application. These buffers can be passed to TiNG RTP authenication/encryption API calls (which will use a key derivation function to extract HMAC and AES keys from this data).

The API is made up of the following calls:

The application will need to provide a set of packet handling functions for the library to use when sending and receiving DTLS UDPs. An example is provided, other formulations may be necessary for particular application architectures. Typically DTLS UDPs are received on the same (VMPRx) UDP port as RTP packets. The TiNG API provides facilities to obtain DTLS UDPs that arrive on the VMPRx port, and to transmit DTLS UDPs. The example packet handling functions illustrate this.

A typical application sequence would be:

Integration into application

The Prosody DTLS library API is designed to fit into an event driven application structure which initiates the next DTLS action upon a packet arrival or non-arrival of a packet within a time limit.

Example application code

An example application is provided in "dtlslib/examples/handshake.c". This acts as a server, awaiting a DTLS Client Hello, then proceeds with the handshake and subsequent encryption configuration for VMPTx and VMPRx objects. It uses the Example TiNG based UDP packet handling functions to send/receive the DTLS UDPs via ProsodyS.

Packet Handling Functions

The Prosody DTLS library layers over the OpenSSL library which in turn is layered over a Basic I/O abstraction (BIO) to send and receive UDPs. The Prosody DTLS library has a BIO implementation that uses callback functions and a UDP endpoint context provided by the application to send/receive these packets.

A non-blocking UDP endpoint is required. Typically it would provide a packet arrival notification mechanism that could be used with a timeout or timer queue. Two callback functions, as described below, must be provided to be passed to dtlslib_create_session.

callback: dtlslib_send_data_cb

typedef int (*dtlslib_send_data_cb)(void* ctx, const char* data, unsigned len)

This callback is used by the Prosody DTLS library to implement the underlying BIO_write primitive of the OpenSSL protocol stack.

The ctx context parameter is that supplied by the application upon invoking dtlslib_create_session and identifies the UDP endpoint.

The callback should queue a UDP for transmission to the peer DTLS entity associated with the endpoint, having for payload the len octets pointed at by data, and return the value len to indicate the number of octets sent in the UDP.

callback: dtlslib_read_data_cb

typedef int (*dtlslib_read_data_cb)(void* ctx, char* data, unsigned max_len)

This callback is used by the Prosody DTLS library to implement the underlying BIO_read primitive of the OpenSSL protocol stack.

The ctx context parameter is that supplied by the application upon invoking dtlslib_create_session and identifies the UDP endpoint.

If a UDP packet is immediately available, its payload should be copied into the buffer pointed at by data. A maximum of max_len octets may be copied. The length of data actually copied should be returned.

If no UDP packet is immediately available, zero should be returned.

Example TiNG based packet handling functions

The TiNG primitives described in Prosody DTLS processing API provide functions to collect DTLS UDPs arriving at a Prosody managed RTP port and pass down DTLS UDPs to be transmitted by a Prosody module. Example UDP packet handling functions built over these primitives are provided in "dtlslib/udp". The following entry points are provided:

An example of use can be seen in the DTLS example application.

DTLS Logging and Debug

if "dtlslib.c" is compiled with PRINT_ERRORS defined, then errors from OpenSSL error queue will be written to stdout.

If "dtlslib.c" is compiled with LOG_ERRORS defined, then errors from OpenSSL error queue and the Prosody DTLS library are reported through logging functions:

These logging functions may be provided by the application to fit in with its own logging scheme. A simple implementation directing the output to stdout is provided in "dtlslib/logging/log.c".

if "dtlslib.c" is compiled with DTLSLIB_SSL_DEBUG defined then OpenSSL packet read and write calls will be dumped to stdout.

Prosody DTLS Library API Calls

These functions are in "dtlslib/dtlslib.c".

dtlslib_init

dtlslib* dtlslib_init(unsigned char* session_context, unsigned int session_context_len)

Parameters

session_context
Data to distinguish application use of OpenSSL from others (passed to SSL_set_session_id_context) - this might typically be text name of application but can be any sequence of octets up to length SSL_MAX_SSL_SESSION_ID_LENGTH.
session_context_len
Length of above octet sequence.

Description

Initialises OpenSSL library and create new SSL_CTX framework for DTLS connections with profile set up for SRTP_AES128_CM_SHA1_80 or SRTP_AES128_CM_SHA1_32.

Returns

pointer to allocated dtlslib if call completed successfully, otherwise NULL pointer.

dtlslib_free

void dtlslib_free(dtlslib* lib)

Parameters

lib
library reference returned by dtlslib_init

Description

Frees resources associated with use of OpenSSL.

dtlslib_create_cert

dtlslib_cert* dtlslib_create_cert(enum dtlslib_hash_type ht, int bits, int serial, long lifetime_seconds, const unsigned char* country, const unsigned char* common_name)

Parameters

ht
Indicate X.509 signature algorithm (message digest) to use.
bits
Modulus bits required for certificate associated RSA key pair (should be >= 1024 for secure key pair)
serial
X.509 certificate serial number or set to -1 to use random number.
lifetime_seconds
Lifetime in seconds of X.509 certificate.
country
NULL or set to two letter country code for X.509 certificate.
common_name
common name for X.509 certificate (a server name, for instance, could be used here)

Description

Creates public/private keypair and encodes public key as X.509 certificate to be conveyed to peer in DTLS handshakes. The bits parameter determines the strength of encryption used for handshake - typically set to 2048 for WebRTC use. The ht parameter would typically be set to sign the certificate using SHA256 algorithm (dtlslib_hash_type_sha_256).

Returns

Pointer to allocated dtlslib_cert if call completed successfully, NULL otherwise.

dtlslib_get_cert_fingerprint

int dtlslib_get_cert_fingerprint(dtlslib_cert* c, char* dest, unsigned int dest_len)

Parameters

c
Pointer to certificate created by dtlslib_create_cert.
dest
Pointer to buffer to receive text of certificate fingerprint.
dest_len
Length of above buffer.

Description

Writes a zero terminated text fingerprint string, suitable for inclusion into SDP, of public key in supplied X.509 certificate.

Returns

Length of fingerprint text (excluding terminating zero), or 0 if supplied buffer not long enough to hold fingerprint, or -1 if fingerprint could not be generated.

dtlslib_free_cert

void dtlslib_free_cert(dtlslib_cert* c)

Parameters

c
Certificate pointer returned by earlier call to dtlslib_create_cert.

Description

Frees memory resources associated with certificate.

dtlslib_create_session

dtlslib_session* dtlslib_create_session(dtlslib* lib, dtlslib_cert* c, dtlslib_send_data_cb send_cb, void* send_ctx, dtlslib_read_data_cb read_cb, void* read_ctx)

Parameters

lib
Library reference as returned by dtlslib_init.
c
Certificate pointer returned by earlier call to dtlslib_create_cert.
send_cb
Send UDP packet callback routine - see here for details.
send_ctx
Context passed to send packet callback routine.
read_cb
Receive UDP packet callback routine - see here for details.
read_ctx
Context passed to receive packet callback routine.

Description

Initialises resources to be used in DTLS handshake using supplied certificate and UDP send/receive instance. The peer port and IP address are transparent to library (normally stored in a send UDP packet context to be used by sender callback).

Returns

Pointer to newly allocated DTLS session structure containing a session cookie and other DTLS related items.

dtlslib_free_session

void dtlslib_free_session(dtlslib_session* sess)

Parameters

sess
Session pointer as returned by dtlslib_create_session.

Description

Frees resources and memory associated with DTLS session.

dtlslib_start_handshake

int dtlslib_start_handshake(dtlslib_session* sess, int is_server)

Parameters

sess
Session pointer as returned by dtlslib_create_session.
is_server
If non-zero, application role is server, otherwise client.

Description

If application is client, invoking this call will initiate handshake through sending of first client hello.

If application is server, invoking this call will wait for and respond to first received DTLS packet of a handshake (should be DTLS client hello).

Returns

-1 if error stopped handshake from being initiated. 0 if handshake underway. 1 if handshake now complete.

dtlslib_continue

int dtlslib_continue(dtlslib_session* sess)

Parameters

sess
Session pointer as returned by dtlslib_create_session.

Description

This function is invoked by an application subsequent to dtlslib_start_handshake upon event of new packet arrival (or non arrival timeout). It processes this event and performs the next action of the DTLS handshake.

Returns

-1 if error stopped handshake from being completed. 0 if handshake underway. 1 if handshake now complete.

dtlslib_get_timeout_ms

int dtlslib_get_timeout_ms(dtlslib_session* sess) This function is invoked by an application subsequent to dtlslib_start_handshake or dtlslib_continue in order to determine the time within which a response packet is expected. The returned millisecond count should be used to generate a timeout event in case of non-arrival of a packet.

Returns

If -1 is returned, this indicates an indefinite timeout. Otherwise return value is timeout in milliseconds.

dtlslib_get_remote_fingerprint

int dtlslib_get_remote_fingerprint(dtlslib_session* sess, enum dtlslib_hash_type ht, char* dest, unsigned int dest_len)

Parameters

sess
Session pointer as returned by dtlslib_create_session.
ht
Hash type.
dest
Pointer to buffer to receive fingerprint text.
dest_len
Length of above buffer.

Description

Writes a zero terminated text fingerprint string, suitable for comparing with that received in SDP, of public key in certificate received from peer during DTLS handshake. The hash type of the peer certificate will have been indicated in received SDP.

Returns

Length of fingerprint text (excluding terminating zero), or 0 if supplied buffer not long enough to hold fingerprint, or -1 if fingerprint could not be generated.

dtlslib_extract_srtp_keys

int dtlslib_extract_srtp_keys(dtlslib_session* sess, enum dtlslib_srtp_mode* mode, char* srtp_tx_key, char* srtp_rx_key)

Parameters

sess
Session pointer as returned by dtlslib_create_session.
mode
Pointer to location where mode will be written.
srtp_tx_key
Pointer to 30 octet buffer to receive encoding cipher key material.
srtp_rx_key
Pointer to 30 octet buffer to receive decoding cipher key material.

Description

Writes a value into mode indicating type of authentication tag associated with cipher keys:

Writes into srtp_tx_key SRTP_MASTER_KEY_KEY_LEN+SRTP_MASTER_KEY_SALT_LEN octets of encoding cipher key material. Writes into srtp_rx_key SRTP_MASTER_KEY_KEY_LEN+SRTP_MASTER_KEY_SALT_LEN octets of decoding cipher key material.

Returns

0 if cipher key material written, -1 otherwise.

OpenSSL Compatibility

The Prosody DTLS source library may be built against OpenSSL 1.0 (link with ssleay32.lib and libeay32.lib) or OpenSSL 1.1 (link with libssl.lib and libcrypto.lib).

The DTLS library is distributed with Prosody.