From 3214b4371ad109269a008aa9471a91e8e0b49cd5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 10 Nov 2016 12:02:56 +0100 Subject: [PATCH] Reworked im encryption engine to be at linphone level instead of sal level --- coreapi/bellesip_sal/sal_op_message.c | 103 +++------------- coreapi/callbacks.c | 7 +- coreapi/chat.c | 168 ++++++++++++-------------- coreapi/im_encryption_engine.h | 4 +- coreapi/lime.c | 106 +++++++++++++--- coreapi/lime.h | 4 +- coreapi/linphonecore.c | 43 +++++++ coreapi/linphonecore.h | 8 +- coreapi/private.h | 2 +- 9 files changed, 241 insertions(+), 204 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index c1858b4b4..07a59ae75 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -59,16 +59,6 @@ static void process_response_event(void *op_base, const belle_sip_response_event op->base.root->callbacks.text_delivery_update(op,status); } -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) || (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) { - 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_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; @@ -94,40 +84,29 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(req,belle_sip_header_date_t); char* from; - bool_t plain_text=FALSE; bool_t external_body=FALSE; - 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) { - 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, req, 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); - - if (external_body || plain_text || rcs_filetransfer || decryptedMessage!=NULL) { + if (is_im_iscomposing(content_type)) { + SalIsComposing saliscomposing; + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); + saliscomposing.from=from; + saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + op->base.root->callbacks.is_composing_received(op,&saliscomposing); + resp = belle_sip_response_create_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + belle_sip_object_unref(address); + belle_sip_free(from); + } else { SalMessage salmsg; char message_id[256]={0}; + + external_body=is_external_body(content_type); if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); op->pending_server_trans=server_transaction; @@ -141,16 +120,9 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve ,belle_sip_header_cseq_get_seq_number(cseq)); salmsg.from=from; /* 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.text=(!external_body)?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 */ - salmsg.content_type = "application/vnd.gsma.rcs-ft-http+xml"; - } + salmsg.content_type = ms_strdup_printf("%s/%s", belle_sip_header_content_type_get_type(content_type), belle_sip_header_content_type_get_subtype(content_type)); 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")); salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/ @@ -160,28 +132,11 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve 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); - } else if (is_im_iscomposing(content_type)) { - SalIsComposing saliscomposing; - address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) - ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); - from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); - saliscomposing.from=from; - saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); - op->base.root->callbacks.is_composing_received(op,&saliscomposing); - resp = belle_sip_response_create_from_request(req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); - belle_sip_object_unref(address); - belle_sip_free(from); - }else{ - ms_error("Unsupported MESSAGE (content-type not recognized)"); - errcode = 415; - goto error; } - }else { + } else { ms_error("Unsupported MESSAGE (no Content-Type)"); goto error; } @@ -203,11 +158,8 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co char content_type_raw[256]; size_t content_length = msg?strlen(msg):0; time_t curtime = ms_time(NULL); - uint8_t *multipartEncryptedMessage = NULL; const char *body; - int retval = -1; - LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + int retval; if (op->dialog){ /*for SIP MESSAGE that are sent in call's dialog*/ @@ -229,31 +181,16 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co } } - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineOutgoingMessageCb cb_process_outgoing_message = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imee_cbs); - if (cb_process_outgoing_message) { - retval = cb_process_outgoing_message(lc, req, peer_uri, content_type, msg, (char **)&multipartEncryptedMessage, &content_length); - } - } - if (retval > 0) { - /*probably not a good idea to do this:*/ - sal_error_info_set(&op->error_info, SalReasonNotAcceptable, retval, "Unable to encrypt IM", NULL); - op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed); - return -1; - } - 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))); - body = (multipartEncryptedMessage==NULL) ? msg : (char*) multipartEncryptedMessage; + body = msg; if (body){ /*don't call set_body() with null argument because it resets content type and content length*/ belle_sip_message_set_body(BELLE_SIP_MESSAGE(req), body, content_length); } retval = sal_op_send_request(op,req); - free(multipartEncryptedMessage); return retval; } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9e6e359fb..b9275a57d 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1159,10 +1159,11 @@ static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){ static void text_received(SalOp *op, const SalMessage *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - if (lc->chat_deny_code==LinphoneReasonNone && is_duplicate_msg(lc,msg->message_id)==FALSE){ - linphone_core_message_received(lc,op,msg); + LinphoneReason reason = lc->chat_deny_code; + if (reason == LinphoneReasonNone && is_duplicate_msg(lc, msg->message_id) == FALSE) { + reason = linphone_core_message_received(lc, op, msg); } - sal_message_reply(op,linphone_reason_to_sal(lc->chat_deny_code)); + sal_message_reply(op,linphone_reason_to_sal(reason)); if (!call) sal_op_release(op); } diff --git a/coreapi/chat.c b/coreapi/chat.c index 933909121..98f3ed0cd 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -27,7 +27,6 @@ #include "lpconfig.h" #include "belle-sip/belle-sip.h" #include "ortp/b64.h" -#include "lime.h" #include #include @@ -265,50 +264,6 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c return _linphone_core_get_or_create_chat_room(lc, to); } -bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) { - if (cr) { - switch (linphone_core_lime_enabled(cr->lc)) { - case LinphoneLimeDisabled: return FALSE; - case LinphoneLimeMandatory: return TRUE; - case LinphoneLimePreferred: { - FILE *CACHEFD = NULL; - if (cr->lc->zrtp_secrets_cache != NULL) { - CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "rb+"); - if (CACHEFD) { - size_t cacheSize; - xmlDocPtr cacheXml; - char *cacheString=ms_load_file_content(CACHEFD, &cacheSize); - if (!cacheString){ - ms_warning("Unable to load content of ZRTP ZID cache to decrypt message"); - return FALSE; - } - cacheString[cacheSize] = '\0'; - cacheSize += 1; - fclose(CACHEFD); - cacheXml = xmlParseDoc((xmlChar*)cacheString); - ms_free(cacheString); - if (cacheXml) { - bool_t res; - limeURIKeys_t associatedKeys; - /* retrieve keys associated to the peer URI */ - associatedKeys.peerURI = (uint8_t *)malloc(strlen(cr->peer)+1); - strcpy((char *)(associatedKeys.peerURI), cr->peer); - associatedKeys.associatedZIDNumber = 0; - associatedKeys.peerKeys = NULL; - - res = (lime_getCachedSndKeysByURI(cacheXml, &associatedKeys) == 0 && associatedKeys.associatedZIDNumber != 0); - lime_freeKeys(&associatedKeys); - xmlFreeDoc(cacheXml); - return res; - } - } - } - } - } - } - return FALSE; -} - static void linphone_chat_room_delete_composing_idle_timer(LinphoneChatRoom *cr) { if (cr->composing_idle_timer) { if (cr->lc && cr->lc->sal) @@ -366,6 +321,10 @@ void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void *ud) { } void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + int retval = -1; + LinphoneCore *lc = cr->lc; + LinphoneImEncryptionEngine *imee = lc->im_encryption_engine; + /*stubed rtt text*/ if (cr->call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(cr->call))) { uint32_t new_line = 0x2028; @@ -406,6 +365,15 @@ void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage } } } + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineOutgoingMessageCb cb_process_outgoing_message = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imee_cbs); + if (cb_process_outgoing_message) { + retval = cb_process_outgoing_message(lc, cr, msg); + } + } + if (op == NULL) { LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cr->lc, cr->peer_url); if (proxy) { @@ -418,6 +386,13 @@ void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage 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 (retval > 0) { + sal_error_info_set((SalErrorInfo *)sal_op_get_error_info(op), SalReasonNotAcceptable, retval, "Unable to encrypt IM", NULL); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + linphone_chat_message_unref(msg); + return; + } if (msg->external_body_url) { content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", msg->external_body_url); @@ -425,21 +400,7 @@ void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage ms_free(content_type); } else { char *peer_uri = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); - const char *content_type; - - if (linphone_chat_room_lime_available(cr)) { - /* ref the msg or it may be destroyed by callback if the encryption failed */ - if (msg->content_type && 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*/ - content_type = "application/cipher.vnd.gsma.rcs-ft-http+xml"; - } else { - content_type = "xml/cipher"; - } - } else { - content_type = msg->content_type; - } - + const char *content_type = msg->content_type; if (content_type == NULL) { sal_text_send(op, identity, cr->peer, msg->message); } else { @@ -509,30 +470,68 @@ void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, linphone_core_notify_is_composing_received(cr->lc, cr); } -void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg) { +LinphoneReason linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg) { LinphoneChatRoom *cr = NULL; LinphoneAddress *addr; + LinphoneAddress *to; LinphoneChatMessage *msg; + LinphoneImEncryptionEngine *imee = lc->im_encryption_engine; const SalCustomHeader *ch; + LinphoneReason reason = LinphoneReasonNone; + int retval = -1; addr = linphone_address_new(sal_msg->from); linphone_address_clean(addr); cr = linphone_core_get_chat_room(lc, addr); - if (sal_msg->content_type != - NULL) { /* content_type field is, for now, used only for rcs file transfer but we shall strcmp it with - "application/vnd.gsma.rcs-ft-http+xml" */ + msg = linphone_chat_room_create_message(cr, sal_msg->text); /* create a msg with empty body */ + msg->content_type = ms_strdup(sal_msg->content_type); /* add the content_type "application/vnd.gsma.rcs-ft-http+xml" */ + linphone_chat_message_set_from(msg, cr->peer_url); + + to = sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op)) : linphone_address_new(linphone_core_get_identity(lc)); + msg->to = to; + + msg->time = sal_msg->time; + msg->state = LinphoneChatMessageStateDelivered; + msg->is_read = FALSE; + msg->dir = LinphoneChatMessageIncoming; + + ch = sal_op_get_recv_custom_header(op); + if (ch) { + msg->custom_headers = sal_custom_header_clone(ch); + } + + if (sal_msg->url) { + linphone_chat_message_set_external_body_url(msg, sal_msg->url); + } + + 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, cr, msg); + } + } + + if (retval < 0 && strcmp("text/plain", msg->content_type) != 0 && strcmp("message/external-body", msg->content_type) != 0 + && strcmp("application/vnd.gsma.rcs-ft-http+xml", msg->content_type) != 0) { + retval = 415; + ms_error("Unsupported MESSAGE (content-type %s not recognized)", msg->content_type); + } + + if (retval > 0) { + reason = linphone_error_code_to_reason(retval); + goto end; + } + + if (strcmp("application/vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0) { xmlChar *file_url = NULL; xmlDocPtr xmlMessageBody; xmlNodePtr cur; - - msg = linphone_chat_room_create_message(cr, NULL); /* create a msg with empty body */ - msg->content_type = - ms_strdup(sal_msg->content_type); /* add the content_type "application/vnd.gsma.rcs-ft-http+xml" */ - msg->file_transfer_information = linphone_content_new(); - + /* content_type field is, for now, used only for rcs file transfer but we shall strcmp it with "application/vnd.gsma.rcs-ft-http+xml" */ /* parse the msg body to get all informations from it */ - xmlMessageBody = xmlParseDoc((const xmlChar *)sal_msg->text); + xmlMessageBody = xmlParseDoc((const xmlChar *)msg->message); + msg->file_transfer_information = linphone_content_new(); cur = xmlDocGetRootElement(xmlMessageBody); if (cur != NULL) { @@ -609,31 +608,8 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag linphone_chat_message_set_external_body_url(msg, (const char *)file_url); xmlFree(file_url); - } else { /* msg is not rcs file transfer, create it with provided sal_msg->text as ->msg */ - msg = linphone_chat_room_create_message(cr, sal_msg->text); - } - linphone_chat_message_set_from(msg, cr->peer_url); - - { - LinphoneAddress *to; - to = sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op)) - : linphone_address_new(linphone_core_get_identity(lc)); - msg->to = to; } - msg->time = sal_msg->time; - msg->state = LinphoneChatMessageStateDelivered; - msg->is_read = FALSE; - msg->dir = LinphoneChatMessageIncoming; - ch = sal_op_get_recv_custom_header(op); - if (ch) - msg->custom_headers = sal_custom_header_clone(ch); - - if (sal_msg->url) { - linphone_chat_message_set_external_body_url(msg, sal_msg->url); - } - - linphone_address_destroy(addr); msg->storage_id = linphone_chat_message_store(msg); if (cr->unread_count < 0) @@ -642,7 +618,11 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag cr->unread_count++; linphone_chat_room_message_received(cr, lc, msg); + +end: + linphone_address_destroy(addr); linphone_chat_message_unref(msg); + return reason; } static int linphone_chat_room_remote_refresh_composing_expired(void *data, unsigned int revents) { diff --git a/coreapi/im_encryption_engine.h b/coreapi/im_encryption_engine.h index 2ec8b701b..d9b2c63b3 100644 --- a/coreapi/im_encryption_engine.h +++ b/coreapi/im_encryption_engine.h @@ -26,9 +26,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define LINPHONE_PUBLIC MS2_PUBLIC #endif -typedef int (*LinphoneImEncryptionEngineIncomingMessageCb)(LinphoneCore* lc, belle_sip_request_t* req, const char* content_type, const char* content_subtype, const char* body, char** decrypted_body); +typedef int (*LinphoneImEncryptionEngineIncomingMessageCb)(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); -typedef int (*LinphoneImEncryptionEngineOutgoingMessageCb)(LinphoneCore* lc, belle_sip_request_t* req, const char *peer_uri, const char* content_type, const char* body, char** crypted_body, size_t* content_length); +typedef int (*LinphoneImEncryptionEngineOutgoingMessageCb)(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); typedef int (*LinphoneImEncryptionEngineDownloadingFileCb)(LinphoneCore *lc, LinphoneChatMessage *msg, const char *buffer, size_t size, char **decrypted_buffer); diff --git a/coreapi/lime.c b/coreapi/lime.c index 23109a662..575c8588a 100644 --- a/coreapi/lime.c +++ b/coreapi/lime.c @@ -812,17 +812,54 @@ 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); +bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) { + if (cr) { + switch (linphone_core_lime_enabled(cr->lc)) { + case LinphoneLimeDisabled: return FALSE; + case LinphoneLimeMandatory: return TRUE; + case LinphoneLimePreferred: { + FILE *CACHEFD = NULL; + if (cr->lc->zrtp_secrets_cache != NULL) { + CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "rb+"); + if (CACHEFD) { + size_t cacheSize; + xmlDocPtr cacheXml; + char *cacheString=ms_load_file_content(CACHEFD, &cacheSize); + if (!cacheString){ + ms_warning("Unable to load content of ZRTP ZID cache to decrypt message"); + return FALSE; + } + cacheString[cacheSize] = '\0'; + cacheSize += 1; + fclose(CACHEFD); + cacheXml = xmlParseDoc((xmlChar*)cacheString); + ms_free(cacheString); + if (cacheXml) { + bool_t res; + limeURIKeys_t associatedKeys; + /* retrieve keys associated to the peer URI */ + associatedKeys.peerURI = (uint8_t *)malloc(strlen(cr->peer)+1); + strcpy((char *)(associatedKeys.peerURI), cr->peer); + associatedKeys.associatedZIDNumber = 0; + associatedKeys.peerKeys = NULL; + + res = (lime_getCachedSndKeysByURI(cacheXml, &associatedKeys) == 0 && associatedKeys.associatedZIDNumber != 0); + lime_freeKeys(&associatedKeys); + xmlFreeDoc(cacheXml); + return res; + } + } + } + } + } + } + return FALSE; } -int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, belle_sip_request_t* req, const char* content_type, const char* content_subtype, const char* body, char** decrypted_body) { +int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) { int errcode = -1; /* check if we have a xml/cipher message to be decrypted */ - if (is_cipher_xml(content_type, content_subtype)) { + if (msg->content_type && (strcmp("xml/cipher", msg->content_type) == 0 || strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0)) { /* 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); @@ -837,6 +874,7 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, bell char *cacheString; int retval; xmlDocPtr cacheXml; + uint8_t *decrypted_body = NULL; cacheString=ms_load_file_content(CACHEFD, &cacheSize); if (!cacheString){ @@ -849,10 +887,10 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, bell fclose(CACHEFD); cacheXml = xmlParseDoc((xmlChar*)cacheString); ms_free(cacheString); - retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)body, (uint8_t **)decrypted_body); + retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)msg->message, &decrypted_body); if (retval != 0) { ms_warning("Unable to decrypt message, reason : %s", lime_error_code_to_string(retval)); - if (*decrypted_body) free(*decrypted_body); + if (decrypted_body) free(decrypted_body); xmlFreeDoc(cacheXml); errcode = 488; return errcode; @@ -868,6 +906,18 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, bell } xmlFree(xmlStringOutput); fclose(CACHEFD); + if (msg->message) { + ms_free(msg->message); + } + msg->message = (char *)decrypted_body; + + if (strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0) { + ms_free(msg->content_type); + msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml"); + } else { + ms_free(msg->content_type); + msg->content_type = ms_strdup("text/plain"); + } } xmlFreeDoc(cacheXml); @@ -876,10 +926,21 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, bell return errcode; } -int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, belle_sip_request_t* req, const char *peer_uri, const char* content_type, const char* body, char** crypted_body, size_t* content_length) { +int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) { int errcode = -1; - /* shall we try to encrypt the message?*/ - if ((strcmp(content_type, "xml/cipher") == 0) || ((strcmp(content_type, "application/cipher.vnd.gsma.rcs-ft-http+xml") == 0))) { + char *content_type = NULL; + + if (linphone_chat_room_lime_available(room)) { + if (msg->content_type && 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*/ + content_type = "application/cipher.vnd.gsma.rcs-ft-http+xml"; + } else { + content_type = "xml/cipher"; + } + msg->content_type = ms_strdup(content_type); + + /* access the zrtp cache to get keys needed to cipher the message */ const char *zrtp_secrets_cache = linphone_core_get_zrtp_secrets_file(lc); FILE *CACHEFD = fopen(zrtp_secrets_cache, "rb+"); @@ -892,6 +953,8 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, bell char *cacheString; xmlDocPtr cacheXml; int retval; + uint8_t *crypted_body = NULL; + char *peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(room)); cacheString=ms_load_file_content(CACHEFD, &cacheSize); if (!cacheString){ @@ -904,10 +967,10 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, bell fclose(CACHEFD); cacheXml = xmlParseDoc((xmlChar*)cacheString); ms_free(cacheString); - retval = lime_createMultipartMessage(cacheXml, (uint8_t *)body, (uint8_t *)peer_uri, (uint8_t **)crypted_body); + retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg->message, (uint8_t *)peer, &crypted_body); if (retval != 0) { - ms_warning("Unable to encrypt message for %s : %s", peer_uri, lime_error_code_to_string(retval)); - if (*crypted_body) free(*crypted_body); + ms_warning("Unable to encrypt message for %s : %s", peer, lime_error_code_to_string(retval)); + if (crypted_body) free(crypted_body); errcode = 488; } else { /* dump updated cache to a string */ @@ -921,8 +984,12 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, bell } xmlFree(xmlStringOutput); fclose(CACHEFD); - *content_length = strlen((const char *)*crypted_body); + if (msg->message) { + ms_free(msg->message); + } + msg->message = (char *)crypted_body; } + ms_free(peer); xmlFreeDoc(cacheXml); } } @@ -965,10 +1032,13 @@ 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, belle_sip_request_t* req, const char* content_type, const char* content_subtype, const char* body, char** decrypted_body) { +bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) { + return FALSE; +} +int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) { return 500; } -int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, belle_sip_request_t* req, const char *peer_uri, const char* content_type, const char* body, char** crypted_body, size_t* content_length) { +int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) { return 500; } int lime_im_encryption_engine_process_downloading_file_cb(LinphoneCore *lc, LinphoneChatMessage *msg, const char *buffer, size_t size, char **decrypted_buffer) { diff --git a/coreapi/lime.h b/coreapi/lime.h index 8c6c2d00f..932ff9bd3 100644 --- a/coreapi/lime.h +++ b/coreapi/lime.h @@ -205,9 +205,9 @@ LINPHONE_PUBLIC char *lime_error_code_to_string(int errorCode); */ LINPHONE_PUBLIC bool_t lime_is_available(void); -int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, belle_sip_request_t* req, const char* content_type, const char* content_subtype, const char* body, char** decrypted_body); +int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); -int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, belle_sip_request_t* req, const char *peer_uri, const char* content_type, const char* body, char** crypted_body, size_t* content_length); +int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); int lime_im_encryption_engine_process_downloading_file_cb(LinphoneCore *lc, LinphoneChatMessage *msg, const char *buffer, size_t size, char **decrypted_buffer); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c03dde5b4..b760a1c80 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7184,6 +7184,49 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "unknown error"; } +LinphoneReason linphone_error_code_to_reason(int err) { + if (err == 200) { + return LinphoneReasonNone; + } else if (err == 503) { + return LinphoneReasonIOError; + } else if (err == 400) { + return LinphoneReasonUnknown; + } else if (err == 486) { + return LinphoneReasonBusy; + } else if (err == 603) { + return LinphoneReasonDeclined; + } else if (err == 600) { + return LinphoneReasonDoNotDisturb; + } else if (err == 403) { + return LinphoneReasonForbidden; + } else if (err == 415) { + return LinphoneReasonUnsupportedContent; + } else if (err == 404) { + return LinphoneReasonNotFound; + } else if (err == 480) { + return LinphoneReasonTemporarilyUnavailable; + } else if (err == 401) { + return LinphoneReasonUnauthorized; + } else if (err == 488) { + return LinphoneReasonNotAcceptable; + } else if (err == 481) { + return LinphoneReasonNoMatch; + } else if (err == 301) { + return LinphoneReasonMovedPermanently; + } else if (err == 410) { + return LinphoneReasonGone; + } else if (err == 484) { + return LinphoneReasonAddressIncomplete; + } else if (err == 501) { + return LinphoneReasonNotImplemented; + } else if (err == 504) { + return LinphoneReasonServerTimeout; + } else if (err == 502) { + return LinphoneReasonBadGateway; + } + return LinphoneReasonUnknown; +} + const char *linphone_error_to_string(LinphoneReason err){ return linphone_reason_to_string(err); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 598209da5..26cfa6817 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -227,6 +227,12 @@ typedef enum _LinphoneReason LinphoneReason; **/ LINPHONE_PUBLIC const char *linphone_reason_to_string(LinphoneReason err); +/** + * Converts a error code to a LinphoneReason. + * @ingroup misc +**/ +LINPHONE_PUBLIC LinphoneReason linphone_error_code_to_reason(int err); + /** * Object representing full details about a signaling error or status. * All LinphoneErrorInfo object returned by the liblinphone API are readonly and transcients. For safety they must be used immediately @@ -1639,7 +1645,7 @@ LINPHONE_PUBLIC uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr) * * @return true if zrtp secrets have already been shared and ready to use */ - LINPHONE_PUBLIC bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr); +LINPHONE_PUBLIC bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr); /** * Returns an list of chat rooms diff --git a/coreapi/private.h b/coreapi/private.h index e72a5618f..ce8386b7a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -549,7 +549,7 @@ LINPHONE_PUBLIC void linphone_core_get_local_ip(LinphoneCore *lc, int af, const LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc, int index); void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,LinphoneProxyConfig *obj, int index); -void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg); +LinphoneReason linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg); void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing); void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call);