aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHubert Chathi <hubert@uhoreg.ca>2020-08-14 17:29:25 -0400
committerHubert Chathi <hubert@uhoreg.ca>2020-08-14 17:29:41 -0400
commit171044f3fca084bd1c5c1f8f4bfe146434b07f0b (patch)
treee0d81cc51b02e46bfae638203744f846ec41e380 /src
parenta0284c2ba36ac8433ea752e93b4a0a331a3f0c0b (diff)
add support for fallback keys
Diffstat (limited to 'src')
-rw-r--r--src/account.cpp100
-rw-r--r--src/olm.cpp36
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 &current_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, &current_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
) {