Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle KeyTransport message correctly #33

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 68 additions & 39 deletions src/libomemo.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#define ENCRYPTED_NODE_NAME "encrypted"
#define HEADER_NODE_NAME "header"
#define IV_NODE_NAME "iv"
#define RECIPIENT_NODE_NAME "keys"
#define KEY_NODE_NAME "key"
#define PAYLOAD_NODE_NAME "payload"
#define STORE_NODE_NAME "store"
Expand All @@ -61,7 +62,9 @@
#define MESSAGE_NODE_FROM_ATTR_NAME "from"
#define MESSAGE_NODE_TO_ATTR_NAME "to"
#define HEADER_NODE_SID_ATTR_NAME "sid"
#define RECIPIENT_NODE_JID_ATTR_NAME "jid"
#define KEY_NODE_RID_ATTR_NAME "rid"
#define KEY_NODE_KEX_ATTR_NAME "kex"
#define PUBLISH_NODE_NODE_ATTR_NAME "node"
#define SIGNED_PRE_KEY_NODE_ID_ATTR_NAME "signedPreKeyId"
#define PRE_KEY_NODE_ID_ATTR_NAME "preKeyId"
Expand Down Expand Up @@ -1090,45 +1093,43 @@ int omemo_message_prepare_encryption(char * outgoing_message, uint32_t sender_de
msg_p->message_node_p = msg_node_p;

body_node_p = mxmlFindPath(msg_node_p, BODY_NODE_NAME);
if (!body_node_p) {
ret_val = OMEMO_ERR_MALFORMED_XML;
goto cleanup;
}
if (body_node_p) {
msg_text = mxmlGetOpaque(body_node_p);
if (!msg_text) {
ret_val = OMEMO_ERR_MALFORMED_XML;
goto cleanup;
}

msg_text = mxmlGetOpaque(body_node_p);
if (!msg_text) {
ret_val = OMEMO_ERR_MALFORMED_XML;
goto cleanup;
}

ret_val = crypto_p->aes_gcm_encrypt_func((uint8_t *) msg_text, strlen(msg_text),
msg_p->iv_p, msg_p->iv_len,
msg_p->key_p, msg_p->key_len,
OMEMO_AES_GCM_TAG_LENGTH,
crypto_p->user_data_p,
&ct_p, &ct_len,
&tag_p);
if (ret_val) {
goto cleanup;
}
ret_val = crypto_p->aes_gcm_encrypt_func((uint8_t *) msg_text, strlen(msg_text),
msg_p->iv_p, msg_p->iv_len,
msg_p->key_p, msg_p->key_len,
OMEMO_AES_GCM_TAG_LENGTH,
crypto_p->user_data_p,
&ct_p, &ct_len,
&tag_p);
if (ret_val) {
goto cleanup;
}

msg_p->tag_len = OMEMO_AES_GCM_TAG_LENGTH;
memcpy(msg_p->key_p + msg_p->key_len, tag_p, msg_p->tag_len);
msg_p->tag_len = OMEMO_AES_GCM_TAG_LENGTH;
memcpy(msg_p->key_p + msg_p->key_len, tag_p, msg_p->tag_len);

ret_val = expect_next_node(body_node_p, mxmlGetParent, BODY_NODE_NAME, &body_node_p);
if (ret_val) {
goto cleanup;
}
ret_val = expect_next_node(body_node_p, mxmlGetParent, BODY_NODE_NAME, &body_node_p);
if (ret_val) {
goto cleanup;
}

mxmlRemove(body_node_p);
mxmlRemove(body_node_p);

payload_b64 = g_base64_encode(ct_p, ct_len);
payload_node_p = mxmlNewElement(MXML_NO_PARENT, PAYLOAD_NODE_NAME);
(void) mxmlNewOpaque(payload_node_p, payload_b64);
msg_p->payload_node_p = payload_node_p;
payload_b64 = g_base64_encode(ct_p, ct_len);
payload_node_p = mxmlNewElement(MXML_NO_PARENT, PAYLOAD_NODE_NAME);
(void) mxmlNewOpaque(payload_node_p, payload_b64);
msg_p->payload_node_p = payload_node_p;

if (strip == OMEMO_STRIP_ALL) {
omemo_message_strip_possible_plaintext(msg_p);
if (strip == OMEMO_STRIP_ALL) {
omemo_message_strip_possible_plaintext(msg_p);
}
}

*message_pp = msg_p;
Expand All @@ -1153,7 +1154,7 @@ size_t omemo_message_get_key_len(omemo_message * msg_p) {
return msg_p->key_len + msg_p->tag_len;
}

int omemo_message_add_recipient(omemo_message * msg_p, uint32_t device_id, const uint8_t * encrypted_key_p, size_t key_len) {
int omemo_message_add_recipient(omemo_message * msg_p, const char * recipient_name_bare, uint32_t device_id, const uint8_t * encrypted_key_p, size_t key_len, int kex) {
if (!msg_p || !msg_p->header_node_p || !encrypted_key_p) {
return OMEMO_ERR_NULL;
}
Expand All @@ -1163,19 +1164,29 @@ int omemo_message_add_recipient(omemo_message * msg_p, uint32_t device_id, const
return OMEMO_ERR;
}

mxml_node_t * recipient_node_p = mxmlFindElement(msg_p->header_node_p, msg_p->header_node_p,
RECIPIENT_NODE_NAME, RECIPIENT_NODE_JID_ATTR_NAME,
recipient_name_bare, MXML_DESCEND);
if (!recipient_node_p) {
recipient_node_p = mxmlNewElement(MXML_NO_PARENT, RECIPIENT_NODE_NAME);
mxmlElementSetAttr(recipient_node_p, RECIPIENT_NODE_JID_ATTR_NAME, recipient_name_bare);
mxmlAdd(msg_p->header_node_p, MXML_ADD_BEFORE, MXML_ADD_TO_PARENT, recipient_node_p);
}
gchar * key_b64 = g_base64_encode(encrypted_key_p, key_len);
mxml_node_t * key_node_p = mxmlNewElement(MXML_NO_PARENT, KEY_NODE_NAME);
mxml_node_t * key_node_p = mxmlNewElement(MXML_NO_PARENT, KEY_NODE_NAME);
mxmlElementSetAttr(key_node_p, KEY_NODE_RID_ATTR_NAME, device_id_string);
free(device_id_string);
if (kex)
mxmlElementSetAttr(key_node_p, KEY_NODE_KEX_ATTR_NAME, "true");
(void) mxmlNewOpaque(key_node_p, key_b64);

mxmlAdd(msg_p->header_node_p, MXML_ADD_BEFORE, MXML_ADD_TO_PARENT, key_node_p);
mxmlAdd(recipient_node_p, MXML_ADD_BEFORE, MXML_ADD_TO_PARENT, key_node_p);
g_free(key_b64);
return 0;
}

int omemo_message_export_encrypted(omemo_message * msg_p, int add_msg, char ** msg_xml) {
if (!msg_p || !msg_p->message_node_p || !msg_p->header_node_p || !msg_p->payload_node_p || !msg_xml) {
if (!msg_p || !msg_p->message_node_p || !msg_p->header_node_p || !msg_xml) {
return OMEMO_ERR_NULL;
}

Expand All @@ -1196,7 +1207,8 @@ int omemo_message_export_encrypted(omemo_message * msg_p, int add_msg, char ** m
mxmlElementSetAttr(encrypted_node_p, XMLNS_ATTR_NAME, OMEMO_NS);

mxmlAdd(encrypted_node_p, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, msg_p->header_node_p);
mxmlAdd(encrypted_node_p, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, msg_p->payload_node_p);
if (msg_p->payload_node_p)
mxmlAdd(encrypted_node_p, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, msg_p->payload_node_p);

if (add_msg == OMEMO_ADD_MSG_EME || add_msg == OMEMO_ADD_MSG_BOTH) {
eme_node_p = mxmlNewElement(msg_p->message_node_p, EME_NODE_NAME);
Expand Down Expand Up @@ -1352,19 +1364,35 @@ char * omemo_message_get_recipient_name_bare(omemo_message * msg_p) {
return jid_strip_resource(omemo_message_get_recipient_name_full(msg_p));
}

int omemo_message_get_encrypted_key(omemo_message * msg_p, uint32_t own_device_id, uint8_t ** key_pp, size_t * key_len_p ) {
int omemo_message_get_encrypted_key(omemo_message * msg_p, const char * recipient_name, uint32_t own_device_id, uint8_t ** key_pp, size_t * key_len_p ) {
if (!msg_p || !key_pp) {
return OMEMO_ERR_NULL;
}

int ret_val = 0;

gchar * recipient_name_bare = (void *) 0;
mxml_node_t * recipient_node_p = (void *) 0;
mxml_node_t * key_node_p = (void *) 0;
char * rid_string = (void *) 0;
const char * key_b64 = (void *) 0;
size_t key_len = 0;

key_node_p = mxmlFindElement(msg_p->header_node_p, msg_p->header_node_p, KEY_NODE_NAME, NULL, NULL, MXML_DESCEND);
if (recipient_name) {
recipient_name_bare = jid_strip_resource(recipient_name);
} else {
recipient_name_bare = omemo_message_get_recipient_name_bare(msg_p);
}
recipient_node_p = mxmlFindElement(msg_p->header_node_p, msg_p->header_node_p, RECIPIENT_NODE_NAME,
RECIPIENT_NODE_JID_ATTR_NAME, recipient_name_bare,MXML_DESCEND);
if (recipient_node_p) {
key_node_p = mxmlFindElement(recipient_node_p, recipient_node_p, KEY_NODE_NAME,
NULL, NULL, MXML_DESCEND);
} else {
// Assuming there is no RECIPIENT_NODEs in the message.
key_node_p = mxmlFindElement(msg_p->header_node_p, msg_p->header_node_p, KEY_NODE_NAME,
NULL, NULL, MXML_DESCEND);
}
if (!key_node_p) {
// if there is not at least one key, skip the rest of the function
ret_val = 0;
Expand Down Expand Up @@ -1405,6 +1433,7 @@ int omemo_message_get_encrypted_key(omemo_message * msg_p, uint32_t own_device_i
*key_len_p = key_len;

cleanup:
g_free(recipient_name_bare)
free(rid_string);
return ret_val;
}
Expand Down
23 changes: 13 additions & 10 deletions src/libomemo.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ int omemo_bundle_set_signed_pre_key(omemo_bundle * bundle_p, uint32_t pre_key_id
*
* @param bundle_p Pointer to the bundle.
* @param pre_key_id_p Will be set to the pre key id as returned by strtol.
* @param data_pp Will be set to a pointer to the serialized key data. Has to be free()d when done.
* @param data_pp Will be set to a pointer to the serialized key data. Has to be g_free()d when done.
* @param data_len_p Will be set to the length of the data.
* @return 0 on success, negative on error.
*/
Expand All @@ -172,7 +172,7 @@ int omemo_bundle_set_signature(omemo_bundle * bundle_p, uint8_t * data_p, size_t
* Gets the signature from the specified bundle.
*
* @param bundle_p Pointer to the bundle.
* @param data_pp Will be set to a pointer to the signature data. Has to be free()d when done.
* @param data_pp Will be set to a pointer to the signature data. Has to be g_free()d when done.
* @param data_len_p Will be set to the length of the data.
* @return 0 on succcess, negative on error.
*/
Expand All @@ -192,7 +192,7 @@ int omemo_bundle_set_identity_key(omemo_bundle * bundle_p, uint8_t * data_p, siz
* Gets the identity key from the specified bundle.
*
* @param bundle_p Pointer to the bundle.
* @param data_pp Will be set to a pointer to the identity key data. Has to be free()d when done.
* @param data_pp Will be set to a pointer to the identity key data. Has to be g_free()d when done.
* @param data_len_p Will be set to the length of the data.
* @return 0 on success, negative on error.
*/
Expand All @@ -214,7 +214,7 @@ int omemo_bundle_add_pre_key(omemo_bundle * bundle_p, uint32_t pre_key_id, uint8
*
* @param bundle_p Pointer to the bundle.
* @param pre_key_id_p Will be set to the ID of the selected pre key.
* @param data_pp Will be set to a pointer to the serialized public key data. Has to be free()d when done.
* @param data_pp Will be set to a pointer to the serialized public key data. Has to be g_free()d when done.
* @param data_len_p Will be set to the length of the data.
* @return 0 on success, negative on error.
*/
Expand Down Expand Up @@ -440,16 +440,18 @@ const uint8_t * omemo_message_get_key(omemo_message * msg_p);
size_t omemo_message_get_key_len(omemo_message * msg_p);

/**
* Add the encrypted symmetric key for a specific device id to the message.
* Add the encrypted symmetric key for a specific device to the message.
* Only makes sense on outgoing messages.
*
* @param msg_p Pointer to the message to add to.
* @param recipient_name_bare The bare JID of the recipient.
* @param device_id The recipient device ID.
* @param encrypted_key_p The encrypted key data.
* @param key_len Length of the encrypted key data.
* @param kex Whether the added key is intended for key exchange, default to 0.
* @return 0 on success, negative on error.
*/
int omemo_message_add_recipient(omemo_message * msg_p, uint32_t device_id, const uint8_t * encrypted_key_p, size_t key_len);
int omemo_message_add_recipient(omemo_message * msg_p, const char * recipient_name_bare, uint32_t device_id, const uint8_t * encrypted_key_p, size_t key_len, int kex);

/**
* After all recipients have been added, this function can be used to export the resulting <message> stanza.
Expand Down Expand Up @@ -502,7 +504,7 @@ const char * omemo_message_get_sender_name_full(omemo_message * msg_p);
* Note that there is no "from" attribute in outgoing messages.
*
* @param msg_p Pointer to the message.
* @return The bare JID. Has to be free()d.
* @return The bare JID. Has to be g_free()d.
*/
char * omemo_message_get_sender_name_bare(omemo_message * msg_p);

Expand All @@ -523,16 +525,17 @@ const char * omemo_message_get_recipient_name_full(omemo_message * msg_p);
char * omemo_message_get_recipient_name_bare(omemo_message * msg_p);

/**
* Gets the encrypted key data for a specific device ID (usually your own so you can decrypt it).
* Gets the encrypted key data for a specific device (usually your own so you can decrypt it).
*
* @param msg_p Pointer to the message.
* @param recipient_name The JID get the encrypted key for, could be 0 for the intended recipient of the message.
* @param own_device_id The device ID to get the encrypted key for.
* @param key_pp Will be set to the encrypted key data, or NULL if there is no data for the specified ID.
* Has to be free()d.
* Has to be g_free()d.
* @param key_len_p Will be set to length of encrypted key data.
* @return 0 on success, negative on error. Note that success does not mean a key was found.
*/
int omemo_message_get_encrypted_key(omemo_message * msg_p, uint32_t own_device_id, uint8_t ** key_pp, size_t * key_len_p );
int omemo_message_get_encrypted_key(omemo_message * msg_p, const char * recipient_name, uint32_t own_device_id, uint8_t ** key_pp, size_t * key_len_p );

/**
* Using the decrypted symmetric key, this method decrypts the payload and exports the original <message> stanza.
Expand Down