aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-09-22 10:27:06 +0200
committerSven Gothel <[email protected]>2020-09-22 10:27:06 +0200
commit8eb3ecb3033b28c5b6cc13807d0948f245ce9729 (patch)
treecf1443928166d0a2d36a8590deeac72f89c4b942
parentefd9938140595944dbdf7fa05e653e7cd61a7e7c (diff)
LE Secure Connections: Initial API to support secure pairing with varying PairingModes (C++, Java)
For now, DBTDevice has a NOP implementation, i.e. returning zero length vectors (or arrays in Java) for supported and required PairingMode. The pair(String passkey) simply returns HCIStatusCode::INTERNAL_FAILURE; Intention is to validate the new API entry with our application.
-rw-r--r--api/direct_bt/BTTypes.hpp33
-rw-r--r--api/direct_bt/DBTDevice.hpp34
-rw-r--r--examples/direct_bt_scanner10/dbt_scanner10.cpp33
-rw-r--r--examples/java/ScannerTinyB10.java27
-rw-r--r--java/direct_bt/tinyb/DBTDevice.java76
-rw-r--r--java/jni/direct_bt/DBTDevice.cxx62
-rw-r--r--java/org/tinyb/BluetoothDevice.java56
-rw-r--r--java/org/tinyb/PairingMode.java85
-rw-r--r--java/tinyb/dbus/DBusDevice.java16
-rw-r--r--src/direct_bt/BTTypes.cpp27
-rw-r--r--src/direct_bt/DBTDevice.cpp15
11 files changed, 442 insertions, 22 deletions
diff --git a/api/direct_bt/BTTypes.hpp b/api/direct_bt/BTTypes.hpp
index d6d09f5a..5994a80f 100644
--- a/api/direct_bt/BTTypes.hpp
+++ b/api/direct_bt/BTTypes.hpp
@@ -59,11 +59,42 @@ namespace direct_bt {
/**
* Maps the specified name to a constant of BTMode.
* @param name the string name to be mapped to a constant of this enum type.
- * @return the corresponding constant of this enum type, using {@link BRMode#NONE} if not supported.
+ * @return the corresponding constant of this enum type, using {@link BTMode#NONE} if not supported.
*/
BTMode getBTMode(const std::string & value) noexcept;
/**
+ * Bluetooth secure pairing mode
+ * <pre>
+ * BT Core Spec v5.2: Vol 1, Part A, 5 Security Overview
+ * BT Core Spec v5.2: Vol 1, Part A, 5.4 LE SECURITY
+ * </pre>
+ */
+ enum class PairingMode : uint8_t {
+ /** No pairing mode, implying no secure connections, no encryption and no MITM protection. */
+ NONE = 0,
+ /** Just Works. Random key exchange with encryption but no MITM protection. */
+ JUST_WORKS = 1,
+ /** Passkey Entry. A known digit sequence (PIN) must be given as a secret to be validated on the device. Random key exchange with additional secret (PIN) and encryption and MITM protection. */
+ PASSKEY_ENTRY = 2,
+ /** Visual numeric comparison of digit sequence (PIN) shown on both devices, peripheral and host, to be answered. Random key exchange with additional secret (PIN) and encryption and MITM protection. */
+ NUMERIC_COMPARISON = 3,
+ /** Utilizing a second factor secret to be used as a secret, e.g. NFC field. Random key exchange with additional secret (2FA) and encryption and potential MITM protection. */
+ OUT_OF_BAND = 4
+ };
+ inline uint8_t number(const PairingMode rhs) noexcept {
+ return static_cast<uint8_t>(rhs);
+ }
+ std::string getPairingModeString(const PairingMode v) noexcept;
+
+ /**
+ * Maps the specified name to a constant of PairingMode.
+ * @param name the string name to be mapped to a constant of this enum type.
+ * @return the corresponding constant of this enum type, using {@link PairingMode#NONE} if not supported.
+ */
+ PairingMode getPairingMode(const std::string & value) noexcept;
+
+ /**
* Meta ScanType as derived from BTMode,
* with defined value mask consisting of BDAddressType bits.
* <p>
diff --git a/api/direct_bt/DBTDevice.hpp b/api/direct_bt/DBTDevice.hpp
index 8aa374ac..3113ba63 100644
--- a/api/direct_bt/DBTDevice.hpp
+++ b/api/direct_bt/DBTDevice.hpp
@@ -336,6 +336,40 @@ namespace direct_bt {
}
/**
+ * The device is securely paired with PasskeyEntry or JustWorks.
+ * <p>
+ * The device must be connected before pairing, see connectDefault().
+ * </p>
+ * <p>
+ * If passkey is an empty string, JustWorks method is being used, otherwise PasskeyEntry.
+ * </p>
+ * @param passkey optional secret used for PasskeyEntry method.
+ * Will be encrypted before sending to counterparty.
+ * Can be an empty string, in which case JustWork method is used.
+ *
+ * @return HCIStatusCode::SUCCESS if the command has been accepted, otherwise HCIStatusCode may disclose reason for rejection.
+ */
+ HCIStatusCode pair(const std::string & passkey);
+
+ /**
+ * Returns a vector of supported PairingMode by the device.
+ * <p>
+ * The device must be connected before querying this status, see connectDefault(). FIXME?
+ * </p>
+ * @return vector of supported PairingMode, empty if pairing is not supported.
+ */
+ std::vector<PairingMode> getSupportedPairingModes();
+
+ /**
+ * Returns a vector of required PairingMode by the device.
+ * <p>
+ * The device must be connected before querying this status, see connectDefault(). FIXME?
+ * </p>
+ * @return vector of required PairingMode, empty if pairing is not required.
+ */
+ std::vector<PairingMode> getRequiredPairingModes();
+
+ /**
* Disconnects this device via disconnect(..) and
* explicitly removes its shared references from the Adapter:
* connected-devices, discovered-devices and shared-devices.
diff --git a/examples/direct_bt_scanner10/dbt_scanner10.cpp b/examples/direct_bt_scanner10/dbt_scanner10.cpp
index 0c08dc25..238c2fd9 100644
--- a/examples/direct_bt_scanner10/dbt_scanner10.cpp
+++ b/examples/direct_bt_scanner10/dbt_scanner10.cpp
@@ -275,6 +275,39 @@ static void processConnectedDevice(std::shared_ptr<DBTDevice> device) {
const uint64_t t1 = getCurrentMilliseconds();
bool success = false;
+ // Secure Pairing
+ {
+ std::vector<PairingMode> spm = device->getSupportedPairingModes();
+ fprintf(stderr, "Supported Secure Pairing Modes: ");
+ std::for_each(spm.begin(), spm.end(), [](PairingMode pm) { fprintf(stderr, "%s, ", getPairingModeString(pm).c_str()); } );
+ fprintf(stderr, "\n");
+
+ std::vector<PairingMode> rpm = device->getRequiredPairingModes();
+ fprintf(stderr, "Required Secure Pairing Modes: ");
+ std::for_each(rpm.begin(), rpm.end(), [](PairingMode pm) { fprintf(stderr, "%s, ", getPairingModeString(pm).c_str()); } );
+ fprintf(stderr, "\n");
+
+ if( spm.end() != std::find (spm.begin(), spm.end(), PairingMode::JUST_WORKS) ) {
+ const std::vector<int> passkey; // empty for JustWorks
+ HCIStatusCode res = device->pair(""); // empty for JustWorks
+ fprintf(stderr, "Secure Pairing Just Works result %s of %s\n", getHCIStatusCodeString(res).c_str(), device->toString().c_str());
+ } else if( spm.end() != std::find (spm.begin(), spm.end(), PairingMode::PASSKEY_ENTRY) ) {
+ HCIStatusCode res = device->pair("111111"); // PasskeyEntry
+ fprintf(stderr, "Secure Pairing Passkey Entry result %s of %s\n", getHCIStatusCodeString(res).c_str(), device->toString().c_str());
+ } else {
+ fprintf(stderr, "Secure Pairing JUST_WORKS or PASSKEY_ENTRY not supported %s\n", device->toString().c_str());
+ }
+ {
+ const std::vector<int> passkey; // empty for JustWorks
+ HCIStatusCode res = device->pair(""); // empty for JustWorks
+ fprintf(stderr, "T1 Secure Pairing Just Works result %s of %s\n", getHCIStatusCodeString(res).c_str(), device->toString().c_str());
+ }
+ {
+ HCIStatusCode res = device->pair("111111"); // PasskeyEntry
+ fprintf(stderr, "T2 Secure Pairing Passkey Entry result %s of %s\n", getHCIStatusCodeString(res).c_str(), device->toString().c_str());
+ }
+ }
+
//
// GATT Service Processing
//
diff --git a/examples/java/ScannerTinyB10.java b/examples/java/ScannerTinyB10.java
index 4ef7c055..1c38a45f 100644
--- a/examples/java/ScannerTinyB10.java
+++ b/examples/java/ScannerTinyB10.java
@@ -50,6 +50,7 @@ import org.tinyb.EIRDataTypeSet;
import org.tinyb.GATTCharacteristicListener;
import org.tinyb.HCIStatusCode;
import org.tinyb.HCIWhitelistConnectType;
+import org.tinyb.PairingMode;
import direct_bt.tinyb.DBTManager;
@@ -262,6 +263,32 @@ public class ScannerTinyB10 {
final long t1 = BluetoothUtils.getCurrentMilliseconds();
boolean success = false;
+ // Secure Pairing
+ {
+ final List<PairingMode> spm = Arrays.asList(device.getSupportedPairingModes());
+ println("Supported Secure Pairing Modes: " + spm.toString());
+ final List<PairingMode> rpm = Arrays.asList(device.getRequiredPairingModes());
+ println("Required Secure Pairing Modes: " + spm.toString());
+
+ if( spm.contains(PairingMode.JUST_WORKS) ) {
+ final HCIStatusCode res = device.pair(null); // empty for JustWorks
+ println("Secure Pairing Just Works result " + res + " of " + device);
+ } else if( spm.contains(PairingMode.PASSKEY_ENTRY) ) {
+ final HCIStatusCode res = device.pair("111111"); // PasskeyEntry
+ println("Secure Pairing Passkey Entry result " + res + " of " + device);
+ } else {
+ println("Secure Pairing JUST_WORKS or PASSKEY_ENTRY not supported, but " + spm.toString() + " on " + device);
+ }
+ {
+ final HCIStatusCode res = device.pair(null); // empty for JustWorks
+ println("T1 Processing Device: Secure Pairing Just Works result " + res + " of " + device);
+ }
+ {
+ final HCIStatusCode res = device.pair("111111"); // PasskeyEntry
+ println("T2 Processing Device: Secure Pairing Passkey Entry result " + res + " of " + device);
+ }
+ }
+
//
// GATT Service Processing
//
diff --git a/java/direct_bt/tinyb/DBTDevice.java b/java/direct_bt/tinyb/DBTDevice.java
index ae361ffc..793d542e 100644
--- a/java/direct_bt/tinyb/DBTDevice.java
+++ b/java/direct_bt/tinyb/DBTDevice.java
@@ -46,6 +46,7 @@ import org.tinyb.BluetoothType;
import org.tinyb.EIRDataTypeSet;
import org.tinyb.GATTCharacteristicListener;
import org.tinyb.HCIStatusCode;
+import org.tinyb.PairingMode;
public class DBTDevice extends DBTObject implements BluetoothDevice
{
@@ -131,6 +132,8 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
}
@Override
public void deviceDisconnected(final BluetoothDevice device, final HCIStatusCode reason, final short handle, final long timestamp) {
+ devicePaired(false);
+
if( isConnected.compareAndSet(true, false) ) {
clearServiceCache();
synchronized(userCallbackLock) {
@@ -164,20 +167,22 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
}
};
+ final private void devicePaired(final boolean _isPaired) {
+ if( DEBUG ) {
+ System.err.println("Device.PairedNotification: "+isPaired+" -> "+_isPaired+" on "+DBTDevice.this.toString());
+ }
+ if( isPaired.compareAndSet(!_isPaired, _isPaired) ) {
+ synchronized(userCallbackLock) {
+ if( null != userPairedNotificationsCB ) {
+ userPairedNotificationsCB.run(_isPaired);
+ }
+ }
+ }
+ }
final private BluetoothNotification<Boolean> pairedNotificationsCB = new BluetoothNotification<Boolean>() {
@Override
public void run(final Boolean value) {
- if( DEBUG ) {
- System.err.println("Device.PairedNotification: "+isPaired+" -> "+value+" on "+DBTDevice.this.toString());
- }
- final boolean _isPaired = value.booleanValue();
- if( isPaired.compareAndSet(!_isPaired, _isPaired) ) {
- synchronized(userCallbackLock) {
- if( null != userPairedNotificationsCB ) {
- userPairedNotificationsCB.run(value);
- }
- }
- }
+ devicePaired( value.booleanValue() );
}
};
@@ -321,10 +326,51 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
public final BluetoothDevice clone() { throw new UnsupportedOperationException(); } // FIXME
@Override
- public boolean pair() throws BluetoothException { throw new UnsupportedOperationException(); } // FIXME
+ public final boolean pair() throws BluetoothException {
+ return HCIStatusCode.SUCCESS == pair(null);
+ }
@Override
- public boolean cancelPairing() throws BluetoothException { throw new UnsupportedOperationException(); } // FIXME
+ public HCIStatusCode pair(final String passkey) throws BluetoothException {
+ if( !getConnected() ) {
+ throw new IllegalStateException("Device must be connected first: "+toString());
+ }
+ final HCIStatusCode res = HCIStatusCode.get( pairImpl(passkey) );
+
+ // Secure Pairing (paired == true) has no explicit notification
+ devicePaired( HCIStatusCode.SUCCESS == res );
+
+ return res;
+ }
+ private native byte pairImpl(final String passkey) throws BluetoothException;
+
+ @Override
+ public final PairingMode[] getSupportedPairingModes() throws BluetoothException {
+ final byte[] res0 = getSupportedPairingModesImpl();
+ final PairingMode[] res1 = new PairingMode[res0.length];
+ for(int i=0; i<res0.length; i++) {
+ res1[i] = PairingMode.get(res0[i]);
+ }
+ return res1;
+ }
+ private native byte[] getSupportedPairingModesImpl() throws BluetoothException;
+
+ @Override
+ public final PairingMode[] getRequiredPairingModes() throws BluetoothException {
+ final byte[] res0 = getRequiredPairingModesImpl();
+ final PairingMode[] res1 = new PairingMode[res0.length];
+ for(int i=0; i<res0.length; i++) {
+ res1[i] = PairingMode.get(res0[i]);
+ }
+ return res1;
+ }
+ private native byte[] getRequiredPairingModesImpl() throws BluetoothException;
+
+ @Override
+ public final boolean cancelPairing() throws BluetoothException {
+ // FIXME: Not supporter (yet)
+ return false;
+ }
@Override
public String getAlias() { return null; } // FIXME
@@ -491,7 +537,7 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
}
@Override
- public boolean getPaired() { return isPaired.get(); }
+ public final boolean getPaired() { return isPaired.get(); }
@Override
public void enableTrustedNotifications(final BluetoothNotification<Boolean> callback) {
@@ -542,7 +588,7 @@ public class DBTDevice extends DBTObject implements BluetoothDevice
private native void disableBlockedNotificationsImpl();
private native void setBlockedImpl(final boolean value);
- // FIXME: Figure out paired:=true, as currently we only attach to unpaired
+ // Note that this is only called natively for unpaired, i.e. paired:=false. Using deviceConnected for paired:=true.
private native void enablePairedNotificationsImpl(BluetoothNotification<Boolean> callback);
private native void disablePairedNotificationsImpl();
diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx
index 67b62645..57e18c17 100644
--- a/java/jni/direct_bt/DBTDevice.cxx
+++ b/java/jni/direct_bt/DBTDevice.cxx
@@ -357,6 +357,66 @@ jbyte Java_direct_1bt_tinyb_DBTDevice_connectImpl__SSSSSS(JNIEnv *env, jobject o
return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE);
}
+jbyte Java_direct_1bt_tinyb_DBTDevice_pairImpl(JNIEnv *env, jobject obj, jstring jpasskey)
+{
+ try {
+ DBTDevice *device = getDBTObject<DBTDevice>(env, obj);
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+
+ const std::string passkey = nullptr != jpasskey ? from_jstring_to_string(env, jpasskey) : std::string();
+ HCIStatusCode res = device->pair(passkey);
+ return (jbyte) number(res);
+
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE);
+}
+
+jbyteArray Java_direct_1bt_tinyb_DBTDevice_getSupportedPairingModesImpl(JNIEnv *env, jobject obj) {
+ try {
+ DBTDevice *device = getDBTObject<DBTDevice>(env, obj);
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+
+ std::vector<PairingMode> res0 = device->getSupportedPairingModes();
+ const size_t value_size = res0.size();
+
+ uint8_t res1[value_size];
+ for(size_t i=0; i < value_size; i++) {
+ res1[i] = number(res0[i]);
+ }
+ jbyteArray jres = env->NewByteArray((jsize)value_size);
+ env->SetByteArrayRegion(jres, 0, (jsize)value_size, (const jbyte *)res1);
+ java_exception_check_and_throw(env, E_FILE_LINE);
+ return jres;
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return JNI_FALSE;
+}
+
+jbyteArray Java_direct_1bt_tinyb_DBTDevice_getRequiredPairingModesImpl(JNIEnv *env, jobject obj) {
+ try {
+ DBTDevice *device = getDBTObject<DBTDevice>(env, obj);
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+
+ std::vector<PairingMode> res0 = device->getRequiredPairingModes();
+ const size_t value_size = res0.size();
+
+ uint8_t res1[value_size];
+ for(size_t i=0; i < value_size; i++) {
+ res1[i] = number(res0[i]);
+ }
+ jbyteArray jres = env->NewByteArray((jsize)value_size);
+ env->SetByteArrayRegion(jres, 0, (jsize)value_size, (const jbyte *)res1);
+ java_exception_check_and_throw(env, E_FILE_LINE);
+ return jres;
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return JNI_FALSE;
+}
+
//
// getter
//
@@ -742,7 +802,7 @@ void Java_direct_1bt_tinyb_DBTDevice_enablePairedNotificationsImpl(JNIEnv *env,
// move BooleanDeviceCBContextRef into CaptureInvocationFunc and operator== includes javaCallback comparison
FunctionDef<bool, std::shared_ptr<MgmtEvent>> funcDef = bindCaptureFunc(BooleanDeviceCBContextRef(ctx), nativeCallback);
setObjectRef(env, obj, funcDef.cloneFunction(), "pairedNotificationRef"); // set java ref
- // FIXME: Figure out paired:=true, as currently we only attach to unpaired
+ // Note that this is only called natively for unpaired, i.e. paired:=false. Using deviceConnected for paired:=true on Java side
mgmt.addMgmtEventCallback(adapter.dev_id, MgmtEvent::Opcode::DEVICE_UNPAIRED, funcDef);
} catch(...) {
rethrow_and_raise_java_exception(env);
diff --git a/java/org/tinyb/BluetoothDevice.java b/java/org/tinyb/BluetoothDevice.java
index c4bc99ec..b0ba1420 100644
--- a/java/org/tinyb/BluetoothDevice.java
+++ b/java/org/tinyb/BluetoothDevice.java
@@ -177,13 +177,61 @@ public interface BluetoothDevice extends BluetoothObject
*/
boolean disconnectProfile(String arg_UUID) throws BluetoothException;
- /** A connection to this device is established, and the device is then
- * paired.
- * @return TRUE if the device connected and paired
- */
+ /**
+ * A secure connection to this device is established, and the device is then paired.
+ * <p>
+ * Use {@link #pair(int[])} for direct_bt
+ * </p>
+ * @return TRUE if the device connected and paired
+ * @implNote secure pairing with JustWorks method on direct_bt.tinyb,
+ * but device must be {@link #connect(short, short, short, short, short, short)} before.
+ * Use {@link #pair(int[])}
+ */
boolean pair() throws BluetoothException;
/**
+ * The device is securely paired with PasskeyEntry or JustWorks.
+ * <p>
+ * The device must be {@link #connect(short, short, short, short, short, short) connected}
+ * before pairing.
+ * </p>
+ * <p>
+ * If passkey is null or an empty string, JustWorks method is being used, otherwise PasskeyEntry.
+ * </p>
+ * @param passkey the optional secret used for secure PasskeyEntry method.
+ * Will be encrypted before sending to counterparty.
+ * Can be null or an empty string, in which case JustWork method is used.
+ * @return {@link HCIStatusCode#SUCCESS} if the command has been accepted, otherwise {@link HCIStatusCode} may disclose reason for rejection.
+ * @since 2.1.0
+ * @implNote not implemented in tinyb.dbus
+ */
+ HCIStatusCode pair(final String passkey) throws BluetoothException;
+
+ /**
+ * Returns a vector of supported PairingMode by the device.
+ * <p>
+ * The device must be {@link #connect(short, short, short, short, short, short) connected}
+ * before querying this status. FIXME?
+ * </p>
+ * @return array of supported PairingMode, empty if pairing is not supported.
+ * @since 2.1.0
+ * @implNote not implemented in tinyb.dbus
+ */
+ PairingMode[] getSupportedPairingModes() throws BluetoothException;
+
+ /**
+ * Returns a vector of required PairingMode by the device.
+ * <p>
+ * The device must be {@link #connect(short, short, short, short, short, short) connected}
+ * before querying this status. FIXME?
+ * </p>
+ * @return array of required PairingMode, empty if pairing is not required.
+ * @since 2.1.0
+ * @implNote not implemented in tinyb.dbus
+ */
+ PairingMode[] getRequiredPairingModes() throws BluetoothException;
+
+ /**
* Remove this device from the system (like an unpair).
* <p>
* Direct-BT: Disconnects this device via disconnect(..) and
diff --git a/java/org/tinyb/PairingMode.java b/java/org/tinyb/PairingMode.java
new file mode 100644
index 00000000..3f06d8e3
--- /dev/null
+++ b/java/org/tinyb/PairingMode.java
@@ -0,0 +1,85 @@
+/**
+ * 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;
+
+/**
+ * Bluetooth secure pairing mode
+ * <pre>
+ * BT Core Spec v5.2: Vol 1, Part A, 5 Security Overview
+ * BT Core Spec v5.2: Vol 1, Part A, 5.4 LE SECURITY
+ * </pre>
+ * <p>
+ * See {@link #get(int)} for its native integer mapping.
+ * </p>
+ * @since 2.1.0
+ */
+public enum PairingMode {
+ /** No pairing mode, implying no secure connections, no encryption and no MITM protection. */
+ NONE ((byte)0),
+ /** Just Works. Random key exchange with encryption but no MITM protection. */
+ JUST_WORKS ((byte)1),
+ /** Passkey Entry. A known digit sequence (PIN) must be given as a secret to be validated on the device. Random key exchange with additional secret (PIN) and encryption and MITM protection. */
+ PASSKEY_ENTRY ((byte)2),
+ /** Visual numeric comparison of digit sequence (PIN) shown on both devices, peripheral and host, to be answered. Random key exchange with additional secret (PIN) and encryption and MITM protection. */
+ NUMERIC_COMPARISON ((byte)3),
+ /** Utilizing a second factor secret to be used as a secret, e.g. NFC field. Random key exchange with additional secret (2FA) and encryption and potential MITM protection. */
+ OUT_OF_BAND ((byte)4);
+
+ public final byte value;
+
+ /**
+ * Maps the specified name to a constant of PairingMode.
+ * <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 PairingMode get(final String name) throws IllegalArgumentException {
+ return valueOf(name);
+ }
+
+ /**
+ * Maps the specified integer value to a constant of {@link PairingMode}.
+ * @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 PairingMode get(final byte value) {
+ switch(value) {
+ case (byte) 0x01: return JUST_WORKS;
+ case (byte) 0x02: return PASSKEY_ENTRY;
+ case (byte) 0x03: return NUMERIC_COMPARISON;
+ case (byte) 0x04: return OUT_OF_BAND;
+ default: return NONE;
+ }
+ }
+
+ PairingMode(final byte v) {
+ value = v;
+ }
+}
diff --git a/java/tinyb/dbus/DBusDevice.java b/java/tinyb/dbus/DBusDevice.java
index bb24d0dd..7413ff18 100644
--- a/java/tinyb/dbus/DBusDevice.java
+++ b/java/tinyb/dbus/DBusDevice.java
@@ -43,6 +43,7 @@ import org.tinyb.BluetoothType;
import org.tinyb.BluetoothUtils;
import org.tinyb.GATTCharacteristicListener;
import org.tinyb.HCIStatusCode;
+import org.tinyb.PairingMode;
public class DBusDevice extends DBusObject implements BluetoothDevice
{
@@ -105,7 +106,20 @@ public class DBusDevice extends DBusObject implements BluetoothDevice
@Override
public native boolean pair() throws BluetoothException;
- @Override
+ @Override
+ public HCIStatusCode pair(final String passkey) throws BluetoothException { return HCIStatusCode.INTERNAL_FAILURE; }
+
+ @Override
+ public final PairingMode[] getSupportedPairingModes() throws BluetoothException {
+ return new PairingMode[0];
+ }
+
+ @Override
+ public final PairingMode[] getRequiredPairingModes() throws BluetoothException {
+ return new PairingMode[0];
+ }
+
+ @Override
public native boolean remove() throws BluetoothException;
@Override
diff --git a/src/direct_bt/BTTypes.cpp b/src/direct_bt/BTTypes.cpp
index 6b39fa6a..5ed893f0 100644
--- a/src/direct_bt/BTTypes.cpp
+++ b/src/direct_bt/BTTypes.cpp
@@ -217,6 +217,33 @@ BTMode direct_bt::getBTMode(const std::string & value) noexcept {
return BTMode::NONE;
}
+std::string direct_bt::getPairingModeString(const PairingMode v) noexcept {
+ switch(v) {
+ case PairingMode::NONE: return "NONE";
+ case PairingMode::JUST_WORKS: return "JUST_WORKS";
+ case PairingMode::PASSKEY_ENTRY: return "PASSKEY_ENTRY";
+ case PairingMode::NUMERIC_COMPARISON: return "NUMERIC_COMPARISON";
+ case PairingMode::OUT_OF_BAND: return "OUT_OF_BAND";
+ }
+ return "Unknown PairingMode";
+}
+
+PairingMode direct_bt::getPairingMode(const std::string & value) noexcept {
+ if( "JUST_WORKS" == value ) {
+ return PairingMode::JUST_WORKS;
+ }
+ if( "PASSKEY_ENTRY" == value ) {
+ return PairingMode::PASSKEY_ENTRY;
+ }
+ if( "NUMERIC_COMPARISON" == value ) {
+ return PairingMode::NUMERIC_COMPARISON;
+ }
+ if( "OUT_OF_BAND" == value ) {
+ return PairingMode::OUT_OF_BAND;
+ }
+ return PairingMode::NONE;
+}
+
ScanType direct_bt::getScanType(BTMode btMode) {
switch ( btMode ) {
case BTMode::DUAL:
diff --git a/src/direct_bt/DBTDevice.cpp b/src/direct_bt/DBTDevice.cpp
index d1df2d33..8ce50ed7 100644
--- a/src/direct_bt/DBTDevice.cpp
+++ b/src/direct_bt/DBTDevice.cpp
@@ -480,6 +480,21 @@ exit:
return res;
}
+std::vector<PairingMode> DBTDevice::getSupportedPairingModes() {
+ std::vector<PairingMode> pairingModes; // FIXME: Implement LE Secure Connections
+ return pairingModes;
+}
+
+std::vector<PairingMode> DBTDevice::getRequiredPairingModes() {
+ std::vector<PairingMode> pairingModes; // FIXME: Implement LE Secure Connections
+ return pairingModes;
+}
+
+HCIStatusCode DBTDevice::pair(const std::string & passkey) {
+ (void) passkey;
+ return HCIStatusCode::INTERNAL_FAILURE; // FIXME: Implement LE Secure Connections
+}
+
void DBTDevice::remove() {
adapter.removeDevice(*this);
}