diff options
author | Sven Gothel <[email protected]> | 2023-10-25 10:23:14 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-10-25 10:23:14 +0200 |
commit | 94124031ffb1cbe93c29fcc02734d891669a55ab (patch) | |
tree | b48c192a2b5c05c1de55ba4d3bcb30ac02fc57c0 /api | |
parent | 080814ec4641de5ddfb377e79cf421e66c216824 (diff) |
LE Resolvable Address: Support IRK: SMPIdentityResolvingKey (IRK w/ added id_address), SMPKeyBin storage and host upload, w/ clearing all IRKs on startup
Diffstat (limited to 'api')
-rw-r--r-- | api/direct_bt/BTManager.hpp | 6 | ||||
-rw-r--r-- | api/direct_bt/MgmtTypes.hpp | 156 | ||||
-rw-r--r-- | api/direct_bt/SMPKeyBin.hpp | 29 | ||||
-rw-r--r-- | api/direct_bt/SMPTypes.hpp | 4 |
4 files changed, 140 insertions, 55 deletions
diff --git a/api/direct_bt/BTManager.hpp b/api/direct_bt/BTManager.hpp index 43ee4979..bfd4ab3a 100644 --- a/api/direct_bt/BTManager.hpp +++ b/api/direct_bt/BTManager.hpp @@ -500,10 +500,14 @@ namespace direct_bt { */ bool isValidLongTermKeyAddressAndType(const EUI48 &address, const BDAddressType &address_type) const noexcept; - HCIStatusCode uploadLongTermKey(const uint16_t dev_id, const jau::darray<MgmtLongTermKeyInfo> &keys) noexcept; + HCIStatusCode uploadLongTermKey(const uint16_t dev_id, const jau::darray<MgmtLongTermKey> &keys) noexcept; HCIStatusCode uploadLongTermKey(const BTRole adapterRole, const uint16_t dev_id, const BDAddressAndType & addressAndType, const jau::darray<SMPLongTermKey>& ltks) noexcept; + HCIStatusCode uploadIdentityResolvingKey(const uint16_t dev_id, const jau::darray<MgmtIdentityResolvingKey> &keys) noexcept; + HCIStatusCode uploadIdentityResolvingKey(const uint16_t dev_id, const jau::darray<SMPIdentityResolvingKey>& irks) noexcept; + HCIStatusCode clearIdentityResolvingKeys(const uint16_t dev_id) noexcept; + HCIStatusCode uploadLinkKey(const uint16_t dev_id, const MgmtLinkKeyInfo &key) noexcept; HCIStatusCode uploadLinkKey(const uint16_t dev_id, const BDAddressAndType & addressAndType, const SMPLinkKey& lk) noexcept; diff --git a/api/direct_bt/MgmtTypes.hpp b/api/direct_bt/MgmtTypes.hpp index 194e7cad..1745f934 100644 --- a/api/direct_bt/MgmtTypes.hpp +++ b/api/direct_bt/MgmtTypes.hpp @@ -140,7 +140,7 @@ namespace direct_bt { std::string to_string(const MgmtLinkKeyType type) noexcept; /** - * Long Term Key Types compatible with Mgmt's MgmtLongTermKeyInfo + * Long Term Key Types compatible with Mgmt's MgmtLongTermKey */ enum class MgmtLTKType : uint8_t { /** Unauthenticated long term key, implying legacy. */ @@ -160,7 +160,7 @@ namespace direct_bt { MgmtLTKType to_MgmtLTKType(const SMPLongTermKey::Property ltk_prop_mask) noexcept; /** - * Signature Resolving Key Types compatible with Mgmt's MgmtSignatureResolvingKeyInfo + * Signature Resolving Key Types compatible with Mgmt's MgmtSignatureResolvingKey */ enum class MgmtCSRKType : uint8_t { /** Unauthenticated local key */ @@ -183,7 +183,7 @@ namespace direct_bt { * since the encryption values are interpreted as a byte stream. * </p> */ - __pack( struct MgmtLongTermKeyInfo { + __pack( struct MgmtLongTermKey { EUI48 address; /** 0 reserved, 1 le public, 2 le static random address. Compatible with BDAddressType. */ BDAddressType address_type; @@ -217,7 +217,7 @@ namespace direct_bt { } /** - * Convert the given states to the MgmtLongTermKeyInfo compatoble role. + * Convert the given states to the MgmtLongTermKey compatoble role. */ static constexpr uint8_t to_role(const BTRole adapterRole, const bool is_responder) { return ( ( BTRole::Slave == adapterRole && !is_responder ) || @@ -226,9 +226,9 @@ namespace direct_bt { } /** - * Convert this instance into its platform agnostic SMPLongTermKeyInfo type. + * Convert this instance into its platform agnostic SMPLongTermKey type. */ - SMPLongTermKey toSMPLongTermKeyInfo(const BTRole adapterRole) const noexcept { + SMPLongTermKey toSMPLongTermKey(const BTRole adapterRole) const noexcept { direct_bt::SMPLongTermKey res; res.clear(); if( ( BTRole::Slave == adapterRole && !role ) || @@ -266,7 +266,7 @@ namespace direct_bt { /** * Used for MgmtLoadIdentityResolvingKeyCmd and MgmtEvtNewIdentityResolvingKey */ - __pack( struct MgmtIdentityResolvingKeyInfo { + __pack( struct MgmtIdentityResolvingKey { EUI48 address; BDAddressType address_type; jau::uint128_t irk; @@ -276,6 +276,16 @@ namespace direct_bt { "], irk "+jau::bytesHexString(irk.data, 0, sizeof(irk), true /* lsbFirst */)+ "]"; } + + SMPIdentityResolvingKey toSMPIdentityResolvingKey(const BTRole adapterRole) const noexcept { + direct_bt::SMPIdentityResolvingKey res; + res.clear(); + if( BTRole::Master == adapterRole ) { + res.properties |= SMPIdentityResolvingKey::Property::RESPONDER; + } + res.irk = irk; + return res; + } } ); /** @@ -284,7 +294,7 @@ namespace direct_bt { * One way for ATT Signed Write. * </p> */ - __pack( struct MgmtSignatureResolvingKeyInfo { + __pack( struct MgmtSignatureResolvingKey { EUI48 address; BDAddressType address_type; MgmtCSRKType key_type; @@ -709,29 +719,83 @@ namespace direct_bt { } public: - MgmtLoadLongTermKeyCmd(const uint16_t dev_id, const MgmtLongTermKeyInfo & key) - : MgmtCommand(Opcode::LOAD_LONG_TERM_KEYS, dev_id, 2 + sizeof(MgmtLongTermKeyInfo)) + MgmtLoadLongTermKeyCmd(const uint16_t dev_id, const MgmtLongTermKey & key) + : MgmtCommand(Opcode::LOAD_LONG_TERM_KEYS, dev_id, 2 + sizeof(MgmtLongTermKey)) + { + pdu.put_uint16_nc(MGMT_HEADER_SIZE, 1); + memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+2), &key, sizeof(MgmtLongTermKey)); + } + + MgmtLoadLongTermKeyCmd(const uint16_t dev_id, const jau::darray<MgmtLongTermKey> &keys) + : MgmtCommand(Opcode::LOAD_LONG_TERM_KEYS, dev_id, 2 + keys.size() * sizeof(MgmtLongTermKey)) + { + jau::nsize_t offset = MGMT_HEADER_SIZE; + pdu.put_uint16_nc(offset, keys.size()); offset+= 2; + + for(auto it = keys.begin(); it != keys.end(); ++it, offset+=sizeof(MgmtLongTermKey)) { + const MgmtLongTermKey& key = *it; + memcpy(pdu.get_wptr_nc(offset), &key, sizeof(MgmtLongTermKey)); + } + } + uint16_t getKeyCount() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE); } + + const MgmtLongTermKey& getLongTermKey(jau::nsize_t idx) const { + checkParamIdx(idx); + return *reinterpret_cast<const MgmtLongTermKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 2 + sizeof(MgmtLongTermKey)*idx) ); + } + }; + + /** + * uint16_t key_count + * MgmtLongTermKey keys[key_count] + */ + class MgmtIdentityResolveKeyCmd : public MgmtCommand + { + private: + void checkParamIdx(const jau::nsize_t idx) const { + const jau::nsize_t kc = getKeyCount(); + if( idx >= kc ) { + throw jau::IndexOutOfBoundsException(idx, kc, E_FILE_LINE); + } + } + + protected: + std::string valueString() const noexcept override { + const jau::nsize_t keyCount = getKeyCount(); + std::string ps = "count "+std::to_string(keyCount)+": "; + for(jau::nsize_t i=0; i<keyCount; i++) { + if( 0 < i ) { + ps.append(", "); + } + ps.append( getLongTermKey(i).toString() ); + } + return "param[size "+std::to_string(getParamSize())+", data["+ps+"]], tsz "+std::to_string(getTotalSize()); + } + + public: + MgmtIdentityResolveKeyCmd(const uint16_t dev_id, const MgmtLongTermKey & key) + : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + sizeof(MgmtLongTermKey)) { pdu.put_uint16_nc(MGMT_HEADER_SIZE, 1); - memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+2), &key, sizeof(MgmtLongTermKeyInfo)); + memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+2), &key, sizeof(MgmtLongTermKey)); } - MgmtLoadLongTermKeyCmd(const uint16_t dev_id, const jau::darray<MgmtLongTermKeyInfo> &keys) - : MgmtCommand(Opcode::LOAD_LONG_TERM_KEYS, dev_id, 2 + keys.size() * sizeof(MgmtLongTermKeyInfo)) + MgmtIdentityResolveKeyCmd(const uint16_t dev_id, const jau::darray<MgmtLongTermKey> &keys) + : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + keys.size() * sizeof(MgmtLongTermKey)) { jau::nsize_t offset = MGMT_HEADER_SIZE; pdu.put_uint16_nc(offset, keys.size()); offset+= 2; - for(auto it = keys.begin(); it != keys.end(); ++it, offset+=sizeof(MgmtLongTermKeyInfo)) { - const MgmtLongTermKeyInfo& key = *it; - memcpy(pdu.get_wptr_nc(offset), &key, sizeof(MgmtLongTermKeyInfo)); + for(auto it = keys.begin(); it != keys.end(); ++it, offset+=sizeof(MgmtLongTermKey)) { + const MgmtLongTermKey& key = *it; + memcpy(pdu.get_wptr_nc(offset), &key, sizeof(MgmtLongTermKey)); } } uint16_t getKeyCount() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE); } - const MgmtLongTermKeyInfo& getLongTermKey(jau::nsize_t idx) const { + const MgmtLongTermKey& getLongTermKey(jau::nsize_t idx) const { checkParamIdx(idx); - return *reinterpret_cast<const MgmtLongTermKeyInfo *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 2 + sizeof(MgmtLongTermKeyInfo)*idx) ); + return *reinterpret_cast<const MgmtLongTermKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 2 + sizeof(MgmtLongTermKey)*idx) ); } }; @@ -799,29 +863,29 @@ namespace direct_bt { } public: - MgmtLoadIdentityResolvingKeyCmd(const uint16_t dev_id, const MgmtIdentityResolvingKeyInfo & key) - : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + sizeof(MgmtIdentityResolvingKeyInfo)) + MgmtLoadIdentityResolvingKeyCmd(const uint16_t dev_id, const MgmtIdentityResolvingKey & key) + : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + sizeof(MgmtIdentityResolvingKey)) { pdu.put_uint16_nc(MGMT_HEADER_SIZE, 1); - memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+2), &key, sizeof(MgmtIdentityResolvingKeyInfo)); + memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+2), &key, sizeof(MgmtIdentityResolvingKey)); } - MgmtLoadIdentityResolvingKeyCmd(const uint16_t dev_id, const jau::darray<MgmtIdentityResolvingKeyInfo> &keys) - : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + keys.size() * sizeof(MgmtIdentityResolvingKeyInfo)) + MgmtLoadIdentityResolvingKeyCmd(const uint16_t dev_id, const jau::darray<MgmtIdentityResolvingKey> &keys) + : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + keys.size() * sizeof(MgmtIdentityResolvingKey)) { jau::nsize_t offset = MGMT_HEADER_SIZE; pdu.put_uint16_nc(offset, keys.size()); offset+= 2; - for(auto it = keys.begin(); it != keys.end(); ++it, offset+=sizeof(MgmtIdentityResolvingKeyInfo)) { - const MgmtIdentityResolvingKeyInfo& key = *it; - memcpy(pdu.get_wptr_nc(offset), &key, sizeof(MgmtIdentityResolvingKeyInfo)); + for(auto it = keys.begin(); it != keys.end(); ++it, offset+=sizeof(MgmtIdentityResolvingKey)) { + const MgmtIdentityResolvingKey& key = *it; + memcpy(pdu.get_wptr_nc(offset), &key, sizeof(MgmtIdentityResolvingKey)); } } uint16_t getKeyCount() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE); } - const MgmtIdentityResolvingKeyInfo& getIdentityResolvingKey(jau::nsize_t idx) const { + const MgmtIdentityResolvingKey& getIdentityResolvingKey(jau::nsize_t idx) const { checkParamIdx(idx); - return *reinterpret_cast<const MgmtIdentityResolvingKeyInfo *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 2 + sizeof(MgmtIdentityResolvingKeyInfo)*idx) ); + return *reinterpret_cast<const MgmtIdentityResolvingKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 2 + sizeof(MgmtIdentityResolvingKey)*idx) ); } }; @@ -1711,7 +1775,7 @@ namespace direct_bt { /** * uint8_t store_hint, - * MgmtLongTermKeyInfo key + * MgmtLongTermKey key */ class MgmtEvtNewLongTermKey : public MgmtEvent { @@ -1723,18 +1787,18 @@ namespace direct_bt { public: MgmtEvtNewLongTermKey(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvent(buffer, buffer_len, 1+sizeof(MgmtLongTermKeyInfo)) + : MgmtEvent(buffer, buffer_len, 1+sizeof(MgmtLongTermKey)) { checkOpcode(getOpcode(), Opcode::NEW_LONG_TERM_KEY); } uint8_t getStoreHint() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE); } - const MgmtLongTermKeyInfo& getLongTermKey() const { - return *reinterpret_cast<const MgmtLongTermKeyInfo *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) ); + const MgmtLongTermKey& getLongTermKey() const { + return *reinterpret_cast<const MgmtLongTermKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) ); } - jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtLongTermKeyInfo); } + jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtLongTermKey); } jau::nsize_t getDataSize() const noexcept override { return 0; } const uint8_t* getData() const noexcept override { return nullptr; } }; @@ -2192,7 +2256,7 @@ namespace direct_bt { public: MgmtEvtNewIdentityResolvingKey(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvent(buffer, buffer_len, 1+6+sizeof(MgmtIdentityResolvingKeyInfo)) + : MgmtEvent(buffer, buffer_len, 1+6+sizeof(MgmtIdentityResolvingKey)) { checkOpcode(getOpcode(), Opcode::NEW_IRK); } @@ -2201,11 +2265,11 @@ namespace direct_bt { const EUI48& getRandomAddress() const { return *reinterpret_cast<const EUI48 *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) ); } - const MgmtIdentityResolvingKeyInfo& getIdentityResolvingKey() const { - return *reinterpret_cast<const MgmtIdentityResolvingKeyInfo *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1 + 6) ); + const MgmtIdentityResolvingKey& getIdentityResolvingKey() const { + return *reinterpret_cast<const MgmtIdentityResolvingKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1 + 6) ); } - jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtIdentityResolvingKeyInfo); } + jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtIdentityResolvingKey); } jau::nsize_t getDataSize() const noexcept override { return 0; } const uint8_t* getData() const noexcept override { return nullptr; } }; @@ -2213,7 +2277,7 @@ namespace direct_bt { /** * uint8_t store_hint, * EUI48 random_address; - * MgmtSignatureResolvingKeyInfo key + * MgmtSignatureResolvingKey key */ class MgmtEvtNewSignatureResolvingKey : public MgmtEvent { @@ -2225,18 +2289,18 @@ namespace direct_bt { public: MgmtEvtNewSignatureResolvingKey(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvent(buffer, buffer_len, 1+sizeof(MgmtSignatureResolvingKeyInfo)) + : MgmtEvent(buffer, buffer_len, 1+sizeof(MgmtSignatureResolvingKey)) { checkOpcode(getOpcode(), Opcode::NEW_CSRK); } uint8_t getStoreHint() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE); } - const MgmtSignatureResolvingKeyInfo& getSignatureResolvingKey() const { - return *reinterpret_cast<const MgmtSignatureResolvingKeyInfo *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) ); + const MgmtSignatureResolvingKey& getSignatureResolvingKey() const { + return *reinterpret_cast<const MgmtSignatureResolvingKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) ); } - jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtSignatureResolvingKeyInfo); } + jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtSignatureResolvingKey); } jau::nsize_t getDataSize() const noexcept override { return 0; } const uint8_t* getData() const noexcept override { return nullptr; } }; @@ -2525,14 +2589,14 @@ namespace direct_bt { const uint8_t* getData() const noexcept override { return nullptr; } /** - * Convert this instance into its platform agnostic SMPLongTermKeyInfo type, + * Convert this instance into its platform agnostic SMPLongTermKey type, * invalid without LTK. * * LTK shall be completed via MgmtEvtHCILELTKReplyAckCmd. * * Local device’s role is BTRole::Slave, responder. */ - SMPLongTermKey toSMPLongTermKeyInfo(const bool isSC, const bool isAuth) const noexcept { + SMPLongTermKey toSMPLongTermKey(const bool isSC, const bool isAuth) const noexcept { direct_bt::SMPLongTermKey res; res.clear(); res.properties |= SMPLongTermKey::Property::RESPONDER; @@ -2709,13 +2773,13 @@ namespace direct_bt { const uint8_t* getData() const noexcept override { return nullptr; } /** - * Convert this instance into its platform agnostic SMPLongTermKeyInfo LTK. + * Convert this instance into its platform agnostic SMPLongTermKey LTK. * * Local device’s role is BTRole::Master, initiator. * * This LTK Encryption key is for the remote device having role BTRole::Slave (responder). */ - SMPLongTermKey toSMPLongTermKeyInfo(const bool isSC, const bool isAuth) const noexcept { + SMPLongTermKey toSMPLongTermKey(const bool isSC, const bool isAuth) const noexcept { direct_bt::SMPLongTermKey res; res.clear(); res.properties |= SMPLongTermKey::Property::RESPONDER; diff --git a/api/direct_bt/SMPKeyBin.hpp b/api/direct_bt/SMPKeyBin.hpp index 5b6859e6..acf7d476 100644 --- a/api/direct_bt/SMPKeyBin.hpp +++ b/api/direct_bt/SMPKeyBin.hpp @@ -78,31 +78,33 @@ class BTAdapter; // forward */ class SMPKeyBin { public: - constexpr static const uint16_t VERSION = (uint16_t)0b0101010101010101U + (uint16_t)5U; // bitpattern + version + constexpr static const uint16_t VERSION = (uint16_t)0b0101010101010101U + (uint16_t)6U; // bitpattern + version private: uint16_t version; // 2 uint16_t size; // 2 uint64_t ts_creation_sec; // 8 + BTRole localRole; // 1 BDAddressAndType localAddress; // 7 BDAddressAndType remoteAddress; // 7 BTSecurityLevel sec_level; // 1 SMPIOCapability io_cap; // 1 SMPKeyType keys_init; // 1 - SMPKeyType keys_resp; // 1 + SMPKeyType keys_resp; // 1 -> 31 SMPLongTermKey ltk_init; // 28 (optional) - SMPIdentityResolvingKey irk_init; // 17 (optional) + SMPIdentityResolvingKey irk_init; // 23 (optional) SMPSignatureResolvingKey csrk_init; // 17 (optional) SMPLinkKey lk_init; // 19 (optional) SMPLongTermKey ltk_resp; // 28 (optional) - SMPIdentityResolvingKey irk_resp; // 17 (optional) + SMPIdentityResolvingKey irk_resp; // 23 (optional) SMPSignatureResolvingKey csrk_resp; // 17 (optional) SMPLinkKey lk_resp; // 19 (optional) - // Min-Max: 30 - 190 bytes + constexpr static const int byte_size_max = 205; + constexpr static const int byte_size_min = 31; bool verbose; @@ -111,6 +113,7 @@ class SMPKeyBin { s += sizeof(version); s += sizeof(size); s += sizeof(ts_creation_sec); + s += sizeof(localRole); s += sizeof(localAddress.address); s += sizeof(localAddress.type); s += sizeof(remoteAddress.address); @@ -234,11 +237,12 @@ class SMPKeyBin { static std::vector<SMPKeyBin> readAll(const std::string& dname, const bool verbose_); static std::vector<SMPKeyBin> readAllForLocalAdapter(const BDAddressAndType& localAddress, const std::string& dname, const bool verbose_); - SMPKeyBin(BDAddressAndType localAddress_, + SMPKeyBin(BTRole localRole_, BDAddressAndType localAddress_, BDAddressAndType remoteAddress_, const BTSecurityLevel sec_level_, const SMPIOCapability io_cap_) : version(VERSION), size(0), ts_creation_sec( jau::getWallClockSeconds() ), + localRole(localRole_), localAddress(std::move(localAddress_)), remoteAddress(std::move(remoteAddress_)), sec_level(sec_level_), io_cap(io_cap_), keys_init(SMPKeyType::NONE), keys_resp(SMPKeyType::NONE), @@ -250,6 +254,7 @@ class SMPKeyBin { SMPKeyBin() : version(VERSION), size(0), ts_creation_sec(0), + localRole(BTRole::None), localAddress(), remoteAddress(), sec_level(BTSecurityLevel::UNSET), io_cap(SMPIOCapability::UNSET), keys_init(SMPKeyType::NONE), keys_resp(SMPKeyType::NONE), @@ -267,6 +272,9 @@ class SMPKeyBin { /** Returns the creation timestamp in seconds since Unix epoch */ constexpr uint64_t getCreationTime() const noexcept { return ts_creation_sec; } + /** Return the local adapter BTRole. */ + constexpr BTRole getLocalRole() const noexcept { return localRole; } + /** Return the local adapter address. */ constexpr const BDAddressAndType& getLocalAddrAndType() const noexcept { return localAddress; } @@ -354,13 +362,20 @@ class SMPKeyBin { * */ constexpr bool isValid() const noexcept { + // local_is_responder == true: responder's IRK info (LL slave), else the initiator's (LL master) + const bool local_is_responder = BTRole::Slave == localRole; + const BDAddressAndType& responderAddress = local_is_responder ? localAddress : remoteAddress; + const BDAddressAndType& initiatorAddress = local_is_responder ? remoteAddress : localAddress; + return isVersionValid() && isSizeValid() && BTSecurityLevel::UNSET != sec_level && SMPIOCapability::UNSET != io_cap && ( !hasLTKInit() || ltk_init.isValid() ) && ( !hasLTKResp() || ltk_resp.isValid() ) && ( !hasLKInit() || lk_init.isValid() ) && - ( !hasLKResp() || lk_resp.isValid() ); + ( !hasLKResp() || lk_resp.isValid() ) && + ( !hasIRKInit() || irk_init.id_address == initiatorAddress.address ) && + ( !hasIRKResp() || irk_resp.id_address == responderAddress.address ); } std::string toString() const noexcept; diff --git a/api/direct_bt/SMPTypes.hpp b/api/direct_bt/SMPTypes.hpp index 7e75d415..b628a554 100644 --- a/api/direct_bt/SMPTypes.hpp +++ b/api/direct_bt/SMPTypes.hpp @@ -613,6 +613,8 @@ namespace direct_bt { Property properties; /** Identity Resolving Key (IRK) */ jau::uint128_t irk; + /** Identity Address for the IRK */ + EUI48 id_address; bool isResponder() const noexcept; @@ -628,7 +630,7 @@ namespace direct_bt { std::string toString() const noexcept { // hex-fmt aligned with btmon return "IRK[props "+getPropertyString(properties)+ - ", irk "+jau::bytesHexString(irk.data, 0, sizeof(irk), true /* lsbFirst */)+ + ", id "+id_address.toString()+", irk "+jau::bytesHexString(irk.data, 0, sizeof(irk), true /* lsbFirst */)+ "]"; } } ); |