Current section

Files

Jump to
hap test hap pair_setup_test.exs
Raw

test/hap/pair_setup_test.exs

defmodule HAP.PairSetupTest do
use ExUnit.Case, async: false
setup do
{:ok, _pid} = HAP.Test.TestAccessoryServer.test_server() |> start_supervised()
:ok
end
test "a valid pair-setup flow results in a pairing being made" do
# A very quick & dirty implementation of the iOS side of the Pair-Setup flow
# Build our request parameters
port = HAP.AccessoryServerManager.port()
{:ok, client} = HAP.Test.HTTPClient.init(:localhost, port)
endpoint = "/pair-setup"
# Build M1
m1 = %{0x06 => <<1>>, 0x00 => <<0>>}
# Send M1
{:ok, 200, headers, body} =
HAP.Test.HTTPClient.post(client, endpoint, HAP.TLVEncoder.to_binary(m1),
"content-type": "application/pairing+tlv8"
)
assert Keyword.get(headers, :"content-type") == "application/pairing+tlv8"
# Verify M2 & Build M3
_m2 = %{0x06 => <<2>>, 0x03 => b, 0x02 => salt} = HAP.TLVParser.parse_tlv(body)
{:ok, auth_context, a} = HAP.Crypto.SRP6A.client("Pair-Setup", HAP.AccessoryServerManager.pairing_code(), salt)
{:ok, m_1, m_2, session_key} = HAP.Crypto.SRP6A.shared_key(auth_context, b, "Pair-Setup", salt)
m3 = %{0x06 => <<3>>, 0x03 => a, 0x04 => m_1}
# Send M3
{:ok, 200, headers, body} =
HAP.Test.HTTPClient.post(client, endpoint, HAP.TLVEncoder.to_binary(m3),
"content-type": "application/pairing+tlv8"
)
assert Keyword.get(headers, :"content-type") == "application/pairing+tlv8"
# Verify M4 & Build M5
_m4 = %{0x06 => <<4>>, 0x04 => ^m_2} = HAP.TLVParser.parse_tlv(body)
{:ok, ios_ltpk, ios_ltsk} = HAP.Crypto.EDDSA.key_gen()
{:ok, ios_device_x} =
HAP.Crypto.HKDF.generate(session_key, "Pair-Setup-Controller-Sign-Salt", "Pair-Setup-Controller-Sign-Info")
ios_identifier = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"
ios_device_info = ios_device_x <> ios_identifier <> ios_ltpk
{:ok, ios_signature} = HAP.Crypto.EDDSA.sign(ios_device_info, ios_ltsk)
sub_tlv = %{0x01 => ios_identifier, 0x03 => ios_ltpk, 0x0A => ios_signature}
{:ok, envelope_key} = HAP.Crypto.HKDF.generate(session_key, "Pair-Setup-Encrypt-Salt", "Pair-Setup-Encrypt-Info")
{:ok, encrypted_data_and_tag} =
HAP.Crypto.ChaCha20.encrypt_and_tag(HAP.TLVEncoder.to_binary(sub_tlv), envelope_key, "PS-Msg05")
m5 = %{0x06 => <<5>>, 0x05 => encrypted_data_and_tag}
# Send M5
{:ok, 200, headers, body} =
HAP.Test.HTTPClient.post(client, endpoint, HAP.TLVEncoder.to_binary(m5),
"content-type": "application/pairing+tlv8"
)
assert Keyword.get(headers, :"content-type") == "application/pairing+tlv8"
# Verify M6
_m6 = %{0x06 => <<6>>, 0x05 => encrypted_data} = HAP.TLVParser.parse_tlv(body)
{:ok, sub_tlv} = HAP.Crypto.ChaCha20.decrypt_and_verify(encrypted_data, envelope_key, "PS-Msg06")
accessory_identifier = HAP.AccessoryServerManager.identifier()
accessory_ltpk = HAP.AccessoryServerManager.ltpk()
%{0x01 => ^accessory_identifier, 0x03 => ^accessory_ltpk, 0x0A => accessory_signature} =
HAP.TLVParser.parse_tlv(sub_tlv)
{:ok, accessory_x} =
HAP.Crypto.HKDF.generate(session_key, "Pair-Setup-Accessory-Sign-Salt", "Pair-Setup-Accessory-Sign-Info")
accessory_info = accessory_x <> accessory_identifier <> accessory_ltpk
{:ok, true} = HAP.Crypto.EDDSA.verify(accessory_info, accessory_signature, accessory_ltpk)
# Finally, verify that we have successfully paired on the Accessory Server side
assert HAP.AccessoryServerManager.controller_pairing(ios_identifier) == {ios_ltpk, <<1>>}
end
end