diff --git a/src/lime_x3dh_protocol.cpp b/src/lime_x3dh_protocol.cpp index ed3540f295135416ed561c7672c24e525ecfd3f1..c10a417f53d2143fc3a3d768a1bdeaeafbd873d3 100644 --- a/src/lime_x3dh_protocol.cpp +++ b/src/lime_x3dh_protocol.cpp @@ -520,7 +520,8 @@ namespace lime { for (auto i=0; i<peersBundleCount; i++) { if (body.size() < index + 2) { // check we have at least a device size to read peersBundle.clear(); - LIME_LOGE<<"Invalid message: size is not what expected, discard without parsing"; + LIME_LOGE<<"Invalid message: size is not what expected, cannot read device size, discard without parsing"; + LIME_LOGD<<"message_trace so far: "<<message_trace.str(); return false; } @@ -530,7 +531,8 @@ namespace lime { if (body.size() < index + deviceIdSize + 1) { // check we have at enough data to read: device size and the following flag peersBundle.clear(); - LIME_LOGE<<"Invalid message: size is not what expected, discard without parsing"; + LIME_LOGE<<"Invalid message: size is not what expected, cannot read device id(size is"<<int(deviceIdSize)<<"), discard without parsing"; + LIME_LOGD<<"message_trace so far: "<<message_trace.str(); return false; } std::string deviceId{body.cbegin()+index, body.cbegin()+index+deviceIdSize}; @@ -551,6 +553,7 @@ namespace lime { break; default: LIME_LOGE<<"Invalid X3DH message: unexpected flag value "<<body[index]<<" in "<<deviceId<<" key bundle"; + LIME_LOGD<<"message_trace so far: "<<message_trace.str(); peersBundle.clear(); return false; } @@ -560,6 +563,7 @@ namespace lime { // add device Id (and its size) to the trace message_trace << endl << dec << " Device Id ("<<static_cast<unsigned int>(deviceIdSize)<<" bytes): "<<deviceId<<" has no key bundle"<<endl; peersBundle.emplace_back(std::move(deviceId)); + index += 1; continue; // skip to next one } @@ -571,7 +575,8 @@ namespace lime { if (body.size() < index + DSA<Curve, lime::DSAtype::publicKey>::ssize() + X<Curve, lime::Xtype::publicKey>::ssize() + DSA<Curve, lime::DSAtype::signature>::ssize() + 4 + (haveOPk?(X<Curve, lime::Xtype::publicKey>::ssize()+4):0) ) { peersBundle.clear(); - LIME_LOGE<<"Invalid message: size is not what expected, discard without parsing"; + LIME_LOGE<<"Invalid message: size is not what expected, not enough buffer to hold keys bundle, discard without parsing"; + LIME_LOGD<<"message_trace so far: "<<message_trace.str(); return false; } diff --git a/tester/lime_lime-tester.cpp b/tester/lime_lime-tester.cpp index 1bcb9621bcade0ce9e367d8cabcee3ccd54e3ee2..004c390d014a2f771b7b754ab915afef0449c005 100644 --- a/tester/lime_lime-tester.cpp +++ b/tester/lime_lime-tester.cpp @@ -2781,6 +2781,105 @@ static void x3dh_user_not_found_test(const lime::CurveId curve, const std::strin cipherMessage->clear(); if (!continuousSession) { managersClean (aliceManager, bobManager, dbFilenameAlice, dbFilenameBob);} + // Repeat the 3 previous encrypt/decrypt but each time delete bob's devices from alice's cache so it will force + // request to the X3DH server to ask for the 3 devices + aliceManager->delete_peerDevice(*bobDevice1); + aliceManager->delete_peerDevice(*bobDevice2); + aliceManager->delete_peerDevice(*bobDevice3); + + // encrypt another one, for d1, d2 and d3. The first two shall be ok and d3 shall have a failed status + recipients->emplace_back(*bobDevice1); + recipients->emplace_back(*bobDevice2); + recipients->emplace_back(*bobDevice3); + message = make_shared<const std::vector<uint8_t>>(lime_tester::messages_pattern[1].begin(), lime_tester::messages_pattern[1].end()); + + aliceManager->encrypt(*aliceDevice1, make_shared<const std::string>("bob"), recipients, message, cipherMessage, callback); + BC_ASSERT_TRUE(lime_tester::wait_for(stack,&counters.operation_success,++expected_success,lime_tester::wait_for_timeout)); + + // loop on cipher message and decrypt with bob Manager + for (auto &recipient : *recipients) { + if (recipient.deviceId == *bobDevice3) { + BC_ASSERT_TRUE(recipient.peerStatus == lime::PeerDeviceStatus::fail); + } else { + std::vector<uint8_t> receivedMessage{}; + BC_ASSERT_TRUE(recipient.peerStatus == lime::PeerDeviceStatus::unknown); // it is the first time alice has contact with bob's d1 and d2 devices + BC_ASSERT_TRUE(lime_tester::DR_message_holdsX3DHInit(recipient.DRmessage)); // first communication holds a X3DH message + BC_ASSERT_TRUE(bobManager->decrypt(recipient.deviceId, "bob", *aliceDevice1, recipient.DRmessage, *cipherMessage, receivedMessage) != lime::PeerDeviceStatus::fail); + std::string receivedMessageString{receivedMessage.begin(), receivedMessage.end()}; + BC_ASSERT_TRUE(receivedMessageString == lime_tester::messages_pattern[1]); + } + } + + // cleaning + recipients->clear(); + message = nullptr; + cipherMessage->clear(); + aliceManager->delete_peerDevice(*bobDevice1); + aliceManager->delete_peerDevice(*bobDevice2); + aliceManager->delete_peerDevice(*bobDevice3); + if (!continuousSession) { managersClean (aliceManager, bobManager, dbFilenameAlice, dbFilenameBob);} + + // encrypt another one, for d3, d2 and d1. + recipients->emplace_back(*bobDevice3); + recipients->emplace_back(*bobDevice2); + recipients->emplace_back(*bobDevice1); + message = make_shared<const std::vector<uint8_t>>(lime_tester::messages_pattern[2].begin(), lime_tester::messages_pattern[2].end()); + + aliceManager->encrypt(*aliceDevice1, make_shared<const std::string>("bob"), recipients, message, cipherMessage, callback); + BC_ASSERT_TRUE(lime_tester::wait_for(stack,&counters.operation_success,++expected_success,lime_tester::wait_for_timeout)); + + // loop on cipher message and decrypt with bob Manager + for (auto &recipient : *recipients) { + if (recipient.deviceId == *bobDevice3) { + BC_ASSERT_TRUE(recipient.peerStatus == lime::PeerDeviceStatus::fail); + } else { + std::vector<uint8_t> receivedMessage{}; + BC_ASSERT_TRUE(recipient.peerStatus == lime::PeerDeviceStatus::unknown); + BC_ASSERT_TRUE(lime_tester::DR_message_holdsX3DHInit(recipient.DRmessage)); // first communication holds a X3DH message + BC_ASSERT_TRUE(bobManager->decrypt(recipient.deviceId, "bob", *aliceDevice1, recipient.DRmessage, *cipherMessage, receivedMessage) != lime::PeerDeviceStatus::fail); + std::string receivedMessageString{receivedMessage.begin(), receivedMessage.end()}; + BC_ASSERT_TRUE(receivedMessageString == lime_tester::messages_pattern[2]); + } + } + + // cleaning + recipients->clear(); + message = nullptr; + cipherMessage->clear(); + aliceManager->delete_peerDevice(*bobDevice1); + aliceManager->delete_peerDevice(*bobDevice2); + aliceManager->delete_peerDevice(*bobDevice3); + if (!continuousSession) { managersClean (aliceManager, bobManager, dbFilenameAlice, dbFilenameBob);} + + // encrypt another one, for d2, d3 and d1. + recipients->emplace_back(*bobDevice2); + recipients->emplace_back(*bobDevice3); + recipients->emplace_back(*bobDevice1); + message = make_shared<const std::vector<uint8_t>>(lime_tester::messages_pattern[3].begin(), lime_tester::messages_pattern[3].end()); + + aliceManager->encrypt(*aliceDevice1, make_shared<const std::string>("bob"), recipients, message, cipherMessage, callback); + BC_ASSERT_TRUE(lime_tester::wait_for(stack,&counters.operation_success,++expected_success,lime_tester::wait_for_timeout)); + + // loop on cipher message and decrypt with bob Manager + for (auto &recipient : *recipients) { + if (recipient.deviceId == *bobDevice3) { + BC_ASSERT_TRUE(recipient.peerStatus == lime::PeerDeviceStatus::fail); + } else { + std::vector<uint8_t> receivedMessage{}; + BC_ASSERT_TRUE(recipient.peerStatus == lime::PeerDeviceStatus::unknown); + BC_ASSERT_TRUE(lime_tester::DR_message_holdsX3DHInit(recipient.DRmessage)); // first communication holds a X3DH message + BC_ASSERT_TRUE(bobManager->decrypt(recipient.deviceId, "bob", *aliceDevice1, recipient.DRmessage, *cipherMessage, receivedMessage) != lime::PeerDeviceStatus::fail); + std::string receivedMessageString{receivedMessage.begin(), receivedMessage.end()}; + BC_ASSERT_TRUE(receivedMessageString == lime_tester::messages_pattern[3]); + } + } + + // cleaning + recipients->clear(); + message = nullptr; + cipherMessage->clear(); + if (!continuousSession) { managersClean (aliceManager, bobManager, dbFilenameAlice, dbFilenameBob);} + // delete the users if (cleanDatabase) { aliceManager->delete_user(*aliceDevice1, callback);