In process of updated Pair-Setup M3...
Cleaning up code by replacing calls to mbedTLS within Pair-Setup with arguments passed to/from SRP6A. Much better and better encapsulates SRP6A
This commit is contained in:
parent
c529f93646
commit
6979ab8080
44
src/HAP.cpp
44
src/HAP.cpp
|
|
@ -384,15 +384,17 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
|
||||||
};
|
};
|
||||||
|
|
||||||
auto itPublicKey=responseTLV.add(kTLVType_PublicKey,384,NULL); // create blank PublicKey TLV with space for 384 bytes
|
auto itPublicKey=responseTLV.add(kTLVType_PublicKey,384,NULL); // create blank PublicKey TLV with space for 384 bytes
|
||||||
auto itSalt=responseTLV.add(kTLVType_Salt,16,NULL); // create blank Salt TLV with space for 16 bytes
|
|
||||||
|
|
||||||
srp=new SRP6A; // create instance of SRP to persist until Pairing is fully complete
|
if(srp==NULL) // create instance of SRP (if not already created) to persist until Pairing is fully complete
|
||||||
TempBuffer<Verification> verifyData; // temporary storage for verification data
|
srp=new SRP6A;
|
||||||
|
|
||||||
|
TempBuffer<Verification> verifyData; // retrieve verification data (should already be stored in NVS)
|
||||||
size_t len=verifyData.len();
|
size_t len=verifyData.len();
|
||||||
nvs_get_blob(srpNVS,"VERIFYDATA",verifyData,&len); // load verification data (should already be stored in NVS)
|
nvs_get_blob(srpNVS,"VERIFYDATA",verifyData,&len);
|
||||||
srp->createPublicKey(verifyData.get()->verifyCode,verifyData.get()->salt); // create accessory Public Key from stored verification data (which was originally derived from Pair-Setup Code)
|
|
||||||
mbedtls_mpi_write_binary(&srp->B,*itPublicKey,(*itPublicKey).len); // write resulting server PublicKey, B, into TLV
|
responseTLV.add(kTLVType_Salt,16,verifyData.get()->salt); // write Salt from verification data into TLV
|
||||||
mbedtls_mpi_write_binary(&srp->s,*itSalt,(*itSalt).len); // write Salt, s, into TLV
|
|
||||||
|
srp->createPublicKey(verifyData,*itPublicKey); // create accessory Public Key from stored verification data and write result into PublicKey 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
|
||||||
|
|
@ -402,39 +404,37 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
|
||||||
|
|
||||||
case pairState_M3:{ // 'SRP Verify Request'
|
case pairState_M3:{ // 'SRP Verify Request'
|
||||||
|
|
||||||
|
responseTLV.add(kTLVType_State,pairState_M4); // set State=<M4>
|
||||||
|
|
||||||
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(iosTLV.len(itPublicKey)<=0 || iosTLV.len(itClientProof)<=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_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
|
responseTLV.add(kTLVType_Error,tagError_Unknown); // set Error=Unknown (there is no specific error type for missing/bad TLV data)
|
||||||
tlvRespond(responseTLV); // send response to client
|
tlvRespond(responseTLV); // send response to client
|
||||||
pairStatus=pairState_M1; // reset pairStatus to first step of unpaired
|
pairStatus=pairState_M1; // reset pairStatus to first step of unpaired
|
||||||
return(0);
|
return(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
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(*itPublicKey,(*itPublicKey).len); // create session key, K, from client Public Key, A
|
||||||
|
|
||||||
if(!srp->verifyProof()){ // verify client Proof, M1
|
if(!srp->verifyClientProof(*itClientProof,(*itClientProof).len)){ // 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_Error,tagError_Authentication); // set Error=Authentication
|
||||||
responseTLV.add(kTLVType_Error,tagError_Authentication); // set Error=Authentication
|
tlvRespond(responseTLV); // send response to client
|
||||||
tlvRespond(responseTLV); // send response to client
|
pairStatus=pairState_M1; // reset pairStatus to first step of unpaired
|
||||||
pairStatus=pairState_M1; // reset pairStatus to first step of unpaired
|
|
||||||
return(0);
|
return(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
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>
|
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);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
10
src/HAP.h
10
src/HAP.h
|
|
@ -51,15 +51,7 @@ 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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1205,7 +1205,7 @@ Span& Span::setPairingCode(const char *s){
|
||||||
|
|
||||||
LOG0("\nGenerating SRP verification data for new Setup Code: %.3s-%.2s-%.3s ... ",setupCode,setupCode+3,setupCode+5);
|
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
|
srp->createVerifyCode(setupCode,verifyData); // create random salt and compute verification code from specified Setup Code
|
||||||
nvs_set_blob(HAPClient::srpNVS,"VERIFYDATA",verifyData,verifyData.len()); // update data
|
nvs_set_blob(HAPClient::srpNVS,"VERIFYDATA",verifyData,verifyData.len()); // update data
|
||||||
nvs_commit(HAPClient::srpNVS); // commit to NVS
|
nvs_commit(HAPClient::srpNVS); // commit to NVS
|
||||||
|
|
||||||
|
|
|
||||||
45
src/SRP.cpp
45
src/SRP.cpp
|
|
@ -93,7 +93,7 @@ SRP6A::~SRP6A(){
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
void SRP6A::createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t *salt){
|
void SRP6A::createVerifyCode(const char *setupCode, Verification *vData){
|
||||||
|
|
||||||
TempBuffer<uint8_t> tBuf(80); // temporary buffer for staging
|
TempBuffer<uint8_t> tBuf(80); // temporary buffer for staging
|
||||||
TempBuffer<uint8_t> tHash(64); // temporary buffer for storing SHA-512 results
|
TempBuffer<uint8_t> tHash(64); // temporary buffer for storing SHA-512 results
|
||||||
|
|
@ -101,7 +101,7 @@ void SRP6A::createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t
|
||||||
|
|
||||||
// generate random salt, s
|
// generate random salt, s
|
||||||
|
|
||||||
randombytes_buf(salt,16); // generate 16 random bytes for salt
|
randombytes_buf(vData->salt,16); // generate 16 random bytes for salt
|
||||||
|
|
||||||
// create I:P
|
// create I:P
|
||||||
|
|
||||||
|
|
@ -109,7 +109,7 @@ void SRP6A::createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t
|
||||||
|
|
||||||
// compute x = SHA512( s | SHA512( I | ":" | P ) )
|
// compute x = SHA512( s | SHA512( I | ":" | P ) )
|
||||||
|
|
||||||
memcpy(tBuf,salt,16); // write salt into first 16 bytes of staging buffer
|
memcpy(tBuf,vData->salt,16); // write salt into first 16 bytes of staging buffer
|
||||||
mbedtls_sha512_ret((uint8_t *)icp,strlen(icp),tBuf+16,0); // create hash of username:password and write into last 64 bytes of staging buffer
|
mbedtls_sha512_ret((uint8_t *)icp,strlen(icp),tBuf+16,0); // create hash of username:password and write into last 64 bytes of staging buffer
|
||||||
mbedtls_sha512_ret(tBuf,80,tHash,0); // create second hash of salted, hashed username:password
|
mbedtls_sha512_ret(tBuf,80,tHash,0); // create second hash of salted, hashed username:password
|
||||||
mbedtls_mpi_read_binary(&x,tHash,64); // load hash result into x
|
mbedtls_mpi_read_binary(&x,tHash,64); // load hash result into x
|
||||||
|
|
@ -117,14 +117,14 @@ void SRP6A::createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t
|
||||||
// compute v = g^x %N
|
// compute v = g^x %N
|
||||||
|
|
||||||
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,vData->verifyCode,384); // write v into verifyCode
|
||||||
|
|
||||||
free(icp);
|
free(icp);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
void SRP6A::createPublicKey(const uint8_t *verifyCode, const uint8_t *salt){
|
void SRP6A::createPublicKey(const Verification *vData, uint8_t *publicKey){
|
||||||
|
|
||||||
TempBuffer<uint8_t> tBuf(768); // temporary buffer for staging
|
TempBuffer<uint8_t> tBuf(768); // temporary buffer for staging
|
||||||
TempBuffer<uint8_t> tHash(64); // temporary buffer for storing SHA-512 results
|
TempBuffer<uint8_t> tHash(64); // temporary buffer for storing SHA-512 results
|
||||||
|
|
@ -132,8 +132,8 @@ void SRP6A::createPublicKey(const uint8_t *verifyCode, const uint8_t *salt){
|
||||||
|
|
||||||
// load stored salt, s, and verification code, v
|
// load stored salt, s, and verification code, v
|
||||||
|
|
||||||
mbedtls_mpi_read_binary(&s,salt,16); // load salt into s for use in later steps
|
mbedtls_mpi_read_binary(&s,vData->salt,16); // load salt into s for use in later steps
|
||||||
mbedtls_mpi_read_binary(&v,verifyCode,384); // load verifyCode into v for use below
|
mbedtls_mpi_read_binary(&v,vData->verifyCode,384); // load verifyCode into v for use below
|
||||||
|
|
||||||
// generate random private key, b
|
// generate random private key, b
|
||||||
|
|
||||||
|
|
@ -154,19 +154,23 @@ void SRP6A::createPublicKey(const uint8_t *verifyCode, const uint8_t *salt){
|
||||||
mbedtls_mpi_add_mpi(&t3,&t1,&t2); // t3 = t1 + t2
|
mbedtls_mpi_add_mpi(&t3,&t1,&t2); // t3 = t1 + t2
|
||||||
mbedtls_mpi_mod_mpi(&B,&t3,&N); // B = t3 %N = ACCESSORY PUBLIC KEY
|
mbedtls_mpi_mod_mpi(&B,&t3,&N); // B = t3 %N = ACCESSORY PUBLIC KEY
|
||||||
|
|
||||||
|
mbedtls_mpi_write_binary(&B,publicKey,384); // write B into publicKey
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
void SRP6A::createSessionKey(){
|
void SRP6A::createSessionKey(const uint8_t *publicKey, size_t len){
|
||||||
|
|
||||||
uint8_t tBuf[768]; // temporary buffer for staging
|
TempBuffer<uint8_t> tBuf(768); // 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
|
||||||
|
|
||||||
|
mbedtls_mpi_read_binary(&A,publicKey,len); // load client PublicKey into A
|
||||||
|
|
||||||
// compute u = SHA512( PAD(A) | PAD(B) )
|
// compute u = SHA512( PAD(A) | PAD(B) )
|
||||||
|
|
||||||
mbedtls_mpi_write_binary(&A,tBuf,384); // write A into first half of staging buffer
|
mbedtls_mpi_write_binary(&A,tBuf,384); // write A into first half of staging buffer (will pad to fill 384 bytes)
|
||||||
mbedtls_mpi_write_binary(&B,tBuf+384,384); // write B into second half of staging buffer
|
mbedtls_mpi_write_binary(&B,tBuf+384,384); // write B into second half of staging buffer (will pad to fill 384 bytes)
|
||||||
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(&u,tHash,64); // load hash result into mpi structure u
|
mbedtls_mpi_read_binary(&u,tHash,64); // load hash result into mpi structure u
|
||||||
|
|
||||||
|
|
@ -189,14 +193,19 @@ void SRP6A::createSessionKey(){
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
int SRP6A::verifyProof(){
|
|
||||||
|
|
||||||
uint8_t tBuf[976]; // temporary buffer for staging
|
int SRP6A::verifyClientProof(const uint8_t *proof, size_t len){
|
||||||
uint8_t tHash[64]; // temporary buffer for storing SHA-512 results
|
|
||||||
|
|
||||||
size_t count=0; // total number of bytes for final hash
|
TempBuffer<uint8_t> tBuf(976); // temporary buffer for staging
|
||||||
|
TempBuffer<uint8_t> tHash(64); // temporary buffer for storing SHA-512 results
|
||||||
|
|
||||||
|
mbedtls_mpi_read_binary(&M1,proof,len); // load client Proof into M1
|
||||||
|
|
||||||
|
size_t count=0; // total number of bytes for final hash
|
||||||
size_t sLen;
|
size_t sLen;
|
||||||
|
|
||||||
|
// compute M1V
|
||||||
|
|
||||||
mbedtls_mpi_write_binary(&N,tBuf,384); // write N into staging buffer
|
mbedtls_mpi_write_binary(&N,tBuf,384); // write N into staging buffer
|
||||||
mbedtls_sha512_ret(tBuf,384,tHash,0); // create hash of data
|
mbedtls_sha512_ret(tBuf,384,tHash,0); // create hash of data
|
||||||
mbedtls_sha512_ret(&g3072,1,tBuf,0); // create hash of g, but place output directly into staging buffer
|
mbedtls_sha512_ret(&g3072,1,tBuf,0); // create hash of g, but place output directly into staging buffer
|
||||||
|
|
@ -221,6 +230,8 @@ int SRP6A::verifyProof(){
|
||||||
|
|
||||||
mbedtls_sha512_ret(tBuf,count,tHash,0); // create hash of data
|
mbedtls_sha512_ret(tBuf,count,tHash,0); // create hash of data
|
||||||
mbedtls_mpi_read_binary(&M1V,tHash,64); // load hash result into mpi structure M1V
|
mbedtls_mpi_read_binary(&M1V,tHash,64); // load hash result into mpi structure M1V
|
||||||
|
|
||||||
|
// check that client Proof M1 matches M1V
|
||||||
|
|
||||||
if(!mbedtls_mpi_cmp_mpi(&M1,&M1V)) // cmp_mpi uses same logic as strcmp: returns 0 if EQUAL, otherwise +/- 1
|
if(!mbedtls_mpi_cmp_mpi(&M1,&M1V)) // cmp_mpi uses same logic as strcmp: returns 0 if EQUAL, otherwise +/- 1
|
||||||
return(1); // success - proof from HAP Client is verified
|
return(1); // success - proof from HAP Client is verified
|
||||||
|
|
|
||||||
16
src/SRP.h
16
src/SRP.h
|
|
@ -43,6 +43,14 @@
|
||||||
#define ps_new(X) new X
|
#define ps_new(X) new X
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// Pair-Setup Code Verification Data and Salt
|
||||||
|
|
||||||
|
struct Verification {
|
||||||
|
uint8_t salt[16];
|
||||||
|
uint8_t verifyCode[384];
|
||||||
|
};
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
// SRP-6A Structure from RFC 5054 (Nov 2007)
|
// SRP-6A Structure from RFC 5054 (Nov 2007)
|
||||||
// ** HAP uses N=3072-bit Group specified in RFC 5054 with Generator g=5
|
// ** HAP uses N=3072-bit Group specified in RFC 5054 with Generator g=5
|
||||||
|
|
@ -98,10 +106,10 @@ struct SRP6A {
|
||||||
|
|
||||||
void *operator new(size_t size){return(HS_MALLOC(size));} // override new operator to use PSRAM when available
|
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); // generates random s and computes v from specified 8-digit Pairing-Setup Code
|
void createVerifyCode(const char *setupCode, Verification *vData); // generates random s and computes v; writes back resulting verification data
|
||||||
void createPublicKey(const uint8_t *verifyCode, const uint8_t *salt); // generates random b and computes k and B from specified v and s
|
void createPublicKey(const Verification *vData, uint8_t *publicKey); // generates random b and computes k and B; writes back resulting accessory public key
|
||||||
void createSessionKey(); // computes u from A and B, and then S from A, v, u, and b
|
void createSessionKey(const uint8_t *publicKey, size_t len); // computes u, S, and K from controller public key, A
|
||||||
int verifyProof(); // verify M1 SRP6A Proof received from HAP client (return 1 on success, 0 on failure)
|
int verifyClientProof(const uint8_t *proof, size_t len); // 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
|
||||||
|
|
||||||
void print(mbedtls_mpi *mpi); // prints size of mpi (in bytes), followed by the mpi itself (as a hex character string)
|
void print(mbedtls_mpi *mpi); // prints size of mpi (in bytes), followed by the mpi itself (as a hex character string)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue