Guide to the libZRTP Test Suite

1. Introduction to the libzrtp test-suite

libzrtp_test is a cross-platform application included in SDK, which is designed to test its performance. The testing software implements the following functions: In addition this application may be used as a simple example of library integration. It demonstrates getting an encrypted communication channel running using a small number of libzrtp functions.

Note that the test application uses the embedded implementations of some libzrtp interfaces, and others are not used at all. Therefore while installing libzrtp the following flags should be used: -DBUILD_WITH_CFUNC, -DBUILD_EMPTY_CACHE, -DBUILD_DEFAULT_TIMER, -DZRTP_ENABLE_TEST, -DZRTP_USE_EXTERN_SRTP. For more detailed information see 1.4 libZRTP setup and building.

To install the test application on Windows there are project files libzrtp_test.dsp and libzrtp_test.vcproj for MS Visual Studio v6,v7 and v8..

To install the test application on Unix you should configure the library using the above-mentioned flags and execute the command: "make check". This will compile, link, and run all possible tests.

2. Crypto-components self-tests

2.1 Cipher tests

The cipher test encrypts and decrypts the given block using a predetermined key. The result of the encryption is combined with a predetermined plaintext.

The cipher test is based on well known test vectors for different key sizes (128 and 256 bit) and different modes ( CTR and CFB).

The test will succeed if and only if the resulting encrypted text matches the predetermined ciphertext, and the resulting decrypted text matches the predetermined plaintext.

The expected output for a successful run of the cipher tests is:

------- Cipher tests -------
128 bit AES CFB
1st test...
        encryption...OK
        decryption...OK
2nd test...
        encryption...OK
        decryption...OK
128 bit AES CTR
1st test...
        encryption...OK
        decryption...OK
256 bit AES CFB
1st test...
        encryption...OK
        decryption...OK
2nd test...
        encryption...OK
        decryption...OK
256 bit AES CTR
1st test...
        encryption...OK
        decryption...OK

If the cipher tests fail, see 5. Possible problems and how to solve them.

2.2 Hash/Hmac tests

The hash component computes the hash function used in the SHA-128 and SHA-256 algorithms, as well as the HMAC based on those hash functions. Both of these computations are tested.

To test the hash function, the hash of the given block is computed and bytewise-compared with the predetermined hash value. We use well-known test vectors for different lengths (1 to 2096 bytes).

The HMAC computation is tested in exactly the same way, using well-known test vectors for lengths of 8 to 73 bytes. During testing we use keys of length 20 and 80 bytes.

The expected output for a successful run of the hash/HMAC tests is:

-------- Hash tests --------
SHA-1 testing
8-bit test...OK
128-bit test...OK
512-bit test...OK
2096-bit test...OK
HMAC SHA-1 testing
1 case test...OK
2 case test...OK
3 case test...OK
4 case test...OK
5 case test...OK
6 case test...OK
7 case test...OK
SHA-256 testing
8-bit test...OK
128-bit test...OK
512-bit test...OK
2096-bit test...OK
HMAC SHA-256 testing
1 case test...OK
2 case test...OK
3 case test...OK
4 case test...OK
5 case test...OK
6 case test...OK
7 case test...OK
8 case test...OK
9 case test...OK
10 case test...OK

If the hash/HMAC tests fail, see 5. Possible problems and how to solve them.

3. SRTP self-tests

3.1 Derive key test

To test the derive key mechanism, we use well-known test vectors, including the master key and master salt. The following values are used in the test and the results are compared with predetermined values. The derive key test is run using AES-128 in CTR mode.

The expected output for a successful run of the derive key tests is:

----- Derive keys test -----
cipher key check...OK
cipher salt check...OK
auth key check...OK

If the derive key tests fail, see 5. Possible problems and how to solve them.

3.2 Replay protection test

This test simulates a call in which the connection is congested, under the influence of an attacker, or in any other condition where the packets may be doubled, lost, or received out of sequence.

The first stage of the test simulates packet loss by generating a packet sequence with gaps. In the second stage, more packet sequences are generated, some of which have sequence numbers that were either omitted, or were already received in the first stage.

The test unit stores two bit strings, test map and res map. Each bit represents a sequence number. Each bit set in test map represents an attempt to send the packet with the corresponding sequence number. Each bit set in res map indicates that the packet with the corresponding sequence number has passed replay protection and is therefore safe to send..

