Merge pull request #3 from ejurgensen/pair_errors1

Return same pairing errors as Airplay devices + announce actual public key
This commit is contained in:
Mike Brady
2021-05-08 09:57:05 +01:00
committed by GitHub
4 changed files with 48 additions and 37 deletions
+1 -2
View File
@@ -299,8 +299,7 @@ typedef struct {
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_pi; // UUID in the Bonjour advertisement and the GETINFO Plist
char *airplay_gid; // UUID in the Bonjour advertisement -- initially the same as the pi
#endif
} shairport_cfg;
+1 -1
Submodule pair_ap updated: 1b9954cba1...1a83fd5c50
+46 -19
View File
@@ -886,6 +886,19 @@ static ssize_t write_encrypted(rtsp_conn_info *conn, const void *buf, size_t cou
free(encrypted);
return count;
}
static void pkString_make(char *str, size_t str_size, const char *device_id) {
uint8_t public_key[32];
if (str_size < 2 * sizeof(public_key) + 1) {
warn("Insufficient string size");
str[0] = '\0';
return;
}
pair_public_key_get(PAIR_SERVER_HOMEKIT, public_key, device_id);
char *ptr = str;
for (size_t i = 0; i < sizeof(public_key); i++)
ptr += sprintf(ptr, "%02x", public_key[i]);
}
#endif
ssize_t read_from_rtsp_connection(rtsp_conn_info *conn, void *buf, size_t count) {
@@ -1238,11 +1251,14 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r
plist_dict_set_item(response_plist, "name", plist_new_string(config.service_name));
char *vs = get_version_string();
plist_dict_set_item(response_plist, "model", plist_new_string(vs));
free(vs);
char pkString[128];
pkString_make(pkString, sizeof(pkString), config.airplay_device_id);
plist_dict_set_item(response_plist, "pk", plist_new_string(pkString));
plist_to_bin(response_plist, &resp->content, &resp->contentlength);
if (resp->contentlength == 0)
debug(1, "GET /info Stage 1: response bplist not created!");
plist_free(response_plist);
free(vs);
}
msg_add_header(resp, "Content-Type", "application/x-apple-binary-plist");
debug_log_rtsp_message(2, "GET /info Stage 1 Response:", resp);
@@ -1264,6 +1280,9 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r
char *vs = get_version_string();
plist_dict_set_item(response_plist, "model", plist_new_string(vs));
free(vs);
char pkString[128];
pkString_make(pkString, sizeof(pkString), config.airplay_device_id);
plist_dict_set_item(response_plist, "pk", plist_new_string(pkString));
plist_to_bin(response_plist, &resp->content, &resp->contentlength);
plist_free(response_plist);
msg_add_header(resp, "Content-Type", "application/x-apple-binary-plist");
@@ -1420,8 +1439,8 @@ void handle_get(__attribute((unused)) rtsp_conn_info *conn, __attribute((unused)
#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;
uint8_t *body = NULL;
size_t body_len = 0;
struct pair_result *result;
debug(2, "Connection %d: pair-verify Content-Length %d", conn->connection_number,
req->contentlength);
@@ -1430,12 +1449,16 @@ void handle_pair_verify(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *r
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");
resp->respcode = 500; // Internal Server Error
goto out;
}
}
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));
resp->respcode = 470; // Connection Authorization Required
goto out;
}
ret = pair_verify_result(&result, conn->ap2_control_pairing.verify_ctx);
@@ -1443,19 +1466,22 @@ void handle_pair_verify(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *r
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");
goto out;
}
}
out:
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");
if (body)
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;
size_t body_len;
uint8_t *body = NULL;
size_t body_len = 0;
struct pair_result *result;
debug(2, "Connection %d: pair-setup Content-Length %d", conn->connection_number,
req->contentlength);
@@ -1464,16 +1490,16 @@ void handle_pair_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *re
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;
return;
resp->respcode = 500; // Internal Server Error
goto out;
}
}
ret = pair_setup(&body, &body_len, conn->ap2_control_pairing.setup_ctx, (const uint8_t *)req->content, req->contentlength);
if (ret < 0) {
debug(1, pair_setup_errmsg(conn->ap2_control_pairing.setup_ctx));
resp->respcode = 451;
return;
resp->respcode = 470; // Connection Authorization Required
goto out;
}
ret = pair_setup_result(NULL, &result, conn->ap2_control_pairing.setup_ctx);
@@ -1483,14 +1509,15 @@ void handle_pair_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *re
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->respcode = 451;
return;
goto out;
}
}
out:
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");
if (body)
msg_add_header(resp, "Content-Type", "application/octet-stream");
debug_log_rtsp_message(2, "pair-setup response", resp);
}
@@ -4098,7 +4125,7 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
#ifdef CONFIG_AIRPLAY_2
*p++ = "srcvers=366.0";
char deviceIdString[64];
snprintf(deviceIdString, sizeof(deviceIdString) - 1, "deviceid=%s", config.airplay_device_id);
snprintf(deviceIdString, sizeof(deviceIdString), "deviceid=%s", config.airplay_device_id);
*p++ = deviceIdString;
// features is a 64 bit number, least significant 32 bits
char featuresString[64];
@@ -4106,8 +4133,7 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
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 "",
snprintf(featuresString, sizeof(featuresString), "features=0x%" PRIx64 ",0x%" PRIx64 "",
features_lo, features_hi);
*p++ = featuresString;
char statusflagsString[32];
@@ -4119,14 +4145,15 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
*p++ = "fv=p20.78000.12";
*p++ = "model=SPS";
char piString[64];
snprintf(piString, sizeof(piString) - 1, "pi=%s", config.airplay_pi);
snprintf(piString, sizeof(piString), "pi=%s", config.airplay_pi);
*p++ = piString;
char gidString[64];
snprintf(gidString, sizeof(gidString) - 1, "gid=%s", config.airplay_gid);
snprintf(gidString, sizeof(gidString), "gid=%s", config.airplay_gid);
*p++ = gidString;
*p++ = "gcgl=0";
char pkString[128];
snprintf(pkString, sizeof(pkString) - 1, "pk=%s", config.airplay_pk);
snprintf(pkString, sizeof(pkString), "pk=");
pkString_make(pkString + strlen("pk="), sizeof(pkString) - strlen("pk="), config.airplay_device_id);
*p++ = pkString;
*p++ = NULL;
#else
-15
View File
@@ -1591,21 +1591,6 @@ int main(int argc, char **argv) {
} else
debug(1, "Started in Airplay 2 mode!");
// now make up a 32-byte "pk" string from random numbers
const ssize_t pk_size = 32;
char pk_bytes[pk_size];
char pk_string[pk_size * 2 + 1];
randombytes_buf(pk_bytes, pk_size); // using libsodium
char *obfp = pk_string;
int obfc;
for (obfc = 0; obfc < pk_size; obfc++) {
snprintf(obfp, 3, "%02X", pk_bytes[obfc]);
obfp += 2;
};
*obfp = 0;
debug(1, "pk string: \"%s\"", pk_string);
config.airplay_pk = strdup(pk_string);
// now generate a UUID
// from https://stackoverflow.com/questions/51053568/generating-a-random-uuid-in-c
// with thanks