Commit 26022db5 authored by johan's avatar johan
Browse files

Cache functionnal

- use libxml2 to manage cache
- add set/unset previously verified sas flag management interface
- clean debug code
parent 4e60d73a
......@@ -31,6 +31,14 @@ if test "$found_cunit" = "no" ; then
])
fi
dnl check libxml2
PKG_CHECK_MODULES(LIBXML2, [libxml-2.0] ,[libxml2_found=yes] ,foo=bar)
if test "$libxml2_found" != "yes" ; then
AC_MSG_WARN([libxml2 not found. Disabling cache.)])
else
AC_DEFINE(HAVE_LIBXML2,1,[defined when libxml2 is available]) ]
fi
if test "$found_cunit" = "no" ; then
AC_MSG_WARN([Could not find cunit framework, tests are not compiled.])
else
......
......@@ -195,4 +195,18 @@ __attribute__ ((visibility ("default"))) int bzrtp_isSecure(bzrtpContext_t *zrtp
*/
__attribute__ ((visibility ("default"))) int bzrtp_processMessage(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, uint8_t *zrtpPacketString, uint16_t zrtpPacketStringLength);
/**
* @brief Called by user when the SAS has been verified
*
* @param[in/out] zrtpContext The ZRTP context we're dealing with
*/
__attribute__ ((visibility ("default"))) void bzrtp_SASVerified(bzrtpContext_t *zrtpContext);
/**
* @brief Called by user when the SAS has been set to unverified
*
* @param[in/out] zrtpContext The ZRTP context we're dealing with
*/
__attribute__ ((visibility ("default"))) void bzrtp_resetSASVerified(bzrtpContext_t *zrtpContext);
#endif /* ifndef BZRTP_H */
......@@ -39,7 +39,6 @@
#define RESPONDER 1
#include <stdint.h>
#include <stdio.h>
typedef struct bzrtpChannelContext_struct bzrtpChannelContext_t;
......@@ -71,7 +70,8 @@ typedef struct bzrtpTimer_struct {
uint8_t timerStep; /**< in ms. Step between next timer fire: used to reset firingTime for next timer fire */
} bzrtpTimer_t;
/* the rs1 and rs2 are 256 bits long - see rfc section 4.6.1 */
#define RETAINED_SECRET_LENGTH 32
/**
* @brief A set of cached secrets retrieved from the cache as defined
*/
......@@ -84,6 +84,7 @@ typedef struct cachedSecrets_struct {
uint8_t auxsecretLength; /**< auxiliary secret length in bytes */
uint8_t *pbxsecret; /**< PBX secret */
uint8_t pbxsecretLength; /**< PBX secret length in bytes */
uint8_t previouslyVerifiedSas; /* boolean, is a SAS has been previously verified with this user */
} cachedSecrets_t;
/**
......@@ -101,8 +102,8 @@ typedef struct cachedSecretsHash_struct {
*/
typedef struct zrtpCallbacks_struct {
/* cache related functions */
int (* bzrtp_loadCache)(uint8_t **cacheBuffer, uint32_t *cacheBufferSize); /**< Cache related function : load the whole cache file in a buffer allocated by the function, return the buffer and its size in bytes */
int (* bzrtp_writeCache)(uint8_t *input, uint32_t size); /**< Cache related function : write size bytes to cache */
int (* bzrtp_loadCache)(void *clientData, uint8_t **cacheBuffer, uint32_t *cacheBufferSize); /**< Cache related function : load the whole cache file in a buffer allocated by the function, return the buffer and its size in bytes */
int (* bzrtp_writeCache)(void *clientData, uint8_t *input, uint32_t size); /**< Cache related function : write size bytes to cache */
/* sending packets */
int (* bzrtp_sendData)(void *clientData, uint8_t *packetString, uint16_t packetLength); /**< Send a ZRTP packet to peer. Shall return 0 on success */
......
......@@ -30,7 +30,8 @@
#include "typedef.h"
#define ZRTP_ZIDCACHE_INVALID_CONTEXT 0x2001
#define ZRTP_ZIDCACHE_UNABLETOUPDATE 0x2002
#define ZRTP_ZIDCACHE_INVALID_CACHE 0x2002
#define ZRTP_ZIDCACHE_UNABLETOUPDATE 0x2003
/**
* @brief : retrieve ZID from cache
......@@ -55,4 +56,18 @@ int bzrtp_getSelfZID(bzrtpContext_t *context, uint8_t selfZID[12]);
*/
int bzrtp_getPeerAssociatedSecretsHash(bzrtpContext_t *context, uint8_t peerZID[12]);
/**
* @brief Write the given taf into peer Node, if the tag exists, content is replaced
* Cache file is locked(TODO), read and updated during this call
*
* @param[in/out] context the current context, used to get the negotiated Hash algorithm and cache access functions and store result
* @param[in] peerZID a byte array of the peer ZID
* @param[in] tagName the tagname of node to be written, it MUST be null terminated
* @param[in] tagNameLength the length of tagname (not including the null termination char)
* @param[in] tagContent the content of the node(a byte buffer which will be converted to hexa string)
* @param[in] tagContentLength the length of the content to be written
*
* return 0 on success, error code otherwise
*/
int bzrtp_writePeerNode(bzrtpContext_t *context, uint8_t peerZID[12], uint8_t *tagName, uint8_t tagNameLength, uint8_t *tagContent, uint32_t tagContentLength);
#endif /* ZIDCACHE_H */
lib_LTLIBRARIES = libbzrtp.la
libbzrtp_la_LIBADD= $(LIBXML2_LIBS)
libbzrtp_la_SOURCES= bzrtp.c cryptoPolarssl.c cryptoUtils.c packetParser.c zidCache.c stateMachine.c
libbzrtp_la_LDFLAGS=-fvisibility=hidden -no-undefined
AM_CPPFLAGS= -I$(top_srcdir)/include
AM_CFLAGS=$(LIBXML2_CFLAGS)
......@@ -109,15 +109,14 @@ bzrtpContext_t *bzrtp_createBzrtpContext(uint32_t selfSSRC)
/**
* @brief Perform some initialisation which can't be done without some callback functions:
* - get ZID
* This function is called once per session when the first channel is created.
* It must be called after the cache callback function have been set
* - load cache
* - get ZID from cache or generate it
*
* @param[in] context The context to initialise
* @param[in] context The context to initialise
*/
void bzrtp_initBzrtpContext(bzrtpContext_t *context) {
/* load the cache buffer */
if (context->zrtpCallbacks.bzrtp_loadCache != 0) {
context->zrtpCallbacks.bzrtp_loadCache(&context->cacheBuffer, &(context->cacheBufferLength));
}
/* initialise ZID. Randomly generated if no ZID is found in cache or no cache found */
bzrtp_getSelfZID(context, context->selfZID);
......@@ -192,10 +191,10 @@ void bzrtp_destroyBzrtpContext(bzrtpContext_t *context, uint32_t selfSSRC)
int bzrtp_setCallback(bzrtpContext_t *context, int (*functionPointer)(), uint16_t functionID) {
switch (functionID) {
case ZRTP_CALLBACK_LOADCACHE:
context->zrtpCallbacks.bzrtp_loadCache = (int (*)(uint8_t **, uint32_t *))functionPointer;
context->zrtpCallbacks.bzrtp_loadCache = (int (*)(void *, uint8_t **, uint32_t *))functionPointer;
break;
case ZRTP_CALLBACK_WRITECACHE:
context->zrtpCallbacks.bzrtp_writeCache = (int (*)(uint8_t *, uint32_t))functionPointer;
context->zrtpCallbacks.bzrtp_writeCache = (int (*)(void *, uint8_t *, uint32_t))functionPointer;
break;
case ZRTP_CALLBACK_SENDDATA:
context->zrtpCallbacks.bzrtp_sendData = (int (*)(void *, uint8_t *, uint16_t))functionPointer;
......@@ -308,7 +307,6 @@ int bzrtp_startChannelEngine(bzrtpContext_t *zrtpContext, uint32_t selfSSRC) {
int bzrtp_iterate(bzrtpContext_t *zrtpContext, uint32_t selfSSRC, uint64_t timeReference) {
/* get channel context */
bzrtpChannelContext_t *zrtpChannelContext = getChannelContext(zrtpContext, selfSSRC);
fflush(NULL);
if (zrtpChannelContext == NULL) {
return BZRTP_ERROR_INVALIDCONTEXT;
......@@ -424,6 +422,32 @@ int bzrtp_isSecure(bzrtpContext_t *zrtpContext, uint32_t selfSSRC) {
}
/*
* @brief Called by user when the SAS has been verified
* update the cache(if any) to set the previously verified flag
*
* @param[in/out] zrtpContext The ZRTP context we're dealing with
*/
void bzrtp_SASVerified(bzrtpContext_t *zrtpContext) {
if (zrtpContext != NULL) {
uint8_t pvsFlag = 1;
bzrtp_writePeerNode(zrtpContext, zrtpContext->peerZID, (uint8_t *)"pvs", 3, &pvsFlag, 1);
}
}
/*
* @brief Called by user when the SAS has been set to unverified
* update the cache(if any) to unset the previously verified flag
*
* @param[in/out] zrtpContext The ZRTP context we're dealing with
*/
void bzrtp_resetSASVerified(bzrtpContext_t *zrtpContext) {
if (zrtpContext != NULL) {
uint8_t pvsFlag = 0;
bzrtp_writePeerNode(zrtpContext, zrtpContext->peerZID, (uint8_t *)"pvs", 3, &pvsFlag, 1);
}
}
/* Local functions implementation */
/**
......
......@@ -139,7 +139,6 @@ bzrtpPacket_t *bzrtp_packetCheck(const uint8_t * input, uint16_t inputLength, ui
* TODO: what if we got a Sequence Number overflowing the 16 bits ? */
uint16_t sequenceNumber = (((uint16_t)input[2])<<8) | ((uint16_t)input[3]);
if (sequenceNumber <= lastValidSequenceNumber) {
printf("Sequence number check last %d current %d", lastValidSequenceNumber, sequenceNumber);
*exitCode = BZRTP_PARSER_ERROR_OUTOFORDER;
return NULL;
}
......@@ -1219,7 +1218,7 @@ bzrtpPacket_t *bzrtp_createZrtpPacket(bzrtpContext_t *zrtpContext, bzrtpChannelC
zrtpConfirmMessage->sig_len = 0; /* signature is not supported */
zrtpConfirmMessage->cacheExpirationInterval = 0xFFFFFFFF; /* expiration interval is set to unlimited as recommended in rfc section 4.9 */
zrtpConfirmMessage->E = 0; /* we are not a PBX and then will never signal an enrollment - rfc section 7.3.1 */
zrtpConfirmMessage->V = 0; /* TODO: this one shall be read from the cache - rfc section 7.1 */
zrtpConfirmMessage->V = zrtpContext->cachedSecret.previouslyVerifiedSas;
zrtpConfirmMessage->A = 0; /* Go clear message is not supported - rfc section 4.7.2 */
zrtpConfirmMessage->D = 0; /* The is no backdoor in our implementation of ZRTP - rfc section 11 */
......
......@@ -25,7 +25,7 @@
*/
#include <stdlib.h>
#include "string.h"
#include <string.h>
#include "typedef.h"
#include "packetParser.h"
#include "cryptoUtils.h"
......@@ -35,11 +35,12 @@
/* Local functions prototypes */
int bzrtp_turnIntoResponder(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket, bzrtpCommitMessage_t *commitMessage);
int bzrtp_responseToHelloMessage(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket, bzrtpStateMachine_t nextState);
int bzrtp_responseToHelloMessage(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket);
int bzrtp_computeS0DHMMode(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext);
int bzrtp_computeS0MultiStreamMode(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext);
int bzrtp_deriveKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext);
int bzrtp_deriveSrtpKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext);
int bzrtp_updateCachedSecrets(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext);
/*
* @brief This is the initial state
......@@ -108,11 +109,16 @@ int state_discovery_init(bzrtpEvent_t event) {
/* if we have an Hello packet, we must use it to determine which algo we will agree on */
if (zrtpPacket->messageType == MSGTYPE_HELLO) {
retval = bzrtp_responseToHelloMessage(zrtpContext, zrtpChannelContext, zrtpPacket, state_discovery_waitingForHelloAck);
retval = bzrtp_responseToHelloMessage(zrtpContext, zrtpChannelContext, zrtpPacket);
if (retval != 0) {
return retval;
}
/* reset the sending Hello timer as peer may have started slowly and lost all our Hello packets */
zrtpChannelContext->timer.status = BZRTP_TIMER_ON;
zrtpChannelContext->timer.firingTime = 0;
zrtpChannelContext->timer.firingCount = 0;
zrtpChannelContext->timer.timerStep = HELLO_BASE_RETRANSMISSION_STEP;
/* set next state (do not call it as we will just be waiting for a HelloACK packet from peer, nothing to do) */
zrtpChannelContext->stateMachine = state_discovery_waitingForHelloAck;
......@@ -204,7 +210,7 @@ int state_discovery_waitingForHello(bzrtpEvent_t event) {
/* packet is valid, set the sequence Number in channel context */
zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber;
retval = bzrtp_responseToHelloMessage(zrtpContext, zrtpChannelContext, zrtpPacket, state_discovery_waitingForHelloAck);
retval = bzrtp_responseToHelloMessage(zrtpContext, zrtpChannelContext, zrtpPacket);
if (retval != 0) {
return retval;
}
......@@ -480,28 +486,41 @@ int state_keyAgreement_sendingCommit(bzrtpEvent_t event) {
/* Check shared secret hash found in the DHPart1 message */
/* if we do not have the secret, don't check it as we do not expect the other part to have it neither */
/* TODO: in case of cache mismatch, warn the user and erase secret as it must not be used to compute s0 */
if (zrtpContext->cachedSecret.rs1!=NULL) {
if (memcmp(zrtpContext->initiatorCachedSecretHash.rs1ID, dhPart1Message->rs1ID,8) != 0) {
bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;
if (memcmp(zrtpContext->responderCachedSecretHash.rs1ID, dhPart1Message->rs1ID,8) != 0) {
free(zrtpContext->cachedSecret.rs1);
zrtpContext->cachedSecret.rs1= NULL;
zrtpContext->cachedSecret.rs1Length = 0;
/*bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;*/
}
}
if (zrtpContext->cachedSecret.rs2!=NULL) {
if (memcmp(zrtpContext->initiatorCachedSecretHash.rs2ID, dhPart1Message->rs2ID,8) != 0) {
bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;
if (memcmp(zrtpContext->responderCachedSecretHash.rs2ID, dhPart1Message->rs2ID,8) != 0) {
free(zrtpContext->cachedSecret.rs2);
zrtpContext->cachedSecret.rs2= NULL;
zrtpContext->cachedSecret.rs2Length = 0;
/*bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;*/
}
}
if (zrtpContext->cachedSecret.auxsecret!=NULL) {
if (memcmp(zrtpChannelContext->initiatorAuxsecretID, dhPart1Message->auxsecretID,8) != 0) {
bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;
if (memcmp(zrtpChannelContext->responderAuxsecretID, dhPart1Message->auxsecretID,8) != 0) {
free(zrtpContext->cachedSecret.auxsecret);
zrtpContext->cachedSecret.auxsecret= NULL;
zrtpContext->cachedSecret.auxsecretLength = 0;
/*bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;*/
}
}
if (zrtpContext->cachedSecret.pbxsecret!=NULL) {
if (memcmp(zrtpContext->initiatorCachedSecretHash.pbxsecretID, dhPart1Message->pbxsecretID,8) != 0) {
bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;
if (memcmp(zrtpContext->responderCachedSecretHash.pbxsecretID, dhPart1Message->pbxsecretID,8) != 0) {
free(zrtpContext->cachedSecret.pbxsecret);
zrtpContext->cachedSecret.pbxsecret= NULL;
zrtpContext->cachedSecret.pbxsecretLength = 0;
/*bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;*/
}
}
......@@ -711,26 +730,38 @@ int state_keyAgreement_responderSendingDHPart1(bzrtpEvent_t event) {
/* if we do not have the secret, don't check it as we do not expect the other part to have it neither */
if (zrtpContext->cachedSecret.rs1!=NULL) {
if (memcmp(zrtpContext->initiatorCachedSecretHash.rs1ID, dhPart2Message->rs1ID,8) != 0) {
bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;
free(zrtpContext->cachedSecret.rs1);
zrtpContext->cachedSecret.rs1= NULL;
zrtpContext->cachedSecret.rs1Length = 0;
/*bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;*/
}
}
if (zrtpContext->cachedSecret.rs2!=NULL) {
if (memcmp(zrtpContext->initiatorCachedSecretHash.rs2ID, dhPart2Message->rs2ID,8) != 0) {
bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;
free(zrtpContext->cachedSecret.rs2);
zrtpContext->cachedSecret.rs2= NULL;
zrtpContext->cachedSecret.rs2Length = 0;
/*bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;*/
}
}
if (zrtpContext->cachedSecret.auxsecret!=NULL) {
if (memcmp(zrtpChannelContext->initiatorAuxsecretID, dhPart2Message->auxsecretID,8) != 0) {
bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;
free(zrtpContext->cachedSecret.auxsecret);
zrtpContext->cachedSecret.auxsecret= NULL;
zrtpContext->cachedSecret.auxsecretLength = 0;
/*bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;*/
}
}
if (zrtpContext->cachedSecret.pbxsecret!=NULL) {
if (memcmp(zrtpContext->initiatorCachedSecretHash.pbxsecretID, dhPart2Message->pbxsecretID,8) != 0) {
bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;
free(zrtpContext->cachedSecret.pbxsecret);
zrtpContext->cachedSecret.pbxsecret= NULL;
zrtpContext->cachedSecret.pbxsecretLength = 0;
/*bzrtp_freeZrtpPacket(zrtpPacket);
return BZRTP_ERROR_CACHEMISMATCH;*/
}
}
......@@ -1077,6 +1108,9 @@ int state_confirmation_responderSendingConfirm1(bzrtpEvent_t event) {
if (retval!=0) {
return retval;
}
/* compute and update in cache the retained shared secret */
bzrtp_updateCachedSecrets(zrtpContext, zrtpChannelContext);
/* send them to the environment for receiver as we may receive a srtp packet in response to our conf2ACK */
if (zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable != NULL) {
......@@ -1244,6 +1278,9 @@ int state_confirmation_initiatorSendingConfirm2(bzrtpEvent_t event) {
/* stop the retransmission timer */
zrtpChannelContext->timer.status = BZRTP_TIMER_OFF;
/* compute and update in cache the retained shared secret */
bzrtp_updateCachedSecrets(zrtpContext, zrtpChannelContext);
/* send the sender srtp keys to the client(we sent receiver only when the first confirm1 packet arrived) */
if (zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable != NULL) {
zrtpContext->zrtpCallbacks.bzrtp_srtpSecretsAvailable(zrtpChannelContext->clientData, &zrtpChannelContext->srtpSecrets, ZRTP_SRTP_SECRETS_FOR_SENDER);
......@@ -1324,7 +1361,7 @@ int state_secure(bzrtpEvent_t event) {
/* call the environment to signal we're ready to operate */
if (zrtpContext->zrtpCallbacks.bzrtp_startSrtpSession!= NULL) {
zrtpContext->zrtpCallbacks.bzrtp_startSrtpSession(zrtpChannelContext->clientData, zrtpChannelContext->srtpSecrets.sas, 0); /* TODO: last param is the verified flag but we are cacheless for now so always 0*/
zrtpContext->zrtpCallbacks.bzrtp_startSrtpSession(zrtpChannelContext->clientData, zrtpChannelContext->srtpSecrets.sas, zrtpContext->cachedSecret.previouslyVerifiedSas);
}
return 0;
}
......@@ -1480,7 +1517,7 @@ int bzrtp_turnIntoResponder(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *
*
* @return 0 on succes, error code otherwise
*/
int bzrtp_responseToHelloMessage(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket, bzrtpStateMachine_t nextState) {
int bzrtp_responseToHelloMessage(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext, bzrtpPacket_t *zrtpPacket) {
int retval;
bzrtpHelloMessage_t *helloMessage = (bzrtpHelloMessage_t *)zrtpPacket->messageData;
......@@ -1559,6 +1596,7 @@ int bzrtp_responseToHelloMessage(bzrtpContext_t *zrtpContext, bzrtpChannelContex
/* When in PreShared mode Derive ZRTPSess, s0 from the retained secret and then all the other keys */
if ((zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Prsh)) {
/*TODO*/
} else if (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult) { /* when in Multistream mode, do nothing, will derive s0 from ZRTPSess when we know who is initiator */
......@@ -1980,3 +2018,45 @@ int bzrtp_deriveSrtpKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_
return 0;
}
/*
* @brief Compute the new rs1 and update the cached secrets according to rfc section 4.6.1
*
* param[in] zrtpContext The context we are operation on
* param[in/out] zrtpChannelContext The channel context we are operation on(contains s0)
*
* return 0 on success, error code otherwise
*/
int bzrtp_updateCachedSecrets(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext) {
/* if this channel context is in multistream mode, do nothing */
if (zrtpChannelContext->keyAgreementAlgo == ZRTP_KEYAGREEMENT_Mult) {
/* destroy s0 */
bzrtp_DestroyKey(zrtpChannelContext->s0, zrtpChannelContext->hashLength, zrtpContext->RNGContext);
free(zrtpChannelContext->s0);
zrtpChannelContext->s0 = NULL;
return 0;
}
/* if this channel context is not in DHM mode, backup rs1 in rs2 if it exists */
if (zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Prsh) {
if (zrtpContext->cachedSecret.rs1 != NULL) {
bzrtp_writePeerNode(zrtpContext, zrtpContext->peerZID, (uint8_t *)"rs2", 3, zrtpContext->cachedSecret.rs1, zrtpContext->cachedSecret.rs1Length);
}
}
/* compute rs1 = KDF(s0, "retained secret", KDF_Context, 256) */
if (zrtpContext->cachedSecret.rs1 == NULL) {
zrtpContext->cachedSecret.rs1 = (uint8_t *)malloc(RETAINED_SECRET_LENGTH);
zrtpContext->cachedSecret.rs1Length = RETAINED_SECRET_LENGTH;
}
bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"retained secret", 15, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, 32, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, zrtpContext->cachedSecret.rs1);
bzrtp_writePeerNode(zrtpContext, zrtpContext->peerZID, (uint8_t *)"rs1", 3, zrtpContext->cachedSecret.rs1, zrtpContext->cachedSecret.rs1Length);
/* destroy s0 */
bzrtp_DestroyKey(zrtpChannelContext->s0, zrtpChannelContext->hashLength, zrtpContext->RNGContext);
free(zrtpChannelContext->s0);
zrtpChannelContext->s0 = NULL;
return 0;
}
......@@ -25,36 +25,30 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include "typedef.h"
#include "string.h"
#include "zidCache.h"
/* local functions prototypes */
int bzrtp_findNextTag(uint8_t *cacheBuffer, uint32_t cacheBufferLength, uint32_t *position, uint8_t *tagName);
int bzrtp_readTag(uint8_t *cacheBuffer, uint32_t cacheBufferLength, uint32_t *position, uint8_t *tagName, uint8_t tagNameLength, int *dataLength, uint8_t *data);
int bzrtp_createTagFromBytes(uint8_t *tagName, uint8_t tagNameLength, uint8_t *data, uint8_t dataLength, uint8_t *tag);
int bzrtp_findClosingTag(uint8_t *cacheBuffer, uint32_t cacheBufferLength, uint32_t *position, uint8_t *tagName, uint8_t tagNameLength, uint8_t *data);
#define MIN_VALID_CACHE_LENGTH 56 /* root tag + selfZID tag size */
#define XML_HEADER_STRING "<?xml version='1.0' encoding='utf-8'?>"
#define XML_HEADER_SIZE 38
/* Local functions prototypes */
void bzrtp_strToUint8(uint8_t *outputBytes, uint8_t *inputString, uint16_t inputLength);
void bzrtp_int8ToStr(uint8_t *outputString, uint8_t *inputBytes, uint16_t inputBytesLength);
uint8_t bzrtp_byteToChar(uint8_t inputByte);
uint8_t bzrtp_charToByte(uint8_t inputChar);
void bzrtp_writeCache(bzrtpContext_t *zrtpContext, xmlDocPtr doc);
/*
* @brief : retrieve ZID from cache
* ZID is randomly generated if cache is empty or inexistant
* ZID is randamly generated in case of cacheless implementation
*
* @param[in] context The current zrpt context, used to access the random function if needed
* and the ZID cache access function
* @param[out] selfZID The ZID, retrieved from cache or randomly generated
*
* @return 0 on success
*/
int bzrtp_getSelfZID(bzrtpContext_t *context, uint8_t selfZID[12]) {
if (context == NULL) {
return ZRTP_ZIDCACHE_INVALID_CONTEXT;
}
/* load the cache buffer. TODO: lock it as we may write it */
if (context->zrtpCallbacks.bzrtp_loadCache != NULL) {
context->zrtpCallbacks.bzrtp_loadCache(context->channelContext[0]->clientData, &context->cacheBuffer, &(context->cacheBufferLength));
}
/* we are running cacheless, return a random number */
if (context->cacheBuffer == NULL) {
......@@ -62,144 +56,256 @@ int bzrtp_getSelfZID(bzrtpContext_t *context, uint8_t selfZID[12]) {
return 0;
}
uint8_t selfZidHex[24]; /* ZID is 96 bytes long -> 24 hexa characters */
int dataLength = 24;
uint32_t position=0;
if (bzrtp_readTag(context->cacheBuffer, context->cacheBufferLength, &position, (uint8_t *)"selfZID", 7, &dataLength, selfZidHex) == 0) { /* we found a selfZID in the cache */
/* convert it from hexa string to bytes string */
bzrtp_strToUint8(selfZID, selfZidHex, 24);
} else { /* no ZID found in the cache, generate it and write it to cache - it will erase anything in the cache which anyway shall be empty */
bzrtpCrypto_getRandom(context->RNGContext, selfZID, 12); /* generate the ZID */
uint8_t selfZIDTag[43]; /* tag length is 43 = 9(<selfZID)+24(data length)+ 10(</selfZID>)*/
int retval = bzrtp_createTagFromBytes((uint8_t *)"selfZID", 7, selfZID, 12, selfZIDTag);
if (retval!=0) {
return ZRTP_ZIDCACHE_UNABLETOUPDATE;
uint8_t *selfZidHex = NULL;
/* parse the cache to find the ZID element */
xmlDocPtr doc = NULL;
if (context->cacheBufferLength>MIN_VALID_CACHE_LENGTH) { /* don't even try to parse it if it is too small, we will create it */
doc = xmlParseDoc(context->cacheBuffer);
}
if (doc != NULL ) { /* there is a cache, try to find our ZID */
xmlNodePtr cur = xmlDocGetRootElement(doc);
/* if we found a root element, parse its children node */
if (cur!=NULL)
{
cur = cur->xmlChildrenNode;
}
while (cur!=NULL) {
if ((!xmlStrcmp(cur->name, (const xmlChar *)"selfZID"))){ /* self ZID found, extract it */
selfZidHex = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
/* convert it from hexa string to bytes string */
bzrtp_strToUint8(selfZID, selfZidHex, strlen((char *)selfZidHex));
break;
}
cur = cur->next;
}
free(context->cacheBuffer);
context->cacheBufferLength = 43;
context->cacheBuffer = selfZIDTag;
context->zrtpCallbacks.bzrtp_writeCache(context->cacheBuffer, context->cacheBufferLength);
}
/* if we didn't found anything in cache, or we have no cache at all: generate ZID, cache string and write it to file */
if (selfZidHex==NULL) {
/* generate a random ZID */
bzrtpCrypto_getRandom(context->RNGContext, selfZID, 12);
/* convert it to an Hexa String */
uint8_t newZidHex[25];
bzrtp_int8ToStr(newZidHex, selfZID, 12);
newZidHex[24] = '\0'; /* the string must be null terminated for libxml2 to add it correctly in the element */
xmlFree(doc);
/* Create a new xml doc */
doc = xmlNewDoc((const xmlChar *)"1.0");
/* root tag is "cache" */
xmlNodePtr rootNode = xmlNewDocNode(doc, NULL, (const xmlChar *)"cache", NULL);
xmlDocSetRootElement(doc, rootNode);
/* add the ZID child */
xmlNewTextChild(rootNode, NULL, (const xmlChar *)"selfZID", newZidHex);
/* write the cache file and unlock it(TODO)*/
bzrtp_writeCache(context, doc);
}
/* TODO unlock the cache */
xmlFree(selfZidHex);
xmlFree(doc);
return 0;
}
/* the maximum length of a taf in the ZID cache file */
#define MAX_TAG_LENGTH 64
#define MAX_DATA_LENGTH 2*MAX_AUX_SECRET_LENGTH
/**
* @brief Read a tag content from the ZID cache file
* @brief Parse the cache to find secrets associated to the given ZID, set them and their length in the context if they are found
*
* @param[in] cacheBuffer The current cache buffer
* @param[in] cacheBufferLenght The current cache buffer length
* @param[in/out] position current position in the cache buffer
* @param[in] tagName The tag name
* @param[in] tagNameLength Length of the tag name
* @param[in/out] dataLength Expected length of data, set to 0 if unknown and then modified to found value
* @param[out] data The data read as a string
* @param[in/out] context the current context, used to get the negotiated Hash algorithm and cache access functions and store result
* @param[in] peerZID a byte array of the peer ZID
*
* @return 0 on succes, -1 if the tag is not found
* return 0 on succes, error code otherwise
*/
int bzrtp_readTag(uint8_t *cacheBuffer, uint32_t cacheBufferLength, uint32_t *position, uint8_t *tagName, uint8_t tagNameLength, int *dataLength, uint8_t *data) {
uint8_t bufferTag[MAX_TAG_LENGTH+3]; /* max tag length + </> */
int nextTagLength = 0;
/* find the tag opening */
while ((nextTagLength = bzrtp_findNextTag(cacheBuffer, cacheBufferLength, position, bufferTag))!=-1) {
if (memcmp(bufferTag, tagName, tagNameLength) == 0) { /* we found our tag copy it */
if (*dataLength!=0) { /* we have an expected length, so just read that amount */
if (*position+*dataLength+tagNameLength+3<=cacheBufferLength) {
if ((memcmp(cacheBuffer+*position+*dataLength, "</", 2) == 0) && (memcmp(cacheBuffer+*position+*dataLength+2, tagName, tagNameLength)==0) && (cacheBuffer[*position+*dataLength+tagNameLength+2] == *">")) {
memcpy(data, cacheBuffer+*position, *dataLength);
*position += *dataLength+tagNameLength+3;
return 0;
} else {
return -1; /* we found the correct tag but the closing wasn't set at the right place*/
int bzrtp_getPeerAssociatedSecretsHash(bzrtpContext_t *context, uint8_t peerZID[12]) {
if (context == NULL) {
return ZRTP_ZIDCACHE_INVALID_CONTEXT;
}
/* resert cached secret buffer */
free(context->cachedSecret.rs1);
free(context->cachedSecret.rs2);
free(context->cachedSecret.pbxsecret);
free(context->cachedSecret.auxsecret);
context->cachedSecret.rs1 = NULL;
context->cachedSecret.rs1Length = 0;
context->cachedSecret.rs2 = NULL;
context->cachedSecret.rs2Length = 0;