Started im encryption engine, process incoming message with lime seems to work

This commit is contained in:
Sylvain Berfini 2016-11-04 12:02:23 +01:00
parent 3a0d46d140
commit 2c905e4cde
11 changed files with 247 additions and 58 deletions

View file

@ -46,6 +46,7 @@ set(LINPHONE_HEADER_FILES
linphonepresence.h
linphone_proxy_config.h
linphone_tunnel.h
im_encryption_engine.h
lpc2xml.h
lpconfig.h
nat_policy.h
@ -95,6 +96,7 @@ set(LINPHONE_SOURCE_FILES_C
info.c
ldap/ldapprovider.c
lime.c
im_encryption_engine.c
linphonecall.c
linphonecore.c
linphone_tunnel_config.c

View file

@ -40,6 +40,7 @@ linphone_include_HEADERS=\
linphonepresence.h \
linphone_proxy_config.h \
linphone_tunnel.h \
im_encryption_engine.h \
lpc2xml.h \
lpconfig.h \
nat_policy.h \
@ -80,6 +81,7 @@ liblinphone_la_SOURCES=\
localplayer.c \
lpc2xml.c \
lime.c lime.h\
im_encryption_engine.c \
lpconfig.c \
lsd.c \
message_storage.c \

View file

@ -70,13 +70,6 @@ static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) {
&& 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)
|| (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
&& strcmp("external-body",belle_sip_header_content_type_get_subtype(content_type))==0;
@ -107,62 +100,28 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
bool_t cipher_xml=FALSE;
bool_t rcs_filetransfer=FALSE;
uint8_t *decryptedMessage = NULL;
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
int retval = -1;
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);
if (content_type){
/* check if we have a xml/cipher message to be decrypted */
if ((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 = NULL;
if (lc->zrtp_secrets_cache != NULL) CACHEFD = fopen(lc->zrtp_secrets_cache, "rb+");
if (CACHEFD == NULL) {
ms_warning("Unable to access ZRTP ZID cache to decrypt message");
goto error;
} else {
size_t cacheSize;
char *cacheString;
int retval;
xmlDocPtr cacheXml;
cacheString=ms_load_file_content(CACHEFD, &cacheSize);
if (!cacheString){
ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
goto error;
}
cacheString[cacheSize] = '\0';
cacheSize += 1;
fclose(CACHEFD);
cacheXml = xmlParseDoc((xmlChar*)cacheString);
ms_free(cacheString);
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);
xmlFreeDoc(cacheXml);
errcode = 488;
goto error;
} else {
/* 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, "wb+");
if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){
ms_warning("Fail to write cache");
}
xmlFree(xmlStringOutput);
fclose(CACHEFD);
}
xmlFreeDoc(cacheXml);
if (content_type) {
LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc);
if (imee) {
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
LinphoneImEncryptionEngineIncomingMessageCb cb_process_incoming_message = linphone_im_encryption_engine_cbs_get_process_incoming_message(imee_cbs);
if (cb_process_incoming_message) {
retval = cb_process_incoming_message(lc, belle_sip_header_content_type_get_type(content_type), belle_sip_header_content_type_get_subtype(content_type),
belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), (char **)&decryptedMessage);
}
}
cipher_xml = retval >= 0;
if (retval > 0) {
errcode = retval;
goto error;
}
external_body=is_external_body(content_type);
plain_text=is_plain_text(content_type);
rcs_filetransfer = is_rcs_filetransfer(content_type);

View file

@ -0,0 +1,71 @@
/*
ImEncryptionEgine.c
Copyright (C) 2016 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphonecore.h"
#include "im_encryption_engine.h"
struct _LinphoneImEncryptionEngineCbs {
void *user_data;
LinphoneImEncryptionEngineIncomingMessageCb process_incoming_message;
};
struct _LinphoneImEncryptionEngine {
void *user_data;
LinphoneImEncryptionEngineCbs *callbacks;
};
LinphoneImEncryptionEngineCbs *linphone_im_encryption_engine_cbs_new(void) {
LinphoneImEncryptionEngineCbs *cbs = ms_new0(LinphoneImEncryptionEngineCbs, 1);
return cbs;
}
void linphone_im_encryption_engine_cbs_destory(LinphoneImEncryptionEngineCbs *cbs) {
ms_free(cbs);
}
void *linphone_im_encryption_engine_cbs_get_user_data(const LinphoneImEncryptionEngineCbs *cbs) {
return cbs->user_data;
}
void linphone_im_encryption_engine_cbs_set_user_data(LinphoneImEncryptionEngineCbs *cbs, void *data) {
cbs->user_data = data;
}
LinphoneImEncryptionEngine *linphone_im_encryption_engine_new(void) {
LinphoneImEncryptionEngine *imee = ms_new0(LinphoneImEncryptionEngine, 1);
imee->callbacks = linphone_im_encryption_engine_cbs_new();
return imee;
}
void linphone_im_encryption_engine_destory(LinphoneImEncryptionEngine *imee) {
if (imee->callbacks) linphone_im_encryption_engine_cbs_destory(imee->callbacks);
ms_free(imee);
}
LinphoneImEncryptionEngineCbs* linphone_im_encryption_engine_get_callbacks(const LinphoneImEncryptionEngine *imee) {
return imee->callbacks;
}
LinphoneImEncryptionEngineIncomingMessageCb linphone_im_encryption_engine_cbs_get_process_incoming_message(LinphoneImEncryptionEngineCbs *cbs) {
return cbs->process_incoming_message;
}
void linphone_im_encryption_engine_cbs_set_process_incoming_message(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineIncomingMessageCb cb) {
cbs->process_incoming_message = cb;
}

View file

@ -0,0 +1,53 @@
/*
ImEncryptionEgine.h
Copyright (C) 2016 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef IM_ENCRYPTION_ENGINE_H
#define IM_ENCRYPTION_ENGINE_H
#include <mediastreamer2/mscommon.h>
#ifndef LINPHONE_PUBLIC
#define LINPHONE_PUBLIC MS2_PUBLIC
#endif
typedef int (*LinphoneImEncryptionEngineIncomingMessageCb)(LinphoneCore* lc, const char* content_type, const char* content_subtype, const char* body, char** decrypted_body);
typedef struct _LinphoneImEncryptionEngineCbs LinphoneImEncryptionEngineCbs;
typedef struct _LinphoneImEncryptionEngine LinphoneImEncryptionEngine;
LINPHONE_PUBLIC LinphoneImEncryptionEngineCbs *linphone_im_encryption_engine_cbs_new(void);
LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_destory(LinphoneImEncryptionEngineCbs *cbs);
LINPHONE_PUBLIC void *linphone_im_encryption_engine_cbs_get_user_data(const LinphoneImEncryptionEngineCbs *cbs);
LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_user_data(LinphoneImEncryptionEngineCbs *cbs, void *data);
LINPHONE_PUBLIC LinphoneImEncryptionEngine *linphone_im_encryption_engine_new(void);
LINPHONE_PUBLIC void linphone_im_encryption_engine_destory(LinphoneImEncryptionEngine *imee);
LINPHONE_PUBLIC LinphoneImEncryptionEngineCbs* linphone_im_encryption_engine_get_callbacks(const LinphoneImEncryptionEngine *imee);
LINPHONE_PUBLIC LinphoneImEncryptionEngineIncomingMessageCb linphone_im_encryption_engine_cbs_get_process_incoming_message(LinphoneImEncryptionEngineCbs *cbs);
LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_incoming_message(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineIncomingMessageCb cb);
#endif /* IM_ENCRYPTION_ENGINE_H */

View file

@ -23,7 +23,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#endif
#ifdef HAVE_LIME
#include "linphonecore.h"
#include "bctoolbox/crypto.h"
/**
@ -812,6 +811,70 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_
return 0;
}
static bool_t is_cipher_xml(const char* content_type, const char *content_subtype) {
return (strcmp("xml",content_type)==0
&& strcmp("cipher",content_subtype)==0)
|| (strcmp("application",content_type)==0
&& strcmp("cipher.vnd.gsma.rcs-ft-http+xml",content_subtype)==0);
}
int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, const char* content_type, const char* content_subtype, const char* body, char** decrypted_body) {
int errcode = -1;
/* check if we have a xml/cipher message to be decrypted */
if (is_cipher_xml(content_type, content_subtype)) {
/* access the zrtp cache to get keys needed to decipher the message */
FILE *CACHEFD = NULL;
const char *zrtp_secrets_cache = linphone_core_get_zrtp_secrets_file(lc);
errcode = 0;
if (zrtp_secrets_cache != NULL) CACHEFD = fopen(zrtp_secrets_cache, "rb+");
if (CACHEFD == NULL) {
ms_warning("Unable to access ZRTP ZID cache to decrypt message");
errcode = 500;
return errcode;
} else {
size_t cacheSize;
char *cacheString;
int retval;
xmlDocPtr cacheXml;
cacheString=ms_load_file_content(CACHEFD, &cacheSize);
if (!cacheString){
ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
errcode = 500;
return errcode;
}
cacheString[cacheSize] = '\0';
cacheSize += 1;
fclose(CACHEFD);
cacheXml = xmlParseDoc((xmlChar*)cacheString);
ms_free(cacheString);
retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)body, (uint8_t **)decrypted_body);
if (retval != 0) {
ms_warning("Unable to decrypt message, reason : %s", lime_error_code_to_string(retval));
free(decrypted_body);
xmlFreeDoc(cacheXml);
errcode = 488;
return errcode;
} else {
/* 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(zrtp_secrets_cache, "wb+");
if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){
ms_warning("Fail to write cache");
}
xmlFree(xmlStringOutput);
fclose(CACHEFD);
}
xmlFreeDoc(cacheXml);
}
}
return errcode;
}
#else /* HAVE_LIME */
@ -837,6 +900,9 @@ int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) {
int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage) {
return LIME_NOT_ENABLED;
}
int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, const char* content_type, const char* content_subtype, const char* body, char** decrypted_body) {
return 500;
}
#endif /* HAVE_LIME */
char *lime_error_code_to_string(int errorCode) {

View file

@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <libxml/parser.h>
#include <libxml/xmlwriter.h>
#include "linphonecore.h"
#include <mediastreamer2/mscommon.h>
#ifndef LINPHONE_PUBLIC
@ -203,4 +204,7 @@ LINPHONE_PUBLIC char *lime_error_code_to_string(int errorCode);
* @return TRUE if Lime is available, FALSE if not
*/
LINPHONE_PUBLIC bool_t lime_is_available(void);
int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, const char* content_type, const char* content_subtype, const char* body, char** decrypted_body);
#endif /* LIME_H */

View file

@ -1950,6 +1950,18 @@ void linphone_core_enable_lime(LinphoneCore *lc, LinphoneLimeState val){
if (linphone_core_ready(lc)){
lp_config_set_int(lc->config,"sip","lime",val);
}
if (val != LinphoneLimeDisabled) {
LinphoneImEncryptionEngine *imee = linphone_im_encryption_engine_new();
LinphoneImEncryptionEngineCbs *cbs = linphone_im_encryption_engine_get_callbacks(imee);
linphone_im_encryption_engine_cbs_set_process_incoming_message(cbs, lime_im_encryption_engine_process_incoming_message_cb);
lc->im_encryption_engine = imee;
} else {
if (lc->im_encryption_engine) {
linphone_im_encryption_engine_destory(lc->im_encryption_engine);
lc->im_encryption_engine = NULL;
}
}
}
bool_t linphone_core_lime_available(const LinphoneCore *lc){
@ -7996,3 +8008,11 @@ const char *linphone_core_get_tls_key_path(const LinphoneCore *lc) {
const char *tls_key_path = lp_config_get_string(lc->config, "sip", "client_cert_key", NULL);
return tls_key_path;
}
void linphone_core_set_im_encryption_engine(LinphoneCore *lc, LinphoneImEncryptionEngine *imee) {
lc->im_encryption_engine = imee;
}
LinphoneImEncryptionEngine *linphone_core_get_im_encryption_engine(const LinphoneCore *lc) {
return lc->im_encryption_engine;
}

View file

@ -432,6 +432,7 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
#include "nat_policy.h"
#include "xmlrpc.h"
#include "conference.h"
#include "im_encryption_engine.h"
#else
#include "linphone/buffer.h"
#include "linphone/call_log.h"
@ -442,6 +443,7 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
#include "linphone/nat_policy.h"
#include "linphone/xmlrpc.h"
#include "linphone/conference.h"
#include "linphone/im_encryption_engine.h"
#endif
LINPHONE_PUBLIC LinphoneAddress * linphone_address_new(const char *addr);
@ -4728,6 +4730,10 @@ LINPHONE_PUBLIC const char *linphone_core_get_tls_cert_path(const LinphoneCore *
*/
LINPHONE_PUBLIC const char *linphone_core_get_tls_key_path(const LinphoneCore *lc);
LINPHONE_PUBLIC void linphone_core_set_im_encryption_engine(LinphoneCore *lc, LinphoneImEncryptionEngine *imee);
LINPHONE_PUBLIC LinphoneImEncryptionEngine * linphone_core_get_im_encryption_engine(const LinphoneCore *lc);
#include "ringtoneplayer.h"
#ifdef __cplusplus

View file

@ -1071,6 +1071,8 @@ struct _LinphoneCore
/*default resource list server*/
LinphoneAddress *default_rls_addr;
LinphoneImEncryptionEngine *im_encryption_engine;
};

View file

@ -809,6 +809,10 @@ static void lime_text_message(void) {
linphone_chat_room_send_message(chat_room,"Bla bla bla bla");
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1));
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedLegacy,1));
BC_ASSERT_PTR_NOT_NULL(marie->stat.last_received_chat_message);
if (marie->stat.last_received_chat_message) {
BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(marie->stat.last_received_chat_message), "Bla bla bla bla");
}
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity));
/* TODO : check the msg arrived correctly deciphered */