diff options
author | Hubert Chathi <hubert@uhoreg.ca> | 2020-08-14 17:29:25 -0400 |
---|---|---|
committer | Hubert Chathi <hubert@uhoreg.ca> | 2020-08-14 17:29:41 -0400 |
commit | 171044f3fca084bd1c5c1f8f4bfe146434b07f0b (patch) | |
tree | e0d81cc51b02e46bfae638203744f846ec41e380 /src | |
parent | a0284c2ba36ac8433ea752e93b4a0a331a3f0c0b (diff) |
add support for fallback keys
Diffstat (limited to 'src')
-rw-r--r-- | src/account.cpp | 100 | ||||
-rw-r--r-- | src/olm.cpp | 36 |
2 files changed, 135 insertions, 1 deletions
diff --git a/src/account.cpp b/src/account.cpp index 05e8134..a747677 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -21,6 +21,11 @@ olm::Account::Account( ) : next_one_time_key_id(0), last_error(OlmErrorCode::OLM_SUCCESS) { + // since we don't need to keep track of whether the fallback keys are + // published, use the published flag as in indication for whether the keys + // were generated + current_fallback_key.published = false; + prev_fallback_key.published = false; } @@ -32,6 +37,14 @@ olm::OneTimeKey const * olm::Account::lookup_key( return &key; } } + if (current_fallback_key.published + && olm::array_equal(current_fallback_key.key.public_key.public_key, public_key.public_key)) { + return ¤t_fallback_key; + } + if (prev_fallback_key.published + && olm::array_equal(prev_fallback_key.key.public_key.public_key, public_key.public_key)) { + return &prev_fallback_key; + } return 0; } @@ -46,6 +59,16 @@ std::size_t olm::Account::remove_key( return id; } } + // check if the key is a fallback key, to avoid returning an error, but + // don't actually remove it + if (current_fallback_key.published + && olm::array_equal(current_fallback_key.key.public_key.public_key, public_key.public_key)) { + return current_fallback_key.id; + } + if (prev_fallback_key.published + && olm::array_equal(prev_fallback_key.key.public_key.public_key, public_key.public_key)) { + return prev_fallback_key.id; + } return std::size_t(-1); } @@ -260,6 +283,67 @@ std::size_t olm::Account::generate_one_time_keys( return number_of_keys; } +std::size_t olm::Account::generate_fallback_key_random_length() { + return CURVE25519_RANDOM_LENGTH; +} + +std::size_t olm::Account::generate_fallback_key( + std::uint8_t const * random, std::size_t random_length +) { + if (random_length < generate_fallback_key_random_length()) { + last_error = OlmErrorCode::OLM_NOT_ENOUGH_RANDOM; + return std::size_t(-1); + } + prev_fallback_key = current_fallback_key; + current_fallback_key.id = ++next_one_time_key_id; + current_fallback_key.published = true; + _olm_crypto_curve25519_generate_key(random, ¤t_fallback_key.key); + return 1; +} + + +std::size_t olm::Account::get_fallback_key_json_length( +) { + std::size_t length = 4 + sizeof(KEY_JSON_CURVE25519); /* {"curve25519":{}} */ + OneTimeKey & key = current_fallback_key; + if (key.published) { + length += 1; /* " */ + length += olm::encode_base64_length(_olm_pickle_uint32_length(key.id)); + length += 3; /* ":" */ + length += olm::encode_base64_length(sizeof(key.key.public_key)); + length += 1; /* " */ + } + return length; +} + +std::size_t olm::Account::get_fallback_key_json( + std::uint8_t * fallback_json, std::size_t fallback_json_length +) { + std::uint8_t * pos = fallback_json; + if (fallback_json_length < get_fallback_key_json_length()) { + last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL; + return std::size_t(-1); + } + *(pos++) = '{'; + pos = write_string(pos, KEY_JSON_CURVE25519); + *(pos++) = '{'; + OneTimeKey & key = current_fallback_key; + if (key.published) { + *(pos++) = '\"'; + std::uint8_t key_id[_olm_pickle_uint32_length(key.id)]; + _olm_pickle_uint32(key_id, key.id); + pos = olm::encode_base64(key_id, sizeof(key_id), pos); + *(pos++) = '\"'; *(pos++) = ':'; *(pos++) = '\"'; + pos = olm::encode_base64( + key.key.public_key.public_key, sizeof(key.key.public_key.public_key), pos + ); + *(pos++) = '\"'; + } + *(pos++) = '}'; + *(pos++) = '}'; + return pos - fallback_json; +} + namespace olm { static std::size_t pickle_length( @@ -329,7 +413,8 @@ static std::uint8_t const * unpickle( namespace { // pickle version 1 used only 32 bytes for the ed25519 private key. // Any keys thus used should be considered compromised. -static const std::uint32_t ACCOUNT_PICKLE_VERSION = 2; +// pickle version 2 does not have fallback keys. +static const std::uint32_t ACCOUNT_PICKLE_VERSION = 3; } @@ -340,6 +425,8 @@ std::size_t olm::pickle_length( length += olm::pickle_length(ACCOUNT_PICKLE_VERSION); length += olm::pickle_length(value.identity_keys); length += olm::pickle_length(value.one_time_keys); + length += olm::pickle_length(value.current_fallback_key); + length += olm::pickle_length(value.prev_fallback_key); length += olm::pickle_length(value.next_one_time_key_id); return length; } @@ -352,6 +439,8 @@ std::uint8_t * olm::pickle( pos = olm::pickle(pos, ACCOUNT_PICKLE_VERSION); pos = olm::pickle(pos, value.identity_keys); pos = olm::pickle(pos, value.one_time_keys); + pos = olm::pickle(pos, value.current_fallback_key); + pos = olm::pickle(pos, value.prev_fallback_key); pos = olm::pickle(pos, value.next_one_time_key_id); return pos; } @@ -365,6 +454,7 @@ std::uint8_t const * olm::unpickle( pos = olm::unpickle(pos, end, pickle_version); switch (pickle_version) { case ACCOUNT_PICKLE_VERSION: + case 2: break; case 1: value.last_error = OlmErrorCode::OLM_BAD_LEGACY_ACCOUNT_PICKLE; @@ -375,6 +465,14 @@ std::uint8_t const * olm::unpickle( } pos = olm::unpickle(pos, end, value.identity_keys); pos = olm::unpickle(pos, end, value.one_time_keys); + if (pickle_version == 2) { + // version 2 did not have fallback keys + value.current_fallback_key.published = false; + value.prev_fallback_key.published = false; + } else { + pos = olm::unpickle(pos, end, value.current_fallback_key); + pos = olm::unpickle(pos, end, value.prev_fallback_key); + } pos = olm::unpickle(pos, end, value.next_one_time_key_id); return pos; } diff --git a/src/olm.cpp b/src/olm.cpp index 0333b10..50742cc 100644 --- a/src/olm.cpp +++ b/src/olm.cpp @@ -417,6 +417,42 @@ size_t olm_account_generate_one_time_keys( } +size_t olm_account_generate_fallback_key_random_length( + OlmAccount * account +) { + return from_c(account)->generate_fallback_key_random_length(); +} + + +size_t olm_account_generate_fallback_key( + OlmAccount * account, + void * random, size_t random_length +) { + size_t result = from_c(account)->generate_fallback_key( + from_c(random), random_length + ); + olm::unset(random, random_length); + return result; +} + + +size_t olm_account_fallback_key_length( + OlmAccount * account +) { + return from_c(account)->get_fallback_key_json_length(); +} + + +size_t olm_account_fallback_key( + OlmAccount * account, + void * fallback_key_json, size_t fallback_key_json_length +) { + return from_c(account)->get_fallback_key_json( + from_c(fallback_key_json), fallback_key_json_length + ); +} + + size_t olm_create_outbound_session_random_length( OlmSession * session ) { |