From 5ef6293af5b1006a7c0f6d383ff372f5ef3e3a59 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Thu, 3 Apr 2014 15:03:56 +0200 Subject: [PATCH 01/19] Prepare for IM encryption - update oRTP and ms2 --- coreapi/linphonecall.c | 1 + mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index eee0e6305..0e69bf546 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1994,6 +1994,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut call->current_params.media_encryption=LinphoneMediaEncryptionNone; params.zid_file=lc->zrtp_secrets_cache; + params.uri= "SetThePeerSipUriHere@nullTerminated.String"; /* TODO: set the sip URI there, MUST be a null terminated string */ audio_stream_enable_zrtp(call->audiostream,¶ms); }else{ call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ? diff --git a/mediastreamer2 b/mediastreamer2 index 9956d3d6e..9117185fd 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9956d3d6e37a09991b948b1cad8d1382e046b0d1 +Subproject commit 9117185fd8b0a4679cc198cded64dad7d85628e0 diff --git a/oRTP b/oRTP index 04f2c4bff..5c3952c5b 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 04f2c4bff871c108fd645f6f16a3164f9fa42769 +Subproject commit 5c3952c5b90b82fe2cff122c67959b88c358bce8 From 8a8eb4afe1c0c8e3aa3c80204d58e99cdda6579f Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Fri, 11 Apr 2014 00:02:36 +0200 Subject: [PATCH 02/19] Add Lime (Linphone Instant Message Encryption) - not fully functional yet. --- coreapi/Makefile.am | 1 + coreapi/chat.c | 89 +++++- coreapi/lime.c | 650 +++++++++++++++++++++++++++++++++++++++ coreapi/lime.h | 141 +++++++++ coreapi/linphonecall.c | 3 +- mediastreamer2 | 2 +- oRTP | 2 +- tester/ZIDCache.xml | 2 + tester/ZIDCacheAlice.xml | 2 + tester/ZIDCacheBob.xml | 4 + tester/message_tester.c | 166 +++++++++- 11 files changed, 1056 insertions(+), 6 deletions(-) create mode 100644 coreapi/lime.c create mode 100644 coreapi/lime.h create mode 100644 tester/ZIDCache.xml create mode 100644 tester/ZIDCacheAlice.xml create mode 100644 tester/ZIDCacheBob.xml diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 68d78447f..6f313d861 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -56,6 +56,7 @@ liblinphone_la_SOURCES=\ xml2lpc.c \ lpc2xml.c \ remote_provisioning.c \ + lime.c \ $(GITVERSION_FILE) if BUILD_UPNP diff --git a/coreapi/chat.c b/coreapi/chat.c index ef01b8b11..328700123 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -28,6 +28,8 @@ #include +#include "lime.h" + #define COMPOSING_DEFAULT_IDLE_TIMEOUT 15 #define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60 #define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120 @@ -194,7 +196,48 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM sal_message_send(op,identity,cr->peer,content_type, NULL); ms_free(content_type); } else { - sal_text_send(op, identity, cr->peer,msg->message); + uint8_t *multipartEncryptedMessage = NULL; + /* shall we try to encrypt the message?*/ + if (1) { /* TODO : set a flag for message encryption into LinphoneChatRoom structure */ + /* get the zrtp cache and parse it into an xml doc */ + FILE *CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "r+"); + ms_message("Cache file is %s", cr->lc->zrtp_secrets_cache); + if (CACHEFD == NULL) { + ms_warning("Unable to access ZRTP ZID cache to encrypt message"); + } else { + fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ + int cacheSize = ftell(CACHEFD); /* Get file length */ + rewind(CACHEFD); /* Back to start of file */ + uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ + fread(cacheString, 1, cacheSize, CACHEFD); + cacheString[cacheSize] = '\0'; + cacheSize += 1; + fclose(CACHEFD); + xmlDocPtr cacheXml = xmlParseDoc(cacheString); + int retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg->message, (uint8_t *)linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)), &multipartEncryptedMessage); + if (retval != 0) { + ms_warning("Unable to encrypt message to %s error %x", linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)), retval); + } + /* dump updated cache to a string */ + xmlChar *xmlStringOutput; + int xmlStringLength; + xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the cache file */ + CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "w+"); + fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD); + xmlFree(xmlStringOutput); + fclose(CACHEFD); + + + xmlFreeDoc(cacheXml); + } + } + if (multipartEncryptedMessage!=NULL) { + sal_text_send(op, identity, cr->peer,(const char *)multipartEncryptedMessage); + free(multipartEncryptedMessage); + } else { + sal_text_send(op, identity, cr->peer,msg->message); + } } msg->dir=LinphoneChatMessageOutgoing; msg->from=linphone_address_new(identity); @@ -264,7 +307,49 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag /* create a new chat room */ cr=linphone_core_create_chat_room(lc,cleanfrom); } - msg = linphone_chat_room_create_message(cr, sal_msg->text); + + /* shall we try to decrypt the message */ + uint8_t *decryptedMessage = NULL; + if (1) { /* TODO : set a flag for message encryption into LinphoneChatRoom structure */ + /* get the zrtp cache and parse it into an xml doc */ + FILE *CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "r+"); + ms_message("Cache file is %s", lc->zrtp_secrets_cache); + if (CACHEFD == NULL) { + ms_warning("Unable to access ZRTP ZID cache to decrypt message"); + } else { + fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ + int cacheSize = ftell(CACHEFD); /* Get file length */ + rewind(CACHEFD); /* Back to start of file */ + uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ + fread(cacheString, 1, cacheSize, CACHEFD); + cacheString[cacheSize] = '\0'; + cacheSize += 1; + fclose(CACHEFD); + xmlDocPtr cacheXml = xmlParseDoc(cacheString); + int retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)(sal_msg->text), &decryptedMessage); + if (retval != 0) { + ms_warning("Unable to decrypt message error %x", retval); + } + /* dump updated cache to a string */ + xmlChar *xmlStringOutput; + int xmlStringLength; + xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the cache file */ + CACHEFD = fopen(lc->zrtp_secrets_cache, "w+"); + fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD); + xmlFree(xmlStringOutput); + fclose(CACHEFD); + + xmlFreeDoc(cacheXml); + } + } + + if (decryptedMessage == NULL) { + msg = linphone_chat_room_create_message(cr, sal_msg->text); + } else { + msg = linphone_chat_room_create_message(cr, (const char *)decryptedMessage); + } + linphone_chat_message_set_from(msg, cr->peer_url); { diff --git a/coreapi/lime.c b/coreapi/lime.c new file mode 100644 index 000000000..7967c3ce6 --- /dev/null +++ b/coreapi/lime.c @@ -0,0 +1,650 @@ +#include "lime.h" +#include "linphonecore.h" +#include "ortp/b64.h" +#include "polarssl/gcm.h" + +/* check polarssl version */ +#include + +#if POLARSSL_VERSION_NUMBER >= 0x01030000 /* for Polarssl version 1.3 */ +#include "polarssl/sha256.h" +#else /* for Polarssl version 1.2 */ +#include "polarssl/sha2.h" +#endif +/** + * @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, uint8_t *inputString, uint16_t inputStringLength) { + int i; + for (i=0; i>4)&0x0F); + outputString[2*i+1] = lime_byteToChar(inputBytes[i]&0x0F); + } +} + + + +int lime_getSelfZid(xmlDocPtr cacheBuffer, uint8_t selfZid[25]) { + if (cacheBuffer == NULL ) { + return LIME_INVALID_CACHE; + } + + xmlNodePtr cur = xmlDocGetRootElement(cacheBuffer); + /* if we found a root element, parse its children node */ + if (cur!=NULL) + { + cur = cur->xmlChildrenNode; + } + xmlChar *selfZidHex = NULL; + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"selfZID"))){ /* self ZID found, extract it */ + selfZidHex = xmlNodeListGetString(cacheBuffer, cur->xmlChildrenNode, 1); + /* copy it to the output buffer and add the null termination */ + memcpy(selfZid, selfZidHex, 24); + selfZid[24]='\0'; + break; + } + cur = cur->next; + } + + /* did we found a ZID? */ + if (selfZidHex == NULL) { + return LIME_INVALID_CACHE; + } + + xmlFree(selfZidHex); + return 0; +} + +int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedKeys) { + + /* parse the file to get all peer matching the sipURI given in associatedKeys*/ + if (cacheBuffer == NULL ) { /* there is no cache return error */ + return LIME_INVALID_CACHE; + } + + /* reset number of associated keys and their buffer */ + associatedKeys->associatedZIDNumber = 0; + associatedKeys->peerKeys = NULL; + + xmlNodePtr cur = xmlDocGetRootElement(cacheBuffer); + /* if we found a root element, parse its children node */ + if (cur!=NULL) + { + cur = cur->xmlChildrenNode; + } + while (cur!=NULL) { /* loop on all peer nodes */ + uint8_t matchingURIFlag = 0; /* this flag is set to one if we found the requested sipURI in the current peer node */ + if ((!xmlStrcmp(cur->name, (const xmlChar *)"peer"))) { /* found a peer node, check if there is a matching sipURI node in it */ + matchingURIFlag = 0; + xmlNodePtr peerNodeChildren = cur->xmlChildrenNode; + + /* loop on children nodes until the end or we found the matching sipURI */ + while (peerNodeChildren!=NULL && matchingURIFlag==0) { + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"uri")) { /* found a peer an URI node, check the content */ + xmlChar *uriNodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + if (!xmlStrcmp(uriNodeContent, (const xmlChar *)associatedKeys->peerURI)) { /* found a match with requested URI */ + matchingURIFlag=1; + } + xmlFree(uriNodeContent); + } + 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 */ + /* 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: 4 nodes*/ + + peerNodeChildren = cur->xmlChildrenNode; /* reset peerNodeChildren to the first child of node */ + while (peerNodeChildren!=NULL && itemFound<4) { + xmlChar *nodeContent = NULL; + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"ZID")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_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); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndSId")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_strToUint8(currentPeerKeys->sessionId, nodeContent, 64); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndIndex")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + 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 */ + lime_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++; + } + + xmlFree(nodeContent); + peerNodeChildren = peerNodeChildren->next; + } + + /* check if we have all the requested information */ + if (itemFound == 4) { + 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); + } + } + } + cur = cur->next; + } + return 0; +} + +int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) { + if (cacheBuffer == NULL ) { /* there is no cache return error */ + return LIME_INVALID_CACHE; + } + + /* get the given ZID into hex format */ + uint8_t peerZidHex[25]; + lime_int8ToStr(peerZidHex, associatedKey->peerZID, 12); + peerZidHex[24]='\0'; /* must be a null terminated string */ + + xmlNodePtr cur = xmlDocGetRootElement(cacheBuffer); + /* if we found a root element, parse its children node */ + if (cur!=NULL) + { + cur = cur->xmlChildrenNode; + + } + uint8_t itemFound = 0; + while (cur!=NULL && itemFound<3) { /* 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 */ + xmlNodePtr peerNodeChildren = cur->xmlChildrenNode->next; + while (peerNodeChildren != NULL && itemFound<3) { /* look for the tag we want to read */ + xmlChar *nodeContent = NULL; + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvKey")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_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); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvIndex")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + 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 */ + lime_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++; + } + xmlFree(nodeContent); + peerNodeChildren = peerNodeChildren->next; + } + } + xmlFree(currentZidHex); + } + cur = cur->next; + } + + + return 0; +} + +int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t role) { + if (cacheBuffer == NULL ) { /* there is no cache return error */ + return LIME_INVALID_CACHE; + } + + /* get the given ZID into hex format */ + uint8_t peerZidHex[25]; + lime_int8ToStr(peerZidHex, associatedKey->peerZID, 12); + peerZidHex[24]='\0'; /* must be a null terminated string */ + + xmlNodePtr cur = xmlDocGetRootElement(cacheBuffer); + /* if we found a root element, parse its children node */ + if (cur!=NULL) + { + cur = cur->xmlChildrenNode; + + } + + /* convert the given tag content to null terminated Hexadecimal strings */ + uint8_t keyHex[65]; /* key is 32 bytes long -> 64 bytes string + null termination */ + lime_int8ToStr(keyHex, associatedKey->key, 32); + keyHex[64] = '\0'; + uint8_t sessionIdHex[65]; /* sessionId is 32 bytes long -> 64 bytes string + null termination */ + lime_int8ToStr(sessionIdHex, associatedKey->sessionId, 32); + sessionIdHex[64] = '\0'; + uint8_t sessionIndexHex[9]; /* sessionInedx is an uint32_t : 4 bytes long -> 8 bytes string + null termination */ + 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'; + + uint8_t itemFound = 0; + while (cur!=NULL && itemFound<3) { /* 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 */ + xmlNodePtr peerNodeChildren = cur->xmlChildrenNode->next; + while (peerNodeChildren != NULL && itemFound<3) { /* 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); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvSId")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)sessionIdHex); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvIndex")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)sessionIndexHex); + itemFound++; + } + } else { /* writing sender key */ + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndKey")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)keyHex); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndSId")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)sessionIdHex); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndIndex")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)sessionIndexHex); + itemFound++; + } + } + peerNodeChildren = peerNodeChildren->next; + } + } + xmlFree(currentZidHex); + } + cur = cur->next; + } + + + return 0; +} + +int lime_deriveKey(limeKey_t *key) { + if (key == NULL) { + return LIME_UNABLE_TO_DERIVE_KEY; + } + + if ((key->key == NULL) || (key->sessionId == NULL)) { + return LIME_UNABLE_TO_DERIVE_KEY; + } + + /* Derivation is made derived Key = HMAC_SHA256(Key, 0x0000001||"MessageKey"||0x00||SessionId||SessionIndex||0x00000100)*/ + /* total data to be hashed is 55 bytes : 4 + 10 + 1 + 32 + 4 + 4 */ + uint8_t inputData[55]; + inputData[0] = 0x00; + inputData[1] = 0x00; + inputData[2] = 0x00; + inputData[3] = 0x01; + + memcpy(inputData+4, "MessageKey", 10); + + inputData[14] = 0x00; + + memcpy(inputData+15, key->sessionId, 32); + + inputData[47] = (uint8_t)((key->sessionIndex>>24)&0x000000FF); + inputData[48] = (uint8_t)((key->sessionIndex>>16)&0x000000FF); + inputData[49] = (uint8_t)((key->sessionIndex>>8)&0x000000FF); + inputData[50] = (uint8_t)(key->sessionIndex&0x000000FF); + + inputData[51] = 0x00; + inputData[52] = 0x00; + inputData[53] = 0x01; + inputData[54] = 0x00; + + /* derive the key in a temp buffer */ + uint8_t derivedKey[32]; +#if POLARSSL_VERSION_NUMBER >= 0x01030000 /* for Polarssl version 1.3 */ + sha256_hmac(key->key, 32, inputData, 55, derivedKey, 0); /* last param to zero to select SHA256 and not SHA224 */ +#else /* for Polarssl version 1.2 */ + sha2_hmac(key->key, 32, inputData, 55, derivedKey, 0); /* last param to zero to select SHA256 and not SHA224 */ +#endif /* POLARSSL_VERSION_NUMBER */ + + /* overwrite the old key with the derived one */ + memcpy(key->key, derivedKey, 32); + + /* increment the session Index */ + key->sessionIndex += 1; + return 0; +} + +void lime_freeKeys(limeURIKeys_t associatedKeys) { + int i; + + /* free all associated keys */ + for (i=0; i< associatedKeys.associatedZIDNumber; i++) { + if (associatedKeys.peerKeys[i] != NULL) { + free(associatedKeys.peerKeys[i]); + associatedKeys.peerKeys[i] = NULL; + } + } + + free(associatedKeys.peerKeys); + + /* free sipURI string */ + free(associatedKeys.peerURI); +} + +int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *encryptedMessage) { + /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */ + uint8_t authenticatedData[28]; + memcpy(authenticatedData, selfZID, 12); + memcpy(authenticatedData+12, key->peerZID, 12); + authenticatedData[24] = (uint8_t)((key->sessionIndex>>24)&0x000000FF); + authenticatedData[25] = (uint8_t)((key->sessionIndex>>16)&0x000000FF); + authenticatedData[26] = (uint8_t)((key->sessionIndex>>8)&0x000000FF); + authenticatedData[27] = (uint8_t)(key->sessionIndex&0x000000FF); + + /* AES-GCM : key is 192 bits long, Init Vector 64 bits. 256 bits key given is AES key||IV */ + /* tag is 16 bytes long and is set in the 16 first bytes of the encrypted message */ + gcm_context gcmContext; + gcm_init(&gcmContext, POLARSSL_CIPHER_ID_AES, key->key, 192); + gcm_crypt_and_tag(&gcmContext, GCM_ENCRYPT, messageLength, key->key+24, 8, authenticatedData, 28, plainMessage, encryptedMessage+16, 16, encryptedMessage); + gcm_free(&gcmContext); + + return 0; +} + +int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage) { + /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */ + uint8_t authenticatedData[28]; + memcpy(authenticatedData, key->peerZID, 12); + memcpy(authenticatedData+12, selfZID, 12); + authenticatedData[24] = (uint8_t)((key->sessionIndex>>24)&0x000000FF); + authenticatedData[25] = (uint8_t)((key->sessionIndex>>16)&0x000000FF); + authenticatedData[26] = (uint8_t)((key->sessionIndex>>8)&0x000000FF); + authenticatedData[27] = (uint8_t)(key->sessionIndex&0x000000FF); + + /* AES-GCM : key is 192 bits long, Init Vector 64 bits. 256 bits key given is AES key||IV */ + /* tag is 16 bytes long and is the 16 first bytes of the encrypted message */ + gcm_context gcmContext; + gcm_init(&gcmContext, POLARSSL_CIPHER_ID_AES, key->key, 192); + /* messageLength-16 is the length of encrypted data, messageLength include the 16 bytes tag included at the begining of encryptedMessage */ + int retval = gcm_auth_decrypt(&gcmContext, messageLength-16, key->key+24, 8, authenticatedData, 28, encryptedMessage, 16, encryptedMessage+16, plainMessage); + gcm_free(&gcmContext); + /* add the null termination char */ + plainMessage[messageLength-16] = '\0'; + + return retval; +} + +int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t *peerURI, uint8_t **output) { + /* retrieve selfZIDHex from cache(return a 24 char hexa string + null termination) */ + uint8_t selfZidHex[25]; + if (lime_getSelfZid(cacheBuffer, selfZidHex) != 0) { + return LIME_UNABLE_TO_ENCRYPT_MESSAGE; + } + uint8_t selfZid[12]; /* same data but in byte buffer */ + lime_strToUint8(selfZid, selfZidHex, 24); + + /* encrypted message length is plaintext + 16 for tag */ + uint32_t encryptedMessageLength = strlen((char *)message) + 16; + + + /* retrieve keys associated to the peer URI */ + limeURIKeys_t associatedKeys; + associatedKeys.peerURI = (uint8_t *)malloc(strlen((char *)peerURI)+1); + strcpy((char *)(associatedKeys.peerURI), (char *)peerURI); + associatedKeys.associatedZIDNumber = 0; + associatedKeys.peerKeys = NULL; + + if (lime_getCachedSndKeysByURI(cacheBuffer, &associatedKeys) != 0) { + lime_freeKeys(associatedKeys); + return LIME_UNABLE_TO_ENCRYPT_MESSAGE; + } + + if (associatedKeys.associatedZIDNumber == 0) { + lime_freeKeys(associatedKeys); + return LIME_NO_KEY_FOUND_FOR_PEER; + } + + /* create an xml doc to hold the multipart message */ + xmlDocPtr xmlOutputMessage = xmlNewDoc((const xmlChar *)"1.0"); + /* root tag is "doc" */ + xmlNodePtr rootNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"doc", NULL); + xmlDocSetRootElement(xmlOutputMessage, rootNode); + /* add the self ZID child */ + xmlNewTextChild(rootNode, NULL, (const xmlChar *)"ZID", selfZidHex); + + /* loop on all keys found */ + int i; + for (i=0; i + * peerZID + * session index + * ciphertext + * */ + xmlNodePtr msgNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"msg", NULL); + uint8_t peerZidHex[25]; + lime_int8ToStr(peerZidHex, currentKey->peerZID, 12); + peerZidHex[24] = '\0'; + uint8_t sessionIndexHex[9]; + 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'; + + xmlNewTextChild(msgNode, NULL, (const xmlChar *)"pzid", peerZidHex); + xmlNewTextChild(msgNode, NULL, (const xmlChar *)"index", sessionIndexHex); + + /* convert the cipherText to base 64 */ + int b64Size = b64_encode(NULL, encryptedMessageLength, NULL, 0); + char *encryptedMessageb64 = (char *)malloc(b64Size+1); + b64Size = b64_encode(encryptedMessage, encryptedMessageLength, encryptedMessageb64, b64Size); + encryptedMessageb64[b64Size] = '\0'; /* libxml need a null terminated string */ + xmlNewTextChild(msgNode, NULL, (const xmlChar *)"text", (const xmlChar *)encryptedMessageb64); + free(encryptedMessage); + free(encryptedMessageb64); + + /* add the message Node into the doc */ + xmlAddChild(rootNode, msgNode); + + /* update the key used */ + lime_deriveKey(currentKey); + lime_setCachedKey(cacheBuffer, currentKey, LIME_SENDER); + } + + /* dump the whole message doc into the output */ + int xmlStringLength; + xmlDocDumpFormatMemoryEnc(xmlOutputMessage, output, &xmlStringLength, "UTF-8", 0); + xmlFreeDoc(xmlOutputMessage); + + lime_freeKeys(associatedKeys); + + return 0; +} + +int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output) { + /* retrieve selfZIDHex from cache(return a 24 char hexa string + null termination) */ + uint8_t selfZidHex[25]; + if (lime_getSelfZid(cacheBuffer, selfZidHex) != 0) { + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + uint8_t selfZid[12]; /* same data but in byte buffer */ + lime_strToUint8(selfZid, selfZidHex, 24); + + /* parse the message into an xml doc */ + xmlDocPtr xmlEncryptedMessage = xmlParseDoc(message); + + /* retrieve the sender ZID which is the first child of root */ + limeKey_t associatedKey; + xmlChar *peerZidHex = NULL; + xmlNodePtr cur = xmlDocGetRootElement(xmlEncryptedMessage); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + if ((!xmlStrcmp(cur->name, (const xmlChar *)"ZID"))){ /* sender ZID found, extract it */ + peerZidHex = xmlNodeListGetString(xmlEncryptedMessage, cur->xmlChildrenNode, 1); + /* convert it from hexa string to bytes string and set the result in the associatedKey structure */ + lime_strToUint8(associatedKey.peerZID, peerZidHex, strlen((char *)peerZidHex)); + cur = cur->next; + } + } + + uint8_t *encryptedMessage = NULL; + uint32_t encryptedMessageLength = 0; + uint32_t usedSessionIndex = 0; + + if (peerZidHex != NULL) { + /* get from cache the matching key */ + int retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); + + if (retval == 0) { + /* retrieve the portion of message which is encrypted with our key */ + while (cur != NULL) { /* loop on all "msg" node in the message */ + xmlNodePtr msgChildrenNode = cur->xmlChildrenNode; + xmlChar *currentZidHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); /* pZID is the first element of msg */ + if (!xmlStrcmp(currentZidHex, (const xmlChar *)selfZidHex)) { /* we found the msg node we are looking for */ + /* get the index (second node in the msg one) */ + msgChildrenNode = msgChildrenNode->next; + xmlChar *sessionIndexHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); + 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]))); + xmlFree(sessionIndexHex); + /* get the encrypted message */ + msgChildrenNode = msgChildrenNode->next; + /* convert the cipherText from base 64 */ + xmlChar *encryptedMessageb64 = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); + encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), NULL, 0); + encryptedMessage = (uint8_t *)malloc(encryptedMessageLength); + encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), encryptedMessage, encryptedMessageLength); + xmlFree(encryptedMessageb64); + } + + cur = cur->next; + xmlFree(currentZidHex); + } + } + } + + xmlFree(peerZidHex); + xmlFreeDoc(xmlEncryptedMessage); + + /* do we have retrieved correctly all the needed data */ + if (encryptedMessage == NULL) { + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + + /* shall we derive our key before going for decryption */ + if (usedSessionIndex>associatedKey.sessionIndex) { + /* TODO */ + } + + /* decrypt the message */ + *output = (uint8_t *)malloc(encryptedMessageLength - 16 +1); /* plain message is same length than encrypted one with 16 bytes less for the tag + 1 to add the null termination char */ + lime_decryptMessage(&associatedKey, encryptedMessage, encryptedMessageLength, selfZid, *output); + free(encryptedMessage); + + /* update used key */ + lime_deriveKey(&associatedKey); + lime_setCachedKey(cacheBuffer, &associatedKey, LIME_RECEIVER); + + return 0; +} diff --git a/coreapi/lime.h b/coreapi/lime.h new file mode 100644 index 000000000..0dc5c075a --- /dev/null +++ b/coreapi/lime.h @@ -0,0 +1,141 @@ +#ifndef LIME_H +#define LIME_H + +#define LIME_INVALID_CACHE 0x1001 +#define LIME_UNABLE_TO_DERIVE_KEY 0x1002 +#define LIME_UNABLE_TO_ENCRYPT_MESSAGE 0x1004 +#define LIME_UNABLE_TO_DECRYPT_MESSAGE 0x1008 +#define LIME_NO_KEY_FOUND_FOR_PEER 0x1010 + +#define LIME_SENDER 0x01 +#define LIME_RECEIVER 0x02 +#include +#include +#include +#include + +/** + * @brief Structure holding all needed material to encrypt/decrypt Messages */ +typedef struct limeKey_struct { + uint8_t key[32]; /**< a 256 bit key used to encrypt/decrypt message */ + uint8_t sessionId[32]; /**< a session id used to derive key */ + uint32_t sessionIndex; /**< an index to count number of derivation */ + uint8_t peerZID[12]; /**< the ZID associated to this key */ +} limeKey_t; + +/** + * @brief Store the differents keys associated to a sipURI */ +typedef struct limeURIKeys_struct { + limeKey_t **peerKeys; /**< an array of all the key material associated to each ZID matching the specified URI */ + uint16_t associatedZIDNumber; /**< previous array length */ + uint8_t *peerURI; /**< the sip URI associated to all the keys, must be a null terminated string */ +} limeURIKeys_t; + +/** + * @brief Retrieve selfZID from cache + * + * @param[in] cacheBuffer The xmlDoc containing current cache + * @param[out] selfZid The ZID found as a 24 hexa char string null terminated + * + * @return 0 on success, error code otherwise + */ +__attribute__ ((visibility ("default"))) int lime_getSelfZid(xmlDocPtr cacheBuffer, uint8_t selfZid[25]); + +/** + * @brief Get from cache all the senders keys associated to the given URI + * peerKeys field from associatedKeys param must be NULL when calling this function. + * Structure content must then be freed using lime_freeKeys function + * + * @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 + */ +__attribute__ ((visibility ("default"))) int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedKeys); + +/** + * @brief Get the receiver key associated to the ZID given in the associatedKey parameter + * + * @param[in] cacheBuffer The xmlDoc containing current cache + * @param[in/out] associatedKey Structure containing the peerZID and will store the retrieved key + * + * @return 0 on success, error code otherwise + */ +__attribute__ ((visibility ("default"))) int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey); + +/** + * @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] role Can be LIME_SENDER or LIME_RECEIVER, specify which key we want to update + * + * @return 0 on success, error code otherwise + */ + +__attribute__ ((visibility ("default"))) int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t role); + +/** + * @brief Free all allocated data in the associated keys structure + * Note, this will also free the peerURI string which then must have been allocated + * + * @param[in/out] associatedKeys The structure to be cleaned + * + */ +__attribute__ ((visibility ("default"))) void lime_freeKeys(limeURIKeys_t associatedKeys); + +/** + * @brief Derive in place the key given in parameter and increment session index + * Derivation is made derived Key = HMAC_SHA256(Key, 0x0000001||"MessageKey"||0x00||SessionId||SessionIndex||256) + * + * @param[in/out] key The structure containing the original key which will be overwritten, the sessionId and SessionIndex + * + * @return 0 on success, error code otherwise + */ +__attribute__ ((visibility ("default"))) int lime_deriveKey(limeKey_t *key); + +/** + * @brief encrypt a message with the given key + * + * @param[in] key Key to use: first 192 bits are used as key, last 64 bits as init vector + * @param[in] message The string to be encrypted + * @param[in] messageLength The length in bytes of the message to be encrypted + * @param[in] selfZID The self ZID is use in authentication tag computation + * @param[out] encryptedMessage A buffer to hold the output, ouput length is input's one + 16 for the authentication tag + * Authentication tag is set at the begining of the encrypted Message + * + * @return 0 on success, error code otherwise + * + */ +__attribute__ ((visibility ("default"))) int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *encryptedMessage); + +/** + * @brief decrypt and authentify a message with the given key + * + * @param[in] key Key to use: first 192 bits are used as key, last 64 bits as init vector + * @param[in] message The string to be decrypted + * @param[in] messageLength The length in bytes of the message to be decrypted (this include the 16 bytes tag at the begining of the message) + * @param[in] selfZID The self ZID is use in authentication tag computation + * @param[out] plainMessage A buffer to hold the output, ouput length is input's one - 16 for the authentication tag + 1 for null termination char + * Authentication tag is retrieved at the begining of the encrypted Message + * + * @return 0 on success, error code otherwise + * + */ + +__attribute__ ((visibility ("default"))) int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage); + +/** + * @brief create the encrypted multipart xml message from plain text and destination URI + * Retrieve in cache the needed keys which are then updated. Output buffer is allocated and must be freed by caller + * + * @param[in/out] cacheBuffer The xmlDoc containing current cache, get the keys and selfZID from it, updated by this function with derivated keys + * @param[in] message The plain text message to be encrypted + * @param[in] peerURI The destination URI, associated keys will be found in cache + * @param[out] output The output buffer, allocated and set with the encrypted message xml body(null terminated string). Must be freed by caller + * + * @return 0 on success, error code otherwise + */ +__attribute__ ((visibility ("default"))) int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t *peerURI, uint8_t **output); +__attribute__ ((visibility ("default"))) int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output); +#endif /* LIME_H */ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 41a92140f..f12cecf65 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2069,7 +2069,8 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut call->current_params.media_encryption=LinphoneMediaEncryptionNone; params.zid_file=lc->zrtp_secrets_cache; - params.uri= "SetThePeerSipUriHere@nullTerminated.String"; /* TODO: set the sip URI there, MUST be a null terminated string */ + + params.uri= linphone_address_as_string_uri_only(call->log->to); audio_stream_enable_zrtp(call->audiostream,¶ms); }else{ call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ? diff --git a/mediastreamer2 b/mediastreamer2 index 9117185fd..da5d1de60 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9117185fd8b0a4679cc198cded64dad7d85628e0 +Subproject commit da5d1de606699162f48751f006d9219321069545 diff --git a/oRTP b/oRTP index a0bab264b..f71c3aa0d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit a0bab264b915bcb5b67c061ed27bbb2b90a1b29a +Subproject commit f71c3aa0dec5267bc78d22d33282661dc8795be5 diff --git a/tester/ZIDCache.xml b/tester/ZIDCache.xml new file mode 100644 index 000000000..1f0fcb1a3 --- /dev/null +++ b/tester/ZIDCache.xml @@ -0,0 +1,2 @@ + +ef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.com963c57bb28e62068d2df23e8f9b771932d3c57bb28e62068d2df23e8f9b77193e9d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b771935f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193e6ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000069000001cc1234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.com123456789012345678901234567890123456765431262068d2df23e8f9b7719325d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000100000000 diff --git a/tester/ZIDCacheAlice.xml b/tester/ZIDCacheAlice.xml new file mode 100644 index 000000000..5fe09a289 --- /dev/null +++ b/tester/ZIDCacheAlice.xml @@ -0,0 +1,2 @@ + +ef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.comf6e5c94feabbe348f25a528cc990b7ec0f3390286314eb70cf2a9a852afb2df4bfd9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b771935f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000074000001a21234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.comb438386ce7d91f0c3341315ff58ce14826a119f36d91650ca26fa7fde2f1601225d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000c00000000 diff --git a/tester/ZIDCacheBob.xml b/tester/ZIDCacheBob.xml new file mode 100644 index 000000000..23116d8da --- /dev/null +++ b/tester/ZIDCacheBob.xml @@ -0,0 +1,4 @@ + +005dbe0399643d953a2202dd + ef7692d0792a67491ae2d44e9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.comf6e5c94feabbe348f25a528cc990b7ec0f3390286314eb70cf2a9a852afb2df4bfd9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b771935f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000074000001a2 + 1234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.com123456789012345678901234567890123456765431262068d2df23e8f9b7719325d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000100000000 diff --git a/tester/message_tester.c b/tester/message_tester.c index 259727715..bd3faadb7 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -22,6 +22,7 @@ #include "linphonecore.h" #include "private.h" #include "liblinphone_tester.h" +#include "lime.h" static char* message_external_body_url; @@ -370,6 +371,168 @@ static void is_composing_notification(void) { linphone_core_manager_destroy(pauline); } +void printHex(char *title, uint8_t *data, uint32_t length) { + printf ("%s : ", title); + int i; + for (i=0; ipeerZID, 12); + printHex("key", associatedKeys.peerKeys[i]->key, 32); + printHex("sessionID", associatedKeys.peerKeys[i]->sessionId, 32); + printf("session index %d\n", associatedKeys.peerKeys[i]->sessionIndex); + } + + /* get data from cache : receiver */ + limeKey_t associatedKey; + uint8_t targetZID[12] = {0x00, 0x5d, 0xbe, 0x03, 0x99, 0x64, 0x3d, 0x95, 0x3a, 0x22, 0x02, 0xdd}; + memcpy(associatedKey.peerZID, targetZID, 12); + retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); + printf("getCachedKey by ZID return %d\n", retval); + + printHex("Key", associatedKey.key, 32); + printHex("sessionID", associatedKey.sessionId, 32); + printf("session index %d\n", associatedKey.sessionIndex); + + /* encrypt/decrypt a message */ + uint8_t senderZID[12] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0}; + uint8_t encryptedMessage[48]; + uint8_t plainMessage[48]; + lime_encryptMessage(associatedKeys.peerKeys[0], (uint8_t *)"bla Bla bla b! Pipo", 20, senderZID, encryptedMessage); + printHex("Ciphered", encryptedMessage, 32); + /* invert sender and receiverZID to decrypt/authenticate */ + uint8_t receiverZID[12]; + memcpy(receiverZID, associatedKeys.peerKeys[0]->peerZID, 12); + memcpy(associatedKeys.peerKeys[0]->peerZID, senderZID, 12); + retval = lime_decryptMessage(associatedKeys.peerKeys[0], encryptedMessage, 36, receiverZID, plainMessage); + printf("Decrypt and auth returned %d\nPlain: %s\n", retval, plainMessage); + + /* update receiver data */ + associatedKey.sessionIndex++; + associatedKey.key[0]++; + associatedKey.sessionId[0]++; + retval = lime_setCachedKey(cacheBuffer, &associatedKey, LIME_RECEIVER); + printf("setCachedKey return %d\n", retval); + + /* 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); + printf("setCachedKey return %d\n", retval); + + /* free memory */ + lime_freeKeys(associatedKeys); + + /* write the file */ + /* dump the xml document into a string */ + xmlDocDumpFormatMemoryEnc(cacheBuffer, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the file */ + CACHE = fopen("ZIDCache.xml", "w+"); + fwrite(xmlStringOutput, 1, xmlStringLength, CACHE); + xmlFree(xmlStringOutput); + fclose(CACHE); + xmlFreeDoc(cacheBuffer); +} + test_t message_tests[] = { { "Text message", text_message }, { "Text message within call's dialog", text_message_within_dialog}, @@ -382,7 +545,8 @@ test_t message_tests[] = { { "Text message denied", text_message_denied }, { "Info message", info_message }, { "Info message with body", info_message_with_body }, - { "IsComposing notification", is_composing_notification } + { "IsComposing notification", is_composing_notification }, + { "Lime", lime } }; test_suite_t message_test_suite = { From aabff39f852046b24389ed0625b33fce36099533 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Tue, 15 Apr 2014 16:03:35 +0200 Subject: [PATCH 03/19] update oRTP --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 209d1bbe7..beee1f20d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 209d1bbe764d4639860bf5f075ebf404d08e8dde +Subproject commit beee1f20d69af3d04cd27fcc00b3830620066367 From 3ccc7fb4deb143225c7b2b685d14c2eb2f1e73fa Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Tue, 22 Apr 2014 12:26:50 +0200 Subject: [PATCH 04/19] Give peer URI to the zrtp context --- coreapi/linphonecall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index bbe448768..75952f404 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2067,7 +2067,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut params.zid_file=lc->zrtp_secrets_cache; - params.uri= linphone_address_as_string_uri_only(call->log->to); + params.uri= linphone_address_as_string_uri_only((call->dir==LinphoneCallIncoming) ? call->log->from : call->log->to); audio_stream_enable_zrtp(call->audiostream,¶ms); }else{ call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ? From 26ada60683bc28982dbfdd40d5eb570c291032f2 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Fri, 25 Apr 2014 21:24:50 +0200 Subject: [PATCH 05/19] Complete LIME integration into liblinphone - add a boolean into linphoneCore to check if encryption is requested - move encryption/decryption from chat.c to sal_op_message.c - check encrypted message validity - return error to application when enable to encrypt/decrypt --- coreapi/bellesip_sal/sal_op_message.c | 115 ++++++++++++++++++++++++-- coreapi/chat.c | 98 ++-------------------- coreapi/lime.c | 41 +++++++-- coreapi/lime.h | 4 + coreapi/linphonecore.c | 11 +++ coreapi/linphonecore.h | 2 + coreapi/private.h | 1 + include/sal/sal.h | 2 +- oRTP | 2 +- 9 files changed, 174 insertions(+), 102 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 2f161c2a6..833ca8c9f 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -18,6 +18,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sal_impl.h" +#include "linphonecore.h" +#include "private.h" +#include "lime.h" +#include + static void process_error( SalOp* op) { if (op->dir == SalOpDirOutgoing) { op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed); @@ -59,6 +64,11 @@ static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) { return strcmp("text",belle_sip_header_content_type_get_type(content_type))==0 && strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0; } + +static bool_t is_cipher_xml(belle_sip_header_content_type_t* content_type) { + return strcmp("xml",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("cipher",belle_sip_header_content_type_get_subtype(content_type))==0; +} static bool_t is_external_body(belle_sip_header_content_type_t* content_type) { return strcmp("message",belle_sip_header_content_type_get_type(content_type))==0 && strcmp("external-body",belle_sip_header_content_type_get_subtype(content_type))==0; @@ -69,7 +79,7 @@ static bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) { } static void add_message_accept(belle_sip_message_t *msg){ - belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml")); + belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml, xml/cipher")); } void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){ @@ -85,11 +95,58 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve char* from; bool_t plain_text=FALSE; bool_t external_body=FALSE; + bool_t cipher_xml=FALSE; from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); + /* check if we have a xml/cipher message to be decrypted */ + uint8_t *decryptedMessage = NULL; + if (content_type && (cipher_xml=is_cipher_xml(content_type))) { + /* access the zrtp cache to get keys needed to decipher the message */ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "r+"); + ms_message("Cache file is %s", lc->zrtp_secrets_cache); + if (CACHEFD == NULL) { + ms_warning("Unable to access ZRTP ZID cache to decrypt message"); + } else { + fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ + int cacheSize = ftell(CACHEFD); /* Get file length */ + rewind(CACHEFD); /* Back to start of file */ + uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ + fread(cacheString, 1, cacheSize, CACHEFD); + cacheString[cacheSize] = '\0'; + cacheSize += 1; + fclose(CACHEFD); + xmlDocPtr cacheXml = xmlParseDoc(cacheString); + free(cacheString); + int retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage); + if (retval != 0) { + ms_warning("JOHAN: Unable to decrypt message, reason %x", retval); + free(decryptedMessage); + xmlFreeDoc(cacheXml); + resp = belle_sip_response_create_from_request(req,488); + belle_sip_server_transaction_send_response(server_transaction,resp); + return; + } else { + ms_warning("JOHAN : Yes we did decrypt the message and it is %s", decryptedMessage); + /* dump updated cache to a string */ + xmlChar *xmlStringOutput; + int xmlStringLength; + xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the cache file */ + CACHEFD = fopen(lc->zrtp_secrets_cache, "w+"); + fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD); + xmlFree(xmlStringOutput); + fclose(CACHEFD); + } + + xmlFreeDoc(cacheXml); + } + + } if (content_type && ((plain_text=is_plain_text(content_type)) - || (external_body=is_external_body(content_type)))) { + || (external_body=is_external_body(content_type)) + || decryptedMessage!=NULL)) { SalMessage salmsg; char message_id[256]={0}; @@ -104,7 +161,7 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve ,belle_sip_header_call_id_get_call_id(call_id) ,belle_sip_header_cseq_get_seq_number(cseq)); salmsg.from=from; - salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; + salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):(cipher_xml?(char *)decryptedMessage:NULL); salmsg.url=NULL; if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) { size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")); @@ -143,11 +200,12 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t sal_process_incoming_message(op,event); } -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ +int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri){ belle_sip_request_t* req; char content_type_raw[256]; size_t content_length = msg?strlen(msg):0; time_t curtime=time(NULL); + uint8_t *multipartEncryptedMessage = NULL; if (op->dialog){ /*for SIP MESSAGE that are sent in call's dialog*/ @@ -165,11 +223,56 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); } } + + /* shall we try to encrypt the message?*/ + if (strcmp(content_type, "xml/cipher") == 0) { + /* access the zrtp cache to get keys needed to cipher the message */ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "r+"); + ms_message("Cache file is %s", lc->zrtp_secrets_cache); + if (CACHEFD == NULL) { + ms_warning("Unable to access ZRTP ZID cache to encrypt message"); + } else { + fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ + int cacheSize = ftell(CACHEFD); /* Get file length */ + rewind(CACHEFD); /* Back to start of file */ + uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ + fread(cacheString, 1, cacheSize, CACHEFD); + cacheString[cacheSize] = '\0'; + cacheSize += 1; + fclose(CACHEFD); + xmlDocPtr cacheXml = xmlParseDoc(cacheString); + free(cacheString); + int retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg, (uint8_t *)peer_uri, &multipartEncryptedMessage); + if (retval != 0) { + ms_warning("Unable to encrypt message to %s error %x", peer_uri, retval); + xmlFreeDoc(cacheXml); + free(multipartEncryptedMessage); + sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); + op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); + return 0; + } else { + ms_warning("Succes in encrypting message for %s to %s", to, peer_uri); + /* dump updated cache to a string */ + xmlChar *xmlStringOutput; + int xmlStringLength; + xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the cache file */ + CACHEFD = fopen(lc->zrtp_secrets_cache, "w+"); + fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD); + xmlFree(xmlStringOutput); + fclose(CACHEFD); + content_length = strlen((const char *)multipartEncryptedMessage); + } + xmlFreeDoc(cacheXml); + } + } + snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); - belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),msg,content_length); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),(multipartEncryptedMessage==NULL)?msg:(const char *)multipartEncryptedMessage,content_length); return sal_op_send_request(op,req); } @@ -186,7 +289,7 @@ int sal_message_reply(SalOp *op, SalReason reason){ } int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { - return sal_message_send(op,from,to,"text/plain",msg); + return sal_message_send(op,from,to,"text/plain",msg, NULL); } static belle_sip_listener_callbacks_t op_message_callbacks={0}; diff --git a/coreapi/chat.c b/coreapi/chat.c index 0f48e9dd4..bb231f97b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -26,10 +26,6 @@ #include "private.h" #include "lpconfig.h" -#include - -#include "lime.h" - #define COMPOSING_DEFAULT_IDLE_TIMEOUT 15 #define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60 #define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120 @@ -203,54 +199,21 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM linphone_configure_op(cr->lc,op,cr->peer_url,msg->custom_headers,lp_config_get_int(cr->lc->config,"sip","chat_msg_with_contact",0)); sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/ } + + if (msg->external_body_url) { content_type=ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->external_body_url); - sal_message_send(op,identity,cr->peer,content_type, NULL); + sal_message_send(op,identity,cr->peer,content_type, NULL, NULL); ms_free(content_type); } else { - uint8_t *multipartEncryptedMessage = NULL; - /* shall we try to encrypt the message?*/ - if (1) { /* TODO : set a flag for message encryption into LinphoneChatRoom structure */ - /* get the zrtp cache and parse it into an xml doc */ - FILE *CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "r+"); - ms_message("Cache file is %s", cr->lc->zrtp_secrets_cache); - if (CACHEFD == NULL) { - ms_warning("Unable to access ZRTP ZID cache to encrypt message"); - } else { - fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ - int cacheSize = ftell(CACHEFD); /* Get file length */ - rewind(CACHEFD); /* Back to start of file */ - uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ - fread(cacheString, 1, cacheSize, CACHEFD); - cacheString[cacheSize] = '\0'; - cacheSize += 1; - fclose(CACHEFD); - xmlDocPtr cacheXml = xmlParseDoc(cacheString); - int retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg->message, (uint8_t *)linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)), &multipartEncryptedMessage); - if (retval != 0) { - ms_warning("Unable to encrypt message to %s error %x", linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)), retval); - } - /* dump updated cache to a string */ - xmlChar *xmlStringOutput; - int xmlStringLength; - xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); - /* write it to the cache file */ - CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "w+"); - fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD); - xmlFree(xmlStringOutput); - fclose(CACHEFD); - - - xmlFreeDoc(cacheXml); - } - } - if (multipartEncryptedMessage!=NULL) { - sal_text_send(op, identity, cr->peer,(const char *)multipartEncryptedMessage); - free(multipartEncryptedMessage); + if (cr->lc->lime == 1) { /* shall we try to encrypt messages? */ + linphone_chat_message_ref(msg); /* ref the message or it may be destroyed by callback if the encryption failed */ + sal_message_send(op, identity, cr->peer, "xml/cipher", msg->message, linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr))); } else { sal_text_send(op, identity, cr->peer,msg->message); } } + msg->dir=LinphoneChatMessageOutgoing; msg->from=linphone_address_new(identity); msg->storage_id=linphone_chat_message_store(msg); @@ -306,7 +269,6 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag LinphoneChatRoom *cr=NULL; LinphoneAddress *addr; char *cleanfrom; - char *from; LinphoneChatMessage* msg; const SalCustomHeader *ch; @@ -314,53 +276,12 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag linphone_address_clean(addr); cr=linphone_core_get_chat_room(lc,addr); cleanfrom=linphone_address_as_string(addr); - from=linphone_address_as_string_uri_only(addr); if (cr==NULL){ /* create a new chat room */ cr=linphone_core_create_chat_room(lc,cleanfrom); } - /* shall we try to decrypt the message */ - uint8_t *decryptedMessage = NULL; - if (1) { /* TODO : set a flag for message encryption into LinphoneChatRoom structure */ - /* get the zrtp cache and parse it into an xml doc */ - FILE *CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "r+"); - ms_message("Cache file is %s", lc->zrtp_secrets_cache); - if (CACHEFD == NULL) { - ms_warning("Unable to access ZRTP ZID cache to decrypt message"); - } else { - fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ - int cacheSize = ftell(CACHEFD); /* Get file length */ - rewind(CACHEFD); /* Back to start of file */ - uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ - fread(cacheString, 1, cacheSize, CACHEFD); - cacheString[cacheSize] = '\0'; - cacheSize += 1; - fclose(CACHEFD); - xmlDocPtr cacheXml = xmlParseDoc(cacheString); - int retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)(sal_msg->text), &decryptedMessage); - if (retval != 0) { - ms_warning("Unable to decrypt message error %x", retval); - } - /* dump updated cache to a string */ - xmlChar *xmlStringOutput; - int xmlStringLength; - xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); - /* write it to the cache file */ - CACHEFD = fopen(lc->zrtp_secrets_cache, "w+"); - fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD); - xmlFree(xmlStringOutput); - fclose(CACHEFD); - - xmlFreeDoc(cacheXml); - } - } - - if (decryptedMessage == NULL) { - msg = linphone_chat_room_create_message(cr, sal_msg->text); - } else { - msg = linphone_chat_room_create_message(cr, (const char *)decryptedMessage); - } + msg = linphone_chat_room_create_message(cr, sal_msg->text); linphone_chat_message_set_from(msg, cr->peer_url); @@ -384,7 +305,6 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag msg->storage_id=linphone_chat_message_store(msg); linphone_chat_room_message_received(cr,lc,msg); ms_free(cleanfrom); - ms_free(from); } static int linphone_chat_room_remote_refresh_composing_expired(void *data, unsigned int revents) { @@ -646,7 +566,7 @@ static void linphone_chat_room_send_is_composing_notification(LinphoneChatRoom * } content = linphone_chat_room_create_is_composing_xml(cr); if (content != NULL) { - sal_message_send(op, identity, cr->peer, "application/im-iscomposing+xml", content); + sal_message_send(op, identity, cr->peer, "application/im-iscomposing+xml", content, NULL); ms_free(content); } } diff --git a/coreapi/lime.c b/coreapi/lime.c index 7967c3ce6..0e1f90031 100644 --- a/coreapi/lime.c +++ b/coreapi/lime.c @@ -557,6 +557,11 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t } int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output) { + int retval; + + if (cacheBuffer == NULL) { + return LIME_INVALID_CACHE; + } /* retrieve selfZIDHex from cache(return a 24 char hexa string + null termination) */ uint8_t selfZidHex[25]; if (lime_getSelfZid(cacheBuffer, selfZidHex) != 0) { @@ -566,7 +571,14 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ lime_strToUint8(selfZid, selfZidHex, 24); /* parse the message into an xml doc */ - xmlDocPtr xmlEncryptedMessage = xmlParseDoc(message); + /* make sure we have a valid xml message before trying to parse it */ + if (memcmp(message, "", 38) != 0 ) { + return LIME_INVALID_ENCRYPTED_MESSAGE; + } + xmlDocPtr xmlEncryptedMessage = xmlParseDoc((const xmlChar *)message); + if (xmlEncryptedMessage == NULL) { + return LIME_INVALID_ENCRYPTED_MESSAGE; + } /* retrieve the sender ZID which is the first child of root */ limeKey_t associatedKey; @@ -588,7 +600,7 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ if (peerZidHex != NULL) { /* get from cache the matching key */ - int retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); + retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); if (retval == 0) { /* retrieve the portion of message which is encrypted with our key */ @@ -633,15 +645,34 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ } /* shall we derive our key before going for decryption */ - if (usedSessionIndex>associatedKey.sessionIndex) { - /* TODO */ + if (usedSessionIndex < associatedKey.sessionIndex) { + /* something wen't wrong with the cache, this shall never happend */ + free(encryptedMessage); + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + + if ((usedSessionIndex - associatedKey.sessionIndex > MAX_DERIVATION_NUMBER) ) { + /* we missed to many messages, ask for a cache reset via a ZRTP call */ + free(encryptedMessage); + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + + while (usedSessionIndex>associatedKey.sessionIndex) { + lime_deriveKey(&associatedKey); } /* decrypt the message */ *output = (uint8_t *)malloc(encryptedMessageLength - 16 +1); /* plain message is same length than encrypted one with 16 bytes less for the tag + 1 to add the null termination char */ - lime_decryptMessage(&associatedKey, encryptedMessage, encryptedMessageLength, selfZid, *output); + retval = lime_decryptMessage(&associatedKey, encryptedMessage, encryptedMessageLength, selfZid, *output); + free(encryptedMessage); + if (retval!=0 ) { + free(*output); + *output = NULL; + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + /* update used key */ lime_deriveKey(&associatedKey); lime_setCachedKey(cacheBuffer, &associatedKey, LIME_RECEIVER); diff --git a/coreapi/lime.h b/coreapi/lime.h index 0dc5c075a..455c80c6c 100644 --- a/coreapi/lime.h +++ b/coreapi/lime.h @@ -6,6 +6,10 @@ #define LIME_UNABLE_TO_ENCRYPT_MESSAGE 0x1004 #define LIME_UNABLE_TO_DECRYPT_MESSAGE 0x1008 #define LIME_NO_KEY_FOUND_FOR_PEER 0x1010 +#define LIME_INVALID_ENCRYPTED_MESSAGE 0x1020 + +/* this define the maximum key derivation number allowed to get the caches back in sync in case of missed messages */ +#define MAX_DERIVATION_NUMBER 100 #define LIME_SENDER 0x01 #define LIME_RECEIVER 0x02 diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d6b3f842c..b3b94cc6d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -697,6 +697,8 @@ static void sip_config_read(LinphoneCore *lc) tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1); linphone_core_set_guess_hostname(lc,tmp); + tmp=lp_config_get_int(lc->config,"sip","lime",0); + linphone_core_set_lime(lc,tmp); tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30); linphone_core_set_inc_timeout(lc,tmp); @@ -1585,6 +1587,15 @@ bool_t linphone_core_get_guess_hostname(LinphoneCore *lc){ return lc->sip_conf.guess_hostname; } +/** + * Tells to LinphoneCore to use Linphone Instant Messaging encryption + * + */ +void linphone_core_set_lime(LinphoneCore *lc, bool_t val){ + lc->lime=val; + lp_config_set_int(lc->config,"sip","lime",val); +} + /** * Same as linphone_core_get_primary_contact() but the result is a LinphoneAddress object * instead of const char* diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 7448341aa..6c16aae40 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1498,6 +1498,8 @@ LINPHONE_PUBLIC const char * linphone_core_get_identity(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val); LINPHONE_PUBLIC bool_t linphone_core_get_guess_hostname(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_lime(LinphoneCore *lc, bool_t val); + LINPHONE_PUBLIC bool_t linphone_core_ipv6_enabled(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val); diff --git a/coreapi/private.h b/coreapi/private.h index 69ca8c728..2c67af176 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -691,6 +691,7 @@ struct _LinphoneCore belle_tls_verify_policy_t *http_verify_policy; MSList *tones; LinphoneReason chat_deny_code; + bool_t lime; }; diff --git a/include/sal/sal.h b/include/sal/sal.h index 1dba31f90..9054a8f44 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -618,7 +618,7 @@ int sal_unregister(SalOp *h); /*Messaging */ int sal_text_send(SalOp *op, const char *from, const char *to, const char *text); -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg); +int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri); int sal_message_reply(SalOp *op, SalReason reason); /*presence Subscribe/notify*/ diff --git a/oRTP b/oRTP index beee1f20d..ebd87c21d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit beee1f20d69af3d04cd27fcc00b3830620066367 +Subproject commit ebd87c21d3d5c8b4775ef08af18e27c4bf4fa3ac From 9242d38292ae685220496e90d7012e7235e81d01 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Fri, 25 Apr 2014 21:26:34 +0200 Subject: [PATCH 06/19] add lime to the android makefile --- build/android/Android.mk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index 18fbbdbfd..d0cae18fe 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -64,7 +64,8 @@ LOCAL_SRC_FILES := \ xml.c \ xml2lpc.c \ lpc2xml.c \ - remote_provisioning.c + remote_provisioning.c \ + lime.c ifndef LINPHONE_VERSION LINPHONE_VERSION = "Devel" @@ -109,7 +110,8 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../../belle-sip/include \ $(LOCAL_PATH)/../../../gen \ $(LOCAL_PATH)/../../externals/libxml2/include \ - $(LOCAL_PATH)/../../externals/build/libxml2 + $(LOCAL_PATH)/../../externals/build/libxml2 \ + $(LOCAL_PATH)/../../externals/polarssl/include LOCAL_LDLIBS += -llog -ldl From c6d02779a398dd6778c39850bad1547a86939b7c Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Fri, 25 Apr 2014 21:48:44 +0200 Subject: [PATCH 07/19] Debug trace cleaning --- coreapi/bellesip_sal/sal_op_message.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 833ca8c9f..0e7009858 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -105,7 +105,6 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve /* access the zrtp cache to get keys needed to decipher the message */ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "r+"); - ms_message("Cache file is %s", lc->zrtp_secrets_cache); if (CACHEFD == NULL) { ms_warning("Unable to access ZRTP ZID cache to decrypt message"); } else { @@ -121,14 +120,13 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve free(cacheString); int retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage); if (retval != 0) { - ms_warning("JOHAN: Unable to decrypt message, reason %x", retval); + ms_warning("Unable to decrypt message, reason %x", retval); free(decryptedMessage); xmlFreeDoc(cacheXml); resp = belle_sip_response_create_from_request(req,488); belle_sip_server_transaction_send_response(server_transaction,resp); return; } else { - ms_warning("JOHAN : Yes we did decrypt the message and it is %s", decryptedMessage); /* dump updated cache to a string */ xmlChar *xmlStringOutput; int xmlStringLength; @@ -229,7 +227,6 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co /* access the zrtp cache to get keys needed to cipher the message */ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "r+"); - ms_message("Cache file is %s", lc->zrtp_secrets_cache); if (CACHEFD == NULL) { ms_warning("Unable to access ZRTP ZID cache to encrypt message"); } else { @@ -245,14 +242,13 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co free(cacheString); int retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg, (uint8_t *)peer_uri, &multipartEncryptedMessage); if (retval != 0) { - ms_warning("Unable to encrypt message to %s error %x", peer_uri, retval); + ms_warning("Unable to encrypt message for %s error %x", peer_uri, retval); xmlFreeDoc(cacheXml); free(multipartEncryptedMessage); sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); return 0; } else { - ms_warning("Succes in encrypting message for %s to %s", to, peer_uri); /* dump updated cache to a string */ xmlChar *xmlStringOutput; int xmlStringLength; From a3869672c8c94210f9d58d4fb5450bd17fc8a71a Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Fri, 25 Apr 2014 22:13:10 +0200 Subject: [PATCH 08/19] Default value shall be Lime enabled --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b3b94cc6d..c1b5e3e41 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -697,7 +697,7 @@ static void sip_config_read(LinphoneCore *lc) tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1); linphone_core_set_guess_hostname(lc,tmp); - tmp=lp_config_get_int(lc->config,"sip","lime",0); + tmp=lp_config_get_int(lc->config,"sip","lime",1); linphone_core_set_lime(lc,tmp); tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30); From 6b6ff7bb2b0572c770e741287176a3cd7cf01ae3 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Mon, 28 Apr 2014 22:03:27 +0200 Subject: [PATCH 09/19] Don't send message in plain if no cache is found --- coreapi/bellesip_sal/sal_op_message.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 0e7009858..3897dd9cb 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -229,6 +229,9 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "r+"); if (CACHEFD == NULL) { ms_warning("Unable to access ZRTP ZID cache to encrypt message"); + sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); + op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); + return 0; } else { fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ int cacheSize = ftell(CACHEFD); /* Get file length */ From 6bdc64962406949861f18981fb7be5890d67883a Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Thu, 12 Jun 2014 00:49:36 +0200 Subject: [PATCH 10/19] Add encrypted file transfer message + test for the encrypted text message + fix bug introduced in last merge --- coreapi/bellesip_sal/sal_op_message.c | 27 ++++-- coreapi/chat.c | 119 ++++++++++++++++++++++++-- coreapi/help/filetransfer.c | 26 +++--- coreapi/info.c | 13 +++ coreapi/lime.c | 50 +++++++++++ coreapi/lime.h | 28 ++++++ coreapi/linphonecore.h | 2 + tester/ZIDCacheAlice.xml | 2 +- tester/ZIDCacheBob.xml | 4 +- tester/message_tester.c | 118 +++++++++++++++++++++---- 10 files changed, 336 insertions(+), 53 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 18db3dbd2..3e0100b4c 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -61,8 +61,8 @@ static void process_response_event(void *op_base, const belle_sip_response_event } static bool_t is_rcs_filetransfer(belle_sip_header_content_type_t* content_type) { - return strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 - && strcmp("vnd.gsma.rcs-ft-http+xml",belle_sip_header_content_type_get_subtype(content_type))==0; + return (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0) + && ((strcmp("vnd.gsma.rcs-ft-http+xml",belle_sip_header_content_type_get_subtype(content_type))==0) || (strcmp("cipher.vnd.gsma.rcs-ft-http+xml",belle_sip_header_content_type_get_subtype(content_type))==0)); } static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) { @@ -71,8 +71,11 @@ static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) { } static bool_t is_cipher_xml(belle_sip_header_content_type_t* content_type) { - return strcmp("xml",belle_sip_header_content_type_get_type(content_type))==0 - && strcmp("cipher",belle_sip_header_content_type_get_subtype(content_type))==0; + return (strcmp("xml",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("cipher",belle_sip_header_content_type_get_subtype(content_type))==0) + + || (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("cipher.vnd.gsma.rcs-ft-http+xml",belle_sip_header_content_type_get_subtype(content_type))==0); } static bool_t is_external_body(belle_sip_header_content_type_t* content_type) { return strcmp("message",belle_sip_header_content_type_get_type(content_type))==0 @@ -84,7 +87,7 @@ static bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) { } static void add_message_accept(belle_sip_message_t *msg){ - belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml, xml/cioher, application/vnd.gsma.rcs-ft-http+xml")); + belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml, xml/cipher, application/vnd.gsma.rcs-ft-http+xml, application/cipher.vnd.gsma.rcs-ft-http+xml")); } void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){ @@ -148,10 +151,12 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve } } + + rcs_filetransfer=is_rcs_filetransfer(content_type); if (content_type && ((plain_text=is_plain_text(content_type)) || (external_body=is_external_body(content_type)) || (decryptedMessage!=NULL) - || (rcs_filetransfer=is_rcs_filetransfer(content_type)))) { + || rcs_filetransfer)) { SalMessage salmsg; char message_id[256]={0}; @@ -166,8 +171,12 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve ,belle_sip_header_call_id_get_call_id(call_id) ,belle_sip_header_cseq_get_seq_number(cseq)); salmsg.from=from; - salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):(cipher_xml?(char *)decryptedMessage:NULL); - salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; + /* if we just deciphered a message, use the deciphered part(which can be a rcs xml body pointing to the file to retreive from server)*/ + if (cipher_xml) { + salmsg.text = (char *)decryptedMessage; + } else { /* message body wasn't ciphered */ + salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; + } salmsg.url=NULL; salmsg.content_type = NULL; if (rcs_filetransfer) { /* if we have a rcs file transfer, set the type, message body (stored in salmsg.text) contains all needed information to retrieve the file */ @@ -235,7 +244,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co } /* shall we try to encrypt the message?*/ - if (strcmp(content_type, "xml/cipher") == 0) { + if ((strcmp(content_type, "xml/cipher") == 0) || ((strcmp(content_type, "application/cipher.vnd.gsma.rcs-ft-http+xml") == 0))) { /* access the zrtp cache to get keys needed to cipher the message */ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "r+"); diff --git a/coreapi/chat.c b/coreapi/chat.c index 9c7050ff2..b66334262 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -26,6 +26,8 @@ #include "private.h" #include "lpconfig.h" #include "belle-sip/belle-sip.h" +#include "lime.h" +#include "ortp/b64.h" #define COMPOSING_DEFAULT_IDLE_TIMEOUT 15 #define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60 @@ -42,6 +44,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM #define MULTIPART_END "\r\n--" MULTIPART_BOUNDARY "--\r\n" const char *multipart_boundary=MULTIPART_BOUNDARY; +#define FILE_TRANSFER_KEY_SIZE 32 static size_t linphone_chat_message_compute_multipart_header_size(const char *filename, const char *content_type) { return strlen(MULTIPART_HEADER_1)+strlen(filename)+strlen(MULTIPART_HEADER_2)+strlen(content_type)+strlen(MULTIPART_HEADER_3); } @@ -98,12 +101,34 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_ *size=partlen; }else if (offsetvtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buffer, size); + if (chatMsg->file_transfer_information->key != NULL) { /* if we have a key to cipher the message, use it! */ + /* get data from callback to a plainBuffer */ + /* if this chunk is not the last one, the lenght must be a multiple of block cipher size(16 bytes)*/ + if (offset+*sizevtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, plainBuffer, size); + lime_encryptFile(&(chatMsg->file_transfer_information->cryptoContext), chatMsg->file_transfer_information->key, *size, plainBuffer, buffer); + free(plainBuffer); + } else { + /* get data from call back directly to the output buffer */ + lc->vtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buffer, size); + } + /* DEBUG DEBUG : THIS SHALL NEVER HAPPEND */ + if (*size == 0) { + exit(1); + } }else{ + /* conclude the file ciphering if needed */ + if (chatMsg->file_transfer_information->key != NULL) { + lime_encryptFile(&(chatMsg->file_transfer_information->cryptoContext), NULL, 0, NULL, NULL); + } + *size=strlen(MULTIPART_END); strncpy(buffer,MULTIPART_END,*size); } + belle_sip_free(content_type); return BELLE_SIP_CONTINUE; } @@ -123,6 +148,12 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co if (event->response){ int code=belle_http_response_get_status_code(event->response); if (code == 204) { /* this is the reply to the first post to the server - an empty message */ + /* shall we encrypt the file */ + if (msg->chat_room->lc->lime == 1) { + /* generate a random 192 bits key + 64 bits of initial vector and store it into the file_transfer_information->key field of the message */ + msg->file_transfer_information->key = (unsigned char *)malloc(FILE_TRANSFER_KEY_SIZE); + sal_get_random_bytes(msg->file_transfer_information->key, FILE_TRANSFER_KEY_SIZE); + } /* start uploading the file */ belle_http_request_listener_callbacks_t cbs={0}; belle_http_request_listener_t *l; @@ -150,7 +181,46 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co } if (code == 200 ) { /* file has been uplaoded correctly, get server reply and send it */ const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); - msg->message = ms_strdup(body); + + /* if we have an encryption key for the file, we must insert it into the message */ + if (msg->file_transfer_information->key != NULL) { + /* parse the message body */ + xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); + + xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + while (cur!=NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */ + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if(!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for : add a file-key children node */ + /* convert key to base64 */ + int b64Size = b64_encode(NULL, FILE_TRANSFER_KEY_SIZE, NULL, 0); + char *keyb64 = (char *)malloc(b64Size+1); + b64Size = b64_encode(msg->file_transfer_information->key, FILE_TRANSFER_KEY_SIZE, keyb64, b64Size); + keyb64[b64Size] = '\0'; /* libxml need a null terminated string */ + + /* add the node containing the key to the file-info node */ + xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); + xmlFree(typeAttribute); + + /* dump the xml into msg->message */ + int xmlStringLength; + xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, "UTF-8", 0); + + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + + } else { /* no encryption key, transfer in plain, just copy the message sent by server */ + msg->message = ms_strdup(body); + } + linphone_content_uninit(msg->file_transfer_information); ms_free(msg->file_transfer_information); msg->file_transfer_information = NULL; @@ -365,7 +435,12 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM } else { if (cr->lc->lime == 1) { /* shall we try to encrypt messages? */ linphone_chat_message_ref(msg); /* ref the message or it may be destroyed by callback if the encryption failed */ - sal_message_send(op, identity, cr->peer, "xml/cipher", msg->message, linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr))); + msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml"); + if (strcmp(msg->content_type, "application/vnd.gsma.rcs-ft-http+xml") == 0 ) { /* it's a file transfer, content type shall be set to application/cipher.vnd.gsma.rcs-ft-http+xml*/ + sal_message_send(op, identity, cr->peer, "application/cipher.vnd.gsma.rcs-ft-http+xml", msg->message, linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr))); + } else { + sal_message_send(op, identity, cr->peer, "xml/cipher", msg->message, linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr))); + } } else { if (msg->content_type == NULL) { sal_text_send(op, identity, cr->peer,msg->message); @@ -487,6 +562,15 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag file_url = xmlGetProp(cur, (const xmlChar *)"url"); } + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-key")) { /* there is a key in the message: file has been encrypted */ + /* convert the key from base 64 */ + xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + int keyLength = b64_decode((char *)keyb64, strlen((char *)keyb64), NULL, 0); + msg->file_transfer_information->key = (uint8_t *)malloc(keyLength); + b64_decode((char *)keyb64, strlen((char *)keyb64), msg->file_transfer_information->key, keyLength); + xmlFree(keyb64); + } + cur=cur->next; } xmlFree(typeAttribute); @@ -944,12 +1028,27 @@ const LinphoneContent *linphone_chat_message_get_file_transfer_information(const } static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const void *buffer, size_t size){ - //printf("Receive %ld bytes\n\n%s\n\n", size, (char *)buffer); + /* first call may be with a zero size, ignore it */ + if (size == 0) { + return; + } LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; LinphoneCore *lc = chatMsg->chat_room->lc; - /* call back given by application level */ - if (lc->vtable.file_transfer_received != NULL) { - lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, buffer, size); + + if (chatMsg->file_transfer_information->key != NULL) { /* we have a key, we must decrypt the file */ + /* get data from callback to a plainBuffer */ + char *plainBuffer = (char *)malloc(size); + lime_decryptFile(&(chatMsg->file_transfer_information->cryptoContext), chatMsg->file_transfer_information->key, size, plainBuffer, (char *)buffer); + /* call back given by application level */ + if (lc->vtable.file_transfer_received != NULL) { + lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, plainBuffer, size); + } + free(plainBuffer); + } else { /* regular file, no deciphering */ + /* call back given by application level */ + if (lc->vtable.file_transfer_received != NULL) { + lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, buffer, size); + } } return; @@ -979,6 +1078,10 @@ static void linphone_chat_process_response_from_get_file(void *data, const belle if (code==200) { LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; LinphoneCore *lc = chatMsg->chat_room->lc; + /* if we the file was encrypted, finish the decryption and free context */ + if (chatMsg->file_transfer_information->key) { + lime_decryptFile(&(chatMsg->file_transfer_information->cryptoContext), NULL, 0, NULL, NULL); + } /* file downloaded succesfully, call again the callback with size at zero */ if (lc->vtable.file_transfer_received != NULL) { lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, NULL, 0); diff --git a/coreapi/help/filetransfer.c b/coreapi/help/filetransfer.c index 9bbbcddeb..4af168ee3 100644 --- a/coreapi/help/filetransfer.c +++ b/coreapi/help/filetransfer.c @@ -69,20 +69,19 @@ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *messag /*first chunk, creating file*/ file = open("receive_file.dump",O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); linphone_chat_message_set_user_data(message,(void*)(long)(0x00000000FFFFFFFF&file)); /*store fd for next chunks*/ - } else { - /*next chunk*/ - file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); + } - if (size==0) { + /*next chunk*/ + file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); - printf("File transfert completed\n"); - linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); - linphone_chat_message_destroy(message); - close(file); - running=FALSE; - } else { /* store content on a file*/ - write(file,buff,size); - } + if (size==0) { + printf("File transfert completed\n"); + linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); + linphone_chat_message_destroy(message); + close(file); + running=FALSE; + } else { /* store content on a file*/ + write(file,buff,size); } } @@ -192,9 +191,6 @@ int main(int argc, char *argv[]){ /*now create a chat message with custom content*/ LinphoneChatMessage* chat_message = linphone_chat_room_create_file_transfer_message(chat_room,&content); - if (chat_message == NULL) { - printf("returned message is null\n"); - } /*initiating file transfer*/ linphone_chat_room_send_message2(chat_room, chat_message, linphone_file_transfer_state_changed, NULL); diff --git a/coreapi/info.c b/coreapi/info.c index 2bf2b85ad..4279a963c 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -47,6 +47,14 @@ void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref){ SET_STRING(obj,subtype,ref->subtype); SET_STRING(obj,encoding,ref->encoding); SET_STRING(obj,name,ref->name); + if (obj->key) { + ms_free(obj->key); + obj->key=NULL; + } + if (ref->key) { + obj->key = (unsigned char *)ms_strdup((const char *)ref->key); + } + if (obj->data) { ms_free(obj->data); obj->data=NULL; @@ -65,6 +73,7 @@ void linphone_content_uninit(LinphoneContent * obj){ if (obj->data) ms_free(obj->data); if (obj->encoding) ms_free(obj->encoding); if (obj->name) ms_free(obj->name); + if (obj->key) ms_free(obj->key); } LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref){ @@ -81,6 +90,8 @@ LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const ((char*)obj->data)[ref->size]='\0'; } obj->size=ref->size; + obj->name = NULL; + obj->key = NULL; return obj; } @@ -91,6 +102,8 @@ const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, cons obj->data=(void*)ref->data; obj->encoding=(char*)ref->encoding; obj->size=ref->size; + obj->name = NULL; + obj->key = NULL; return obj; } return NULL; diff --git a/coreapi/lime.c b/coreapi/lime.c index 0e1f90031..3873a33cb 100644 --- a/coreapi/lime.c +++ b/coreapi/lime.c @@ -436,6 +436,56 @@ int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageL return 0; } + +int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) { + gcm_context *gcmContext; + + if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */ + gcmContext = (gcm_context *)malloc(sizeof(gcm_context)); + *cryptoContext = (void *)gcmContext; + gcm_init(gcmContext, POLARSSL_CIPHER_ID_AES, key, 192); + gcm_starts(gcmContext, GCM_ENCRYPT, key+24, 8, NULL, 0); /* key contains 192bits of key || 64 bits of Initialisation Vector */ + } else { /* this is not the first call, get the context */ + gcmContext = (gcm_context *)*cryptoContext; + } + + if (length != 0) { + gcm_update(gcmContext, length, (const unsigned char *)plain, (unsigned char *)cipher); + } else { /* lenght is 0, finish the stream */ + gcm_finish(gcmContext, NULL, 0); /* do not generate tag */ + gcm_free(gcmContext); + free(*cryptoContext); + *cryptoContext = NULL; + } + + return 0; +} + +int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) { + gcm_context *gcmContext; + + if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */ + gcmContext = (gcm_context *)malloc(sizeof(gcm_context)); + *cryptoContext = (void *)gcmContext; + gcm_init(gcmContext, POLARSSL_CIPHER_ID_AES, key, 192); + gcm_starts(gcmContext, GCM_DECRYPT, key+24, 8, NULL, 0); /* key contains 192bits of key || 64 bits of Initialisation Vector */ + } else { /* this is not the first call, get the context */ + gcmContext = (gcm_context *)*cryptoContext; + } + + if (length != 0) { + gcm_update(gcmContext, length, (const unsigned char *)cipher, (unsigned char *)plain); + } else { /* lenght is 0, finish the stream */ + gcm_finish(gcmContext, NULL, 0); /* do not generate tag */ + gcm_free(gcmContext); + free(*cryptoContext); + *cryptoContext = NULL; + } + + return 0; +} + + int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage) { /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */ uint8_t authenticatedData[28]; diff --git a/coreapi/lime.h b/coreapi/lime.h index 455c80c6c..7ccb3740f 100644 --- a/coreapi/lime.h +++ b/coreapi/lime.h @@ -113,6 +113,34 @@ __attribute__ ((visibility ("default"))) int lime_deriveKey(limeKey_t *key); */ __attribute__ ((visibility ("default"))) int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *encryptedMessage); +/** + * @brief Encrypt a file before transfering it to the server, encryption is done in several call, first one will be done with cryptoContext null, last one with length = 0 + * + * @param[in/out] cryptoContext The context used to encrypt the file using AES-GCM. Is created at first call(if null) + * @param[in] key 256 bits : 192 bits of key || 64 bits of Initial Vector + * @param[in] length Length of data to be encrypted, if 0 it will conclude the encryption + * @param[in] plain Plain data to be encrypted (length bytes) + * @param[out] cipher Output to a buffer allocated by caller, at least length bytes available + * + * @return 0 on success, error code otherwise + * + */ +__attribute__ ((visibility ("default"))) int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher); + +/** + * @brief Decrypt a file retrieved from server, decryption is done in several call, first one will be done with cryptoContext null, last one with length = 0 + * + * @param[in/out] cryptoContext The context used to decrypt the file using AES-GCM. Is created at first call(if null) + * @param[in] key 256 bits : 192 bits of key || 64 bits of Initial Vector + * @param[in] length Length of data to be decrypted, if 0 it will conclude the decryption + * @param[out] plain Output to a buffer allocated by caller, at least length bytes available + * @param[in] cipher Cipher text to be decrypted(length bytes) + * + * @return 0 on success, error code otherwise + * + */ +__attribute__ ((visibility ("default"))) int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher); + /** * @brief decrypt and authentify a message with the given key * diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4e7aa6256..55fa9f6a1 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -138,6 +138,8 @@ struct _LinphoneContent{ When provided by callback #LinphoneCoreFileTransferSendCb or #LinphoneCoreFileTransferReceiveCb, it states the total number of bytes of the transfered file*/ char *encoding; /** -ef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.comf6e5c94feabbe348f25a528cc990b7ec0f3390286314eb70cf2a9a852afb2df4bfd9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b771935f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000074000001a21234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.comb438386ce7d91f0c3341315ff58ce14826a119f36d91650ca26fa7fde2f1601225d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000c00000000 +ef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:pauline@sip.example.org6cac6d8e4453ccf70749674c421b7ca434d300ca30265a9a86b2979c32bdd1595b91adffd91fcfa5b9cc6907a7d59bd5c21ffe8d508b4d6c536cb73329c914c35f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000077000001c61234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:pauline@sip.example.org72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a917625d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000f00000000 diff --git a/tester/ZIDCacheBob.xml b/tester/ZIDCacheBob.xml index 23116d8da..31ff1393a 100644 --- a/tester/ZIDCacheBob.xml +++ b/tester/ZIDCacheBob.xml @@ -1,4 +1,4 @@ 005dbe0399643d953a2202dd - ef7692d0792a67491ae2d44e9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.comf6e5c94feabbe348f25a528cc990b7ec0f3390286314eb70cf2a9a852afb2df4bfd9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b771935f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000074000001a2 - 1234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.com123456789012345678901234567890123456765431262068d2df23e8f9b7719325d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000100000000 + ef7692d0792a67491ae2d44e9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:marie@sip.example.org6cac6d8e4453ccf70749674c421b7ca434d300ca30265a9a86b2979c32bdd1595b91adffd91fcfa5b9cc6907a7d59bd5c21ffe8d508b4d6c536cb73329c914c35f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000077000001c6 + 1234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:marie@sip.example.org21397a0d145badd58b3073ba0f537cab1bc97ca7de1f0d2db9a57fc3f63b74b725d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000002500000000 diff --git a/tester/message_tester.c b/tester/message_tester.c index 613fc82c4..ba5272e30 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -62,27 +62,26 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess * */ void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){ int file=-1; + /* first chunk, creating file */ if (!linphone_chat_message_get_user_data(message)) { - /*first chunk, creating file*/ file = open("receive_file.dump",O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); linphone_chat_message_set_user_data(message,(void*)(long)(0x00000000FFFFFFFF&file)); /*store fd for next chunks*/ - } else { - /*next chunk*/ - file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); + } - if (size==0) { /* tranfer complerte */ - linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); - linphone_chat_message_destroy(message); - stats* counters = get_stats(lc); - counters->number_of_LinphoneMessageExtBodyReceived++; - close(file); - } else { /* store content on a file*/ - write(file,buff,size); - } + file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); + + if (size==0) { /* tranfer complete */ + linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); + linphone_chat_message_destroy(message); + stats* counters = get_stats(lc); + counters->number_of_LinphoneMessageExtBodyReceived++; + close(file); + } else { /* store content on a file*/ + write(file,buff,size); } } -static char big_file [128000]; /* a buffer to simulate a big file for the file transfer message test */ +char big_file[128000]; /* a buffer to simulate a big file for the file transfer message test */ /* * function called when the file transfer is initiated. file content should be feed into object LinphoneContent @@ -364,9 +363,13 @@ static void file_transfer_message(void) { int i; /* setting dummy file content to something */ const char* big_file_content="big file"; - for (i=0;ilc, 1); + linphone_core_set_lime(pauline->lc, 1); + + /* set the zid caches files */ + linphone_core_set_zrtp_secrets_file(marie->lc, "ZIDCacheAlice.xml"); + linphone_core_set_zrtp_secrets_file(pauline->lc, "ZIDCacheBob.xml"); + + /* Globally configure an http file transfer server. */ + linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + + /* create a file transfer message */ + LinphoneContent content; + memset(&content,0,sizeof(content)); + content.type="text"; + content.subtype="plain"; + content.size=sizeof(big_file); /*total size to be transfered*/ + content.name = "bigfile.txt"; + LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chat_room, &content); + + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + static void text_message_with_send_error(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -567,7 +619,7 @@ void printHex(char *title, uint8_t *data, uint32_t length) { printf ("\n"); } -static void lime(void) { +static void lime_unit(void) { int retval; /* Load Alice cache file */ FILE *CACHE = fopen("ZIDCacheAlice.xml", "r+"); @@ -599,7 +651,7 @@ static void lime(void) { /* encrypt a message */ uint8_t *multipartMessage = NULL; - retval = lime_createMultipartMessage(cacheBufferAlice, (uint8_t *)"Bonjour les petits lapins,ca va? éh oui oui", (uint8_t *)"pipo1@pipo.com", &multipartMessage); + retval = lime_createMultipartMessage(cacheBufferAlice, (uint8_t *)"Bonjour les petits lapins,ca va? éh oui oui", (uint8_t *)"sip:pauline@sip.example.org", &multipartMessage); printf("create message return %d\n", retval); if (retval == 0) { @@ -720,6 +772,34 @@ static void lime(void) { xmlFreeDoc(cacheBuffer); } +static void lime_text_message(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + /* make sure lime is enabled */ + linphone_core_set_lime(marie->lc, 1); + linphone_core_set_lime(pauline->lc, 1); + + /* set the zid caches files */ + linphone_core_set_zrtp_secrets_file(marie->lc, "ZIDCacheAlice.xml"); + linphone_core_set_zrtp_secrets_file(pauline->lc, "ZIDCacheBob.xml"); + + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + ms_free(to); + + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + /* TODO : check the message arrived correctly deciphered */ + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + #ifdef MSG_STORAGE_ENABLED /* @@ -813,11 +893,13 @@ test_t message_tests[] = { { "Text message with send error", text_message_with_send_error }, { "Text message with external body", text_message_with_external_body }, { "File transfer message", file_transfer_message }, + { "Lime File transfer message", lime_file_transfer_message }, { "Text message denied", text_message_denied }, { "Info message", info_message }, { "Info message with body", info_message_with_body }, { "IsComposing notification", is_composing_notification }, - { "Lime", lime } + { "Lime Unitary", lime_unit }, + { "Lime Text Message", lime_text_message } #ifdef MSG_STORAGE_ENABLED ,{ "Database migration", message_storage_migration } #endif From 421bde2e3715e50ce5b5482a9cc10ae8ae819c47 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 30 Jun 2014 21:19:04 +0200 Subject: [PATCH 11/19] fix filetransfer --- coreapi/help/filetransfer.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/coreapi/help/filetransfer.c b/coreapi/help/filetransfer.c index 552137688..3005fff01 100644 --- a/coreapi/help/filetransfer.c +++ b/coreapi/help/filetransfer.c @@ -73,9 +73,7 @@ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *messag /*next chunk*/ file = (FILE*)linphone_chat_message_get_user_data(message); - /*next chunk*/ - file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); - + if (size) { printf("File transfert completed\n"); linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); linphone_chat_message_destroy(message); From 65984cd5e2c3f4ebd7171946ed45710afaa1c0b1 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Tue, 1 Jul 2014 10:18:47 +0200 Subject: [PATCH 12/19] Fix bug in selection message content type in encrypted mode --- coreapi/chat.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 5172c359e..c0df41464 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -443,8 +443,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM } else { if (cr->lc->lime == 1) { /* shall we try to encrypt messages? */ linphone_chat_message_ref(msg); /* ref the message or it may be destroyed by callback if the encryption failed */ - msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml"); - if (strcmp(msg->content_type, "application/vnd.gsma.rcs-ft-http+xml") == 0 ) { /* it's a file transfer, content type shall be set to application/cipher.vnd.gsma.rcs-ft-http+xml*/ + if ((msg->content_type != NULL) && (strcmp(msg->content_type, "application/vnd.gsma.rcs-ft-http+xml") == 0 )) { /* it's a file transfer, content type shall be set to application/cipher.vnd.gsma.rcs-ft-http+xml*/ sal_message_send(op, identity, cr->peer, "application/cipher.vnd.gsma.rcs-ft-http+xml", msg->message, linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr))); } else { sal_message_send(op, identity, cr->peer, "xml/cipher", msg->message, linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr))); From f6eb21ad82ed36c42c90ef6d651bf19580a1612d Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Sun, 13 Jul 2014 00:02:47 +0200 Subject: [PATCH 13/19] Lime checks the PVS flag in ZRTP cache when getting keys --- coreapi/lime.c | 106 ++++++++++++++++++++++++--------------- coreapi/lime.h | 2 +- tester/ZIDCacheAlice.xml | 2 +- tester/ZIDCacheBob.xml | 4 +- 4 files changed, 70 insertions(+), 44 deletions(-) diff --git a/coreapi/lime.c b/coreapi/lime.c index 3873a33cb..c9f499ede 100644 --- a/coreapi/lime.c +++ b/coreapi/lime.c @@ -159,10 +159,11 @@ int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedK if (matchingURIFlag == 1) { /* we found a match for the URI in this peer node, extract the keys, session Id and index values */ /* 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: 4 nodes*/ + uint8_t itemFound = 0; /* count the item found, we must get all of the requested infos: 5 nodes*/ + uint8_t pvs = 0; peerNodeChildren = cur->xmlChildrenNode; /* reset peerNodeChildren to the first child of node */ - while (peerNodeChildren!=NULL && itemFound<4) { + while (peerNodeChildren!=NULL && itemFound<5) { xmlChar *nodeContent = NULL; if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"ZID")) { nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); @@ -188,13 +189,18 @@ int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedK 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 */ + itemFound++; + } xmlFree(nodeContent); peerNodeChildren = peerNodeChildren->next; } - /* check if we have all the requested information */ - if (itemFound == 4) { + /* 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 *)); @@ -229,13 +235,17 @@ int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) { cur = cur->xmlChildrenNode; } + + /* to check we collect all the information needed from the cache and that pvs(boolean for previously verified Sas) is set in cache */ uint8_t itemFound = 0; - while (cur!=NULL && itemFound<3) { /* loop on all peer nodes */ + uint8_t pvs = 0; + + while (cur!=NULL) { /* 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 */ xmlNodePtr peerNodeChildren = cur->xmlChildrenNode->next; - while (peerNodeChildren != NULL && itemFound<3) { /* look for the tag we want to read */ + while (peerNodeChildren != NULL && itemFound<4) { /* look for the tag we want to read : rcvKey, rcvSId, rcvIndex and pvs*/ xmlChar *nodeContent = NULL; if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvKey")) { nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); @@ -255,17 +265,29 @@ int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) { 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 */ + itemFound++; + } xmlFree(nodeContent); peerNodeChildren = peerNodeChildren->next; } + xmlFree(currentZidHex); + break; /* we parsed the peer node we were looking for, get out of the main while */ } xmlFree(currentZidHex); } cur = cur->next; } - - return 0; + /* if we manage to find the correct key information and that pvs is set to 1, return 0 (success) */ + if ((pvs == 1) && (itemFound == 4)) { + return 0; + } + + /* otherwise, key wasn't found or is invalid */ + return LIME_NO_VALID_KEY_FOUND_FOR_PEER; } int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t role) { @@ -536,7 +558,7 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t if (associatedKeys.associatedZIDNumber == 0) { lime_freeKeys(associatedKeys); - return LIME_NO_KEY_FOUND_FOR_PEER; + return LIME_NO_VALID_KEY_FOUND_FOR_PEER; } /* create an xml doc to hold the multipart message */ @@ -652,38 +674,42 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ /* get from cache the matching key */ retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); - if (retval == 0) { - /* retrieve the portion of message which is encrypted with our key */ - while (cur != NULL) { /* loop on all "msg" node in the message */ - xmlNodePtr msgChildrenNode = cur->xmlChildrenNode; - xmlChar *currentZidHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); /* pZID is the first element of msg */ - if (!xmlStrcmp(currentZidHex, (const xmlChar *)selfZidHex)) { /* we found the msg node we are looking for */ - /* get the index (second node in the msg one) */ - msgChildrenNode = msgChildrenNode->next; - xmlChar *sessionIndexHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); - 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]))); - xmlFree(sessionIndexHex); - /* get the encrypted message */ - msgChildrenNode = msgChildrenNode->next; - /* convert the cipherText from base 64 */ - xmlChar *encryptedMessageb64 = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); - encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), NULL, 0); - encryptedMessage = (uint8_t *)malloc(encryptedMessageLength); - encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), encryptedMessage, encryptedMessageLength); - xmlFree(encryptedMessageb64); - } - - cur = cur->next; - xmlFree(currentZidHex); - } + if (retval != 0) { + xmlFree(peerZidHex); + xmlFreeDoc(xmlEncryptedMessage); + return retval; } + + /* retrieve the portion of message which is encrypted with our key */ + while (cur != NULL) { /* loop on all "msg" node in the message */ + xmlNodePtr msgChildrenNode = cur->xmlChildrenNode; + xmlChar *currentZidHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); /* pZID is the first element of msg */ + if (!xmlStrcmp(currentZidHex, (const xmlChar *)selfZidHex)) { /* we found the msg node we are looking for */ + /* get the index (second node in the msg one) */ + msgChildrenNode = msgChildrenNode->next; + xmlChar *sessionIndexHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); + 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]))); + xmlFree(sessionIndexHex); + /* get the encrypted message */ + msgChildrenNode = msgChildrenNode->next; + /* convert the cipherText from base 64 */ + xmlChar *encryptedMessageb64 = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); + encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), NULL, 0); + encryptedMessage = (uint8_t *)malloc(encryptedMessageLength); + encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), encryptedMessage, encryptedMessageLength); + xmlFree(encryptedMessageb64); + } + + cur = cur->next; + xmlFree(currentZidHex); + } } xmlFree(peerZidHex); diff --git a/coreapi/lime.h b/coreapi/lime.h index 7ccb3740f..dfaf3d866 100644 --- a/coreapi/lime.h +++ b/coreapi/lime.h @@ -5,7 +5,7 @@ #define LIME_UNABLE_TO_DERIVE_KEY 0x1002 #define LIME_UNABLE_TO_ENCRYPT_MESSAGE 0x1004 #define LIME_UNABLE_TO_DECRYPT_MESSAGE 0x1008 -#define LIME_NO_KEY_FOUND_FOR_PEER 0x1010 +#define LIME_NO_VALID_KEY_FOUND_FOR_PEER 0x1010 #define LIME_INVALID_ENCRYPTED_MESSAGE 0x1020 /* this define the maximum key derivation number allowed to get the caches back in sync in case of missed messages */ diff --git a/tester/ZIDCacheAlice.xml b/tester/ZIDCacheAlice.xml index dfef1fe86..86e346b38 100644 --- a/tester/ZIDCacheAlice.xml +++ b/tester/ZIDCacheAlice.xml @@ -1,2 +1,2 @@ -ef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:pauline@sip.example.org6cac6d8e4453ccf70749674c421b7ca434d300ca30265a9a86b2979c32bdd1595b91adffd91fcfa5b9cc6907a7d59bd5c21ffe8d508b4d6c536cb73329c914c35f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000077000001c61234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:pauline@sip.example.org72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a917625d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000f00000000 +ef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:pauline@sip.example.org6cac6d8e4453ccf70749674c421b7ca434d300ca30265a9a86b2979c32bdd15960f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000077000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:pauline@sip.example.org72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a917625d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000f00000000 diff --git a/tester/ZIDCacheBob.xml b/tester/ZIDCacheBob.xml index 31ff1393a..1cd910fb8 100644 --- a/tester/ZIDCacheBob.xml +++ b/tester/ZIDCacheBob.xml @@ -1,4 +1,4 @@ 005dbe0399643d953a2202dd - ef7692d0792a67491ae2d44e9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:marie@sip.example.org6cac6d8e4453ccf70749674c421b7ca434d300ca30265a9a86b2979c32bdd1595b91adffd91fcfa5b9cc6907a7d59bd5c21ffe8d508b4d6c536cb73329c914c35f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000077000001c6 - 1234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:marie@sip.example.org21397a0d145badd58b3073ba0f537cab1bc97ca7de1f0d2db9a57fc3f63b74b725d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000002500000000 + ef7692d0792a67491ae2d44e9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:marie@sip.example.org6cac6d8e4453ccf70749674c421b7ca434d300ca30265a9a86b2979c32bdd15960f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000077000001cf01 + 1234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:marie@sip.example.org81e6e6362c34dc974263d1f77cbb9a8d6d6a718330994379099a8fa19fb12faa25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000002e0000000001 From cb4b534a4d4d68c630d70550ddac081172f1d794 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Sun, 13 Jul 2014 00:31:58 +0200 Subject: [PATCH 14/19] Lime gives more explicit warning messages --- coreapi/bellesip_sal/sal_op_message.c | 4 ++-- coreapi/lime.c | 13 +++++++++++++ coreapi/lime.h | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 3e0100b4c..270bc0561 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -129,7 +129,7 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve free(cacheString); int retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage); if (retval != 0) { - ms_warning("Unable to decrypt message, reason %x", retval); + ms_warning("Unable to decrypt message, reason : %s - op [%p]", lime_error_code_to_string(retval), op); free(decryptedMessage); xmlFreeDoc(cacheXml); resp = belle_sip_response_create_from_request(req,488); @@ -266,7 +266,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co free(cacheString); int retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg, (uint8_t *)peer_uri, &multipartEncryptedMessage); if (retval != 0) { - ms_warning("Unable to encrypt message for %s error %x", peer_uri, retval); + ms_warning("Unable to encrypt message for %s : %s - op [%p]", peer_uri, lime_error_code_to_string(retval), op); xmlFreeDoc(cacheXml); free(multipartEncryptedMessage); sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); diff --git a/coreapi/lime.c b/coreapi/lime.c index c9f499ede..045d4be5d 100644 --- a/coreapi/lime.c +++ b/coreapi/lime.c @@ -755,3 +755,16 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ return 0; } + +char *lime_error_code_to_string(int errorCode) { + switch (errorCode) { + case LIME_INVALID_CACHE: return "Invalid ZRTP cache"; + case LIME_UNABLE_TO_DERIVE_KEY: return "Unable to derive Key"; + 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_INVALID_ENCRYPTED_MESSAGE: return "Invalid encrypted message"; + } + return "Unknow error"; + +} diff --git a/coreapi/lime.h b/coreapi/lime.h index dfaf3d866..861c9acd7 100644 --- a/coreapi/lime.h +++ b/coreapi/lime.h @@ -169,5 +169,24 @@ __attribute__ ((visibility ("default"))) int lime_decryptMessage(limeKey_t *key, * @return 0 on success, error code otherwise */ __attribute__ ((visibility ("default"))) int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t *peerURI, uint8_t **output); + +/** + * @brief decrypt a multipart xml message + * Retrieve in cache the needed key which is then updated. Output buffer is allocated and must be freed by caller + * + * @param[in/out] cacheBuffer The xmlDoc containing current cache, get the key and selfZID from it, updated by this function with derivated keys + * @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 + * + * @return 0 on success, error code otherwise + */ + __attribute__ ((visibility ("default"))) int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output); + +/** + * @brief given a readable version of error code generated by Lime functions + * @param[in] errorCode The error code + * @return a string containing the error description + */ +char *lime_error_code_to_string(int errorCode); #endif /* LIME_H */ From 5ac8a8595d5cfe9fd3bf7a6587cbe79bb9686439 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 25 Sep 2014 18:17:16 +0200 Subject: [PATCH 15/19] fix merge --- coreapi/chat.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 582638210..09bc7df38 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -99,6 +99,7 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_ LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; LinphoneCore *lc = chatMsg->chat_room->lc; char *buf = (char *)buffer; + char *content_type=belle_sip_strdup_printf("%s/%s", chatMsg->file_transfer_information->type, chatMsg->file_transfer_information->subtype); size_t end_of_file=linphone_chat_message_compute_filepart_header_size(chatMsg->file_transfer_information->name, content_type)+chatMsg->file_transfer_information->size; /* if we've not reach the end of file yet, ask for more data*/ @@ -197,14 +198,13 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co msg->http_request=req; /* update the reference to the http request to be able to cancel it during upload */ belle_http_provider_send_request(msg->chat_room->lc->http_provider,req,l); } - if (code == 200 ) { /* file has been uplaoded correctly, get server reply and send it */ const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); /* TODO Check that the transfer has not been cancelled, note this shall be removed once the belle sip API will provide a cancel request as we shall never reach this part if the transfer is actually cancelled */ if (msg->http_request == NULL) { return; - + } /* if we have an encryption key for the file, we must insert it into the message */ if (msg->file_transfer_information->key != NULL) { /* parse the message body */ @@ -243,11 +243,11 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co } else { /* no encryption key, transfer in plain, just copy the message sent by server */ msg->message = ms_strdup(body); } + msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml"); _linphone_chat_room_send_message(msg->chat_room, msg); } } - } @@ -1115,17 +1115,18 @@ static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t /* TODO: while belle sip doesn't implement the cancel http request method, test if a request is still linked to the message before forwarding the data to callback */ if (chatMsg->http_request == NULL) { return; + } if (chatMsg->file_transfer_information->key != NULL) { /* we have a key, we must decrypt the file */ /* get data from callback to a plainBuffer */ char *plainBuffer = (char *)malloc(size); lime_decryptFile(&(chatMsg->file_transfer_information->cryptoContext), chatMsg->file_transfer_information->key, size, plainBuffer, (char *)buffer); /* call back given by application level */ - linphone_core_notify_file_transfer_rec(lc, chatMsg, chatMsg->file_transfer_information, plainBuffer, size); + linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, plainBuffer, size); free(plainBuffer); } else { /* regular file, no deciphering */ /* call back given by application level */ - linphone_core_notify_file_transfer_recd(lc, chatMsg, chatMsg->file_transfer_information, (char *)buffer, size); + linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, (char *)buffer, size); } return; From f942fdeb3b128d08f6f08f07bcec94ce635c5a71 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Sun, 28 Sep 2014 23:02:19 +0200 Subject: [PATCH 16/19] Fix merge and make code C90 compliant --- coreapi/bellesip_sal/sal_op_message.c | 28 ++-- coreapi/chat.c | 44 +++--- coreapi/lime.c | 124 +++++++++------- tester/ZIDCache.xml | 2 +- tester/message_tester.c | 206 ++++++++++++++++---------- 5 files changed, 242 insertions(+), 162 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 270bc0561..182e5268e 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -105,11 +105,11 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve bool_t external_body=FALSE; bool_t cipher_xml=FALSE; bool_t rcs_filetransfer=FALSE; + uint8_t *decryptedMessage = NULL; from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); /* check if we have a xml/cipher message to be decrypted */ - uint8_t *decryptedMessage = NULL; if (content_type && (cipher_xml=is_cipher_xml(content_type))) { /* access the zrtp cache to get keys needed to decipher the message */ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); @@ -117,17 +117,22 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve if (CACHEFD == NULL) { ms_warning("Unable to access ZRTP ZID cache to decrypt message"); } else { + int cacheSize; + uint8_t *cacheString; + int retval; + xmlDocPtr cacheXml; + fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ - int cacheSize = ftell(CACHEFD); /* Get file length */ + cacheSize = ftell(CACHEFD); /* Get file length */ rewind(CACHEFD); /* Back to start of file */ - uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ + cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ fread(cacheString, 1, cacheSize, CACHEFD); cacheString[cacheSize] = '\0'; cacheSize += 1; fclose(CACHEFD); - xmlDocPtr cacheXml = xmlParseDoc(cacheString); + cacheXml = xmlParseDoc(cacheString); free(cacheString); - int retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage); + retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage); if (retval != 0) { ms_warning("Unable to decrypt message, reason : %s - op [%p]", lime_error_code_to_string(retval), op); free(decryptedMessage); @@ -254,17 +259,22 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); return 0; } else { + int cacheSize; + uint8_t *cacheString; + xmlDocPtr cacheXml; + int retval; + fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ - int cacheSize = ftell(CACHEFD); /* Get file length */ + cacheSize = ftell(CACHEFD); /* Get file length */ rewind(CACHEFD); /* Back to start of file */ - uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ + cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ fread(cacheString, 1, cacheSize, CACHEFD); cacheString[cacheSize] = '\0'; cacheSize += 1; fclose(CACHEFD); - xmlDocPtr cacheXml = xmlParseDoc(cacheString); + cacheXml = xmlParseDoc(cacheString); free(cacheString); - int retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg, (uint8_t *)peer_uri, &multipartEncryptedMessage); + retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg, (uint8_t *)peer_uri, &multipartEncryptedMessage); if (retval != 0) { ms_warning("Unable to encrypt message for %s : %s - op [%p]", peer_uri, lime_error_code_to_string(retval), op); xmlFreeDoc(cacheXml); diff --git a/coreapi/chat.c b/coreapi/chat.c index 09bc7df38..469e53e63 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -99,35 +99,30 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_ LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; LinphoneCore *lc = chatMsg->chat_room->lc; char *buf = (char *)buffer; - char *content_type=belle_sip_strdup_printf("%s/%s", chatMsg->file_transfer_information->type, chatMsg->file_transfer_information->subtype); - size_t end_of_file=linphone_chat_message_compute_filepart_header_size(chatMsg->file_transfer_information->name, content_type)+chatMsg->file_transfer_information->size; /* if we've not reach the end of file yet, ask for more data*/ if (offsetfile_transfer_information->size){ if (chatMsg->file_transfer_information->key != NULL) { /* if we have a key to cipher the message, use it! */ + char *plainBuffer; /* get data from callback to a plainBuffer */ /* if this chunk is not the last one, the lenght must be a multiple of block cipher size(16 bytes)*/ - if (offset+*sizefile_transfer_information->size) { *size -=(*size%16); } - char *plainBuffer = (char *)malloc(*size); - linphone_core_notify_file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buf, size); + plainBuffer = (char *)malloc(*size); + linphone_core_notify_file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, plainBuffer, size); lime_encryptFile(&(chatMsg->file_transfer_information->cryptoContext), chatMsg->file_transfer_information->key, *size, plainBuffer, (char*)buffer); free(plainBuffer); + /* check if we reach the end of file */ + if (offset+*size>=chatMsg->file_transfer_information->size) { + /* conclude file ciphering by calling it context with a zero size */ + lime_encryptFile(&(chatMsg->file_transfer_information->cryptoContext), NULL, 0, NULL, NULL); + } } else { /* get data from call back directly to the output buffer */ linphone_core_notify_file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buf, size); } - /* DEBUG DEBUG : THIS SHALL NEVER HAPPEND */ - if (*size == 0) { - exit(1); - } - }else{ - /* conclude the file ciphering if needed */ - if (chatMsg->file_transfer_information->key != NULL) { - lime_encryptFile(&(chatMsg->file_transfer_information->cryptoContext), NULL, 0, NULL, NULL); - } } return BELLE_SIP_CONTINUE; @@ -148,12 +143,6 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co if (event->response){ int code=belle_http_response_get_status_code(event->response); if (code == 204) { /* this is the reply to the first post to the server - an empty message */ - /* shall we encrypt the file */ - if (msg->chat_room->lc->lime == 1) { - /* generate a random 192 bits key + 64 bits of initial vector and store it into the file_transfer_information->key field of the message */ - msg->file_transfer_information->key = (unsigned char *)malloc(FILE_TRANSFER_KEY_SIZE); - sal_get_random_bytes(msg->file_transfer_information->key, FILE_TRANSFER_KEY_SIZE); - } /* start uploading the file */ belle_http_request_listener_callbacks_t cbs={0}; belle_http_request_listener_t *l; @@ -165,6 +154,13 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co char *first_part_header; belle_sip_user_body_handler_t *first_part_bh; + /* shall we encrypt the file */ + if (msg->chat_room->lc->lime == 1) { + /* generate a random 192 bits key + 64 bits of initial vector and store it into the file_transfer_information->key field of the message */ + msg->file_transfer_information->key = (unsigned char *)malloc(FILE_TRANSFER_KEY_SIZE); + sal_get_random_bytes(msg->file_transfer_information->key, FILE_TRANSFER_KEY_SIZE); + } + /* temporary storage for the Content-disposition header value */ first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", msg->file_transfer_information->name); @@ -220,6 +216,8 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co /* convert key to base64 */ int b64Size = b64_encode(NULL, FILE_TRANSFER_KEY_SIZE, NULL, 0); char *keyb64 = (char *)malloc(b64Size+1); + int xmlStringLength; + b64Size = b64_encode(msg->file_transfer_information->key, FILE_TRANSFER_KEY_SIZE, keyb64, b64Size); keyb64[b64Size] = '\0'; /* libxml need a null terminated string */ @@ -228,7 +226,6 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co xmlFree(typeAttribute); /* dump the xml into msg->message */ - int xmlStringLength; xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, "UTF-8", 0); break; @@ -1106,12 +1103,13 @@ const LinphoneContent *linphone_chat_message_get_file_transfer_information(const } static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const uint8_t *buffer, size_t size){ + LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; + LinphoneCore *lc = chatMsg->chat_room->lc; + /* first call may be with a zero size, ignore it */ if (size == 0) { return; } - LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; - LinphoneCore *lc = chatMsg->chat_room->lc; /* TODO: while belle sip doesn't implement the cancel http request method, test if a request is still linked to the message before forwarding the data to callback */ if (chatMsg->http_request == NULL) { return; diff --git a/coreapi/lime.c b/coreapi/lime.c index 045d4be5d..aef48ce93 100644 --- a/coreapi/lime.c +++ b/coreapi/lime.c @@ -90,17 +90,20 @@ void lime_int8ToStr(uint8_t *outputString, uint8_t *inputBytes, uint16_t inputBy int lime_getSelfZid(xmlDocPtr cacheBuffer, uint8_t selfZid[25]) { + xmlNodePtr cur; + xmlChar *selfZidHex; + if (cacheBuffer == NULL ) { return LIME_INVALID_CACHE; } - xmlNodePtr cur = xmlDocGetRootElement(cacheBuffer); + cur = xmlDocGetRootElement(cacheBuffer); /* if we found a root element, parse its children node */ if (cur!=NULL) { cur = cur->xmlChildrenNode; } - xmlChar *selfZidHex = NULL; + selfZidHex = NULL; while (cur!=NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *)"selfZID"))){ /* self ZID found, extract it */ selfZidHex = xmlNodeListGetString(cacheBuffer, cur->xmlChildrenNode, 1); @@ -122,6 +125,7 @@ int lime_getSelfZid(xmlDocPtr cacheBuffer, uint8_t selfZid[25]) { } int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedKeys) { + xmlNodePtr cur; /* parse the file to get all peer matching the sipURI given in associatedKeys*/ if (cacheBuffer == NULL ) { /* there is no cache return error */ @@ -132,7 +136,7 @@ int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedK associatedKeys->associatedZIDNumber = 0; associatedKeys->peerKeys = NULL; - xmlNodePtr cur = xmlDocGetRootElement(cacheBuffer); + cur = xmlDocGetRootElement(cacheBuffer); /* if we found a root element, parse its children node */ if (cur!=NULL) { @@ -141,8 +145,8 @@ int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedK while (cur!=NULL) { /* loop on all peer nodes */ uint8_t matchingURIFlag = 0; /* this flag is set to one if we found the requested sipURI in the current peer node */ if ((!xmlStrcmp(cur->name, (const xmlChar *)"peer"))) { /* found a peer node, check if there is a matching sipURI node in it */ - matchingURIFlag = 0; xmlNodePtr peerNodeChildren = cur->xmlChildrenNode; + matchingURIFlag = 0; /* loop on children nodes until the end or we found the matching sipURI */ while (peerNodeChildren!=NULL && matchingURIFlag==0) { @@ -182,8 +186,8 @@ int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedK itemFound++; } if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndIndex")) { - nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); 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); /* convert it back to a uint32_t (MSByte first)*/ currentPeerKeys->sessionIndex = sessionIndexBuffer[3] + (sessionIndexBuffer[2]<<8) + (sessionIndexBuffer[1]<<16) + (sessionIndexBuffer[0]<<24); @@ -219,16 +223,21 @@ int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedK } int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) { + uint8_t peerZidHex[25]; + /* to check we collect all the information needed from the cache and that pvs(boolean for previously verified Sas) is set in cache */ + uint8_t itemFound = 0; + uint8_t pvs = 0; + xmlNodePtr cur; + if (cacheBuffer == NULL ) { /* there is no cache return error */ return LIME_INVALID_CACHE; } /* get the given ZID into hex format */ - uint8_t peerZidHex[25]; lime_int8ToStr(peerZidHex, associatedKey->peerZID, 12); peerZidHex[24]='\0'; /* must be a null terminated string */ - xmlNodePtr cur = xmlDocGetRootElement(cacheBuffer); + cur = xmlDocGetRootElement(cacheBuffer); /* if we found a root element, parse its children node */ if (cur!=NULL) { @@ -236,10 +245,6 @@ int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) { } - /* to check we collect all the information needed from the cache and that pvs(boolean for previously verified Sas) is set in cache */ - uint8_t itemFound = 0; - uint8_t pvs = 0; - while (cur!=NULL) { /* 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 */ @@ -258,8 +263,8 @@ int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) { itemFound++; } if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvIndex")) { - nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); 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); /* convert it back to a uint32_t (MSByte first)*/ associatedKey->sessionIndex = sessionIndexBuffer[3] + (sessionIndexBuffer[2]<<8) + (sessionIndexBuffer[1]<<16) + (sessionIndexBuffer[0]<<24); @@ -291,16 +296,22 @@ int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) { } int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t role) { + 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 itemFound = 0; + if (cacheBuffer == NULL ) { /* there is no cache return error */ return LIME_INVALID_CACHE; } /* get the given ZID into hex format */ - uint8_t peerZidHex[25]; lime_int8ToStr(peerZidHex, associatedKey->peerZID, 12); peerZidHex[24]='\0'; /* must be a null terminated string */ - xmlNodePtr cur = xmlDocGetRootElement(cacheBuffer); + cur = xmlDocGetRootElement(cacheBuffer); /* if we found a root element, parse its children node */ if (cur!=NULL) { @@ -309,13 +320,10 @@ int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t r } /* convert the given tag content to null terminated Hexadecimal strings */ - uint8_t keyHex[65]; /* key is 32 bytes long -> 64 bytes string + null termination */ lime_int8ToStr(keyHex, associatedKey->key, 32); keyHex[64] = '\0'; - uint8_t sessionIdHex[65]; /* sessionId is 32 bytes long -> 64 bytes string + null termination */ lime_int8ToStr(sessionIdHex, associatedKey->sessionId, 32); sessionIdHex[64] = '\0'; - uint8_t sessionIndexHex[9]; /* sessionInedx is an uint32_t : 4 bytes long -> 8 bytes string + null termination */ 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)); @@ -326,7 +334,6 @@ int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t r sessionIndexHex[7] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex)&0x0F)); sessionIndexHex[8] = '\0'; - uint8_t itemFound = 0; while (cur!=NULL && itemFound<3) { /* 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 */ @@ -373,6 +380,9 @@ int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t r } int lime_deriveKey(limeKey_t *key) { + uint8_t inputData[55]; + uint8_t derivedKey[32]; + if (key == NULL) { return LIME_UNABLE_TO_DERIVE_KEY; } @@ -383,7 +393,6 @@ int lime_deriveKey(limeKey_t *key) { /* Derivation is made derived Key = HMAC_SHA256(Key, 0x0000001||"MessageKey"||0x00||SessionId||SessionIndex||0x00000100)*/ /* total data to be hashed is 55 bytes : 4 + 10 + 1 + 32 + 4 + 4 */ - uint8_t inputData[55]; inputData[0] = 0x00; inputData[1] = 0x00; inputData[2] = 0x00; @@ -406,7 +415,6 @@ int lime_deriveKey(limeKey_t *key) { inputData[54] = 0x00; /* derive the key in a temp buffer */ - uint8_t derivedKey[32]; #if POLARSSL_VERSION_NUMBER >= 0x01030000 /* for Polarssl version 1.3 */ sha256_hmac(key->key, 32, inputData, 55, derivedKey, 0); /* last param to zero to select SHA256 and not SHA224 */ #else /* for Polarssl version 1.2 */ @@ -439,8 +447,9 @@ void lime_freeKeys(limeURIKeys_t associatedKeys) { } int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *encryptedMessage) { - /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */ uint8_t authenticatedData[28]; + gcm_context gcmContext; + /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */ memcpy(authenticatedData, selfZID, 12); memcpy(authenticatedData+12, key->peerZID, 12); authenticatedData[24] = (uint8_t)((key->sessionIndex>>24)&0x000000FF); @@ -450,7 +459,6 @@ int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageL /* AES-GCM : key is 192 bits long, Init Vector 64 bits. 256 bits key given is AES key||IV */ /* tag is 16 bytes long and is set in the 16 first bytes of the encrypted message */ - gcm_context gcmContext; gcm_init(&gcmContext, POLARSSL_CIPHER_ID_AES, key->key, 192); gcm_crypt_and_tag(&gcmContext, GCM_ENCRYPT, messageLength, key->key+24, 8, authenticatedData, 28, plainMessage, encryptedMessage+16, 16, encryptedMessage); gcm_free(&gcmContext); @@ -458,7 +466,6 @@ int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageL return 0; } - int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) { gcm_context *gcmContext; @@ -509,8 +516,11 @@ int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, ch int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage) { - /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */ uint8_t authenticatedData[28]; + gcm_context gcmContext; + int retval; + + /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */ memcpy(authenticatedData, key->peerZID, 12); memcpy(authenticatedData+12, selfZID, 12); authenticatedData[24] = (uint8_t)((key->sessionIndex>>24)&0x000000FF); @@ -520,10 +530,9 @@ int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t mess /* AES-GCM : key is 192 bits long, Init Vector 64 bits. 256 bits key given is AES key||IV */ /* tag is 16 bytes long and is the 16 first bytes of the encrypted message */ - gcm_context gcmContext; gcm_init(&gcmContext, POLARSSL_CIPHER_ID_AES, key->key, 192); /* messageLength-16 is the length of encrypted data, messageLength include the 16 bytes tag included at the begining of encryptedMessage */ - int retval = gcm_auth_decrypt(&gcmContext, messageLength-16, key->key+24, 8, authenticatedData, 28, encryptedMessage, 16, encryptedMessage+16, plainMessage); + retval = gcm_auth_decrypt(&gcmContext, messageLength-16, key->key+24, 8, authenticatedData, 28, encryptedMessage, 16, encryptedMessage+16, plainMessage); gcm_free(&gcmContext); /* add the null termination char */ plainMessage[messageLength-16] = '\0'; @@ -532,20 +541,25 @@ int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t mess } int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t *peerURI, uint8_t **output) { - /* retrieve selfZIDHex from cache(return a 24 char hexa string + null termination) */ uint8_t selfZidHex[25]; + uint8_t selfZid[12]; /* same data but in byte buffer */ + uint32_t encryptedMessageLength; + limeURIKeys_t associatedKeys; + xmlDocPtr xmlOutputMessage; + xmlNodePtr rootNode; + int i; + int xmlStringLength; + + /* retrieve selfZIDHex from cache(return a 24 char hexa string + null termination) */ if (lime_getSelfZid(cacheBuffer, selfZidHex) != 0) { return LIME_UNABLE_TO_ENCRYPT_MESSAGE; } - uint8_t selfZid[12]; /* same data but in byte buffer */ lime_strToUint8(selfZid, selfZidHex, 24); /* encrypted message length is plaintext + 16 for tag */ - uint32_t encryptedMessageLength = strlen((char *)message) + 16; - + encryptedMessageLength = strlen((char *)message) + 16; /* retrieve keys associated to the peer URI */ - limeURIKeys_t associatedKeys; associatedKeys.peerURI = (uint8_t *)malloc(strlen((char *)peerURI)+1); strcpy((char *)(associatedKeys.peerURI), (char *)peerURI); associatedKeys.associatedZIDNumber = 0; @@ -562,16 +576,21 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t } /* create an xml doc to hold the multipart message */ - xmlDocPtr xmlOutputMessage = xmlNewDoc((const xmlChar *)"1.0"); + xmlOutputMessage = xmlNewDoc((const xmlChar *)"1.0"); /* root tag is "doc" */ - xmlNodePtr rootNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"doc", NULL); + rootNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"doc", NULL); xmlDocSetRootElement(xmlOutputMessage, rootNode); /* add the self ZID child */ xmlNewTextChild(rootNode, NULL, (const xmlChar *)"ZID", selfZidHex); /* loop on all keys found */ - int i; for (i=0; isession index * ciphertext * */ - xmlNodePtr msgNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"msg", NULL); - uint8_t peerZidHex[25]; + msgNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"msg", NULL); lime_int8ToStr(peerZidHex, currentKey->peerZID, 12); peerZidHex[24] = '\0'; - uint8_t sessionIndexHex[9]; 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)); @@ -602,8 +619,8 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t xmlNewTextChild(msgNode, NULL, (const xmlChar *)"index", sessionIndexHex); /* convert the cipherText to base 64 */ - int b64Size = b64_encode(NULL, encryptedMessageLength, NULL, 0); - char *encryptedMessageb64 = (char *)malloc(b64Size+1); + b64Size = b64_encode(NULL, encryptedMessageLength, NULL, 0); + encryptedMessageb64 = (char *)malloc(b64Size+1); b64Size = b64_encode(encryptedMessage, encryptedMessageLength, encryptedMessageb64, b64Size); encryptedMessageb64[b64Size] = '\0'; /* libxml need a null terminated string */ xmlNewTextChild(msgNode, NULL, (const xmlChar *)"text", (const xmlChar *)encryptedMessageb64); @@ -619,7 +636,6 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t } /* dump the whole message doc into the output */ - int xmlStringLength; xmlDocDumpFormatMemoryEnc(xmlOutputMessage, output, &xmlStringLength, "UTF-8", 0); xmlFreeDoc(xmlOutputMessage); @@ -630,16 +646,23 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output) { int retval; + uint8_t selfZidHex[25]; + uint8_t selfZid[12]; /* same data but in byte buffer */ + limeKey_t associatedKey; + xmlChar *peerZidHex = NULL; + xmlNodePtr cur; + uint8_t *encryptedMessage = NULL; + uint32_t encryptedMessageLength = 0; + uint32_t usedSessionIndex = 0; + xmlDocPtr xmlEncryptedMessage; if (cacheBuffer == NULL) { return LIME_INVALID_CACHE; } /* retrieve selfZIDHex from cache(return a 24 char hexa string + null termination) */ - uint8_t selfZidHex[25]; if (lime_getSelfZid(cacheBuffer, selfZidHex) != 0) { return LIME_UNABLE_TO_DECRYPT_MESSAGE; } - uint8_t selfZid[12]; /* same data but in byte buffer */ lime_strToUint8(selfZid, selfZidHex, 24); /* parse the message into an xml doc */ @@ -647,15 +670,13 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ if (memcmp(message, "", 38) != 0 ) { return LIME_INVALID_ENCRYPTED_MESSAGE; } - xmlDocPtr xmlEncryptedMessage = xmlParseDoc((const xmlChar *)message); + xmlEncryptedMessage = xmlParseDoc((const xmlChar *)message); if (xmlEncryptedMessage == NULL) { return LIME_INVALID_ENCRYPTED_MESSAGE; } /* retrieve the sender ZID which is the first child of root */ - limeKey_t associatedKey; - xmlChar *peerZidHex = NULL; - xmlNodePtr cur = xmlDocGetRootElement(xmlEncryptedMessage); + cur = xmlDocGetRootElement(xmlEncryptedMessage); if (cur != NULL) { cur = cur->xmlChildrenNode; if ((!xmlStrcmp(cur->name, (const xmlChar *)"ZID"))){ /* sender ZID found, extract it */ @@ -666,10 +687,6 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ } } - uint8_t *encryptedMessage = NULL; - uint32_t encryptedMessageLength = 0; - uint32_t usedSessionIndex = 0; - if (peerZidHex != NULL) { /* get from cache the matching key */ retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); @@ -686,8 +703,11 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ xmlChar *currentZidHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); /* pZID is the first element of msg */ if (!xmlStrcmp(currentZidHex, (const xmlChar *)selfZidHex)) { /* we found the msg node we are looking for */ /* get the index (second node in the msg one) */ + xmlChar *sessionIndexHex; + xmlChar *encryptedMessageb64; + msgChildrenNode = msgChildrenNode->next; - xmlChar *sessionIndexHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); + sessionIndexHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); usedSessionIndex = (((uint32_t)lime_charToByte(sessionIndexHex[0]))<<28) | (((uint32_t)lime_charToByte(sessionIndexHex[1]))<<24) | (((uint32_t)lime_charToByte(sessionIndexHex[2]))<<20) @@ -700,7 +720,7 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ /* get the encrypted message */ msgChildrenNode = msgChildrenNode->next; /* convert the cipherText from base 64 */ - xmlChar *encryptedMessageb64 = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); + encryptedMessageb64 = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), NULL, 0); encryptedMessage = (uint8_t *)malloc(encryptedMessageLength); encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), encryptedMessage, encryptedMessageLength); diff --git a/tester/ZIDCache.xml b/tester/ZIDCache.xml index 1f0fcb1a3..0881ae45d 100644 --- a/tester/ZIDCache.xml +++ b/tester/ZIDCache.xml @@ -1,2 +1,2 @@ -ef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.com963c57bb28e62068d2df23e8f9b771932d3c57bb28e62068d2df23e8f9b77193e9d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b771935f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193e6ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000069000001cc1234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.com123456789012345678901234567890123456765431262068d2df23e8f9b7719325d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000100000000 +ef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.com963c57bb28e62068d2df23e8f9b771932d3c57bb28e62068d2df23e8f9b77193fcd9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b771935f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193f9ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000069000001df011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.com123456789012345678901234567890123456765431262068d2df23e8f9b7719325d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193000000010000000001 diff --git a/tester/message_tester.c b/tester/message_tester.c index ef5f819b5..058823403 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -74,15 +74,15 @@ void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, cons } else { /*next chunk*/ file = (FILE*)linphone_chat_message_get_user_data(message); + } - if (size==0) { /* tranfer complete */ - stats* counters = get_stats(lc); - counters->number_of_LinphoneMessageExtBodyReceived++; - fclose(file); - } else { /* store content on a file*/ - if (fwrite(buff,size,1,file)==-1){ - ms_error("file_transfer_received(): write() failed: %s",strerror(errno)); - } + if (size==0) { /* tranfer complete */ + stats* counters = get_stats(lc); + counters->number_of_LinphoneMessageExtBodyReceived++; + fclose(file); + } else { /* store content on a file*/ + if (fwrite(buff,size,1,file)==-1){ + ms_error("file_transfer_received(): write() failed: %s",strerror(errno)); } } } @@ -167,13 +167,15 @@ void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,Linph static void text_message(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + char* to; + LinphoneChatRoom* chat_room; /* make sure lime is not enabled */ linphone_core_set_lime(marie->lc, 0); linphone_core_set_lime(pauline->lc, 0); - char* to = linphone_address_as_string(marie->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); ms_free(to); { int dummy=0; @@ -269,6 +271,10 @@ static void text_message_with_credential_from_auth_cb(void) { } static void text_message_with_privacy(void) { + char *to; + LinphoneChatRoom* chat_room; + + LinphoneProxyConfig* pauline_proxy; LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -276,9 +282,8 @@ static void text_message_with_privacy(void) { linphone_core_set_lime(marie->lc, 0); linphone_core_set_lime(pauline->lc, 0); - LinphoneProxyConfig* pauline_proxy; - char* to = linphone_address_as_string(marie->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); ms_free(to); /*test proxy config privacy*/ @@ -352,18 +357,19 @@ static void text_message_compatibility_mode(void) { static void text_message_with_ack(void) { int leaked_objects; int begin; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + belle_sip_object_enable_leak_detector(TRUE); begin=belle_sip_object_get_object_count(); - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new( "pauline_rc"); /* make sure lime is not enabled */ linphone_core_set_lime(marie->lc, 0); linphone_core_set_lime(pauline->lc, 0); { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); char* to = linphone_address_as_string(marie->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); @@ -388,6 +394,10 @@ static void text_message_with_ack(void) { } static void text_message_with_external_body(void) { + char* to; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -395,9 +405,9 @@ static void text_message_with_external_body(void) { linphone_core_set_lime(marie->lc, 0); linphone_core_set_lime(pauline->lc, 0); - char* to = linphone_address_as_string(marie->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); - LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); + message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); linphone_chat_message_set_external_body_url(message,message_external_body_url="http://www.linphone.org"); { int dummy=0; @@ -424,37 +434,35 @@ static void text_message_with_external_body(void) { } static void file_transfer_message(void) { - int i; - LinphoneCoreManager *marie, *pauline; - LinphoneChatRoom *chat_room; + int i; + char* to; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; LinphoneContent content; - LinphoneChatMessage *message; - /* setting dummy file content to something */ - const char* big_file_content="big file"; - for (i=0;i<=sizeof(big_file)-strlen(big_file_content);i+=strlen(big_file_content)) - memcpy(big_file+i, big_file_content, strlen(big_file_content)); - - if (ilc, 0); linphone_core_set_lime(pauline->lc, 0); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + for (i=0;ilc,"https://www.linphone.org:444/lft.php"); /* create a chatroom on pauline's side */ - char* to = linphone_address_as_string(marie->identity); + to = linphone_address_as_string(marie->identity); chat_room = linphone_core_create_chat_room(pauline->lc,to); - + ms_free(to); /* create a file transfer message */ memset(&content,0,sizeof(content)); content.type="text"; @@ -462,12 +470,21 @@ static void file_transfer_message(void) { content.size=sizeof(big_file); /*total size to be transfered*/ content.name = "bigfile.txt"; message = linphone_chat_room_create_file_transfer_message(chat_room, &content); - + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1)); + if (marie->stat.last_received_chat_message ) { + linphone_chat_message_start_file_download(marie->stat.last_received_chat_message, liblinphone_tester_chat_message_state_change); + } CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); linphone_core_manager_destroy(marie); @@ -545,6 +562,10 @@ static void file_transfer_message_io_error_upload(void) { const char* big_file_content="big file"; /* setting dummy file content to something */ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + /* make sure lime is not enabled */ + linphone_core_set_lime(marie->lc, 0); + linphone_core_set_lime(pauline->lc, 0); + reset_counters(&marie->stat); reset_counters(&pauline->stat); @@ -606,6 +627,10 @@ static void file_transfer_message_io_error_download(void) { const char* big_file_content="big file"; /* setting dummy file content to something */ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + /* make sure lime is not enabled */ + linphone_core_set_lime(marie->lc, 0); + linphone_core_set_lime(pauline->lc, 0); + reset_counters(&marie->stat); reset_counters(&pauline->stat); @@ -670,6 +695,10 @@ static void file_transfer_message_upload_cancelled(void) { const char* big_file_content="big file"; /* setting dummy file content to something */ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + /* make sure lime is not enabled */ + linphone_core_set_lime(marie->lc, 0); + linphone_core_set_lime(pauline->lc, 0); + reset_counters(&marie->stat); reset_counters(&pauline->stat); @@ -725,6 +754,10 @@ static void file_transfer_message_download_cancelled(void) { const char* big_file_content="big file"; /* setting dummy file content to something */ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + /* make sure lime is not enabled */ + linphone_core_set_lime(marie->lc, 0); + linphone_core_set_lime(pauline->lc, 0); + reset_counters(&marie->stat); reset_counters(&pauline->stat); @@ -781,6 +814,10 @@ static void file_transfer_message_download_cancelled(void) { } static void text_message_with_send_error(void) { + char* to; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -788,9 +825,9 @@ static void text_message_with_send_error(void) { linphone_core_set_lime(marie->lc, 0); linphone_core_set_lime(pauline->lc, 0); - char* to = linphone_address_as_string(pauline->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); - LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + to = linphone_address_as_string(pauline->identity); + chat_room = linphone_core_create_chat_room(marie->lc,to); + message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); reset_counters(&marie->stat); reset_counters(&pauline->stat); @@ -822,6 +859,10 @@ static void text_message_with_send_error(void) { } static void text_message_denied(void) { + char* to; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -829,9 +870,9 @@ static void text_message_denied(void) { linphone_core_set_lime(marie->lc, 0); linphone_core_set_lime(pauline->lc, 0); - char* to = linphone_address_as_string(pauline->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); - LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + to = linphone_address_as_string(pauline->identity); + chat_room = linphone_core_create_chat_room(marie->lc,to); + message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); /*pauline doesn't want to be disturbed*/ linphone_core_disable_chat(pauline->lc,LinphoneReasonDoNotDisturb); @@ -865,6 +906,10 @@ void info_message_received(LinphoneCore *lc, LinphoneCall* call, const LinphoneI static void info_message_with_args(bool_t with_content) { + LinphoneInfoMessage *info; + const LinphoneContent *content; + const char *hvalue; + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -872,10 +917,6 @@ static void info_message_with_args(bool_t with_content) { linphone_core_set_lime(marie->lc, 0); linphone_core_set_lime(pauline->lc, 0); - LinphoneInfoMessage *info; - const LinphoneContent *content; - const char *hvalue; - CU_ASSERT_TRUE(call(pauline,marie)); info=linphone_core_create_info_message(marie->lc); @@ -932,6 +973,10 @@ static void info_message_with_body(){ } static void is_composing_notification(void) { + char* to; + LinphoneChatRoom* chat_room; + int dummy = 0; + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -939,9 +984,8 @@ static void is_composing_notification(void) { linphone_core_set_lime(marie->lc, 0); linphone_core_set_lime(pauline->lc, 0); - char* to = linphone_address_as_string(marie->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc, to); - int dummy = 0; + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc, to); ms_free(to); { @@ -961,8 +1005,8 @@ static void is_composing_notification(void) { } void printHex(char *title, uint8_t *data, uint32_t length) { - printf ("%s : ", title); int i; + printf ("%s : ", title); for (i=0; ipeerZID, 12); printHex("key", associatedKeys.peerKeys[i]->key, 32); @@ -1071,8 +1127,6 @@ static void lime_unit(void) { } /* get data from cache : receiver */ - limeKey_t associatedKey; - uint8_t targetZID[12] = {0x00, 0x5d, 0xbe, 0x03, 0x99, 0x64, 0x3d, 0x95, 0x3a, 0x22, 0x02, 0xdd}; memcpy(associatedKey.peerZID, targetZID, 12); retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); printf("getCachedKey by ZID return %d\n", retval); @@ -1082,13 +1136,9 @@ static void lime_unit(void) { printf("session index %d\n", associatedKey.sessionIndex); /* encrypt/decrypt a message */ - uint8_t senderZID[12] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0}; - uint8_t encryptedMessage[48]; - uint8_t plainMessage[48]; lime_encryptMessage(associatedKeys.peerKeys[0], (uint8_t *)"bla Bla bla b! Pipo", 20, senderZID, encryptedMessage); printHex("Ciphered", encryptedMessage, 32); /* invert sender and receiverZID to decrypt/authenticate */ - uint8_t receiverZID[12]; memcpy(receiverZID, associatedKeys.peerKeys[0]->peerZID, 12); memcpy(associatedKeys.peerKeys[0]->peerZID, senderZID, 12); retval = lime_decryptMessage(associatedKeys.peerKeys[0], encryptedMessage, 36, receiverZID, plainMessage); @@ -1123,6 +1173,8 @@ static void lime_unit(void) { } static void lime_text_message(void) { + char* to; + LinphoneChatRoom* chat_room; LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -1134,8 +1186,8 @@ static void lime_text_message(void) { linphone_core_set_zrtp_secrets_file(marie->lc, "ZIDCacheAlice.xml"); linphone_core_set_zrtp_secrets_file(pauline->lc, "ZIDCacheBob.xml"); - char* to = linphone_address_as_string(marie->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); ms_free(to); linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); @@ -1277,6 +1329,7 @@ static void history_messages_count() { #endif test_t message_tests[] = { + { "Lime Text Message", lime_text_message }, { "Text message", text_message }, { "Text message within call's dialog", text_message_within_dialog}, { "Text message with credentials from auth info cb", text_message_with_credential_from_auth_cb}, @@ -1295,8 +1348,7 @@ test_t message_tests[] = { { "Info message", info_message }, { "Info message with body", info_message_with_body }, { "IsComposing notification", is_composing_notification }, - { "Lime Unitary", lime_unit }, - { "Lime Text Message", lime_text_message } + { "Lime Unitary", lime_unit } #ifdef MSG_STORAGE_ENABLED ,{ "Database migration", message_storage_migration } ,{ "History count", history_messages_count } From 959cbc5ab80c23af30cbc827b2814fbd5ce65966 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Tue, 30 Sep 2014 22:43:51 +0200 Subject: [PATCH 17/19] File transfer: mask the filename using a generic one when LIME is on - filename is not sent to the server who stores the encrypted file but only in an encrypted message to the recipient --- coreapi/chat.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 469e53e63..cc95bed26 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -159,11 +159,14 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co /* generate a random 192 bits key + 64 bits of initial vector and store it into the file_transfer_information->key field of the message */ msg->file_transfer_information->key = (unsigned char *)malloc(FILE_TRANSFER_KEY_SIZE); sal_get_random_bytes(msg->file_transfer_information->key, FILE_TRANSFER_KEY_SIZE); + /* temporary storage for the Content-disposition header value : use a generic filename to not leak it + * Actual filename stored in msg->file_transfer_information->name will be set in encrypted message sended to the */ + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\""); + } else { + /* temporary storage for the Content-disposition header value */ + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", msg->file_transfer_information->name); } - /* temporary storage for the Content-disposition header value */ - first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", msg->file_transfer_information->name); - /* create a user body handler to take care of the file and add the content disposition and content-type headers */ first_part_bh=belle_sip_user_body_handler_new(msg->file_transfer_information->size,NULL,NULL,linphone_chat_message_file_transfer_on_send_body,msg); belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh, belle_sip_header_create("Content-disposition", first_part_header)); @@ -201,7 +204,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co if (msg->http_request == NULL) { return; } - /* if we have an encryption key for the file, we must insert it into the message */ + /* if we have an encryption key for the file, we must insert it into the message and restore the correct filename */ if (msg->file_transfer_information->key != NULL) { /* parse the message body */ xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); @@ -213,6 +216,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */ xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); if(!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for : add a file-key children node */ + xmlNodePtr fileInfoNodeChildren = cur->xmlChildrenNode; /* need to parse the children node to update the file-name one */ /* convert key to base64 */ int b64Size = b64_encode(NULL, FILE_TRANSFER_KEY_SIZE, NULL, 0); char *keyb64 = (char *)malloc(b64Size+1); @@ -225,6 +229,17 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); xmlFree(typeAttribute); + /* look for the file-name node and update its content */ + while (fileInfoNodeChildren!=NULL) { + if (!xmlStrcmp(fileInfoNodeChildren->name, (const xmlChar *)"file-name")) { /* we found a the file-name node, update its content with the real filename */ + /* update node content */ + xmlNodeSetContent(fileInfoNodeChildren, (const xmlChar *)(msg->file_transfer_information->name)); + break; + } + fileInfoNodeChildren = fileInfoNodeChildren->next; + } + + /* dump the xml into msg->message */ xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, "UTF-8", 0); From 60cadbb6c6407390490d19ad1ca986f2f8a55c59 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Tue, 30 Sep 2014 22:55:55 +0200 Subject: [PATCH 18/19] Fix memory leaks (LIME related) --- coreapi/bellesip_sal/sal_op_message.c | 7 ++++++- coreapi/chat.c | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 182e5268e..6998704bf 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -195,6 +195,8 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve salmsg.message_id=message_id; salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL); op->base.root->callbacks.text_received(op,&salmsg); + + free(decryptedMessage); belle_sip_object_unref(address); belle_sip_free(from); if (salmsg.url) ms_free((char*)salmsg.url); @@ -230,6 +232,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co size_t content_length = msg?strlen(msg):0; time_t curtime=time(NULL); uint8_t *multipartEncryptedMessage = NULL; + int retval; if (op->dialog){ /*for SIP MESSAGE that are sent in call's dialog*/ @@ -303,8 +306,10 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),(multipartEncryptedMessage==NULL)?msg:(const char *)multipartEncryptedMessage,content_length); - return sal_op_send_request(op,req); + retval = sal_op_send_request(op,req); + free(multipartEncryptedMessage); + return retval; } int sal_message_reply(SalOp *op, SalReason reason){ diff --git a/coreapi/chat.c b/coreapi/chat.c index cc95bed26..d6986f1ec 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -228,6 +228,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co /* add the node containing the key to the file-info node */ xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); xmlFree(typeAttribute); + free(keyb64); /* look for the file-name node and update its content */ while (fileInfoNodeChildren!=NULL) { From 2f17142775cbf0524d2a8d7caadbaebf1622598b Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Thu, 26 Feb 2015 22:47:55 +0100 Subject: [PATCH 19/19] Lime not active as default --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2cc259e7c..75cfd2cd9 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -890,7 +890,7 @@ static void sip_config_read(LinphoneCore *lc) tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1); linphone_core_set_guess_hostname(lc,tmp); - tmp=lp_config_get_int(lc->config,"sip","lime",1); + tmp=lp_config_get_int(lc->config,"sip","lime",0); linphone_core_set_lime(lc,tmp); tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30);