Completed and fully tested refactoring of TLV8
Next up: remove old TLV code and clean up
This commit is contained in:
parent
76a6a2bde9
commit
3c172da714
302
src/HAP.cpp
302
src/HAP.cpp
|
|
@ -112,17 +112,17 @@ void HAPClient::init(){
|
||||||
|
|
||||||
printControllers();
|
printControllers();
|
||||||
|
|
||||||
tlv8.create(kTLVType_Separator,0,"SEPARATOR"); // define the actual TLV records needed for the implementation of HAP; one for each kTLVType needed (HAP Table 5-6)
|
// tlv8.create(kTLVType_Separator,0,"SEPARATOR"); // define the actual TLV records needed for the implementation of HAP; one for each kTLVType needed (HAP Table 5-6)
|
||||||
tlv8.create(kTLVType_State,1,"STATE");
|
// tlv8.create(kTLVType_State,1,"STATE");
|
||||||
tlv8.create(kTLVType_PublicKey,384,"PUBKEY");
|
// tlv8.create(kTLVType_PublicKey,384,"PUBKEY");
|
||||||
tlv8.create(kTLVType_Method,1,"METHOD");
|
// tlv8.create(kTLVType_Method,1,"METHOD");
|
||||||
tlv8.create(kTLVType_Salt,16,"SALT");
|
// tlv8.create(kTLVType_Salt,16,"SALT");
|
||||||
tlv8.create(kTLVType_Error,1,"ERROR");
|
// tlv8.create(kTLVType_Error,1,"ERROR");
|
||||||
tlv8.create(kTLVType_Proof,64,"PROOF");
|
// tlv8.create(kTLVType_Proof,64,"PROOF");
|
||||||
tlv8.create(kTLVType_EncryptedData,1024,"ENC.DATA");
|
// tlv8.create(kTLVType_EncryptedData,1024,"ENC.DATA");
|
||||||
tlv8.create(kTLVType_Signature,64,"SIGNATURE");
|
// tlv8.create(kTLVType_Signature,64,"SIGNATURE");
|
||||||
tlv8.create(kTLVType_Identifier,64,"IDENTIFIER");
|
// tlv8.create(kTLVType_Identifier,64,"IDENTIFIER");
|
||||||
tlv8.create(kTLVType_Permissions,1,"PERMISSION");
|
// tlv8.create(kTLVType_Permissions,1,"PERMISSION");
|
||||||
|
|
||||||
if(!nvs_get_blob(hapNVS,"HAPHASH",NULL,&len)){ // if found HAP HASH structure
|
if(!nvs_get_blob(hapNVS,"HAPHASH",NULL,&len)){ // if found HAP HASH structure
|
||||||
nvs_get_blob(hapNVS,"HAPHASH",&homeSpan.hapConfig,&len); // retrieve data
|
nvs_get_blob(hapNVS,"HAPHASH",&homeSpan.hapConfig,&len); // retrieve data
|
||||||
|
|
@ -217,33 +217,23 @@ void HAPClient::processRequest(){
|
||||||
if(cLen==0){
|
if(cLen==0){
|
||||||
badRequestError();
|
badRequestError();
|
||||||
LOG0("\n*** ERROR: HTTP POST request contains no Content\n\n");
|
LOG0("\n*** ERROR: HTTP POST request contains no Content\n\n");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strncmp(body,"POST /pair-setup ",17) && strstr(body,"Content-Type: application/pairing+tlv8")){ // POST PAIR-SETUP
|
else if(!strncmp(body,"POST /pair-setup ",17) && strstr(body,"Content-Type: application/pairing+tlv8")) // POST PAIR-SETUP
|
||||||
postPairSetupURL(content,cLen);
|
postPairSetupURL(content,cLen);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!strncmp(body,"POST /pair-verify ",18) && strstr(body,"Content-Type: application/pairing+tlv8")){ // POST PAIR-VERIFY
|
else if(!strncmp(body,"POST /pair-verify ",18) && strstr(body,"Content-Type: application/pairing+tlv8")) // POST PAIR-VERIFY
|
||||||
postPairVerifyURL(content,cLen);
|
postPairVerifyURL(content,cLen);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!strncmp(body,"POST /pairings ",15) && // POST PAIRINGS
|
else if(!strncmp(body,"POST /pairings ",15) && strstr(body,"Content-Type: application/pairing+tlv8")) // POST PAIRINGS
|
||||||
strstr(body,"Content-Type: application/pairing+tlv8") && // check that content is TLV8
|
postPairingsURL(content,cLen);
|
||||||
tlv8.unpack(content,cLen)){ // read TLV content
|
|
||||||
tlv8.print(2); // print TLV records in form "TAG(INT) LENGTH(INT) VALUES(HEX)"
|
|
||||||
LOG2("------------ END TLVS! ------------\n");
|
|
||||||
|
|
||||||
postPairingsURL(); // process URL
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
notFoundError();
|
else {
|
||||||
LOG0("\n*** ERROR: Bad POST request - URL not found\n\n");
|
notFoundError();
|
||||||
return;
|
LOG0("\n*** ERROR: Bad POST request - URL not found\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
} // POST request
|
} // POST request
|
||||||
|
|
||||||
if(!strncmp(body,"PUT ",4)){ // this is a PUT request
|
if(!strncmp(body,"PUT ",4)){ // this is a PUT request
|
||||||
|
|
@ -381,7 +371,7 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
|
||||||
auto itState=iosTLV.find(kTLVType_State);
|
auto itState=iosTLV.find(kTLVType_State);
|
||||||
|
|
||||||
if(iosTLV.len(itState)!=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 'State' TLV\n\n");
|
||||||
badRequestError(); // return with 400 error, which closes connection
|
badRequestError(); // return with 400 error, which closes connection
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
@ -627,7 +617,7 @@ int HAPClient::postPairVerifyURL(uint8_t *content, size_t len){
|
||||||
auto itState=iosTLV.find(kTLVType_State);
|
auto itState=iosTLV.find(kTLVType_State);
|
||||||
|
|
||||||
if(iosTLV.len(itState)!=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 'State' TLV\n\n");
|
||||||
badRequestError(); // return with 400 error, which closes connection
|
badRequestError(); // return with 400 error, which closes connection
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
@ -828,101 +818,129 @@ int HAPClient::getAccessoriesURL(){
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
int HAPClient::postPairingsURL(){
|
int HAPClient::postPairingsURL(uint8_t *content, size_t len){
|
||||||
|
|
||||||
if(!cPair){ // unverified, unencrypted session
|
if(!cPair){ // unverified, unencrypted session
|
||||||
unauthorizedError();
|
unauthorizedError();
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG1("In Post Pairings #");
|
HAPTLV iosTLV;
|
||||||
LOG1(conNum);
|
HAPTLV responseTLV;
|
||||||
LOG1(" (");
|
|
||||||
LOG1(client.remoteIP());
|
|
||||||
LOG1(")...");
|
|
||||||
|
|
||||||
if(tlv8.val(kTLVType_State)!=1){
|
iosTLV.unpack(content,len);
|
||||||
LOG0("\n*** ERROR: 'State' TLV record is either missing or not set to <M1> as required\n\n");
|
iosTLV.print();
|
||||||
badRequestError(); // return with 400 error, which closes connection
|
LOG2("------------ END TLVS! ------------\n");
|
||||||
|
|
||||||
|
LOG2("In Post Pairings #%d (%s)...",conNum,client.remoteIP().toString().c_str());
|
||||||
|
|
||||||
|
auto itState=iosTLV.find(kTLVType_State);
|
||||||
|
auto itMethod=iosTLV.find(kTLVType_Method);
|
||||||
|
|
||||||
|
if(iosTLV.len(itState)!=1 || (*itState)[0]!=1){ // missing STATE TLV
|
||||||
|
LOG0("\n*** ERROR: Parirings 'State' is either missing or not set to <M1>\n\n");
|
||||||
|
badRequestError(); // return with 400 error, which closes connection
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(tlv8.val(kTLVType_Method)){
|
if(iosTLV.len(itMethod)!=1){ // missing METHOD TLV
|
||||||
|
LOG0("\n*** ERROR: Missing or invalid 'Method' TLV\n\n");
|
||||||
|
badRequestError(); // return with 400 error, which closes connection
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tlvMethod=(*itMethod)[0];
|
||||||
|
|
||||||
|
responseTLV.add(kTLVType_State,pairState_M2); // all responses include State=M2
|
||||||
|
|
||||||
|
switch(tlvMethod){ // List-Pairings received -- process request! (HAP Sections 5.10-5.12)
|
||||||
|
|
||||||
case 3: {
|
case 3: {
|
||||||
LOG1("Add...\n");
|
LOG1("Add...\n");
|
||||||
|
|
||||||
if(!tlv8.len(kTLVType_Identifier) || !tlv8.len(kTLVType_PublicKey) || !tlv8.len(kTLVType_Permissions)){
|
auto itIdentifier=iosTLV.find(kTLVType_Identifier);
|
||||||
|
auto itPublicKey=iosTLV.find(kTLVType_PublicKey);
|
||||||
|
auto itPermissions=iosTLV.find(kTLVType_Permissions);
|
||||||
|
|
||||||
|
if(iosTLV.len(itIdentifier)!=hap_controller_IDBYTES || iosTLV.len(itPublicKey)!=crypto_sign_PUBLICKEYBYTES || iosTLV.len(itPermissions)!=1){
|
||||||
LOG0("\n*** ERROR: One or more of required 'Identifier,' 'PublicKey,' and 'Permissions' TLV records for this step is bad or missing\n\n");
|
LOG0("\n*** ERROR: One or more of required 'Identifier,' 'PublicKey,' and 'Permissions' TLV records for this step is bad or missing\n\n");
|
||||||
tlv8.clear();
|
responseTLV.add(kTLVType_Error,tagError_Unknown);
|
||||||
tlv8.val(kTLVType_Error,tagError_Unknown);
|
tlvRespond(responseTLV);
|
||||||
|
return(0);
|
||||||
} else if(!cPair->admin){
|
|
||||||
LOG0("\n*** ERROR: Controller making request does not have admin privileges to add/update other Controllers\n\n");
|
|
||||||
tlv8.clear();
|
|
||||||
tlv8.val(kTLVType_Error,tagError_Authentication);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
tagError err=addController(tlv8.buf(kTLVType_Identifier),tlv8.buf(kTLVType_PublicKey),tlv8.val(kTLVType_Permissions));
|
|
||||||
tlv8.clear();
|
|
||||||
if(err!=tagError_None)
|
|
||||||
tlv8.val(kTLVType_Error,err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tlv8.val(kTLVType_State,pairState_M2);
|
if(!cPair->admin){
|
||||||
tlvRespond();
|
LOG0("\n*** ERROR: Controller making request does not have admin privileges to add/update other Controllers\n\n");
|
||||||
|
responseTLV.add(kTLVType_Error,tagError_Authentication);
|
||||||
|
tlvRespond(responseTLV);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tagError err=addController(*itIdentifier,*itPublicKey,(*itPermissions)[0]);
|
||||||
|
if(err!=tagError_None)
|
||||||
|
responseTLV.add(kTLVType_Error,err);
|
||||||
|
|
||||||
|
tlvRespond(responseTLV);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 4: {
|
case 4: {
|
||||||
LOG1("Remove...\n");
|
LOG1("Remove...\n");
|
||||||
|
|
||||||
uint8_t id[36];
|
auto itIdentifier=iosTLV.find(kTLVType_Identifier);
|
||||||
|
|
||||||
if(!tlv8.len(kTLVType_Identifier)){
|
if(iosTLV.len(itIdentifier)!=hap_controller_IDBYTES){
|
||||||
LOG0("\n*** ERROR: Required 'Identifier' TLV record for this step is bad or missing\n\n");
|
LOG0("\n*** ERROR: Required 'Identifier' TLV record for this step is bad or missing\n\n");
|
||||||
tlv8.clear();
|
responseTLV.add(kTLVType_Error,tagError_Unknown);
|
||||||
tlv8.val(kTLVType_Error,tagError_Unknown);
|
tlvRespond(responseTLV);
|
||||||
|
return(0);
|
||||||
} else if(!cPair->admin){
|
|
||||||
LOG0("\n*** ERROR: Controller making request does not have admin privileges to remove Controllers\n\n");
|
|
||||||
tlv8.clear();
|
|
||||||
tlv8.val(kTLVType_Error,tagError_Authentication);
|
|
||||||
} else {
|
|
||||||
memcpy(id,tlv8.buf(kTLVType_Identifier),36);
|
|
||||||
tlv8.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tlv8.val(kTLVType_State,pairState_M2);
|
|
||||||
tlvRespond(); // must send response before removing Controller below
|
|
||||||
|
|
||||||
if(tlv8.val(kTLVType_Error)==-1)
|
if(!cPair->admin){
|
||||||
removeController(id);
|
LOG0("\n*** ERROR: Controller making request does not have admin privileges to remove Controllers\n\n");
|
||||||
|
responseTLV.add(kTLVType_Error,tagError_Authentication);
|
||||||
|
tlvRespond(responseTLV);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tlvRespond(responseTLV); // must send response before removing Controller
|
||||||
|
removeController(*itIdentifier);
|
||||||
|
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 5: {
|
case 5: {
|
||||||
LOG1("List...\n");
|
LOG1("List...\n");
|
||||||
|
|
||||||
TempBuffer<uint8_t> tBuf(listControllers(NULL));
|
if(!cPair->admin){
|
||||||
|
LOG0("\n*** ERROR: Controller making request does not have admin privileges to remove Controllers\n\n");
|
||||||
|
responseTLV.add(kTLVType_Error,tagError_Authentication);
|
||||||
|
tlvRespond(responseTLV);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
char *body;
|
boolean addSeparator=false;
|
||||||
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
|
|
||||||
|
|
||||||
LOG2("\n>>>>>>>>>> ");
|
|
||||||
LOG2(client.remoteIP());
|
|
||||||
LOG2(" >>>>>>>>>>\n");
|
|
||||||
LOG2(body);
|
|
||||||
listControllers(tBuf);
|
|
||||||
sendEncrypted(body,tBuf,tBuf.len());
|
|
||||||
free(body);
|
|
||||||
|
|
||||||
|
for(auto it=controllerList.begin();it!=controllerList.end();it++){
|
||||||
|
if((*it).allocated){
|
||||||
|
if(addSeparator)
|
||||||
|
responseTLV.add(kTLVType_Separator);
|
||||||
|
responseTLV.add(kTLVType_Permissions,(*it).admin);
|
||||||
|
responseTLV.add(kTLVType_Identifier,hap_controller_IDBYTES,(*it).ID);
|
||||||
|
responseTLV.add(kTLVType_PublicKey,crypto_sign_PUBLICKEYBYTES,(*it).LTPK);
|
||||||
|
addSeparator=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tlvRespond(responseTLV);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
LOG0("\n*** ERROR: 'Method' TLV record is either missing or not set to either 3, 4, or 5 as required\n\n");
|
LOG0("\n*** ERROR: Undefined List-Pairings Method: %d. Must be 3, 4, or 5\n\n",tlvMethod);
|
||||||
badRequestError(); // return with 400 error, which closes connection
|
badRequestError(); // return with 400 error, which closes connection
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
@ -1372,31 +1390,31 @@ 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
|
||||||
|
//
|
||||||
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
|
||||||
|
//
|
||||||
LOG2("\n>>>>>>>>>> ");
|
// LOG2("\n>>>>>>>>>> ");
|
||||||
LOG2(client.remoteIP());
|
// LOG2(client.remoteIP());
|
||||||
LOG2(" >>>>>>>>>>\n");
|
// LOG2(" >>>>>>>>>>\n");
|
||||||
LOG2(body);
|
// LOG2(body);
|
||||||
tlv8.print(2);
|
// tlv8.print(2);
|
||||||
|
//
|
||||||
if(!cPair){ // unverified, unencrypted session
|
// if(!cPair){ // unverified, unencrypted session
|
||||||
client.print(body);
|
// client.print(body);
|
||||||
client.write(tBuf,tBuf.len());
|
// client.write(tBuf,tBuf.len());
|
||||||
LOG2("------------ SENT! --------------\n");
|
// LOG2("------------ SENT! --------------\n");
|
||||||
} else {
|
// } else {
|
||||||
sendEncrypted(body,tBuf,tBuf.len());
|
// sendEncrypted(body,tBuf,tBuf.len());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
free(body);
|
// free(body);
|
||||||
|
//
|
||||||
} // tlvRespond
|
//} // tlvRespond
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
|
@ -1619,33 +1637,33 @@ void HAPClient::tearDown(uint8_t *id){
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
int HAPClient::listControllers(uint8_t *tlvBuf){
|
//int HAPClient::listControllers(uint8_t *tlvBuf){
|
||||||
|
//
|
||||||
int nBytes=0;
|
// int nBytes=0;
|
||||||
int n;
|
// int n;
|
||||||
|
//
|
||||||
tlv8.clear();
|
// tlv8.clear();
|
||||||
tlv8.val(kTLVType_State,pairState_M2);
|
// tlv8.val(kTLVType_State,pairState_M2);
|
||||||
|
//
|
||||||
for(auto it=controllerList.begin();it!=controllerList.end();it++){
|
// for(auto it=controllerList.begin();it!=controllerList.end();it++){
|
||||||
if((*it).allocated){
|
// if((*it).allocated){
|
||||||
if(tlv8.val(kTLVType_State)==-1) // if State is not set then this is not the first controller found
|
// if(tlv8.val(kTLVType_State)==-1) // if State is not set then this is not the first controller found
|
||||||
tlv8.val(kTLVType_Separator,1);
|
// tlv8.val(kTLVType_Separator,1);
|
||||||
tlv8.val(kTLVType_Permissions,(*it).admin);
|
// tlv8.val(kTLVType_Permissions,(*it).admin);
|
||||||
tlv8.buf(kTLVType_Identifier,(*it).ID,36);
|
// tlv8.buf(kTLVType_Identifier,(*it).ID,36);
|
||||||
tlv8.buf(kTLVType_PublicKey,(*it).LTPK,32);
|
// tlv8.buf(kTLVType_PublicKey,(*it).LTPK,32);
|
||||||
n=tlv8.pack(tlvBuf);
|
// n=tlv8.pack(tlvBuf);
|
||||||
nBytes+=n;
|
// nBytes+=n;
|
||||||
if(tlvBuf){
|
// if(tlvBuf){
|
||||||
tlvBuf+=n;
|
// tlvBuf+=n;
|
||||||
tlv8.print();
|
// tlv8.print();
|
||||||
}
|
// }
|
||||||
tlv8.clear();
|
// tlv8.clear();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return(nBytes);
|
// return(nBytes);
|
||||||
}
|
//}
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
|
@ -1716,7 +1734,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;
|
||||||
nvs_handle HAPClient::hapNVS;
|
nvs_handle HAPClient::hapNVS;
|
||||||
nvs_handle HAPClient::srpNVS;
|
nvs_handle HAPClient::srpNVS;
|
||||||
HKDF HAPClient::hkdf;
|
HKDF HAPClient::hkdf;
|
||||||
|
|
|
||||||
43
src/HAP.h
43
src/HAP.h
|
|
@ -30,26 +30,29 @@
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
|
||||||
#include "HomeSpan.h"
|
#include "HomeSpan.h"
|
||||||
#include "TLV.h"
|
//#include "TLV.h"
|
||||||
#include "HAPConstants.h"
|
#include "HAPConstants.h"
|
||||||
#include "HKDF.h"
|
#include "HKDF.h"
|
||||||
#include "SRP.h"
|
#include "SRP.h"
|
||||||
#include "TLV8.h"
|
#include "TLV8.h"
|
||||||
|
|
||||||
const TLV8_names HAP_Names[] = {
|
const TLV8_names HAP_Names[] = {
|
||||||
{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"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define hap_controller_IDBYTES 36
|
||||||
|
#define hap_accessory_IDBYTES 17
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
// NONCE Structure (HAP used last 64 of 96 bits)
|
// NONCE Structure (HAP used last 64 of 96 bits)
|
||||||
|
|
||||||
|
|
@ -67,7 +70,7 @@ struct Nonce {
|
||||||
struct Controller {
|
struct Controller {
|
||||||
boolean allocated=false; // DEPRECATED (but needed for backwards compatability with original NVS storage of Controller info)
|
boolean allocated=false; // DEPRECATED (but needed for backwards compatability with original NVS storage of Controller info)
|
||||||
boolean admin; // Controller has admin privileges
|
boolean admin; // Controller has admin privileges
|
||||||
uint8_t ID[36]; // Pairing ID
|
uint8_t ID[hap_controller_IDBYTES]; // Pairing ID
|
||||||
uint8_t LTPK[crypto_sign_PUBLICKEYBYTES]; // Long Term Ed2519 Public Key
|
uint8_t LTPK[crypto_sign_PUBLICKEYBYTES]; // Long Term Ed2519 Public Key
|
||||||
|
|
||||||
Controller(){}
|
Controller(){}
|
||||||
|
|
@ -85,9 +88,9 @@ struct Controller {
|
||||||
// Accessory Structure for Permanently-Stored Data
|
// Accessory Structure for Permanently-Stored Data
|
||||||
|
|
||||||
struct Accessory {
|
struct Accessory {
|
||||||
uint8_t ID[17]; // Pairing ID in form "XX:XX:XX:XX:XX:XX"
|
uint8_t ID[hap_accessory_IDBYTES]; // Pairing ID in form "XX:XX:XX:XX:XX:XX" (no null terminator)
|
||||||
uint8_t LTSK[crypto_sign_SECRETKEYBYTES]; // secret key for Ed25519 signatures
|
uint8_t LTSK[crypto_sign_SECRETKEYBYTES]; // Long Term Ed2519 Secret Key
|
||||||
uint8_t LTPK[crypto_sign_PUBLICKEYBYTES]; // public key for Ed25519 signatures
|
uint8_t LTPK[crypto_sign_PUBLICKEYBYTES]; // Long Term Ed2519 Public Key
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
|
|
@ -102,7 +105,7 @@ 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 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
|
||||||
|
|
@ -136,14 +139,14 @@ struct HAPClient {
|
||||||
void processRequest(); // process HAP request
|
void processRequest(); // process HAP request
|
||||||
int postPairSetupURL(uint8_t *content, size_t len); // POST /pair-setup (HAP Section 5.6)
|
int postPairSetupURL(uint8_t *content, size_t len); // POST /pair-setup (HAP Section 5.6)
|
||||||
int postPairVerifyURL(uint8_t *content, size_t len); // POST /pair-verify (HAP Section 5.7)
|
int postPairVerifyURL(uint8_t *content, size_t len); // POST /pair-verify (HAP Section 5.7)
|
||||||
|
int postPairingsURL(uint8_t *content, size_t len); // POST /pairings (HAP Sections 5.10-5.12)
|
||||||
int getAccessoriesURL(); // GET /accessories (HAP Section 6.6)
|
int getAccessoriesURL(); // GET /accessories (HAP Section 6.6)
|
||||||
int postPairingsURL(); // POST /pairings (HAP Sections 5.10-5.12)
|
|
||||||
int getCharacteristicsURL(char *urlBuf); // GET /characteristics (HAP Section 6.7.4)
|
int getCharacteristicsURL(char *urlBuf); // GET /characteristics (HAP Section 6.7.4)
|
||||||
int putCharacteristicsURL(char *json); // PUT /characteristics (HAP Section 6.7.2)
|
int putCharacteristicsURL(char *json); // PUT /characteristics (HAP Section 6.7.2)
|
||||||
int putPrepareURL(char *json); // PUT /prepare (HAP Section 6.7.2.4)
|
int putPrepareURL(char *json); // PUT /prepare (HAP Section 6.7.2.4)
|
||||||
int getStatusURL(); // GET / status (an optional, non-HAP feature)
|
int getStatusURL(); // GET / status (an optional, non-HAP feature)
|
||||||
|
|
||||||
void tlvRespond(); // respond to client with HTTP OK header and all defined TLV data records (those with length>0)
|
// void tlvRespond(); // respond to client with HTTP OK header and all defined TLV data records (those with length>0)
|
||||||
void tlvRespond(TLV8 &tlv8); // respond to client with HTTP OK header and all defined TLV data records
|
void tlvRespond(TLV8 &tlv8); // respond to client with HTTP OK header and all defined TLV data records
|
||||||
void sendEncrypted(char *body, uint8_t *dataBuf, int dataLen); // send client complete ChaCha20-Poly1305 encrypted HTTP mesage comprising a null-terminated 'body' and 'dataBuf' with 'dataLen' bytes
|
void sendEncrypted(char *body, uint8_t *dataBuf, int dataLen); // send client complete ChaCha20-Poly1305 encrypted HTTP mesage comprising a null-terminated 'body' and 'dataBuf' with 'dataLen' bytes
|
||||||
int receiveEncrypted(uint8_t *httpBuf, int messageSize); // decrypt HTTP request (HAP Section 6.5)
|
int receiveEncrypted(uint8_t *httpBuf, int messageSize); // decrypt HTTP request (HAP Section 6.5)
|
||||||
|
|
@ -164,7 +167,7 @@ struct HAPClient {
|
||||||
static tagError addController(uint8_t *id, uint8_t *ltpk, boolean admin); // stores data for new Controller with specified data. Returns tagError (if any)
|
static tagError addController(uint8_t *id, uint8_t *ltpk, boolean admin); // stores data for new Controller with specified data. Returns tagError (if any)
|
||||||
static void removeController(uint8_t *id); // removes specific Controller. If no remaining admin Controllers, remove all others (if any) as per HAP requirements.
|
static void removeController(uint8_t *id); // removes specific Controller. If no remaining admin Controllers, remove all others (if any) as per HAP requirements.
|
||||||
static void printControllers(int minLogLevel=0); // prints IDs of all allocated (paired) Controller, subject to specified minimum log level
|
static void printControllers(int minLogLevel=0); // prints IDs of all allocated (paired) Controller, subject to specified minimum log level
|
||||||
static int listControllers(uint8_t *tlvBuf); // creates and prints a multi-TLV list of Controllers (HAP Section 5.12)
|
// static int listControllers(uint8_t *tlvBuf); // creates and prints a multi-TLV list of Controllers (HAP Section 5.12)
|
||||||
static void saveControllers(); // saves Controller list in NVS
|
static void saveControllers(); // saves Controller list in NVS
|
||||||
static int nAdminControllers(); // returns number of admin Controller
|
static int nAdminControllers(); // returns number of admin Controller
|
||||||
static void tearDown(uint8_t *id); // tears down connections using Controller with ID=id; tears down all connections if id=NULL
|
static void tearDown(uint8_t *id); // tears down connections using Controller with ID=id; tears down all connections if id=NULL
|
||||||
|
|
|
||||||
|
|
@ -577,16 +577,6 @@ Span& Span::setQRID(const char *id){
|
||||||
void Span::processSerialCommand(const char *c){
|
void Span::processSerialCommand(const char *c){
|
||||||
|
|
||||||
switch(c[0]){
|
switch(c[0]){
|
||||||
|
|
||||||
case 'Z': {
|
|
||||||
HAPClient::saveControllers();
|
|
||||||
break;
|
|
||||||
TempBuffer<uint8_t> tBuf(HAPClient::listControllers(NULL));
|
|
||||||
HAPClient::listControllers(tBuf);
|
|
||||||
Serial.printf("SIZE = %d\n",tBuf.len());
|
|
||||||
HAPClient::hexPrintRow(tBuf,tBuf.len());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 's': {
|
case 's': {
|
||||||
|
|
||||||
|
|
|
||||||
48
src/SRP.cpp
48
src/SRP.cpp
|
|
@ -239,30 +239,30 @@ void SRP6A::createProof(){
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
int SRP6A::loadTLV(kTLVType tag, mbedtls_mpi *mpi, int nBytes){
|
//int SRP6A::loadTLV(kTLVType tag, mbedtls_mpi *mpi, int nBytes){
|
||||||
|
//
|
||||||
uint8_t *buf=HAPClient::tlv8.buf(tag,nBytes);
|
// uint8_t *buf=HAPClient::tlv8.buf(tag,nBytes);
|
||||||
|
//
|
||||||
if(!buf)
|
// if(!buf)
|
||||||
return(0);
|
// return(0);
|
||||||
|
//
|
||||||
mbedtls_mpi_write_binary(mpi,buf,nBytes);
|
// mbedtls_mpi_write_binary(mpi,buf,nBytes);
|
||||||
return(1);
|
// return(1);
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
//////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
//
|
||||||
int SRP6A::writeTLV(kTLVType tag, mbedtls_mpi *mpi){
|
//int SRP6A::writeTLV(kTLVType tag, mbedtls_mpi *mpi){
|
||||||
|
//
|
||||||
int nBytes=HAPClient::tlv8.len(tag);
|
// int nBytes=HAPClient::tlv8.len(tag);
|
||||||
|
//
|
||||||
if(nBytes>0){
|
// if(nBytes>0){
|
||||||
mbedtls_mpi_read_binary(mpi,HAPClient::tlv8.buf(tag),nBytes);
|
// mbedtls_mpi_read_binary(mpi,HAPClient::tlv8.buf(tag),nBytes);
|
||||||
return(1);
|
// return(1);
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
return(0);
|
// return(0);
|
||||||
}
|
//}
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,8 @@ struct SRP6A {
|
||||||
void createPublicKey(); // computes x, v, and B from random s, P, and b
|
void createPublicKey(); // computes x, v, and B from random s, P, and b
|
||||||
void createSessionKey(); // computes u from A and B, and then S from A, v, u, and b
|
void createSessionKey(); // computes u from A and B, and then S from A, v, u, and b
|
||||||
|
|
||||||
int loadTLV(kTLVType tag, mbedtls_mpi *mpi, int nBytes); // load binary contents of mpi into a TLV record and set its length
|
// int loadTLV(kTLVType tag, mbedtls_mpi *mpi, int nBytes); // load binary contents of mpi into a TLV record and set its length
|
||||||
int writeTLV(kTLVType tag, mbedtls_mpi *mpi); // write binary contents of a TLV record into an mpi
|
// int writeTLV(kTLVType tag, mbedtls_mpi *mpi); // write binary contents of a TLV record into an mpi
|
||||||
|
|
||||||
int verifyProof(); // verify M1 SRP6A Proof received from HAP client (return 1 on success, 0 on failure)
|
int verifyProof(); // verify M1 SRP6A Proof received from HAP client (return 1 on success, 0 on failure)
|
||||||
void createProof(); // create M2 server-side SRP6A Proof based on M1 as received from HAP Client
|
void createProof(); // create M2 server-side SRP6A Proof based on M1 as received from HAP Client
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue