Start re-working SRP6A's use in Pair-Setup to make it local instead of global
This commit is contained in:
parent
beef66eec0
commit
da55b9b6b1
71
src/HAP.cpp
71
src/HAP.cpp
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
void HAPClient::init(){
|
void HAPClient::init(){
|
||||||
|
|
||||||
size_t len; // not used but required to read blobs from NVS
|
size_t len; // not used but required to read blobs from NVS
|
||||||
|
|
||||||
nvs_open("SRP",NVS_READWRITE,&srpNVS); // open SRP data namespace in NVS
|
nvs_open("SRP",NVS_READWRITE,&srpNVS); // open SRP data namespace in NVS
|
||||||
nvs_open("HAP",NVS_READWRITE,&hapNVS); // open HAP data namespace in NVS
|
nvs_open("HAP",NVS_READWRITE,&hapNVS); // open HAP data namespace in NVS
|
||||||
|
|
@ -48,37 +48,20 @@ void HAPClient::init(){
|
||||||
homeSpan.spanOTA.setPassword(DEFAULT_OTA_PASSWORD); // ...use default password
|
homeSpan.spanOTA.setPassword(DEFAULT_OTA_PASSWORD); // ...use default password
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(nvs_get_blob(srpNVS,"VERIFYDATA",NULL,&len)) // if Pair-Setup verification code data not found in NVS
|
||||||
|
homeSpan.setPairingCode(DEFAULT_SETUP_CODE); // create and save verification from using Pairing Setup Code
|
||||||
|
|
||||||
if(strlen(homeSpan.pairingCodeCommand)){ // load verification setup code if provided
|
if(!strlen(homeSpan.qrID)){ // is Setup ID has not been specified in sketch
|
||||||
homeSpan.processSerialCommand(homeSpan.pairingCodeCommand); // if load failed due to invalid code, the logic below still runs and will pick up previous code or use the default one
|
if(!nvs_get_str(hapNVS,"SETUPID",NULL,&len)){ // check for saved value
|
||||||
}
|
nvs_get_str(hapNVS,"SETUPID",homeSpan.qrID,&len); // retrieve data
|
||||||
|
|
||||||
struct { // temporary structure to hold SRP verification code and salt stored in NVS
|
|
||||||
uint8_t salt[16];
|
|
||||||
uint8_t verifyCode[384];
|
|
||||||
} verifyData;
|
|
||||||
|
|
||||||
if(!nvs_get_blob(srpNVS,"VERIFYDATA",NULL,&len)){ // if found verification code data in NVS
|
|
||||||
nvs_get_blob(srpNVS,"VERIFYDATA",&verifyData,&len); // retrieve data
|
|
||||||
srp.loadVerifyCode(verifyData.verifyCode,verifyData.salt); // load verification code and salt into SRP structure
|
|
||||||
} else {
|
|
||||||
LOG0("Generating SRP verification data for default Setup Code: %.3s-%.2s-%.3s\n",homeSpan.defaultSetupCode,homeSpan.defaultSetupCode+3,homeSpan.defaultSetupCode+5);
|
|
||||||
srp.createVerifyCode(homeSpan.defaultSetupCode,verifyData.verifyCode,verifyData.salt); // create verification code from default Setup Code and random salt
|
|
||||||
nvs_set_blob(srpNVS,"VERIFYDATA",&verifyData,sizeof(verifyData)); // update data
|
|
||||||
nvs_commit(srpNVS); // commit to NVS
|
|
||||||
LOG0("Setup Payload for Optional QR Code: %s\n\n",homeSpan.qrCode.get(atoi(homeSpan.defaultSetupCode),homeSpan.qrID,atoi(homeSpan.category)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!strlen(homeSpan.qrID)){ // Setup ID has not been specified in sketch
|
|
||||||
if(!nvs_get_str(hapNVS,"SETUPID",NULL,&len)){ // check for saved value
|
|
||||||
nvs_get_str(hapNVS,"SETUPID",homeSpan.qrID,&len); // retrieve data
|
|
||||||
} else {
|
} else {
|
||||||
sprintf(homeSpan.qrID,"%s",DEFAULT_QR_ID); // use default
|
sprintf(homeSpan.qrID,"%s",DEFAULT_QR_ID); // use default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!nvs_get_blob(hapNVS,"ACCESSORY",NULL,&len)){ // if found long-term Accessory data in NVS
|
if(!nvs_get_blob(hapNVS,"ACCESSORY",NULL,&len)){ // if found long-term Accessory data in NVS
|
||||||
nvs_get_blob(hapNVS,"ACCESSORY",&accessory,&len); // retrieve data
|
nvs_get_blob(hapNVS,"ACCESSORY",&accessory,&len); // retrieve data
|
||||||
} else {
|
} else {
|
||||||
LOG0("Generating new random Accessory ID and Long-Term Ed25519 Signature Keys...\n\n");
|
LOG0("Generating new random Accessory ID and Long-Term Ed25519 Signature Keys...\n\n");
|
||||||
uint8_t buf[6];
|
uint8_t buf[6];
|
||||||
|
|
@ -91,13 +74,13 @@ void HAPClient::init(){
|
||||||
memcpy(accessory.ID,cBuf,17); // copy into Accessory ID for permanent storage
|
memcpy(accessory.ID,cBuf,17); // copy into Accessory ID for permanent storage
|
||||||
crypto_sign_keypair(accessory.LTPK,accessory.LTSK); // generate new random set of keys using libsodium public-key signature
|
crypto_sign_keypair(accessory.LTPK,accessory.LTSK); // generate new random set of keys using libsodium public-key signature
|
||||||
|
|
||||||
nvs_set_blob(hapNVS,"ACCESSORY",&accessory,sizeof(accessory)); // update data
|
nvs_set_blob(hapNVS,"ACCESSORY",&accessory,sizeof(accessory)); // update data
|
||||||
nvs_commit(hapNVS); // commit to NVS
|
nvs_commit(hapNVS); // commit to NVS
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!nvs_get_blob(hapNVS,"CONTROLLERS",NULL,&len)){ // if found long-term Controller Pairings data from NVS
|
if(!nvs_get_blob(hapNVS,"CONTROLLERS",NULL,&len)){ // if found long-term Controller Pairings data from NVS
|
||||||
TempBuffer<Controller> tBuf(len/sizeof(Controller));
|
TempBuffer<Controller> tBuf(len/sizeof(Controller));
|
||||||
nvs_get_blob(hapNVS,"CONTROLLERS",tBuf,&len); // retrieve data
|
nvs_get_blob(hapNVS,"CONTROLLERS",tBuf,&len); // retrieve data
|
||||||
for(int i=0;i<tBuf.size();i++){
|
for(int i=0;i<tBuf.size();i++){
|
||||||
if(tBuf[i].allocated)
|
if(tBuf[i].allocated)
|
||||||
controllerList.push_back(tBuf[i]);
|
controllerList.push_back(tBuf[i]);
|
||||||
|
|
@ -403,9 +386,9 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
|
||||||
auto itSalt=responseTLV.add(kTLVType_Salt,16,NULL); // create blank Salt TLV with space for 16 bytes
|
auto itSalt=responseTLV.add(kTLVType_Salt,16,NULL); // create blank Salt TLV with space for 16 bytes
|
||||||
|
|
||||||
responseTLV.add(kTLVType_State,pairState_M2); // set State=<M2>
|
responseTLV.add(kTLVType_State,pairState_M2); // set State=<M2>
|
||||||
srp.createPublicKey(); // create accessory Public Key from Pair-Setup code (displayed to user)
|
srp->createPublicKey(); // create accessory Public Key from Pair-Setup code (displayed to user)
|
||||||
mbedtls_mpi_write_binary(&srp.B,*itPublicKey,(*itPublicKey).len); // load server PublicKey, B, into TLV
|
mbedtls_mpi_write_binary(&srp->B,*itPublicKey,(*itPublicKey).len); // load server PublicKey, B, into TLV
|
||||||
mbedtls_mpi_write_binary(&srp.s,*itSalt,(*itSalt).len); // load Salt, s, into TLV
|
mbedtls_mpi_write_binary(&srp->s,*itSalt,(*itSalt).len); // load Salt, s, into TLV
|
||||||
tlvRespond(responseTLV); // send response to client
|
tlvRespond(responseTLV); // send response to client
|
||||||
pairStatus=pairState_M3; // set next expected pair-state request from client
|
pairStatus=pairState_M3; // set next expected pair-state request from client
|
||||||
return(1);
|
return(1);
|
||||||
|
|
@ -426,12 +409,12 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
|
||||||
return(0);
|
return(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
mbedtls_mpi_read_binary(&srp.A,*itPublicKey,(*itPublicKey).len); // load client PublicKey TLV into A
|
mbedtls_mpi_read_binary(&srp->A,*itPublicKey,(*itPublicKey).len); // load client PublicKey TLV into A
|
||||||
mbedtls_mpi_read_binary(&srp.M1,*itClientProof,(*itClientProof).len); // load client Proof TLV into M1
|
mbedtls_mpi_read_binary(&srp->M1,*itClientProof,(*itClientProof).len); // load client Proof TLV into M1
|
||||||
|
|
||||||
srp.createSessionKey(); // create session key, K, from receipt of client Public Key, A
|
srp->createSessionKey(); // create session key, K, from receipt of client Public Key, A
|
||||||
|
|
||||||
if(!srp.verifyProof()){ // verify client Proof, M1
|
if(!srp->verifyProof()){ // verify client Proof, M1
|
||||||
LOG0("\n*** ERROR: SRP Proof Verification Failed\n\n");
|
LOG0("\n*** ERROR: SRP Proof 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
|
||||||
|
|
@ -443,8 +426,8 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
|
||||||
auto itAccProof=responseTLV.add(kTLVType_Proof,64,NULL); // create blank accessory Proof TLV with space for 64 bytes
|
auto itAccProof=responseTLV.add(kTLVType_Proof,64,NULL); // create blank accessory Proof TLV with space for 64 bytes
|
||||||
|
|
||||||
responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4>
|
responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4>
|
||||||
srp.createProof(); // M1 has been successully verified; now create accessory proof M2
|
srp->createProof(); // M1 has been successully verified; now create accessory proof M2
|
||||||
mbedtls_mpi_write_binary(&srp.M2,*itAccProof,(*itAccProof).len); // load accessory Proof, M2, into TLV
|
mbedtls_mpi_write_binary(&srp->M2,*itAccProof,(*itAccProof).len); // load accessory Proof, M2, into TLV
|
||||||
tlvRespond(responseTLV); // send response to client
|
tlvRespond(responseTLV); // send response to client
|
||||||
pairStatus=pairState_M5; // set next expected pair-state request from client
|
pairStatus=pairState_M5; // set next expected pair-state request from client
|
||||||
return(1);
|
return(1);
|
||||||
|
|
@ -473,7 +456,7 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
|
||||||
// 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.
|
||||||
|
|
||||||
TempBuffer<uint8_t> srpSessionKey(crypto_box_PUBLICKEYBYTES); // temporary space - used only in this block
|
TempBuffer<uint8_t> srpSessionKey(crypto_box_PUBLICKEYBYTES); // temporary space - used only in this block
|
||||||
hkdf.create(srpSessionKey,srp.sharedSecret,64,"Pair-Setup-Encrypt-Salt","Pair-Setup-Encrypt-Info"); // create SessionKey
|
hkdf.create(srpSessionKey,srp->sharedSecret,64,"Pair-Setup-Encrypt-Salt","Pair-Setup-Encrypt-Info"); // create SessionKey
|
||||||
|
|
||||||
LOG2("------- DECRYPTING SUB-TLVS -------\n");
|
LOG2("------- DECRYPTING SUB-TLVS -------\n");
|
||||||
|
|
||||||
|
|
@ -514,7 +497,7 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
|
||||||
// Note that the SALT and INFO text fields now match those in HAP Section 5.6.6.1
|
// Note that the SALT and INFO text fields now match those in HAP Section 5.6.6.1
|
||||||
|
|
||||||
TempBuffer<uint8_t> iosDeviceX(32);
|
TempBuffer<uint8_t> iosDeviceX(32);
|
||||||
hkdf.create(iosDeviceX,srp.sharedSecret,64,"Pair-Setup-Controller-Sign-Salt","Pair-Setup-Controller-Sign-Info"); // derive iosDeviceX (32 bytes) from SRP Shared Secret using HKDF
|
hkdf.create(iosDeviceX,srp->sharedSecret,64,"Pair-Setup-Controller-Sign-Salt","Pair-Setup-Controller-Sign-Info"); // derive iosDeviceX (32 bytes) from SRP Shared Secret using HKDF
|
||||||
|
|
||||||
// Concatenate iosDeviceX, IOS ID, and IOS PublicKey into iosDeviceInfo
|
// Concatenate iosDeviceX, IOS ID, and IOS PublicKey into iosDeviceInfo
|
||||||
|
|
||||||
|
|
@ -534,7 +517,7 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
|
||||||
// Now perform the above steps in reverse to securely transmit the AccessoryLTPK to the Controller (HAP Section 5.6.6.2)
|
// Now perform the above steps in reverse to securely transmit the AccessoryLTPK to the Controller (HAP Section 5.6.6.2)
|
||||||
|
|
||||||
TempBuffer<uint8_t> accessoryX(32);
|
TempBuffer<uint8_t> accessoryX(32);
|
||||||
hkdf.create(accessoryX,srp.sharedSecret,64,"Pair-Setup-Accessory-Sign-Salt","Pair-Setup-Accessory-Sign-Info"); // derive accessoryX from SRP Shared Secret using HKDF
|
hkdf.create(accessoryX,srp->sharedSecret,64,"Pair-Setup-Accessory-Sign-Salt","Pair-Setup-Accessory-Sign-Info"); // derive accessoryX from SRP Shared Secret using HKDF
|
||||||
|
|
||||||
// Concatenate accessoryX, Accessory ID, and Accessory PublicKey into accessoryInfo
|
// Concatenate accessoryX, Accessory ID, and Accessory PublicKey into accessoryInfo
|
||||||
|
|
||||||
|
|
@ -1672,6 +1655,6 @@ HKDF HAPClient::hkdf;
|
||||||
pairState HAPClient::pairStatus;
|
pairState HAPClient::pairStatus;
|
||||||
Accessory HAPClient::accessory;
|
Accessory HAPClient::accessory;
|
||||||
list<Controller, Mallocator<Controller>> HAPClient::controllerList;
|
list<Controller, Mallocator<Controller>> HAPClient::controllerList;
|
||||||
SRP6A HAPClient::srp;
|
SRP6A *HAPClient::srp;
|
||||||
int HAPClient::conNum;
|
int HAPClient::conNum;
|
||||||
|
|
||||||
|
|
|
||||||
10
src/HAP.h
10
src/HAP.h
|
|
@ -52,6 +52,14 @@ const TLV8_names HAP_Names[] = {
|
||||||
#define hap_controller_IDBYTES 36
|
#define hap_controller_IDBYTES 36
|
||||||
#define hap_accessory_IDBYTES 17
|
#define hap_accessory_IDBYTES 17
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// Pair-Setup Code Verification Data and Salt
|
||||||
|
|
||||||
|
struct Verification {
|
||||||
|
uint8_t salt[16];
|
||||||
|
uint8_t verifyCode[384];
|
||||||
|
};
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
// NONCE Structure (HAP used last 64 of 96 bits)
|
// NONCE Structure (HAP used last 64 of 96 bits)
|
||||||
|
|
||||||
|
|
@ -108,7 +116,7 @@ struct HAPClient {
|
||||||
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 (must persist through multiple calls to 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
|
||||||
|
|
|
||||||
|
|
@ -674,31 +674,8 @@ void Span::processSerialCommand(const char *c){
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S': {
|
case 'S': {
|
||||||
|
|
||||||
char setupCode[10];
|
|
||||||
|
|
||||||
struct { // temporary structure to hold SRP verification code and salt stored in NVS
|
setPairingCode(c+1);
|
||||||
uint8_t salt[16];
|
|
||||||
uint8_t verifyCode[384];
|
|
||||||
} verifyData;
|
|
||||||
|
|
||||||
sscanf(c+1," %9[0-9]",setupCode);
|
|
||||||
|
|
||||||
if(strlen(setupCode)!=8){
|
|
||||||
LOG0("\n*** Invalid request to change Setup Code. Code must be exactly 8 digits.\n\n");
|
|
||||||
} else
|
|
||||||
|
|
||||||
if(!network.allowedCode(setupCode)){
|
|
||||||
LOG0("\n*** Invalid request to change Setup Code. Code too simple.\n\n");
|
|
||||||
} else {
|
|
||||||
|
|
||||||
LOG0("\nGenerating SRP verification data for new Setup Code: %.3s-%.2s-%.3s ... ",setupCode,setupCode+3,setupCode+5);
|
|
||||||
HAPClient::srp.createVerifyCode(setupCode,verifyData.verifyCode,verifyData.salt); // create verification code from default Setup Code and random salt
|
|
||||||
nvs_set_blob(HAPClient::srpNVS,"VERIFYDATA",&verifyData,sizeof(verifyData)); // update data
|
|
||||||
nvs_commit(HAPClient::srpNVS); // commit to NVS
|
|
||||||
LOG0("New Code Saved!\n");
|
|
||||||
LOG0("Setup Payload for Optional QR Code: %s\n\n",qrCode.get(atoi(setupCode),qrID,atoi(category)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1207,6 +1184,40 @@ const char* Span::statusString(HS_STATUS s){
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
|
Span& Span::setPairingCode(const char *s){
|
||||||
|
|
||||||
|
char setupCode[10];
|
||||||
|
|
||||||
|
sscanf(s," %9[0-9]",setupCode);
|
||||||
|
|
||||||
|
if(strlen(setupCode)!=8){
|
||||||
|
LOG0("\n*** Invalid request to change Setup Code. Code must be exactly 8 digits.\n\n");
|
||||||
|
return(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!network.allowedCode(setupCode)){
|
||||||
|
LOG0("\n*** Invalid request to change Setup Code. Code too simple.\n\n");
|
||||||
|
return(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
TempBuffer<Verification> verifyData; // temporary storage for verification data
|
||||||
|
SRP6A *srp=new SRP6A; // create instance of SRP
|
||||||
|
|
||||||
|
LOG0("\nGenerating SRP verification data for new Setup Code: %.3s-%.2s-%.3s ... ",setupCode,setupCode+3,setupCode+5);
|
||||||
|
|
||||||
|
srp->createVerifyCode(setupCode,verifyData.get()->verifyCode,verifyData.get()->salt); // create verification code with random salt from specified Setup Code
|
||||||
|
nvs_set_blob(HAPClient::srpNVS,"VERIFYDATA",&verifyData,sizeof(verifyData)); // update data
|
||||||
|
nvs_commit(HAPClient::srpNVS); // commit to NVS
|
||||||
|
|
||||||
|
LOG0("New Code Saved!\n");
|
||||||
|
LOG0("Setup Payload for Optional QR Code: %s\n\n",qrCode.get(atoi(setupCode),qrID,atoi(category)));
|
||||||
|
|
||||||
|
delete srp;
|
||||||
|
return(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
Span& Span::setWifiCredentials(const char *ssid, const char *pwd){
|
Span& Span::setWifiCredentials(const char *ssid, const char *pwd){
|
||||||
sprintf(network.wifiData.ssid,"%.*s",MAX_SSID,ssid);
|
sprintf(network.wifiData.ssid,"%.*s",MAX_SSID,ssid);
|
||||||
sprintf(network.wifiData.pwd,"%.*s",MAX_PWD,pwd);
|
sprintf(network.wifiData.pwd,"%.*s",MAX_PWD,pwd);
|
||||||
|
|
|
||||||
|
|
@ -364,7 +364,7 @@ class Span{
|
||||||
Span& setStatusCallback(void (*f)(HS_STATUS status)){statusCallback=f;return(*this);} // sets an optional user-defined function to call when HomeSpan status changes
|
Span& setStatusCallback(void (*f)(HS_STATUS status)){statusCallback=f;return(*this);} // sets an optional user-defined function to call when HomeSpan status changes
|
||||||
const char* statusString(HS_STATUS s); // returns char string for HomeSpan status change messages
|
const char* statusString(HS_STATUS s); // returns char string for HomeSpan status change messages
|
||||||
|
|
||||||
Span& setPairingCode(const char *s){sprintf(pairingCodeCommand,"S %9s",s);return(*this);} // sets the Pairing Code - use is NOT recommended. Use 'S' from CLI instead
|
Span& setPairingCode(const char *s); // {sprintf(pairingCodeCommand,"S %9s",s);return(*this);} // sets the Pairing Code - use is NOT recommended. Use 'S' from CLI instead
|
||||||
void deleteStoredValues(){processSerialCommand("V");} // deletes stored Characteristic values from NVS
|
void deleteStoredValues(){processSerialCommand("V");} // deletes stored Characteristic values from NVS
|
||||||
|
|
||||||
int enableOTA(boolean auth=true, boolean safeLoad=true){return(spanOTA.init(auth, safeLoad, NULL));} // enables Over-the-Air updates, with (auth=true) or without (auth=false) authorization password
|
int enableOTA(boolean auth=true, boolean safeLoad=true){return(spanOTA.init(auth, safeLoad, NULL));} // enables Over-the-Air updates, with (auth=true) or without (auth=false) authorization password
|
||||||
|
|
|
||||||
50
src/SRP.cpp
50
src/SRP.cpp
|
|
@ -39,19 +39,6 @@ SRP6A::SRP6A(){
|
||||||
uint8_t tBuf[768]; // temporary buffer for staging
|
uint8_t tBuf[768]; // temporary buffer for staging
|
||||||
uint8_t tHash[64]; // temporary buffer for storing SHA-512 results
|
uint8_t tHash[64]; // temporary buffer for storing SHA-512 results
|
||||||
|
|
||||||
char N3072[]="FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74"
|
|
||||||
"020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437"
|
|
||||||
"4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
|
||||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05"
|
|
||||||
"98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB"
|
|
||||||
"9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
|
||||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
|
|
||||||
"3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33"
|
|
||||||
"A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
|
|
||||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864"
|
|
||||||
"D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2"
|
|
||||||
"08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
|
|
||||||
|
|
||||||
// initialize MPI structures
|
// initialize MPI structures
|
||||||
|
|
||||||
mbedtls_mpi_init(&N);
|
mbedtls_mpi_init(&N);
|
||||||
|
|
@ -85,21 +72,47 @@ SRP6A::SRP6A(){
|
||||||
mbedtls_mpi_write_binary(&g,tBuf+384,384); // write g into second half of staging buffer (fully padded with leading zeros)
|
mbedtls_mpi_write_binary(&g,tBuf+384,384); // write g into second half of staging buffer (fully padded with leading zeros)
|
||||||
mbedtls_sha512_ret(tBuf,768,tHash,0); // create hash of data
|
mbedtls_sha512_ret(tBuf,768,tHash,0); // create hash of data
|
||||||
mbedtls_mpi_read_binary(&k,tHash,64); // load hash result into mpi structure k
|
mbedtls_mpi_read_binary(&k,tHash,64); // load hash result into mpi structure k
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
SRP6A::~SRP6A(){
|
||||||
|
|
||||||
|
mbedtls_mpi_free(&N);
|
||||||
|
mbedtls_mpi_free(&g);
|
||||||
|
mbedtls_mpi_free(&s);
|
||||||
|
mbedtls_mpi_free(&x);
|
||||||
|
mbedtls_mpi_free(&v);
|
||||||
|
mbedtls_mpi_free(&A);
|
||||||
|
mbedtls_mpi_free(&b);
|
||||||
|
mbedtls_mpi_free(&B);
|
||||||
|
mbedtls_mpi_free(&S);
|
||||||
|
mbedtls_mpi_free(&k);
|
||||||
|
mbedtls_mpi_free(&u);
|
||||||
|
mbedtls_mpi_free(&K);
|
||||||
|
mbedtls_mpi_free(&M1);
|
||||||
|
mbedtls_mpi_free(&M1V);
|
||||||
|
mbedtls_mpi_free(&M2);
|
||||||
|
mbedtls_mpi_free(&_rr);
|
||||||
|
mbedtls_mpi_free(&t1);
|
||||||
|
mbedtls_mpi_free(&t2);
|
||||||
|
mbedtls_mpi_free(&t3);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
void SRP6A::createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t *salt){
|
void SRP6A::createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t *salt){
|
||||||
|
|
||||||
uint8_t tBuf[80]; // temporary buffer for staging
|
TempBuffer<uint8_t> tBuf(80); // temporary buffer for staging
|
||||||
uint8_t tHash[64]; // temporary buffer for storing SHA-512 results
|
TempBuffer<uint8_t> tHash(64); // temporary buffer for storing SHA-512 results
|
||||||
char icp[22]; // storage for I:P
|
char *icp; // storage for I:P
|
||||||
|
|
||||||
randombytes_buf(salt,16); // generate 16 random bytes using libsodium (which uses the ESP32 hardware-based random number generator)
|
randombytes_buf(salt,16); // generate 16 random bytes using libsodium (which uses the ESP32 hardware-based random number generator)
|
||||||
mbedtls_mpi_read_binary(&s,salt,16);
|
mbedtls_mpi_read_binary(&s,salt,16);
|
||||||
|
|
||||||
sprintf(icp,"Pair-Setup:%.3s-%.2s-%.3s",setupCode,setupCode+3,setupCode+5);
|
asprintf(&icp,"Pair-Setup:%.3s-%.2s-%.3s",setupCode,setupCode+3,setupCode+5);
|
||||||
|
|
||||||
// compute x = SHA512( s | SHA512( I | ":" | P ) )
|
// compute x = SHA512( s | SHA512( I | ":" | P ) )
|
||||||
|
|
||||||
|
|
@ -112,7 +125,8 @@ void SRP6A::createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t
|
||||||
|
|
||||||
mbedtls_mpi_exp_mod(&v,&g,&x,&N,&_rr); // create verifier, v (_rr is an internal "helper" structure that mbedtls uses to speed up subsequent exponential calculations)
|
mbedtls_mpi_exp_mod(&v,&g,&x,&N,&_rr); // create verifier, v (_rr is an internal "helper" structure that mbedtls uses to speed up subsequent exponential calculations)
|
||||||
mbedtls_mpi_write_binary(&v,verifyCode,384); // write v into verifyCode
|
mbedtls_mpi_write_binary(&v,verifyCode,384); // write v into verifyCode
|
||||||
|
|
||||||
|
free(icp);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
|
||||||
28
src/SRP.h
28
src/SRP.h
|
|
@ -31,7 +31,17 @@
|
||||||
#include <mbedtls/bignum.h>
|
#include <mbedtls/bignum.h>
|
||||||
#include <mbedtls/base64.h>
|
#include <mbedtls/base64.h>
|
||||||
|
|
||||||
#include "HAPConstants.h"
|
#if defined(BOARD_HAS_PSRAM)
|
||||||
|
#define HS_MALLOC ps_malloc
|
||||||
|
#define HS_CALLOC ps_calloc
|
||||||
|
#define HS_REALLOC ps_realloc
|
||||||
|
#define ps_new(X) new(ps_malloc(sizeof(X)))X
|
||||||
|
#else
|
||||||
|
#define HS_MALLOC malloc
|
||||||
|
#define HS_CALLOC calloc
|
||||||
|
#define HS_REALLOC realloc
|
||||||
|
#define ps_new(X) new X
|
||||||
|
#endif
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
// SRP-6A Structure from RFC 5054 (Nov 2007)
|
// SRP-6A Structure from RFC 5054 (Nov 2007)
|
||||||
|
|
@ -41,6 +51,19 @@
|
||||||
// I = SRP-6A username, defined by HAP to be the word "Pair-Setup"
|
// I = SRP-6A username, defined by HAP to be the word "Pair-Setup"
|
||||||
// P = SRP-6A password, defined to be equal to the accessory's 8-digit setup code in the format "XXX-XX-XXX"
|
// P = SRP-6A password, defined to be equal to the accessory's 8-digit setup code in the format "XXX-XX-XXX"
|
||||||
|
|
||||||
|
const char N3072[]="FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74"
|
||||||
|
"020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437"
|
||||||
|
"4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
||||||
|
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05"
|
||||||
|
"98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB"
|
||||||
|
"9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
||||||
|
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
|
||||||
|
"3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33"
|
||||||
|
"A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
|
||||||
|
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864"
|
||||||
|
"D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2"
|
||||||
|
"08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
|
||||||
|
|
||||||
struct SRP6A {
|
struct SRP6A {
|
||||||
|
|
||||||
mbedtls_mpi N; // N - 3072-bit Group pre-defined prime used for all SRP-6A calculations (384 bytes)
|
mbedtls_mpi N; // N - 3072-bit Group pre-defined prime used for all SRP-6A calculations (384 bytes)
|
||||||
|
|
@ -71,6 +94,9 @@ struct SRP6A {
|
||||||
uint8_t sharedSecret[64]; // permanent storage for binary version of SHARED SECRET KEY for ease of use upstream
|
uint8_t sharedSecret[64]; // permanent storage for binary version of SHARED SECRET KEY for ease of use upstream
|
||||||
|
|
||||||
SRP6A(); // initializes N, G, and computes k
|
SRP6A(); // initializes N, G, and computes k
|
||||||
|
~SRP6A();
|
||||||
|
|
||||||
|
void *operator new(size_t size){return(HS_MALLOC(size));} // override new operator to use PSRAM when available
|
||||||
|
|
||||||
void createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t *salt);
|
void createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t *salt);
|
||||||
void loadVerifyCode(uint8_t *verifyCode, uint8_t *salt);
|
void loadVerifyCode(uint8_t *verifyCode, uint8_t *salt);
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class TempBuffer {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TempBuffer(size_t _nElements) : nElements(_nElements) {
|
TempBuffer(size_t _nElements=1) : nElements(_nElements) {
|
||||||
buf=(bufType *)HS_MALLOC(nElements*sizeof(bufType));
|
buf=(bufType *)HS_MALLOC(nElements*sizeof(bufType));
|
||||||
if(buf==NULL){
|
if(buf==NULL){
|
||||||
Serial.printf("\n\n*** FATAL ERROR: Requested allocation of %d bytes failed. Program Halting.\n\n",nElements*sizeof(bufType));
|
Serial.printf("\n\n*** FATAL ERROR: Requested allocation of %d bytes failed. Program Halting.\n\n",nElements*sizeof(bufType));
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ void setup() {
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
homeSpan.setLogLevel(2);
|
homeSpan.setLogLevel(2); // .setPairingCode("33344456");
|
||||||
|
|
||||||
homeSpan.begin(Category::Lighting,"HomeSpan Max");
|
homeSpan.begin(Category::Lighting,"HomeSpan Max");
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue