Expose IsPrimeAndGood() interface from connection.

Also fix a race in MTProto debug type serialization initialization.
This commit is contained in:
John Preston 2017-04-03 21:28:18 +03:00
parent c1aa1c5a0f
commit afa9393f38
4 changed files with 93 additions and 66 deletions

View File

@ -437,7 +437,7 @@ def addTextSerialize(lst, dct, dataLetter):
conditions = data[6];
trivialConditions = data[7];
result += 'void _serialize_' + name + '(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {\n';
result += 'void Serialize_' + name + '(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {\n';
if (len(conditions)):
result += '\tMTP' + dataLetter + name + '::Flags flag(iflag);\n\n';
if (len(prms)):
@ -524,7 +524,7 @@ def addTextSerializeInit(lst, dct):
v = dct[restype];
for data in v:
name = data[0];
result += '\t_serializers.insert(mtpc_' + name + ', _serialize_' + name + ');\n';
result += '\tresult.insert(mtpc_' + name + ', Serialize_' + name + ');\n';
return result;
textSerializeMethods += addTextSerialize(typesList, typesDict, 'D');
@ -869,9 +869,9 @@ void _serialize_core_message(MTPStringLogger &to, int32 stage, int32 lev, Types
\n';
textSerializeInit += '\
_serializers.insert(mtpc_rpc_result, _serialize_rpc_result);\n\
_serializers.insert(mtpc_msg_container, _serialize_msg_container);\n\
_serializers.insert(mtpc_core_message, _serialize_core_message);\n';
result.insert(mtpc_rpc_result, _serialize_rpc_result);\n\
result.insert(mtpc_msg_container, _serialize_msg_container);\n\
result.insert(mtpc_core_message, _serialize_core_message);\n';
# module itself
@ -969,26 +969,27 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org\n\
*/\n\
#include "scheme.h"\n\
\n\
typedef QVector<mtpTypeId> Types;\ntypedef QVector<int32> StagesFlags;\n\
using Types = QVector<mtpTypeId>;\n\
using StagesFlags = QVector<int32>;\n\
\n\
' + textSerializeMethods + '\n\
namespace {\n\
\n\
using mtpTextSerializer = void (*)(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag);\n\
using TextSerializers = QMap<mtpTypeId, mtpTextSerializer>;\n\
using TextSerializer = void (*)(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag);\n\
using TextSerializers = QMap<mtpTypeId, TextSerializer>;\n\
\n\
TextSerializers _serializers;\n\
QMap<mtpTypeId, TextSerializer> createTextSerializers() {\n\
auto result = QMap<mtpTypeId, TextSerializer>();\n\
\n\
void initTextSerializers() {\n\
' + textSerializeInit + '\n\
\n\
return result;\n\
}\n\
\n\
} // namespace\n\
\n\
void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpPrime *end, mtpPrime cons, uint32 level, mtpPrime vcons) {\n\
if (_serializers.isEmpty()) {\n\
initTextSerializers();\n\
}\n\
static auto serializers = createTextSerializers();\n\
\n\
QVector<mtpTypeId> types, vtypes;\n\
QVector<int32> stages, flags;\n\
@ -1015,8 +1016,8 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
}\n\
\n\
int32 lev = level + types.size() - 1;\n\
TextSerializers::const_iterator it = _serializers.constFind(type);\n\
if (it != _serializers.cend()) {\n\
auto it = serializers.constFind(type);\n\
if (it != serializers.cend()) {\n\
(*it.value())(to, stage, lev, types, vtypes, stages, flags, start, end, flag);\n\
} else {\n\
mtpTextSerializeCore(to, from, end, type, lev, vtype);\n\

View File

@ -45,7 +45,6 @@ enum {
MTPConnectionOldTimeout = 192000, // 192 seconds
MTPTcpConnectionWaitTimeout = 2000, // 2 seconds waiting for tcp, until we accept http
MTPIPv4ConnectionWaitTimeout = 1000, // 1 seconds waiting for ipv4, until we accept ipv6
MTPMillerRabinIterCount = 30, // 30 Miller-Rabin iterations for dh_prime primality check
MTPUploadSessionsCount = 2, // max 2 upload sessions is created
MTPDownloadSessionsCount = 2, // max 2 download sessions is created

View File

@ -108,6 +108,24 @@ bool parsePQ(const QByteArray &pqStr, QByteArray &pStr, QByteArray &qStr) {
class BigNumCounter {
public:
BigNumCounter() : ctx(BN_CTX_new()) {
BN_init(&bnPower);
BN_init(&bnModul);
BN_init(&bn_g);
BN_init(&bn_g_a);
BN_init(&bnResult);
BN_init(&bnTemp);
}
~BigNumCounter() {
BN_CTX_free(ctx);
BN_clear_free(&bnPower);
BN_clear_free(&bnModul);
BN_clear_free(&bn_g);
BN_clear_free(&bn_g_a);
BN_clear_free(&bnResult);
BN_clear_free(&bnTemp);
}
bool count(const void *power, const void *modul, uint32 g, void *gResult, const void *g_a, void *g_aResult) {
DEBUG_LOG(("BigNum Info: counting g_b = g ^ b % dh_prime and auth_key = g_a ^ b % dh_prime"));
uint32 g_be = qToBigEndian(g);
@ -200,24 +218,6 @@ public:
return true;
}
BigNumCounter() : ctx(BN_CTX_new()) {
BN_init(&bnPower);
BN_init(&bnModul);
BN_init(&bn_g);
BN_init(&bn_g_a);
BN_init(&bnResult);
BN_init(&bnTemp);
}
~BigNumCounter() {
BN_CTX_free(ctx);
BN_clear_free(&bnPower);
BN_clear_free(&bnModul);
BN_clear_free(&bn_g);
BN_clear_free(&bn_g_a);
BN_clear_free(&bnResult);
BN_clear_free(&bnTemp);
}
private:
BIGNUM bnPower, bnModul, bn_g, bn_g_a, bnResult, bnTemp;
BN_CTX *ctx;
@ -227,42 +227,70 @@ private:
// Miller-Rabin primality test
class BigNumPrimeTest {
public:
BigNumPrimeTest() : _context(BN_CTX_new()) {
BN_init(&_prime);
}
~BigNumPrimeTest() {
BN_clear_free(&_prime);
BN_CTX_free(_context);
}
bool isPrimeAndGood(const void *pData, uint32 iterCount, int32 g) {
if (!memcmp(pData, "\xC7\x1C\xAE\xB9\xC6\xB1\xC9\x04\x8E\x6C\x52\x2F\x70\xF1\x3F\x73\x98\x0D\x40\x23\x8E\x3E\x21\xC1\x49\x34\xD0\x37\x56\x3D\x93\x0F\x48\x19\x8A\x0A\xA7\xC1\x40\x58\x22\x94\x93\xD2\x25\x30\xF4\xDB\xFA\x33\x6F\x6E\x0A\xC9\x25\x13\x95\x43\xAE\xD4\x4C\xCE\x7C\x37\x20\xFD\x51\xF6\x94\x58\x70\x5A\xC6\x8C\xD4\xFE\x6B\x6B\x13\xAB\xDC\x97\x46\x51\x29\x69\x32\x84\x54\xF1\x8F\xAF\x8C\x59\x5F\x64\x24\x77\xFE\x96\xBB\x2A\x94\x1D\x5B\xCD\x1D\x4A\xC8\xCC\x49\x88\x07\x08\xFA\x9B\x37\x8E\x3C\x4F\x3A\x90\x60\xBE\xE6\x7C\xF9\xA4\xA4\xA6\x95\x81\x10\x51\x90\x7E\x16\x27\x53\xB5\x6B\x0F\x6B\x41\x0D\xBA\x74\xD8\xA8\x4B\x2A\x14\xB3\x14\x4E\x0E\xF1\x28\x47\x54\xFD\x17\xED\x95\x0D\x59\x65\xB4\xB9\xDD\x46\x58\x2D\xB1\x17\x8D\x16\x9C\x6B\xC4\x65\xB0\xD6\xFF\x9C\xA3\x92\x8F\xEF\x5B\x9A\xE4\xE4\x18\xFC\x15\xE8\x3E\xBE\xA0\xF8\x7F\xA9\xFF\x5E\xED\x70\x05\x0D\xED\x28\x49\xF4\x7B\xF9\x59\xD9\x56\x85\x0C\xE9\x29\x85\x1F\x0D\x81\x15\xF6\x35\xB1\x05\xEE\x2E\x4E\x15\xD0\x4B\x24\x54\xBF\x6F\x4F\xAD\xF0\x34\xB1\x04\x03\x11\x9C\xD8\xE3\xB9\x2F\xCC\x5B", 256)) {
bool isPrimeAndGood(const QByteArray &data, int g) {
constexpr auto kMillerRabinIterationCount = 30;
constexpr auto kGoodPrimeSize = 256;
if (data.size() != kGoodPrimeSize) {
LOG(("BigNum PT Error: data size %1").arg(data.size()));
return false;
}
if (!memcmp(data.constData(), "\
\xC7\x1C\xAE\xB9\xC6\xB1\xC9\x04\x8E\x6C\x52\x2F\x70\xF1\x3F\x73\
\x98\x0D\x40\x23\x8E\x3E\x21\xC1\x49\x34\xD0\x37\x56\x3D\x93\x0F\
\x48\x19\x8A\x0A\xA7\xC1\x40\x58\x22\x94\x93\xD2\x25\x30\xF4\xDB\
\xFA\x33\x6F\x6E\x0A\xC9\x25\x13\x95\x43\xAE\xD4\x4C\xCE\x7C\x37\
\x20\xFD\x51\xF6\x94\x58\x70\x5A\xC6\x8C\xD4\xFE\x6B\x6B\x13\xAB\
\xDC\x97\x46\x51\x29\x69\x32\x84\x54\xF1\x8F\xAF\x8C\x59\x5F\x64\
\x24\x77\xFE\x96\xBB\x2A\x94\x1D\x5B\xCD\x1D\x4A\xC8\xCC\x49\x88\
\x07\x08\xFA\x9B\x37\x8E\x3C\x4F\x3A\x90\x60\xBE\xE6\x7C\xF9\xA4\
\xA4\xA6\x95\x81\x10\x51\x90\x7E\x16\x27\x53\xB5\x6B\x0F\x6B\x41\
\x0D\xBA\x74\xD8\xA8\x4B\x2A\x14\xB3\x14\x4E\x0E\xF1\x28\x47\x54\
\xFD\x17\xED\x95\x0D\x59\x65\xB4\xB9\xDD\x46\x58\x2D\xB1\x17\x8D\
\x16\x9C\x6B\xC4\x65\xB0\xD6\xFF\x9C\xA3\x92\x8F\xEF\x5B\x9A\xE4\
\xE4\x18\xFC\x15\xE8\x3E\xBE\xA0\xF8\x7F\xA9\xFF\x5E\xED\x70\x05\
\x0D\xED\x28\x49\xF4\x7B\xF9\x59\xD9\x56\x85\x0C\xE9\x29\x85\x1F\
\x0D\x81\x15\xF6\x35\xB1\x05\xEE\x2E\x4E\x15\xD0\x4B\x24\x54\xBF\
\x6F\x4F\xAD\xF0\x34\xB1\x04\x03\x11\x9C\xD8\xE3\xB9\x2F\xCC\x5B", kGoodPrimeSize)) {
if (g == 3 || g == 4 || g == 5 || g == 7) {
return true;
}
}
if (
!BN_bin2bn((const uchar*)pData, 64 * sizeof(uint32), &bnPrime)
) {
if (!BN_bin2bn((const uchar*)data.constData(), kGoodPrimeSize, &_prime)) {
ERR_load_crypto_strings();
LOG(("BigNum PT Error: BN_bin2bn failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0)));
DEBUG_LOG(("BigNum PT Error: prime %1").arg(Logs::mb(pData, 64 * sizeof(uint32)).str()));
DEBUG_LOG(("BigNum PT Error: prime %1").arg(Logs::mb(data.constData(), kGoodPrimeSize).str()));
return false;
}
int32 numBits = BN_num_bits(&bnPrime);
auto numBits = BN_num_bits(&_prime);
if (numBits != 2048) {
LOG(("BigNum PT Error: BN_bin2bn failed, bad dh_prime num bits: %1").arg(numBits));
return false;
}
if (BN_is_prime_ex(&bnPrime, MTPMillerRabinIterCount, ctx, NULL) == 0) {
if (BN_is_prime_ex(&_prime, kMillerRabinIterationCount, _context, NULL) == 0) {
return false;
}
switch (g) {
case 2: {
int32 mod8 = BN_mod_word(&bnPrime, 8);
auto mod8 = BN_mod_word(&_prime, 8);
if (mod8 != 7) {
LOG(("BigNum PT Error: bad g value: %1, mod8: %2").arg(g).arg(mod8));
return false;
}
} break;
case 3: {
int32 mod3 = BN_mod_word(&bnPrime, 3);
auto mod3 = BN_mod_word(&_prime, 3);
if (mod3 != 2) {
LOG(("BigNum PT Error: bad g value: %1, mod3: %2").arg(g).arg(mod3));
return false;
@ -270,53 +298,46 @@ public:
} break;
case 4: break;
case 5: {
int32 mod5 = BN_mod_word(&bnPrime, 5);
auto mod5 = BN_mod_word(&_prime, 5);
if (mod5 != 1 && mod5 != 4) {
LOG(("BigNum PT Error: bad g value: %1, mod5: %2").arg(g).arg(mod5));
return false;
}
} break;
case 6: {
int32 mod24 = BN_mod_word(&bnPrime, 24);
auto mod24 = BN_mod_word(&_prime, 24);
if (mod24 != 19 && mod24 != 23) {
LOG(("BigNum PT Error: bad g value: %1, mod24: %2").arg(g).arg(mod24));
return false;
}
} break;
case 7: {
int32 mod7 = BN_mod_word(&bnPrime, 7);
auto mod7 = BN_mod_word(&_prime, 7);
if (mod7 != 3 && mod7 != 5 && mod7 != 6) {
LOG(("BigNum PT Error: bad g value: %1, mod7: %2").arg(g).arg(mod7));
return false;
}
} break;
default:
LOG(("BigNum PT Error: bad g value: %1").arg(g));
return false;
break;
default: {
LOG(("BigNum PT Error: bad g value: %1").arg(g));
return false;
} break;
}
BN_sub_word(&bnPrime, 1); // (p - 1) / 2
BN_div_word(&bnPrime, 2);
BN_sub_word(&_prime, 1); // (p - 1) / 2
BN_div_word(&_prime, 2);
if (BN_is_prime_ex(&bnPrime, MTPMillerRabinIterCount, ctx, NULL) == 0) {
if (BN_is_prime_ex(&_prime, kMillerRabinIterationCount, _context, NULL) == 0) {
return false;
}
return true;
}
BigNumPrimeTest() : ctx(BN_CTX_new()) {
BN_init(&bnPrime);
}
~BigNumPrimeTest() {
BN_CTX_free(ctx);
BN_clear_free(&bnPrime);
}
private:
BIGNUM bnPrime;
BN_CTX *ctx;
BIGNUM _prime;
BN_CTX *_context;
};
typedef QMap<uint64, RSAPublicKey> RSAPublicKeys;
@ -2577,8 +2598,7 @@ void ConnectionPrivate::dhParamsAnswered() {
}
// check that dhPrime and (dhPrime - 1) / 2 are really prime using openssl BIGNUM methods
MTP::internal::BigNumPrimeTest bnPrimeTest;
if (!bnPrimeTest.isPrimeAndGood(dhPrime.constData(), MTPMillerRabinIterCount, dh_inner_data.vg.v)) {
if (!IsPrimeAndGood(dhPrime, dh_inner_data.vg.v)) {
LOG(("AuthKey Error: bad dh_prime primality!").arg(dhPrime.length()).arg(g_a.length()));
DEBUG_LOG(("AuthKey Error: dh_prime %1").arg(Logs::mb(dhPrime.constData(), dhPrime.length()).str()));
return restart();
@ -3074,4 +3094,9 @@ void ConnectionPrivate::stop() {
}
} // namespace internal
bool IsPrimeAndGood(const QByteArray &data, int g) {
return MTP::internal::BigNumPrimeTest().isPrimeAndGood(data, g);
}
} // namespace MTP

View File

@ -28,6 +28,8 @@ namespace MTP {
class Instance;
bool IsPrimeAndGood(const QByteArray &data, int g);
namespace internal {
class AbstractConnection;