Commit 757e47ef authored by johan's avatar johan

Add OPks management in update

+ modidy API so user can set initial upload OPk batch size
To be completed with accurate test on OPk status
parent da09a28c
......@@ -65,12 +65,16 @@ namespace lime {
* A user is identified by its deviceId(shall be the GRUU) and must at creation select a base Elliptic curve to use, this setting cannot be changed later
* A user is published on an X3DH key server who must run using the same elliptic curve selected for this user (creation will fail otherwise), the server url cannot be changed later
*
* @param[in] localDeviceId Identify the local user acount to use, it must be unique and is also be used as Id on the X3DH key server, it shall be the GRUU
* @param[in] x3dhServerUrl The complete url(including port) of the X3DH key server. It must connect using HTTPS. Example: https://sip5.linphone.org:25519
* @param[in] curve Choice of elliptic curve to use as base for ECDH and EdDSA operation involved. Can be CurveId::c25519 or CurveId::c448.
* @param[in] callback This operation contact the X3DH server and is thus asynchronous, when server responds,
* this callback will be called giving the exit status and an error message in case of failure
* @param[in] localDeviceId Identify the local user acount to use, it must be unique and is also be used as Id on the X3DH key server, it shall be the GRUU
* @param[in] x3dhServerUrl The complete url(including port) of the X3DH key server. It must connect using HTTPS. Example: https://sip5.linphone.org:25519
* @param[in] curve Choice of elliptic curve to use as base for ECDH and EdDSA operation involved. Can be CurveId::c25519 or CurveId::c448.
* @param[in] initialOPkBatchSize Number of OPks in the first batch uploaded to X3DH server
* @param[in] callback This operation contact the X3DH server and is thus asynchronous, when server responds,
* this callback will be called giving the exit status and an error message in case of failure
* The initialOPkBatchSize is optionnal, if not used, set to defaults defined in lime::settings
* (not done with param default value as the lime::settings shall not be available in public include)
*/
void create_user(const std::string &localDeviceId, const std::string &x3dhServerUrl, const lime::CurveId curve, const uint16_t initialOPkBatchSize, const limeCallback &callback);
void create_user(const std::string &localDeviceId, const std::string &x3dhServerUrl, const lime::CurveId curve, const limeCallback &callback);
/**
......@@ -135,10 +139,16 @@ namespace lime {
*
* Is performed for all users founds in local storage
*
* @param[in] callback This operation may contact the X3DH server and is thus asynchronous, when server responds,
* this callback will be called giving the exit status and an error message in case of failure.
* @param[in] callback This operation may contact the X3DH server and is thus asynchronous, when server responds,
* this callback will be called giving the exit status and an error message in case of failure.
* @param[in] OPkServerLowLimit If server holds less OPk than this limit, generate and upload a batch of OPks
* @param[in] OPkBatchSize Number of OPks in a batch uploaded to server
*
* The last two parameters are optionnal, if not used, set to defaults defined in lime::settings
* (not done with param default value as the lime::settings shall not be available in public include)
*/
void update(const limeCallback &callback);
void update(const limeCallback &callback, uint16_t OPkServerLowLimit, uint16_t OPkBatchSize);
LimeManager() = delete; // no manager without Database and http provider
LimeManager(const LimeManager&) = delete; // no copy constructor
......
......@@ -107,11 +107,12 @@ namespace lime {
* @brief Publish on X3DH server the user, it is performed just after creation in local storage
* this will, on success, trigger generation and sending of SPk and OPks for our new user
*
* @param[in] callback call when completed
* @param[in] initialOPkBatchSize Number of OPks in the first batch uploaded to X3DH server
* @param[in] callback call when completed
*/
template <typename Curve>
void Lime<Curve>::publish_user(const limeCallback &callback) {
callbackUserData<Curve> *userData = new callbackUserData<Curve>{this->shared_from_this(), callback, true};
void Lime<Curve>::publish_user(const limeCallback &callback, const uint16_t OPkInitialBatchSize) {
callbackUserData<Curve> *userData = new callbackUserData<Curve>{this->shared_from_this(), callback, OPkInitialBatchSize, true};
get_SelfIdentityKey(); // make sure our Ik is loaded in object
std::vector<uint8_t> X3DHmessage{};
x3dh_protocol::buildMessage_registerUser<Curve>(X3DHmessage, m_Ik.publicKey());
......@@ -149,6 +150,15 @@ namespace lime {
}
}
template <typename Curve>
void Lime<Curve>::update_OPk(const limeCallback &callback, uint16_t OPkServerLowLimit, uint16_t OPkBatchSize) {
// Request Server for the count of our OPk it still holds
callbackUserData<Curve> *userData = new callbackUserData<Curve>{this->shared_from_this(), callback, OPkServerLowLimit, OPkBatchSize};
std::vector<uint8_t> X3DHmessage{};
x3dh_protocol::buildMessage_getSelfOPks<Curve>(X3DHmessage);
postToX3DHServer(userData, X3DHmessage); // in the response from server, if more OPks are needed, it will generate and post them before calling the callback
}
template <typename Curve>
void Lime<Curve>::encrypt(std::shared_ptr<const std::string> recipientUserId, std::shared_ptr<std::vector<recipientData>> recipients, std::shared_ptr<const std::vector<uint8_t>> plainMessage, std::shared_ptr<std::vector<uint8_t>> cipherMessage, const limeCallback &callback) {
bctbx_debug("encrypt from %s to %ld recipients", m_selfDeviceId.data(), recipients->size());
......@@ -281,14 +291,15 @@ namespace lime {
* @param[in] deviceId User to create in DB, deviceId shall be the GRUU
* @param[in] url URL of X3DH key server to be used to publish our keys
* @param[in] curve Which curve shall we use for this account, select the implemenation to instanciate when using this user
* @param[in] initialOPkBatchSize Number of OPks in the first batch uploaded to X3DH server
* @param[in] http_provider An http provider used to communicate with x3dh key server
* @param[in] user_authentication_callback To complete user authentication on server: must provide user credentials
* @param[in] callback To provide caller the operation result
*
* @return a pointer to the LimeGeneric class allowing access to API declared in lime.hpp
*/
std::shared_ptr<LimeGeneric> insert_LimeUser(const std::string &dbFilename, const std::string &deviceId, const std::string &url, const lime::CurveId curve, belle_http_provider *http_provider,
const userAuthenticateCallback &user_authentication_callback, const limeCallback &callback) {
std::shared_ptr<LimeGeneric> insert_LimeUser(const std::string &dbFilename, const std::string &deviceId, const std::string &url, const lime::CurveId curve, const uint16_t OPkInitialBatchSize,
belle_http_provider *http_provider, const userAuthenticateCallback &user_authentication_callback, const limeCallback &callback) {
BCTBX_SLOGI<<"Create Lime user "<<deviceId;
/* first check the requested curve is instanciable and return an exception if not */
#ifndef EC25519_ENABLED
......@@ -313,7 +324,7 @@ namespace lime {
{
/* constructor will insert user in Db, if already present, raise an exception*/
auto lime_ptr = std::make_shared<Lime<C255>>(std::move(localStorage), deviceId, url, http_provider, user_authentication_callback);
lime_ptr->publish_user(callback);
lime_ptr->publish_user(callback, OPkInitialBatchSize);
return lime_ptr;
}
#endif
......@@ -323,7 +334,7 @@ namespace lime {
#ifdef EC448_ENABLED
{
auto lime_ptr = std::make_shared<Lime<C448>>(std::move(localStorage), deviceId, url, http_provider, user_authentication_callback);
lime_ptr->publish_user(callback);
lime_ptr->publish_user(callback, OPkInitialBatchSize);
return lime_ptr;
}
#endif
......
......@@ -106,7 +106,7 @@ namespace lime {
Lime(Lime<Curve> &a) = delete; // can't copy a session, force usage of shared pointers
Lime<Curve> &operator=(Lime<Curve> &a) = delete; // can't copy a session
void publish_user(const limeCallback &callback) override;
void publish_user(const limeCallback &callback, const uint16_t OPkInitialBatchSize) override;
void delete_user(const limeCallback &callback) override;
/**
......@@ -116,6 +116,18 @@ namespace lime {
*/
void update_SPk(const limeCallback &callback) override;
/**
* @brief check if we shall upload more OPks on X3DH server
* - ask server four our keys (returns the count and all their Ids)
* - check if it's under the low limit, if yes, generate a batch of keys and upload them
*
* @param[in] callback Called with success or failure when operation is completed.
* @param[in] OPkServerLowLimit If server holds less OPk than this limit, generate and upload a batch of OPks
* @param[in] OPkBatchSize Number of OPks in a batch uploaded to server
*/
void update_OPk(const limeCallback &callback, uint16_t OPkServerLowLimit, uint16_t OPkBatchSize) override;
void encrypt(std::shared_ptr<const std::string> recipientUserId, std::shared_ptr<std::vector<recipientData>> recipients, std::shared_ptr<const std::vector<uint8_t>> plainMessage, std::shared_ptr<std::vector<uint8_t>> cipherMessage, const limeCallback &callback) override;
bool decrypt(const std::string &recipientUserId, const std::string &senderDeviceId, const std::vector<uint8_t> &cipherHeader, const std::vector<uint8_t> &cipherMessage, std::vector<uint8_t> &plainMessage) override;
};
......@@ -132,17 +144,27 @@ namespace lime {
std::shared_ptr<const std::vector<uint8_t>> plainMessage;
std::shared_ptr<std::vector<uint8_t>> cipherMessage;
lime::network_state network_state_machine; /* used to run a simple state machine at user creation to perform sequence of packet sending: registerUser, postSPk, postOPks */
uint16_t OPkServerLowLimit; /* Used when fetching from server self OPk to check if we shall upload more */
uint16_t OPkBatchSize;
// created at user create/delete and keys Post
callbackUserData(std::weak_ptr<Lime<Curve>> thiz, const limeCallback &callbackRef, uint16_t OPkInitialBatchSize=lime::settings::OPk_initialBatchSize, bool startRegisterUserSequence=false)
: limeObj{thiz}, callback{callbackRef},
recipientUserId{nullptr}, recipients{nullptr}, plainMessage{nullptr}, cipherMessage{nullptr}, network_state_machine{startRegisterUserSequence?lime::network_state::sendSPk:lime::network_state::done},
OPkServerLowLimit(0), OPkBatchSize(OPkInitialBatchSize) {};
// when created at user_create/delete
callbackUserData(std::weak_ptr<Lime<Curve>> thiz, const limeCallback &callbackRef, bool startRegisterUserSequence=false)
// created at update: getSelfOPks
callbackUserData(std::weak_ptr<Lime<Curve>> thiz, const limeCallback &callbackRef, uint16_t OPkServerLowLimit, uint16_t OPkBatchSize)
: limeObj{thiz}, callback{callbackRef},
recipientUserId{nullptr}, recipients{nullptr}, plainMessage{nullptr}, cipherMessage{nullptr}, network_state_machine{startRegisterUserSequence?lime::network_state::sendSPk:lime::network_state::done} {};
// when created at encrypt
recipientUserId{nullptr}, recipients{nullptr}, plainMessage{nullptr}, cipherMessage{nullptr}, network_state_machine{lime::network_state::done},
OPkServerLowLimit{OPkServerLowLimit}, OPkBatchSize{OPkBatchSize} {};
// created at encrypt(getPeerBundle)
callbackUserData(std::weak_ptr<Lime<Curve>> thiz, const limeCallback &callbackRef,
std::shared_ptr<const std::string> recipientUserId, std::shared_ptr<std::vector<recipientData>> recipients,
std::shared_ptr<const std::vector<uint8_t>> plainMessage, std::shared_ptr<std::vector<uint8_t>> cipherMessage)
: limeObj{thiz}, callback{callbackRef},
recipientUserId{recipientUserId}, recipients{recipients}, plainMessage{plainMessage}, cipherMessage{cipherMessage}, network_state_machine {lime::network_state::done} {};// copy construct all shared_ptr
recipientUserId{recipientUserId}, recipients{recipients}, plainMessage{plainMessage}, cipherMessage{cipherMessage}, network_state_machine {lime::network_state::done}, // copy construct all shared_ptr
OPkServerLowLimit(0), OPkBatchSize(0) {};
// do not copy callback data, force passing the pointer around after creation
callbackUserData(callbackUserData &a) = delete;
callbackUserData operator=(callbackUserData &a) = delete;
......
......@@ -34,9 +34,10 @@ namespace lime {
/* Encrypt/Decrypt */
virtual void encrypt(std::shared_ptr<const std::string> recipientUserId, std::shared_ptr<std::vector<recipientData>> recipients, std::shared_ptr<const std::vector<uint8_t>> plainMessage, std::shared_ptr<std::vector<uint8_t>> cipherMessage, const limeCallback &callback) = 0;
virtual bool decrypt(const std::string &recipientUserId, const std::string &senderDeviceId, const std::vector<uint8_t> &cipherHeader, const std::vector<uint8_t> &cipherMessage, std::vector<uint8_t> &plainMessage) = 0;
virtual void publish_user(const limeCallback &callback) = 0;
virtual void publish_user(const limeCallback &callback, const uint16_t OPkInitialBatchSize) = 0;
virtual void delete_user(const limeCallback &callback) = 0;
virtual void update_SPk(const limeCallback &callback) = 0;
virtual void update_OPk(const limeCallback &callback, uint16_t OPkServerLowLimit, uint16_t OPkBatchSize) = 0;
virtual ~LimeGeneric() {};
};
......@@ -50,14 +51,15 @@ namespace lime {
* @param[in] deviceId User to create in DB, deviceId shall be the GRUU
* @param[in] url URL of X3DH key server to be used to publish our keys
* @param[in] curve Which curve shall we use for this account, select the implemenation to instanciate when using this user
* @param[in] initialOPkBatchSize Number of OPks in the first batch uploaded to X3DH server
* @param[in] http_provider An http provider used to communicate with x3dh key server
* @param[in] user_authentication_callback To complete user authentication on server: must provide user credentials
* @param[in] callback To provide caller the operation result
*
* @return a pointer to the LimeGeneric class allowing access to API declared in lime.hpp
*/
std::shared_ptr<LimeGeneric> insert_LimeUser(const std::string &dbFilename, const std::string &deviceId, const std::string &url, const lime::CurveId curve, belle_http_provider *http_provider,
const userAuthenticateCallback &user_authentication_callback, const limeCallback &callback);
std::shared_ptr<LimeGeneric> insert_LimeUser(const std::string &dbFilename, const std::string &deviceId, const std::string &url, const lime::CurveId curve, const uint16_t OPkInitialBatchSize,
belle_http_provider *http_provider, const userAuthenticateCallback &user_authentication_callback, const limeCallback &callback);
/**
* @brief Load a local user from database
......
......@@ -25,6 +25,7 @@
#include "lime/lime.hpp"
#include "lime_lime.hpp"
#include "lime_localStorage.hpp"
#include "lime_utils.hpp"
using namespace::std;
......@@ -35,6 +36,9 @@ namespace lime {
/* */
/****************************************************************************/
void LimeManager::create_user(const std::string &localDeviceId, const std::string &x3dhServerUrl, const lime::CurveId curve, const limeCallback &callback) {
create_user(localDeviceId, x3dhServerUrl, curve, lime::settings::OPk_initialBatchSize, callback);
}
void LimeManager::create_user(const std::string &localDeviceId, const std::string &x3dhServerUrl, const lime::CurveId curve, const uint16_t OPkInitialBatchSize, const limeCallback &callback) {
auto thiz = this;
limeCallback managerCreateCallback([thiz, localDeviceId, callback](lime::callbackReturn returnCode, std::string errorMessage) {
// first forward the callback
......@@ -48,7 +52,7 @@ namespace lime {
}
});
m_users_cache.insert({localDeviceId, insert_LimeUser(m_db_access, localDeviceId, x3dhServerUrl, curve, m_http_provider, m_user_auth, managerCreateCallback)});
m_users_cache.insert({localDeviceId, insert_LimeUser(m_db_access, localDeviceId, x3dhServerUrl, curve, OPkInitialBatchSize, m_http_provider, m_user_auth, managerCreateCallback)});
}
void LimeManager::delete_user(const std::string &localDeviceId, const limeCallback &callback) {
......@@ -105,7 +109,11 @@ namespace lime {
return user->decrypt(recipientUserId, senderDeviceId, cipherHeader, cipherMessage, plainMessage);
}
/* This version use default settings */
void LimeManager::update(const limeCallback &callback) {
update(callback, lime::settings::OPk_serverLowLimit, lime::settings::OPk_batchSize);
}
void LimeManager::update(const limeCallback &callback, uint16_t OPkServerLowLimit, uint16_t OPkBatchSize) {
// open local DB
auto localStorage = std::unique_ptr<lime::Db>(new lime::Db(m_db_access));
......@@ -117,19 +125,19 @@ namespace lime {
std::vector<std::string> deviceIds{};
localStorage->get_allLocalDevices(deviceIds);
//This counter will trace number of callbacks, to trace how many operation did end,
auto callbackCounts = make_shared<size_t>(0);
//This counter will trace number of callbacks, to trace how many operation did end.
// we expect two callback per local user account: one for update SPk, one for get OPk number on server
size_t expectedCallbacks = deviceIds.size();
auto callbackCount = make_shared<size_t>(deviceIds.size()*2);
auto globalReturnCode = make_shared<lime::callbackReturn>(lime::callbackReturn::success);
limeCallback managerUpdateCallback([callbackCounts, expectedCallbacks, globalReturnCode, callback](lime::callbackReturn returnCode, std::string errorMessage) {
(*callbackCounts)++;
// this callback will get all callbacks from update OPk and SPk on all users, when everyone is done, call the callback given to LimeManager::update
limeCallback managerUpdateCallback([callbackCount, globalReturnCode, callback](lime::callbackReturn returnCode, std::string errorMessage) {
(*callbackCount)--;
if (returnCode == lime::callbackReturn::fail) {
*globalReturnCode = lime::callbackReturn::fail; // if one fail, return fail at the end of it
}
if (*callbackCounts == expectedCallbacks) {
if (*callbackCount == 0) {
if (callback) callback(*globalReturnCode, "");
}
});
......@@ -148,8 +156,8 @@ namespace lime {
user = userElem->second;
}
// send a request to X3DH server to check how many OPk are left on server
// send a request to X3DH server to check how many OPk are left on server, upload more if needed
user->update_OPk(managerUpdateCallback, OPkServerLowLimit, OPkBatchSize);
// update the SPk(if needed)
user->update_SPk(managerUpdateCallback);
......
......@@ -22,12 +22,6 @@
namespace lime {
// this namespace hold constants definition used as settings in all components of the lime library
namespace settings {
/******************************************************************************/
/* */
/* Generic settings: number of OPks to generate, Life time of SPks, ecc.. */
/* */
/******************************************************************************/
constexpr uint16_t OPk_batch_number = 5; //TODO: 5 is ok for testing purpose what to set on real deployment
/******************************************************************************/
/* */
......@@ -88,6 +82,10 @@ namespace settings {
constexpr unsigned int SPK_lifeTime_days=7; // in days, Life time of a signed pre-key, it will be set to stale after that period
constexpr unsigned int SPK_limboTime_days=30; // in days, How long shall we keep a signed pre-key once it has been replaced by a new one
constexpr uint16_t OPk_batchSize = 25; // default batch size when uploading OPks to X3DH server
constexpr uint16_t OPk_initialBatchSize = 2*OPk_batchSize; // default batch size when creating a new user
constexpr uint16_t OPk_serverLowLimit = 50; // this is a default value but it can be set by parameter to the update function
}
}
......
......@@ -65,6 +65,11 @@ namespace lime {
* (OPk <ECDH Public Key Length> || OPk id <4 bytes>){0,1 in accordance to flag}
* ) { bundle Count}
*
* - getSelfOPks : empty message, ask server for the OPk Id it still holds for us
*
* - selfOPks : OPk Count <2 bytes unsigned integer Big Endian> ||
* (OPk id <4 bytes uint32_t big endian>){OPk Count}
*
* - error : errorCode<1 byte> || (errorMessage<...>){0,1}
*/
......@@ -77,6 +82,8 @@ namespace lime {
postOPks=0x04,
getPeerBundle=0x05,
peerBundle=0x06,
getSelfOPks=0x07,
selfOPks=0x08,
error=0xff};
enum class x3dh_error_code : uint8_t{ bad_content_type=0x00,
......@@ -173,6 +180,14 @@ namespace lime {
}
}
// getSelfOPks : empty message, ask server for the OPk Id it still holds for us
template <typename Curve>
void buildMessage_getSelfOPks(std::vector<uint8_t> &message) noexcept {
// create the header
message = X3DH_makeHeader(x3dh_message_type::getSelfOPks, Curve::curveId());
}
/*
* @brief Perform validity verifications on x3dh message and extract its type and error code if its the case
*
......@@ -225,6 +240,12 @@ namespace lime {
case static_cast<uint8_t>(x3dh_message_type::peerBundle) :
message_type = x3dh_message_type::peerBundle;
break;
case static_cast<uint8_t>(x3dh_message_type::getSelfOPks) :
message_type = x3dh_message_type::getSelfOPks;
break;
case static_cast<uint8_t>(x3dh_message_type::selfOPks) :
message_type = x3dh_message_type::selfOPks;
break;
case static_cast<uint8_t>(x3dh_message_type::error) :
message_type = x3dh_message_type::error;
break;
......@@ -361,6 +382,46 @@ namespace lime {
return true;
}
/*
* selfOPks : OPk Count <2 bytes unsigned integer Big Endian> ||
* (OPk id <4 bytes uint32_t big endian>){OPk Count}
*/
/**
* @brief Parse a selfPk message and populate a self OPk ids
* Warning: no checks are done on message type, they are performed before calling this function
*
* @param[in] body a buffer holding the message
* @param[in] bodySize size of previous buffer
* @param[out] selfOPkIds a vector to be populated from message content, is empty if no OPk returned
*
* @return true if all went ok, false otherwise
*/
template <typename Curve>
bool parseMessage_selfOPks(const uint8_t *body, const size_t bodySize, std::vector<uint32_t> &selfOPkIds) noexcept {
selfOPkIds.clear();
if (bodySize < X3DH_headerSize+2) { // we must be able to at least have a count of bundles
return false;
}
uint16_t selfOPkIdsCount = (static_cast<uint16_t>(body[X3DH_headerSize]))<<8|body[X3DH_headerSize+1];
if (bodySize < X3DH_headerSize+2+4*selfOPkIdsCount) { // this expected message size
return false;
}
size_t index = X3DH_headerSize+2;
// loop on all OPk Ids
for (auto i=0; i<selfOPkIdsCount; i++) { // they are in big endian
uint32_t OPkId = static_cast<uint32_t>(body[index])<<24 |
static_cast<uint32_t>(body[index+1])<<16 |
static_cast<uint32_t>(body[index+2])<<8 |
static_cast<uint32_t>(body[index+3]);
index+=4;
selfOPkIds.push_back(OPkId);
}
return true;
}
/* Instanciate templated functions */
#ifdef EC25519_ENABLED
template void buildMessage_registerUser<C255>(std::vector<uint8_t> &message, const ED<C255> &Ik) noexcept;
......@@ -368,6 +429,7 @@ namespace lime {
template void buildMessage_publishSPk<C255>(std::vector<uint8_t> &message, const X<C255> &SPk, const Signature<C255> &Sig, const uint32_t SPk_id) noexcept;
template void buildMessage_publishOPks<C255>(std::vector<uint8_t> &message, const std::vector<X<C255>> &OPks, const std::vector<uint32_t> &OPk_ids) noexcept;
template void buildMessage_getPeerBundles<C255>(std::vector<uint8_t> &message, std::vector<std::string> &peer_device_ids) noexcept;
template void buildMessage_getSelfOPks<C255>(std::vector<uint8_t> &message) noexcept;
#endif
#ifdef EC448_ENABLED
......@@ -376,6 +438,7 @@ namespace lime {
template void buildMessage_publishSPk<C448>(std::vector<uint8_t> &message, const X<C448> &SPk, const Signature<C448> &Sig, const uint32_t SPk_id) noexcept;
template void buildMessage_publishOPks<C448>(std::vector<uint8_t> &message, const std::vector<X<C448>> &OPks, const std::vector<uint32_t> &OPk_ids) noexcept;
template void buildMessage_getPeerBundles<C448>(std::vector<uint8_t> &message, std::vector<std::string> &peer_device_ids) noexcept;
template void buildMessage_getSelfOPks<C448>(std::vector<uint8_t> &message) noexcept;
#endif
} //namespace x3dh_protocol
......@@ -431,7 +494,6 @@ namespace lime {
auto body = reinterpret_cast<const uint8_t *>(belle_sip_message_get_body(message));
auto bodySize = belle_sip_message_get_body_size(message);
lime::x3dh_protocol::x3dh_message_type message_type{x3dh_protocol::x3dh_message_type::unset_type};
lime::x3dh_protocol::x3dh_error_code error_code{x3dh_protocol::x3dh_error_code::unset_error_code};
if (!x3dh_protocol::parseMessage_getType<Curve>(body, bodySize, message_type, error_code, callback)) {
......@@ -476,6 +538,33 @@ namespace lime {
return;
}
// Is it a selfOPks message?
if (message_type == lime::x3dh_protocol::x3dh_message_type::selfOPks) {
std::vector<uint32_t> selfOPkIds{};
if (!x3dh_protocol::parseMessage_selfOPks<Curve>(body, bodySize, selfOPkIds)) { // parsing went wrong
BCTBX_SLOGE<<"Got an invalid selfOPKs packet from X3DH server";
if (callback) callback(lime::callbackReturn::fail, "Got an invalid selfOPKs packet from X3DH server");
thiz->cleanUserData(userData);
return;
}
// TODO: tag as seen on server all the Ids so one day we can remove the OPk distributed by server but not used
// Check if we shall upload more packets
if (selfOPkIds.size() < userData->OPkServerLowLimit) {
// generate and publish the OPks
std::vector<X<Curve>> OPks{};
std::vector<uint32_t> OPk_ids{};
thiz->X3DH_generate_OPks(OPks, OPk_ids, userData->OPkBatchSize);
std::vector<uint8_t> X3DHmessage{};
x3dh_protocol::buildMessage_publishOPks(X3DHmessage, OPks, OPk_ids);
thiz->postToX3DHServer(userData, X3DHmessage);
} else { /* nothing to do, just call the callback */
if (callback) callback(lime::callbackReturn::success, "");
thiz->cleanUserData(userData);
}
return;
}
// Rudimental state machine active at user registration only:
// - after registering a new user on X3dh server, if all goes well(server responde message type is registerIdentity), we shall upload SPK
// - after uploading SPk on X3dh server, if all goes well(server responde message type is registerIdentity), we shall upload SPK
......@@ -494,7 +583,7 @@ namespace lime {
// generate and publish the OPks
std::vector<X<Curve>> OPks{};
std::vector<uint32_t> OPk_ids{};
thiz->X3DH_generate_OPks(OPks, OPk_ids, lime::settings::OPk_batch_number);
thiz->X3DH_generate_OPks(OPks, OPk_ids, userData->OPkBatchSize);
std::vector<uint8_t> X3DHmessage{};
x3dh_protocol::buildMessage_publishOPks(X3DHmessage, OPks, OPk_ids);
thiz->postToX3DHServer(userData, X3DHmessage);
......
......@@ -58,6 +58,9 @@ namespace lime {
template <typename Curve>
void buildMessage_getPeerBundles(std::vector<uint8_t> &message, std::vector<std::string> &peer_device_ids) noexcept;
template <typename Curve>
void buildMessage_getSelfOPks(std::vector<uint8_t> &message) noexcept;
/* this templates are intanciated in lime_x3dh_procotocol.cpp, do not re-instanciate it anywhere else */
#ifdef EC25519_ENABLED
extern template void buildMessage_registerUser<C255>(std::vector<uint8_t> &message, const ED<C255> &Ik) noexcept;
......@@ -65,6 +68,7 @@ namespace lime {
extern template void buildMessage_publishSPk<C255>(std::vector<uint8_t> &message, const X<C255> &SPk, const Signature<C255> &Sig, const uint32_t SPk_id) noexcept;
extern template void buildMessage_publishOPks<C255>(std::vector<uint8_t> &message, const std::vector<X<C255>> &OPks, const std::vector<uint32_t> &OPk_ids) noexcept;
extern template void buildMessage_getPeerBundles<C255>(std::vector<uint8_t> &message, std::vector<std::string> &peer_device_ids) noexcept;
extern template void buildMessage_getSelfOPks<C255>(std::vector<uint8_t> &message) noexcept;
#endif
#ifdef EC448_ENABLED
......@@ -73,6 +77,7 @@ namespace lime {
extern template void buildMessage_publishSPk<C448>(std::vector<uint8_t> &message, const X<C448> &SPk, const Signature<C448> &Sig, const uint32_t SPk_id) noexcept;
extern template void buildMessage_publishOPks<C448>(std::vector<uint8_t> &message, const std::vector<X<C448>> &OPks, const std::vector<uint32_t> &OPk_ids) noexcept;
extern template void buildMessage_getPeerBundles<C448>(std::vector<uint8_t> &message, std::vector<std::string> &peer_device_ids) noexcept;
extern template void buildMessage_getSelfOPks<C448>(std::vector<uint8_t> &message) noexcept;
#endif
} // namespace x3dh_protocol
......
......@@ -41,6 +41,9 @@ namespace lime_tester {
// default value for the timeout
int wait_for_timeout=4000;
// default value for initial OPk batch size, keep it small so not too many OPks generated
uint16_t OPkInitialBatchSize=3;
std::vector<std::string> messages_pattern = {
{"Frankly, my dear, I don't give a damn."},
{"I'm gonna make him an offer he can't refuse."},
......
......@@ -34,6 +34,9 @@ extern std::vector<std::string> messages_pattern;
// default value for the timeout
extern int wait_for_timeout;
// default value for initial OPk batch size, keep it small so not too many OPks generated
extern uint16_t OPkInitialBatchSize;
/**
* @brief Create and initialise the two sessions given in parameter. Alice as sender session and Bob as receiver one
* Alice must then send the first message, once bob got it, sessions are fully initialised
......
This diff is collapsed.
......@@ -91,6 +91,8 @@ const enum_messageTypes = {
postOPks:0x04,
getPeerBundle:0x05,
peerBundle:0x06,
getSelfOPks:0x07,
selfOPks:0x08,
error:0xff
};
......@@ -533,6 +535,40 @@ https.createServer(digest, options, (req, res) => {
break;
/* selfOPks : OPKs Id Count < 2 bytes unsigned Big Endian> |
* (OPk id <4 bytes>){ OPks Id Count}
*/
case enum_messageTypes.getSelfOPks:
console.log("Process a getSelfOPks Message from "+userId);
db.all("SELECT o.OPk_id as OPk_id FROM Users as u INNER JOIN OPk as o ON u.Uid=o.Uid WHERE UserId = ?;", userId, function (err, rows) {
if (err) {
returnError(enum_errorCodes.db_error, " Database error in getSelfOPks by "+userId+" : "+err);
return;
}
// create the return message
let selfOPKsBuffer = Buffer.allocUnsafe(X3DH_headerSize+2);
selfOPKsBuffer.writeUInt8(X3DH_protocolVersion, 0);
selfOPKsBuffer.writeUInt8(enum_messageTypes.selfOPks, 1);
selfOPKsBuffer.writeUInt8(curveId, 2);
if (rows == undefined || rows.length == 0) { // no Id founds
selfOPKsBuffer.writeUInt16BE(0, 3); // peers bundle count on 2 bytes in Big Endian
} else {
selfOPKsBuffer.writeUInt16BE(rows.length, 3); // peers bundle count on 2 bytes in Big Endian
for (let i=0; i<rows.length; i++) {
let OPk_idBuffer = Buffer.allocUnsafe(4);
OPk_idBuffer.writeUInt32BE(rows[i]['OPk_id'], 0); // OPk id on 4 bytes in Big Endian
selfOPKsBuffer = Buffer.concat([selfOPKsBuffer, OPk_idBuffer]);
}
}
returnOk(selfOPKsBuffer);
});
break;
default:
returnError(enum_errorCodes.bad_message_type, "Unknown message type "+messageType);
break;
......
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