diff options
Diffstat (limited to 'arduino/libraries/BLEHomekit/src/service')
8 files changed, 1079 insertions, 0 deletions
diff --git a/arduino/libraries/BLEHomekit/src/service/HAPAccessoryInfo.cpp b/arduino/libraries/BLEHomekit/src/service/HAPAccessoryInfo.cpp new file mode 100755 index 0000000..bae3f44 --- /dev/null +++ b/arduino/libraries/BLEHomekit/src/service/HAPAccessoryInfo.cpp @@ -0,0 +1,93 @@ +/**************************************************************************/ +/*! + @file HAPAccessoryInfo.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include <bluefruit.h> +#include "HAPUuid.h" +#include "HAPAccessoryInfo.h" + +HAPAccessoryInfo::HAPAccessoryInfo(void) + : HAPService (HAP_UUID_SVC_ACCESSORY_INFO), + _identify (HAP_UUID_CHR_IDENTIFY , BLE_GATT_CPF_FORMAT_UTF8S), + _mfr (HAP_UUID_CHR_MANUFACTURER , BLE_GATT_CPF_FORMAT_UTF8S), + _model (HAP_UUID_CHR_MODEL , BLE_GATT_CPF_FORMAT_UTF8S), + _name (HAP_UUID_CHR_NAME , BLE_GATT_CPF_FORMAT_UTF8S), + _serial (HAP_UUID_CHR_SERIAL_NUMBER , BLE_GATT_CPF_FORMAT_UTF8S), + _fw_rev (HAP_UUID_CHR_FIRMWARE_REV , BLE_GATT_CPF_FORMAT_UTF8S) +{ + +} + +err_t HAPAccessoryInfo::begin(void) +{ + VERIFY_STATUS( HAPService::begin() ); // Invoke base class begin() + + // Identify + _identify.setHapProperties(HAP_CHR_PROPS_SECURE_WRITE); +// _identify.setFixedLen(1); + VERIFY_STATUS( _identify.begin() ); + + const char* strvals[] = + { + "Adafruit Industrial", + "Adafruit Bluefruit nrf52", + "Bluefruit52", + getMcuUniqueID(), + "0.9.0" + }; + + // Manufacturer + _mfr.setHapProperties(HAP_CHR_PROPS_SECURE_READ); + VERIFY_STATUS( _mfr.begin() ); + + // Model + _model.setHapProperties(HAP_CHR_PROPS_SECURE_READ); + VERIFY_STATUS( _model.begin() ); + + // Name + _name.setHapProperties(HAP_CHR_PROPS_SECURE_READ); + VERIFY_STATUS( _name.begin() ); + + // Serial + _serial.setHapProperties(HAP_CHR_PROPS_SECURE_READ); + VERIFY_STATUS( _serial.begin() ); + + // Firmware Revision + _fw_rev.setHapProperties(HAP_CHR_PROPS_SECURE_READ); + VERIFY_STATUS( _fw_rev.begin() ); + + return ERROR_NONE; +} + diff --git a/arduino/libraries/BLEHomekit/src/service/HAPAccessoryInfo.h b/arduino/libraries/BLEHomekit/src/service/HAPAccessoryInfo.h new file mode 100755 index 0000000..52f1fef --- /dev/null +++ b/arduino/libraries/BLEHomekit/src/service/HAPAccessoryInfo.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/*! + @file HAPAccessoryInfo.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef HAPACCESSORYINFO_H_ +#define HAPACCESSORYINFO_H_ + +#include "HAPCharacteristic.h" +#include "HAPService.h" + +class HAPAccessoryInfo : public HAPService +{ + public: + HAPAccessoryInfo(void); + + virtual err_t begin(void); + + private: + HAPCharacteristic _identify; + + HAPCharacteristic _mfr; + HAPCharacteristic _model; + HAPCharacteristic _name; + HAPCharacteristic _serial; + HAPCharacteristic _fw_rev; +}; + + + +#endif /* HAPACCESSORYINFO_H_ */ diff --git a/arduino/libraries/BLEHomekit/src/service/HAPLightBulb.cpp b/arduino/libraries/BLEHomekit/src/service/HAPLightBulb.cpp new file mode 100755 index 0000000..9d59ab3 --- /dev/null +++ b/arduino/libraries/BLEHomekit/src/service/HAPLightBulb.cpp @@ -0,0 +1,62 @@ +/**************************************************************************/ +/*! + @file HAPLightBulb.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include <bluefruit.h> +#include "HAPUuid.h" +#include "HAPLightBulb.h" + +HAPLightBulb::HAPLightBulb(void) + : HAPService(HAP_UUID_SVC_LIGHT_BULB), + _on(HAP_UUID_CHR_ON, BLE_GATT_CPF_FORMAT_BOOLEAN), + _name(HAP_UUID_CHR_NAME, BLE_GATT_CPF_FORMAT_UTF8S) +{ + +} + +err_t HAPLightBulb::begin(void) +{ + VERIFY_STATUS( HAPService::begin() ); // Invoke base class begin() + + // ON char + _on.setHapProperties(HAP_CHR_PROPS_SECURE_READ | HAP_CHR_PROPS_SECURE_WRITE | HAP_CHR_PROPS_NOTIFY ); + VERIFY_STATUS( _on.begin() ); + + // Name char + _name.setHapProperties(HAP_CHR_PROPS_SECURE_READ); + VERIFY_STATUS( _name.begin() ); + + return ERROR_NONE; +} diff --git a/arduino/libraries/BLEHomekit/src/service/HAPLightBulb.h b/arduino/libraries/BLEHomekit/src/service/HAPLightBulb.h new file mode 100755 index 0000000..da71501 --- /dev/null +++ b/arduino/libraries/BLEHomekit/src/service/HAPLightBulb.h @@ -0,0 +1,57 @@ +/**************************************************************************/ +/*! + @file HAPLightBulb.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef HAPLIGHTBULB_H_ +#define HAPLIGHTBULB_H_ + +#include "HAPCharacteristic.h" +#include "HAPService.h" + +class HAPLightBulb : public HAPService +{ + public: + HAPLightBulb(void); + + virtual err_t begin(void); + + private: + HAPCharacteristic _on; + HAPCharacteristic _name; +}; + + + + +#endif /* HAPLIGHTBULB_H_ */ diff --git a/arduino/libraries/BLEHomekit/src/service/HAPPairing.cpp b/arduino/libraries/BLEHomekit/src/service/HAPPairing.cpp new file mode 100755 index 0000000..c2f288f --- /dev/null +++ b/arduino/libraries/BLEHomekit/src/service/HAPPairing.cpp @@ -0,0 +1,613 @@ +/**************************************************************************/ +/*! + @file HAPPairing.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include <bluefruit.h> +#include "HAPUuid.h" +#include "HAPPairing.h" +#include "Bluefruit_FileIO.h" + +#include "crypto/crypto.h" + +#define DEBUG_HAP_PAIRING 0 + +/* SRP design detail http://srp.stanford.edu/design.html + */ + +// kTLV type for pairing +enum { + PAIRING_TYPE_METHOD = 0 , // 0 + PAIRING_TYPE_IDENTIFIER , // 1 + PAIRING_TYPE_SALT , // 2 + PAIRING_TYPE_PUBLIC_KEY , // 3 + PAIRING_TYPE_PROOF , // 4 + PAIRING_TYPE_ENCRYPTED_DATA , // 5 + PAIRING_TYPE_STATE , // 6 + PAIRING_TYPE_ERROR , // 7 + PAIRING_TYPE_RETRY_DELAY , // 8 + PAIRING_TYPE_CERTIFICATE , // 9 + PAIRING_TYPE_SIGNATURE , // 10 + PAIRING_TYPE_PERMISSIONS , // 11 + PAIRING_TYPE_FRAGMENT_DATA , // 12 + PAIRING_TYPE_FRAGMENT_LAST , // 13 + PAIRING_TYPE_SEPARATOR = 0xff +}; + +// kTLV value for pairing method +enum +{ + PAIRING_METHOD_SETUP = 1, + PAIRING_METHOD_VERIFY, + PAIRING_METHOD_ADD, + PAIRING_METHOD_REMOVE, + PAIRING_METHOD_LIST +}; + +// kTLV value for pairing error +enum +{ + PAIRING_ERROR_UNKNOWN = 1, + PAIRING_ERROR_AUTHENTICATION, + PAIRING_ERROR_BACKOFF, + PAIRING_ERROR_MAX_PEERS, + PAIRING_ERROR_MAX_TRIES, + PAIRING_ERROR_UNAVAILABLE, + PAIRING_ERROR_BUSY +}; + +#if CFG_DEBUG >= 2 +static const char* pairing_method_str[] = +{ + "", "Pair Setup", "Pair Verify", "Add Pairing", "Remove Pairing", "List Pairings" +}; + +static const char* pairing_type_str[] = +{ + "Method", "Identifier", "Salt", "Public Key", "Proof", + "Encrypted Data", "State", "Error", "Retry Delay", "Certificate", + "Signature", "Permissions", "Fragment Data", "Fragment Last", +}; + +#endif + +void _pair_setup_write_cb (uint16_t conn_hdl, HAPCharacteristic* chr, HAPRequest_t const* hap_req); +void _pair_verify_write_cb (uint16_t conn_hdl, HAPCharacteristic* chr, HAPRequest_t const* hap_req); + +// TODO add connection handle parameter +void gatt_reply_now(void) +{ + ble_gatts_rw_authorize_reply_params_t reply = + { + .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, + .params = { + .write = { + .gatt_status = BLE_GATT_STATUS_SUCCESS, + .update = 1, + } + } + }; + VERIFY_STATUS( sd_ble_gatts_rw_authorize_reply(Bluefruit.connHandle(), &reply), ); +} + +HAPPairing::HAPPairing(void) + : HAPService(HAP_UUID_SVC_PAIRING), + _setup (HAP_UUID_CHR_PAIR_SETUP , BLE_GATT_CPF_FORMAT_STRUCT), + _verify (HAP_UUID_CHR_PAIR_VERIFY , BLE_GATT_CPF_FORMAT_STRUCT), + _features (HAP_UUID_SVC_PAIR_FEATURE , BLE_GATT_CPF_FORMAT_UINT8 ), + _pairing (HAP_UUID_SVC_PAIR_PAIRING , BLE_GATT_CPF_FORMAT_STRUCT) +{ + varclr(_pair_id); +} + +err_t HAPPairing::begin(void) +{ + VERIFY_STATUS( HAPService::begin() ); // Invoke base class begin() + + _setup.setHapProperties(HAP_CHR_PROPS_READ | HAP_CHR_PROPS_WRITE); + _setup.setHapWriteCallback(_pair_setup_write_cb); + _setup.setMaxLen(200); // FIXME change later + VERIFY_STATUS( _setup.begin() ); + + _verify.setHapProperties(HAP_CHR_PROPS_READ | HAP_CHR_PROPS_WRITE); + _verify.setHapWriteCallback(_pair_verify_write_cb); + _verify.setMaxLen(200); // FIXME change later + VERIFY_STATUS( _verify.begin() ); + + _features.setHapProperties(HAP_CHR_PROPS_READ); + VERIFY_STATUS( _features.begin() ); + // Must be 0x00, 0x01 (support HAP pairing) is for MFi license, iOS will reject pairing attempt without MFi + _features.writeHapValue( (uint32_t) 0x00); + + _pairing.setHapProperties(HAP_CHR_PROPS_SECURE_READ | HAP_CHR_PROPS_SECURE_WRITE); + VERIFY_STATUS( _pairing.begin() ); + + // Make PairID based on MAC address + uint8_t mac[6]; + Bluefruit.Gap.getAddr(mac); + setDeviceID(mac); + + // Init cryptography + if ( !InternalFS.exists("/adafruit/homekit") ) InternalFS.mkdir("/adafruit/homekit"); + + crypto_init(); + + return ERROR_NONE; +} + +void HAPPairing::setDeviceID(uint8_t dev_id[6]) +{ + char str[sizeof(_pair_id) + 1]; + sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X", dev_id[0], dev_id[1], dev_id[2], dev_id[3], dev_id[4], dev_id[5]); + memcpy(_pair_id, str, sizeof(_pair_id)); +} + +void HAPPairing::createSrpResponse(uint16_t conn_hdl, uint8_t status, TLV8_t ktlv[], uint8_t count) +{ + uint16_t srplen = tlv8_encode_calculate_len(ktlv, count); + uint8_t* srpbuf = (uint8_t*) rtos_malloc(srplen); + VERIFY( srpbuf != NULL, ); + + if( srplen == tlv8_encode_n(srpbuf, srplen, ktlv, count) ) + { +#if DEBUG_HAP_PAIRING + LOG_LV2_BUFFER("srpbuf", srpbuf, srplen); +#endif + + TLV8_t tlv = { .type = HAP_PARAM_VALUE, .len = srplen, .value = srpbuf }; + _setup.createHapResponse(conn_hdl, status, &tlv, 1); + } + + rtos_free(srpbuf); +} + +/*------------------------------------------------------------------*/ +/* PAIR SETUP + *------------------------------------------------------------------*/ +void HAPPairing::pair_setup_m1(uint16_t conn_hdl, HAPRequest_t const* hap_req) +{ + // if paired return PAIRING_ERROR_UNAVAILABLE + // tries more than 100 time return PAIRING_ERROR_MAX_TRIES + // pairing with other iOS return PAIRING_ERROR_BUSY + + // step 4 + srp_start(); + + // step 5 : username (I) = "Pair-Setup" + // step 6 : 16 bytes salt already created in srp_init() + // step 7,8 : password (p = setup code) done in srp_init() + // step 9 : public key (B) done in srp_init() + + uint8_t mstate = 2; + + TLV8_t tlv_para[] = + { + { .type = PAIRING_TYPE_STATE , .len = 1 , .value = &mstate }, + { .type = PAIRING_TYPE_PUBLIC_KEY , .len = 384, .value = srp_getB() }, + { .type = PAIRING_TYPE_SALT , .len = 16 , .value = srp_getSalt() }, + }; + + #if DEBUG_HAP_PAIRING + LOG_LV2_BUFFER("SRP State" , tlv_para[0].value, tlv_para[0].len); + LOG_LV2_BUFFER("SRP Pub Key", tlv_para[1].value, tlv_para[1].len); + LOG_LV2_BUFFER("SRP Salt" , tlv_para[2].value, tlv_para[2].len); + #endif + + createSrpResponse(conn_hdl, HAP_STATUS_SUCCESS, tlv_para, arrcount(tlv_para)); +} + +void HAPPairing::pair_setup_m3(uint16_t conn_hdl, HAPRequest_t const* hap_req, TLV8_t pubkey, TLV8_t proof) +{ + uint8_t mstate = 4; + uint8_t pair_error = PAIRING_ERROR_AUTHENTICATION; + + TLV8_t tlv_para[2] = + { + { .type = PAIRING_TYPE_STATE, .len = 1, .value = &mstate }, + { 0 } + }; + + #if DEBUG_HAP_PAIRING + LOG_LV2_BUFFER("SRP State", tlv_para[0].value, tlv_para[0].len); + #endif + + // Set iOS public key + srp_setA( (uint8_t*) pubkey.value, pubkey.len, gatt_reply_now); + + // Check proof + if ( srp_checkM1( (uint8_t*) proof.value, proof.len) ) + { + tlv_para[1].type = PAIRING_TYPE_PROOF; + tlv_para[1].len = 64; + tlv_para[1].value = srp_getM2(); + + #if DEBUG_HAP_PAIRING + LOG_LV2_BUFFER("SRP Proof", tlv_para[1].value, tlv_para[1].len); + #endif + }else + { + tlv_para[1].type = PAIRING_TYPE_ERROR; + tlv_para[1].len = 1; + tlv_para[1].value = &pair_error; + + #if DEBUG_HAP_PAIRING + LOG_LV2_BUFFER("SRP Error", tlv_para[1].value, tlv_para[1].len); + #endif + } + + createSrpResponse(conn_hdl, HAP_STATUS_SUCCESS, tlv_para, arrcount(tlv_para)); +} + +void HAPPairing::pair_setup_m5(uint16_t conn_hdl, HAPRequest_t const* hap_req, TLV8_t encrypted) +{ + uint8_t const pair_error = PAIRING_ERROR_AUTHENTICATION; + uint8_t const mstate = 6; + + TLV8_t tlv_para[2] = + { + { .type = PAIRING_TYPE_STATE, .len = 1, .value = &mstate }, + { 0 } + }; + + bool failed = false; + + /*------------------------------------------------------------------*/ + /* M5 Verification + *------------------------------------------------------------------*/ + uint8_t session_key[64]; + + // Step 0: Create Session Key + crypto_hkdf(session_key, (uint8_t*) "Pair-Setup-Encrypt-Salt", 23, (uint8_t*) "Pair-Setup-Encrypt-Info\001", 24, srp_getK(), 64); + + // Step 1 + 2: Verify Auth Tag and Decrypt using ChaCha20-Poly1305 + if (crypto_verifyAndDecrypt(session_key, (uint8_t*) "PS-Msg05", (uint8_t*)encrypted.value, encrypted.len - 16, (uint8_t*) encrypted.value, ((uint8_t*) encrypted.value) + encrypted.len - 16)) + { + uint16_t blength = encrypted.len - 16; + uint8_t const* buf = (uint8_t const*) encrypted.value; + + uint8_t* client = NULL; + uint8_t* signature = NULL; + uint8_t* ltpk = NULL; + + // Parse iOS's ID, Public Key (ED25519) and Signature + while(blength) + { + TLV8_t tlv = tlv8_decode_next(&buf, &blength); + + LOG_LV2("M5", "type = %s", tlv.type == PAIRING_TYPE_SEPARATOR ? "Separator" : pairing_type_str[tlv.type]); + LOG_LV2_BUFFER(NULL, tlv.value, tlv.len); + + switch(tlv.type) + { + case PAIRING_TYPE_IDENTIFIER: + VERIFY(tlv.len == 36, ); + client = (uint8_t*) tlv.value; + break; + + case PAIRING_TYPE_PUBLIC_KEY: + VERIFY(tlv.len == 32, ); + ltpk = (uint8_t*) tlv.value; + break; + + case PAIRING_TYPE_SIGNATURE: + VERIFY(tlv.len == 64, ); + signature = (uint8_t*) tlv.value; + break; + + default: + failed = true; + break; + } + + // There is no value > 255, there is no need to clean up. Put here for reference only + // tlv8_decode_cleanup(tlv); + } + + if (client && signature && ltpk) + { + // iOSDeviceInfo = iOSDeviceX + iOSDevicePairingID, iOSDeviceLTPK + uint8_t message[64 + 32 + 36 + 32]; + memcpy(message, signature, 64); + + // Step 3: Derive iOSDeviceX + crypto_hkdf(message + 64, (uint8_t*) "Pair-Setup-Controller-Sign-Salt", 31, (uint8_t*) "Pair-Setup-Controller-Sign-Info\001", 32, srp_getK(), 64); + + // Step 4: Construct iOSDeviceInfo + memcpy(message + 64 + 32, client, 36); + memcpy(message + 64 + 32 + 36, ltpk, 32); + + uint8_t result[sizeof(message)]; + uint64_t rlen = 0; + + // Step 5: Verify iOSDeviceInfo with ED25519 + if (crypto_sign_open(result, &rlen, message, sizeof(message), ltpk) < 0) + { + failed = true; + } + else + { + // Step 6: save PairingID and LTPK + memcpy(crypto_keys.client.ltpk, ltpk, sizeof(crypto_keys.client.ltpk)); + memcpy(crypto_keys.client.name, client, 36); + crypto_scheduleStoreKeys(); + + // If failed to save ---> MaxPeers error + } + } + } + else + { + // Error + failed = true; + } + + if (failed) + { + tlv_para[1].type = PAIRING_TYPE_ERROR; + tlv_para[1].len = 1; + tlv_para[1].value = &pair_error; + + createSrpResponse(conn_hdl, HAP_STATUS_SUCCESS, tlv_para, arrcount(tlv_para)); + + return; + } + + /*------------------------------------------------------------------*/ + /* M6 Response Generation + *------------------------------------------------------------------*/ + uint8_t smessage[64 + 32 + sizeof(_pair_id) + 32]; + + // Step 2: derive AccessoryX using HKDF_SHA512 + crypto_hkdf(smessage + 64, (uint8_t*) "Pair-Setup-Accessory-Sign-Salt", 30, (uint8_t*) "Pair-Setup-Accessory-Sign-Info\001", 31, srp_getK(), 64); + + // Step 3: Concat AccessoryX + PairingID + AccessoryLTPK + memcpy(smessage + 64 + 32, _pair_id, sizeof(_pair_id)); + memcpy(smessage + 64 + 32 + sizeof(_pair_id), crypto_keys.sign.pub, sizeof(crypto_keys.sign.pub)); + + // Step 4: Generate AccessorySignature with Ed25519 + uint64_t slen = 0; + crypto_sign(smessage, &slen, smessage + 64, sizeof(smessage) - 64, crypto_keys.sign.secret); + + // Step 5: Construct sub-tlv + TLV8_t ktlv[] = + { + { .type = PAIRING_TYPE_IDENTIFIER, .len = sizeof(_pair_id), .value = _pair_id }, + { .type = PAIRING_TYPE_PUBLIC_KEY, .len = 32, .value = crypto_keys.sign.pub }, + { .type = PAIRING_TYPE_SIGNATURE , .len = 64, .value = smessage } + }; + + uint16_t const lbuffer = tlv8_encode_calculate_len(ktlv, arrcount(ktlv)); + uint8_t* buffer = (uint8_t*) rtos_malloc(lbuffer + 16); // Additional 16 byte for Auth Tag + VERIFY( buffer != NULL, ); + + tlv8_encode_n(buffer, lbuffer, ktlv, arrcount(ktlv)); + + // Step 6: Encrypt above sub-tlv and generate 16-byte auth tag. + crypto_encryptAndSeal(session_key, (uint8_t*) "PS-Msg06", buffer, lbuffer, buffer, buffer + lbuffer); + + tlv_para[1].type = PAIRING_TYPE_ENCRYPTED_DATA; + tlv_para[1].len = lbuffer+16; + tlv_para[1].value = buffer; + + createSrpResponse(conn_hdl, HAP_STATUS_SUCCESS, tlv_para, arrcount(tlv_para)); + + rtos_free(buffer); +} + +void _pair_setup_write_cb (uint16_t conn_hdl, HAPCharacteristic* chr, HAPRequest_t const* hap_req) +{ + uint16_t body_len = hap_req->body_len; + uint8_t const* body_data = hap_req->body_data; + + // Parse TLV data + while (body_len) + { + TLV8_t tlv = tlv8_decode_next(&body_data, &body_len); + + LOG_LV2_BUFFER("Decoded HAP", tlv.value, tlv.len); + + // ignore HAP_PARAM_RETURN_RESP, it should always been 1 for pair setup sequence + if (HAP_PARAM_VALUE == tlv.type) + { + uint8_t mstate = 0; + + // M1 parameters + uint8_t method = 0; + + // M3 parameters + TLV8_t ipubkey = { 0 }; // (A ) 384 bytes + TLV8_t iproof = { 0 }; // (M1) 64 bytes + TLV8_t iencrypted = { 0 }; // Encrypted data + + /*------------- Parse sub TLV (kTLV) data -------------*/ + uint8_t const* param_val = (uint8_t const*) tlv.value; + uint16_t param_len = tlv.len; + while(param_len) + { + TLV8_t ktlv = tlv8_decode_next(¶m_val, ¶m_len); + + LOG_LV2("Pair-Setup", "type = %s", ktlv.type == PAIRING_TYPE_SEPARATOR ? "Separator" : pairing_type_str[ktlv.type]); + LOG_LV2_BUFFER(NULL, ktlv.value, ktlv.len); + + switch (ktlv.type) + { + case PAIRING_TYPE_METHOD: + memcpy(&method, ktlv.value, 1); + LOG_LV2("HAP", "Method %s", pairing_method_str[method]); + break; + + // TODO multiple pairing support + case PAIRING_TYPE_STATE: + memcpy(&mstate, ktlv.value, 1); + LOG_LV2("HAP", "State = M%d", mstate); + break; + + case PAIRING_TYPE_PUBLIC_KEY: + ipubkey = ktlv; + break; + + case PAIRING_TYPE_PROOF: + iproof = ktlv; + break; + + case PAIRING_TYPE_ENCRYPTED_DATA: + iencrypted = ktlv; + break; + + // ignore other type and clean up + default: + tlv8_decode_cleanup(ktlv); + break; + } + + // Purposely skip tlv8_decode_cleanup() here, will call it later after processing + } + + /*------------- Processing setup sequence -------------*/ + HAPPairing& svc = (HAPPairing&) chr->parentService(); + switch (mstate) + { + case 1: + svc.pair_setup_m1(conn_hdl, hap_req); + break; + + case 3: + svc.pair_setup_m3(conn_hdl, hap_req, ipubkey, iproof); + + tlv8_decode_cleanup(ipubkey); + tlv8_decode_cleanup(iproof); + break; + + case 5: + + svc.pair_setup_m5(conn_hdl, hap_req, iencrypted); + + tlv8_decode_cleanup(iencrypted); + break; + + default: break; + } + } + + tlv8_decode_cleanup(tlv); + } +} + +/*------------------------------------------------------------------*/ +/* PAIR VERIFY + *------------------------------------------------------------------*/ +void _pair_verify_write_cb (uint16_t conn_hdl, HAPCharacteristic* chr, HAPRequest_t const* hap_req) +{ + uint16_t body_len = hap_req->body_len; + uint8_t const* body_data = hap_req->body_data; + + // Parse TLV data + while (body_len) + { + TLV8_t tlv = tlv8_decode_next(&body_data, &body_len); + + LOG_LV2_BUFFER("Decoded HAP", tlv.value, tlv.len); + + // ignore HAP_PARAM_RETURN_RESP, it should always been 1 for pair setup sequence + if (HAP_PARAM_VALUE == tlv.type) + { + uint8_t mstate = 0; + TLV8_t tlvparam = { 0 }; + + /*------------- Parse sub TLV (kTLV) data -------------*/ + uint8_t const* param_val = (uint8_t const*) tlv.value; + uint16_t param_len = tlv.len; + while(param_len) + { + TLV8_t ktlv = tlv8_decode_next(¶m_val, ¶m_len); + + LOG_LV2("Pair-Verify", "type = %s", ktlv.type == PAIRING_TYPE_SEPARATOR ? "Separator" : pairing_type_str[ktlv.type]); + LOG_LV2_BUFFER(NULL, ktlv.value, ktlv.len); + + switch (ktlv.type) + { + case PAIRING_TYPE_STATE: + memcpy(&mstate, ktlv.value, 1); + LOG_LV2("HAP", "State = M%d", mstate); + break; + + case PAIRING_TYPE_PUBLIC_KEY: + tlvparam = ktlv; + break; + + case PAIRING_TYPE_ENCRYPTED_DATA: + tlvparam = ktlv; + break; + + // ignore other type and clean up + default: + tlv8_decode_cleanup(ktlv); + break; + } + + // Purposely skip tlv8_decode_cleanup() here, will call it later after processing + } + + /*------------- Processing VERIFY sequence -------------*/ + HAPPairing& svc = (HAPPairing&) chr->parentService(); + switch (mstate) + { + case 1: + svc.pair_verify_m1(conn_hdl, hap_req, tlvparam); + break; + + case 3: + svc.pair_verify_m3(conn_hdl, hap_req, tlvparam); + break; + + default: break; + } + + tlv8_decode_cleanup(tlvparam); + } + + tlv8_decode_cleanup(tlv); + } +} + +void HAPPairing::pair_verify_m1(uint16_t conn_hdl, HAPRequest_t const* hap_req, TLV8_t pubkey) +{ + +} + +void HAPPairing::pair_verify_m3(uint16_t conn_hdl, HAPRequest_t const* hap_req, TLV8_t encrypted) +{ + +} + diff --git a/arduino/libraries/BLEHomekit/src/service/HAPPairing.h b/arduino/libraries/BLEHomekit/src/service/HAPPairing.h new file mode 100755 index 0000000..d457116 --- /dev/null +++ b/arduino/libraries/BLEHomekit/src/service/HAPPairing.h @@ -0,0 +1,78 @@ +/**************************************************************************/ +/*! + @file HAPPairing.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef HAPPAIRING_H_ +#define HAPPAIRING_H_ + +#include "HAPCharacteristic.h" +#include "HAPService.h" + +class HAPPairing : public HAPService +{ + public: + HAPPairing(void); + virtual err_t begin(void); + + private: + HAPCharacteristic _setup; + HAPCharacteristic _verify; + HAPCharacteristic _features; + HAPCharacteristic _pairing; + + uint8_t _pair_id[17]; // Device ID in string format e.g "aa:bb:cc:dd:ee" + + void setDeviceID(uint8_t dev_id[6]); + + void createSrpResponse(uint16_t conn_hdl, uint8_t status, TLV8_t ktlv[], uint8_t count); + + void pair_setup_m1(uint16_t conn_hdl, HAPRequest_t const* hap_req); + void pair_setup_m3(uint16_t conn_hdl, HAPRequest_t const* hap_req, TLV8_t pubkey, TLV8_t proof); + void pair_setup_m5(uint16_t conn_hdl, HAPRequest_t const* hap_req, TLV8_t encrypted); + + + void pair_verify_m1(uint16_t conn_hdl, HAPRequest_t const* hap_req, TLV8_t pubkey); + void pair_verify_m3(uint16_t conn_hdl, HAPRequest_t const* hap_req, TLV8_t encrypted); + + friend void _pair_setup_write_cb (uint16_t conn_hdl, HAPCharacteristic* chr, HAPRequest_t const* hap_req); + friend void _pair_verify_write_cb (uint16_t conn_hdl, HAPCharacteristic* chr, HAPRequest_t const* hap_req); + +#if CFG_DEBUG + friend void test_homekit(void); +#endif +}; + + + +#endif /* HAPPAIRING_H_ */ diff --git a/arduino/libraries/BLEHomekit/src/service/HAPProtocol.cpp b/arduino/libraries/BLEHomekit/src/service/HAPProtocol.cpp new file mode 100755 index 0000000..4decfac --- /dev/null +++ b/arduino/libraries/BLEHomekit/src/service/HAPProtocol.cpp @@ -0,0 +1,59 @@ +/**************************************************************************/ +/*! + @file HAPProtocol.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include <bluefruit.h> +#include "HAPUuid.h" +#include "HAPProtocol.h" + +HAPProtocol::HAPProtocol(void) + : HAPService(HAP_UUID_SVC_PROTOCOL_INFO), _version(HAP_UUID_CHR_VERSION, BLE_GATT_CPF_FORMAT_UTF8S) +{ + +} + +err_t HAPProtocol::begin(void) +{ + VERIFY_STATUS( HAPService::begin() ); // Invoke base class begin() + + _version.setHapProperties(HAP_CHR_PROPS_SECURE_READ); +// _version.setFixedLen(strlen(HOMEKIT_PROTOCOL_VERSION_STR)); + + VERIFY_STATUS( _version.begin() ); +// _version.write(HOMEKIT_PROTOCOL_VERSION_STR); + + return ERROR_NONE; +} + diff --git a/arduino/libraries/BLEHomekit/src/service/HAPProtocol.h b/arduino/libraries/BLEHomekit/src/service/HAPProtocol.h new file mode 100755 index 0000000..28230b2 --- /dev/null +++ b/arduino/libraries/BLEHomekit/src/service/HAPProtocol.h @@ -0,0 +1,56 @@ +/**************************************************************************/ +/*! + @file HAPProtocol.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef HAPPROTOCOL_H_ +#define HAPPROTOCOL_H_ + +#include "HAPCharacteristic.h" +#include "HAPService.h" + +#define HOMEKIT_PROTOCOL_VERSION_STR "02.01.00" + +class HAPProtocol : public HAPService +{ + public: + HAPProtocol(void); + virtual err_t begin(void); + + private: + HAPCharacteristic _version; +}; + + + +#endif /* HAPPROTOCOL_H_ */ |