hap_pair_setup.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #include <string.h>
  2. #include "hap.h"
  3. #include "hap_internal.h"
  4. #include "srp.h"
  5. #include "tlv8.h"
  6. #include "esp_log.h"
  7. #include "sodium.h"
  8. static const char *TAG = "hap_setup";
  9. #define TLV_TYPE_METHOD 0x00
  10. #define TLV_TYPE_SALT 0x02
  11. #define TLV_TYPE_PROOF 0x04
  12. #define TLV_TYPE_FLAGS 0x13
  13. #define PAIR_SETUP_M1 1
  14. #define PAIR_SETUP_M2 2
  15. #define PAIR_SETUP_M3 3
  16. #define PAIR_SETUP_M4 4
  17. #define PAIR_SETUP_M5 5
  18. #define PAIR_SETUP_M6 6
  19. esp_err_t hap_pair_setup_m1(hap_session_t *session, const uint8_t *input,
  20. size_t input_len, uint8_t *output,
  21. size_t output_capacity, size_t *output_len) {
  22. size_t state_len = 0;
  23. size_t flags_len = 0;
  24. const uint8_t *state =
  25. tlv8_find(input, input_len, TLV_TYPE_STATE, &state_len);
  26. const uint8_t *flags =
  27. tlv8_find(input, input_len, TLV_TYPE_FLAGS, &flags_len);
  28. if (!state || state_len != 1 || state[0] != PAIR_SETUP_M1) {
  29. ESP_LOGE(TAG, "Invalid pair-setup M1 state");
  30. return ESP_ERR_INVALID_ARG;
  31. }
  32. bool transient = false;
  33. if (flags && flags_len == 1) {
  34. transient = (flags[0] & 0x10) != 0;
  35. }
  36. session->pair_setup_transient = transient;
  37. if (session->srp) {
  38. srp_session_free(session->srp);
  39. }
  40. session->srp = srp_session_create();
  41. if (!session->srp) {
  42. ESP_LOGE(TAG, "Failed to create SRP session");
  43. return ESP_ERR_NO_MEM;
  44. }
  45. const char *password = transient ? "3939" : "0000";
  46. esp_err_t err = srp_start(session->srp, "Pair-Setup", password);
  47. if (err != ESP_OK) {
  48. ESP_LOGE(TAG, "Failed to start SRP: %d", err);
  49. return err;
  50. }
  51. size_t pk_len = 0;
  52. const uint8_t *salt = srp_get_salt(session->srp);
  53. const uint8_t *pk = srp_get_public_key(session->srp, &pk_len);
  54. tlv8_encoder_t enc;
  55. tlv8_encoder_init(&enc, output, output_capacity);
  56. tlv8_encode_byte(&enc, TLV_TYPE_STATE, PAIR_SETUP_M2);
  57. tlv8_encode(&enc, TLV_TYPE_SALT, salt, SRP_SALT_BYTES);
  58. tlv8_encode(&enc, TLV_TYPE_PUBLIC_KEY, pk, pk_len);
  59. *output_len = tlv8_encoder_size(&enc);
  60. session->pair_setup_state = PAIR_SETUP_M2;
  61. return ESP_OK;
  62. }
  63. esp_err_t hap_pair_setup_m3(hap_session_t *session, const uint8_t *input,
  64. size_t input_len, uint8_t *output,
  65. size_t output_capacity, size_t *output_len) {
  66. if (!session->srp) {
  67. ESP_LOGE(TAG, "No SRP session for M3");
  68. return ESP_ERR_INVALID_STATE;
  69. }
  70. size_t state_len = 0;
  71. size_t pk_len = 0;
  72. size_t proof_len = 0;
  73. const uint8_t *state =
  74. tlv8_find(input, input_len, TLV_TYPE_STATE, &state_len);
  75. if (!state || state_len != 1 || state[0] != PAIR_SETUP_M3) {
  76. ESP_LOGE(TAG, "Invalid pair-setup M3 state");
  77. return ESP_ERR_INVALID_ARG;
  78. }
  79. uint8_t client_pk[512];
  80. if (!tlv8_decode_concat(input, input_len, TLV_TYPE_PUBLIC_KEY, client_pk,
  81. sizeof(client_pk), &pk_len)) {
  82. ESP_LOGE(TAG, "Missing client public key in M3");
  83. return ESP_ERR_INVALID_ARG;
  84. }
  85. uint8_t client_proof[64];
  86. if (!tlv8_decode_concat(input, input_len, TLV_TYPE_PROOF, client_proof,
  87. sizeof(client_proof), &proof_len)) {
  88. ESP_LOGE(TAG, "Missing client proof in M3");
  89. return ESP_ERR_INVALID_ARG;
  90. }
  91. esp_err_t err = srp_verify_client(session->srp, client_pk, pk_len,
  92. client_proof, proof_len);
  93. if (err != ESP_OK) {
  94. ESP_LOGE(TAG, "Client verification failed");
  95. tlv8_encoder_t enc;
  96. tlv8_encoder_init(&enc, output, output_capacity);
  97. tlv8_encode_byte(&enc, TLV_TYPE_STATE, PAIR_SETUP_M4);
  98. tlv8_encode_byte(&enc, TLV_TYPE_ERROR, 0x02);
  99. *output_len = tlv8_encoder_size(&enc);
  100. return ESP_OK;
  101. }
  102. if (session->pair_setup_transient) {
  103. size_t srp_key_len = 0;
  104. const uint8_t *srp_key = srp_get_session_key(session->srp, &srp_key_len);
  105. if (!srp_key || srp_key_len == 0) {
  106. ESP_LOGE(TAG, "Missing SRP session key for transient pairing");
  107. return ESP_ERR_INVALID_STATE;
  108. }
  109. memcpy(session->shared_secret, srp_key, 32);
  110. hap_hkdf_sha512((uint8_t *)"Control-Salt", 12, srp_key, srp_key_len,
  111. (uint8_t *)"Control-Read-Encryption-Key", 27,
  112. session->encrypt_key, 32);
  113. hap_hkdf_sha512((uint8_t *)"Control-Salt", 12, srp_key, srp_key_len,
  114. (uint8_t *)"Control-Write-Encryption-Key", 28,
  115. session->decrypt_key, 32);
  116. session->encrypt_nonce = 0;
  117. session->decrypt_nonce = 0;
  118. session->session_established = true;
  119. }
  120. const uint8_t *server_proof = srp_get_proof(session->srp);
  121. tlv8_encoder_t enc;
  122. tlv8_encoder_init(&enc, output, output_capacity);
  123. tlv8_encode_byte(&enc, TLV_TYPE_STATE, PAIR_SETUP_M4);
  124. tlv8_encode(&enc, TLV_TYPE_PROOF, server_proof, SRP_PROOF_BYTES);
  125. *output_len = tlv8_encoder_size(&enc);
  126. session->pair_setup_state = PAIR_SETUP_M4;
  127. return ESP_OK;
  128. }
  129. esp_err_t hap_pair_setup_m5(hap_session_t *session, const uint8_t *input,
  130. size_t input_len, uint8_t *output,
  131. size_t output_capacity, size_t *output_len) {
  132. (void)output;
  133. (void)output_capacity;
  134. (void)output_len;
  135. if (!session->srp) {
  136. ESP_LOGE(TAG, "No SRP session for M5");
  137. return ESP_ERR_INVALID_STATE;
  138. }
  139. size_t state_len = 0;
  140. const uint8_t *state =
  141. tlv8_find(input, input_len, TLV_TYPE_STATE, &state_len);
  142. if (!state || state_len != 1 || state[0] != PAIR_SETUP_M5) {
  143. ESP_LOGE(TAG, "Invalid pair-setup M5 state");
  144. return ESP_ERR_INVALID_ARG;
  145. }
  146. uint8_t encrypted[512];
  147. size_t encrypted_len = 0;
  148. if (!tlv8_decode_concat(input, input_len, TLV_TYPE_ENCRYPTED_DATA, encrypted,
  149. sizeof(encrypted), &encrypted_len)) {
  150. ESP_LOGE(TAG, "Missing encrypted data in M5");
  151. return ESP_ERR_INVALID_ARG;
  152. }
  153. size_t srp_key_len = 0;
  154. const uint8_t *srp_key = srp_get_session_key(session->srp, &srp_key_len);
  155. if (!srp_key || srp_key_len == 0) {
  156. ESP_LOGE(TAG, "Missing SRP session key");
  157. return ESP_ERR_INVALID_STATE;
  158. }
  159. uint8_t setup_key[32];
  160. hap_hkdf_sha512((uint8_t *)"Pair-Setup-Encrypt-Salt", 23, srp_key,
  161. srp_key_len, (uint8_t *)"Pair-Setup-Encrypt-Info", 23,
  162. setup_key, 32);
  163. uint8_t nonce[12] = {0, 0, 0, 0, 'P', 'S', '-', 'M', 's', 'g', '0', '5'};
  164. uint8_t decrypted[512];
  165. unsigned long long decrypted_len = 0;
  166. if (crypto_aead_chacha20poly1305_ietf_decrypt(decrypted, &decrypted_len, NULL,
  167. encrypted, encrypted_len, NULL,
  168. 0, nonce, setup_key) != 0) {
  169. ESP_LOGE(TAG, "M5 decryption failed");
  170. return ESP_FAIL;
  171. }
  172. session->encrypt_nonce = 0;
  173. session->decrypt_nonce = 0;
  174. return ESP_OK;
  175. }