Starting to integrate new TLV8 into postPairVerify
This commit is contained in:
parent
aa700f94f1
commit
1587f56626
174
src/HAP.cpp
174
src/HAP.cpp
|
|
@ -224,9 +224,12 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,9 +237,12 @@ 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");
|
||||||
|
|
||||||
postPairVerifyURL(); // process URL
|
postPairVerifyURL(); // process URL
|
||||||
|
tlv8_new.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,9 +250,12 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -649,153 +658,145 @@ int HAPClient::postPairVerifyURL(){
|
||||||
LOG2(client.remoteIP());
|
LOG2(client.remoteIP());
|
||||||
LOG2(")...");
|
LOG2(")...");
|
||||||
|
|
||||||
char buf[64];
|
auto itState=tlv8_new.find(kTLVType_State);
|
||||||
|
|
||||||
int tlvState=tlv8.val(kTLVType_State);
|
if(itState==tlv8_new.end()){ // missing STATE TLV
|
||||||
|
|
||||||
if(tlvState==-1){ // 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tlvState=(*itState)[0];
|
||||||
|
|
||||||
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");
|
||||||
tlv8.clear(); // clear TLV records
|
tlv8_new.clear(); // clear TLV records
|
||||||
tlv8.val(kTLVType_State,tlvState+1); // set response STATE to requested state+1 (which should match the state that was expected by the controller)
|
tlv8_new.add(kTLVType_State,tlvState+1); // set response STATE to requested state+1 (which should match the state that was expected by the controller)
|
||||||
tlv8.val(kTLVType_Error,tagError_Unknown); // set Error=Unknown
|
tlv8_new.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown
|
||||||
tlvRespond(); // send response to client
|
tlvRespond(); // send response to client
|
||||||
return(0);
|
return(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
sprintf(buf,"Found <M%d>\n",tlvState); // unlike pair-setup, out-of-sequencing can be handled gracefully for pair-verify (HAP requirement). No need to keep track of pairStatus
|
LOG2("Found <M%d>\n",tlvState); // unlike pair-setup, out-of-sequencing can be handled gracefully for pair-verify (HAP requirement). No need to keep track of pairStatus
|
||||||
LOG2(buf);
|
|
||||||
|
|
||||||
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'
|
||||||
|
|
||||||
if(!tlv8.len(kTLVType_PublicKey)){
|
auto itPublicKey=tlv8_new.find(kTLVType_PublicKey);
|
||||||
|
|
||||||
|
if(itPublicKey==tlv8_new.end() || (*itPublicKey).len!=32){
|
||||||
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");
|
||||||
tlv8.clear(); // clear TLV records
|
tlv8_new.clear(); // clear TLV records
|
||||||
tlv8.val(kTLVType_State,pairState_M2); // set State=<M2>
|
tlv8_new.add(kTLVType_State,pairState_M2); // set State=<M2>
|
||||||
tlv8.val(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
|
tlv8_new.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
|
||||||
tlvRespond(); // send response to client
|
tlvRespond(); // send response to client
|
||||||
return(0);
|
return(0);
|
||||||
|
}
|
||||||
} else {
|
|
||||||
|
|
||||||
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,tlv8.buf(kTLVType_PublicKey),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)
|
||||||
|
|
||||||
uint8_t *accessoryPairingID = accessory.ID; // set accessoryPairingID
|
TempBuffer<uint8_t> accessoryInfo(81);
|
||||||
const size_t accessoryPairingIDLen = 17;
|
|
||||||
|
|
||||||
const size_t accessoryInfoLen=32+accessoryPairingIDLen+32; // total size of accessoryInfo
|
|
||||||
uint8_t accessoryInfo[accessoryInfoLen];
|
|
||||||
|
|
||||||
memcpy(accessoryInfo,publicCurveKey,32); // accessoryInfo = Accessory's Curve25519 public key
|
memcpy(accessoryInfo,publicCurveKey,32); // accessoryInfo = Accessory's Curve25519 public key
|
||||||
memcpy(accessoryInfo+32,accessoryPairingID,accessoryPairingIDLen); // +accessoryPairingID
|
memcpy(accessoryInfo+32,accessory.ID,17); // +accessoryPairingID
|
||||||
memcpy(accessoryInfo+32+accessoryPairingIDLen,iosCurveKey,32); // +Controller's Curve25519 public key
|
memcpy(accessoryInfo+49,iosCurveKey,32); // +Controller's Curve25519 public key
|
||||||
|
|
||||||
tlv8.clear(); // clear existing TLV records
|
tlv8_new.clear();
|
||||||
|
|
||||||
crypto_sign_detached(tlv8.buf(kTLVType_Signature,64),NULL,accessoryInfo,accessoryInfoLen,accessory.LTSK); // produce signature of accessoryInfo using AccessoryLTSK (Ed25519 long-term secret key)
|
auto itSignature=tlv8_new.add(kTLVType_Signature,64,NULL); //create blank Signature TLV with space for 64 bytes
|
||||||
|
|
||||||
tlv8.buf(kTLVType_Identifier,accessoryPairingID,accessoryPairingIDLen); // set Identifier TLV record as accessoryPairingID
|
crypto_sign_detached(*itSignature,NULL,accessoryInfo,accessoryInfo.len(),accessory.LTSK); // produce Signature of accessoryInfo using AccessoryLTSK (Ed25519 long-term secret key)
|
||||||
|
|
||||||
|
tlv8_new.add(kTLVType_Identifier,17,accessory.ID); // set Identifier TLV record as accessoryPairingID
|
||||||
|
|
||||||
LOG2("------- ENCRYPTING SUB-TLVS -------\n");
|
LOG2("------- ENCRYPTING SUB-TLVS -------\n");
|
||||||
|
|
||||||
tlv8.print(2);
|
tlv8_new.print();
|
||||||
|
|
||||||
size_t subTLVLen=tlv8.pack(NULL); // get size of buffer needed to store sub-TLV
|
TempBuffer<uint8_t> subTLV(tlv8_new.pack_size()); // create sub-TLV by packing Identifier and Signature TLV records together
|
||||||
uint8_t subTLV[subTLVLen];
|
tlv8_new.pack(subTLV);
|
||||||
subTLVLen=tlv8.pack(subTLV); // create sub-TLV by packing Identifier and Signature TLV records together
|
|
||||||
|
|
||||||
tlv8.clear(); // clear existing TLV records
|
tlv8_new.clear();
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
unsigned long long edLen;
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
crypto_aead_chacha20poly1305_ietf_encrypt(tlv8.buf(kTLVType_EncryptedData),&edLen,subTLV,subTLVLen,NULL,0,NULL,(unsigned char *)"\x00\x00\x00\x00PV-Msg02",sessionKey);
|
auto itEncryptedData=tlv8_new.add(kTLVType_EncryptedData,subTLV.len()+crypto_aead_chacha20poly1305_IETF_ABYTES,NULL); //create blank EncryptedData TLV with space for subTLV + Authentication Tag
|
||||||
|
|
||||||
|
crypto_aead_chacha20poly1305_ietf_encrypt(*itEncryptedData,NULL,subTLV,subTLV.len(),NULL,0,NULL,(unsigned char *)"\x00\x00\x00\x00PV-Msg02",sessionKey);
|
||||||
|
|
||||||
LOG2("---------- END SUB-TLVS! ----------\n");
|
LOG2("---------- END SUB-TLVS! ----------\n");
|
||||||
|
|
||||||
tlv8.buf(kTLVType_EncryptedData,edLen); // set length of EncryptedData TLV record, which should now include the Authentication Tag at the end as required by HAP
|
tlv8_new.add(kTLVType_State,pairState_M2); // set State=<M2>
|
||||||
tlv8.val(kTLVType_State,pairState_M2); // set State=<M2>
|
tlv8_new.add(kTLVType_PublicKey,32,publicCurveKey); // set PublicKey to Accessory's Curve25519 public key
|
||||||
tlv8.buf(kTLVType_PublicKey,publicCurveKey,32); // set PublicKey to Accessory's Curve25519 public key
|
|
||||||
|
|
||||||
tlvRespond(); // send response to client
|
tlvRespond(); // send response to client
|
||||||
return(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pairState_M3: // 'Verify Finish Request'
|
case pairState_M3:{ // 'Verify Finish Request'
|
||||||
|
|
||||||
if(!tlv8.len(kTLVType_EncryptedData)){
|
auto itEncryptedData=tlv8_new.find(kTLVType_EncryptedData);
|
||||||
|
|
||||||
|
if(itEncryptedData==tlv8_new.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");
|
||||||
tlv8.clear(); // clear TLV records
|
tlv8_new.clear(); // clear TLV records
|
||||||
tlv8.val(kTLVType_State,pairState_M4); // set State=<M4>
|
tlv8_new.add(kTLVType_State,pairState_M4); // set State=<M4>
|
||||||
tlv8.val(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
|
tlv8_new.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
|
||||||
tlvRespond(); // send response to client
|
tlvRespond(); // send response to client
|
||||||
return(0);
|
return(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
TempBuffer<uint8_t> decrypted(tlv8.len(kTLVType_EncryptedData)); // temporary storage for decrypted data
|
TempBuffer<uint8_t> decrypted((*itEncryptedData).len-crypto_aead_chacha20poly1305_IETF_ABYTES); // temporary storage for decrypted data
|
||||||
unsigned long long decryptedLen; // length (in bytes) of decrypted data
|
|
||||||
|
|
||||||
if(crypto_aead_chacha20poly1305_ietf_decrypt( // use SessionKey to decrypt encrypytedData TLV with padded nonce="PV-Msg03"
|
if(crypto_aead_chacha20poly1305_ietf_decrypt( // use SessionKey to decrypt encrypytedData TLV with padded nonce="PV-Msg03"
|
||||||
decrypted, &decryptedLen, NULL,
|
decrypted, NULL, NULL,
|
||||||
tlv8.buf(kTLVType_EncryptedData), tlv8.len(kTLVType_EncryptedData), NULL, 0,
|
(*itEncryptedData).val.get(), (*itEncryptedData).len, NULL, 0,
|
||||||
(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");
|
||||||
tlv8.clear(); // clear TLV records
|
tlv8_new.clear(); // clear TLV records
|
||||||
tlv8.val(kTLVType_State,pairState_M4); // set State=<M4>
|
tlv8_new.add(kTLVType_State,pairState_M4); // set State=<M4>
|
||||||
tlv8.val(kTLVType_Error,tagError_Authentication); // set Error=Authentication
|
tlv8_new.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication
|
||||||
tlvRespond(); // send response to client
|
tlvRespond(); // send response to client
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!tlv8.unpack(decrypted,decryptedLen)){
|
tlv8_new.clear();
|
||||||
LOG0("\n*** ERROR: Can't parse decrypted data into separate TLV records\n\n");
|
tlv8_new.unpack(decrypted,decrypted.len());
|
||||||
tlv8.clear(); // clear TLV records
|
|
||||||
tlv8.val(kTLVType_State,pairState_M4); // set State=<M4>
|
|
||||||
tlv8.val(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
|
|
||||||
tlvRespond(); // send response to client
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
tlv8.print(2); // print decrypted TLV data
|
tlv8_new.print(); // print decrypted TLV data
|
||||||
LOG2("------- END DECRYPTED TLVS! -------\n");
|
LOG2("------- END DECRYPTED TLVS! -------\n");
|
||||||
|
|
||||||
if(!tlv8.len(kTLVType_Identifier) || !tlv8.len(kTLVType_Signature)){
|
auto itIdentifier=tlv8_new.find(kTLVType_Identifier);
|
||||||
|
auto itSignature=tlv8_new.find(kTLVType_Signature);
|
||||||
|
|
||||||
|
if(itIdentifier==tlv8_new.end() || (*itIdentifier).len!=36 || itSignature==tlv8_new.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");
|
||||||
tlv8.clear(); // clear TLV records
|
tlv8_new.clear(); // clear TLV records
|
||||||
tlv8.val(kTLVType_State,pairState_M4); // set State=<M4>
|
tlv8_new.add(kTLVType_State,pairState_M4); // set State=<M4>
|
||||||
tlv8.val(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
|
tlv8_new.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
|
||||||
tlvRespond(); // send response to client
|
tlvRespond(); // send response to client
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller *tPair; // temporary pointer to Controller
|
Controller *tPair; // temporary pointer to Controller
|
||||||
|
|
||||||
if(!(tPair=findController(tlv8.buf(kTLVType_Identifier)))){
|
if(!(tPair=findController((*itIdentifier).val.get()))){
|
||||||
LOG0("\n*** ERROR: Unrecognized Controller ID: ");
|
LOG0("\n*** ERROR: Unrecognized Controller ID: ");
|
||||||
charPrintRow(tlv8.buf(kTLVType_Identifier),36,2);
|
charPrintRow((*itIdentifier).val.get(),36,2);
|
||||||
LOG0("\n\n");
|
LOG0("\n\n");
|
||||||
tlv8.clear(); // clear TLV records
|
tlv8_new.clear(); // clear TLV records
|
||||||
tlv8.val(kTLVType_State,pairState_M4); // set State=<M4>
|
tlv8_new.add(kTLVType_State,pairState_M4); // set State=<M4>
|
||||||
tlv8.val(kTLVType_Error,tagError_Authentication); // set Error=Authentication
|
tlv8_new.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication
|
||||||
tlvRespond(); // send response to client
|
tlvRespond(); // send response to client
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
@ -804,24 +805,23 @@ int HAPClient::postPairVerifyURL(){
|
||||||
charPrintRow(tPair->ID,36,2);
|
charPrintRow(tPair->ID,36,2);
|
||||||
LOG2("...\n");
|
LOG2("...\n");
|
||||||
|
|
||||||
const size_t iosDeviceInfoLen=32+36+32;
|
TempBuffer<uint8_t> iosDeviceInfo(100);
|
||||||
uint8_t iosDeviceInfo[iosDeviceInfoLen];
|
|
||||||
|
|
||||||
memcpy(iosDeviceInfo,iosCurveKey,32);
|
memcpy(iosDeviceInfo,iosCurveKey,32);
|
||||||
memcpy(iosDeviceInfo+32,tPair->ID,36);
|
memcpy(iosDeviceInfo+32,tPair->ID,36);
|
||||||
memcpy(iosDeviceInfo+32+36,publicCurveKey,32);
|
memcpy(iosDeviceInfo+68,publicCurveKey,32);
|
||||||
|
|
||||||
if(crypto_sign_verify_detached(tlv8.buf(kTLVType_Signature), iosDeviceInfo, iosDeviceInfoLen, 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");
|
||||||
tlv8.clear(); // clear TLV records
|
tlv8_new.clear(); // clear TLV records
|
||||||
tlv8.val(kTLVType_State,pairState_M4); // set State=<M4>
|
tlv8_new.add(kTLVType_State,pairState_M4); // set State=<M4>
|
||||||
tlv8.val(kTLVType_Error,tagError_Authentication); // set Error=Authentication
|
tlv8_new.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication
|
||||||
tlvRespond(); // send response to client
|
tlvRespond(); // send response to client
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
tlv8.clear(); // clear TLV records
|
tlv8_new.clear(); // clear TLV records
|
||||||
tlv8.val(kTLVType_State,pairState_M4); // set State=<M4>
|
tlv8_new.add(kTLVType_State,pairState_M4); // set State=<M4>
|
||||||
tlvRespond(); // send response to client (unencrypted since cPair=NULL)
|
tlvRespond(); // 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
|
||||||
|
|
@ -833,8 +833,7 @@ int HAPClient::postPairVerifyURL(){
|
||||||
c2aNonce.zero();
|
c2aNonce.zero();
|
||||||
|
|
||||||
LOG2("\n*** SESSION VERIFICATION COMPLETE *** \n");
|
LOG2("\n*** SESSION VERIFICATION COMPLETE *** \n");
|
||||||
return(1);
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} // switch
|
} // switch
|
||||||
|
|
@ -1401,8 +1400,11 @@ void HAPClient::eventNotify(SpanBuf *pObj, int nObj, int ignoreClient){
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -1411,7 +1413,7 @@ void HAPClient::tlvRespond(){
|
||||||
LOG2(client.remoteIP());
|
LOG2(client.remoteIP());
|
||||||
LOG2(" >>>>>>>>>>\n");
|
LOG2(" >>>>>>>>>>\n");
|
||||||
LOG2(body);
|
LOG2(body);
|
||||||
tlv8.print(2);
|
tlv8_new.print();
|
||||||
|
|
||||||
if(!cPair){ // unverified, unencrypted session
|
if(!cPair){ // unverified, unencrypted session
|
||||||
client.print(body);
|
client.print(body);
|
||||||
|
|
@ -1477,7 +1479,7 @@ void HAPClient::sendEncrypted(char *body, uint8_t *dataBuf, int dataLen){
|
||||||
if(maxFrameSize>FRAME_SIZE) // cap maxFrameSize by FRAME_SIZE (HAP restriction)
|
if(maxFrameSize>FRAME_SIZE) // cap maxFrameSize by FRAME_SIZE (HAP restriction)
|
||||||
maxFrameSize=FRAME_SIZE;
|
maxFrameSize=FRAME_SIZE;
|
||||||
|
|
||||||
TempBuffer<uint8_t> tBuf(2+maxFrameSize+16); // 2-byte AAD + encrytped data + 16-byte authentication tag
|
TempBuffer<uint8_t> tBuf(2+maxFrameSize+16); // 2-byte AAD + encrypted data + 16-byte authentication tag
|
||||||
|
|
||||||
tBuf[0]=bodyLen%256; // store number of bytes in first frame that encrypts the Body (AAD bytes)
|
tBuf[0]=bodyLen%256; // store number of bytes in first frame that encrypts the Body (AAD bytes)
|
||||||
tBuf[1]=bodyLen/256;
|
tBuf[1]=bodyLen/256;
|
||||||
|
|
@ -1744,7 +1746,7 @@ 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};
|
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;
|
||||||
|
|
|
||||||
24
src/HAP.h
24
src/HAP.h
|
|
@ -37,17 +37,17 @@
|
||||||
#include "TLV8.h"
|
#include "TLV8.h"
|
||||||
|
|
||||||
const TLV8_names tlvNames[] = {
|
const TLV8_names tlvNames[] = {
|
||||||
{kTLVType_Separator,"SEPARATOR"},
|
{kTLVType_Separator,"*SEPARATOR"},
|
||||||
{kTLVType_State,"STATE"},
|
{kTLVType_State,"*STATE"},
|
||||||
{kTLVType_PublicKey,"PUBKEY"},
|
{kTLVType_PublicKey,"*PUBKEY"},
|
||||||
{kTLVType_Method,"METHOD"},
|
{kTLVType_Method,"*METHOD"},
|
||||||
{kTLVType_Salt,"SALT"},
|
{kTLVType_Salt,"*SALT"},
|
||||||
{kTLVType_Error,"ERROR"},
|
{kTLVType_Error,"*ERROR"},
|
||||||
{kTLVType_Proof,"PROOF"},
|
{kTLVType_Proof,"*PROOF"},
|
||||||
{kTLVType_EncryptedData,"ENC.DATA"},
|
{kTLVType_EncryptedData,"*ENC.DATA"},
|
||||||
{kTLVType_Signature,"SIGNATURE"},
|
{kTLVType_Signature,"*SIGNATURE"},
|
||||||
{kTLVType_Identifier,"IDENTIFIER"},
|
{kTLVType_Identifier,"*IDENTIFIER"},
|
||||||
{kTLVType_Permissions,"PERMISSION"}
|
{kTLVType_Permissions,"*PERMISSION"}
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
|
|
@ -121,7 +121,7 @@ struct HAPClient {
|
||||||
// These keys are generated in the first call to pair-verify and used in the second call to pair-verify so must persist for a short period
|
// These keys are generated in the first call to pair-verify and used in the second call to pair-verify so must persist for a short period
|
||||||
|
|
||||||
uint8_t publicCurveKey[32]; // public key for Curve25519 encryption
|
uint8_t publicCurveKey[32]; // public key for Curve25519 encryption
|
||||||
uint8_t sharedCurveKey[32]; // Pair-Verfied Shared Secret key derived from Accessory's epehmeral secretCurveKey and Controller's iosCurveKey
|
uint8_t sharedCurveKey[32]; // Pair-Verfied Shared Secret key derived from Accessory's ephemeral secretCurveKey and Controller's iosCurveKey
|
||||||
uint8_t sessionKey[32]; // shared Session Key (derived with various HKDF calls)
|
uint8_t sessionKey[32]; // shared Session Key (derived with various HKDF calls)
|
||||||
uint8_t iosCurveKey[32]; // Curve25519 public key for associated paired controller
|
uint8_t iosCurveKey[32]; // Curve25519 public key for associated paired controller
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,14 @@
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
|
|
||||||
void TLV8::add(uint8_t tag, size_t len, const uint8_t* val){
|
TLV8_it TLV8::add(uint8_t tag, size_t len, const uint8_t* val){
|
||||||
|
|
||||||
if(!empty() && back().tag==tag)
|
if(!empty() && back().tag==tag)
|
||||||
back().update(len,val);
|
back().update(len,val);
|
||||||
else
|
else
|
||||||
emplace_back(tag,len,val);
|
emplace_back(tag,len,val);
|
||||||
|
|
||||||
|
return(end()-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
|
|
@ -165,7 +167,7 @@ const char *TLV8::getName(uint8_t tag){
|
||||||
if(names==NULL)
|
if(names==NULL)
|
||||||
return(NULL);
|
return(NULL);
|
||||||
|
|
||||||
for(int i=0;i<sizeof(names);i++){
|
for(int i=0;i<nNames;i++){
|
||||||
if(names[i].tag==tag)
|
if(names[i].tag==tag)
|
||||||
return(names[i].name);
|
return(names[i].name);
|
||||||
}
|
}
|
||||||
|
|
@ -177,6 +179,9 @@ const char *TLV8::getName(uint8_t tag){
|
||||||
|
|
||||||
void TLV8::print(TLV8_it it1, TLV8_it it2){
|
void TLV8::print(TLV8_it it1, TLV8_it it2){
|
||||||
|
|
||||||
|
if(homeSpan.getLogLevel()<2)
|
||||||
|
return;
|
||||||
|
|
||||||
while(it1!=it2){
|
while(it1!=it2){
|
||||||
const char *name=getName((*it1).tag);
|
const char *name=getName((*it1).tag);
|
||||||
if(name)
|
if(name)
|
||||||
|
|
|
||||||
16
src/TLV8.h
16
src/TLV8.h
|
|
@ -53,6 +53,10 @@ struct tlv8_t {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator uint8_t*() const{
|
||||||
|
return(val.get());
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
|
|
@ -75,15 +79,17 @@ class TLV8 : public vector<tlv8_t, Mallocator<tlv8_t>> {
|
||||||
size_t unpackBytes;
|
size_t unpackBytes;
|
||||||
int unpackPhase;
|
int unpackPhase;
|
||||||
|
|
||||||
const TLV8_names *names;
|
const TLV8_names *names=NULL;
|
||||||
|
int nNames=0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TLV8(const TLV8_names *names=NULL) : names{names}{};
|
TLV8(){};
|
||||||
|
TLV8(const TLV8_names *names, int nNames) : names{names}, nNames{nNames} {};
|
||||||
|
|
||||||
void add(uint8_t tag, size_t len, const uint8_t *val);
|
TLV8_it add(uint8_t tag, size_t len, const uint8_t *val);
|
||||||
void add(uint8_t tag, uint8_t val){add(tag, 1, &val);}
|
TLV8_it add(uint8_t tag, uint8_t val){return(add(tag, 1, &val));}
|
||||||
void add(uint8_t tag){add(tag, 0, NULL);}
|
TLV8_it add(uint8_t tag){return(add(tag, 0, NULL));}
|
||||||
|
|
||||||
TLV8_it find(uint8_t tag, TLV8_it it1, TLV8_it it2);
|
TLV8_it find(uint8_t tag, TLV8_it it1, TLV8_it it2);
|
||||||
TLV8_it find(uint8_t tag, TLV8_it it1){return(find(tag, it1, end()));}
|
TLV8_it find(uint8_t tag, TLV8_it it1){return(find(tag, it1, end()));}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue