Manage LIME key expiration date

This commit is contained in:
Johan Pascal 2017-02-05 15:33:12 +07:00
parent cc4966a130
commit d0222b5a87
4 changed files with 142 additions and 159 deletions

View file

@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef HAVE_LIME
#include "private.h"
#include "bctoolbox/crypto.h"
#include "bctoolbox/port.h"
#define FILE_TRANSFER_KEY_SIZE 32
@ -35,84 +36,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
bool_t lime_is_available(void) { return TRUE; }
/**
* @brief convert an hexa char [0-9a-fA-F] into the corresponding unsigned integer value
* Any invalid char will be converted to zero without any warning
*
* @param[in] inputChar a char which shall be in range [0-9a-fA-F]
*
* @return the unsigned integer value in range [0-15]
*/
uint8_t lime_charToByte(uint8_t inputChar) {
/* 0-9 */
if (inputChar>0x29 && inputChar<0x3A) {
return inputChar - 0x30;
}
/* a-f */
if (inputChar>0x60 && inputChar<0x67) {
return inputChar - 0x57; /* 0x57 = 0x61(a) + 0x0A*/
}
/* A-F */
if (inputChar>0x40 && inputChar<0x47) {
return inputChar - 0x37; /* 0x37 = 0x41(a) + 0x0A*/
}
/* shall never arrive here, string is not Hex*/
return 0;
}
/**
* @brief convert a byte which value is in range [0-15] into an hexa char [0-9a-fA-F]
*
* @param[in] inputByte an integer which shall be in range [0-15]
*
* @return the hexa char [0-9a-f] corresponding to the input
*/
uint8_t lime_byteToChar(uint8_t inputByte) {
inputByte &=0x0F; /* restrict the input value to range [0-15] */
/* 0-9 */
if(inputByte<0x0A) {
return inputByte+0x30;
}
/* a-f */
return inputByte + 0x57;
}
/**
* @brief Convert an hexadecimal string into the corresponding byte buffer
*
* @param[out] outputBytes The output bytes buffer, must have a length of half the input string buffer
* @param[in] inputString The input string buffer, must be hexadecimal(it is not checked by function, any non hexa char is converted to 0)
* @param[in] inputStringLength The lenght in chars of the string buffer, output is half this length
*/
void lime_strToUint8(uint8_t *outputBytes, const uint8_t *inputString, uint16_t inputStringLength) {
int i;
for (i=0; i<inputStringLength/2; i++) {
outputBytes[i] = (lime_charToByte(inputString[2*i]))<<4 | lime_charToByte(inputString[2*i+1]);
}
}
/**
* @brief Convert a byte buffer into the corresponding hexadecimal string
*
* @param[out] outputString The output string buffer, must have a length of twice the input bytes buffer
* @param[in] inputBytes The input bytes buffer
* @param[in] inputBytesLength The lenght in bytes buffer, output is twice this length
*/
void lime_int8ToStr(uint8_t *outputString, uint8_t *inputBytes, uint16_t inputBytesLength) {
int i;
for (i=0; i<inputBytesLength; i++) {
outputString[2*i] = lime_byteToChar((inputBytes[i]>>4)&0x0F);
outputString[2*i+1] = lime_byteToChar(inputBytes[i]&0x0F);
}
}
/**
* @brief Retrieve selfZID from cache
*
@ -158,6 +81,7 @@ static int lime_getSelfZid(xmlDocPtr cacheBuffer, uint8_t selfZid[25]) {
int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedKeys) {
xmlNodePtr cur;
size_t keysFound = 0; /* used to detect the no key found error because of validity expired */
/* parse the file to get all peer matching the sipURI given in associatedKeys*/
if (cacheBuffer == NULL ) { /* there is no cache return error */
@ -192,58 +116,80 @@ int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedK
peerNodeChildren = peerNodeChildren->next;
}
if (matchingURIFlag == 1) { /* we found a match for the URI in this peer node, extract the keys, session Id and index values */
if (matchingURIFlag == 1) { /* we found a match for the URI in this peer node, extract the keys, session Id, index values and key validity period */
/* allocate a new limeKey_t structure to hold the retreived keys */
limeKey_t *currentPeerKeys = (limeKey_t *)malloc(sizeof(limeKey_t));
uint8_t itemFound = 0; /* count the item found, we must get all of the requested infos: 5 nodes*/
uint8_t pvs = 0;
uint8_t keyValidityFound = 0; /* flag raised when we found a key validity in the cache */
bctoolboxTimeSpec currentTimeSpec;
bctoolboxTimeSpec validityTimeSpec; /* optionnal(backward compatibility) tag for key validity */
validityTimeSpec.tv_sec=0;
validityTimeSpec.tv_nsec=0;
peerNodeChildren = cur->xmlChildrenNode; /* reset peerNodeChildren to the first child of node */
while (peerNodeChildren!=NULL && itemFound<5) {
while (peerNodeChildren!=NULL && itemFound<6) {
xmlChar *nodeContent = NULL;
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"ZID")) {
nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1);
lime_strToUint8(currentPeerKeys->peerZID, nodeContent, 24);
bctbx_strToUint8(currentPeerKeys->peerZID, nodeContent, 24);
itemFound++;
}
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndKey")) {
nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1);
lime_strToUint8(currentPeerKeys->key, nodeContent, 64);
bctbx_strToUint8(currentPeerKeys->key, nodeContent, 64);
itemFound++;
}
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndSId")) {
nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1);
lime_strToUint8(currentPeerKeys->sessionId, nodeContent, 64);
bctbx_strToUint8(currentPeerKeys->sessionId, nodeContent, 64);
itemFound++;
}
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndIndex")) {
uint8_t sessionIndexBuffer[4]; /* session index is a uint32_t but we first retrieved it as an hexa string, convert it to a 4 uint8_t buffer */
nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1);
lime_strToUint8(sessionIndexBuffer, nodeContent, 8);
bctbx_strToUint8(sessionIndexBuffer, nodeContent, 8);
/* convert it back to a uint32_t (MSByte first)*/
currentPeerKeys->sessionIndex = sessionIndexBuffer[3] + (sessionIndexBuffer[2]<<8) + (sessionIndexBuffer[1]<<16) + (sessionIndexBuffer[0]<<24);
itemFound++;
}
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"pvs")) {
nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1);
lime_strToUint8(&pvs, nodeContent, 2); /* pvs is retrieved as a 2 characters hexa string, convert it to an int8 */
bctbx_strToUint8(&pvs, nodeContent, 2); /* pvs is retrieved as a 2 characters hexa string, convert it to an int8 */
itemFound++;
}
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"valid")) {
nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1);
validityTimeSpec.tv_sec = bctbx_strToUint64(nodeContent); /* validity is retrieved as a 16 characters hexa string, convert it to an uint64 */
itemFound++;
keyValidityFound = 1;
}
xmlFree(nodeContent);
peerNodeChildren = peerNodeChildren->next;
}
/* check if we have all the requested information and the PVS flag is set to 1 */
if (itemFound == 5 && pvs == 1) {
associatedKeys->associatedZIDNumber +=1;
/* extend array of pointer to limeKey_t structures to add the one we found */
associatedKeys->peerKeys = (limeKey_t **)realloc(associatedKeys->peerKeys, (associatedKeys->associatedZIDNumber)*sizeof(limeKey_t *));
/* key validity may not be present in cache(transition from older versions), so check this, if not found-> set it to 0 wich means valid for ever */
if (keyValidityFound == 0) {
itemFound++;
validityTimeSpec.tv_sec = 0;
}
/* add the new entry at the end */
associatedKeys->peerKeys[associatedKeys->associatedZIDNumber-1] = currentPeerKeys;
/* check if we have all the requested information and the PVS flag is set to 1 and key is still valid*/
_bctbx_get_cur_time(&currentTimeSpec, TRUE);
if (itemFound == 6 && pvs == 1) {
keysFound++;
if (validityTimeSpec.tv_sec == 0 || bctbx_timespec_compare(&currentTimeSpec, &validityTimeSpec)<0) {
associatedKeys->associatedZIDNumber +=1;
/* extend array of pointer to limeKey_t structures to add the one we found */
associatedKeys->peerKeys = (limeKey_t **)realloc(associatedKeys->peerKeys, (associatedKeys->associatedZIDNumber)*sizeof(limeKey_t *));
/* add the new entry at the end */
associatedKeys->peerKeys[associatedKeys->associatedZIDNumber-1] = currentPeerKeys;
} else {
free(currentPeerKeys);
}
} else {
free(currentPeerKeys);
}
@ -251,6 +197,13 @@ int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedK
}
cur = cur->next;
}
if (associatedKeys->associatedZIDNumber == 0) {
if (keysFound == 0) {
return LIME_NO_VALID_KEY_FOUND_FOR_PEER;
} else {
return LIME_PEER_KEY_HAS_EXPIRED;
}
}
return 0;
}
@ -266,7 +219,7 @@ int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) {
}
/* get the given ZID into hex format */
lime_int8ToStr(peerZidHex, associatedKey->peerZID, 12);
bctbx_int8ToStr(peerZidHex, associatedKey->peerZID, 12);
peerZidHex[24]='\0'; /* must be a null terminated string */
cur = xmlDocGetRootElement(cacheBuffer);
@ -286,25 +239,25 @@ int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) {
xmlChar *nodeContent = NULL;
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvKey")) {
nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1);
lime_strToUint8(associatedKey->key, nodeContent, 64);
bctbx_strToUint8(associatedKey->key, nodeContent, 64);
itemFound++;
}
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvSId")) {
nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1);
lime_strToUint8(associatedKey->sessionId, nodeContent, 64);
bctbx_strToUint8(associatedKey->sessionId, nodeContent, 64);
itemFound++;
}
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvIndex")) {
uint8_t sessionIndexBuffer[4]; /* session index is a uint32_t but we first retrieved it as an hexa string, convert it to a 4 uint8_t buffer */
nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1);
lime_strToUint8(sessionIndexBuffer, nodeContent, 8);
bctbx_strToUint8(sessionIndexBuffer, nodeContent, 8);
/* convert it back to a uint32_t (MSByte first)*/
associatedKey->sessionIndex = sessionIndexBuffer[3] + (sessionIndexBuffer[2]<<8) + (sessionIndexBuffer[1]<<16) + (sessionIndexBuffer[0]<<24);
itemFound++;
}
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"pvs")) {
nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1);
lime_strToUint8(&pvs, nodeContent, 2); /* pvs is retrieved as a 2 characters hexa string, convert it to an int8 */
bctbx_strToUint8(&pvs, nodeContent, 2); /* pvs is retrieved as a 2 characters hexa string, convert it to an int8 */
itemFound++;
}
xmlFree(nodeContent);
@ -327,12 +280,16 @@ int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) {
return LIME_NO_VALID_KEY_FOUND_FOR_PEER;
}
int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t role) {
int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t role, uint64_t validityTimeSpan) {
uint8_t done=0;
xmlNodePtr cur;
uint8_t peerZidHex[25];
uint8_t keyHex[65]; /* key is 32 bytes long -> 64 bytes string + null termination */
uint8_t sessionIdHex[65]; /* sessionId is 32 bytes long -> 64 bytes string + null termination */
uint8_t sessionIndexHex[9]; /* sessionInedx is an uint32_t : 4 bytes long -> 8 bytes string + null termination */
uint8_t validHex[17]; /* validity is a unix period in seconds on 64bits -> 16 bytes string + null termination */
bctoolboxTimeSpec currentTimeSpec;
uint8_t itemFound = 0;
if (cacheBuffer == NULL ) { /* there is no cache return error */
@ -340,7 +297,7 @@ int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t r
}
/* get the given ZID into hex format */
lime_int8ToStr(peerZidHex, associatedKey->peerZID, 12);
bctbx_int8ToStr(peerZidHex, associatedKey->peerZID, 12);
peerZidHex[24]='\0'; /* must be a null terminated string */
cur = xmlDocGetRootElement(cacheBuffer);
@ -352,26 +309,27 @@ int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t r
}
/* convert the given tag content to null terminated Hexadecimal strings */
lime_int8ToStr(keyHex, associatedKey->key, 32);
bctbx_int8ToStr(keyHex, associatedKey->key, 32);
keyHex[64] = '\0';
lime_int8ToStr(sessionIdHex, associatedKey->sessionId, 32);
bctbx_int8ToStr(sessionIdHex, associatedKey->sessionId, 32);
sessionIdHex[64] = '\0';
sessionIndexHex[0] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>28)&0x0F));
sessionIndexHex[1] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>24)&0x0F));
sessionIndexHex[2] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>20)&0x0F));
sessionIndexHex[3] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>16)&0x0F));
sessionIndexHex[4] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>12)&0x0F));
sessionIndexHex[5] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>8)&0x0F));
sessionIndexHex[6] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>4)&0x0F));
sessionIndexHex[7] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex)&0x0F));
sessionIndexHex[8] = '\0';
bctbx_uint32ToStr(sessionIndexHex, associatedKey->sessionIndex);
if (validityTimeSpan > 0 && role == LIME_RECEIVER) {
_bctbx_get_cur_time(&currentTimeSpec, TRUE);
bctbx_timespec_add(&currentTimeSpec, validityTimeSpan);
bctbx_uint64ToStr(validHex, currentTimeSpec.tv_sec);
}
while (cur!=NULL && itemFound<3) { /* loop on all peer nodes */
while (cur!=NULL && done==0) { /* loop on all peer nodes */
if ((!xmlStrcmp(cur->name, (const xmlChar *)"peer"))){ /* found a peer, check his ZID element */
xmlChar *currentZidHex = xmlNodeListGetString(cacheBuffer, cur->xmlChildrenNode->xmlChildrenNode, 1); /* ZID is the first element of peer */
if (!xmlStrcmp(currentZidHex, (const xmlChar *)peerZidHex)) { /* we found the peer element we are looking for */
uint8_t validFound = 0;
xmlNodePtr peerNodeChildren = cur->xmlChildrenNode->next;
while (peerNodeChildren != NULL && itemFound<3) { /* look for the tag we want to write */
if (role==LIME_SENDER) {
itemFound=1; /* we do not look for valid when setting sender key */
}
while (peerNodeChildren != NULL && itemFound<4) { /* look for the tag we want to write */
if (role == LIME_RECEIVER) { /* writing receiver key */
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvKey")) {
xmlNodeSetContent(peerNodeChildren, (const xmlChar *)keyHex);
@ -385,6 +343,13 @@ int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t r
xmlNodeSetContent(peerNodeChildren, (const xmlChar *)sessionIndexHex);
itemFound++;
}
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"valid")) {
if (validityTimeSpan > 0) {
xmlNodeSetContent(peerNodeChildren, (const xmlChar *)validHex);
}
itemFound++;
validFound=1;
}
} else { /* writing sender key */
if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndKey")) {
xmlNodeSetContent(peerNodeChildren, (const xmlChar *)keyHex);
@ -401,13 +366,17 @@ int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t r
}
peerNodeChildren = peerNodeChildren->next;
}
/* we may want to add the valid node which if it is missing and we've been ask to update it */
if (role == LIME_RECEIVER && validityTimeSpan>0 && validFound==0) {
xmlNewTextChild(cur, NULL, (const xmlChar *)"valid", validHex);
}
done=1; /* step out of the <peer> loop */
}
xmlFree(currentZidHex);
}
cur = cur->next;
}
return 0;
}
@ -581,7 +550,7 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, const char *contentType,
limeURIKeys_t associatedKeys;
xmlDocPtr xmlOutputMessage;
xmlNodePtr rootNode;
int i;
int i,ret;
int xmlStringLength;
xmlChar *local_output = NULL;
@ -589,7 +558,7 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, const char *contentType,
if (lime_getSelfZid(cacheBuffer, selfZidHex) != 0) {
return LIME_UNABLE_TO_ENCRYPT_MESSAGE;
}
lime_strToUint8(selfZid, selfZidHex, 24);
bctbx_strToUint8(selfZid, selfZidHex, 24);
/* encrypted message length is plaintext + 16 for tag */
encryptedMessageLength = (uint32_t)strlen((char *)message) + 16;
@ -601,14 +570,9 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, const char *contentType,
associatedKeys.associatedZIDNumber = 0;
associatedKeys.peerKeys = NULL;
if (lime_getCachedSndKeysByURI(cacheBuffer, &associatedKeys) != 0) {
if ((ret = lime_getCachedSndKeysByURI(cacheBuffer, &associatedKeys)) != 0) {
lime_freeKeys(&associatedKeys);
return LIME_UNABLE_TO_ENCRYPT_MESSAGE;
}
if (associatedKeys.associatedZIDNumber == 0) {
lime_freeKeys(&associatedKeys);
return LIME_NO_VALID_KEY_FOUND_FOR_PEER;
return ret;
}
/* create an xml doc to hold the multipart message */
@ -643,17 +607,9 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, const char *contentType,
* <content-type>ciphertext</content-type>
* </msg> */
msgNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"msg", NULL);
lime_int8ToStr(peerZidHex, currentKey->peerZID, 12);
bctbx_int8ToStr(peerZidHex, currentKey->peerZID, 12);
peerZidHex[24] = '\0';
sessionIndexHex[0] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>28)&0x0F));
sessionIndexHex[1] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>24)&0x0F));
sessionIndexHex[2] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>20)&0x0F));
sessionIndexHex[3] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>16)&0x0F));
sessionIndexHex[4] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>12)&0x0F));
sessionIndexHex[5] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>8)&0x0F));
sessionIndexHex[6] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>4)&0x0F));
sessionIndexHex[7] = lime_byteToChar((uint8_t)((currentKey->sessionIndex)&0x0F));
sessionIndexHex[8] = '\0';
bctbx_uint32ToStr(sessionIndexHex, currentKey->sessionIndex);
xmlNewTextChild(msgNode, NULL, (const xmlChar *)"pzid", peerZidHex);
xmlNewTextChild(msgNode, NULL, (const xmlChar *)"index", sessionIndexHex);
@ -682,7 +638,7 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, const char *contentType,
/* update the key used */
lime_deriveKey(currentKey);
lime_setCachedKey(cacheBuffer, currentKey, LIME_SENDER);
lime_setCachedKey(cacheBuffer, currentKey, LIME_SENDER, 0); /* never update validity when sending a message */
}
/* dump the whole message doc into the output */
@ -699,7 +655,7 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, const char *contentType,
return 0;
}
int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output, char **content_type) {
int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output, char **content_type, uint64_t validityTimeSpan) {
int retval = 0;
uint8_t selfZidHex[25];
uint8_t selfZid[12]; /* same data but in byte buffer */
@ -722,7 +678,7 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_
if (lime_getSelfZid(cacheBuffer, selfZidHex) != 0) {
return LIME_UNABLE_TO_DECRYPT_MESSAGE;
}
lime_strToUint8(selfZid, selfZidHex, 24);
bctbx_strToUint8(selfZid, selfZidHex, 24);
xml_ctx = linphone_xmlparsing_context_new();
xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
@ -741,7 +697,7 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_
peerZidHex = linphone_get_xml_text_content(xml_ctx, "/doc/ZID");
if (peerZidHex != NULL) {
/* Convert it from hexa string to bytes string and set the result in the associatedKey structure */
lime_strToUint8(associatedKey.peerZID, (const uint8_t *)peerZidHex, (uint16_t)strlen(peerZidHex));
bctbx_strToUint8(associatedKey.peerZID, (const uint8_t *)peerZidHex, (uint16_t)strlen(peerZidHex));
linphone_free_xml_text_content(peerZidHex);
/* Get the matching key from cache */
@ -765,14 +721,7 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_
snprintf(xpath_str, sizeof(xpath_str), "/doc/msg[%i]/index", i);
sessionIndexHex = linphone_get_xml_text_content(xml_ctx, xpath_str);
if (sessionIndexHex != NULL) {
usedSessionIndex = (((uint32_t)lime_charToByte(sessionIndexHex[0]))<<28)
| (((uint32_t)lime_charToByte(sessionIndexHex[1]))<<24)
| (((uint32_t)lime_charToByte(sessionIndexHex[2]))<<20)
| (((uint32_t)lime_charToByte(sessionIndexHex[3]))<<16)
| (((uint32_t)lime_charToByte(sessionIndexHex[4]))<<12)
| (((uint32_t)lime_charToByte(sessionIndexHex[5]))<<8)
| (((uint32_t)lime_charToByte(sessionIndexHex[6]))<<4)
| (((uint32_t)lime_charToByte(sessionIndexHex[7])));
usedSessionIndex = bctbx_strToUint32((const unsigned char *)sessionIndexHex);
linphone_free_xml_text_content(sessionIndexHex);
}
snprintf(xpath_str, sizeof(xpath_str), "/doc/msg[%i]/text", i);
@ -844,7 +793,7 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_
/* update used key */
lime_deriveKey(&associatedKey);
lime_setCachedKey(cacheBuffer, &associatedKey, LIME_RECEIVER);
lime_setCachedKey(cacheBuffer, &associatedKey, LIME_RECEIVER, validityTimeSpan);
error:
linphone_xmlparsing_context_destroy(xml_ctx);
@ -884,7 +833,7 @@ bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) {
associatedKeys.associatedZIDNumber = 0;
associatedKeys.peerKeys = NULL;
res = (lime_getCachedSndKeysByURI(cacheXml, &associatedKeys) == 0 && associatedKeys.associatedZIDNumber != 0);
res = (lime_getCachedSndKeysByURI(cacheXml, &associatedKeys) == 0);
lime_freeKeys(&associatedKeys);
xmlFreeDoc(cacheXml);
ms_free(peer);
@ -931,7 +880,7 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
fclose(CACHEFD);
cacheXml = xmlParseDoc((xmlChar*)cacheString);
ms_free(cacheString);
retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)msg->message, &decrypted_body, &decrypted_content_type);
retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)msg->message, &decrypted_body, &decrypted_content_type, lp_config_get_int(lc->config, "sip", "lime_key_validity", 0));
if (retval != 0) {
ms_warning("Unable to decrypt message, reason : %s", lime_error_code_to_string(retval));
if (decrypted_body) ms_free(decrypted_body);
@ -1151,6 +1100,7 @@ char *lime_error_code_to_string(int errorCode) {
case LIME_UNABLE_TO_ENCRYPT_MESSAGE: return "Unable to encrypt message";
case LIME_UNABLE_TO_DECRYPT_MESSAGE: return "Unable to decrypt message";
case LIME_NO_VALID_KEY_FOUND_FOR_PEER: return "No valid key found";
case LIME_PEER_KEY_HAS_EXPIRED: return "Any key matching peer Uri has expired";
case LIME_INVALID_ENCRYPTED_MESSAGE: return "Invalid encrypted message";
case LIME_NOT_ENABLED: return "Lime not enabled at build";
}

View file

@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define LIME_UNABLE_TO_DECRYPT_MESSAGE 0x1008
#define LIME_NO_VALID_KEY_FOUND_FOR_PEER 0x1010
#define LIME_INVALID_ENCRYPTED_MESSAGE 0x1020
#define LIME_PEER_KEY_HAS_EXPIRED 0x1040
#define LIME_NOT_ENABLED 0x1100
/* this define the maximum key derivation number allowed to get the caches back in sync in case of missed messages */
@ -66,7 +67,7 @@ typedef struct limeURIKeys_struct {
* @param[in] cacheBuffer The xmlDoc containing current cache
* @param[in,out] associatedKeys Structure containing the peerURI. After this call contains all key material associated to the given URI. Must be then freed through lime_freeKeys function
*
* @return 0 on success, error code otherwise
* @return 0 on success(at least one valid key found), error code otherwise
*/
LINPHONE_PUBLIC int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedKeys);
@ -84,13 +85,14 @@ LINPHONE_PUBLIC int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *
* @brief Set in cache the given key material, association is made by ZID contained in the associatedKey parameter
*
* @param[out] cacheBuffer The xmlDoc containing current cache to be updated
* @param[in,out] associatedKey Structure containing the key and ZID to identify the peer node to be updated
* @param[in,out] associatedKey Structure containing the key and ZID to identify the peer node to be updated
* @param[in] role Can be LIME_SENDER or LIME_RECEIVER, specify which key we want to update
* @param[in] validityTimeSpan If not 0, set the <valid> tag to now+validityTimeSpan (in seconds)
*
* @return 0 on success, error code otherwise
*/
LINPHONE_PUBLIC int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t role);
LINPHONE_PUBLIC int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, const uint8_t role, const uint64_t validityTimeSpan);
/**
* @brief Free all allocated data in the associated keys structure
@ -183,10 +185,10 @@ LINPHONE_PUBLIC int lime_createMultipartMessage(xmlDocPtr cacheBuffer, const cha
* @param[in] message The multipart message, contain one or several part identified by destination ZID, one shall match the self ZID retrieved from cache
* @param[out] output The output buffer, allocated and set with the decrypted message(null terminated string). Must be freed by caller
* @param[out] content_type The content type of the decrypted message
* @param[in] validityTimeSpan If not 0, update the <valid> tag associated to sender to now+validityTimeSpan (in seconds)
* @return 0 on success, error code otherwise
*/
LINPHONE_PUBLIC int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output, char **content_type);
LINPHONE_PUBLIC int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output, char **content_type, const uint64_t validityTimeSpan);
/**
* @brief given a readable version of error code generated by Lime functions

View file

@ -2531,6 +2531,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
/*call->current_params.media_encryption will be set later when zrtp is activated*/
params.zid_file=lc->zrtp_secrets_cache;
params.uri=uri;
params.limeKeyTimeSpan = lp_config_get_int(lc->config, "sip", "lime_key_validity", 0); /* get key lifespan from config file, default is 0:forever valid */
setZrtpCryptoTypesParameters(&params,call->core);
audio_stream_enable_zrtp(call->audiostream,&params);
if (uri != NULL) ms_free(uri);

