diff options
-rw-r--r-- | include/olm/inbound_group_session.h | 23 | ||||
-rw-r--r-- | javascript/olm_inbound_group_session.js | 15 | ||||
-rw-r--r-- | python/olm/inbound_group_session.py | 15 | ||||
-rw-r--r-- | src/inbound_group_session.c | 49 | ||||
-rw-r--r-- | src/outbound_group_session.c | 41 | ||||
-rw-r--r-- | tests/test_group_session.cpp | 39 |
6 files changed, 137 insertions, 45 deletions
diff --git a/include/olm/inbound_group_session.h b/include/olm/inbound_group_session.h index 49992b2..59146c2 100644 --- a/include/olm/inbound_group_session.h +++ b/include/olm/inbound_group_session.h @@ -95,8 +95,6 @@ size_t olm_unpickle_inbound_group_session( */ size_t olm_init_inbound_group_session( OlmInboundGroupSession *session, - uint32_t message_index, - /* base64-encoded keys */ uint8_t const * session_key, size_t session_key_length ); @@ -146,6 +144,27 @@ size_t olm_group_decrypt( ); +/** + * Get the number of bytes returned by olm_inbound_group_session_id() + */ +size_t olm_inbound_group_session_id_length( + const OlmInboundGroupSession *session +); + +/** + * Get a base64-encoded identifier for this session. + * + * Returns the length of the session id on success or olm_error() on + * failure. On failure last_error will be set with an error code. The + * last_error will be OUTPUT_BUFFER_TOO_SMALL if the id buffer was too + * small. + */ +size_t olm_inbound_group_session_id( + OlmInboundGroupSession *session, + uint8_t * id, size_t id_length +); + + #ifdef __cplusplus } // extern "C" #endif diff --git a/javascript/olm_inbound_group_session.js b/javascript/olm_inbound_group_session.js index 9722c31..6058233 100644 --- a/javascript/olm_inbound_group_session.js +++ b/javascript/olm_inbound_group_session.js @@ -52,12 +52,12 @@ InboundGroupSession.prototype['unpickle'] = restore_stack(function(key, pickle) ); }); -InboundGroupSession.prototype['create'] = restore_stack(function(message_index, session_key) { +InboundGroupSession.prototype['create'] = restore_stack(function(session_key) { var key_array = array_from_string(session_key); var key_buffer = stack(key_array); inbound_group_session_method(Module['_olm_init_inbound_group_session'])( - this.ptr, message_index, key_buffer, key_array.length + this.ptr, key_buffer, key_array.length ); }); @@ -89,4 +89,15 @@ InboundGroupSession.prototype['decrypt'] = restore_stack(function( return Pointer_stringify(plaintext_buffer); }); +InboundGroupSession.prototype['session_id'] = restore_stack(function() { + var length = inbound_group_session_method( + Module['_olm_inbound_group_session_id_length'] + )(this.ptr); + var session_id = stack(length + NULL_BYTE_PADDING_LENGTH); + inbound_group_session_method(Module['_olm_inbound_group_session_id'])( + this.ptr, session_id, length + ); + return Pointer_stringify(session_id); +}); + olm_exports['InboundGroupSession'] = InboundGroupSession; diff --git a/python/olm/inbound_group_session.py b/python/olm/inbound_group_session.py index 6c01095..d5547fd 100644 --- a/python/olm/inbound_group_session.py +++ b/python/olm/inbound_group_session.py @@ -33,7 +33,7 @@ inbound_group_session_function( ) inbound_group_session_function( - lib.olm_init_inbound_group_session, c_uint32, c_void_p, c_size_t + lib.olm_init_inbound_group_session, c_void_p, c_size_t ) inbound_group_session_function( @@ -45,6 +45,9 @@ inbound_group_session_function( c_void_p, c_size_t, # plaintext ) +inbound_group_session_function(lib.olm_inbound_group_session_id_length) +inbound_group_session_function(lib.olm_inbound_group_session_id, c_void_p, c_size_t) + class InboundGroupSession(object): def __init__(self): self.buf = create_string_buffer(lib.olm_inbound_group_session_size()) @@ -66,10 +69,10 @@ class InboundGroupSession(object): self.ptr, key_buffer, len(key), pickle_buffer, len(pickle) ) - def init(self, message_index, session_key): + def init(self, session_key): key_buffer = create_string_buffer(session_key) lib.olm_init_inbound_group_session( - self.ptr, message_index, key_buffer, len(session_key) + self.ptr, key_buffer, len(session_key) ) def decrypt(self, message): @@ -84,3 +87,9 @@ class InboundGroupSession(object): plaintext_buffer, max_plaintext_length ) return plaintext_buffer.raw[:plaintext_length] + + def session_id(self): + id_length = lib.olm_inbound_group_session_id_length(self.ptr) + id_buffer = create_string_buffer(id_length) + lib.olm_inbound_group_session_id(self.ptr, id_buffer, id_length); + return id_buffer.raw diff --git a/src/inbound_group_session.c b/src/inbound_group_session.c index 11e3dbe..bf00008 100644 --- a/src/inbound_group_session.c +++ b/src/inbound_group_session.c @@ -29,8 +29,9 @@ #define OLM_PROTOCOL_VERSION 3 +#define GROUP_SESSION_ID_LENGTH ED25519_PUBLIC_KEY_LENGTH #define PICKLE_VERSION 1 -#define SESSION_KEY_VERSION 1 +#define SESSION_KEY_VERSION 2 struct OlmInboundGroupSession { /** our earliest known ratchet value */ @@ -71,12 +72,12 @@ size_t olm_clear_inbound_group_session( } #define SESSION_KEY_RAW_LENGTH \ - (1 + MEGOLM_RATCHET_LENGTH + ED25519_PUBLIC_KEY_LENGTH) + (1 + 4 + MEGOLM_RATCHET_LENGTH + ED25519_PUBLIC_KEY_LENGTH\ + + ED25519_SIGNATURE_LENGTH) /** init the session keys from the un-base64-ed session keys */ static size_t _init_group_session_keys( OlmInboundGroupSession *session, - uint32_t message_index, const uint8_t *key_buf ) { const uint8_t *ptr = key_buf; @@ -87,19 +88,32 @@ static size_t _init_group_session_keys( return (size_t)-1; } - megolm_init(&session->initial_ratchet, ptr, message_index); - megolm_init(&session->latest_ratchet, ptr, message_index); + uint32_t counter = 0; + // Decode counter as a big endian 32-bit number. + for (unsigned i = 0; i < 4; i++) { + counter <<= 8; counter |= *ptr++; + } + + megolm_init(&session->initial_ratchet, ptr, counter); + megolm_init(&session->latest_ratchet, ptr, counter); + ptr += MEGOLM_RATCHET_LENGTH; memcpy( session->signing_key.public_key, ptr, ED25519_PUBLIC_KEY_LENGTH ); ptr += ED25519_PUBLIC_KEY_LENGTH; + + if (!_olm_crypto_ed25519_verify( + &session->signing_key, key_buf, ptr - key_buf, ptr + )) { + session->last_error = OLM_BAD_SIGNATURE; + return (size_t)-1; + } return 0; } size_t olm_init_inbound_group_session( OlmInboundGroupSession *session, - uint32_t message_index, const uint8_t * session_key, size_t session_key_length ) { uint8_t key_buf[SESSION_KEY_RAW_LENGTH]; @@ -117,7 +131,7 @@ size_t olm_init_inbound_group_session( } _olm_decode_base64(session_key, session_key_length, key_buf); - result = _init_group_session_keys(session, message_index, key_buf); + result = _init_group_session_keys(session, key_buf); _olm_unset(key_buf, SESSION_KEY_RAW_LENGTH); return result; } @@ -288,7 +302,6 @@ static size_t _decrypt( return (size_t)-1; } - max_length = megolm_cipher->ops->decrypt_max_plaintext_length( megolm_cipher, decoded_results.ciphertext_length @@ -351,3 +364,23 @@ size_t olm_group_decrypt( plaintext, max_plaintext_length ); } + +size_t olm_inbound_group_session_id_length( + const OlmInboundGroupSession *session +) { + return _olm_encode_base64_length(GROUP_SESSION_ID_LENGTH); +} + +size_t olm_inbound_group_session_id( + OlmInboundGroupSession *session, + uint8_t * id, size_t id_length +) { + if (id_length < olm_inbound_group_session_id_length(session)) { + session->last_error = OLM_OUTPUT_BUFFER_TOO_SMALL; + return (size_t)-1; + } + + return _olm_encode_base64( + session->signing_key.public_key, GROUP_SESSION_ID_LENGTH, id + ); +} diff --git a/src/outbound_group_session.c b/src/outbound_group_session.c index a605fa6..4e4561a 100644 --- a/src/outbound_group_session.c +++ b/src/outbound_group_session.c @@ -29,10 +29,9 @@ #include "olm/pickle_encoding.h" #define OLM_PROTOCOL_VERSION 3 -#define SESSION_ID_RANDOM_BYTES 4 -#define GROUP_SESSION_ID_LENGTH (sizeof(struct timeval) + SESSION_ID_RANDOM_BYTES) +#define GROUP_SESSION_ID_LENGTH ED25519_PUBLIC_KEY_LENGTH #define PICKLE_VERSION 1 -#define SESSION_KEY_VERSION 1 +#define SESSION_KEY_VERSION 2 struct OlmOutboundGroupSession { /** the Megolm ratchet providing the encryption keys */ @@ -41,9 +40,6 @@ struct OlmOutboundGroupSession { /** The ed25519 keypair used for signing the messages */ struct _olm_ed25519_key_pair signing_key; - /** unique identifier for this session */ - uint8_t session_id[GROUP_SESSION_ID_LENGTH]; - enum OlmErrorCode last_error; }; @@ -80,8 +76,6 @@ static size_t raw_pickle_length( length += _olm_pickle_uint32_length(PICKLE_VERSION); length += megolm_pickle_length(&(session->ratchet)); length += _olm_pickle_ed25519_key_pair_length(&(session->signing_key)); - length += _olm_pickle_bytes_length(session->session_id, - GROUP_SESSION_ID_LENGTH); return length; } @@ -108,7 +102,6 @@ size_t olm_pickle_outbound_group_session( pos = _olm_pickle_uint32(pos, PICKLE_VERSION); pos = megolm_pickle(&(session->ratchet), pos); pos = _olm_pickle_ed25519_key_pair(pos, &(session->signing_key)); - pos = _olm_pickle_bytes(pos, session->session_id, GROUP_SESSION_ID_LENGTH); return _olm_enc_output(key, key_length, pickled, raw_length); } @@ -138,7 +131,6 @@ size_t olm_unpickle_outbound_group_session( } pos = megolm_unpickle(&(session->ratchet), pos, end); pos = _olm_unpickle_ed25519_key_pair(pos, end, &(session->signing_key)); - pos = _olm_unpickle_bytes(pos, end, session->session_id, GROUP_SESSION_ID_LENGTH); if (end != pos) { /* We had the wrong number of bytes in the input. */ @@ -157,8 +149,7 @@ size_t olm_init_outbound_group_session_random_length( * session id. */ return MEGOLM_RATCHET_LENGTH + - ED25519_RANDOM_LENGTH + - SESSION_ID_RANDOM_BYTES; + ED25519_RANDOM_LENGTH; } size_t olm_init_outbound_group_session( @@ -177,13 +168,6 @@ size_t olm_init_outbound_group_session( _olm_crypto_ed25519_generate_key(random, &(session->signing_key)); random += ED25519_RANDOM_LENGTH; - /* initialise the session id. This just has to be unique. We use the - * current time plus some random data. - */ - gettimeofday((struct timeval *)(session->session_id), NULL); - memcpy((session->session_id) + sizeof(struct timeval), - random, SESSION_ID_RANDOM_BYTES); - return 0; } @@ -314,7 +298,9 @@ size_t olm_outbound_group_session_id( return (size_t)-1; } - return _olm_encode_base64(session->session_id, GROUP_SESSION_ID_LENGTH, id); + return _olm_encode_base64( + session->signing_key.public_key.public_key, GROUP_SESSION_ID_LENGTH, id + ); } uint32_t olm_outbound_group_session_message_index( @@ -324,7 +310,8 @@ uint32_t olm_outbound_group_session_message_index( } #define SESSION_KEY_RAW_LENGTH \ - (1 + MEGOLM_RATCHET_LENGTH + ED25519_PUBLIC_KEY_LENGTH) + (1 + 4 + MEGOLM_RATCHET_LENGTH + ED25519_PUBLIC_KEY_LENGTH\ + + ED25519_SIGNATURE_LENGTH) size_t olm_outbound_group_session_key_length( const OlmOutboundGroupSession *session @@ -349,6 +336,12 @@ size_t olm_outbound_group_session_key( raw = ptr = key + encoded_length - SESSION_KEY_RAW_LENGTH; *ptr++ = SESSION_KEY_VERSION; + uint32_t counter = session->ratchet.counter; + // Encode counter as a big endian 32-bit number. + for (unsigned i = 0; i < 4; i++) { + *ptr++ = 0xFF & (counter >> 24); counter <<= 8; + } + memcpy(ptr, megolm_get_data(&session->ratchet), MEGOLM_RATCHET_LENGTH); ptr += MEGOLM_RATCHET_LENGTH; @@ -358,5 +351,11 @@ size_t olm_outbound_group_session_key( ); ptr += ED25519_PUBLIC_KEY_LENGTH; + /* sign the whole thing with the ed25519 key. */ + _olm_crypto_ed25519_sign( + &(session->signing_key), + raw, ptr - raw, ptr + ); + return _olm_encode_base64(raw, SESSION_KEY_RAW_LENGTH, key); } diff --git a/tests/test_group_session.cpp b/tests/test_group_session.cpp index 7ac91c3..9930927 100644 --- a/tests/test_group_session.cpp +++ b/tests/test_group_session.cpp @@ -97,7 +97,7 @@ int main() { uint8_t memory[size]; OlmOutboundGroupSession *session = olm_outbound_group_session(memory); - assert_equals((size_t)164, + assert_equals((size_t)160, olm_init_outbound_group_session_random_length(session)); size_t res = olm_init_outbound_group_session( @@ -130,9 +130,29 @@ int main() { olm_inbound_group_session(inbound_session_memory); res = olm_init_inbound_group_session( - inbound_session, 0U, session_key, session_key_len); + inbound_session, session_key, session_key_len); assert_equals((size_t)0, res); + + /* Check the session ids */ + + size_t out_session_id_len = olm_outbound_group_session_id_length(session); + uint8_t out_session_id[out_session_id_len]; + assert_equals(out_session_id_len, olm_outbound_group_session_id( + session, out_session_id, out_session_id_len + )); + + size_t in_session_id_len = olm_inbound_group_session_id_length( + inbound_session + ); + uint8_t in_session_id[in_session_id_len]; + assert_equals(in_session_id_len, olm_inbound_group_session_id( + inbound_session, in_session_id, in_session_id_len + )); + + assert_equals(in_session_id_len, out_session_id_len); + assert_equals(out_session_id, in_session_id, in_session_id_len); + /* decode the message */ /* olm_group_decrypt_max_plaintext_length destroys the input so we have to @@ -154,14 +174,15 @@ int main() { size_t plaintext_length = sizeof(plaintext) - 1; uint8_t session_key[] = - "ATAxMjM0NTY3ODlBQkRFRjAxMjM0NTY3ODlBQkNERUYwMTIzNDU2Nzg5QUJERUYw" - "MTIzNDU2Nzg5QUJDREVGMDEyMzQ1Njc4OUFCREVGMDEyMzQ1Njc4OUFCQ0RFRjAx" - "MjM0NTY3ODlBQkRFRjAxMjM0NTY3ODlBQkNERUYwMTIzDRt2DUEOrg/H+yUGjDTq" - "ryf8H1YF/BZjI04HwOVSZcY"; + "AgAAAAAwMTIzNDU2Nzg5QUJERUYwMTIzNDU2Nzg5QUJDREVGMDEyMzQ1Njc4OUFCREVGM" + "DEyMzQ1Njc4OUFCQ0RFRjAxMjM0NTY3ODlBQkRFRjAxMjM0NTY3ODlBQkNERUYwMTIzND" + "U2Nzg5QUJERUYwMTIzNDU2Nzg5QUJDREVGMDEyMztqJ7zOtqQtYqOo0CpvDXNlMhV3HeJ" + "DpjrASKGLWdop4lx1cSN3Xv1TgfLPW8rhGiW+hHiMxd36nRuxscNv9k4oJA/KP+o0mi1w" + "v44StrEJ1wwx9WZHBUIWkQbaBSuBDw"; uint8_t message[] = - "AwgAEhAcbh6UpbByoyZxufQ+h2B+8XHMjhR69G8F4+qjMaFlnIXusJZX3r8LnROR" - "G9T3DXFdbVuvIWrLyRfm4i8QRbe8VPwGRFG57B1CtmxanuP8bHtnnYqlwPsD"; + "AwgAEhAcbh6UpbByoyZxufQ+h2B+8XHMjhR69G8nP4pNZGl/3QMgrzCZPmP+F2aPLyKPz" + "xRPBMUkeXRJ6Iqm5NeOdx2eERgTW7P20CM+lL3Xpk+ZUOOPvsSQNaAL"; size_t msglen = sizeof(message)-1; /* build the inbound session */ @@ -171,7 +192,7 @@ int main() { olm_inbound_group_session(inbound_session_memory); size_t res = olm_init_inbound_group_session( - inbound_session, 0U, session_key, sizeof(session_key)-1 + inbound_session, session_key, sizeof(session_key)-1 ); assert_equals((size_t)0, res); |