diff options
Diffstat (limited to 'src/libzrtpcpp/ZRtp.h')
-rw-r--r-- | src/libzrtpcpp/ZRtp.h | 1292 |
1 files changed, 1292 insertions, 0 deletions
diff --git a/src/libzrtpcpp/ZRtp.h b/src/libzrtpcpp/ZRtp.h new file mode 100644 index 0000000..4e03f28 --- /dev/null +++ b/src/libzrtpcpp/ZRtp.h @@ -0,0 +1,1292 @@ +/* + Copyright (C) 2006-2010 Werner Dittmann + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _ZRTP_H_ +#define _ZRTP_H_ +/** + * @file ZRtp.h + * @brief The ZRTP main engine + * @defgroup GNU_ZRTP The GNU ZRTP C++ implementation + * @{ + */ + +#include <cstdlib> + +#include <libzrtpcpp/ZrtpPacketHello.h> +#include <libzrtpcpp/ZrtpPacketHelloAck.h> +#include <libzrtpcpp/ZrtpPacketCommit.h> +#include <libzrtpcpp/ZrtpPacketDHPart.h> +#include <libzrtpcpp/ZrtpPacketConfirm.h> +#include <libzrtpcpp/ZrtpPacketConf2Ack.h> +#include <libzrtpcpp/ZrtpPacketGoClear.h> +#include <libzrtpcpp/ZrtpPacketClearAck.h> +#include <libzrtpcpp/ZrtpPacketError.h> +#include <libzrtpcpp/ZrtpPacketErrorAck.h> +#include <libzrtpcpp/ZrtpPacketPing.h> +#include <libzrtpcpp/ZrtpPacketPingAck.h> +#include <libzrtpcpp/ZrtpPacketSASrelay.h> +#include <libzrtpcpp/ZrtpPacketRelayAck.h> +#include <libzrtpcpp/ZrtpCallback.h> +#include <libzrtpcpp/ZIDRecord.h> + +#ifndef SHA256_DIGEST_LENGTH +#define SHA256_DIGEST_LENGTH 32 +#endif + +// Prepare to support digest algorithms up to 512 bit (64 bytes) +#define MAX_DIGEST_LENGTH 64 +#define IMPL_MAX_DIGEST_LENGTH 64 + +class __EXPORT ZrtpStateClass; +class ZrtpDH; + +/** + * The main ZRTP class. + * + * This is the main class of the RTP/SRTP independent part of the GNU + * ZRTP. It handles the ZRTP HMAC, DH, and other data management. The + * user of this class needs to know only a few methods and needs to + * provide only a few external functions to connect to a Timer + * mechanism and to send data via RTP and SRTP. Refer to the + * ZrtpCallback class to get detailed information regading the + * callback methods required by GNU RTP. + * + * The class ZrtpQueue is the GNU ccRTP specific implementation that + * extends standard ccRTP RTP provide ZRTP support. Refer to the + * documentation of ZrtpQueue to get more information about the usage + * of ZRtp and associated classes. + * + * The main entry into the ZRTP class is the processExtensionHeader() + * method. + * + * This class does not directly handle the protocol states, timers, + * and packet resend. The protocol state engine is responsible for + * these actions. + * + * Example how to use ZRtp: + *<pre> + * zrtpEngine = new ZRtp((uint8_t*)ownZid, (ZrtpCallback*)this, idString); + * zrtpEngine->startZrtpEngine(); + *</pre> + * @see ZrtpCallback + * + * @author Werner Dittmann <Werner.Dittmann@t-online.de> + */ +class __EXPORT ZRtp { + + public: + + /** + * Constructor intializes all relevant data but does not start the + * engine. + */ + ZRtp(uint8_t* myZid, ZrtpCallback* cb, std::string id, + ZrtpConfigure* config, bool mitmm= false, bool sasSignSupport= false); + + /** + * Destructor cleans up. + */ + ~ZRtp(); + + /** + * Kick off the ZRTP protocol engine. + * + * This method calls the ZrtpStateClass#evInitial() state of the state + * engine. After this call we are able to process ZRTP packets + * from our peer and to process them. + */ + void startZrtpEngine(); + + /** + * Stop ZRTP security. + * + */ + void stopZrtp(); + + /** + * Process RTP extension header. + * + * This method expects to get a pointer to the extension header of + * a RTP packet. The method checks if this is really a ZRTP + * packet. If this check fails the method returns 0 (false) in + * case this is not a ZRTP packet. We return a 1 if we processed + * the ZRTP extension header and the caller may process RTP data + * after the extension header as usual. The method return -1 the + * call shall dismiss the packet and shall not forward it to + * further RTP processing. + * + * @param extHeader + * A pointer to the first byte of the extension header. Refer to + * RFC3550. + * @param peerSSRC + * The peer's SSRC. + * @return + * Code indicating further packet handling, see description above. + */ + void processZrtpMessage(uint8_t *extHeader, uint32_t peerSSRC); + + /** + * Process a timeout event. + * + * We got a timeout from the timeout provider. Forward it to the + * protocol state engine. + * + */ + void processTimeout(); + + /** + * Check for and handle GoClear ZRTP packet header. + * + * This method checks if this is a GoClear packet. If not, just return + * false. Otherwise handle it according to the specification. + * + * @param extHeader + * A pointer to the first byte of the extension header. Refer to + * RFC3550. + * @return + * False if not a GoClear, true otherwise. + */ + bool handleGoClear(uint8_t *extHeader); + + /** + * Set the auxilliary secret. + * + * Use this method to set the auxilliary secret data. Refer to ZRTP + * specification, chapter 4.3 ff + * + * @param data + * Points to the secret data. + * @param length + * Length of the auxilliary secrect in bytes + */ + void setAuxSecret(uint8_t* data, int32_t length); + + /** + * Check current state of the ZRTP state engine + * + * @param state + * The state to check. + * @return + * Returns true id ZRTP engine is in the given state, false otherwise. + */ + bool inState(int32_t state); + + /** + * Set SAS as verified. + * + * Call this method if the user confirmed (verfied) the SAS. ZRTP + * remembers this together with the retained secrets data. + */ + void SASVerified(); + + /** + * Reset the SAS verfied flag for the current active user's retained secrets. + * + */ + void resetSASVerified(); + + /** + * Get the ZRTP Hello Hash data. + * + * Use this method to get the ZRTP Hello Hash data. The method + * returns the data as a string containing the ZRTP protocol version and + * hex-digits. + * + * Refer to ZRTP specification, chapter 8. + * + * @return + * a std:string containing the Hello hash value as hex-digits. The + * hello hash is available immediately after class instantiation. + */ + std::string getHelloHash(); + + /** + * Get the peer's ZRTP Hello Hash data. + * + * Use this method to get the peer's ZRTP Hello Hash data. The method + * returns the data as a string containing the ZRTP protocol version and + * hex-digits. + * + * The peer's hello hash is available only after ZRTP received a hello. If + * no data is available the function returns an empty string. + * + * Refer to ZRTP specification, chapter 8. + * + * @return + * a std:string containing the Hello version and the hello hash as hex digits. + */ + std::string getPeerHelloHash(); + + /** + * Get Multi-stream parameters. + * + * Use this method to get the Multi-stream that were computed during + * the ZRTP handshake. An application may use these parameters to + * enable multi-stream processing for an associated SRTP session. + * + * Refer to chapter 4.4.2 in the ZRTP specification for further details + * and restriction how and when to use multi-stream mode. + * + * @return + * a string that contains the multi-stream parameters. The application + * must not modify the contents of this string, it is opaque data. The + * application may hand over this string to a new ZrtpQueue instance + * to enable multi-stream processing for this ZrtpQueue. + * If ZRTP was not started or ZRTP is not yet in secure state the method + * returns an empty string. + */ + std::string getMultiStrParams(); + + /** + * Set Multi-stream parameters. + * + * Use this method to set the parameters required to enable Multi-stream + * processing of ZRTP. The multi-stream parameters must be set before the + * application starts the ZRTP protocol engine. + * + * Refer to chapter 4.4.2 in the ZRTP specification for further details + * of multi-stream mode. + * + * @param parameters + * A string that contains the multi-stream parameters that this + * new ZrtpQueue instanace shall use. See also + * <code>getMultiStrParams()</code> + */ + void setMultiStrParams(std::string parameters); + + /** + * Check if this ZRTP session is a Multi-stream session. + * + * Use this method to check if this ZRTP instance uses multi-stream. + * Refer to chapters 4.2 and 4.4.2 in the ZRTP. + * + * @return + * True if multi-stream is used, false otherwise. + */ + bool isMultiStream(); + + /** + * Check if the other ZRTP client supports Multi-stream. + * + * Use this method to check if the other ZRTP client supports + * Multi-stream mode. + * + * @return + * True if multi-stream is available, false otherwise. + */ + bool isMultiStreamAvailable(); + + /** + * Accept a PBX enrollment request. + * + * If a PBX service asks to enroll the PBX trusted MitM key and the user + * accepts this request, for example by pressing an OK button, the client + * application shall call this method and set the parameter + * <code>accepted</code> to true. If the user does not accept the request + * set the parameter to false. + * + * @param accepted + * True if the enrollment request is accepted, false otherwise. + */ + void acceptEnrollment(bool accepted); + + /** + * Check the state of the enrollment mode. + * + * If true then we will set the enrollment flag (E) in the confirm + * packets and perform the enrollment actions. A MitM (PBX) enrollment service + * started this ZRTP session. Can be set to true only if mitmMode is also true. + * + * @return status of the enrollmentMode flag. + */ + bool isEnrollmentMode(); + + /** + * Set the state of the enrollment mode. + * + * If true then we will set the enrollment flag (E) in the confirm + * packets and perform the enrollment actions. A MitM (PBX) enrollment + * service must sets this mode to true. + * + * Can be set to true only if mitmMode is also true. + * + * @param enrollmentMode defines the new state of the enrollmentMode flag + */ + void setEnrollmentMode(bool enrollmentMode); + + /** + * Check if a peer's cache entry has a vaild MitM key. + * + * If true then the other peer ha a valid MtiM key, i.e. the peer has performed + * the enrollment procedure. A PBX ZRTP Back-2-Back application can use this function + * to check which of the peers is enrolled. + * + * @return True if the other peer has a valid Mitm key (is enrolled). + */ + bool isPeerEnrolled(); + + /** + * Send the SAS relay packet. + * + * The method creates and sends a SAS relay packet according to the ZRTP + * specifications. Usually only a MitM capable user agent (PBX) uses this + * function. + * + * @param sh the full SAS hash value, 32 bytes + * @param render the SAS rendering algorithm + */ + bool sendSASRelayPacket(uint8_t* sh, std::string render); + + /** + * Get the commited SAS rendering algorithm for this ZRTP session. + * + * @return the commited SAS rendering algorithm + */ + std::string getSasType(); + + /** + * Get the computed SAS hash for this ZRTP session. + * + * A PBX ZRTP back-to-Back function uses this function to get the SAS + * hash of an enrolled client to construct the SAS relay packet for + * the other client. + * + * @return a pointer to the byte array that contains the full + * SAS hash. + */ + uint8_t* getSasHash(); + + /** + * Set signature data. + * + * This functions stores signature data and transmitts it during ZRTP + * processing to the other party as part of the Confirm packets. Refer to + * chapters 5.7 and 7.2. + * + * The signature data must be set before ZRTP the application calls + * <code>start()</code>. + * + * @param data + * The signature data including the signature type block. The method + * copies this data into the Confirm packet at signature type block. + * @param length + * The length of the signature data in bytes. This length must be + * multiple of 4. + * @return + * True if the method stored the data, false otherwise. + */ + bool setSignatureData(uint8_t* data, int32_t length); + + /** + * Get signature data. + * + * This functions returns a pointer to the signature data that was receivied + * during ZRTP processing. Refer to chapters 5.7 and 7.2. + * + * The returned pointer points to volatile data that is valid only during the + * <code>checkSASSignature()</code> callback funtion. The application must copy + * the signature data if it will be used after the callback function returns. + * + * The signature data can be retrieved after ZRTP enters secure state. + * <code>start()</code>. + * + * @return + * Pointer to signature data. + */ + const uint8_t* getSignatureData(); + + /** + * Get length of signature data in number of bytes. + * + * This functions returns the length of signature data that was receivied + * during ZRTP processing. Refer to chapters 5.7 and 7.2. + * + * @return + * Length in bytes of the received signature data. The method returns + * zero if no signature data is avilable. + */ + int32_t getSignatureLength(); + + /** + * Emulate a Conf2Ack packet. + * + * This method emulates a Conf2Ack packet. According to ZRTP specification + * the first valid SRTP packet that the Initiator receives must switch + * on secure mode. Refer to chapter 4 in the specificaton + * + */ + void conf2AckSecure(); + + /** + * Get other party's ZID (ZRTP Identifier) data + * + * This functions returns the other party's ZID that was receivied + * during ZRTP processing. + * + * The ZID data can be retrieved after ZRTP receive the first Hello + * packet from the other party. The application may call this method + * for example during SAS processing in showSAS(...) user callback + * method. + * + * @param data + * Pointer to a data buffer. This buffer must have a size of + * at least 12 bytes (96 bit) (ZRTP Identifier, see chap. 4.9) + * @return + * Number of bytes copied into the data buffer - must be equivalent + * to 96 bit, usually 12 bytes. + */ + int32_t getPeerZid(uint8_t* data); + +private: + friend class ZrtpStateClass; + + /** + * The state engine takes care of protocol processing. + */ + ZrtpStateClass* stateEngine; + + /** + * This is my ZID that I send to the peer. + */ + uint8_t zid[IDENTIFIER_LEN]; + + /** + * The peer's ZID + */ + uint8_t peerZid[IDENTIFIER_LEN]; + + /** + * The callback class provides me with the interface to send + * data and to deal with timer management of the hosting system. + */ + ZrtpCallback* callback; + + /** + * My active Diffie-Helman context + */ + ZrtpDH* dhContext; + + /** + * The computed DH shared secret + */ + uint8_t* DHss; + + /** + * My computed public key + */ + uint8_t pubKeyBytes[400]; + /** + * Length off public key + */ +// int32_t pubKeyLen; + /** + * My Role in the game + */ + Role myRole; + + /** + * The human readable SAS value + */ + std::string SAS; + + /** + * The SAS hash for signaling and alike. Refer to chapters + * 4.5 and 7 how sasHash, sasValue and the SAS string are derived. + */ + uint8_t sasHash[MAX_DIGEST_LENGTH]; + /** + * The ids for the retained and other shared secrets + */ + uint8_t rs1IDr[MAX_DIGEST_LENGTH]; + uint8_t rs2IDr[MAX_DIGEST_LENGTH]; + uint8_t auxSecretIDr[MAX_DIGEST_LENGTH]; + uint8_t pbxSecretIDr[MAX_DIGEST_LENGTH]; + + uint8_t rs1IDi[MAX_DIGEST_LENGTH]; + uint8_t rs2IDi[MAX_DIGEST_LENGTH]; + uint8_t auxSecretIDi[MAX_DIGEST_LENGTH]; + uint8_t pbxSecretIDi[MAX_DIGEST_LENGTH]; + + /** + * pointers to aux secret storage and length of aux secret + */ + uint8_t* auxSecret; + int32_t auxSecretLength; + + /** + * Record if valid rs1 and/or rs1 were found in the + * retaind secret cache. + */ + bool rs1Valid; + bool rs2Valid; + /** + * My hvi + */ + uint8_t hvi[MAX_DIGEST_LENGTH]; + + /** + * The peer's hvi + */ + uint8_t peerHvi[8*ZRTP_WORD_SIZE]; + + /** + * Context to compute the SHA256 hash of selected messages. + * Used to compute the s0, refer to chapter 4.4.1.4 + */ + void* msgShaContext; + /** + * Commited Hash, Cipher, and public key algorithms + */ + AlgorithmEnum* hash; + AlgorithmEnum* cipher; + AlgorithmEnum* pubKey; + /** + * The selected SAS type. + */ + AlgorithmEnum* sasType; + + /** + * The selected SAS type. + */ + AlgorithmEnum* authLength; + + /** + * The Hash images as defined in chapter 5.1.1 (H0 is a random value, + * not stored here). Need full SHA 256 lenght to store hash value but + * only the leftmost 128 bits are used in computations and comparisons. + */ + uint8_t H0[IMPL_MAX_DIGEST_LENGTH]; + uint8_t H1[IMPL_MAX_DIGEST_LENGTH]; + uint8_t H2[IMPL_MAX_DIGEST_LENGTH]; + uint8_t H3[IMPL_MAX_DIGEST_LENGTH]; + uint8_t helloHash[IMPL_MAX_DIGEST_LENGTH]; + + uint8_t peerHelloHash[IMPL_MAX_DIGEST_LENGTH]; + uint8_t peerHelloVersion[ZRTP_WORD_SIZE + 1]; // +1 for nul byte + + // We get the peer's H? from the message where length is defined as 8 words + uint8_t peerH0[8*ZRTP_WORD_SIZE]; + uint8_t peerH1[8*ZRTP_WORD_SIZE]; + uint8_t peerH2[8*ZRTP_WORD_SIZE]; + uint8_t peerH3[8*ZRTP_WORD_SIZE]; + + /** + * The SHA256 hash over selected messages + */ + uint8_t messageHash[MAX_DIGEST_LENGTH]; + + /** + * The s0 + */ + uint8_t s0[MAX_DIGEST_LENGTH]; + + /** + * The new Retained Secret + */ + uint8_t newRs1[MAX_DIGEST_LENGTH]; + + /** + * The GoClear HMAC keys and confirm HMAC key + */ + uint8_t hmacKeyI[MAX_DIGEST_LENGTH]; + uint8_t hmacKeyR[MAX_DIGEST_LENGTH]; + + /** + * The Initiator's srtp key and salt + */ + uint8_t srtpKeyI[MAX_DIGEST_LENGTH]; + uint8_t srtpSaltI[MAX_DIGEST_LENGTH]; + + /** + * The Responder's srtp key and salt + */ + uint8_t srtpKeyR[MAX_DIGEST_LENGTH]; + uint8_t srtpSaltR[MAX_DIGEST_LENGTH]; + + /** + * The keys used to encrypt/decrypt the confirm message + */ + uint8_t zrtpKeyI[MAX_DIGEST_LENGTH]; + uint8_t zrtpKeyR[MAX_DIGEST_LENGTH]; + + /** + * Pointers to negotiated hash and HMAC functions + */ + void (*hashFunction)(unsigned char *data, + unsigned int data_length, + unsigned char *digest); + + void (*hashListFunction)(unsigned char *data[], + unsigned int data_length[], + unsigned char *digest); + + void (*hmacFunction)(uint8_t* key, uint32_t key_length, + uint8_t* data, int32_t data_length, + uint8_t* mac, uint32_t* mac_length); + + void (*hmacListFunction)( uint8_t* key, uint32_t key_length, + uint8_t* data[], uint32_t data_length[], + uint8_t* mac, uint32_t* mac_length ); + + void* (*createHashCtx)(); + + void (*closeHashCtx)(void* ctx, unsigned char* digest); + + void (*hashCtxFunction)(void* ctx, unsigned char* data, + unsigned int dataLength); + + void (*hashCtxListFunction)(void* ctx, unsigned char* dataChunks[], + unsigned int dataChunkLength[]); + + int32_t hashLength; + + // Funtion pointers to implicit hash and hmac functions + void (*hashFunctionImpl)(unsigned char *data, + unsigned int data_length, + unsigned char *digest); + + void (*hashListFunctionImpl)(unsigned char *data[], + unsigned int data_length[], + unsigned char *digest); + + void (*hmacFunctionImpl)(uint8_t* key, uint32_t key_length, + uint8_t* data, int32_t data_length, + uint8_t* mac, uint32_t* mac_length); + + void (*hmacListFunctionImpl)( uint8_t* key, uint32_t key_length, + uint8_t* data[], uint32_t data_length[], + uint8_t* mac, uint32_t* mac_length ); + + int32_t hashLengthImpl; + + /** + * The ZRTP Session Key + * Refer to chapter 5.4.1.4 + */ + uint8_t zrtpSession[MAX_DIGEST_LENGTH]; + + /** + * True if this ZRTP instance uses multi-stream mode. + */ + bool multiStream; + + /** + * True if the other ZRTP client supports multi-stream mode. + */ + bool multiStreamAvailable; + + /** + * Enable MitM (PBX) enrollment + * + * If set to true then ZRTP honors the PBX enrollment flag in + * Commit packets and calls the appropriate user callback + * methods. If the parameter is set to false ZRTP ignores the PBX + * enrollment flags. + */ + bool enableMitmEnrollment; + + /** + * True if a valid trusted MitM key of the other peer is available, i.e. enrolled. + */ + bool peerIsEnrolled; + + /** + * Set to true if the Hello packet contained the M-flag (MitM flag). + * We use this later to check some stuff for SAS Relay processing + */ + bool mitmSeen; + + /** + * Temporarily store computed pbxSecret, if user accepts enrollment then + * it will copied to our ZID record of the PBX (MitM) + */ + uint8_t* pbxSecretTmp; + uint8_t pbxSecretTmpBuffer[MAX_DIGEST_LENGTH]; + + /** + * If true then we will set the enrollment flag (E) in the confirm + * packets. Set to true if the PBX enrollment service started this ZRTP + * session. Can be set to true only if mitmMode is also true. + */ + bool enrollmentMode; + + /** + * Configuration data which algorithms to use. + */ + ZrtpConfigure configureAlgos; + /** + * Pre-initialized packets. + */ + ZrtpPacketHello zrtpHello; + ZrtpPacketHelloAck zrtpHelloAck; + ZrtpPacketConf2Ack zrtpConf2Ack; + ZrtpPacketClearAck zrtpClearAck; + ZrtpPacketGoClear zrtpGoClear; + ZrtpPacketError zrtpError; + ZrtpPacketErrorAck zrtpErrorAck; + ZrtpPacketDHPart zrtpDH1; + ZrtpPacketDHPart zrtpDH2; + ZrtpPacketCommit zrtpCommit; + ZrtpPacketConfirm zrtpConfirm1; + ZrtpPacketConfirm zrtpConfirm2; + ZrtpPacketPingAck zrtpPingAck; + ZrtpPacketSASrelay zrtpSasRelay; + ZrtpPacketRelayAck zrtpRelayAck; + + /** + * Random IV data to encrypt the confirm data, 128 bit for AES + */ + uint8_t randomIV[16]; + + uint8_t tempMsgBuffer[1024]; + int32_t lengthOfMsgData; + + /** + * Variables to store signature data. Includes the signature type block + */ + const uint8_t* signatureData; // will be set when needed + int32_t signatureLength; // overall length in bytes + + /** + * Is true if the other peer signaled SAS signature support in its Hello packet. + */ + bool signSasSeen; + + uint32_t peerSSRC; // peer's SSRC, required to setup PingAck packet + + /** + * Enable or disable paranoid mode. + * + * The Paranoid mode controls the behaviour and handling of the SAS verify flag. If + * Panaoid mode is set to flase then ZRtp applies the normal handling. If Paranoid + * mode is set to true then the handling is: + * + * <ul> + * <li> Force the SAS verify flag to be false at srtpSecretsOn() callback. This gives + * the user interface (UI) the indication to handle the SAS as <b>not verified</b>. + * See implementation note below.</li> + * <li> Don't set the SAS verify flag in the <code>Confirm</code> packets, thus the other + * also must report the SAS as <b>not verified</b>.</li> + * <li> ignore the <code>SASVerified()</code> function, thus do not set the SAS to verified + * in the ZRTP cache. </li> + * <li> Disable the <b>Trusted PBX MitM</b> feature. Just send the <code>SASRelay</code> packet + * but do not process the relayed data. This protects the user from a malicious + * "trusted PBX".</li> + * </ul> + * ZRtp performs alls other steps during the ZRTP negotiations as usual, in particular it + * computes, compares, uses, and stores the retained secrets. This avoids unnecessary warning + * messages. The user may enable or disable the Paranoid mode on a call-by-call basis without + * breaking the key continuity data. + * + * <b>Implementation note:</b></br> + * An application shall always display the SAS code if the SAS verify flag is <code>false</code>. + * The application shall also use mechanisms to remind the user to compare the SAS code, for + * example useing larger fonts, different colours and other display features. + */ + bool paranoidMode; + + /** + * Find the best Hash algorithm that is offered in Hello. + * + * Find the best, that is the strongest, Hash algorithm that our peer + * offers in its Hello packet. + * + * @param hello + * The Hello packet. + * @return + * The Enum that identifies the best offered Hash algortihm. Return + * <code>NumSupportedHashes</code> to signal that no matching Hash algorithm + * was found at all. + */ + AlgorithmEnum* findBestHash(ZrtpPacketHello *hello); + + /** + * Find the best symmetric cipher algorithm that is offered in Hello. + * + * Find the best, that is the strongest, cipher algorithm that our peer + * offers in its Hello packet. + * + * @param hello + * The Hello packet. + * @param pk + * The id of the selected public key algorithm + * @return + * The Enum that identifies the best offered Cipher algortihm. Return + * <code>NumSupportedSymCiphers</code> to signal that no matching Cipher algorithm + * was found at all. + */ + AlgorithmEnum* findBestCipher(ZrtpPacketHello *hello, AlgorithmEnum* pk); + + /** + * Find the best Public Key algorithm that is offered in Hello. + * + * Find the best, that is the strongest, public key algorithm that our peer + * offers in its Hello packet. + * + * @param hello + * The Hello packet. + * @return + * The Enum that identifies the best offered Public Key algortihm. Return + * <code>NumSupportedPubKeys</code> to signal that no matching Public Key algorithm + * was found at all. + */ + AlgorithmEnum* findBestPubkey(ZrtpPacketHello *hello); + + /** + * Find the best SAS algorithm that is offered in Hello. + * + * Find the best, that is the strongest, SAS algorithm that our peer + * offers in its Hello packet. + * + * @param hello + * The Hello packet. + * @return + * The Enum that identifies the best offered SAS algortihm. Return + * <code>NumSupportedSASTypes</code> to signal that no matching SAS algorithm + * was found at all. + */ + AlgorithmEnum* findBestSASType(ZrtpPacketHello* hello); + + /** + * Find the best authentication length that is offered in Hello. + * + * Find the best, that is the strongest, authentication length that our peer + * offers in its Hello packet. + * + * @param hello + * The Hello packet. + * @return + * The Enum that identifies the best offered authentication length. Return + * <code>NumSupportedAuthLenghts</code> to signal that no matching length + * was found at all. + */ + AlgorithmEnum* findBestAuthLen(ZrtpPacketHello* hello); + + /** + * Check if MultiStream mode is offered in Hello. + * + * Find the best, that is the strongest, authentication length that our peer + * offers in its Hello packet. + * + * @param hello + * The Hello packet. + * @return + * True if multi stream mode is available, false otherwise. + */ + bool checkMultiStream(ZrtpPacketHello* hello); + + /** + * Save the computed MitM secret to the ZID record of the peer + */ + void writeEnrollmentPBX(); + + /** + * Compute my hvi value according to ZRTP specification. + */ + void computeHvi(ZrtpPacketDHPart* dh, ZrtpPacketHello *hello); + + void computeSharedSecretSet(ZIDRecord& zidRec); + + void computeSRTPKeys(); + + void KDF(uint8_t* key, uint32_t keyLength, uint8_t* label, int32_t labelLength, + uint8_t* context, int32_t contextLength, int32_t L, uint8_t* output); + + void generateKeysInitiator(ZrtpPacketDHPart *dhPart, ZIDRecord& zidRec); + + void generateKeysResponder(ZrtpPacketDHPart *dhPart, ZIDRecord& zidRec); + + void generateKeysMultiStream(); + + void computePBXSecret(); + + void setNegotiatedHash(AlgorithmEnum* hash); + + /* + * The following methods are helper functions for ZrtpStateClass. + * ZrtpStateClass calls them to prepare packets, send data, report + * problems, etc. + */ + /** + * Send a ZRTP packet. + * + * The state engines calls this method to send a packet via the RTP + * stack. + * + * @param packet + * Points to the ZRTP packet. + * @return + * zero if sending failed, one if packet was send + */ + int32_t sendPacketZRTP(ZrtpPacketBase *packet); + + /** + * Activate a Timer using the host callback. + * + * @param tm + * The time in milliseconds. + * @return + * zero if activation failed, one if timer was activated + */ + int32_t activateTimer(int32_t tm); + + /** + * Cancel the active Timer using the host callback. + * + * @return + * zero if activation failed, one if timer was activated + */ + int32_t cancelTimer(); + + /** + * Prepare a Hello packet. + * + * Just take the preinitialized Hello packet and return it. No + * further processing required. + * + * @return + * A pointer to the initialized Hello packet. + */ + ZrtpPacketHello* prepareHello(); + + /** + * Prepare a HelloAck packet. + * + * Just take the preinitialized HelloAck packet and return it. No + * further processing required. + * + * @return + * A pointer to the initialized HelloAck packet. + */ + ZrtpPacketHelloAck* prepareHelloAck(); + + /** + * Prepare a Commit packet. + * + * We have received a Hello packet from our peer. Check the offers + * it makes to us and select the most appropriate. Using the + * selected values prepare a Commit packet and return it to protocol + * state engine. + * + * @param hello + * Points to the received Hello packet + * @param errMsg + * Points to an integer that can hold a ZRTP error code. + * @return + * A pointer to the prepared Commit packet + */ + ZrtpPacketCommit* prepareCommit(ZrtpPacketHello *hello, uint32_t* errMsg); + + /** + * Prepare a Commit packet for Multi Stream mode. + * + * Using the selected values prepare a Commit packet and return it to protocol + * state engine. + * + * @param hello + * Points to the received Hello packet + * @return + * A pointer to the prepared Commit packet for multi stream mode + */ + ZrtpPacketCommit* prepareCommitMultiStream(ZrtpPacketHello *hello); + + /** + * Prepare the DHPart1 packet. + * + * This method prepares a DHPart1 packet. The input to the method is always + * a Commit packet received from the peer. Also we a in the role of the + * Responder. + * + * When we receive a Commit packet we get the selected ciphers, hashes, etc + * and cross-check if this is ok. Then we need to initialize a set of DH + * keys according to the selected cipher. Using this data we prepare our DHPart1 + * packet. + */ + ZrtpPacketDHPart* prepareDHPart1(ZrtpPacketCommit *commit, uint32_t* errMsg); + + /** + * Prepare the DHPart2 packet. + * + * This method prepares a DHPart2 packet. The input to the method is always + * a DHPart1 packet received from the peer. Our peer sends the DH1Part as + * response to our Commit packet. Thus we are in the role of the + * Initiator. + * + */ + ZrtpPacketDHPart* prepareDHPart2(ZrtpPacketDHPart* dhPart1, uint32_t* errMsg); + + /** + * Prepare the Confirm1 packet. + * + * This method prepare the Confirm1 packet. The input to this method is the + * DHPart2 packect received from our peer. The peer sends the DHPart2 packet + * as response of our DHPart1. Here we are in the role of the Responder + * + */ + ZrtpPacketConfirm* prepareConfirm1(ZrtpPacketDHPart* dhPart2, uint32_t* errMsg); + + /** + * Prepare the Confirm1 packet in multi stream mode. + * + * This method prepares the Confirm1 packet. The state engine call this method + * if multi stream mode is selected and a Commit packet was received. The input to + * this method is the Commit. + * Here we are in the role of the Responder + * + */ + ZrtpPacketConfirm* prepareConfirm1MultiStream(ZrtpPacketCommit* commit, uint32_t* errMsg); + + /** + * Prepare the Confirm2 packet. + * + * This method prepare the Confirm2 packet. The input to this method is the + * Confirm1 packet received from our peer. The peer sends the Confirm1 packet + * as response of our DHPart2. Here we are in the role of the Initiator + */ + ZrtpPacketConfirm* prepareConfirm2(ZrtpPacketConfirm* confirm1, uint32_t* errMsg); + + /** + * Prepare the Confirm2 packet in multi stream mode. + * + * This method prepares the Confirm2 packet. The state engine call this method if + * multi stream mode is active and in state CommitSent. The input to this method is + * the Confirm1 packet received from our peer. The peer sends the Confirm1 packet + * as response of our Commit packet in multi stream mode. + * Here we are in the role of the Initiator + */ + ZrtpPacketConfirm* prepareConfirm2MultiStream(ZrtpPacketConfirm* confirm1, uint32_t* errMsg); + + /** + * Prepare the Conf2Ack packet. + * + * This method prepare the Conf2Ack packet. The input to this method is the + * Confirm2 packet received from our peer. The peer sends the Confirm2 packet + * as response of our Confirm1. Here we are in the role of the Initiator + */ + ZrtpPacketConf2Ack* prepareConf2Ack(ZrtpPacketConfirm* confirm2, uint32_t* errMsg); + + /** + * Prepare the ErrorAck packet. + * + * This method prepares the ErrorAck packet. The input to this method is the + * Error packet received from the peer. + */ + ZrtpPacketErrorAck* prepareErrorAck(ZrtpPacketError* epkt); + + /** + * Prepare the Error packet. + * + * This method prepares the Error packet. The input to this method is the + * error code to be included into the message. + */ + ZrtpPacketError* prepareError(uint32_t errMsg); + + /** + * Prepare a ClearAck packet. + * + * This method checks if the GoClear message is valid. If yes then switch + * off SRTP processing, stop sending of RTP packets (pause transmit) and + * inform the user about the fact. Only if user confirms the GoClear message + * normal RTP processing is resumed. + * + * @return + * NULL if GoClear could not be authenticated, a ClearAck packet + * otherwise. + */ + ZrtpPacketClearAck* prepareClearAck(ZrtpPacketGoClear* gpkt); + + /** + * Prepare the ErrorAck packet. + * + * This method prepares the ErrorAck packet. The input to this method is the + * Error packet received from the peer. + */ + ZrtpPacketPingAck* preparePingAck(ZrtpPacketPing* ppkt); + + /** + * Prepare the RelayAck packet. + * + * This method prepares the RelayAck packet. The input to this method is the + * SASrelay packet received from the peer. + */ + ZrtpPacketRelayAck* prepareRelayAck(ZrtpPacketSASrelay* srly, uint32_t* errMsg); + + /** + * Prepare a GoClearAck packet w/o HMAC + * + * Prepare a GoCLear packet without a HMAC but with a short error message. + * This type of GoClear is used if something went wrong during the ZRTP + * negotiation phase. + * + * @return + * A goClear packet without HMAC + */ + ZrtpPacketGoClear* prepareGoClear(uint32_t errMsg = 0); + + /** + * Compare the hvi values. + * + * Compare a received Commit packet with our Commit packet and returns + * which Commit packt is "more important". See chapter 5.2 to get further + * information how to compare Commit packets. + * + * @param commit + * Pointer to the peer's commit packet we just received. + * @return + * <0 if our Commit packet is "less important" + * >0 if our Commit is "more important" + * 0 shouldn't happen because we compare crypto hashes + */ + int32_t compareCommit(ZrtpPacketCommit *commit); + + /** + * Verify the H2 hash image. + * + * Verifies the H2 hash contained in a received commit message. + * This functions just verifies H2 but does not store it. + * + * @param commit + * Pointer to the peer's commit packet we just received. + * @return + * true if H2 is ok and verified + * false if H2 could not be verified + */ + bool verifyH2(ZrtpPacketCommit *commit); + + /** + * Send information messages to the hosting environment. + * + * The ZRTP implementation uses this method to send information messages + * to the host. Along with the message ZRTP provides a severity indicator + * that defines: Info, Warning, Error, Alert. Refer to the MessageSeverity + * enum in the ZrtpCallback class. + * + * @param severity + * This defines the message's severity + * @param subCode + * The subcode identifying the reason. + * @see ZrtpCodes#MessageSeverity + */ + void sendInfo(GnuZrtpCodes::MessageSeverity severity, int32_t subCode); + + /** + * ZRTP state engine calls this if the negotiation failed. + * + * ZRTP calls this method in case ZRTP negotiation failed. The parameters + * show the severity as well as some explanatory text. + * + * @param severity + * This defines the message's severity + * @param subCode + * The subcode identifying the reason. + * @see ZrtpCodes#MessageSeverity + */ + void zrtpNegotiationFailed(GnuZrtpCodes::MessageSeverity severity, int32_t subCode); + + /** + * ZRTP state engine calls this method if the other side does not support ZRTP. + * + * If the other side does not answer the ZRTP <em>Hello</em> packets then + * ZRTP calls this method, + * + */ + void zrtpNotSuppOther(); + + /** + * Signal SRTP secrets are ready. + * + * This method calls a callback method to inform the host that the SRTP + * secrets are ready. + * + * @param part + * Defines for which part (sender or receiver) to switch on security + * @return + * Returns false if something went wrong during initialization of SRTP + * context. Propagate error back to state engine. + */ + bool srtpSecretsReady(EnableSecurity part); + + /** + * Switch off SRTP secrets. + * + * This method calls a callback method to inform the host that the SRTP + * secrets shall be cleared. + * + * @param part + * Defines for which part (sender or receiver) to clear + */ + void srtpSecretsOff(EnableSecurity part); + + /** + * ZRTP state engine calls these methods to enter or leave its + * synchronization mutex. + */ + void synchEnter(); + + void synchLeave(); + + /** + * Helper function to store ZRTP message data in a temporary buffer + * + * This functions first clears the temporary buffer, then stores + * the packet's data to it. We use this to check the packet's HMAC + * after we received the HMAC key in to following packet. + * + * @param data + * Pointer to the packet's ZRTP message + */ + void storeMsgTemp(ZrtpPacketBase* pkt); + + /** + * Helper function to check a ZRTP message HMAC + * + * This function gets a HMAC key and uses it to compute a HMAC + * with this key and the stored data of a previous received ZRTP + * message. It compares the computed HMAC and the HMAC stored in + * the received message and returns the result. + * + * @param key + * Pointer to the HMAC key. + * @return + * Returns true if the computed HMAC and the stored HMAC match, + * false otherwise. + */ + bool checkMsgHmac(uint8_t* key); + + /** + * Set the client ID for ZRTP Hello message. + * + * The user of ZRTP must set its id to identify itself in the + * ZRTP HELLO message. The maximum length is 16 characters. Shorter + * id string are allowed, they will be filled with blanks. A longer id + * is truncated to 16 characters. + * + * The identifier is set in the Hello packet of ZRTP. Thus only after + * setting the identifier ZRTP can compute the HMAC and the final + * helloHash. + * + * @param id + * The client's id + */ + void setClientId(std::string id); +}; + +/** + * @} + */ +#endif // ZRTP + |