Update pair_ap to 0.7 (fixes incorrect pair-list response)

This commit is contained in:
ejurgensen
2021-07-13 22:28:34 +02:00
parent a7047e41d7
commit 1959d2cf0c
3 changed files with 21 additions and 10 deletions
+7 -6
View File
@@ -2,9 +2,10 @@
C client implementation of pairing for: C client implementation of pairing for:
* Apple TV device verification, which became mandatory with tvOS 10.2 (this is * Apple TV device verification, which became mandatory with tvOS 10.2 (this is
called fruit mode in pair_ap) called fruit mode in pair_ap)
* Homekit pairing (for AirPlay 2, not working for Home app) * Homekit pairing (also for AirPlay 2)
Credit goes to @funtax and @ViktoriiaKh for doing some of the heavy lifting. Credit goes to @funtax and @ViktoriiaKh for doing some of the heavy lifting.
## Requirements ## Requirements
- libsodium - libsodium
- libgcrypt or libopenssl - libgcrypt or libopenssl
@@ -33,7 +34,7 @@ The controller uses `/pair-add` to make sure that all devices on a network get
the ID and public key of all the other devices, so that the user only needs to the ID and public key of all the other devices, so that the user only needs to
pair a device once. pair a device once.
### Normal pairing ### Normal pairing with one-time code
For a normal first-time pairing, the client needs a one-time code (the device For a normal first-time pairing, the client needs a one-time code (the device
announces via mDNS whether a code is required). The client calls announces via mDNS whether a code is required). The client calls
`/pair-pin-start` and the device displays the code. There is also QR-based `/pair-pin-start` and the device displays the code. There is also QR-based
@@ -42,12 +43,12 @@ pairing, which is (probably?) an encoded code.
After obtaining the code, the client initiates a three step `/pair-setup` After obtaining the code, the client initiates a three step `/pair-setup`
sequence, which results in both peers registering each other's ID and public sequence, which results in both peers registering each other's ID and public
key. Henceforth, a pairing is verified with the two step `/pair-verify`, where key. Henceforth, a pairing is verified with the two step `/pair-verify`, where
the parties check each-others identify. Saving the peer's ID + public key isn't the parties check eachothers identify. Saving the peer's ID + public key isn't
strictly necessary if client or server doesn't care about verifying the peer, strictly necessary if client or server doesn't care about verifying the peer,
i.e. that `/pair-setup` has actually been completed. i.e. that `/pair-setup` has actually been completed.
The result of `/pair-verify` is a shared secret that is used for symmetric The result of `/pair-verify` is a shared secret that is used for symmetric
encryption of the following communinacation between the parties. encryption of the following communication between the parties.
### Transient pairing ### Transient pairing
Some devices don't require a code from the user for pairing (e.g. an Airport Some devices don't require a code from the user for pairing (e.g. an Airport
@@ -55,8 +56,7 @@ Express 2). If so, the client just needs to go through a two-step `/pair-setup`
sequence which results in a shared secret, which is then used for encrypted sequence which results in a shared secret, which is then used for encrypted
communication. A fixed code of 3939 is used. communication. A fixed code of 3939 is used.
Such devices don't appear to be fully Homekit compatible - they will not, for The controller can still use `/pair-add` etc. towards such devices.
instance - appear in the Home app.
## "fruit" pairing ## "fruit" pairing
Like normal Homekit pairing, this consists of first requesting a code with Like normal Homekit pairing, this consists of first requesting a code with
@@ -69,4 +69,5 @@ shared secret.
- [AirPlayAuth](https://github.com/funtax/AirPlayAuth) - [AirPlayAuth](https://github.com/funtax/AirPlayAuth)
- [AirPlayAuth-ObjC](https://github.com/ViktoriiaKh/AirPlayAuth-ObjC) - [AirPlayAuth-ObjC](https://github.com/ViktoriiaKh/AirPlayAuth-ObjC)
- [ap2-sender](https://github.com/ViktoriiaKh/ap2-sender) - [ap2-sender](https://github.com/ViktoriiaKh/ap2-sender)
- [airplay2-receiver](https://github.com/ckdo/airplay2-receiver)
- [csrp](https://github.com/cocagne/csrp) - [csrp](https://github.com/cocagne/csrp)
+1 -1
View File
@@ -4,7 +4,7 @@
#include <stdint.h> #include <stdint.h>
#define PAIR_AP_VERSION_MAJOR 0 #define PAIR_AP_VERSION_MAJOR 0
#define PAIR_AP_VERSION_MINOR 5 #define PAIR_AP_VERSION_MINOR 7
#define PAIR_AP_DEVICE_ID_LEN_MAX 64 #define PAIR_AP_DEVICE_ID_LEN_MAX 64
+13 -3
View File
@@ -2679,6 +2679,7 @@ server_add_remove_request(pair_cb cb, void *cb_arg, const uint8_t *in, size_t in
pair_tlv_t *device_id; pair_tlv_t *device_id;
pair_tlv_t *pk; pair_tlv_t *pk;
char id_str[PAIR_AP_DEVICE_ID_LEN_MAX] = { 0 }; char id_str[PAIR_AP_DEVICE_ID_LEN_MAX] = { 0 };
uint8_t *public_key = NULL;
request = message_process(in, in_len, &errmsg); request = message_process(in, in_len, &errmsg);
if (!request) if (!request)
@@ -2687,15 +2688,21 @@ server_add_remove_request(pair_cb cb, void *cb_arg, const uint8_t *in, size_t in
} }
device_id = pair_tlv_get_value(request, TLVType_Identifier); device_id = pair_tlv_get_value(request, TLVType_Identifier);
pk = pair_tlv_get_value(request, TLVType_PublicKey); if (!device_id || device_id->size >= sizeof(id_str))
if (!device_id || device_id->size >= sizeof(id_str) || !pk || pk->size != crypto_sign_PUBLICKEYBYTES)
{ {
goto error; goto error;
} }
// Only present when adding
pk = pair_tlv_get_value(request, TLVType_PublicKey);
if (pk && pk->size == crypto_sign_PUBLICKEYBYTES)
{
public_key = pk->value;
}
memcpy(id_str, device_id->value, device_id->size); memcpy(id_str, device_id->value, device_id->size);
cb(pk->value, id_str, cb_arg); cb(public_key, id_str, cb_arg);
pair_tlv_free(request); pair_tlv_free(request);
return 0; return 0;
@@ -2757,9 +2764,12 @@ static int
server_list_cb(uint8_t public_key[crypto_sign_PUBLICKEYBYTES], const char *device_id, void *cb_arg) server_list_cb(uint8_t public_key[crypto_sign_PUBLICKEYBYTES], const char *device_id, void *cb_arg)
{ {
pair_tlv_values_t *response = cb_arg; pair_tlv_values_t *response = cb_arg;
uint8_t permissions = 1; // Means admin (TODO don't hardcode - let caller set)
pair_tlv_add_value(response, TLVType_Identifier, (unsigned char *)device_id, strlen(device_id)); pair_tlv_add_value(response, TLVType_Identifier, (unsigned char *)device_id, strlen(device_id));
pair_tlv_add_value(response, TLVType_PublicKey, public_key, crypto_sign_PUBLICKEYBYTES); pair_tlv_add_value(response, TLVType_PublicKey, public_key, crypto_sign_PUBLICKEYBYTES);
pair_tlv_add_value(response, TLVType_Permissions, &permissions, sizeof(permissions));
return 0; return 0;
} }