Support for pair-verify

This commit is contained in:
ejurgensen
2021-05-04 20:38:35 +02:00
parent 493e9604d3
commit ba73111a6f
3 changed files with 52 additions and 4 deletions
+2
View File
@@ -296,7 +296,9 @@ typedef struct {
#ifdef CONFIG_AIRPLAY_2
uint64_t airplay_features;
uint32_t airplay_statusflags;
char *airplay_device_id; // for the Bonjour advertisement and the GETINFO PList
char *airplay_pin; // non-NULL, 4 char PIN, if required for pairing
char *airplay_pk; // "pk" string in the Bonjour advertisement
char *airplay_pi; // UUID in the Bonjour advertisement and the GETINFO Plist
char *airplay_gid; // UUID in the Bonjour advertisement -- initially the same as the pi
+43 -4
View File
@@ -1232,6 +1232,7 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r
debug(1, "GET /info Stage 1: response plist not created from XML!");
} else {
plist_dict_set_item(response_plist, "features", plist_new_uint(config.airplay_features));
plist_dict_set_item(response_plist, "statusFlags", plist_new_uint(config.airplay_statusflags));
plist_dict_set_item(response_plist, "deviceID", plist_new_string(config.airplay_device_id));
plist_dict_set_item(response_plist, "pi", plist_new_string(config.airplay_pi));
plist_dict_set_item(response_plist, "name", plist_new_string(config.service_name));
@@ -1256,6 +1257,7 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r
plist_from_xml((const char *)plists_get_info_response_xml, plists_get_info_response_xml_len,
&response_plist);
plist_dict_set_item(response_plist, "features", plist_new_uint(config.airplay_features));
plist_dict_set_item(response_plist, "statusFlags", plist_new_uint(config.airplay_statusflags));
plist_dict_set_item(response_plist, "deviceID", plist_new_string(config.airplay_device_id));
plist_dict_set_item(response_plist, "pi", plist_new_string(config.airplay_pi));
plist_dict_set_item(response_plist, "name", plist_new_string(config.service_name));
@@ -1416,6 +1418,40 @@ void handle_get(__attribute((unused)) rtsp_conn_info *conn, __attribute((unused)
#endif
#ifdef CONFIG_AIRPLAY_2
void handle_pair_verify(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
int ret;
uint8_t *body;
size_t body_len;
struct pair_result *result;
debug(2, "Connection %d: pair-verify Content-Length %d", conn->connection_number,
req->contentlength);
if (!conn->ap2_control_pairing.verify_ctx) {
conn->ap2_control_pairing.verify_ctx = pair_verify_new(PAIR_SERVER_HOMEKIT, NULL, NULL, NULL, config.airplay_device_id);
if (!conn->ap2_control_pairing.verify_ctx) {
debug(1, "Error creating verify context");
}
}
ret = pair_verify(&body, &body_len, conn->ap2_control_pairing.verify_ctx, (const uint8_t *)req->content, req->contentlength);
if (ret < 0) {
debug(1, pair_verify_errmsg(conn->ap2_control_pairing.verify_ctx));
}
ret = pair_verify_result(&result, conn->ap2_control_pairing.verify_ctx);
if (ret == 0 && result->shared_secret_len > 0) {
conn->ap2_control_pairing.cipher_ctx = pair_cipher_new(PAIR_SERVER_HOMEKIT, 2, result->shared_secret, result->shared_secret_len);
if (!conn->ap2_control_pairing.cipher_ctx) {
debug(1, "Error setting up rtsp control channel ciphering\n");
}
}
resp->content = (char *)body; // these will be freed when the data is sent
resp->contentlength = body_len;
msg_add_header(resp, "Content-Type", "application/octet-stream");
debug_log_rtsp_message(2, "pair-verify response", resp);
}
void handle_pair_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
int ret;
uint8_t *body;
@@ -1425,7 +1461,7 @@ void handle_pair_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *re
req->contentlength);
if (!conn->ap2_control_pairing.setup_ctx) {
conn->ap2_control_pairing.setup_ctx = pair_setup_new(PAIR_SERVER_HOMEKIT, NULL, NULL, NULL, config.airplay_device_id);
conn->ap2_control_pairing.setup_ctx = pair_setup_new(PAIR_SERVER_HOMEKIT, config.airplay_pin, NULL, NULL, config.airplay_device_id);
if (!conn->ap2_control_pairing.setup_ctx) {
debug(1, "Error creating setup context");
resp->respcode = 451;
@@ -1564,6 +1600,8 @@ void handle_post(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
resp->respcode = 200;
if (strcmp(req->path, "/pair-setup") == 0) {
handle_pair_setup(conn, req, resp);
} else if (strcmp(req->path, "/pair-verify") == 0) {
handle_pair_verify(conn, req, resp);
} else if (strcmp(req->path, "/fp-setup") == 0) {
handle_fp_setup(conn, req, resp);
} else {
@@ -4062,17 +4100,18 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
snprintf(deviceIdString, sizeof(deviceIdString) - 1, "deviceid=%s", config.airplay_device_id);
*p++ = deviceIdString;
// features is a 64 bit number, least significant 32 bits
char featuresString[64];
uint64_t features_hi = config.airplay_features;
features_hi = (features_hi >> 32) & 0xffffffff;
uint64_t features_lo = config.airplay_features;
features_lo = features_lo & 0xffffffff;
// @mikebrady I don't think the -1 here (and other places) is necessary
snprintf(featuresString, sizeof(featuresString) - 1, "features=0x%" PRIx64 ",0x%" PRIx64 "",
features_lo, features_hi);
*p++ = featuresString;
*p++ = "flags=0x4";
char statusflagsString[32];
snprintf(statusflagsString, sizeof(statusflagsString), "flags=0x%" PRIx32, config.airplay_statusflags);
*p++ = statusflagsString;
*p++ = "protovers=1.1";
*p++ = "acl=0";
*p++ = "rsf=0x0";
+7
View File
@@ -1577,6 +1577,13 @@ int main(int argc, char **argv) {
// 496155702020608 this setting here is the source of both the plist features response and the
// mDNS string.
config.airplay_features = 0x1C340405F4A00;
// Advertised with mDNS and returned with GET /info, see https://openairplay.github.io/airplay-spec/status_flags.html
// 0x4: Audio cable attached, no PIN required (transient pairing), no Homekit access control
// 0x204: Audio cable attached, OneTimePairingRequired
// 0x604: Audio cable attached, OneTimePairingRequired, allow Homekit access control
config.airplay_statusflags = 0x4;
// Set to NULL to work with transient pairing
config.airplay_pin = NULL;
// get a device id -- the first non-local MAC address, not necessarily the one in use
config.airplay_device_id = get_device_id();
if (config.airplay_device_id) {