Commit c95a125f authored by johan's avatar johan

Add test for non OPk X3DH init packet

parent 454f681b
......@@ -66,7 +66,9 @@ namespace lime {
public :
constexpr static size_t keyLength(void) {return Curve::XkeySize();}; // provide a static size function to be able to call the function not on an object
constexpr static uint8_t byteId(void) {return Curve::XkeyByteId();};
X(const uint8_t *buffer) {std::copy_n(buffer, Curve::XkeySize(), this->data());} // construct from a C style buffer
// construct from a C style buffer
// WARNING: very dangerous code could lead to read anywhere(X{0} will call this constructor), get rid of it if we manage to use c++ buffer style only - get a bctoolbox/crypto.hpp?
X(const uint8_t *buffer) {std::copy_n(buffer, Curve::XkeySize(), this->data());}
X(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Curve::XkeySize(), this->begin());} // construct from a std::vector<uint8_t>
X() {};
void assign(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Curve::XkeySize(), this->begin());} // copy from a std::vector<uint8_t>
......@@ -84,7 +86,9 @@ namespace lime {
public :
constexpr static size_t keyLength(void) {return Curve::EDkeySize();}; // provide a static size function to be able to call the function not on an object
constexpr static uint8_t byteId(void) {return Curve::EDkeyByteId();};
ED(const uint8_t *buffer) {std::copy_n(buffer, Curve::EDkeySize(), this->data());} // construct from a C style buffer
// construct from a C style buffer
// WARNING: very dangerous code could lead to read anywhere(ED{0} will call this constructor), get rid of it if we manage to use c++ buffer style only - get a bctoolbox/crypto.hpp?
ED(const uint8_t *buffer) {std::copy_n(buffer, Curve::EDkeySize(), this->data());}
ED(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Curve::EDkeySize(), this->begin());} // contruct from a std::vector<uint8_t>
ED() {};
void assign(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Curve::EDkeySize(), this->begin());} // copy from a std::vector<uint8_t>
......
......@@ -35,7 +35,8 @@ namespace lime {
uint32_t OPk_id;
// use uint8_t * constructor for all keys/signatures
X3DH_peerBundle(std::string &&deviceId, const uint8_t *Ik, const uint8_t *SPk, uint32_t SPk_id, const uint8_t *SPk_sig) :
deviceId{deviceId}, Ik{Ik}, SPk{SPk}, SPk_id{SPk_id}, SPk_sig{SPk_sig}, haveOPk{false}, OPk{0}, OPk_id{0} {};
deviceId{deviceId}, Ik{Ik}, SPk{SPk}, SPk_id{SPk_id}, SPk_sig{SPk_sig}, haveOPk{false}, OPk{}, OPk_id{0} {};
X3DH_peerBundle(std::string &&deviceId, const uint8_t *Ik, const uint8_t *SPk, uint32_t SPk_id, const uint8_t *SPk_sig, const uint8_t *OPk, uint32_t OPk_id) :
deviceId{deviceId}, Ik{Ik}, SPk{SPk}, SPk_id{SPk_id}, SPk_sig{SPk_sig}, haveOPk{true}, OPk{OPk}, OPk_id{OPk_id} {};
......
......@@ -248,6 +248,11 @@ void dr_devicesInit(std::string dbBaseFilename, std::vector<std::vector<std::vec
bool DR_message_holdsX3DHInit(std::vector<uint8_t> &message) {
bool dummy;
return DR_message_holdsX3DHInit(message, dummy);
}
bool DR_message_holdsX3DHInit(std::vector<uint8_t> &message, bool &haveOPk) {
// checks on length
if (message.size()<4) return false;
......@@ -263,16 +268,20 @@ bool DR_message_holdsX3DHInit(std::vector<uint8_t> &message) {
case static_cast<uint8_t>(lime::CurveId::c25519):
if (message[3] == 0x00) { // no OPk in the X3DH init message
if (message.size() != (71 + X<C255>::keyLength() + 5 + ED<C255>::keyLength() + X<C255>::keyLength())) return false;
haveOPk=false;
} else { // OPk present in the X3DH init message
if (message.size() != (71 + X<C255>::keyLength() + 9 + ED<C255>::keyLength() + X<C255>::keyLength())) return false;
haveOPk=true;
}
return true;
break;
case static_cast<uint8_t>(lime::CurveId::c448):
if (message[3] == 0x00) { // no OPk in the X3DH init message
if (message.size() != (71 + X<C448>::keyLength() + 5 + ED<C448>::keyLength() + X<C448>::keyLength())) return false;
haveOPk=false;
} else { // OPk present in the X3DH init message
if (message.size() != (71 + X<C448>::keyLength() + 9 + ED<C448>::keyLength() + X<C448>::keyLength())) return false;
haveOPk=true;
}
return true;
......
......@@ -67,6 +67,8 @@ void dr_devicesInit(std::string dbBaseFilename, std::vector<std::vector<std::vec
/* return true if the message buffer is a valid DR message holding a X3DH init one in its header */
bool DR_message_holdsX3DHInit(std::vector<uint8_t> &message);
/* this version will set the OPk status in the given bool if a packet is found */
bool DR_message_holdsX3DHInit(std::vector<uint8_t> &message, bool &haveOPk);
/* return true if the message buffer is a valid DR message holding a X3DH init one in its header and copy the X3DH init message in the provided buffer */
bool DR_message_extractX3DHInit(std::vector<uint8_t> &message, std::vector<uint8_t> &X3DH_initMessage);
......
......@@ -78,6 +78,91 @@ static void managersClean(std::unique_ptr<LimeManager> &alice, std::unique_ptr<L
BCTBX_SLOGI<<"Trash and reload alice and bob LimeManagers";
}
/** Scenario
* - Create one device for alice
* - Create OPk_batch_number devices for bob, they will all fetch a key and encrypt a messaage to alice, server shall not have anymore OPks
* - Create another device for alice and send a message to bob, it shall get a non OPk bundle, check it is the case in the message sent to Alice
* Alice decrypt all messages to complete the check
*
*/
static void x3dh_without_OPk_test(const lime::CurveId curve, const std::string &dbBaseFilename, const std::string &x3dh_server_url, bool continuousSession=true) {
// create DB
std::string dbFilenameAlice{dbBaseFilename};
dbFilenameAlice.append(".alice.").append((curve==CurveId::c25519)?"C25519":"C448").append(".sqlite3");
std::string dbFilenameBob{dbBaseFilename};
dbFilenameBob.append(".bob.").append((curve==CurveId::c25519)?"C25519":"C448").append(".sqlite3");
remove(dbFilenameAlice.data()); // delete the database file if already exists
remove(dbFilenameBob.data()); // delete the database file if already exists
events_counters_t counters={};
int expected_success=0;
limeCallback callback([&counters](lime::callbackReturn returnCode, std::string anythingToSay) {
if (returnCode == lime::callbackReturn::success) {
counters.operation_success++;
} else {
counters.operation_failed++;
BCTBX_SLOGE<<"Lime operation failed : "<<anythingToSay;
}
});
try {
// create Manager and device for alice
auto aliceManager = std::unique_ptr<LimeManager>(new LimeManager(dbFilenameAlice, prov));
auto aliceDeviceId = makeRandomDeviceName("alice.d1.");
aliceManager->create_user(*aliceDeviceId, x3dh_server_url, curve, callback);
BC_ASSERT_TRUE(wait_for(stack,&counters.operation_success, ++expected_success,wait_for_timeout));
for (auto i=0; i<lime::settings::OPk_batch_number +1; i++) {
// Create manager and device for bob
auto bobManager = std::unique_ptr<LimeManager>(new LimeManager(dbFilenameBob, prov));
auto bobDeviceId = makeRandomDeviceName("bob.d");
bobManager->create_user(*bobDeviceId, x3dh_server_url, curve, callback);
BC_ASSERT_TRUE(wait_for(stack,&counters.operation_success, ++expected_success,wait_for_timeout));
// encrypt a message to Alice
auto messagePatternIndex = i % lime_messages_pattern.size();
auto bobRecipients = make_shared<std::vector<recipientData>>();
bobRecipients->emplace_back(*aliceDeviceId);
auto bobMessage = make_shared<const std::vector<uint8_t>>(lime_messages_pattern[messagePatternIndex].begin(), lime_messages_pattern[messagePatternIndex].end());
auto bobCipherMessage = make_shared<std::vector<uint8_t>>();
bobManager->encrypt(*bobDeviceId, make_shared<const std::string>("alice"), bobRecipients, bobMessage, bobCipherMessage, callback);
BC_ASSERT_TRUE(wait_for(stack,&counters.operation_success,++expected_success,wait_for_timeout)); // we must get a callback saying all went well
// alice decrypt
std::vector<uint8_t> receivedMessage{};
bool haveOPk=false;
BC_ASSERT_TRUE(DR_message_holdsX3DHInit((*bobRecipients)[0].cipherHeader, haveOPk));
if (i<lime::settings::OPk_batch_number) { // the first OPk_batch_messages must hold an X3DH init message with an OPk
BC_ASSERT_TRUE(haveOPk);
} else { // then the last message shall not convey OPK_id as none were available
BC_ASSERT_FALSE(haveOPk);
}
BC_ASSERT_TRUE(aliceManager->decrypt(*aliceDeviceId, "alice", *bobDeviceId, (*bobRecipients)[0].cipherHeader, *bobCipherMessage, receivedMessage));
auto receivedMessageString = std::string{receivedMessage.begin(), receivedMessage.end()};
BC_ASSERT_TRUE(receivedMessageString == lime_messages_pattern[messagePatternIndex]);
// destroy and reload the Managers(tests everything is correctly saved/load from local Storage)
if (!continuousSession) { managersClean (aliceManager, bobManager, dbFilenameAlice, dbFilenameBob);}
}
} catch (BctbxException &e) {
BCTBX_SLOGE <<e;;
BC_FAIL();
}
}
static void x3dh_without_OPk() {
#ifdef EC25519_ENABLED
x3dh_without_OPk_test(lime::CurveId::c25519, "lime_x3dh_without_OPk", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c25519_server_port).data());
x3dh_without_OPk_test(lime::CurveId::c25519, "lime_x3dh_without_OPk_clean", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c25519_server_port).data(), false);
#endif
#ifdef EC448_ENABLED
x3dh_without_OPk_test(lime::CurveId::c448, "lime_x3dh_without_OPk", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c448_server_port).data());
x3dh_without_OPk_test(lime::CurveId::c448, "lime_x3dh_without_OPk_clean", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c448_server_port).data(), false);
#endif
}
/* Alice encrypt to bob, bob replies so session is fully established, then alice encrypt more tjan maxSendingChain message so we must start a new session with bob
* - alice.d1 and bob.d1 exchange messages
* - alice encrypt maxSendingChain messages, bob never reply, no real need to decryp them, just check they are not holding X3DH init message
......@@ -217,12 +302,12 @@ static void x3dh_sending_chain_limit_test(const lime::CurveId curve, const std::
}
static void x3dh_sending_chain_limit() {
#ifdef EC25519_ENABLED
x3dh_sending_chain_limit_test(lime::CurveId::c25519, "lime_x3dh_multiple_DRsessions", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c25519_server_port).data());
x3dh_sending_chain_limit_test(lime::CurveId::c25519, "lime_x3dh_multiple_DRsessions_clean", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c25519_server_port).data(), false);
x3dh_sending_chain_limit_test(lime::CurveId::c25519, "lime_x3dh_sending_chain_limit", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c25519_server_port).data());
x3dh_sending_chain_limit_test(lime::CurveId::c25519, "lime_x3dh_sending_chain_limit_clean", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c25519_server_port).data(), false);
#endif
#ifdef EC448_ENABLED
x3dh_sending_chain_limit_test(lime::CurveId::c448, "lime_x3dh_multiple_DRsessions", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c448_server_port).data());
x3dh_sending_chain_limit_test(lime::CurveId::c448, "lime_x3dh_multiple_DRsessions_clean", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c448_server_port).data(), false);
x3dh_sending_chain_limit_test(lime::CurveId::c448, "lime_x3dh_sending_chain_limit", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c448_server_port).data());
x3dh_sending_chain_limit_test(lime::CurveId::c448, "lime_x3dh_sending_chain_limit_clean", std::string("https://").append(test_x3dh_server_url).append(":").append(test_x3dh_c448_server_port).data(), false);
#endif
}
......@@ -1100,6 +1185,7 @@ static test_t tests[] = {
TEST_NO_TAG("Multi devices queued encryption", x3dh_multidev_operation_queue),
TEST_NO_TAG("Multiple sessions", x3dh_multiple_DRsessions),
TEST_NO_TAG("Sending chain limit", x3dh_sending_chain_limit),
TEST_NO_TAG("Without OPk", x3dh_without_OPk),
};
test_suite_t lime_lime_test_suite = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment