Preparing for re-factoring postPairSetup

This commit is contained in:
Gregg 2023-12-23 15:59:04 -06:00
parent 6e323976fd
commit fe3389da3b
2 changed files with 43 additions and 55 deletions

View File

@ -224,12 +224,9 @@ void HAPClient::processRequest(){
strstr(body,"Content-Type: application/pairing+tlv8") && // check that content is TLV8 strstr(body,"Content-Type: application/pairing+tlv8") && // check that content is TLV8
tlv8.unpack(content,cLen)){ // read TLV content tlv8.unpack(content,cLen)){ // read TLV content
tlv8.print(2); // print TLV records in form "TAG(INT) LENGTH(INT) VALUES(HEX)" tlv8.print(2); // print TLV records in form "TAG(INT) LENGTH(INT) VALUES(HEX)"
tlv8_new.unpack(content,cLen);
tlv8_new.print();
LOG2("------------ END TLVS! ------------\n"); LOG2("------------ END TLVS! ------------\n");
postPairSetupURL(); // process URL postPairSetupURL(); // process URL
tlv8_new.clear();
return; return;
} }
@ -256,12 +253,9 @@ void HAPClient::processRequest(){
strstr(body,"Content-Type: application/pairing+tlv8") && // check that content is TLV8 strstr(body,"Content-Type: application/pairing+tlv8") && // check that content is TLV8
tlv8.unpack(content,cLen)){ // read TLV content tlv8.unpack(content,cLen)){ // read TLV content
tlv8.print(2); // print TLV records in form "TAG(INT) LENGTH(INT) VALUES(HEX)" tlv8.print(2); // print TLV records in form "TAG(INT) LENGTH(INT) VALUES(HEX)"
tlv8_new.unpack(content,cLen);
tlv8_new.print();
LOG2("------------ END TLVS! ------------\n"); LOG2("------------ END TLVS! ------------\n");
postPairingsURL(); // process URL postPairingsURL(); // process URL
tlv8_new.clear();
return; return;
} }
@ -670,7 +664,7 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
auto itState=iosTLV.find(kTLVType_State); auto itState=iosTLV.find(kTLVType_State);
if(itState==iosTLV.end()){ // missing STATE TLV if(itState==iosTLV.end()){ // missing STATE TLV
LOG0("\n*** ERROR: Missing <M#> State TLV\n\n"); LOG0("\n*** ERROR: Missing <M#> State TLV\n\n");
badRequestError(); // return with 400 error, which closes connection badRequestError(); // return with 400 error, which closes connection
return(0); return(0);
@ -680,9 +674,9 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
if(!nAdminControllers()){ // error: Device not yet paired - we should not be receiving any requests for Pair-Verify! if(!nAdminControllers()){ // error: Device not yet paired - we should not be receiving any requests for Pair-Verify!
LOG0("\n*** ERROR: Device not yet paired!\n\n"); LOG0("\n*** ERROR: Device not yet paired!\n\n");
responseTLV.add(kTLVType_State,tlvState+1); // set response STATE to requested state+1 (which should match the state that was expected by the controller) responseTLV.add(kTLVType_State,tlvState+1); // set response STATE to requested state+1 (which should match the state that was expected by the controller)
responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown
tlvRespond(responseTLV); // send response to client tlvRespond(responseTLV); // send response to client
return(0); return(0);
}; };
@ -690,7 +684,7 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
switch(tlvState){ // Pair-Verify STATE received -- process request! (HAP Section 5.7) switch(tlvState){ // Pair-Verify STATE received -- process request! (HAP Section 5.7)
case pairState_M1:{ // 'Verify Start Request' case pairState_M1:{ // 'Verify Start Request'
auto itPublicKey=iosTLV.find(kTLVType_PublicKey); auto itPublicKey=iosTLV.find(kTLVType_PublicKey);
@ -698,15 +692,14 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
LOG0("\n*** ERROR: Required 'PublicKey' TLV record for this step is bad or missing\n\n"); LOG0("\n*** ERROR: Required 'PublicKey' TLV record for this step is bad or missing\n\n");
responseTLV.add(kTLVType_State,pairState_M2); // set State=<M2> responseTLV.add(kTLVType_State,pairState_M2); // set State=<M2>
responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data) responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
tlvRespond(responseTLV); // send response to client tlvRespond(responseTLV); // send response to client
return(0); return(0);
} }
uint8_t secretCurveKey[32]; // Accessory's secret key for Curve25519 encryption (32 bytes). Ephemeral usage - created below and used only in this block uint8_t secretCurveKey[32]; // Accessory's secret key for Curve25519 encryption (32 bytes). Ephemeral usage - created below and used only in this block
crypto_box_keypair(publicCurveKey,secretCurveKey); // generate Curve25519 public key pair (will persist until end of verification process)
crypto_box_keypair(publicCurveKey,secretCurveKey); // generate Curve25519 public key pair (will persist until end of verification process) memcpy(iosCurveKey,*itPublicKey,32); // save iosCurveKey (will persist until end of verification process)
memcpy(iosCurveKey,*itPublicKey,32); // save iosCurveKey (will persist until end of verification process)
crypto_scalarmult_curve25519(sharedCurveKey,secretCurveKey,iosCurveKey); // generate (and persist) Pair Verify SharedSecret CurveKey from Accessory's Curve25519 secret key and Controller's Curve25519 public key (32 bytes) crypto_scalarmult_curve25519(sharedCurveKey,secretCurveKey,iosCurveKey); // generate (and persist) Pair Verify SharedSecret CurveKey from Accessory's Curve25519 secret key and Controller's Curve25519 public key (32 bytes)
@ -716,11 +709,11 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
memcpy(accessoryInfo+32,accessory.ID,17); // +accessoryPairingID memcpy(accessoryInfo+32,accessory.ID,17); // +accessoryPairingID
memcpy(accessoryInfo+49,iosCurveKey,32); // +Controller's Curve25519 public key memcpy(accessoryInfo+49,iosCurveKey,32); // +Controller's Curve25519 public key
auto itSignature=subTLV.add(kTLVType_Signature,64,NULL); //create blank Signature TLV with space for 64 bytes auto itSignature=subTLV.add(kTLVType_Signature,64,NULL); //create blank Signature TLV with space for 64 bytes
crypto_sign_detached(*itSignature,NULL,accessoryInfo,accessoryInfo.len(),accessory.LTSK); // produce Signature of accessoryInfo using AccessoryLTSK (Ed25519 long-term secret key) crypto_sign_detached(*itSignature,NULL,accessoryInfo,accessoryInfo.len(),accessory.LTSK); // produce Signature of accessoryInfo using AccessoryLTSK (Ed25519 long-term secret key)
subTLV.add(kTLVType_Identifier,17,accessory.ID); // set Identifier TLV record as accessoryPairingID subTLV.add(kTLVType_Identifier,17,accessory.ID); // set Identifier TLV record as accessoryPairingID
LOG2("------- ENCRYPTING SUB-TLVS -------\n"); LOG2("------- ENCRYPTING SUB-TLVS -------\n");
@ -731,9 +724,9 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
// create SessionKey from Curve25519 SharedSecret using HKDF-SHA-512, then encrypt subTLV data with SessionKey using ChaCha20-Poly1305. Output stored in EncryptedData TLV // create SessionKey from Curve25519 SharedSecret using HKDF-SHA-512, then encrypt subTLV data with SessionKey using ChaCha20-Poly1305. Output stored in EncryptedData TLV
hkdf.create(sessionKey,sharedCurveKey,32,"Pair-Verify-Encrypt-Salt","Pair-Verify-Encrypt-Info"); // create SessionKey (32 bytes) hkdf.create(sessionKey,sharedCurveKey,32,"Pair-Verify-Encrypt-Salt","Pair-Verify-Encrypt-Info"); // create SessionKey (32 bytes)
auto itEncryptedData=responseTLV.add(kTLVType_EncryptedData,subPack.len()+crypto_aead_chacha20poly1305_IETF_ABYTES,NULL); //create blank EncryptedData TLV with space for subTLV + Authentication Tag auto itEncryptedData=responseTLV.add(kTLVType_EncryptedData,subPack.len()+crypto_aead_chacha20poly1305_IETF_ABYTES,NULL); //create blank EncryptedData TLV with space for subTLV + Authentication Tag
crypto_aead_chacha20poly1305_ietf_encrypt(*itEncryptedData,NULL,subPack,subPack.len(),NULL,0,NULL,(unsigned char *)"\x00\x00\x00\x00PV-Msg02",sessionKey); crypto_aead_chacha20poly1305_ietf_encrypt(*itEncryptedData,NULL,subPack,subPack.len(),NULL,0,NULL,(unsigned char *)"\x00\x00\x00\x00PV-Msg02",sessionKey);
@ -742,7 +735,7 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
responseTLV.add(kTLVType_State,pairState_M2); // set State=<M2> responseTLV.add(kTLVType_State,pairState_M2); // set State=<M2>
responseTLV.add(kTLVType_PublicKey,32,publicCurveKey); // set PublicKey to Accessory's Curve25519 public key responseTLV.add(kTLVType_PublicKey,32,publicCurveKey); // set PublicKey to Accessory's Curve25519 public key
tlvRespond(responseTLV); // send response to client tlvRespond(responseTLV); // send response to client
} }
break; break;
@ -752,9 +745,9 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
if(itEncryptedData==iosTLV.end() || (*itEncryptedData).len==0){ if(itEncryptedData==iosTLV.end() || (*itEncryptedData).len==0){
LOG0("\n*** ERROR: Required 'EncryptedData' TLV record for this step is bad or missing\n\n"); LOG0("\n*** ERROR: Required 'EncryptedData' TLV record for this step is bad or missing\n\n");
responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4> responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4>
responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data) responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
tlvRespond(responseTLV); // send response to client tlvRespond(responseTLV); // send response to client
return(0); return(0);
}; };
@ -768,9 +761,9 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
(unsigned char *)"\x00\x00\x00\x00PV-Msg03", sessionKey)==-1){ (unsigned char *)"\x00\x00\x00\x00PV-Msg03", sessionKey)==-1){
LOG0("\n*** ERROR: Verify Authentication Failed\n\n"); LOG0("\n*** ERROR: Verify Authentication Failed\n\n");
responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4> responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4>
responseTLV.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication responseTLV.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication
tlvRespond(responseTLV); // send response to client tlvRespond(responseTLV); // send response to client
return(0); return(0);
} }
@ -785,21 +778,21 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
if(itIdentifier==subTLV.end() || (*itIdentifier).len!=36 || itSignature==subTLV.end() || (*itSignature).len!=crypto_sign_BYTES){ if(itIdentifier==subTLV.end() || (*itIdentifier).len!=36 || itSignature==subTLV.end() || (*itSignature).len!=crypto_sign_BYTES){
LOG0("\n*** ERROR: One or more of required 'Identifier,' and 'Signature' TLV records for this step is bad or missing\n\n"); LOG0("\n*** ERROR: One or more of required 'Identifier,' and 'Signature' TLV records for this step is bad or missing\n\n");
responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4> responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4>
responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data) responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
tlvRespond(responseTLV); // send response to client tlvRespond(responseTLV); // send response to client
return(0); return(0);
} }
Controller *tPair; // temporary pointer to Controller Controller *tPair; // temporary pointer to Controller
if(!(tPair=findController((*itIdentifier).val.get()))){ if(!(tPair=findController((*itIdentifier).val.get()))){
LOG0("\n*** ERROR: Unrecognized Controller ID: "); LOG0("\n*** ERROR: Unrecognized Controller ID: ");
charPrintRow((*itIdentifier).val.get(),36,2); charPrintRow((*itIdentifier).val.get(),36,2);
LOG0("\n\n"); LOG0("\n\n");
responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4> responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4>
responseTLV.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication responseTLV.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication
tlvRespond(responseTLV); // send response to client tlvRespond(responseTLV); // send response to client
return(0); return(0);
} }
@ -815,14 +808,14 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
if(crypto_sign_verify_detached((*itSignature).val.get(), iosDeviceInfo, iosDeviceInfo.len(), tPair->LTPK) != 0){ // verify signature of iosDeviceInfo using iosDeviceLTPK if(crypto_sign_verify_detached((*itSignature).val.get(), iosDeviceInfo, iosDeviceInfo.len(), tPair->LTPK) != 0){ // verify signature of iosDeviceInfo using iosDeviceLTPK
LOG0("\n*** ERROR: LPTK Signature Verification Failed\n\n"); LOG0("\n*** ERROR: LPTK Signature Verification Failed\n\n");
responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4> responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4>
responseTLV.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication responseTLV.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication
tlvRespond(responseTLV); // send response to client tlvRespond(responseTLV); // send response to client
return(0); return(0);
} }
responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4> responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4>
tlvRespond(responseTLV); // send response to client (unencrypted since cPair=NULL) tlvRespond(responseTLV); // send response to client (unencrypted since cPair=NULL)
cPair=tPair; // save Controller for this connection slot - connection is now verified and should be encrypted going forward cPair=tPair; // save Controller for this connection slot - connection is now verified and should be encrypted going forward
@ -1426,11 +1419,8 @@ void HAPClient::tlvRespond(TLV8 &tlv8){
void HAPClient::tlvRespond(){ void HAPClient::tlvRespond(){
// TempBuffer<uint8_t> tBuf(tlv8.pack(NULL)); // create buffer to hold TLV data TempBuffer<uint8_t> tBuf(tlv8.pack(NULL)); // create buffer to hold TLV data
// tlv8.pack(tBuf); // pack TLV records into buffer tlv8.pack(tBuf); // pack TLV records into buffer
TempBuffer<uint8_t> tBuf(tlv8_new.pack_size()); // create buffer to hold TLV data
tlv8_new.pack(tBuf); // pack TLV records into buffer
char *body; char *body;
asprintf(&body,"HTTP/1.1 200 OK\r\nContent-Type: application/pairing+tlv8\r\nContent-Length: %d\r\n\r\n",tBuf.len()); // create Body with Content Length = size of TLV data asprintf(&body,"HTTP/1.1 200 OK\r\nContent-Type: application/pairing+tlv8\r\nContent-Length: %d\r\n\r\n",tBuf.len()); // create Body with Content Length = size of TLV data
@ -1439,7 +1429,7 @@ void HAPClient::tlvRespond(){
LOG2(client.remoteIP()); LOG2(client.remoteIP());
LOG2(" >>>>>>>>>>\n"); LOG2(" >>>>>>>>>>\n");
LOG2(body); LOG2(body);
tlv8_new.print(); tlv8.print(2);
if(!cPair){ // unverified, unencrypted session if(!cPair){ // unverified, unencrypted session
client.print(body); client.print(body);
@ -1772,7 +1762,6 @@ void Nonce::inc(){
// instantiate all static HAP Client structures and data // instantiate all static HAP Client structures and data
TLV<kTLVType,11> HAPClient::tlv8; TLV<kTLVType,11> HAPClient::tlv8;
TLV8 HAPClient::tlv8_new{tlvNames,11};
nvs_handle HAPClient::hapNVS; nvs_handle HAPClient::hapNVS;
nvs_handle HAPClient::srpNVS; nvs_handle HAPClient::srpNVS;
HKDF HAPClient::hkdf; HKDF HAPClient::hkdf;

View File

@ -36,7 +36,7 @@
#include "SRP.h" #include "SRP.h"
#include "TLV8.h" #include "TLV8.h"
const TLV8_names tlvNames[] = { const TLV8_names HAP_Names[] = {
{kTLVType_Separator,"*SEPARATOR"}, {kTLVType_Separator,"*SEPARATOR"},
{kTLVType_State,"*STATE"}, {kTLVType_State,"*STATE"},
{kTLVType_PublicKey,"*PUBKEY"}, {kTLVType_PublicKey,"*PUBKEY"},
@ -102,16 +102,15 @@ struct HAPClient {
static const int MAX_CONTROLLERS=16; // maximum number of paired controllers (HAP requires at least 16) static const int MAX_CONTROLLERS=16; // maximum number of paired controllers (HAP requires at least 16)
static const int MAX_ACCESSORIES=150; // maximum number of allowed Accessories (HAP limit=150) static const int MAX_ACCESSORIES=150; // maximum number of allowed Accessories (HAP limit=150)
static TLV<kTLVType,11> tlv8; // TLV8 structure (HAP Section 14.1) with space for 11 TLV records of type kTLVType (HAP Table 5-6) static TLV<kTLVType,11> tlv8; // TLV8 structure (HAP Section 14.1) with space for 11 TLV records of type kTLVType (HAP Table 5-6)
static TLV8 tlv8_new; // TLV8 structure (HAP Section 14.1) with space for 11 TLV records of type kTLVType (HAP Table 5-6) static nvs_handle hapNVS; // handle for non-volatile-storage of HAP data
static nvs_handle hapNVS; // handle for non-volatile-storage of HAP data static nvs_handle srpNVS; // handle for non-volatile-storage of SRP data
static nvs_handle srpNVS; // handle for non-volatile-storage of SRP data static HKDF hkdf; // generates (and stores) HKDF-SHA-512 32-byte keys derived from an inputKey of arbitrary length, a salt string, and an info string
static HKDF hkdf; // generates (and stores) HKDF-SHA-512 32-byte keys derived from an inputKey of arbitrary length, a salt string, and an info string static pairState pairStatus; // tracks pair-setup status
static pairState pairStatus; // tracks pair-setup status static SRP6A srp; // stores all SRP-6A keys used for Pair-Setup
static SRP6A srp; // stores all SRP-6A keys used for Pair-Setup static Accessory accessory; // Accessory ID and Ed25519 public and secret keys- permanently stored
static Accessory accessory; // Accessory ID and Ed25519 public and secret keys- permanently stored static list<Controller, Mallocator<Controller>> controllerList; // linked-list of Paired Controller IDs and ED25519 long-term public keys - permanently stored
static list<Controller, Mallocator<Controller>> controllerList; // linked-list of Paired Controller IDs and ED25519 long-term public keys - permanently stored static int conNum; // connection number - used to keep track of per-connection EV notifications
static int conNum; // connection number - used to keep track of per-connection EV notifications
// individual structures and data defined for each Hap Client connection // individual structures and data defined for each Hap Client connection
@ -155,7 +154,7 @@ struct HAPClient {
// define static methods // define static methods
static void init(); // initialize HAP after start-up static void init(); // initialize HAP after start-up
static void hexPrintColumn(uint8_t *buf, int n, int minLogLevel=0); // prints 'n' bytes of *buf as HEX, one byte per row, subject to specified minimum log level static void hexPrintColumn(uint8_t *buf, int n, int minLogLevel=0); // prints 'n' bytes of *buf as HEX, one byte per row, subject to specified minimum log level
static void hexPrintRow(uint8_t *buf, int n, int minLogLevel=0); // prints 'n' bytes of *buf as HEX, all on one row, subject to specified minimum log level static void hexPrintRow(uint8_t *buf, int n, int minLogLevel=0); // prints 'n' bytes of *buf as HEX, all on one row, subject to specified minimum log level
@ -173,9 +172,9 @@ struct HAPClient {
static void checkTimedWrites(); // checks for expired Timed Write PIDs, and clears any found (HAP Section 6.7.2.4) static void checkTimedWrites(); // checks for expired Timed Write PIDs, and clears any found (HAP Section 6.7.2.4)
static void eventNotify(SpanBuf *pObj, int nObj, int ignoreClient=-1); // transmits EVENT Notifications for nObj SpanBuf objects, pObj, with optional flag to ignore a specific client static void eventNotify(SpanBuf *pObj, int nObj, int ignoreClient=-1); // transmits EVENT Notifications for nObj SpanBuf objects, pObj, with optional flag to ignore a specific client
class HAPTLV : public TLV8 { class HAPTLV : public TLV8 { // dedicated class for HAP TLV8 records
public: public:
HAPTLV() : TLV8(tlvNames,11){} HAPTLV() : TLV8(HAP_Names,11){}
}; };
}; };