Pre-check DH parameters.

GitOrigin-RevId: 98a488559b95651eab0c43b747a1f1fae2b716a5
This commit is contained in:
levlam 2018-08-09 23:41:01 +03:00
parent 466ebd2908
commit 73aa76dc5f
6 changed files with 29 additions and 20 deletions

View File

@ -54,13 +54,14 @@ class HandshakeBench : public Benchmark {
DhHandshake a; DhHandshake a;
DhHandshake b; DhHandshake b;
auto prime = base64url_decode(prime_base64).move_as_ok(); auto prime = base64url_decode(prime_base64).move_as_ok();
DhHandshake::check_config(g, prime, &dh_callback).ensure();
for (int i = 0; i < n; i += 2) { for (int i = 0; i < n; i += 2) {
a.set_config(g, prime); a.set_config(g, prime);
b.set_config(g, prime); b.set_config(g, prime);
b.set_g_a(a.get_g_b()); b.set_g_a(a.get_g_b());
a.set_g_a(b.get_g_b()); a.set_g_a(b.get_g_b());
a.run_checks(&dh_callback).ensure(); a.run_checks(true, &dh_callback).ensure();
b.run_checks(&dh_callback).ensure(); b.run_checks(true, &dh_callback).ensure();
auto a_key = a.gen_key(); auto a_key = a.gen_key();
auto b_key = b.gen_key(); auto b_key = b.gen_key();
CHECK(a_key.first == b_key.first); CHECK(a_key.first == b_key.first);

View File

@ -208,10 +208,7 @@ Status DhHandshake::check_config(Slice prime_str, const BigNum &prime, int32 g_i
return Status::OK(); return Status::OK();
} }
Status DhHandshake::dh_check(Slice prime_str, const BigNum &prime, int32 g_int, const BigNum &g_a, const BigNum &g_b, Status DhHandshake::dh_check(const BigNum &prime, const BigNum &g_a, const BigNum &g_b) {
BigNumContext &ctx, DhCallback *callback) {
TRY_STATUS(check_config(prime_str, prime, g_int, ctx, callback));
// IMPORTANT: Apart from the conditions on the Diffie-Hellman prime dh_prime and generator g, both sides are // IMPORTANT: Apart from the conditions on the Diffie-Hellman prime dh_prime and generator g, both sides are
// to check that g, g_a and g_b are greater than 1 and less than dh_prime - 1. // to check that g, g_a and g_b are greater than 1 and less than dh_prime - 1.
// We recommend checking that g_a and g_b are between 2^{2048-64} and dh_prime - 2^{2048-64} as well. // We recommend checking that g_a and g_b are between 2^{2048-64} and dh_prime - 2^{2048-64} as well.
@ -305,14 +302,18 @@ string DhHandshake::get_g_b_hash() const {
return g_b_hash; return g_b_hash;
} }
Status DhHandshake::run_checks(DhCallback *callback) { Status DhHandshake::run_checks(bool skip_config_check, DhCallback *callback) {
CHECK(has_g_a_ && has_config_); CHECK(has_g_a_ && has_config_);
if (has_g_a_hash_ && !ok_g_a_hash_) { if (has_g_a_hash_ && !ok_g_a_hash_) {
return Status::Error("g_a_hash mismatch"); return Status::Error("g_a_hash mismatch");
} }
return dh_check(prime_str_, prime_, g_int_, g_a_, g_b_, ctx_, callback); if (!skip_config_check) {
TRY_STATUS(check_config(prime_str_, prime_, g_int_, ctx_, callback));
}
return dh_check(prime_, g_a_, g_b_);
} }
BigNum DhHandshake::get_g() const { BigNum DhHandshake::get_g() const {
@ -354,7 +355,7 @@ Status dh_handshake(int g_int, Slice prime_str, Slice g_a_str, string *g_b_str,
DhHandshake handshake; DhHandshake handshake;
handshake.set_config(g_int, prime_str); handshake.set_config(g_int, prime_str);
handshake.set_g_a(g_a_str); handshake.set_g_a(g_a_str);
TRY_STATUS(handshake.run_checks(callback)); TRY_STATUS(handshake.run_checks(false, callback));
*g_b_str = handshake.get_g_b(); *g_b_str = handshake.get_g_b();
*g_ab_str = handshake.gen_key().second; *g_ab_str = handshake.gen_key().second;
return Status::OK(); return Status::OK();

View File

@ -73,7 +73,7 @@ class DhHandshake {
string get_g_a() const; string get_g_a() const;
string get_g_b() const; string get_g_b() const;
string get_g_b_hash() const; string get_g_b_hash() const;
Status run_checks(DhCallback *callback) TD_WARN_UNUSED_RESULT; Status run_checks(bool skip_config_check, DhCallback *callback) TD_WARN_UNUSED_RESULT;
BigNum get_g() const; BigNum get_g() const;
BigNum get_p() const; BigNum get_p() const;
@ -137,8 +137,8 @@ class DhHandshake {
private: private:
static Status check_config(Slice prime_str, const BigNum &prime, int32 g_int, BigNumContext &ctx, static Status check_config(Slice prime_str, const BigNum &prime, int32 g_int, BigNumContext &ctx,
DhCallback *callback) TD_WARN_UNUSED_RESULT; DhCallback *callback) TD_WARN_UNUSED_RESULT;
static Status dh_check(Slice prime_str, const BigNum &prime, int32 g_int, const BigNum &g_a, const BigNum &g_b,
BigNumContext &ctx, DhCallback *callback) TD_WARN_UNUSED_RESULT; static Status dh_check(const BigNum &prime, const BigNum &g_a, const BigNum &g_b) TD_WARN_UNUSED_RESULT;
string prime_str_; string prime_str_;
BigNum prime_; BigNum prime_;

View File

@ -322,7 +322,7 @@ Status CallActor::do_update_call(telegram_api::phoneCallAccepted &call) {
LOG(DEBUG) << "Do update call to Accepted"; LOG(DEBUG) << "Do update call to Accepted";
dh_handshake_.set_g_a(call.g_b_.as_slice()); dh_handshake_.set_g_a(call.g_b_.as_slice());
TRY_STATUS(dh_handshake_.run_checks(DhCache::instance())); TRY_STATUS(dh_handshake_.run_checks(true, DhCache::instance()));
std::tie(call_state_.key_fingerprint, call_state_.key) = dh_handshake_.gen_key(); std::tie(call_state_.key_fingerprint, call_state_.key) = dh_handshake_.gen_key();
state_ = State::SendConfirmQuery; state_ = State::SendConfirmQuery;
on_begin_exchanging_key(); on_begin_exchanging_key();
@ -348,7 +348,7 @@ Status CallActor::do_update_call(telegram_api::phoneCall &call) {
LOG(DEBUG) << "Do update call to Ready from state " << static_cast<int32>(state_); LOG(DEBUG) << "Do update call to Ready from state " << static_cast<int32>(state_);
if (state_ == State::WaitAcceptResult) { if (state_ == State::WaitAcceptResult) {
dh_handshake_.set_g_a(call.g_a_or_b_.as_slice()); dh_handshake_.set_g_a(call.g_a_or_b_.as_slice());
TRY_STATUS(dh_handshake_.run_checks(DhCache::instance())); TRY_STATUS(dh_handshake_.run_checks(true, DhCache::instance()));
std::tie(call_state_.key_fingerprint, call_state_.key) = dh_handshake_.gen_key(); std::tie(call_state_.key_fingerprint, call_state_.key) = dh_handshake_.gen_key();
} }
if (call_state_.key_fingerprint != call.key_fingerprint_) { if (call_state_.key_fingerprint != call.key_fingerprint_) {
@ -430,8 +430,14 @@ void CallActor::on_dh_config(Result<std::shared_ptr<DhConfig>> r_dh_config, bool
if (r_dh_config.is_error()) { if (r_dh_config.is_error()) {
return on_error(r_dh_config.move_as_error()); return on_error(r_dh_config.move_as_error());
} }
dh_config_ready_ = true;
dh_config_ = r_dh_config.move_as_ok(); dh_config_ = r_dh_config.move_as_ok();
auto check_result = DhHandshake::check_config(dh_config_->g, dh_config_->prime, DhCache::instance());
if (check_result.is_error()) {
return on_error(std::move(check_result));
}
dh_config_ready_ = true;
yield(); yield();
} }

View File

@ -574,7 +574,7 @@ Status SecretChatActor::run_auth() {
if (!auth_state_.handshake.has_config()) { if (!auth_state_.handshake.has_config()) {
return Status::OK(); return Status::OK();
} }
TRY_STATUS(auth_state_.handshake.run_checks(context_->dh_callback())); TRY_STATUS(auth_state_.handshake.run_checks(true, context_->dh_callback()));
auto id_and_key = auth_state_.handshake.gen_key(); auto id_and_key = auth_state_.handshake.gen_key();
pfs_state_.auth_key = mtproto::AuthKey(id_and_key.first, std::move(id_and_key.second)); pfs_state_.auth_key = mtproto::AuthKey(id_and_key.first, std::move(id_and_key.second));
calc_key_hash(); calc_key_hash();
@ -1859,7 +1859,7 @@ Status SecretChatActor::on_update_chat(telegram_api::encryptedChat &update) {
TRY_STATUS(save_common_info(update)); TRY_STATUS(save_common_info(update));
if (auth_state_.state == State::WaitRequestResponse) { if (auth_state_.state == State::WaitRequestResponse) {
auth_state_.handshake.set_g_a(update.g_a_or_b_.as_slice()); auth_state_.handshake.set_g_a(update.g_a_or_b_.as_slice());
TRY_STATUS(auth_state_.handshake.run_checks(context_->dh_callback())); TRY_STATUS(auth_state_.handshake.run_checks(true, context_->dh_callback()));
auto id_and_key = auth_state_.handshake.gen_key(); auto id_and_key = auth_state_.handshake.gen_key();
pfs_state_.auth_key = mtproto::AuthKey(id_and_key.first, std::move(id_and_key.second)); pfs_state_.auth_key = mtproto::AuthKey(id_and_key.first, std::move(id_and_key.second));
calc_key_hash(); calc_key_hash();
@ -1974,6 +1974,7 @@ Status SecretChatActor::on_dh_config(NetQueryPtr query) {
LOG(INFO) << "Got dh config"; LOG(INFO) << "Got dh config";
TRY_RESULT(config, fetch_result<telegram_api::messages_getDhConfig>(std::move(query))); TRY_RESULT(config, fetch_result<telegram_api::messages_getDhConfig>(std::move(query)));
downcast_call(*config, [&](auto &obj) { this->on_dh_config(obj); }); downcast_call(*config, [&](auto &obj) { this->on_dh_config(obj); });
TRY_STATUS(DhHandshake::check_config(auth_state_.dh_config.g, auth_state_.dh_config.prime, context_->dh_callback()));
auth_state_.handshake.set_config(auth_state_.dh_config.g, auth_state_.dh_config.prime); auth_state_.handshake.set_config(auth_state_.dh_config.g, auth_state_.dh_config.prime);
return Status::OK(); return Status::OK();
} }
@ -2147,7 +2148,7 @@ Status SecretChatActor::on_inbound_action(secret_api::decryptedMessageActionRequ
pfs_state_.exchange_id = request_key.exchange_id_; pfs_state_.exchange_id = request_key.exchange_id_;
pfs_state_.handshake.set_config(auth_state_.dh_config.g, auth_state_.dh_config.prime); pfs_state_.handshake.set_config(auth_state_.dh_config.g, auth_state_.dh_config.prime);
pfs_state_.handshake.set_g_a(request_key.g_a_.as_slice()); pfs_state_.handshake.set_g_a(request_key.g_a_.as_slice());
TRY_STATUS(pfs_state_.handshake.run_checks(context_->dh_callback())); TRY_STATUS(pfs_state_.handshake.run_checks(true, context_->dh_callback()));
auto id_and_key = pfs_state_.handshake.gen_key(); auto id_and_key = pfs_state_.handshake.gen_key();
pfs_state_.other_auth_key = mtproto::AuthKey(id_and_key.first, std::move(id_and_key.second)); pfs_state_.other_auth_key = mtproto::AuthKey(id_and_key.first, std::move(id_and_key.second));
@ -2167,7 +2168,7 @@ Status SecretChatActor::on_inbound_action(secret_api::decryptedMessageActionAcce
return Status::Error("AcceptKey: exchange_id mismatch"); return Status::Error("AcceptKey: exchange_id mismatch");
} }
pfs_state_.handshake.set_g_a(accept_key.g_b_.as_slice()); pfs_state_.handshake.set_g_a(accept_key.g_b_.as_slice());
TRY_STATUS(pfs_state_.handshake.run_checks(context_->dh_callback())); TRY_STATUS(pfs_state_.handshake.run_checks(true, context_->dh_callback()));
auto id_and_key = pfs_state_.handshake.gen_key(); auto id_and_key = pfs_state_.handshake.gen_key();
if (static_cast<int64>(id_and_key.first) != accept_key.key_fingerprint_) { if (static_cast<int64>(id_and_key.first) != accept_key.key_fingerprint_) {
return Status::Error("AcceptKey: key_fingerprint mismatch"); return Status::Error("AcceptKey: key_fingerprint mismatch");

View File

@ -137,7 +137,7 @@ class SecretChatActor : public NetQueryCallback {
enum class State : int32 { Empty, SendRequest, SendAccept, WaitRequestResponse, WaitAcceptResponse, Ready, Closed }; enum class State : int32 { Empty, SendRequest, SendAccept, WaitRequestResponse, WaitAcceptResponse, Ready, Closed };
static constexpr int32 MAX_RESEND_COUNT = 1000; static constexpr int32 MAX_RESEND_COUNT = 1000;
// We have git state that should be shynchronized with db. // We have git state that should be synchronized with db.
// It is splitted into several parts because: // It is splitted into several parts because:
// 1. Some parts are BIG (auth_key, for example) and are rarely updated. // 1. Some parts are BIG (auth_key, for example) and are rarely updated.
// 2. Other are frequently updated, so probably should be as small as possible. // 2. Other are frequently updated, so probably should be as small as possible.