GNU ZRTP How To

From GNU Telephony

Jump to: navigation, search

Contents

This how-to gives a short introduction to GNU ZRTP. The first part of this how-to describes the overall structure of GNU ZRTP: the two main parts GNU ZRTP core and GNU ZRTP ccRTP extension and how they are work together with ccRTP and the application. The second part of the how-to shows some short programming examples and describes the differences between normal ccRTP RTP sessions and GNU ZRTP SRTP session.

GNU ZRTP C++ Overview

A complete GNU ZRTP implementation consists of two parts, the GNU ZRTP core and specific code that binds the GNU ZRTP core to the underlying RTP/SRTP stack and the operating system:

  • The GNU ZRTP C++ core is independent of a specific RTP/SRTP stack and the operationg system and consists of the ZRTP protocol state engine, the ZRTP protocol messages, and the GNU ZRTP C++ engine. The GNU ZRTP C++ engine provides methods to setup ZRTP message and to analyze received ZRTP messages, to compute the cryptographic data required for SRTP, and to maintain the required hashes and HMAC.
  • The second part of an implementation is specific glue code the binds the GNU ZRTP core to the actual RTP/SRTP implementation and other operating system specific services such as timers.

The GNU ZRTP C++ core uses a callback interface class (ZrtpCallback) to access RTP/SRTP or operating specific methods, for example to send data via the RTP/SRTP stack, to access timers and mutex handling, and to report events to the application.

An application uses the the RTP/SRTP specific code only. This is the application's interface to control ZRTP behaviour and to send and receive data. Therefore the following paragraphs of this how to mainly describe the GNU ZRTP ccRTP extension. The source distribution of GNU ZRTP C++ also contains the documentation of the core implementation.

The ccRTP specific extension ZrtpQueue

ZrtpQueue implements code that is specific to the GNU ccRTP implementation. ZrtpQueue also implements code to provide the mutex and timeout handling to the GNU ZRTP C++ core. Both, the mutex and the timeout handling, use the GNU Common C++ library to stay independent of the operating system. For more information refer to the GNU Common C++ web site.

To perform its tasks ZrtpQueue

  • extends GNU ccRTP classes to use the underlying ccRTP methods and the RTP/SRTP send and receive queues
  • implements the ZrtpCallback interface to provide access to ccRTP functions and to operating specific services (timer, mutex).
  • provides ZRTP specific methods that applications may use to control and setup GNU ZRTP C++
  • can register and use an application specific callback class (refer to ZrtpUserCallback)

After instantiating a ZrtpQueue object using a specific type (see below for a short example) applications may use the ZRTP specific methods of ZrtpQueue to control and setup GNU ZRTP C++, for example enable or disable ZRTP processing or getting ZRTP status information.

How GNU ZRTP C++, ccRTP, and applications work together

GNU ZRTP provides a ZrtpUserCallback class that an application may extend and register with ZrtpQueue. GNU ZRTP C++ and ZrtpQueue use the ZrtpUserCallback methods to report ZRTP events to the application. The application may display this information to the user or act otherwise.

The following figure depicts the relationships between ZrtpQueue, ccRTP RTP/SRTP implementation, the GNU ZRTP C++ core, and an application that provides an ZrtpUserCallback class.


                          +----------+
                          |  ccRTP   |
                          | RTP/SRTP |
                          |          |
                          +----------+
                               ^
                               | extends
                               |
 +----------------+      +-----+------+
 |  Application   |      |            |      +-----------------+
 |  instantiates  | uses | ZrtpQueue  | uses |                 |
 | a ZRTP Session +------+ implements +------+    GNU ZRTP     |
 |  and provides  |      |ZrtpCallback|      |      core       |
 |ZrtpUserCallback|      |            |      | implementation  |
 +----------------+      +------------+      |  (ZRtp et al)   |
                                             |                 |
                                             +-----------------+

The picture shows that ZrtpQueue has a janus face: one face to the application and one face to the GNU ZRTP C++ core implementation. As an extension to the standard ccRTP RTP/SRTP implementation ZrtpQueue can provide the RTP/SRTP services to both, the application and the GNU ZRTP C++ core. The uses relations are two way uses relations: the application uses the interface of ZrtpQueue to set up and control GNU ZRTP and ZrtpQueue uses the ZrtpUserCallback methods to report events to the application (if the application registered an own class that extends ZrtpUserCallback). On the other side ZrtpQueue instantiates the GNU ZRTP C++ core class (ZRtp) and uses its interface to control ZRTP, mainly on behalf of the application. ZrtpQueue also registers itself with GNU ZRTP C++ core providing the internal ZrtpCallback interface. GNU ZRTP C++ uses this internal interface to access various services, such as send data via RTP session or timer support.

Using GNU ZRTP C++

The following paragraphs show some short examples how to use GNU ZRTP C++. Most code snippets are extracted from the small demo program zrtptest located in the demo folder.

The GNU ZRTP C++ source distribution contains a detailed documentation of the available methods.

How to instantiate a GNU ZRTP C++ object

Because ZrtpQueue extends the ccRTP RTP/SRTP implementation (AVPQueue) all public methods defined by ccRTP are also available for a ZRTP session. ZrtpQueue overwrites some of the public methods of ccRTP (AVPQueue) to implement ZRTP specific code.

GNU ZRTP C++ provides a SymmetricZRTPSession type to simplify its use. An application uses this type in the same way as it would use the normal ccRTP SymmetricRTPSession type. The following short code snippets show how an application could instantiate ccRTP and GNU ZRTP C++ sessions. The first snippet shows how to instantiate a ccRTP session:

