Bayonne logo

GNU ZRTP Howto

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

Contents

  1. GNU ZRTP C++ Overview
    1. The ccRTP-specific extension ZrtpQueue
    2. How GNU ZRTP C++, ccRTP, and applications work together
  2. Using GNU ZRTP C++
    1. How to instantiate a GNU ZRTP C++ object
    2. Using a GNU ZRTP C++ session
    3. Using the GNU ZRTP C++ user callback
    4. Start of the ZRTP discovery phase - Immediate and Auto Sensing
    5. Restart of the ZRTP discovery phase [TODO]

I. GNU ZRTP C++ Overview

A complete GNU ZRTP implementation consists of two components, 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 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 RTP/SRTP specific code only. This is the application's interface to control ZRTP behavior and to send and receive data. Therefore, the following paragraphs of this howto mainly describe the GNU ZRTP ccRTP extension. The source distribution of GNU ZRTP C++ also contains the documentation of the core implementation.

1. 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 page.

To perform its tasks, ZrtpQueue

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 set up GNU ZRTP C++, for example enable or disable ZRTP processing, or getting ZRTP status information.

2. 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 a ZrtpUserCallback class.


                           +----------+
                           |  ccRTP   |
                           | RTP/SRTP |
                           |          |
                           +----------+
                                ^
                                | extends
                                |
  +----------------+      +-----+------+      +-----------------+
  |  Application   |      |            |      |                 |
  |  instantiates  | uses | ZrtpQueue  | uses |    GNU ZRTP     |
  | a ZRTP Session +------+ implements +------+      core       |
  |  and provides  |      |ZrtpCallback|      | implementation  |
  |ZrtpUserCallback|      |            |      |  (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 use relations are two-way use 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 the GNU ZRTP C++ core providing the internal ZrtpCallback interface. GNU ZRTP C++ uses this internal interface to access various services, for instance to send data via RTP session or timer support

II. Using GNU ZRTP C++

The following paragraphs show some short examples of 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.

1. 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.

2. 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 the application doesn'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 one. 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 immediately 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.

3. Using the GNU ZRTP C++ user callback

To avoid sending unprotected data, applications can monitor the ZRTP activities and start data transmission only after GNU ZRTP has 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 as been 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 has been 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) has been computed and the verified flag has been 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 verified 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.

4. Start of the ZRTP discovery phase - Immediate and Auto Sensing

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

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 whether the peer is available, and whether 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 not ZRTP-capable, 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.

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.

5. Restart of the ZRTP discovery phase

[TODO]