aboutsummaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
Diffstat (limited to 'api')
-rw-r--r--api/direct_bt/SMPTypes.hpp1360
1 files changed, 1360 insertions, 0 deletions
diff --git a/api/direct_bt/SMPTypes.hpp b/api/direct_bt/SMPTypes.hpp
new file mode 100644
index 00000000..a349c705
--- /dev/null
+++ b/api/direct_bt/SMPTypes.hpp
@@ -0,0 +1,1360 @@
+/*
+ * 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.
+ */
+
+#ifndef SMP_TYPES_HPP_
+#define SMP_TYPES_HPP_
+
+#include <cstring>
+#include <string>
+#include <cstdint>
+
+#include <algorithm>
+#include <mutex>
+
+#include <jau/basic_types.hpp>
+
+#include "OctetTypes.hpp"
+
+/**
+ * - - - - - - - - - - - - - - -
+ *
+ * Module SMPTypes:
+ *
+ * - BT Core Spec v5.2: Vol 3, Part H Security Manager Specification (SM): 2 Security Manager (SM)
+ * - BT Core Spec v5.2: Vol 3, Part H Security Manager Specification (SM): 3 Security Manager Protocol (SMP)
+ *
+ */
+namespace direct_bt {
+
+ class SMPException : public jau::RuntimeException {
+ protected:
+ SMPException(std::string const type, std::string const m, const char* file, int line) noexcept
+ : RuntimeException(type, m, file, line) {}
+
+ public:
+ SMPException(std::string const m, const char* file, int line) noexcept
+ : RuntimeException("HCIException", m, file, line) {}
+ };
+
+ class SMPPacketException : public SMPException {
+ public:
+ SMPPacketException(std::string const m, const char* file, int line) noexcept
+ : SMPException("SMPPacketException", m, file, line) {}
+ };
+ class SMPOpcodeException : public SMPException {
+ public:
+ SMPOpcodeException(std::string const m, const char* file, int line) noexcept
+ : SMPException("SMPOpcodeException", m, file, line) {}
+ };
+
+ class SMPValueException : public SMPException {
+ public:
+ SMPValueException(std::string const m, const char* file, int line) noexcept
+ : SMPException("SMPValueException", m, file, line) {}
+ };
+
+ enum class SMPConstInt : int32_t {
+ };
+ constexpr int32_t number(const SMPConstInt rhs) noexcept {
+ return static_cast<int>(rhs);
+ }
+
+ enum class SMPConstU16 : uint16_t {
+ /** SMP Timeout Vol 3, Part H (SM): 3.4 */
+ SMP_TIMEOUT_MS = 30000
+ };
+ constexpr uint16_t number(const SMPConstU16 rhs) noexcept {
+ return static_cast<uint16_t>(rhs);
+ }
+
+
+ /**
+ * SMP Authentication Requirements Bits, denotes specific bits or whole protocol uint8_t bit-mask.
+ * <pre>
+ * SMP Pairing Request Vol 3, Part H (SM): 3.5.1
+ * SMP Pairing Response Vol 3, Part H (SM): 3.5.2
+ * SMP Security Request Vol 3, Part H (SM): 3.6.7
+ * </pre>
+ * Layout LSB -> MSB
+ * <pre>
+ * uint8_t bonding_flags : 2, mitm : 1, sc : 1, keypress : 1, ct2 : 1, rfu : 2;
+ * </pre>
+ */
+ enum class SMPAuthReqs : uint8_t {
+ NONE = 0,
+ /**
+ * Indicate bonding being requested by the initiating device.
+ */
+ BONDING = 0b00000001,
+ /** Reserved for future use */
+ BONDING_RESERVED = 0b00000010,
+ /**
+ * A device sets the MITM flag to one to request an Authenticated security property
+ * for the STK when using LE legacy pairing
+ * and the LTK when using LE Secure Connections.
+ */
+ MITM = 0b00000100,
+ /**
+ * If LE Secure Connections pairing is supported by
+ * the device, then the SC field shall be set to 1, otherwise it shall be set to 0.
+ * If both devices support LE Secure Connections pairing,
+ * then LE Secure Connections pairing shall be used,
+ * otherwise LE Legacy pairing shall be used.
+ */
+ LE_SECURE_CONNECTIONS = 0b00001000,
+ /**
+ * The keypress field is used only in the Passkey Entry
+ * protocol and shall be ignored in other protocols.
+ * When both sides set that field to one,
+ * Keypress notifications shall be generated and sent using SMP
+ * Pairing Keypress Notification PDUs.
+ */
+ KEYPRESS = 0b00010000,
+ /**
+ * The CT2 field shall be set to 1 upon transmission to indicate
+ * support for the h7 function.
+ * <pre>
+ * See sections:
+ * - 2.4.2.4 Derivation of BR/EDR link key from LE LTK
+ * - 2.4.2.5 Derivation of LE LTK from BR/EDR link key
+ * </pre>
+ */
+ CT2_H7_FUNC_SUPPORT = 0b00100000,
+ /** Reserved for future use */
+ RFU_1 = 0b01000000,
+ /** Reserved for future use */
+ RFU_2 = 0b10000000
+ };
+ constexpr uint8_t number(const SMPAuthReqs rhs) noexcept {
+ return static_cast<uint8_t>(rhs);
+ }
+ constexpr bool isSMPAuthReqBitSet(const SMPAuthReqs mask, const SMPAuthReqs bit) noexcept {
+ return 0 != ( static_cast<uint8_t>(mask) & static_cast<uint8_t>(bit) );
+ }
+ std::string getSMPAuthReqBitString(const SMPAuthReqs bit) noexcept;
+ std::string getSMPAuthReqMaskString(const SMPAuthReqs mask) noexcept;
+
+ /**
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.3 Command Format
+ * <p>
+ * Message format between both devices, negotiating security details.
+ * </p>
+ * <p>
+ * Vol 3 (Host), Part H Security Manager Specification (SM): 1.2.1 Bit and byte ordering conventions<br>
+ * Little-Endian: Multiple-octet fields shall be transmitted with the least significant octet first.
+ * </p>
+ */
+ class SMPMsg
+ {
+ public:
+ /** SMP Command Codes Vol 3, Part H (SM): 3.3 */
+ enum class Opcode : uint8_t {
+ UNDEFINED = 0x00, // our own pseudo opcode, indicating no ATT PDU message
+
+ PAIRING_REQUEST = 0x01,
+ PAIRING_RESPONSE = 0x02,
+ PAIRING_CONFIRM = 0x03,
+ PAIRING_RANDOM = 0x04,
+ PAIRING_FAILED = 0x05,
+
+ ENCRYPTION_INFORMATION = 0x06,
+ MASTER_IDENTIFICATION = 0x07,
+ IDENTITY_INFORMATION = 0x08,
+ IDENTITY_ADDRESS_INFORMATION = 0x09,
+ SIGNING_INFORMATION = 0x0A,
+ SECURITY_REQUEST = 0x0B,
+
+ PAIRING_PUBLIC_KEY = 0x0C,
+ PAIRING_DHKEY_CHECK = 0x0D,
+ PAIRING_KEYPRESS_NOTIFICATION = 0x0E
+ };
+ static constexpr uint8_t number(const Opcode rhs) noexcept {
+ return static_cast<uint8_t>(rhs);
+ }
+ static std::string getOpcodeString(const Opcode opc) noexcept;
+
+ protected:
+ void checkOpcode(const Opcode expected) const
+ {
+ const Opcode has = getOpcode();
+ if( expected != has ) {
+ throw SMPOpcodeException("Has opcode "+jau::uint8HexString(number(has), true)+" "+getOpcodeString(has)+
+ ", but expected "+jau::uint8HexString(number(expected), true)+" "+getOpcodeString(expected), E_FILE_LINE);
+ }
+ }
+ void checkOpcode(const Opcode exp1, const Opcode exp2) const
+ {
+ const Opcode has = getOpcode();
+ if( exp1 != has && exp2 != has ) {
+ throw SMPOpcodeException("Has opcode "+jau::uint8HexString(number(has), true)+" "+getOpcodeString(has)+
+ ", but expected either "+jau::uint8HexString(number(exp1), true)+" "+getOpcodeString(exp1)+
+ " or "+jau::uint8HexString(number(exp1), true)+" "+getOpcodeString(exp1), E_FILE_LINE);
+ }
+ }
+
+ virtual std::string baseString() const noexcept {
+ return "opcode="+jau::uint8HexString(number(getOpcode()), true)+" "+getOpcodeString()+
+ ", size[total="+std::to_string(pdu.getSize())+", param "+std::to_string(getPDUParamSize())+"]";
+ }
+ virtual std::string valueString() const noexcept {
+ return "size "+std::to_string(getDataSize())+", data "
+ +jau::bytesHexString(pdu.get_ptr(), getDataOffset(), getDataSize(), true /* lsbFirst */, true /* leading0X */);
+ }
+
+ public:
+ /** actual received PDU */
+ POctets pdu;
+
+ /** creation timestamp in milliseconds */
+ const uint64_t ts_creation;
+
+ /**
+ * Return a newly created specialized instance pointer to base class.
+ * <p>
+ * Returned memory reference is managed by caller (delete etc)
+ * </p>
+ */
+ static std::shared_ptr<const SMPMsg> getSpecialized(const uint8_t * buffer, jau::nsize_t const buffer_size) noexcept;
+
+ /** Persistent memory, w/ ownership ..*/
+ SMPMsg(const uint8_t* source, const jau::nsize_t size)
+ : pdu(source, std::max<jau::nsize_t>(1, size)), ts_creation(jau::getCurrentMilliseconds())
+ {
+ pdu.check_range(0, getDataOffset()+getDataSize());
+ }
+
+ /** Persistent memory, w/ ownership ..*/
+ SMPMsg(const Opcode opc, const jau::nsize_t size)
+ : pdu(std::max<jau::nsize_t>(1, size)), ts_creation(jau::getCurrentMilliseconds())
+ {
+ pdu.put_uint8_nc(0, number(opc));
+ pdu.check_range(0, getDataOffset()+getDataSize());
+ }
+
+ SMPMsg(const SMPMsg &o) noexcept = default;
+ SMPMsg(SMPMsg &&o) noexcept = default;
+ SMPMsg& operator=(const SMPMsg &o) noexcept = delete; // const ts_creation
+ SMPMsg& operator=(SMPMsg &&o) noexcept = delete; // const ts_creation
+
+ virtual ~SMPMsg() noexcept {}
+
+ /** SMP Command Codes Vol 3, Part H (SM): 3.3 */
+ inline Opcode getOpcode() const noexcept {
+ return static_cast<Opcode>(pdu.get_uint8_nc(0));
+ }
+ std::string getOpcodeString() const noexcept { return getOpcodeString(getOpcode()); }
+
+ /**
+ * Returns the actual PDU size less one octet for the opcode,
+ * which should result in 0-22 octets or 64 octets.
+ * <p>
+ * Note that the PDU parameter include the data value below.
+ * </p>
+ * <p>
+ * Use getDataSize() for the actual required data size
+ * according to the specific packet.
+ * </p>
+ *
+ * @see SMPMsg::getDataSize()
+ */
+ jau::nsize_t getPDUParamSize() const noexcept {
+ return pdu.getSize() - 1 /* opcode */;
+ }
+
+ /**
+ * Returns the required data size according to the specified packet,
+ * which should be within 0-22 or 64 octets.
+ *
+ * @see SMPMsg::getPDUParamSize()
+ */
+ virtual jau::nsize_t getDataSize() const noexcept {
+ return getPDUParamSize();
+ }
+
+
+ /**
+ * Returns the octet offset to the data segment in this PDU
+ * including the mandatory opcode,
+ * i.e. the number of octets until the first value octet.
+ */
+ constexpr jau::nsize_t getDataOffset() const noexcept { return 1; /* default: opcode */ }
+
+ virtual std::string getName() const noexcept {
+ return "SMPMsg";
+ }
+
+ virtual std::string toString() const noexcept{
+ return getName()+"["+baseString()+", value["+valueString()+"]]";
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.5.1 Pairing Request message.<br>
+ * Vol 3, Part H: 3.5.2 Pairing Response message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.5 Pairing Methods
+ * Vol 3 (Host), Part H (SM): 2 (SM), 2.3 Pairing Methods
+ * </pre>
+ * <p>
+ * Opcode::PAIRING_REQUEST or Opcode::PAIRING_RESPONSE
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * uint8_t io_capability
+ * uint8_t oob_data_flag
+ * uint8_t auth_req_mask
+ * uint8_t max_encryption_key_size
+ * uint8_t initiator_key_distribution
+ * uint8_t responder_key_distribution
+ * </pre>
+ *
+ * <br>
+ * SMP Pairing Request Vol 3, Part H (SM): 3.5.1
+ * <p>
+ * Initiator starts the Pairing Feature Exchange
+ * by sending a Pairing Request command to the responding device.
+ * </p>
+ * <p>
+ * The rules for handing a collision between a pairing procedure
+ * on the LE transport and a pairing procedure on the BR/EDR transport
+ * are defined in Vol 3, Part C (GAP): 14.2 BRD/EDR/LE security aspects - Collision Handling.
+ * </p>
+ *
+ * <br>
+ * SMP Pairing Response Vol 3, Part H (SM): 3.5.2
+ * <p>
+ * Command is used by the responding device to complete the Pairing Feature Exchange
+ * after it has received a Pairing Request command from the initiating device,
+ * if the responding device allows pairing.
+ * </p>
+ * <p>
+ * If a Pairing Request is received over the BR/EDR transport
+ * when either cross-transport key derivation/generation is not supported
+ * or the BR/EDR transport is not encrypted using a Link Key generated using P256,
+ * a Pairing Failed shall be sent with the error code
+ * SMPPairFailedMsg::ReasonCode::CROSSXPORT_KEY_DERIGEN_NOT_ALLOWED (Cross-Transport Key Derivation/Generation Not Allowed).
+ * </p>
+ * <p>
+ * The rules for handing a collision between a pairing procedure
+ * on the LE transport and a pairing procedure on the BR/EDR transport
+ * are defined in Vol 3, Part C (GAP): 14.2 BRD/EDR/LE security aspects - Collision Handling.
+ * </p>
+ */
+ class SMPPairingMsg : public SMPMsg
+ {
+ public:
+ /**
+ * Vol 3, Part H, 2.3.2 IO capabilities
+ */
+ enum class IOCapability : uint8_t {
+ DISPLAY_ONLY = 0x00,/**< DISPLAY_ONLY */
+ DISPLAY_YES_NO = 0x01,/**< DISPLAY_YES_NO */
+ KEYBOARD_ONLY = 0x02,/**< KEYBOARD_ONLY */
+ NO_INPUT_NO_OUTPUT = 0x03,/**< NO_INPUT_NO_OUTPUT */
+ KEYBOARD_DISPLAY = 0x04 /**< KEYBOARD_DISPLAY */
+ };
+ static constexpr uint8_t number(const IOCapability rhs) noexcept {
+ return static_cast<uint8_t>(rhs);
+ }
+ static std::string getIOCapabilityString(const IOCapability ioc) noexcept;
+
+ /**
+ * Vol 3, Part H, 2.3.3 OOB authentication data
+ *
+ */
+ enum class OOBDataFlag : uint8_t {
+ OOB_AUTH_DATA_NOT_PRESENT = 0x00,/**< OOB_AUTH_DATA_NOT_PRESENT */
+ OOB_AUTH_DATA_REMOTE_PRESENT = 0x01 /**< OOB_AUTH_DATA_REMOTE_PRESENT */
+ };
+ static constexpr uint8_t number(const OOBDataFlag rhs) noexcept {
+ return static_cast<uint8_t>(rhs);
+ }
+ static std::string getOOBDataFlagString(const OOBDataFlag v) noexcept;
+
+ /**
+ * LE Key Distribution format, 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.
+ * </pre>
+ * </p>
+ * Layout LSB -> MSB
+ * <pre>
+ * uint8_t EncKey : 1, IdKey : 1, SignKey : 1, LinkKey : 1, RFU : 4;
+ * </pre>
+ */
+ enum class KeyDistFormat : uint8_t {
+ NONE = 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 = 0b00000001,
+ /**
+ * Indicates that the device shall distribute IRK using the Identity Information command
+ * followed by its public device or statuc random address using Identity Address Information.
+ */
+ ID_KEY = 0b00000010,
+ /**
+ * Indicates that the device shall distribute CSRK using the Signing Information command.
+ */
+ SIGN_KEY = 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 = 0b00001000,
+ /** Reserved for future use */
+ RFU_1 = 0b00010000,
+ /** Reserved for future use */
+ RFU_2 = 0b00100000,
+ /** Reserved for future use */
+ RFU_3 = 0b01000000,
+ /** Reserved for future use */
+ RFU_4 = 0b10000000
+ };
+ static constexpr uint8_t number(const KeyDistFormat rhs) noexcept {
+ return static_cast<uint8_t>(rhs);
+ }
+ static constexpr bool isKeyDistFormatBitSet(const KeyDistFormat mask, const KeyDistFormat bit) noexcept {
+ return 0 != ( static_cast<uint8_t>(mask) & static_cast<uint8_t>(bit) );
+ }
+ static std::string getKeyDistFormatBitString(const KeyDistFormat bit) noexcept;
+ static std::string getKeyDistFormatMaskString(const KeyDistFormat mask) noexcept;
+
+ private:
+ const bool request;
+ const SMPAuthReqs authReqMask;
+ const KeyDistFormat initiator_key_dist;
+ const KeyDistFormat responder_key_dist;
+
+ public:
+ SMPPairingMsg(const bool request_, const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length),
+ request(request_),
+ authReqMask(static_cast<SMPAuthReqs>( pdu.get_uint8_nc(3) )),
+ initiator_key_dist(static_cast<KeyDistFormat>(pdu.get_uint8_nc(5))),
+ responder_key_dist(static_cast<KeyDistFormat>(pdu.get_uint8_nc(6)))
+ {
+ checkOpcode(request? Opcode::PAIRING_REQUEST : Opcode::PAIRING_RESPONSE);
+ }
+
+ SMPPairingMsg(const bool request_,
+ const IOCapability ioc, const OOBDataFlag odf,
+ const SMPAuthReqs auth_req_mask, const uint8_t maxEncKeySize,
+ const KeyDistFormat initiator_key_dist_,
+ const KeyDistFormat responder_key_dist_)
+ : SMPMsg(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_)
+ {
+ pdu.put_uint8_nc(1, number(ioc));
+ pdu.put_uint8_nc(2, number(odf));
+ pdu.put_uint8_nc(3, direct_bt::number(authReqMask));
+ pdu.put_uint8_nc(4, maxEncKeySize);
+ pdu.put_uint8_nc(5, number(initiator_key_dist));
+ pdu.put_uint8_nc(6, number(responder_key_dist));
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 6;
+ }
+
+ /**
+ * Returns the IO capability bit field.
+ * <pre>
+ * Vol 3, Part H, 2.3.2 IO capabilities
+ * </pre>
+ * @see IOCapability
+ */
+ IOCapability getIOCapability() const noexcept {
+ return static_cast<IOCapability>(pdu.get_uint8_nc(1));
+ }
+
+ /**
+ * Returns the OBB authenticate data flag
+ * <pre>
+ * Vol 3, Part H, 2.3.3 OOB authentication data
+ * </pre>
+ * @see OOBDataFlag
+ */
+ OOBDataFlag getOOBDataFlag() const noexcept {
+ return static_cast<OOBDataFlag>(pdu.get_uint8_nc(2));
+ }
+
+ /**
+ * Returns the Authentication Requirements mask.
+ * <pre>
+ * SMP Pairing Request Vol 3, Part H (SM): 3.5.1
+ * SMP Pairing Response Vol 3, Part H (SM): 3.5.2
+ * </pre>
+ * @see AuthRequirements
+ */
+ constexpr SMPAuthReqs getAuthReqMask() const noexcept {
+ return authReqMask;
+ }
+ constexpr bool isAuthRequirementBitSet(const SMPAuthReqs bit) const noexcept {
+ return isSMPAuthReqBitSet(authReqMask, bit);
+ }
+
+ /**
+ * This value defines the maximum encryption key size in octets that the device
+ * can support. The maximum key size shall be in the range 7 to 16 octets.
+ */
+ uint8_t getMaxEncryptionKeySize() const noexcept {
+ return pdu.get_uint8_nc(4);
+ }
+ /**
+ * Returns the Initiator Key Distribution field,
+ * which defines which keys the initiator shall
+ * distribute and use during the Transport Specific Key Distribution phase.
+ * <pre>
+ * See Vol 3, Part H, 2.4.3 SM - LE Security - Distribution of keys.
+ * Field format and usage: Vol 3, Part H, 3.6.1 SMP - LE Security - Key distribution and generation.
+ * </pre>
+ * @see KeyDistributionFormat
+ */
+ constexpr KeyDistFormat getInitiatorKeyDistribution() const noexcept {
+ return initiator_key_dist;
+ }
+ constexpr bool isInitiatorKeyDistributionBitSet(const KeyDistFormat bit) const noexcept {
+ return isKeyDistFormatBitSet(initiator_key_dist, bit);
+ }
+ /**
+ * Return the Responder Key Distribution field,
+ * which defines which keys the responder shall
+ * distribute and use during the Transport Specific Key Distribution phase.
+ * <p>
+ * See Vol 3, Part H, 2.4.3 SM - LE Security - Distribution of keys.
+ * Field format and usage: Vol 3, Part H, 3.6.1 SMP - LE Security - Key distribution and generation.
+ * </p>
+ * @see KeyDistributionFormat
+ */
+ constexpr KeyDistFormat getResponderKeyDistribution() const noexcept {
+ return responder_key_dist;
+ }
+ constexpr bool isResponderKeyDistributionBitSet(const KeyDistFormat bit) const noexcept {
+ return isKeyDistFormatBitSet(initiator_key_dist, bit);
+ }
+
+ std::string getName() const noexcept override {
+ return request ? "SMPPairReq" : "SMPPairRes";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ return "iocap "+getIOCapabilityString(getIOCapability())+
+ ", oob "+getOOBDataFlagString(getOOBDataFlag())+
+ ", auth_req "+getSMPAuthReqMaskString(getAuthReqMask())+
+ ", max_keysz "+std::to_string(getMaxEncryptionKeySize())+
+ ", key_dist[init "+getKeyDistFormatMaskString(getInitiatorKeyDistribution())+
+ ", resp "+getKeyDistFormatMaskString(getResponderKeyDistribution())+
+ "]";
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.5.3 Pairing Confirm message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.5 Pairing Methods
+ * </pre>
+ * <p>
+ * Opcode::PAIRING_CONFIRM
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * jau::uint128_t confirm_value
+ * </pre>
+ * <p>
+ * Used following a successful Pairing Feature Exchange to start
+ * STK Generation for LE legacy pairing and LTK Generation for LE Secure Connections pairing.
+ * </p>
+ * <p>
+ * Command is used by both devices to send the confirm value to the peer device,<br>
+ * see Vol 3, Part H, 2.3.5.5 SM - Pairing algo - LE legacy pairing phase 2 and<br>
+ * and Vol 3, Part H, 2.3.5.6 SM - Pairing algo - LE Secure Connections pairing phase 2.
+ * </p>
+ * <p>
+ * The initiating device starts key generation by sending the Pairing Confirm command to the responding device.<br>
+ * If the initiating device wants to abort pairing it can transmit a Pairing Failed command instead.
+ * </p>
+ * <p>
+ * The responding device sends the Pairing Confirm command
+ * after it has received a Pairing Confirm command from the initiating device.
+ * </p>
+ */
+ class SMPPairConfMsg : public SMPMsg
+ {
+ public:
+ SMPPairConfMsg(const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length)
+ {
+ checkOpcode(Opcode::PAIRING_CONFIRM);
+ }
+
+ SMPPairConfMsg(const jau::uint128_t & confirm_value)
+ : SMPMsg(Opcode::PAIRING_CONFIRM, 1+16)
+ {
+ pdu.put_uint128_nc(1, confirm_value);
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 16;
+ }
+
+ /**
+ * Returns the 128-bit Confirm value (16 octets)
+ * <p>
+ * In LE legacy pairing, the initiating device sends Mconfirm and the
+ * responding device sends Sconfirm as defined in
+ * Vol 3, Part H, 2.3.5.5 SM - Pairing algo - LE legacy pairing phase 2
+ * </p>
+ * <p>
+ * In LE Secure Connections, Ca and Cb are defined in
+ * Vol 3, Part H, Section 2.2.6 SM - Crypto Toolbox - LE Secure Connections confirm value generation function f4.<br>
+ * See Vol 3, Part H, 2.3.5.6 SM - Pairing algo - LE Secure Connections pairing phase 2.
+ * </p>
+ */
+ jau::uint128_t getConfirmValuePtr() const noexcept { return pdu.get_uint128_nc(1); }
+
+ std::string getName() const noexcept override {
+ return "SMPPairConf";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ return "size "+std::to_string(getDataSize())+", data anon"; // FIXME: Shareable?
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.5.4 Pairing Random message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.5 Pairing Methods
+ * </pre>
+ * <p>
+ * Opcode::PAIRING_RANDOM
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * jau::uint128_t random_value
+ * </pre>
+ * <p>
+ * Used by the initiating and responding device to send the
+ * random number used to calculate the Confirm value sent in the Pairing Confirm command.
+ * </p>
+ * <p>
+ * The initiating device sends a Pairing Random command
+ * after it has received a Pairing Confirm command from the responding device.
+ * </p>
+ * <p>
+ * LE legacy pairing: Responding device sends a Pairing Random command
+ * after receiving a Pairing Random command from the initiating device
+ * if the Confirm value calculated on the responding device matches the
+ * Confirm value received from the initiating device.<br>
+ * If the calculated Confirm value does not match
+ * then the responding device shall respond with the Pairing Failed command.
+ * </p>
+ * <p>
+ * LE Secure Connections: Responding device sends a Pairing Random command
+ * after it has received a Pairing Random command from the initiating device
+ * <i>if the Confirm value calculated on the responding device matches the
+ * Confirm value received from the initiating device(?)</i>.<br>
+ * If the calculated Confirm value does not match then the responding device
+ * shall respond with the Pairing Failed command.
+ * </p>
+ * <p>
+ * The initiating device shall encrypt the link using
+ * the generated key (STK in LE legacy pairing or LTK in LE Secure Connections)
+ * if the Confirm value calculated on the initiating device matches
+ * the Confirm value received from the responding device.<br>
+ * The successful encryption or re-encryption of the link is the signal
+ * to the responding device that key generation has completed successfully.<br>
+ * If the calculated Confirm value does not match then
+ * the initiating device shall respond with the Pairing Failed command.
+ * </p>
+ */
+ class SMPPairRandMsg : public SMPMsg
+ {
+ public:
+ SMPPairRandMsg(const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length)
+ {
+ checkOpcode(Opcode::PAIRING_RANDOM);
+ }
+
+ SMPPairRandMsg(const jau::uint128_t & random_value)
+ : SMPMsg(Opcode::PAIRING_RANDOM, 1+16)
+ {
+ pdu.put_uint128_nc(1, random_value);
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 16;
+ }
+
+ /**
+ * Returns the 128-bit Random value (16 octets)
+ * <p>
+ * In LE legacy pairing, the initiating device sends Mrand and the
+ * responding device sends Srand as defined in
+ * Vol 3, Part H, 2.3.5.5 SM - Pairing algo - LE legacy pairing phase 2
+ * </p>
+ * <p>
+ * In LE Secure Connections,
+ * the initiating device sends Na and the responding device sends Nb.
+ * </p>
+ */
+ jau::uint128_t getRandomValuePtr() const noexcept { return pdu.get_uint128_nc(1); }
+
+ std::string getName() const noexcept override {
+ return "SMPPairRand";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ return "size "+std::to_string(getDataSize())+", data anon";
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.5.5 Pairing Failed message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.5 Pairing Methods
+ * </pre>
+ * <p>
+ * Opcode::PAIRING_FAILED
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * uint8_t reason_code
+ * </pre>
+ */
+ class SMPPairFailedMsg: public SMPMsg
+ {
+ public:
+ enum class ReasonCode : uint8_t {
+ UNDEFINED = 0x00,
+ PASSKEY_ENTRY_FAILED = 0x01,
+ OOB_NOT_AVAILABLE = 0x02,
+ AUTHENTICATION_REQUIREMENTS = 0x03,
+ CONFIRM_VALUE_FAILED = 0x04,
+ PAIRING_NOT_SUPPORTED = 0x05,
+ ENCRYPTION_KEY_SIZE = 0x06,
+ COMMON_NOT_SUPPORTED = 0x07,
+ UNSPECIFIED_REASON = 0x08,
+ REPEATED_ATTEMPTS = 0x09,
+ INVALID_PARAMTERS = 0x0A,
+ DHKEY_CHECK_FAILED = 0x0B,
+ NUMERIC_COMPARISON_FAILED = 0x0C,
+ BREDR_PAIRING_IN_PROGRESS = 0x0D,
+ CROSSXPORT_KEY_DERIGEN_NOT_ALLOWED = 0x0E
+ };
+ static constexpr uint8_t number(const ReasonCode rhs) noexcept {
+ return static_cast<uint8_t>(rhs);
+ }
+ static std::string getPlainReasonString(const ReasonCode reasonCode) noexcept;
+
+ SMPPairFailedMsg(const uint8_t* source, const jau::nsize_t length) : SMPMsg(source, length) {
+ checkOpcode(Opcode::PAIRING_FAILED);
+ }
+
+ SMPPairFailedMsg(const ReasonCode rc)
+ : SMPMsg(Opcode::PAIRING_FAILED, 1+1)
+ {
+ pdu.put_uint8_nc(1, number(rc));
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 1;
+ }
+
+ ReasonCode getReasonCode() const noexcept {
+ return static_cast<ReasonCode>(pdu.get_uint8_nc(1));
+ }
+
+ std::string getName() const noexcept override {
+ return "SMPPairFailed";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ const ReasonCode ec = getReasonCode();
+ return jau::uint8HexString(number(ec), true) + ": " + getPlainReasonString(ec);
+ }
+ };
+
+
+ /**
+ * Vol 3, Part H: 3.5.6 Pairing Public Key message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.5 Pairing Methods
+ * </pre>
+ * <p>
+ * Opcode::PAIRING_PUBLIC_KEY
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * jau::uint256_t public_key_x_value
+ * jau::uint256_t public_key_y_value
+ * </pre>
+ * <p>
+ * Message is used to transfer the device’s local public key (X and Y coordinates) to the remote device.<br>
+ * This message is used by both the initiator and responder.<br>
+ * This PDU is only used for LE Secure Connections.
+ * </p>
+ */
+ class SMPPairPubKeyMsg : public SMPMsg
+ {
+ public:
+ SMPPairPubKeyMsg(const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length)
+ {
+ checkOpcode(Opcode::PAIRING_PUBLIC_KEY);
+ }
+
+ SMPPairPubKeyMsg(const jau::uint256_t & pub_key_x, const jau::uint256_t & pub_key_y)
+ : SMPMsg(Opcode::PAIRING_PUBLIC_KEY, 1+32+32)
+ {
+ pdu.put_uint256_nc(1, pub_key_x);
+ pdu.put_uint256_nc(1+32, pub_key_y);
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 32+32;
+ }
+
+ /**
+ * Returns the 256-bit Public Key X value (32 octets)
+ */
+ jau::uint256_t getPublicKeyXValuePtr() const noexcept { return pdu.get_uint256_nc(1); }
+
+ /**
+ * Returns the 256-bit Public Key Y value (32 octets)
+ */
+ jau::uint256_t getPublicKeyYValuePtr() const noexcept { return pdu.get_uint256_nc(1+32); }
+
+ std::string getName() const noexcept override {
+ return "SMPPairPubKey";
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.5.7 Pairing DHKey Check message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.5 Pairing Methods
+ * </pre>
+ * <p>
+ * Opcode::PAIRING_DHKEY_CHECK
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * jau::uint128_t dhkey_check_values
+ * </pre>
+ * <p>
+ * Message is used to transmit the 128-bit DHKey Check values (Ea/Eb) generated using f6.<br>
+ * This message is used by both initiator and responder.<br>
+ * This PDU is only used for LE Secure Connections.
+ * </p>
+ */
+ class SMPPairDHKeyCheckMsg : public SMPMsg
+ {
+ public:
+ SMPPairDHKeyCheckMsg(const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length)
+ {
+ checkOpcode(Opcode::PAIRING_DHKEY_CHECK);
+ }
+
+ SMPPairDHKeyCheckMsg(const jau::uint128_t & dhkey_check_values)
+ : SMPMsg(Opcode::PAIRING_DHKEY_CHECK, 1+16)
+ {
+ pdu.put_uint128_nc(1, dhkey_check_values);
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 16;
+ }
+
+ /**
+ * Returns the 128-bit DHKey Check value (16 octets)
+ */
+ jau::uint128_t getDHKeyCheckValuePtr() const noexcept { return pdu.get_uint128_nc(1); }
+
+ std::string getName() const noexcept override {
+ return "SMPPairDHKeyCheck";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ return "size "+std::to_string(getDataSize())+", data anon"; // FIXME: Shareable?
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.5.8 Passkey Entry: Keypress notification messages.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.5 Pairing Methods
+ * </pre>
+ * <p>
+ * Opcode::PAIRING_KEYPRESS_NOTIFICATION
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * uint8_t notification_type
+ * </pre>
+ * <p>
+ * Message is used during the Passkey Entry protocol by a device with KeyboardOnly IO capabilities
+ * to inform the remote device when keys have been entered or erased.
+ * </p>
+ */
+ class SMPPasskeyNotification: public SMPMsg
+ {
+ public:
+ enum class TypeCode : uint8_t {
+ PASSKEY_ENTRY_STARTED = 0x00,
+ PASSKEY_DIGIT_ENTERED = 0x01,
+ PASSKEY_DIGIT_ERASED = 0x02,
+ PASSKEY_CLEARED = 0x03,
+ PASSKEY_ENTRY_COMPLETED = 0x04
+ };
+ static constexpr uint8_t number(const TypeCode rhs) noexcept {
+ return static_cast<uint8_t>(rhs);
+ }
+ static std::string getTypeCodeString(const TypeCode tc) noexcept;
+
+ SMPPasskeyNotification(const uint8_t* source, const jau::nsize_t length) : SMPMsg(source, length) {
+ checkOpcode(Opcode::PAIRING_KEYPRESS_NOTIFICATION);
+ }
+
+ SMPPasskeyNotification(const TypeCode tc)
+ : SMPMsg(Opcode::PAIRING_KEYPRESS_NOTIFICATION, 1+1)
+ {
+ pdu.put_uint8_nc(1, number(tc));
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 1;
+ }
+
+ TypeCode getTypeCode() const noexcept {
+ return static_cast<TypeCode>(pdu.get_uint8_nc(1));
+ }
+
+ std::string getName() const noexcept override {
+ return "SMPPasskeyNotify";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ const TypeCode ec = getTypeCode();
+ return jau::uint8HexString(number(ec), true) + ": " + getTypeCodeString(ec);
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.6.2 Encryption Information message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.6 SECURITY IN BLUETOOTH LOW ENERGY
+ * </pre>
+ * <p>
+ * Opcode::ENCRYPTION_INFORMATION
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * jau::uint128_t long_term_key
+ * </pre>
+ * <p>
+ * Message is used in the LE legacy pairing Transport Specific Key Distribution
+ * to distribute LTK that is used when encrypting future connections.
+ * </p>
+ * <p>
+ * The message shall only be sent when the link has been encrypted or re-encrypted using the generated STK.
+ * </p>
+ */
+ class SMPEncInfoMsg : public SMPMsg
+ {
+ public:
+ SMPEncInfoMsg(const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length)
+ {
+ checkOpcode(Opcode::ENCRYPTION_INFORMATION);
+ }
+
+ SMPEncInfoMsg(const jau::uint128_t & long_term_key)
+ : SMPMsg(Opcode::ENCRYPTION_INFORMATION, 1+16)
+ {
+ pdu.put_uint128_nc(1, long_term_key);
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 16;
+ }
+
+ /**
+ * Returns the 128-bit Long Term Key (16 octets)
+ * <p>
+ * The generated LTK value being distributed,
+ * see Vol 3, Part H, 2.4.2.3 SM - Generation of CSRK - LE legacy pairing - generation of LTK, EDIV and Rand.
+ * </p>
+ */
+ jau::uint128_t getLongTermKeyPtr() const noexcept { return pdu.get_uint128_nc(1); }
+
+ std::string getName() const noexcept override {
+ return "SMPEncInfo";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ return "size "+std::to_string(getDataSize())+", data anon";
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.6.3 Master Identification message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.6 SECURITY IN BLUETOOTH LOW ENERGY
+ * </pre>
+ * <p>
+ * Opcode::MASTER_IDENTIFICATION
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * uint16_t ediv
+ * uint64_t rand
+ * </pre>
+ * <p>
+ * Message is used in the LE legacy pairing Transport Specific Key Distribution phase
+ * to distribute EDIV and Rand which are used when encrypting future connections.
+ * </p>
+ * <p>
+ * The message shall only be sent when the link has been encrypted or re-encrypted using the generated STK.
+ * </p>
+ */
+ class SMPMasterIdentMsg : public SMPMsg
+ {
+ public:
+ SMPMasterIdentMsg(const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length)
+ {
+ checkOpcode(Opcode::MASTER_IDENTIFICATION);
+ }
+
+ SMPMasterIdentMsg(const uint16_t ediv, const uint64_t & rand)
+ : SMPMsg(Opcode::MASTER_IDENTIFICATION, 1+2+8)
+ {
+ pdu.put_uint16_nc(1, ediv);
+ pdu.put_uint64_nc(1+2, rand);
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 10;
+ }
+
+ /**
+ * Returns the 16-bit EDIV value (2 octets) being distributed
+ * <p>
+ * See Vol 3, Part H, 2.4.2.3 SM - Generation of CSRK - LE legacy pairing - generation of LTK, EDIV and Rand.
+ * </p>
+ */
+ uint16_t getEDIV() const noexcept { return pdu.get_uint16_nc(1); }
+
+ /**
+ * Returns the 64-bit Rand value (8 octets) being distributed
+ * <p>
+ * See Vol 3, Part H, 2.4.2.3 SM - Generation of CSRK - LE legacy pairing - generation of LTK, EDIV and Rand.
+ * </p>
+ */
+ uint64_t getRand() const noexcept { return pdu.get_uint64_nc(1+2); }
+
+ std::string getName() const noexcept override {
+ return "SMPMasterIdent";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ return "size "+std::to_string(getDataSize())+", data anon";
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.6.4 Identify Information message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.6 SECURITY IN BLUETOOTH LOW ENERGY
+ * </pre>
+ * <p>
+ * Opcode::IDENTITY_INFORMATION
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * jau::uint128_t identity_resolving_key
+ * </pre>
+ * <p>
+ * Message is used in the Transport Specific Key Distribution phase to distribute IRK.
+ * </p>
+ * <p>
+ * The message shall only shall only be sent when the link has been encrypted or re-encrypted using the generated key.
+ * </p>
+ */
+ class SMPIdentInfoMsg : public SMPMsg
+ {
+ public:
+ SMPIdentInfoMsg(const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length)
+ {
+ checkOpcode(Opcode::IDENTITY_INFORMATION);
+ }
+
+ SMPIdentInfoMsg(const jau::uint128_t & identity_resolving_key)
+ : SMPMsg(Opcode::IDENTITY_INFORMATION, 1+16)
+ {
+ pdu.put_uint128_nc(1, identity_resolving_key);
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 16;
+ }
+
+ /**
+ * Returns the 128-bit Identity Resolving Key (IRK, 16 octets)
+ * <p>
+ * The 128-bit IRK value being distributed,
+ * see Vol 3, Part H, 2.4.2.1 SM - Definition of keys and values - Generation of IRK.
+ * </p>
+ */
+ jau::uint128_t getIRKPtr() const noexcept { return pdu.get_uint128_nc(1); }
+
+ std::string getName() const noexcept override {
+ return "SMPIdentInfo";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ return "size "+std::to_string(getDataSize())+", data anon";
+ }
+ };
+
+
+ /**
+ * Vol 3, Part H: 3.6.5 Identity Address Information message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.6 SECURITY IN BLUETOOTH LOW ENERGY
+ * </pre>
+ * <p>
+ * Opcode::IDENTITY_ADDRESS_INFORMATION
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * uint8_t address_type (0x01 static random, 0x00 public)
+ * EUI48 address
+ * </pre>
+ * <p>
+ * Message is used in the Transport Specific Key Distribution phase
+ * to distribute its public device address or static random address.
+ * </p>
+ * <p>
+ * The message shall only be sent when the link has been encrypted or re-encrypted using the generated key.
+ * </p>
+ */
+ class SMPIdentAddrInfoMsg : public SMPMsg
+ {
+ public:
+ SMPIdentAddrInfoMsg(const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length)
+ {
+ checkOpcode(Opcode::IDENTITY_ADDRESS_INFORMATION);
+ }
+
+ SMPIdentAddrInfoMsg(const bool addrIsStaticRandom, const EUI48 & addr)
+ : SMPMsg(Opcode::IDENTITY_ADDRESS_INFORMATION, 1+1+6)
+ {
+ pdu.put_uint8_nc(1, addrIsStaticRandom ? 0x01 : 0x00);
+ pdu.put_eui48_nc(1+1, addr);
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 1+6;
+ }
+
+ /**
+ * Returns whether the device address is static random (true) or public (false).
+ */
+ bool isStaticRandomAddress() const noexcept { return pdu.get_uint16_nc(1) == 0x01; }
+
+ /**
+ * Returns the device address
+ */
+ EUI48 getAddress() const noexcept { return pdu.get_eui48_nc(1+1); }
+
+ std::string getName() const noexcept override {
+ return "SMPIdentAddrInfo";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ const std::string ats = isStaticRandomAddress() ? "static-random" : "public";
+ return "address["+getAddress().toString()+", "+ats+"]";
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.6.6 Signing Information message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.6 SECURITY IN BLUETOOTH LOW ENERGY
+ * </pre>
+ * <p>
+ * Opcode::SIGNING_INFORMATION
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * jau::uint128_t signature_key
+ * </pre>
+ * <p>
+ * Message is used in the Transport Specific Key Distribution to distribute the CSRK which a device uses to sign data.
+ * </p>
+ * <p>
+ * The message shall only shall only be sent when the link has been encrypted or re-encrypted using the generated key.
+ * </p>
+ */
+ class SMPSignInfoMsg : public SMPMsg
+ {
+ public:
+ SMPSignInfoMsg(const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length)
+ {
+ checkOpcode(Opcode::SIGNING_INFORMATION);
+ }
+
+ SMPSignInfoMsg(const jau::uint128_t & signature_key)
+ : SMPMsg(Opcode::SIGNING_INFORMATION, 1+16)
+ {
+ pdu.put_uint128_nc(1, signature_key);
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 16;
+ }
+
+ /**
+ * Returns the 128-bit Identity Resolving Key (IRK, 16 octets)
+ * <p>
+ * The 128-bit IRK value being distributed,
+ * see Vol 3, Part H, 2.4.2.1 SM - Definition of keys and values - Generation of IRK.
+ * </p>
+ */
+ jau::uint128_t getIRKPtr() const noexcept { return pdu.get_uint128_nc(1); }
+
+ std::string getName() const noexcept override {
+ return "SMPSignInfo";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ return "size "+std::to_string(getDataSize())+", data anon";
+ }
+ };
+
+ /**
+ * Vol 3, Part H: 3.6.7 Security Request message.
+ * <pre>
+ * Vol 3 (Host), Part H (SM): 3 (SMP), 3.6 SECURITY IN BLUETOOTH LOW ENERGY
+ * </pre>
+ * <p>
+ * Opcode::SECURITY_REQUEST
+ * </p>
+ * <pre>
+ * [uint8_t opcode]
+ * uint8_t auth_req_mask
+ * </pre>
+ * <p>
+ * Message is used by the slave to request that the master initiates security with the requested security properties,<br>
+ * see Vol 3 (Host), Part H (SM): 2 (SM), 2.4 SECURITY IN BLUETOOTH LOW ENERGY, 2.4.6 Slave Security Request
+ * </p>
+ */
+ class SMPSecurityReqMsg : public SMPMsg
+ {
+ private:
+ SMPAuthReqs authReqMask;
+ public:
+ SMPSecurityReqMsg(const uint8_t* source, const jau::nsize_t length)
+ : SMPMsg(source, length),
+ authReqMask(static_cast<SMPAuthReqs>( pdu.get_uint8_nc(1) ))
+ {
+ checkOpcode(Opcode::SECURITY_REQUEST);
+ }
+
+ SMPSecurityReqMsg(const SMPAuthReqs auth_req_mask)
+ : SMPMsg(Opcode::SECURITY_REQUEST, 1+1), authReqMask(auth_req_mask)
+ {
+ pdu.put_uint8_nc(1, direct_bt::number(authReqMask));
+ }
+
+ jau::nsize_t getDataSize() const noexcept override {
+ return 1;
+ }
+
+ /**
+ * Returns the SMPPairingMsg::AuthRequirements (1 octet)
+ * <p>
+ * The AuthReq field is a bit field that indicates the requested security properties,<br>
+ * see Vol 3 (Host), Part H (SM): 2 (SM), 2.3 Pairing Methods, 2.3.1 Security Properties,<br>
+ * for the STK or LTK and GAP bonding information,<br>
+ * see Vol 3 (Host), Part C (GAP): 9.4 Bonding Modes and Procedures<br>
+ * </p>
+ */
+ constexpr SMPAuthReqs getAuthReqMask() const noexcept {
+ return authReqMask;
+ }
+ constexpr bool isAuthRequirementBitSet(const SMPAuthReqs bit) const noexcept {
+ return isSMPAuthReqBitSet(authReqMask, bit);
+ }
+
+ std::string getName() const noexcept override {
+ return "SMPSecurityReq";
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ return "auth_req "+getSMPAuthReqMaskString(getAuthReqMask());
+ }
+ };
+
+} // namespace direct_bt
+
+#endif /* SMP_TYPES_HPP_ */