The test generates test map to represent a sequence of packets. It then runs the replay protection algorithm, which acts as a filter. The filter is applied as a sliding window. If the filter allows a sequence number to pass, then res map is updated to have a "1" in the position corresponding to the packet's sequence number.

The test uses the following sizes of bit-strings:

These values can be changed; their values are stored in the constants TEST_MAP_WIDTH, ZRTP_SRTP_WINDOW_WIDTH, and FIRST_TEST_MAP_INIT_WIDTH. Changes must preserve the following constraints: TEST_MAP_WIDTH > FIRST_TEST_MAP_INIT_WIDTH > ZRTP_SRTP_WINDOW_WIDTH.

Since the packet sequence generated in the first stage of the test is always increasing, after the first stage of the test, test map and res map must be identical.

Here is an example of the sequence of intervals in res map relative to the replay protection window after the first stage is completed.

                              A                           B          C
Res  map: 0000000000000000000000000000000000000000010001101111001011111110
Window  :                                          1000110111100101
                                            <---window sliding direction---

In the second stage of the test, test map is repopulated, but the window will retain information about the original packet sequence.

After the second stage of the test, res map must have the following properties:

The test will pass when those conditions are met.

An example of output for a successful run of the replay protection tests is:

--- Replay protection test ---
1st test. Wnd[16]...
after  wnd: (7;0]
inside wnd: [22;7]
before wnd: [63;22)
Test map: 0000000000000000000000000000000000000000010001101111001011111110
Res  map: 0000000000000000000000000000000000000000010001101111001011111110
Window  :                                          1000110111100101
2nd test. Wnd[16]...
Test map: 0010001010101110010111100110000010010110101000111010100001011101
Res  map: 0010001010101110010111100110000010010110101000010000100000000000
Window  :   1000101010111001
Test passed successfully

If the replay protection tests fail, see 5. Possible problems and how to solve them.

4. ZRTP protocol test-engine

Although simplicity and implementation transparency are valued above certain kinds of functionality, the supported features are very general and include multithreading.

4.1 Main Algorithm

This section describes the test application tasks, requirements, and the main algorithm.

The first stage tests the implementation of the minimal set of system interfaces. Since the library is configured to use the embedded implementations of platform-dependent functions during the build, there are only a couple of callbacks, the RTP packages, and a sending function left to be implemented.

In order to emulate calls, we use a structure that encapsulates the concepts of media session and media stream. A call is then emulated by two media sessions represented by zrtp_test_connection_t objects, one for each side. Each object can then participate in RTP traffic exchanges.

Each session has a maximum number of streams, ZRTP_MAX_STREAMS_PER_SESSION. Streams are represented by zrtp_test_stream_t objects. Both sessions in the frame of a call share a collection of media streams, which is stored in a linked list.

The test unit has an interface of commands to operate on the call such that all streams of a session are affected by a given command.

Two kinds of threads are created during initalization to perform packet exchanges. Threads of the first type are used for generating RTP and RTCP packets for random sessions and encrypting them using libztrp, and for sending new packets to the other side through the shared queue. Threads of the second type are responsible for receiving packets from the shared queue and decrypting them.

4.2 Realization

The minimal set of libzrtp system interfaces is used for the test module installation.

As mentioned above, the test unit used in the build uses embedded implementations when available (see 1.4 libZRTP setup and building), so only the following functions need testing:

As the application should work on one machine in multi-threaded mode, a synchronized queue is used as a communication channel. Its implementation is trivial and doesn't need explanation (zrtp_queue.h, zrtp_queue.c).

Each test connection, zrtp_test_connection, models one side of the ZRTP point-to-point channel. For this purpose, a zrtp_test_connection contains two test media streams zrtp_test_stream_t (one for video and one for voice). These zrtp_test_stream_t objects encapsulate the ZRTP stream context. The exchange process between threads is shown in the figure 1 "Scheme of test application thread interaction". As one connection represents only one side of the call, we need to have a corresponding connection with the same id. When a thread responsible for receiving traffic gets a packet from the queue, it has to find the appropriate connection and stream to send it to. This is done by checking the remote ssrc of the media streams of each connection in the linked list.

zrtp_test_calls.png

Figure 1.1 "Linked list of zrtp connections"