...
#include <ccrtp/rtp.h>
...
    SymmetricRTPSession tx(ssrc,InetHostAddress("localhost"));
...

The same code as above but using a GNU ZRTP C++ session this time:

...
#include <libzrtpcpp/zrtpccrtp.h>
...
    SymmetricZRTPSession tx(ssrc, InetHostAddress("localhost"));
...

The only differences are the different include statements and the different session types.

Using a GNU ZRTP C++ session

An application may use a GNU ZRTP C++ session in the same way as a normal ccRTP RTP session. Because ZRTP requires a two-way communication both parties of a RTP session must be able to send and receive data. Thus a RTP transmitter has to set a receiver address and a RTP receiver has to set a transmitter address. The following code snippet shows this:

...
    SymmetricZRTPSession tx(ssrc, InetHostAddress("localhost"), port + 2);

    tx.addDestination(InetHostAddress("host.destination.org"), port);
...

This example uses different port numbers to set up the RTP receiver and transmitter (just in case the sender and receiver are on the same host). Otherwise application doen't see any difference. To use the ZRTP capabilities the application has to initialize GNU ZRTP first. Continuing the above code snippet:

     tx.initialize("test_t.zid");

The parameter test_t.zid defines the name of a ZRTP Id file (ZID file) that stores the ZRTP identifier, the ZRTP retained secrets and some other data used by ZRTP.

Note: Currently GNU ZRTP requires a ZID file, later versions may run without a ZID file. Running without a ZID file does not compromise security but may be less convenient for an user.

The initialization method opens the ZID file, performs some housekeeping and enables ZRTP processing if no error occurred during the initialization phase. The application may now start the ZRTP discovery phase.

     tx.startZrtp();

This method immediatly starts the ZRTP discovery phase and GNU ZRTP sends Hello packets to its peer. If the peer is already up and has ZRTP enabled both will exchange Hello packets, negotiate the keys, compute the SRTP cryptographic data, and setup the SRTP session. Depending on the application's design and how the application uses GNU ZRTP C++ the ZRTP discovery and key exchange may overlap with RTP communication. Therefore the application may send some RTP data packet that are not protected by SRTP.

Using the GNU ZRTP C++ user callback

To avoid sending of unprotected data applications can monitor the ZRTP activities and start data transmission only after GNU ZRTP established the SRTP session. GNU ZRTP provides a user callback class that an application can extend and register with GNU ZRTP. The GNU ZRTP core and the GNU ZRTP ccRTP extension call the methods of the user callback to report events, for example after secure mode was reached and SRTP sessions are up. See the following example for a simple user callback class:

/**
 * Simple User Callback class
 *
 * This class overwrites some methods from ZrtpUserCallback to get information
 * about ZRTP processing and information about ZRTP results. The standard 
 * implementation of this class just performs return, thus effectively
 * supressing any callback or trigger.
 */
class
MyUserCallback: public ZrtpUserCallback {
    void secureOn(std::string cipher) {
        cout << "Using cipher:" << cipher << endl;
    }

    void showSAS(std::string sas, bool verified) {
        cout << "SAS is: " << sas << endl;

    }
};

...
    tx.setUserCallback(new MyUserCallback());
...

This simple user callback class just displays some information. GNU ZRTP C++ calls the method secureOn() after secure mode was reached and the SRTP session is active. The string parameter contains the name, the mode, and the key length of the symmetric cipher that SRTP uses to encrypt the data.

After the Short Authentication String (SAS) was computed and the verified flag was checked GNU ZRTP calls the showSAS() method. The string parameter contains the SAS string and the boolean parameter is set to true if both parties verfied the SAS during a previous session (refer to the ZRTP specification for a detailed description of SAS).

Applications may use these callback methods to control the start of data transmission, for example start data transmission only after the secureOn() event.

CAVEAT
All methods of the user callback class and classes that extend this class run in the context of the RTP thread. Thus it is of paramount importance to keep the execution time of the methods as short as possible.

Start of the ZRTP discovery phase - Immediate and Auto Sensing

GNU ZRTP C++ provides two ways to start the ZRTP discovery phase:

  • Immediate mode
  • Auto Sensing mode

The next paragraphs describe these two mode in some more detail.

Immediate mode

If the application disabled auto sensing mode then the application must start ZRTP by calling startZrtp(). GNU ZRTP C++ immediately starts to send Hello packets to discover if the peer is available and if it supports ZRTP. If the peer supports ZRTP then both parties continue with ZRTP handshake and negotiate the keys to set up SRTP.

If the peer is either not available or does not support ZRTP then GNU ZRTP C++ calls the user callback method zrtpNotSuppOther(). After this callback returns GNU ZRTP C++ does not disable ZRTP processing completely but switches into a detect state. See also Restart of the ZRTP discovery phase below.

Auto Sensing mode

If ZRTP was initialized with auto sensing mode the application does not need to call startZrtp(). In auto sensing mode GNU ZRTP C++ monitors the traffic on the RTP session to decide when to start the ZRTP discovery phase. GNU ZRTP C++ starts the ZRTP discovery phase after at least one RTP packet was sent and received on the associated RTP session.

The auto sensing mode is convenient for applications that open RTP sessions but the actual RTP traffic starts some time later. This is often the case for RTP applications that use a signaling protocol to exchange the actual RTP parameters (port numbers, IP address) with their peer applications. Even after the signaling was successful the applications cannot exactly determine when data starts to flow on the RTP sessions. This starting time depends on a lot of factors, for example network delays or delays in the applications.

Restart of the ZRTP discovery phase

Personal tools