added TLV length function

Checks that iterator exists (i.e. does not equal end()) and returns length, else returns -1.  Can be used for checking for both the presence, and length, of a TLV record
This commit is contained in:
Gregg 2023-12-24 15:22:00 -06:00
parent 66e7fc6654
commit edb0cc1be0
2 changed files with 51 additions and 58 deletions

View File

@ -380,7 +380,7 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
auto itState=iosTLV.find(kTLVType_State); auto itState=iosTLV.find(kTLVType_State);
if(itState==iosTLV.end() || (*itState).len!=1){ // missing STATE TLV if(iosTLV.len(itState)!=1){ // missing STATE TLV
LOG0("\n*** ERROR: Missing or invalid <M#> State TLV\n\n"); LOG0("\n*** ERROR: Missing or invalid <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);
@ -413,7 +413,7 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
auto itMethod=iosTLV.find(kTLVType_Method); auto itMethod=iosTLV.find(kTLVType_Method);
if(itMethod==iosTLV.end() || (*itMethod).len!=1 || (*itMethod)[0]!=1){ // error: "Pair Setup" method must always be 0 to indicate setup without MiFi Authentification (HAP Table 5-3) if(iosTLV.len(itMethod)!=1 || (*itMethod)[0]!=1){ // error: "Pair Setup" method must always be 0 to indicate setup without MiFi Authentification (HAP Table 5-3)
LOG0("\n*** ERROR: Pair 'Method' missing or not set to 0\n\n"); LOG0("\n*** ERROR: Pair 'Method' missing or not set to 0\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_Unavailable); // set Error=Unavailable responseTLV.add(kTLVType_Error,tagError_Unavailable); // set Error=Unavailable
@ -441,7 +441,7 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
auto itPublicKey=iosTLV.find(kTLVType_PublicKey); auto itPublicKey=iosTLV.find(kTLVType_PublicKey);
auto itClientProof=iosTLV.find(kTLVType_Proof); auto itClientProof=iosTLV.find(kTLVType_Proof);
if(itPublicKey==iosTLV.end() || (*itPublicKey).len==0 || itClientProof==iosTLV.end() || (*itClientProof).len==0){ if(iosTLV.len(itPublicKey)<=0 || iosTLV.len(itClientProof)<=0){
LOG0("\n*** ERROR: One or both of the required 'PublicKey' and 'Proof' TLV records for this step is bad or missing\n\n"); LOG0("\n*** ERROR: One or both of the required 'PublicKey' and 'Proof' 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)
@ -476,14 +476,15 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
} }
break; break;
case pairState_M5: // 'Exchange Request' case pairState_M5:{ // 'Exchange Request'
if(!tlv8.len(kTLVType_EncryptedData)){ auto itEncryptedData=iosTLV.find(kTLVType_EncryptedData);
if(iosTLV.len(itEncryptedData)<=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 responseTLV.add(kTLVType_State,pairState_M6); // set State=<M6>
tlv8.val(kTLVType_State,pairState_M6); // set State=<M6> responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
tlv8.val(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(); // send response to client
pairStatus=pairState_M1; // reset pairStatus to first step of unpaired pairStatus=pairState_M1; // reset pairStatus to first step of unpaired
return(0); return(0);
}; };
@ -496,44 +497,37 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
// Note the SALT and INFO text fields used by HKDF to create this Session Key are NOT the same as those for creating iosDeviceX. // Note the SALT and INFO text fields used by HKDF to create this Session Key are NOT the same as those for creating iosDeviceX.
// The iosDeviceX HKDF calculations are separate and will be performed further below with the SALT and INFO as specified in the HAP docs. // The iosDeviceX HKDF calculations are separate and will be performed further below with the SALT and INFO as specified in the HAP docs.
hkdf.create(sessionKey, srp.sharedSecret,64,"Pair-Setup-Encrypt-Salt","Pair-Setup-Encrypt-Info"); // create SessionKey hkdf.create(sessionKey,srp.sharedSecret,64,"Pair-Setup-Encrypt-Salt","Pair-Setup-Encrypt-Info"); // create SessionKey
TempBuffer<uint8_t> decrypted(tlv8.len(kTLVType_EncryptedData)); // temporary storage for decrypted data LOG2("------- DECRYPTING SUB-TLVS -------\n");
unsigned long long decryptedLen; // length (in bytes) of decrypted data
if(crypto_aead_chacha20poly1305_ietf_decrypt( // use SessionKey to decrypt encryptedData TLV with padded nonce="PS-Msg05" // use SessionKey to decrypt encryptedData TLV with padded nonce="PS-Msg05"
decrypted, &decryptedLen, NULL,
tlv8.buf(kTLVType_EncryptedData), tlv8.len(kTLVType_EncryptedData), NULL, 0,
(unsigned char *)"\x00\x00\x00\x00PS-Msg05", sessionKey)==-1){
TempBuffer<uint8_t> decrypted((*itEncryptedData).len-crypto_aead_chacha20poly1305_IETF_ABYTES); // temporary storage for decrypted data
if(crypto_aead_chacha20poly1305_ietf_decrypt(decrypted, NULL, NULL, *itEncryptedData, (*itEncryptedData).len, NULL, 0, (unsigned char *)"\x00\x00\x00\x00PS-Msg05", sessionKey)==-1){
LOG0("\n*** ERROR: Exchange-Request Authentication Failed\n\n"); LOG0("\n*** ERROR: Exchange-Request Authentication Failed\n\n");
tlv8.clear(); // clear TLV records responseTLV.add(kTLVType_State,pairState_M6); // set State=<M6>
tlv8.val(kTLVType_State,pairState_M6); // set State=<M6> responseTLV.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication
tlv8.val(kTLVType_Error,tagError_Authentication); // set Error=Authentication tlvRespond(responseTLV); // send response to client
tlvRespond(); // send response to client
pairStatus=pairState_M1; // reset pairStatus to first step of unpaired pairStatus=pairState_M1; // reset pairStatus to first step of unpaired
return(0); return(0);
} }
if(!tlv8.unpack(decrypted,decryptedLen)){ subTLV.unpack(decrypted,decrypted.len()); // unpack TLV
LOG0("\n*** ERROR: Can't parse decrypted data into separate TLV records\n\n"); subTLV.print(); // print decrypted TLV data
tlv8.clear(); // clear TLV records
tlv8.val(kTLVType_State,pairState_M6); // set State=<M6>
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
pairStatus=pairState_M1; // reset pairStatus to first step of unpaired
return(0);
}
tlv8.print(2); // print decrypted TLV data LOG2("---------- END SUB-TLVS! ----------\n");
LOG2("------- END DECRYPTED TLVS! -------\n");
if(!tlv8.len(kTLVType_Identifier) || !tlv8.len(kTLVType_PublicKey) || !tlv8.len(kTLVType_Signature)){ auto itIdentifier=subTLV.find(kTLVType_Identifier);
auto itSignature=subTLV.find(kTLVType_Signature);
auto itPublicKey=subTLV.find(kTLVType_PublicKey);
if(subTLV.len(itIdentifier)!=36 || subTLV.len(itSignature)!=crypto_sign_BYTES || subTLV.len(itPublicKey)<=0){
LOG0("\n*** ERROR: One or more of required 'Identifier,' 'PublicKey,' and 'Signature' TLV records for this step is bad or missing\n\n"); LOG0("\n*** ERROR: One or more of required 'Identifier,' 'PublicKey,' and 'Signature' TLV records for this step is bad or missing\n\n");
tlv8.clear(); // clear TLV records responseTLV.add(kTLVType_State,pairState_M6); // set State=<M6>
tlv8.val(kTLVType_State,pairState_M6); // set State=<M6> responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
tlv8.val(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(); // send response to client
pairStatus=pairState_M1; // reset pairStatus to first step of unpaired pairStatus=pairState_M1; // reset pairStatus to first step of unpaired
return(0); return(0);
}; };
@ -633,7 +627,7 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
homeSpan.pairCallback(true); homeSpan.pairCallback(true);
return(1); return(1);
}
break; break;
} // switch } // switch
@ -658,7 +652,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() || (*itState).len!=1){ // missing STATE TLV if(iosTLV.len(itState)!=1){ // missing STATE TLV
LOG0("\n*** ERROR: Missing or invalid <M#> State TLV\n\n"); LOG0("\n*** ERROR: Missing or invalid <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);
@ -682,7 +676,7 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
auto itPublicKey=iosTLV.find(kTLVType_PublicKey); auto itPublicKey=iosTLV.find(kTLVType_PublicKey);
if(itPublicKey==iosTLV.end() || (*itPublicKey).len!=32){ if(iosTLV.len(itPublicKey)!=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");
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)
@ -737,7 +731,7 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
auto itEncryptedData=iosTLV.find(kTLVType_EncryptedData); auto itEncryptedData=iosTLV.find(kTLVType_EncryptedData);
if(itEncryptedData==iosTLV.end() || (*itEncryptedData).len==0){ if(iosTLV.len(itEncryptedData)<=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)
@ -747,13 +741,11 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
LOG2("------- DECRYPTING SUB-TLVS -------\n"); LOG2("------- DECRYPTING SUB-TLVS -------\n");
// use SessionKey to decrypt encrypytedData TLV with padded nonce="PV-Msg03"
TempBuffer<uint8_t> decrypted((*itEncryptedData).len-crypto_aead_chacha20poly1305_IETF_ABYTES); // temporary storage for decrypted data TempBuffer<uint8_t> decrypted((*itEncryptedData).len-crypto_aead_chacha20poly1305_IETF_ABYTES); // temporary storage for 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(decrypted, NULL, NULL, *itEncryptedData, (*itEncryptedData).len, NULL, 0, (unsigned char *)"\x00\x00\x00\x00PV-Msg03", sessionKey)==-1){
decrypted, NULL, NULL,
(*itEncryptedData).val.get(), (*itEncryptedData).len, NULL, 0,
(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
@ -761,8 +753,7 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
return(0); return(0);
} }
subTLV.unpack(decrypted,decrypted.len()); subTLV.unpack(decrypted,decrypted.len()); // unpack TLV
subTLV.print(); // print decrypted TLV data subTLV.print(); // print decrypted TLV data
LOG2("---------- END SUB-TLVS! ----------\n"); LOG2("---------- END SUB-TLVS! ----------\n");
@ -770,7 +761,7 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
auto itIdentifier=subTLV.find(kTLVType_Identifier); auto itIdentifier=subTLV.find(kTLVType_Identifier);
auto itSignature=subTLV.find(kTLVType_Signature); auto itSignature=subTLV.find(kTLVType_Signature);
if(itIdentifier==subTLV.end() || (*itIdentifier).len!=36 || itSignature==subTLV.end() || (*itSignature).len!=crypto_sign_BYTES){ if(subTLV.len(itIdentifier)!=36 || subTLV.len(itSignature)!=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)
@ -780,9 +771,9 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
Controller *tPair; // temporary pointer to Controller Controller *tPair; // temporary pointer to Controller
if(!(tPair=findController((*itIdentifier).val.get()))){ if(!(tPair=findController(*itIdentifier))){
LOG0("\n*** ERROR: Unrecognized Controller ID: "); LOG0("\n*** ERROR: Unrecognized Controller ID: ");
charPrintRow((*itIdentifier).val.get(),36,2); charPrintRow(*itIdentifier,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
@ -800,7 +791,7 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
memcpy(iosDeviceInfo+32,tPair->ID,36); memcpy(iosDeviceInfo+32,tPair->ID,36);
memcpy(iosDeviceInfo+68,publicCurveKey,32); memcpy(iosDeviceInfo+68,publicCurveKey,32);
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, 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

View File

@ -95,6 +95,8 @@ class TLV8 : public vector<tlv8_t, Mallocator<tlv8_t>> {
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()));}
TLV8_it find(uint8_t tag){return(find(tag, begin(), end()));} TLV8_it find(uint8_t tag){return(find(tag, begin(), end()));}
int len(TLV8_it it){return(it==end()?-1:(*it).len);}
size_t pack_size(TLV8_it it1, TLV8_it it2); size_t pack_size(TLV8_it it1, TLV8_it it2);
size_t pack_size(TLV8_it it1){return(pack_size(it1, it1+1));} size_t pack_size(TLV8_it it1){return(pack_size(it1, it1+1));}
size_t pack_size(){return(pack_size(begin(), end()));} size_t pack_size(){return(pack_size(begin(), end()));}