diff --git a/src/client_callbacks.c b/src/client_callbacks.c index 71d3a07c..688d3f73 100644 --- a/src/client_callbacks.c +++ b/src/client_callbacks.c @@ -30,7 +30,8 @@ otrng_client_callbacks_ensure_needed_exist(const otrng_client_callbacks_s *cb) { cb->create_client_profile != NULL && cb->store_expired_client_profile != NULL && cb->create_prekey_profile != NULL && - cb->write_expired_prekey_profile != NULL && + cb->store_expired_prekey_profile != NULL && + cb->load_expired_prekey_profile != NULL && cb->get_shared_session_state != NULL && cb->display_error_message != NULL && cb->load_privkey_v4 != NULL && cb->load_client_profile != NULL && cb->load_prekey_profile != NULL && diff --git a/src/client_callbacks.h b/src/client_callbacks.h index d09d33cf..444810d1 100644 --- a/src/client_callbacks.h +++ b/src/client_callbacks.h @@ -85,13 +85,14 @@ typedef struct otrng_client_callbacks_s { void (*load_expired_client_profile)(struct otrng_client_s *client); /* REQUIRED */ - void (*create_prekey_profile)(struct otrng_client_s *client, - const struct otrng_client_id_s client_opdata); + void (*store_expired_prekey_profile)(struct otrng_client_s *client); + + /* REQUIRED */ + void (*load_expired_prekey_profile)(struct otrng_client_s *client); /* REQUIRED */ - void (*write_expired_prekey_profile)( - struct otrng_client_s *client, - const struct otrng_client_id_s client_opdata); + void (*create_prekey_profile)(struct otrng_client_s *client, + const struct otrng_client_id_s client_opdata); /* OPTIONAL */ void (*gone_secure)(const struct otrng_s *); diff --git a/src/client_orchestration.c b/src/client_orchestration.c index 68f749dc..5277377c 100644 --- a/src/client_orchestration.c +++ b/src/client_orchestration.c @@ -70,6 +70,12 @@ tstatic void load_expired_client_profile_from_storage(otrng_client_s *client) { otrng_debug_exit("orchestration.load_expired_client_profile_from_storage"); } +tstatic void load_expired_prekey_profile_from_storage(otrng_client_s *client) { + otrng_debug_enter("orchestration.load_expired_prekey_profile_from_storage"); + client->global_state->callbacks->load_expired_prekey_profile(client); + otrng_debug_exit("orchestration.load_expired_prekey_profile_from_storage"); +} + tstatic void create_client_profile(otrng_client_s *client) { otrng_debug_enter("orchestration.create_client_profile"); client->global_state->callbacks->create_client_profile(client, @@ -119,6 +125,13 @@ tstatic void clean_expired_client_profile(otrng_client_s *client) { } } +tstatic void clean_expired_prekey_profile(otrng_client_s *client) { + if (client->exp_prekey_profile != NULL) { + otrng_prekey_profile_free(client->exp_prekey_profile); + client->exp_prekey_profile = NULL; + } +} + tstatic void clean_prekey_profile(otrng_client_s *client) { if (client->prekey_profile != NULL) { otrng_prekey_profile_free(client->prekey_profile); @@ -236,6 +249,19 @@ tstatic otrng_bool verify_valid_expired_client_profile(otrng_client_s *client) { client->exp_client_profile, itag, client->profiles_extra_valid_time); } +tstatic otrng_bool verify_valid_expired_prekey_profile(otrng_client_s *client) { + uint32_t itag; + + if (client->exp_prekey_profile == NULL) { + return otrng_false; + } + + itag = otrng_client_get_instance_tag(client); + return otrng_prekey_profile_is_expired_but_valid( + client->exp_prekey_profile, itag, client->profiles_extra_valid_time, + client->keypair->pub); +} + tstatic otrng_bool verify_valid_prekey_profile(otrng_client_s *client) { uint32_t instag; @@ -263,6 +289,21 @@ tstatic void move_client_profile_to_expired(otrng_client_s *client) { otrng_debug_exit("move_client_profile_to_expired"); } +tstatic void move_prekey_profile_to_expired(otrng_client_s *client) { + otrng_debug_enter("move_prekey_profile_to_expired"); + + if (client->exp_prekey_profile) { + otrng_prekey_profile_free(client->exp_prekey_profile); + client->exp_prekey_profile = NULL; + } + client->exp_prekey_profile = client->prekey_profile; + client->prekey_profile = NULL; + + client->global_state->callbacks->store_expired_prekey_profile(client); + + otrng_debug_exit("move_prekey_profile_to_expired"); +} + tstatic void check_if_expired_client_profile(otrng_client_s *client) { uint32_t itag; if (client->client_profile) { @@ -274,6 +315,18 @@ tstatic void check_if_expired_client_profile(otrng_client_s *client) { } } +tstatic void check_if_expired_prekey_profile(otrng_client_s *client) { + uint32_t itag; + if (client->prekey_profile) { + itag = otrng_client_get_instance_tag(client); + if (otrng_prekey_profile_is_expired_but_valid( + client->prekey_profile, itag, client->profiles_extra_valid_time, + client->keypair->pub)) { + move_prekey_profile_to_expired(client); + } + } +} + tstatic otrng_bool check_if_close_to_expired_client_profile(otrng_client_s *client) { if (otrng_client_profile_is_close_to_expiry(client->client_profile, @@ -284,6 +337,16 @@ check_if_close_to_expired_client_profile(otrng_client_s *client) { return otrng_true; } +tstatic otrng_bool +check_if_close_to_expired_prekey_profile(otrng_client_s *client) { + if (otrng_prekey_profile_is_close_to_expiry(client->prekey_profile, + client->profiles_buffer_time)) { + move_prekey_profile_to_expired(client); + return otrng_false; + } + return otrng_true; +} + tstatic void ensure_valid_client_profile(otrng_client_s *client) { if (verify_valid_client_profile(client)) { return; @@ -316,9 +379,7 @@ tstatic void ensure_valid_client_profile(otrng_client_s *client) { } tstatic void ensure_valid_expired_client_profile(otrng_client_s *client) { - otrng_debug_enter("verify_valid_expired_client_profile"); if (verify_valid_expired_client_profile(client)) { - otrng_debug_exit("verify_valid_expired_client_profile.exit.1"); return; } @@ -326,13 +387,27 @@ tstatic void ensure_valid_expired_client_profile(otrng_client_s *client) { load_expired_client_profile_from_storage(client); if (verify_valid_expired_client_profile(client)) { - otrng_debug_exit("verify_valid_expired_client_profile.exit.2"); return; } clean_expired_client_profile(client); client->global_state->callbacks->store_expired_client_profile(client); - otrng_debug_exit("verify_valid_expired_client_profile.exit.3"); +} + +tstatic void ensure_valid_expired_prekey_profile(otrng_client_s *client) { + if (verify_valid_expired_prekey_profile(client)) { + return; + } + + clean_expired_prekey_profile(client); + load_expired_prekey_profile_from_storage(client); + + if (verify_valid_expired_prekey_profile(client)) { + return; + } + + clean_expired_prekey_profile(client); + client->global_state->callbacks->store_expired_prekey_profile(client); } tstatic void ensure_valid_prekey_profile(otrng_client_s *client) { @@ -342,9 +417,12 @@ tstatic void ensure_valid_prekey_profile(otrng_client_s *client) { clean_prekey_profile(client); load_prekey_profile_from_storage(client); + check_if_expired_prekey_profile(client); if (verify_valid_prekey_profile(client)) { - return; + if (!check_if_close_to_expired_prekey_profile(client)) { + return; + } } clean_prekey_profile(client); @@ -439,9 +517,7 @@ API void otrng_client_ensure_correct_state(otrng_client_s *client) { ensure_valid_client_profile(client); ensure_valid_expired_client_profile(client); ensure_valid_prekey_profile(client); - - // TODO: @ola here we should check if the prekeyprofile is close to expiring, - // and in that case move it to the expired part and create a new one + ensure_valid_expired_prekey_profile(client); ensure_enough_prekey_messages(client); diff --git a/src/persistence.c b/src/persistence.c index 41c7247e..3461016d 100644 --- a/src/persistence.c +++ b/src/persistence.c @@ -723,15 +723,6 @@ otrng_client_prekey_profile_read_from(otrng_client_s *client, FILE *profilef) { return result; } - if (otrng_prekey_profile_expired(profile.expires)) { - client->global_state->callbacks->write_expired_prekey_profile( - client, client->client_id); - - // TODO: I'm suspecting this will make a lot of tests fail, so - // no return for the moment - // return OTRNG_SUCCESS; - } - otrng_prekey_profile_free(client->prekey_profile); client->prekey_profile = NULL; diff --git a/src/prekey_profile.c b/src/prekey_profile.c index 7f2ae0e0..ff106f61 100644 --- a/src/prekey_profile.c +++ b/src/prekey_profile.c @@ -370,7 +370,7 @@ INTERNAL otrng_bool otrng_prekey_profile_invalid(time_t expires, return difftime(expires + extra_valid_time, time(NULL)) <= 0; } -INTERNAL otrng_bool otrng_prekey_profile_valid( +tstatic otrng_bool otrng_prekey_profile_valid_without_expiry( const otrng_prekey_profile_s *profile, const uint32_t sender_instance_tag, const otrng_public_key pub) { /* 1. Verify that the Prekey Profile signature is valid. */ @@ -385,12 +385,7 @@ INTERNAL otrng_bool otrng_prekey_profile_valid( return otrng_false; } - /* 3. Verify that the Prekey Profile has not expired. */ - if (otrng_prekey_profile_expired(profile->expires)) { - return otrng_false; - } - - /* 4. Validate that the Public Shared Prekey is on the curve Ed448-Goldilocks. + /* 3. Validate that the Public Shared Prekey is on the curve Ed448-Goldilocks. */ if (!otrng_ec_point_valid(profile->shared_prekey)) { return otrng_false; @@ -399,6 +394,33 @@ INTERNAL otrng_bool otrng_prekey_profile_valid( return otrng_true; } +INTERNAL otrng_bool otrng_prekey_profile_valid( + const otrng_prekey_profile_s *profile, const uint32_t sender_instance_tag, + const otrng_public_key pub) { + if (!otrng_prekey_profile_valid_without_expiry(profile, sender_instance_tag, + pub)) { + return otrng_false; + } + + return !otrng_prekey_profile_expired(profile->expires); +} + +/* This function should be called on a profile that is valid - it + assumes this, and doesn't verify it. */ +INTERNAL otrng_bool otrng_prekey_profile_is_close_to_expiry( + const otrng_prekey_profile_s *profile, uint64_t buffer_time) { + return otrng_prekey_profile_expired(profile->expires + buffer_time); +} + +INTERNAL otrng_bool otrng_prekey_profile_is_expired_but_valid( + const otrng_prekey_profile_s *profile, const uint32_t sender_instance_tag, + uint64_t extra_valid_time, const otrng_public_key pub) { + return otrng_prekey_profile_valid_without_expiry(profile, sender_instance_tag, + pub) && + otrng_prekey_profile_expired(profile->expires) && + !otrng_prekey_profile_invalid(profile->expires, extra_valid_time); +} + API void otrng_prekey_profile_start_publishing(otrng_prekey_profile_s *profile) { profile->is_publishing = otrng_true; diff --git a/src/prekey_profile.h b/src/prekey_profile.h index e3aaf004..3343d88c 100644 --- a/src/prekey_profile.h +++ b/src/prekey_profile.h @@ -54,6 +54,13 @@ INTERNAL otrng_bool otrng_prekey_profile_expired(time_t expires); INTERNAL otrng_bool otrng_prekey_profile_invalid(time_t expires, uint64_t extra_valid_time); +INTERNAL otrng_bool otrng_prekey_profile_is_close_to_expiry( + const otrng_prekey_profile_s *profile, uint64_t buffer_time); + +INTERNAL otrng_bool otrng_prekey_profile_is_expired_but_valid( + const otrng_prekey_profile_s *profile, uint32_t itag, + uint64_t extra_valid_time, const otrng_public_key pub); + INTERNAL otrng_bool otrng_prekey_profile_valid( const otrng_prekey_profile_s *profile, const uint32_t sender_instance_tag, const otrng_public_key pub); diff --git a/src/test/test_fixtures.c b/src/test/test_fixtures.c index 3ea45271..f28e63bb 100644 --- a/src/test/test_fixtures.c +++ b/src/test/test_fixtures.c @@ -141,7 +141,7 @@ otrng_client_callbacks_s test_callbacks[1] = {{ .create_client_profile = &create_client_profile_cb, .store_expired_client_profile = &write_expired_client_profile_cb_empty, .create_prekey_profile = &create_prekey_profile_cb, - .write_expired_prekey_profile = &write_expired_prekey_profile_cb_empty, + .store_expired_prekey_profile = &write_expired_prekey_profile_cb_empty, .get_shared_session_state = &get_shared_session_state_cb, .display_error_message = &display_error_message_cb, .load_privkey_v4 = &load_privkey_v4_cb_empty, @@ -442,11 +442,8 @@ void create_prekey_profile_cb_empty( (void)client_opdata; } -void write_expired_prekey_profile_cb_empty( - struct otrng_client_s *client, - const struct otrng_client_id_s client_opdata) { +void write_expired_prekey_profile_cb_empty(struct otrng_client_s *client) { (void)client; - (void)client_opdata; } otrng_shared_session_state_s diff --git a/src/test/test_fixtures.h b/src/test/test_fixtures.h index dcc9aa1d..aae71809 100644 --- a/src/test/test_fixtures.h +++ b/src/test/test_fixtures.h @@ -101,9 +101,7 @@ void create_prekey_profile_cb_empty( struct otrng_client_s *client, const struct otrng_client_id_s client_opdata); -void write_expired_prekey_profile_cb_empty( - struct otrng_client_s *client, - const struct otrng_client_id_s client_opdata); +void write_expired_prekey_profile_cb_empty(struct otrng_client_s *client); void create_shared_prekey_cb_empty( struct otrng_client_s *client, diff --git a/src/test/units/test_messaging.c b/src/test/units/test_messaging.c index a15af007..fb560819 100644 --- a/src/test/units/test_messaging.c +++ b/src/test/units/test_messaging.c @@ -65,7 +65,7 @@ static otrng_client_callbacks_s empty_callbacks[1] = {{ .create_privkey_v4 = &create_privkey_v4_cb_empty, .create_forging_key = &create_forging_key_cb_empty, .store_expired_client_profile = &write_expired_client_profile_cb_empty, - .write_expired_prekey_profile = &write_expired_prekey_profile_cb_empty, + .store_expired_prekey_profile = &write_expired_prekey_profile_cb_empty, .display_error_message = &display_error_message_cb_empty, .load_privkey_v4 = &load_privkey_v4_cb_empty, .load_client_profile = &load_client_profile_cb_empty,