summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/direct_bt/DBTDevice.hpp24
-rw-r--r--api/direct_bt/SMPTypes.hpp62
-rw-r--r--examples/direct_bt_scanner10/dbt_scanner10.cpp47
-rw-r--r--examples/java/DBTScanner10.java109
-rw-r--r--java/direct_bt/tinyb/DBTDevice.java16
-rw-r--r--java/jni/direct_bt/DBTDevice.cxx36
-rw-r--r--java/org/tinyb/BluetoothDevice.java22
-rw-r--r--java/org/tinyb/SMPKeyMask.java165
-rw-r--r--java/org/tinyb/SMPSignatureResolvingKeyInfo.java187
-rw-r--r--java/tinyb/dbus/DBusDevice.java8
-rw-r--r--src/direct_bt/DBTDevice.cpp80
-rw-r--r--src/direct_bt/SMPTypes.cpp38
12 files changed, 714 insertions, 80 deletions
diff --git a/api/direct_bt/DBTDevice.hpp b/api/direct_bt/DBTDevice.hpp
index 22772080..ae363599 100644
--- a/api/direct_bt/DBTDevice.hpp
+++ b/api/direct_bt/DBTDevice.hpp
@@ -95,8 +95,8 @@ namespace direct_bt {
SMPIOCapability ioCap_init, ioCap_resp;
SMPOOBDataFlag oobFlag_init, oobFlag_resp;
uint8_t maxEncsz_init, maxEncsz_resp;
- SMPKeyDist keys_init_exp, keys_resp_exp;
- SMPKeyDist keys_init_has, keys_resp_has;
+ SMPKeyType keys_init_exp, keys_resp_exp;
+ SMPKeyType keys_init_has, keys_resp_has;
// LTK: Set of Long Term Key data: ltk, ediv + rand
SMPLongTermKeyInfo ltk_init, ltk_resp;
@@ -107,7 +107,7 @@ namespace direct_bt {
bool is_static_random_address;
// CSRK
- jau::uint128_t csrk_init, csrk_resp;
+ SMPSignatureResolvingKeyInfo csrk_init, csrk_resp;
};
PairingData pairing_data;
std::mutex mtx_pairing;
@@ -447,7 +447,14 @@ namespace direct_bt {
HCIStatusCode disconnect(const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION ) noexcept;
/**
- * Returns a copy of the long term ket (LTK) info, valid after connection and SMP pairing has been completed.
+ * Returns the available ::SMPKeyType mask for the responder (LL slave) or initiator (LL master).
+ * @param responder if true, queries the responder (LL slave) key, otherwise the initiator (LL master) key.
+ * @return ::SMPKeyType mask result
+ */
+ SMPKeyType getAvailableSMPKeys(const bool responder) const noexcept;
+
+ /**
+ * Returns a copy of the Long Term Key (LTK) info, valid after connection and SMP pairing has been completed.
* @param responder true will return the responder's LTK info (remote device, LL slave), otherwise the initiator's (the LL master).
* @return the resulting key. SMPLongTermKeyInfo::enc_size will be zero if invalid.
* @see ::SMPPairingState::COMPLETED
@@ -466,6 +473,15 @@ namespace direct_bt {
HCIStatusCode setLongTermKeyInfo(const SMPLongTermKeyInfo& ltk) noexcept;
/**
+ * Returns a copy of the Signature Resolving Key (LTK) info, valid after connection and SMP pairing has been completed.
+ * @param responder true will return the responder's LTK info (remote device, LL slave), otherwise the initiator's (the LL master).
+ * @return the resulting key
+ * @see ::SMPPairingState::COMPLETED
+ * @see AdapterStatusListener::deviceReady()
+ */
+ SMPSignatureResolvingKeyInfo getSignatureResolvingKeyInfo(const bool responder) const noexcept;
+
+ /**
* Unpairs this device from the adapter while staying connected.
* <p>
* All keys will be cleared within the adapter and host implementation.<br>
diff --git a/api/direct_bt/SMPTypes.hpp b/api/direct_bt/SMPTypes.hpp
index 42d709d8..2b30ffc4 100644
--- a/api/direct_bt/SMPTypes.hpp
+++ b/api/direct_bt/SMPTypes.hpp
@@ -331,7 +331,7 @@ namespace direct_bt {
const SMPIOCapability ioCap_ini, const SMPIOCapability ioCap_res) noexcept;
/**
- * SMP Key Distribution, indicates keys distributed in the Transport Specific Key Distribution phase.
+ * SMP Key Type for Distribution, indicates keys distributed in the Transport Specific Key Distribution phase.
* <pre>
* Field format and usage: Vol 3, Part H, 3.6.1 SMP - LE Security - Key distribution and generation.
* See also Vol 3, Part H, 2.4.3 SM - LE Security - Distribution of keys.
@@ -342,7 +342,7 @@ namespace direct_bt {
* uint8_t EncKey : 1, IdKey : 1, SignKey : 1, LinkKey : 1, RFU : 4;
* </pre>
*/
- enum class SMPKeyDist : uint8_t {
+ enum class SMPKeyType : uint8_t {
NONE = 0,
/**
* LE legacy pairing: Indicates device shall distribute LTK using the Encryption Information command,
@@ -386,41 +386,41 @@ namespace direct_bt {
/** Reserved for future use */
RFU_4 = 0b10000000
};
- constexpr SMPKeyDist operator ^(const SMPKeyDist lhs, const SMPKeyDist rhs) noexcept {
- return static_cast<SMPKeyDist> ( static_cast<uint8_t>(lhs) ^ static_cast<uint8_t>(rhs) );
+ constexpr SMPKeyType operator ^(const SMPKeyType lhs, const SMPKeyType rhs) noexcept {
+ return static_cast<SMPKeyType> ( static_cast<uint8_t>(lhs) ^ static_cast<uint8_t>(rhs) );
}
- constexpr SMPKeyDist& operator ^=(SMPKeyDist& store, const SMPKeyDist& rhs) noexcept {
- store = static_cast<SMPKeyDist> ( static_cast<uint8_t>(store) ^ static_cast<uint8_t>(rhs) );
+ constexpr SMPKeyType& operator ^=(SMPKeyType& store, const SMPKeyType& rhs) noexcept {
+ store = static_cast<SMPKeyType> ( static_cast<uint8_t>(store) ^ static_cast<uint8_t>(rhs) );
return store;
}
- constexpr SMPKeyDist operator |(const SMPKeyDist lhs, const SMPKeyDist rhs) noexcept {
- return static_cast<SMPKeyDist> ( static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs) );
+ constexpr SMPKeyType operator |(const SMPKeyType lhs, const SMPKeyType rhs) noexcept {
+ return static_cast<SMPKeyType> ( static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs) );
}
- constexpr SMPKeyDist& operator |=(SMPKeyDist& store, const SMPKeyDist& rhs) noexcept {
- store = static_cast<SMPKeyDist> ( static_cast<uint8_t>(store) | static_cast<uint8_t>(rhs) );
+ constexpr SMPKeyType& operator |=(SMPKeyType& store, const SMPKeyType& rhs) noexcept {
+ store = static_cast<SMPKeyType> ( static_cast<uint8_t>(store) | static_cast<uint8_t>(rhs) );
return store;
}
- constexpr SMPKeyDist operator &(const SMPKeyDist lhs, const SMPKeyDist rhs) noexcept {
- return static_cast<SMPKeyDist> ( static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs) );
+ constexpr SMPKeyType operator &(const SMPKeyType lhs, const SMPKeyType rhs) noexcept {
+ return static_cast<SMPKeyType> ( static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs) );
}
- constexpr SMPKeyDist& operator &=(SMPKeyDist& store, const SMPKeyDist& rhs) noexcept {
- store = static_cast<SMPKeyDist> ( static_cast<uint8_t>(store) & static_cast<uint8_t>(rhs) );
+ constexpr SMPKeyType& operator &=(SMPKeyType& store, const SMPKeyType& rhs) noexcept {
+ store = static_cast<SMPKeyType> ( static_cast<uint8_t>(store) & static_cast<uint8_t>(rhs) );
return store;
}
- constexpr bool operator ==(const SMPKeyDist lhs, const SMPKeyDist rhs) noexcept {
+ constexpr bool operator ==(const SMPKeyType lhs, const SMPKeyType rhs) noexcept {
return static_cast<uint8_t>(lhs) == static_cast<uint8_t>(rhs);
}
- constexpr bool operator !=(const SMPKeyDist lhs, const SMPKeyDist rhs) noexcept {
+ constexpr bool operator !=(const SMPKeyType lhs, const SMPKeyType rhs) noexcept {
return !( lhs == rhs );
}
- constexpr uint8_t number(const SMPKeyDist rhs) noexcept {
+ constexpr uint8_t number(const SMPKeyType rhs) noexcept {
return static_cast<uint8_t>(rhs);
}
- constexpr bool isKeyDistBitSet(const SMPKeyDist mask, const SMPKeyDist bit) noexcept {
- return SMPKeyDist::NONE != ( mask & bit );
+ constexpr bool isKeyDistBitSet(const SMPKeyType mask, const SMPKeyType bit) noexcept {
+ return SMPKeyType::NONE != ( mask & bit );
}
- std::string getSMPKeyDistBitString(const SMPKeyDist bit) noexcept;
- std::string getSMPKeyDistMaskString(const SMPKeyDist mask) noexcept;
+ std::string getSMPKeyTypeBitString(const SMPKeyType bit) noexcept;
+ std::string getSMPKeyTypeMaskString(const SMPKeyType mask) noexcept;
/**
* SMP Long Term Key Info, used for platform agnostic persistence.
@@ -822,16 +822,16 @@ namespace direct_bt {
private:
const bool request;
const SMPAuthReqs authReqMask;
- const SMPKeyDist initiator_key_dist;
- const SMPKeyDist responder_key_dist;
+ const SMPKeyType initiator_key_dist;
+ const SMPKeyType responder_key_dist;
public:
SMPPairingMsg(const bool request_, const uint8_t* source, const jau::nsize_t length)
: SMPPDUMsg(source, length),
request(request_),
authReqMask(static_cast<SMPAuthReqs>( pdu.get_uint8_nc(3) )),
- initiator_key_dist(static_cast<SMPKeyDist>(pdu.get_uint8_nc(5))),
- responder_key_dist(static_cast<SMPKeyDist>(pdu.get_uint8_nc(6)))
+ initiator_key_dist(static_cast<SMPKeyType>(pdu.get_uint8_nc(5))),
+ responder_key_dist(static_cast<SMPKeyType>(pdu.get_uint8_nc(6)))
{
checkOpcode(request? Opcode::PAIRING_REQUEST : Opcode::PAIRING_RESPONSE);
}
@@ -839,8 +839,8 @@ namespace direct_bt {
SMPPairingMsg(const bool request_,
const SMPIOCapability ioc, const SMPOOBDataFlag odf,
const SMPAuthReqs auth_req_mask, const uint8_t maxEncKeySize,
- const SMPKeyDist initiator_key_dist_,
- const SMPKeyDist responder_key_dist_)
+ const SMPKeyType initiator_key_dist_,
+ const SMPKeyType responder_key_dist_)
: SMPPDUMsg(request_? Opcode::PAIRING_REQUEST : Opcode::PAIRING_RESPONSE, 1+6),
request(request_),
authReqMask(auth_req_mask), initiator_key_dist(initiator_key_dist_), responder_key_dist(responder_key_dist_)
@@ -911,7 +911,7 @@ namespace direct_bt {
* </pre>
* @see SMPKeyDistFormat
*/
- constexpr SMPKeyDist getInitKeyDist() const noexcept {
+ constexpr SMPKeyType getInitKeyDist() const noexcept {
return initiator_key_dist;
}
/**
@@ -924,7 +924,7 @@ namespace direct_bt {
* </p>
* @see SMPKeyDistFormat
*/
- constexpr SMPKeyDist getRespKeyDist() const noexcept {
+ constexpr SMPKeyType getRespKeyDist() const noexcept {
return responder_key_dist;
}
@@ -938,8 +938,8 @@ namespace direct_bt {
", oob "+getSMPOOBDataFlagString(getOOBDataFlag())+
", auth_req "+getSMPAuthReqMaskString(getAuthReqMask())+
", max_keysz "+std::to_string(getMaxEncryptionKeySize())+
- ", key_dist[init "+getSMPKeyDistMaskString(getInitKeyDist())+
- ", resp "+getSMPKeyDistMaskString(getRespKeyDist())+
+ ", key_dist[init "+getSMPKeyTypeMaskString(getInitKeyDist())+
+ ", resp "+getSMPKeyTypeMaskString(getRespKeyDist())+
"]";
}
};
diff --git a/examples/direct_bt_scanner10/dbt_scanner10.cpp b/examples/direct_bt_scanner10/dbt_scanner10.cpp
index 1336c71e..99b85e89 100644
--- a/examples/direct_bt_scanner10/dbt_scanner10.cpp
+++ b/examples/direct_bt_scanner10/dbt_scanner10.cpp
@@ -195,6 +195,35 @@ __pack( struct MyLongTermKeyInfo {
}
} );
+__pack( struct MySignatureResolvingKeyInfo {
+ EUI48 address;
+ BDAddressType address_type;
+ SMPSignatureResolvingKeyInfo smp_csrk;
+
+ bool write(const std::string filename) {
+ std::ofstream file(filename, std::ios::binary | std::ios::trunc);
+ file.write((char*)this, sizeof(*this));
+ file.close();
+ fprintf(stderr, "****** WRITE CSRK [%s %s, written]: %s\n",
+ address.toString().c_str(), getBDAddressTypeString(address_type).c_str(),
+ smp_csrk.toString().c_str());
+ return true;
+ }
+
+ bool read(const std::string filename) {
+ std::ifstream file(filename, std::ios::binary);
+ if (!file.is_open() ) {
+ return false;
+ }
+ file.read((char*)this, sizeof(*this));
+ file.close();
+ fprintf(stderr, "****** READ CSRK [%s %s]: %s\n",
+ address.toString().c_str(), getBDAddressTypeString(address_type).c_str(),
+ smp_csrk.toString().c_str());
+ return true;
+ }
+} );
+
class MyAdapterStatusListener : public AdapterStatusListener {
void adapterSettingsChanged(DBTAdapter &a, const AdapterSetting oldmask, const AdapterSetting newmask,
@@ -448,16 +477,30 @@ static void processReadyDevice(std::shared_ptr<DBTDevice> device) {
const SMPPairingState pstate = device->getPairingState();
const PairingMode pmode = device->getPairingMode(); // Skip PairingMode::PRE_PAIRED (write again)
if( SMPPairingState::COMPLETED == pstate && PairingMode::PRE_PAIRED != pmode ) {
- {
+ const SMPKeyType keys_resp = device->getAvailableSMPKeys(true /* responder */);
+ const SMPKeyType keys_init = device->getAvailableSMPKeys(false /* responder */);
+
+ if( ( SMPKeyType::ENC_KEY & keys_init ) != SMPKeyType::NONE ) {
MyLongTermKeyInfo my_ltk { device->getAddress(), device->getAddressType(),
device->getLongTermKeyInfo(false /* responder */) };
my_ltk.write(my_ltk.address.toString()+".init.ltk");
}
- {
+ if( ( SMPKeyType::ENC_KEY & keys_resp ) != SMPKeyType::NONE ) {
MyLongTermKeyInfo my_ltk { device->getAddress(), device->getAddressType(),
device->getLongTermKeyInfo(true /* responder */) };
my_ltk.write(my_ltk.address.toString()+".resp.ltk");
}
+
+ if( ( SMPKeyType::SIGN_KEY & keys_init ) != SMPKeyType::NONE ) {
+ MySignatureResolvingKeyInfo my_csrk { device->getAddress(), device->getAddressType(),
+ device->getSignatureResolvingKeyInfo(false /* responder */) };
+ my_csrk.write(my_csrk.address.toString()+".init.csrk");
+ }
+ if( ( SMPKeyType::SIGN_KEY & keys_resp ) != SMPKeyType::NONE ) {
+ MySignatureResolvingKeyInfo my_csrk { device->getAddress(), device->getAddressType(),
+ device->getSignatureResolvingKeyInfo(true /* responder */) };
+ my_csrk.write(my_csrk.address.toString()+".resp.csrk");
+ }
}
}
#if 1
diff --git a/examples/java/DBTScanner10.java b/examples/java/DBTScanner10.java
index f995bce8..c5b1ebeb 100644
--- a/examples/java/DBTScanner10.java
+++ b/examples/java/DBTScanner10.java
@@ -65,8 +65,10 @@ import org.tinyb.HCIStatusCode;
import org.tinyb.HCIWhitelistConnectType;
import org.tinyb.PairingMode;
import org.tinyb.SMPIOCapability;
+import org.tinyb.SMPKeyMask;
import org.tinyb.SMPLongTermKeyInfo;
import org.tinyb.SMPPairingState;
+import org.tinyb.SMPSignatureResolvingKeyInfo;
import org.tinyb.ScanType;
import direct_bt.tinyb.DBTManager;
@@ -144,6 +146,11 @@ public class DBTScanner10 {
BluetoothAddressType address_type;
SMPLongTermKeyInfo smp_ltk;
+ MyLongTermKeyInfo(final EUI48 address, final BluetoothAddressType address_type, final SMPLongTermKeyInfo smp_ltk) {
+ this.address = address;
+ this.address_type = address_type;
+ this.smp_ltk = smp_ltk;
+ }
MyLongTermKeyInfo() {
address = new EUI48();
address_type = BluetoothAddressType.BDADDR_UNDEFINED;
@@ -210,6 +217,78 @@ public class DBTScanner10 {
return false;
}
}
+ static public class MySignatureResolvingKeyInfo {
+ EUI48 address;
+ BluetoothAddressType address_type;
+ SMPSignatureResolvingKeyInfo smp_csrk;
+
+ MySignatureResolvingKeyInfo(final EUI48 address, final BluetoothAddressType address_type, final SMPSignatureResolvingKeyInfo smp_csrk) {
+ this.address = address;
+ this.address_type = address_type;
+ this.smp_csrk = smp_csrk;
+ }
+ MySignatureResolvingKeyInfo() {
+ address = new EUI48();
+ address_type = BluetoothAddressType.BDADDR_UNDEFINED;
+ smp_csrk = new SMPSignatureResolvingKeyInfo();
+ }
+
+ boolean write(final String filename) {
+ final File file = new File(filename);
+ OutputStream out = null;
+ try {
+ file.delete(); // alternative to truncate, if existing
+ out = new FileOutputStream(file);
+ out.write(address.b);
+ out.write(address_type.value);
+ final byte[] smp_ltk_b = new byte[SMPSignatureResolvingKeyInfo.byte_size];
+ smp_csrk.getStream(smp_ltk_b, 0);
+ out.write(smp_ltk_b);
+ println("****** WRITE CSRK ["+address+" "+address_type+", written]: "+smp_csrk);
+ return true;
+ } catch (final Exception ex) {
+ ex.printStackTrace();
+ } finally {
+ try {
+ if( null != out ) {
+ out.close();
+ }
+ } catch (final IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+
+ boolean read(final String filename) {
+ final File file = new File(filename);
+ InputStream in = null;
+ try {
+ final byte[] buffer = new byte[6 + 1 + SMPSignatureResolvingKeyInfo.byte_size];
+ in = new FileInputStream(file);
+ final int read_count = in.read(buffer, 0, buffer.length);
+ if( read_count != buffer.length ) {
+ throw new IOException("Couldn't read "+buffer.length+" bytes, only "+read_count+" from "+filename);
+ }
+ address.putStream(buffer, 0);
+ address_type = BluetoothAddressType.get(buffer[6]);
+ smp_csrk.putStream(buffer, 6+1);
+ println("****** READ CSRK ["+address+" "+address_type+"]: "+smp_csrk);
+ return true;
+ } catch (final Exception ex) {
+ ex.printStackTrace();
+ } finally {
+ try {
+ if( null != in ) {
+ in.close();
+ }
+ } catch (final IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+ }
Collection<EUI48> devicesInProcessing = Collections.synchronizedCollection(new ArrayList<>());
Collection<EUI48> devicesProcessed = Collections.synchronizedCollection(new ArrayList<>());
@@ -442,20 +521,30 @@ public class DBTScanner10 {
final SMPPairingState pstate = device.getPairingState();
final PairingMode pmode = device.getPairingMode(); // Skip PairingMode::PRE_PAIRED (write again)
if( SMPPairingState.COMPLETED == pstate && PairingMode.PRE_PAIRED != pmode ) {
- {
- final MyLongTermKeyInfo my_ltk = new MyLongTermKeyInfo();
- my_ltk.address = device.getAddress();
- my_ltk.address_type = device.getAddressType();
- my_ltk.smp_ltk = device.getLongTermKeyInfo(false /* responder */);
+ final SMPKeyMask keys_resp = device.getAvailableSMPKeys(true /* responder */);
+ final SMPKeyMask keys_init = device.getAvailableSMPKeys(false /* responder */);
+
+ if( keys_init.isSet(SMPKeyMask.KeyType.ENC_KEY) ) {
+ final MyLongTermKeyInfo my_ltk = new MyLongTermKeyInfo(device.getAddress(), device.getAddressType(),
+ device.getLongTermKeyInfo(false /* responder */));
my_ltk.write(my_ltk.address.toString()+".init.ltk");
}
- {
- final MyLongTermKeyInfo my_ltk = new MyLongTermKeyInfo();
- my_ltk.address = device.getAddress();
- my_ltk.address_type = device.getAddressType();
- my_ltk.smp_ltk = device.getLongTermKeyInfo(true /* responder */);
+ if( keys_resp.isSet(SMPKeyMask.KeyType.ENC_KEY) ) {
+ final MyLongTermKeyInfo my_ltk = new MyLongTermKeyInfo(device.getAddress(), device.getAddressType(),
+ device.getLongTermKeyInfo(true /* responder */));
my_ltk.write(my_ltk.address.toString()+".resp.ltk");
}
+
+ if( keys_init.isSet(SMPKeyMask.KeyType.SIGN_KEY) ) {
+ final MySignatureResolvingKeyInfo my_csrk = new MySignatureResolvingKeyInfo(device.getAddress(), device.getAddressType(),
+ device.getSignatureResolvingKeyInfo(false /* responder */));
+ my_csrk.write(my_csrk.address.toString()+".init.csrk");
+ }
+ if( keys_resp.isSet(SMPKeyMask.KeyType.SIGN_KEY) ) {
+ final MySignatureResolvingKeyInfo my_csrk = new MySignatureResolvingKeyInfo(device.getAddress(), device.getAddressType(),
+ device.getSignatureResolvingKeyInfo(true /* responder */));
+ my_csrk.write(my_csrk.address.toString()+".resp.csrk");
+ }
}
}
diff --git a/java/direct_bt/tinyb/DBTDevice.java b/java/direct_bt/tinyb/DBTDevice.java
index 6f5b1f37..3a07b144 100644
--- a/java/direct_bt/tinyb/DBTDevice.java
+++ b/java/direct_bt/tinyb/DBTDevice.java
@@ -49,8 +49,10 @@ import org.tinyb.GATTCharacteristicListener;
import org.tinyb.HCIStatusCode;
import org.tinyb.PairingMode;
import org.tinyb.SMPIOCapability;
+import org.tinyb.SMPKeyMask;
import org.tinyb.SMPLongTermKeyInfo;
import org.tinyb.SMPPairingState;
+import org.tinyb.SMPSignatureResolvingKeyInfo;
public class DBTDevice extends DBTObject implements BluetoothDevice
{
@@ -329,6 +331,12 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
public final BluetoothDevice clone() { throw new UnsupportedOperationException(); } // FIXME
@Override
+ public final SMPKeyMask getAvailableSMPKeys(final boolean responder) {
+ return new SMPKeyMask(getAvailableSMPKeysImpl(responder));
+ }
+ private final native byte getAvailableSMPKeysImpl(final boolean responder);
+
+ @Override
public final SMPLongTermKeyInfo getLongTermKeyInfo(final boolean responder) {
final byte[] stream = new byte[SMPLongTermKeyInfo.byte_size];
getLongTermKeyInfoImpl(responder, stream);
@@ -345,6 +353,14 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
private final native byte setLongTermKeyInfoImpl(final byte[] source);
@Override
+ public final SMPSignatureResolvingKeyInfo getSignatureResolvingKeyInfo(final boolean responder) {
+ final byte[] stream = new byte[SMPSignatureResolvingKeyInfo.byte_size];
+ getSignatureResolvingKeyInfoImpl(responder, stream);
+ return new SMPSignatureResolvingKeyInfo(stream, 0);
+ }
+ private final native void getSignatureResolvingKeyInfoImpl(final boolean responder, final byte[] sink);
+
+ @Override
public final boolean pair() throws BluetoothException {
return false;
}
diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx
index c61dfb03..ea821818 100644
--- a/java/jni/direct_bt/DBTDevice.cxx
+++ b/java/jni/direct_bt/DBTDevice.cxx
@@ -378,6 +378,18 @@ jbyte Java_direct_1bt_tinyb_DBTDevice_connectLEImpl1(JNIEnv *env, jobject obj,
return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE);
}
+jbyte Java_direct_1bt_tinyb_DBTDevice_getAvailableSMPKeysImpl(JNIEnv *env, jobject obj, jboolean responder) {
+ try {
+ DBTDevice *device = getJavaUplinkObject<DBTDevice>(env, obj);
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+
+ return number( device->getAvailableSMPKeys(JNI_TRUE == responder) ); // assign data of new key copy to JNI critical-array
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return 0;
+}
+
void Java_direct_1bt_tinyb_DBTDevice_getLongTermKeyInfoImpl(JNIEnv *env, jobject obj, jboolean responder, jbyteArray jsink) {
try {
DBTDevice *device = getJavaUplinkObject<DBTDevice>(env, obj);
@@ -429,6 +441,30 @@ jbyte Java_direct_1bt_tinyb_DBTDevice_setLongTermKeyInfoImpl(JNIEnv *env, jobjec
return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE);
}
+void Java_direct_1bt_tinyb_DBTDevice_getSignatureResolvingKeyInfoImpl(JNIEnv *env, jobject obj, jboolean responder, jbyteArray jsink) {
+ try {
+ DBTDevice *device = getJavaUplinkObject<DBTDevice>(env, obj);
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+
+ if( nullptr == jsink ) {
+ throw IllegalArgumentException("byte array null", E_FILE_LINE);
+ }
+ const size_t sink_size = env->GetArrayLength(jsink);
+ if( sizeof(SMPSignatureResolvingKeyInfo) > sink_size ) {
+ throw IllegalArgumentException("byte array "+std::to_string(sink_size)+" < "+std::to_string(sizeof(SMPSignatureResolvingKeyInfo)), E_FILE_LINE);
+ }
+ JNICriticalArray<uint8_t, jbyteArray> criticalArray(env); // RAII - release
+ uint8_t * sink_ptr = criticalArray.get(jsink, criticalArray.Mode::UPDATE_AND_RELEASE);
+ if( NULL == sink_ptr ) {
+ throw InternalError("GetPrimitiveArrayCritical(byte array) is null", E_FILE_LINE);
+ }
+ SMPSignatureResolvingKeyInfo& csrk_sink = *reinterpret_cast<SMPSignatureResolvingKeyInfo *>(sink_ptr);
+ csrk_sink = device->getSignatureResolvingKeyInfo(JNI_TRUE == responder); // assign data of new key copy to JNI critical-array
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+}
+
jbyte Java_direct_1bt_tinyb_DBTDevice_unpairImpl(JNIEnv *env, jobject obj) {
try {
DBTDevice *device = getJavaUplinkObject<DBTDevice>(env, obj);
diff --git a/java/org/tinyb/BluetoothDevice.java b/java/org/tinyb/BluetoothDevice.java
index 23eb930c..b1bcdc8d 100644
--- a/java/org/tinyb/BluetoothDevice.java
+++ b/java/org/tinyb/BluetoothDevice.java
@@ -181,7 +181,16 @@ public interface BluetoothDevice extends BluetoothObject
boolean disconnectProfile(String arg_UUID) throws BluetoothException;
/**
- * Returns a copy of the long term ket (LTK) info, valid after connection and SMP pairing has been completed.
+ * Returns the available {@link SMPKeyMask.KeyType} {@link SMPKeyMask} for the responder (LL slave) or initiator (LL master).
+ * @param responder if true, queries the responder (LL slave) key, otherwise the initiator (LL master) key.
+ * @return {@link SMPKeyMask.KeyType} {@link SMPKeyMask} result
+ * @since 2.2.0
+ * @implNote not implemented in tinyb.dbus
+ */
+ SMPKeyMask getAvailableSMPKeys(final boolean responder);
+
+ /**
+ * Returns a copy of the long term key (LTK) info, valid after connection and SMP pairing has been completed.
* @param responder true will return the responder's LTK info (remote device, LL slave), otherwise the initiator's (the LL master).
* @return the resulting key. {@link SMPLongTermKeyInfo#enc_size} will be zero if invalid.
* @see {@link SMPPairingState#COMPLETED}
@@ -204,6 +213,17 @@ public interface BluetoothDevice extends BluetoothObject
HCIStatusCode setLongTermKeyInfo(final SMPLongTermKeyInfo ltk);
/**
+ * Returns a copy of the Signature Resolving Key (LTK) info, valid after connection and SMP pairing has been completed.
+ * @param responder true will return the responder's LTK info (remote device, LL slave), otherwise the initiator's (the LL master).
+ * @return the resulting key
+ * @see {@link SMPPairingState#COMPLETED}
+ * @see {@link AdapterStatusListener#deviceReady(BluetoothDevice, long)}
+ * @since 2.2.0
+ * @implNote not implemented in tinyb.dbus
+ */
+ SMPSignatureResolvingKeyInfo getSignatureResolvingKeyInfo(final boolean responder);
+
+ /**
* A secure connection to this device is established, and the device is then paired.
* <p>
* For direct_bt use {@link #setConnSecurity(BTSecurityLevel, SMPIOCapability) setConnSecurity(..) or its variants}
diff --git a/java/org/tinyb/SMPKeyMask.java b/java/org/tinyb/SMPKeyMask.java
new file mode 100644
index 00000000..eb362956
--- /dev/null
+++ b/java/org/tinyb/SMPKeyMask.java
@@ -0,0 +1,165 @@
+/**
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2020 Gothel Software e.K.
+ * Copyright (c) 2020 ZAFENA AB
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.tinyb;
+
+/**
+ * SMP Key Type for Distribution, indicates keys distributed in the Transport Specific Key Distribution phase.
+ * <p>
+ * {@link SMPKeyMask} {@link SMPKeyMask.KeyType} Bit Mask
+ * </p>
+ * <pre>
+ * Field format and usage: Vol 3, Part H, 3.6.1 SMP - LE Security - Key distribution and generation.
+ * See also Vol 3, Part H, 2.4.3 SM - LE Security - Distribution of keys.
+ * </pre>
+ * </p>
+ * Layout LSB -> MSB
+ * <pre>
+ * uint8_t EncKey : 1, IdKey : 1, SignKey : 1, LinkKey : 1, RFU : 4;
+ * </pre>
+ * @since 2.2.0
+ */
+public class SMPKeyMask {
+ /**
+ * {@link SMPKeyMask} Key Type
+ */
+ static public enum KeyType {
+ NONE ((byte)0),
+ /**
+ * LE legacy pairing: Indicates device shall distribute LTK using the Encryption Information command,
+ * followed by EDIV and Rand using the Master Identification command.
+ * <p>
+ * LE Secure Connections pairing (SMP on LE transport): Ignored,
+ * EDIV and Rand shall be zero and shall not be distributed.
+ * </p>
+ * <p>
+ * SMP on BR/EDR transport: Indicates device likes to derive LTK from BR/EDR Link Key.<br>
+ * When EncKey is set to 1 by both devices in the initiator and responder Key Distribution / Generation fields,
+ * the procedures for calculating the LTK from the BR/EDR Link Key shall be used.
+ * </p>
+ */
+ ENC_KEY ((byte) 0b00000001),
+ /**
+ * Indicates that the device shall distribute IRK using the Identity Information command
+ * followed by its public device or status random address using Identity Address Information.
+ */
+ ID_KEY ((byte) 0b00000010),
+ /**
+ * Indicates that the device shall distribute CSRK using the Signing Information command.
+ */
+ SIGN_KEY ((byte) 0b00000100),
+ /**
+ * SMP on the LE transport: Indicate that the device would like to derive the Link Key from the LTK.<br>
+ * When LinkKey is set to 1 by both devices in the initiator and responder Key Distribution / Generation fields,
+ * the procedures for calculating the BR/EDR link key from the LTK shall be used.<br>
+ * Devices not supporting LE Secure Connections shall set this bit to zero and ignore it on reception.
+ * <p>
+ * SMP on BR/EDR transport: Reserved for future use.
+ * </p>
+ */
+ LINK_KEY ((byte) 0b00001000),
+ /** Reserved for future use */
+ RFU_1 ((byte) 0b00010000),
+ /** Reserved for future use */
+ RFU_2 ((byte) 0b00100000),
+ /** Reserved for future use */
+ RFU_3 ((byte) 0b01000000),
+ /** Reserved for future use */
+ RFU_4 ((byte) 0b10000000);
+
+ public final byte value;
+
+ /**
+ * Maps the specified name to a constant of {@link KeyType}.
+ * <p>
+ * Implementation simply returns {@link #valueOf(String)}.
+ * This maps the constant names itself to their respective constant.
+ * </p>
+ * @param name the string name to be mapped to a constant of this enum type.
+ * @return the corresponding constant of this enum type.
+ * @throws IllegalArgumentException if the specified name can't be mapped to a constant of this enum type
+ * as described above.
+ */
+ public static KeyType get(final String name) throws IllegalArgumentException {
+ return valueOf(name);
+ }
+
+ /**
+ * Maps the specified integer value to a constant of {@link KeyType}.
+ * @param value the integer value to be mapped to a constant of this enum type.
+ * @return the corresponding constant of this enum type, using {@link #NONE} if not supported.
+ */
+ public static KeyType get(final byte value) {
+ switch(value) {
+ case (byte) 0b00000001: return ENC_KEY;
+ case (byte) 0b00000010: return ID_KEY;
+ case (byte) 0b00000100: return SIGN_KEY;
+ case (byte) 0b00001000: return LINK_KEY;
+ case (byte) 0b00010000: return RFU_1;
+ case (byte) 0b00100000: return RFU_2;
+ case (byte) 0b01000000: return RFU_3;
+ case (byte) 0b10000000: return RFU_4;
+ default: return NONE;
+ }
+ }
+
+ KeyType(final byte v) {
+ value = v;
+ }
+ }
+
+ /** The {@link KeyType} bit mask */
+ public byte mask;
+
+ public SMPKeyMask(final byte v) {
+ mask = v;
+ }
+
+ public SMPKeyMask() {
+ mask = (byte)0;
+ }
+
+ public boolean isEmpty() { return 0 == mask; }
+ public boolean isSet(final KeyType bit) { return 0 != ( mask & bit.value ); }
+ public void set(final KeyType bit) { mask = (byte) ( mask | bit.value ); }
+
+ @Override
+ public String toString() {
+ boolean has_pre = false;
+ final StringBuilder out = new StringBuilder();
+ out.append("[");
+ for(int i=0; i<8; i++) {
+ final KeyType key_type = KeyType.get( (byte) ( 1 << i ) );
+ if( isSet( key_type ) ) {
+ if( has_pre ) { out.append(", "); }
+ out.append( key_type.toString() );
+ has_pre = true;
+ }
+ }
+ out.append("]");
+ return out.toString();
+ }
+
+};
diff --git a/java/org/tinyb/SMPSignatureResolvingKeyInfo.java b/java/org/tinyb/SMPSignatureResolvingKeyInfo.java
new file mode 100644
index 00000000..cc9e818b
--- /dev/null
+++ b/java/org/tinyb/SMPSignatureResolvingKeyInfo.java
@@ -0,0 +1,187 @@
+/**
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2020 Gothel Software e.K.
+ * Copyright (c) 2020 ZAFENA AB
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.tinyb;
+
+/**
+ * SMP Signature Resolving Key Info, used for platform agnostic persistence.
+ * <p>
+ * Notable: No endian wise conversion shall occur on this data,
+ * since the encryption values are interpreted as a byte stream.
+ * </p>
+ * <p>
+ * Byte layout must be synchronized with native direct_bt::SMPSignatureResolvingKey
+ * </p>
+ * @since 2.2.0
+ */
+public class SMPSignatureResolvingKeyInfo {
+ /**
+ * {@link SMPSignatureResolvingKeyInfo} Property Bits
+ */
+ static public enum PropertyType {
+ /** No specific property */
+ NONE((byte)0),
+ /** Responder Key (LL slave). Absence indicates Initiator Key (LL master). */
+ RESPONDER((byte)0x01),
+ /** Authentication used. */
+ AUTH((byte)0x02);
+
+ public final byte value;
+
+ /**
+ * Maps the specified name to a constant of {@link PropertyType}.
+ * <p>
+ * Implementation simply returns {@link #valueOf(String)}.
+ * This maps the constant names itself to their respective constant.
+ * </p>
+ * @param name the string name to be mapped to a constant of this enum type.
+ * @return the corresponding constant of this enum type.
+ * @throws IllegalArgumentException if the specified name can't be mapped to a constant of this enum type
+ * as described above.
+ */
+ public static PropertyType get(final String name) throws IllegalArgumentException {
+ return valueOf(name);
+ }
+
+ /**
+ * Maps the specified integer value to a constant of {@link PropertyType}.
+ * @param value the integer value to be mapped to a constant of this enum type.
+ * @return the corresponding constant of this enum type, using {@link #NONE} if not supported.
+ */
+ public static PropertyType get(final byte value) {
+ switch(value) {
+ case (byte) 0x01: return RESPONDER;
+ case (byte) 0x02: return AUTH;
+ default: return NONE;
+ }
+ }
+
+ PropertyType(final byte v) {
+ value = v;
+ }
+ }
+
+ /**
+ * {@link SMPSignatureResolvingKeyInfo} {@link PropertyType} Bit Mask
+ */
+ static public class Properties {
+ /** The {@link PropertyType} bit mask */
+ public byte mask;
+
+ public Properties(final byte v) {
+ mask = v;
+ }
+
+ public boolean isEmpty() { return 0 == mask; }
+ public boolean isSet(final PropertyType bit) { return 0 != ( mask & bit.value ); }
+ public void set(final PropertyType bit) { mask = (byte) ( mask | bit.value ); }
+
+ @Override
+ public String toString() {
+ int count = 0;
+ final StringBuilder out = new StringBuilder();
+ if( isSet(PropertyType.RESPONDER) ) {
+ out.append(PropertyType.RESPONDER.name()); count++;
+ }
+ if( isSet(PropertyType.AUTH) ) {
+ if( 0 < count ) { out.append(", "); }
+ out.append(PropertyType.AUTH.name()); count++;
+ }
+ return "["+out.toString()+"]";
+ }
+ }
+
+ /** {@link Properties} bit mask. 1 octet or 8 bits. */
+ public Properties properties;
+
+ /** Connection Signature Resolving Key (CSRK) */
+ public byte csrk[/*16*/];
+
+ /**
+ * Size of the byte stream representation in bytes
+ * @see #getStream(byte[], int)
+ */
+ public static final int byte_size = 1+16;
+
+ /** Construct instance via given source byte array */
+ public SMPSignatureResolvingKeyInfo(final byte source[], final int pos) {
+ if( byte_size > ( source.length - pos ) ) {
+ throw new IllegalArgumentException("Stream ( "+source.length+" - "+pos+" ) < "+byte_size+" bytes");
+ }
+ csrk = new byte[16];
+ putStream(source, pos);
+ }
+
+ /** Construct emoty unset instance. */
+ public SMPSignatureResolvingKeyInfo() {
+ properties = new Properties((byte)0);
+ csrk = new byte[16];
+ }
+
+ /**
+ * Method transfers all bytes representing a SMPLongTermKeyInfo from the given
+ * source array at the given position into this instance.
+ * <p>
+ * Implementation is consistent with {@link #getStream(byte[], int)}.
+ * </p>
+ * @param source the source array
+ * @param pos starting position in the source array
+ * @see #getStream(byte[], int)
+ */
+ public void putStream(final byte[] source, int pos) {
+ if( byte_size > ( source.length - pos ) ) {
+ throw new IllegalArgumentException("Stream ( "+source.length+" - "+pos+" ) < "+byte_size+" bytes");
+ }
+ properties = new Properties(source[pos++]);
+ System.arraycopy(source, pos, csrk, 0, 16); pos+=16;
+ }
+
+ /**
+ * Method transfers all bytes representing this instance into the given
+ * destination array at the given position.
+ * <p>
+ * Implementation is consistent with {@link #SMPLongTermKeyInfo(byte[], int)}.
+ * </p>
+ * @param sink the destination array
+ * @param pos starting position in the destination array
+ * @see #SMPLongTermKeyInfo(byte[], int)
+ * @see #putStream(byte[], int)
+ */
+ public final void getStream(final byte[] sink, int pos) {
+ if( byte_size > ( sink.length - pos ) ) {
+ throw new IllegalArgumentException("Stream ( "+sink.length+" - "+pos+" ) < "+byte_size+" bytes");
+ }
+ sink[pos++] = properties.mask;
+ System.arraycopy(csrk, 0, sink, pos, 16); pos+=16;
+ }
+
+ @Override
+ public String toString() { // hex-fmt aligned with btmon
+ return "LTK[props "+properties.toString()+
+ ", csrk "+BluetoothUtils.bytesHexString(csrk, 0, -1, true /* lsbFirst */, false /* leading0X */, true /* lowerCase */)+
+ "]";
+ }
+
+};
diff --git a/java/tinyb/dbus/DBusDevice.java b/java/tinyb/dbus/DBusDevice.java
index a381701b..b066e0e8 100644
--- a/java/tinyb/dbus/DBusDevice.java
+++ b/java/tinyb/dbus/DBusDevice.java
@@ -47,8 +47,10 @@ import org.tinyb.GATTCharacteristicListener;
import org.tinyb.HCIStatusCode;
import org.tinyb.PairingMode;
import org.tinyb.SMPIOCapability;
+import org.tinyb.SMPKeyMask;
import org.tinyb.SMPLongTermKeyInfo;
import org.tinyb.SMPPairingState;
+import org.tinyb.SMPSignatureResolvingKeyInfo;
public class DBusDevice extends DBusObject implements BluetoothDevice
{
@@ -109,12 +111,18 @@ public class DBusDevice extends DBusObject implements BluetoothDevice
public native boolean disconnectProfile(String arg_UUID) throws BluetoothException;
@Override
+ public final SMPKeyMask getAvailableSMPKeys(final boolean responder) { return new SMPKeyMask(); }
+
+ @Override
public final SMPLongTermKeyInfo getLongTermKeyInfo(final boolean responder) { return new SMPLongTermKeyInfo(); } // FIXME
@Override
public final HCIStatusCode setLongTermKeyInfo(final SMPLongTermKeyInfo ltk) { return HCIStatusCode.NOT_SUPPORTED; } // FIXME
@Override
+ public final SMPSignatureResolvingKeyInfo getSignatureResolvingKeyInfo(final boolean responder) { return new SMPSignatureResolvingKeyInfo(); } // FIXME
+
+ @Override
public native boolean pair() throws BluetoothException;
@Override
diff --git a/src/direct_bt/DBTDevice.cpp b/src/direct_bt/DBTDevice.cpp
index 1d68ae3a..f8e889a2 100644
--- a/src/direct_bt/DBTDevice.cpp
+++ b/src/direct_bt/DBTDevice.cpp
@@ -522,8 +522,8 @@ void DBTDevice::processDeviceReady(std::shared_ptr<DBTDevice> sthis, const uint6
}
-static const SMPKeyDist _key_mask_legacy = SMPKeyDist::ENC_KEY | SMPKeyDist::ID_KEY | SMPKeyDist::SIGN_KEY;
-static const SMPKeyDist _key_mask_sc = SMPKeyDist::ID_KEY | SMPKeyDist::SIGN_KEY | SMPKeyDist::LINK_KEY;
+static const SMPKeyType _key_mask_legacy = SMPKeyType::ENC_KEY | SMPKeyType::ID_KEY | SMPKeyType::SIGN_KEY;
+static const SMPKeyType _key_mask_sc = SMPKeyType::ID_KEY | SMPKeyType::SIGN_KEY | SMPKeyType::LINK_KEY;
bool DBTDevice::checkPairingKeyDistributionComplete(const std::string& timestamp) const noexcept {
bool res = false;
@@ -550,10 +550,10 @@ bool DBTDevice::checkPairingKeyDistributionComplete(const std::string& timestamp
address.toString().c_str(), getBDAddressTypeString(addressType).c_str());
jau::PLAIN_PRINT(false, "[%s] - keys[init %s / %s, resp %s / %s]",
timestamp.c_str(),
- getSMPKeyDistMaskString(pairing_data.keys_init_has).c_str(),
- getSMPKeyDistMaskString(pairing_data.keys_init_exp).c_str(),
- getSMPKeyDistMaskString(pairing_data.keys_resp_has).c_str(),
- getSMPKeyDistMaskString(pairing_data.keys_resp_exp).c_str());
+ getSMPKeyTypeMaskString(pairing_data.keys_init_has).c_str(),
+ getSMPKeyTypeMaskString(pairing_data.keys_init_exp).c_str(),
+ getSMPKeyTypeMaskString(pairing_data.keys_resp_has).c_str(),
+ getSMPKeyTypeMaskString(pairing_data.keys_resp_exp).c_str());
}
}
@@ -619,27 +619,27 @@ bool DBTDevice::updatePairingState(std::shared_ptr<DBTDevice> sthis, std::shared
const bool responder = ( SMPLongTermKeyInfo::Property::RESPONDER & smp_ltk.properties ) != SMPLongTermKeyInfo::Property::NONE;
if( responder ) {
- if( ( SMPKeyDist::ENC_KEY & pairing_data.keys_resp_has ) == SMPKeyDist::NONE ) { // no overwrite
+ if( ( SMPKeyType::ENC_KEY & pairing_data.keys_resp_has ) == SMPKeyType::NONE ) { // no overwrite
if( jau::environment::get().debug ) {
jau::PLAIN_PRINT(false, "[%s] DBTDevice::updatePairingState.0: ENC_KEY responder set", timestamp.c_str());
jau::PLAIN_PRINT(false, "[%s] - old %s", timestamp.c_str(), pairing_data.ltk_resp.toString().c_str());
jau::PLAIN_PRINT(false, "[%s] - new %s", timestamp.c_str(), smp_ltk.toString().c_str());
}
pairing_data.ltk_resp = smp_ltk;
- pairing_data.keys_resp_has |= SMPKeyDist::ENC_KEY;
+ pairing_data.keys_resp_has |= SMPKeyType::ENC_KEY;
if( checkPairingKeyDistributionComplete(timestamp) ) {
is_device_ready = true;
}
}
} else {
- if( ( SMPKeyDist::ENC_KEY & pairing_data.keys_init_has ) == SMPKeyDist::NONE ) { // no overwrite
+ if( ( SMPKeyType::ENC_KEY & pairing_data.keys_init_has ) == SMPKeyType::NONE ) { // no overwrite
if( jau::environment::get().debug ) {
jau::PLAIN_PRINT(false, "[%s] DBTDevice::updatePairingState.0: ENC_KEY initiator set", timestamp.c_str());
jau::PLAIN_PRINT(false, "[%s] - old %s", timestamp.c_str(), pairing_data.ltk_init.toString().c_str());
jau::PLAIN_PRINT(false, "[%s] - new %s", timestamp.c_str(), smp_ltk.toString().c_str());
}
pairing_data.ltk_init = smp_ltk;
- pairing_data.keys_init_has |= SMPKeyDist::ENC_KEY;
+ pairing_data.keys_init_has |= SMPKeyType::ENC_KEY;
if( checkPairingKeyDistributionComplete(timestamp) ) {
is_device_ready = true;
}
@@ -767,8 +767,8 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_
jau::PLAIN_PRINT(false, "[%s] - encsz: init %d", timestamp.c_str(), (int)pairing_data.maxEncsz_init);
jau::PLAIN_PRINT(false, "[%s] - encsz: resp %d", timestamp.c_str(), (int)pairing_data.maxEncsz_resp);
jau::PLAIN_PRINT(false, "[%s] ", timestamp.c_str());
- jau::PLAIN_PRINT(false, "[%s] - keys: init %s", timestamp.c_str(), getSMPKeyDistMaskString(pairing_data.keys_init_exp).c_str());
- jau::PLAIN_PRINT(false, "[%s] - keys: resp %s", timestamp.c_str(), getSMPKeyDistMaskString(pairing_data.keys_resp_exp).c_str());
+ jau::PLAIN_PRINT(false, "[%s] - keys: init %s", timestamp.c_str(), getSMPKeyTypeMaskString(pairing_data.keys_init_exp).c_str());
+ jau::PLAIN_PRINT(false, "[%s] - keys: resp %s", timestamp.c_str(), getSMPKeyTypeMaskString(pairing_data.keys_resp_exp).c_str());
}
}
} break;
@@ -838,12 +838,12 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_
const SMPMasterIdentMsg & msg1 = *static_cast<const SMPMasterIdentMsg *>( msg.get() );
if( HCIACLData::l2cap_frame::PBFlag::START_AUTOFLUSH == source.pb_flag ) {
// from responder (LL slave)
- pairing_data.keys_resp_has |= SMPKeyDist::ENC_KEY;
+ pairing_data.keys_resp_has |= SMPKeyType::ENC_KEY;
pairing_data.ltk_resp.ediv = msg1.getEDIV();
pairing_data.ltk_resp.rand = msg1.getRand();
} else {
// from initiator (LL master)
- pairing_data.keys_init_has |= SMPKeyDist::ENC_KEY;
+ pairing_data.keys_init_has |= SMPKeyType::ENC_KEY;
pairing_data.ltk_init.ediv = msg1.getEDIV();
pairing_data.ltk_init.rand = msg1.getRand();
}
@@ -866,12 +866,12 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_
const SMPIdentAddrInfoMsg & msg1 = *static_cast<const SMPIdentAddrInfoMsg *>( msg.get() );
if( HCIACLData::l2cap_frame::PBFlag::START_AUTOFLUSH == source.pb_flag ) {
// from responder (LL slave)
- pairing_data.keys_resp_has |= SMPKeyDist::ID_KEY;
+ pairing_data.keys_resp_has |= SMPKeyType::ID_KEY;
pairing_data.address = msg1.getAddress();
pairing_data.is_static_random_address = msg1.isStaticRandomAddress();
} else {
// from initiator (LL master)
- pairing_data.keys_init_has |= SMPKeyDist::ID_KEY;
+ pairing_data.keys_init_has |= SMPKeyType::ID_KEY;
pairing_data.address = msg1.getAddress();
pairing_data.is_static_random_address = msg1.isStaticRandomAddress();
}
@@ -882,12 +882,22 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_
const SMPSignInfoMsg & msg1 = *static_cast<const SMPSignInfoMsg *>( msg.get() );
if( HCIACLData::l2cap_frame::PBFlag::START_AUTOFLUSH == source.pb_flag ) {
// from responder (LL slave)
- pairing_data.keys_resp_has |= SMPKeyDist::SIGN_KEY;
- pairing_data.csrk_resp = msg1.getCSRK();
+ pairing_data.keys_resp_has |= SMPKeyType::SIGN_KEY;
+
+ pairing_data.csrk_resp.properties |= SMPSignatureResolvingKeyInfo::Property::RESPONDER;
+ if( BTSecurityLevel::ENC_AUTH <= pairing_data.sec_level_conn ) {
+ pairing_data.csrk_resp.properties |= SMPSignatureResolvingKeyInfo::Property::AUTH;
+ }
+ pairing_data.csrk_resp.csrk = msg1.getCSRK();
} else {
// from initiator (LL master)
- pairing_data.keys_init_has |= SMPKeyDist::SIGN_KEY;
- pairing_data.csrk_init = msg1.getCSRK();
+ pairing_data.keys_init_has |= SMPKeyType::SIGN_KEY;
+
+ // pairing_data.csrk_init.properties |= SMPSignatureResolvingKeyInfo::Property::INITIATOR;
+ if( BTSecurityLevel::ENC_AUTH <= pairing_data.sec_level_conn ) {
+ pairing_data.csrk_init.properties |= SMPSignatureResolvingKeyInfo::Property::AUTH;
+ }
+ pairing_data.csrk_init.csrk = msg1.getCSRK();
}
} break;
@@ -917,10 +927,10 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_
is_device_ready);
jau::PLAIN_PRINT(false, "[%s] - keys[init %s / %s, resp %s / %s]",
timestamp.c_str(),
- getSMPKeyDistMaskString(pairing_data.keys_init_has).c_str(),
- getSMPKeyDistMaskString(pairing_data.keys_init_exp).c_str(),
- getSMPKeyDistMaskString(pairing_data.keys_resp_has).c_str(),
- getSMPKeyDistMaskString(pairing_data.keys_resp_exp).c_str());
+ getSMPKeyTypeMaskString(pairing_data.keys_init_has).c_str(),
+ getSMPKeyTypeMaskString(pairing_data.keys_init_exp).c_str(),
+ getSMPKeyTypeMaskString(pairing_data.keys_resp_has).c_str(),
+ getSMPKeyTypeMaskString(pairing_data.keys_resp_exp).c_str());
}
if( old_pstate == pstate /* && old_pmode == pmode */ ) {
@@ -942,6 +952,15 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_
}
}
+SMPKeyType DBTDevice::getAvailableSMPKeys(const bool responder) const noexcept {
+ jau::sc_atomic_critical sync(const_cast<DBTDevice*>(this)->sync_pairing);
+ if( responder ) {
+ return pairing_data.keys_resp_has;
+ } else {
+ return pairing_data.keys_init_has;
+ }
+}
+
SMPLongTermKeyInfo DBTDevice::getLongTermKeyInfo(const bool responder) const noexcept {
jau::sc_atomic_critical sync(const_cast<DBTDevice*>(this)->sync_pairing);
return responder ? pairing_data.ltk_resp : pairing_data.ltk_init;
@@ -965,6 +984,11 @@ HCIStatusCode DBTDevice::setLongTermKeyInfo(const SMPLongTermKeyInfo& ltk) noexc
return res;
}
+SMPSignatureResolvingKeyInfo DBTDevice::getSignatureResolvingKeyInfo(const bool responder) const noexcept {
+ jau::sc_atomic_critical sync(const_cast<DBTDevice*>(this)->sync_pairing);
+ return responder ? pairing_data.csrk_resp : pairing_data.csrk_init;
+}
+
HCIStatusCode DBTDevice::pair(const SMPIOCapability io_cap) noexcept {
/**
* Experimental only.
@@ -1172,8 +1196,8 @@ void DBTDevice::clearSMPStates(const bool connected) noexcept {
pairing_data.ioCap_resp = SMPIOCapability::NO_INPUT_NO_OUTPUT;
pairing_data.oobFlag_resp = SMPOOBDataFlag::OOB_AUTH_DATA_NOT_PRESENT;
pairing_data.maxEncsz_resp = 0;
- pairing_data.keys_resp_exp = SMPKeyDist::NONE;
- pairing_data.keys_resp_has = SMPKeyDist::NONE;
+ pairing_data.keys_resp_exp = SMPKeyType::NONE;
+ pairing_data.keys_resp_has = SMPKeyType::NONE;
pairing_data.ltk_resp.clear();
pairing_data.irk_resp.clear();
// pairing_data.address;
@@ -1184,8 +1208,8 @@ void DBTDevice::clearSMPStates(const bool connected) noexcept {
pairing_data.ioCap_init = SMPIOCapability::NO_INPUT_NO_OUTPUT;
pairing_data.oobFlag_init = SMPOOBDataFlag::OOB_AUTH_DATA_NOT_PRESENT;
pairing_data.maxEncsz_init = 0;
- pairing_data.keys_init_exp = SMPKeyDist::NONE;
- pairing_data.keys_init_has = SMPKeyDist::NONE;
+ pairing_data.keys_init_exp = SMPKeyType::NONE;
+ pairing_data.keys_init_has = SMPKeyType::NONE;
pairing_data.ltk_init.clear();
pairing_data.irk_init.clear();
pairing_data.csrk_init.clear();
diff --git a/src/direct_bt/SMPTypes.cpp b/src/direct_bt/SMPTypes.cpp
index e3294020..88f6e0d8 100644
--- a/src/direct_bt/SMPTypes.cpp
+++ b/src/direct_bt/SMPTypes.cpp
@@ -268,9 +268,9 @@ PairingMode direct_bt::getPairingMode(const bool use_sc,
X(RFU_3) \
X(RFU_4)
-#define CASE_TO_STRING_KEYDISTFMT(V) case SMPKeyDist::V: return #V;
+#define CASE_TO_STRING_KEYDISTFMT(V) case SMPKeyType::V: return #V;
-std::string direct_bt::getSMPKeyDistBitString(const SMPKeyDist bit) noexcept {
+std::string direct_bt::getSMPKeyTypeBitString(const SMPKeyType bit) noexcept {
switch(bit) {
KEYDISTFMT_ENUM(CASE_TO_STRING_KEYDISTFMT)
default: ; // fall through intended
@@ -278,7 +278,7 @@ std::string direct_bt::getSMPKeyDistBitString(const SMPKeyDist bit) noexcept {
return "Unknown SMPKeyDistFormat bit";
}
-std::string direct_bt::getSMPKeyDistMaskString(const SMPKeyDist mask) noexcept {
+std::string direct_bt::getSMPKeyTypeMaskString(const SMPKeyType mask) noexcept {
const uint8_t one = 1;
bool has_pre = false;
std::string out("[");
@@ -286,7 +286,7 @@ std::string direct_bt::getSMPKeyDistMaskString(const SMPKeyDist mask) noexcept {
const uint8_t settingBit = one << i;
if( 0 != ( static_cast<uint8_t>(mask) & settingBit ) ) {
if( has_pre ) { out.append(", "); }
- out.append( getSMPKeyDistBitString( static_cast<SMPKeyDist>(settingBit) ) );
+ out.append( getSMPKeyTypeBitString( static_cast<SMPKeyType>(settingBit) ) );
has_pre = true;
}
}
@@ -331,6 +331,36 @@ std::string SMPLongTermKeyInfo::getPropertyMaskString(const Property mask) noexc
return out;
}
+#define CSRKPROP_ENUM(X) \
+ X(NONE) \
+ X(RESPONDER) \
+ X(AUTH)
+
+#define CASE_TO_STRING_CSRKPROPFMT(V) case SMPSignatureResolvingKeyInfo::Property::V: return #V;
+
+std::string SMPSignatureResolvingKeyInfo::getPropertyBitString(const Property bit) noexcept {
+ switch(bit) {
+ CSRKPROP_ENUM(CASE_TO_STRING_CSRKPROPFMT)
+ default: ; // fall through intended
+ }
+ return "Unknown SMPSignatureResolvingKeyInfo::Property bit";
+}
+
+std::string SMPSignatureResolvingKeyInfo::getPropertyMaskString(const Property mask) noexcept {
+ bool has_pre = false;
+ std::string out("[");
+ if( Property::NONE != ( mask & Property::RESPONDER ) ) {
+ out.append( getPropertyBitString( Property::RESPONDER ) );
+ has_pre = true;
+ }
+ if( Property::NONE != ( mask & Property::AUTH ) ) {
+ if( has_pre ) { out.append(", "); }
+ out.append( getPropertyBitString( Property::AUTH ) );
+ has_pre = true;
+ }
+ out.append("]");
+ return out;
+}
#define OPCODE_ENUM(X) \
X(UNDEFINED) \