Incoming processing threads read packets from the global queue and process them using the library. If the packet is a protocol packet, the library will generate a reply and will send the packet through the zrtp_send_rtp() interface. If the packet is a data packet it will be decrypted and returned to the processing loop.

The outgoing stream starts RTP media generation right after running. Endpoints exchange plaintext packets while switching to the secure state, after which RTP traffic gets encrypted.

zrtp_test_threads.png

Figure 1.2 "Scheme of test application thread interaction"

Here are the steps of the command handling mechanism:

  1. read command from stdin (full list of commands is listed below);
  2. search for the required session according to command options (function finder);
  3. call handler function which interacts directly with libzrtp and performs the required action.

4.3 Usage

Each session has a unique identifier of integer type and is represented by two connections of zrtp_test_connection_t type, which have the same Ids. For example: if command with specified ID was called it will be applied for the every connection with the same ID.

Libzrtp_test understands these commands:

REMARKS: For commands d, z, r, i, p: if start_id and last_id are not specified, the command will be applied to all sessions.

For example. 
-------------------------------------------------------------------------------- 
Lets create one session. 

> c 
You'll see next: 

### libzrtp_test: (ZRTP_STATE_ACTIVE) [093e23d4] OUTPUT. aardvark 
### libzrtp_test: (ZRTP_STATE_ACTIVE) [093e3bd4] INPUT.  aardvark 
### libzrtp_test: (ZRTP_STATE_ACTIVE) [093e3bd4] OUTPUT. adroitness 
### libzrtp_test: (ZRTP_STATE_ACTIVE) [093e23d4] INPUT.  adroitness 

(ZRTP_STATE_xxxxx)  - indicates the current ZRTP stream state;
[address] - physical address of the ZRTP stream for debugging needs;

-------------------------------------------------------------------------------- 
Now lets start zrtp streams. 
> z 

### libzrtp_test: (ZRTP_STATE_SECURE) [093e23d4] OUTPUT. standard 
### libzrtp_test: (ZRTP_STATE_SECURE) [093e3bd4] INPUT.  standard 

The session is protected now. If an error occurs, the ZRTP stream switches to
ZRTP_STATE_ERROR state.
-------------------------------------------------------------------------------- 
Lets switch off packet encryption. 
> r 

### libzrtp_test: (ZRTP_STATE_CLEAR) [093e23d4] OUTPUT. classroom 
### libzrtp_test: (ZRTP_STATE_CLEAR) [093e3bd4] INPUT.  classroom 

Traffic is unprotected now. 
-------------------------------------------------------------------------------- 
To secure the session again press 
> s 

### libzrtp_test: (ZRTP_STATE_SECURE) [093e23d4] OUTPUT. lockup 
### libzrtp_test: (ZRTP_STATE_SECURE) [093e3bd4] INPUT.  lockup 
-------------------------------------------------------------------------------- 

4.4 Specifics of mobile platforms

Windows Mobile 5.0 uses almost the same code as a PC. The difference is that logs, which level is greater than ZRTP_LOG_DEBUG, are written to the ListBox GUI of the test unit, and Windows CE test-unite uses an OK button counter instead of common commands.

  1. First press - initializes the test unit;
  2. Second press - creates and launches the media session; streams begin processing ZRTP packet exchange; if all goes well, begins receiving RTP traffic;
  3. Third press - stops the session;
  4. Fourth press - exits the application.

The test unit for Windows CE resides in the ./projects folder and is named libzrtp_wince_vc8.sln

The implementation for Symbian differs from the preceding first and foremost by the presence of classes.

Control of the test unit is through the back button:

To exit the application, choose the corresponding option in the menu.

Logs whose level does not match the level of ZRTP_LOG_DEBUG are written to the ListBox, and all logs are also written to "c:/zfone.log"

To build the test unit on Symbian follow these recommendations:

  1. build libzrtp for Symbian ( projects folder contains Symbian project files)
  2. build the test unit itself using project files from "test/Symbian/group";

To build, type:

bldmake bldfiles
ABLD build gcce urel

5. Possible problems and how to solve them


This file is part of the documentation for Zfone.
Copyright ©  2006-2008 Philip R. Zimmermann. All rights reserved.
Generated on Mon November 10 2008 by doxygen 1.5.7-20060202. Written by Viktor Krikun, © 2006-2008