View file

@ -1213,7 +1213,6 @@ static void lime_text_message(void) {
}
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity));
/* TODO : check the msg arrived correctly deciphered */
end:
remove("tmpZIDCacheMarie.xml");
remove("tmpZIDCachePauline.xml");
@ -1442,9 +1441,24 @@ static void printHex(char *title, uint8_t *data, size_t length) {
ms_message("%s", debug_string_buffer);
}
static void stripnCR(char *dst, const char *src, const size_t srcLength) {
size_t i=0;
for (i=0; *src != '\0' && i<srcLength; src++,i++) {
*dst = *src;
if (*dst != '\r' && *dst != '\n') {
dst++;
}
}
*dst = '\0';
}
static void lime_unit(void) {
if (lime_is_available()) {
const char* PLAIN_TEXT_TEST_MESSAGE = "Ceci est un fabuleux msg de test à encrypter";
const char* pattern_ZIDCache_noValidity = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<cache><selfZID>ef7692d0792a67491ae2d44e</selfZID><peer><ZID>005dbe0399643d953a2202dd</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>pipo1@pipo.com</uri><sndKey>963c57bb28e62068d2df23e8f9b771932d3c57bb28e62068d2df23e8f9b77193</sndKey><rcvKey>06d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>03ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000069</sndIndex><rcvIndex>000001e9</rcvIndex><pvs>01</pvs></peer><peer><ZID>1234567889643d953a2202ee</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>pipo1@pipo.com</uri><sndKey>123456789012345678901234567890123456765431262068d2df23e8f9b77193</sndKey><rcvKey>25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>22ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000001</sndIndex><rcvIndex>00000000</rcvIndex><pvs>01</pvs></peer></cache>\r\n";
char cachedStringBufferExpected[2048];
char cachedStringBufferActual[2048];
char cachedStringBuffer[2048];
int retval;
size_t size;
uint8_t *cacheBufferString;
@ -1471,7 +1485,7 @@ static void lime_unit(void) {
/* create and load cache file */
CACHE = fopen_from_write_dir("ZIDCache.xml", "wb");
fprintf (CACHE, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<cache><selfZID>ef7692d0792a67491ae2d44e</selfZID><peer><ZID>005dbe0399643d953a2202dd</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>pipo1@pipo.com</uri><sndKey>963c57bb28e62068d2df23e8f9b771932d3c57bb28e62068d2df23e8f9b77193</sndKey><rcvKey>05d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>02ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000069</sndIndex><rcvIndex>000001e8</rcvIndex><pvs>01</pvs></peer><peer><ZID>1234567889643d953a2202ee</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>pipo1@pipo.com</uri><sndKey>123456789012345678901234567890123456765431262068d2df23e8f9b77193</sndKey><rcvKey>25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>22ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000001</sndIndex><rcvIndex>00000000</rcvIndex><pvs>01</pvs></peer></cache>");
fprintf (CACHE, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<cache><selfZID>ef7692d0792a67491ae2d44e</selfZID><peer><ZID>005dbe0399643d953a2202dd</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>pipo1@pipo.com</uri><sndKey>963c57bb28e62068d2df23e8f9b771932d3c57bb28e62068d2df23e8f9b77193</sndKey><rcvKey>05d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>02ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000069</sndIndex><rcvIndex>000001e8</rcvIndex><pvs>01</pvs></peer><peer><ZID>1234567889643d953a2202ee</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>pipo1@pipo.com</uri><sndKey>123456789012345678901234567890123456765431262068d2df23e8f9b77193</sndKey><rcvKey>25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>22ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000001</sndIndex><rcvIndex>00000000</rcvIndex><pvs>01</pvs></peer></cache>");
fclose(CACHE);
CACHE = fopen_from_write_dir("ZIDCache.xml", "rb+");
cacheBufferString = (uint8_t*) ms_load_file_content(CACHE, &size);
@ -1521,22 +1535,28 @@ static void lime_unit(void) {
associatedKey.sessionIndex++;
associatedKey.key[0]++;
associatedKey.sessionId[0]++;
retval = lime_setCachedKey(cacheBuffer, &associatedKey, LIME_RECEIVER);
retval = lime_setCachedKey(cacheBuffer, &associatedKey, LIME_RECEIVER, 0);
BC_ASSERT_EQUAL(retval, 0, int, "%d");
/* update sender data */
associatedKeys.peerKeys[0]->sessionIndex++;
associatedKeys.peerKeys[0]->key[0]++;
associatedKeys.peerKeys[0]->sessionId[0]++;
retval = lime_setCachedKey(cacheBuffer, associatedKeys.peerKeys[0], LIME_SENDER);
retval = lime_setCachedKey(cacheBuffer, associatedKeys.peerKeys[0], LIME_SENDER, 0);
BC_ASSERT_EQUAL(retval, 0, int, "%d");
/* free memory */
lime_freeKeys(&associatedKeys);
/* write the file */
/* dump the xml document into a string */
xmlDocDumpFormatMemoryEnc(cacheBuffer, &xmlStringOutput, &xmlStringLength, "UTF-8", 0);
/* must strip buffers of their \n\r or strcmp won't like it */
stripnCR(cachedStringBufferExpected, pattern_ZIDCache_noValidity, strlen(pattern_ZIDCache_noValidity));
stripnCR(cachedStringBufferActual, (const char *)xmlStringOutput, strlen((const char *)xmlStringOutput));
BC_ASSERT_NSTRING_EQUAL(cachedStringBufferExpected, cachedStringBufferActual, strlen(cachedStringBufferExpected));
/* write it to the file */
CACHE = fopen_from_write_dir("ZIDCache.xml", "w+");
fwrite(xmlStringOutput, 1, xmlStringLength, CACHE);
@ -1544,10 +1564,11 @@ static void lime_unit(void) {
fclose(CACHE);
xmlFreeDoc(cacheBuffer);
/**** Higher level tests using 2 caches to encrypt/decrypt a msg ****/
/* Create Alice cache file and then load it */
CACHE = fopen_from_write_dir("ZIDCacheAlice.xml", "wb");
fprintf(CACHE, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<cache><selfZID>ef7692d0792a67491ae2d44e</selfZID><peer><ZID>005dbe0399643d953a2202dd</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>sip:pauline@sip.example.org</uri><sndKey>9111ebeb52e50edcc6fcb3eea1a2d3ae3c2c75d3668923e83c59d0f472455150</sndKey><rcvKey>60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a</rcvKey><sndSId>5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000080</sndIndex><rcvIndex>000001cf</rcvIndex><pvs>01</pvs></peer><peer><ZID>1234567889643d953a2202ee</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>sip:pauline@sip.example.org</uri><sndKey>72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a9176</sndKey><rcvKey>25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>22ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>0000000f</sndIndex><rcvIndex>00000000</rcvIndex></peer></cache>");
fprintf(CACHE, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<cache><selfZID>ef7692d0792a67491ae2d44e</selfZID><peer><ZID>005dbe0399643d953a2202dd</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>sip:pauline@sip.example.org</uri><sndKey>9111ebeb52e50edcc6fcb3eea1a2d3ae3c2c75d3668923e83c59d0f472455150</sndKey><rcvKey>60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a</rcvKey><sndSId>5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000080</sndIndex><rcvIndex>000001cf</rcvIndex><pvs>01</pvs><valid>00000000386d4380</valid></peer><peer><ZID>1234567889643d953a2202ee</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>sip:pauline@sip.example.org</uri><sndKey>72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a9176</sndKey><rcvKey>25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>22ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>0000000f</sndIndex><rcvIndex>00000000</rcvIndex><valid>00000000386d4380</valid></peer></cache>");
fclose(CACHE);
CACHE = fopen_from_write_dir("ZIDCacheAlice.xml", "rb+");
cacheBufferString = (uint8_t *)ms_load_file_content(CACHE, &size);
@ -1570,17 +1591,26 @@ static void lime_unit(void) {
ms_free(cacheBufferString);
/*Try to encrypt the message, but it shall fail due to expired key */
/* encrypt a msg */
retval = lime_createMultipartMessage(cacheBufferAlice, "text/plain", (uint8_t *)PLAIN_TEXT_TEST_MESSAGE, (uint8_t *)"sip:pauline@sip.example.org", &multipartMessage);
BC_ASSERT_EQUAL(retval, LIME_PEER_KEY_HAS_EXPIRED, int, "%d");
/* reload a cache but with valid key (time bomb: validity is set to the 2038 bug epoch even if we are not prone to it) */
sprintf(cachedStringBuffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<cache><selfZID>ef7692d0792a67491ae2d44e</selfZID><peer><ZID>005dbe0399643d953a2202dd</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>sip:pauline@sip.example.org</uri><sndKey>9111ebeb52e50edcc6fcb3eea1a2d3ae3c2c75d3668923e83c59d0f472455150</sndKey><rcvKey>60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a</rcvKey><sndSId>5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000080</sndIndex><rcvIndex>000001cf</rcvIndex><pvs>01</pvs><valid>000000007fffffff</valid></peer><peer><ZID>1234567889643d953a2202ee</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>sip:pauline@sip.example.org</uri><sndKey>72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a9176</sndKey><rcvKey>25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>22ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>0000000f</sndIndex><rcvIndex>00000000</rcvIndex><valid>000000007fffffff</valid></peer></cache>");
xmlFreeDoc(cacheBufferAlice);
cacheBufferAlice = xmlParseDoc((unsigned char *)cachedStringBuffer);
/* retry to encrypt a msg */
retval = lime_createMultipartMessage(cacheBufferAlice, "text/plain", (uint8_t *)PLAIN_TEXT_TEST_MESSAGE, (uint8_t *)"sip:pauline@sip.example.org", &multipartMessage);
BC_ASSERT_EQUAL(retval, 0, int, "%d");
if (retval == 0) {
ms_message("Encrypted msg created is %s", multipartMessage);
}
/* decrypt the multipart msg */
retval = lime_decryptMultipartMessage(cacheBufferBob, multipartMessage, &decryptedMessage, &decryptedContentType);
retval = lime_decryptMultipartMessage(cacheBufferBob, multipartMessage, &decryptedMessage, &decryptedContentType, 1000);
BC_ASSERT_EQUAL(retval, 0, int, "%d");
if (retval == 0) {