diff --git a/src/modules/module-raop-sink.c b/src/modules/module-raop-sink.c index ac53d5458..00162f796 100644 --- a/src/modules/module-raop-sink.c +++ b/src/modules/module-raop-sink.c @@ -269,8 +269,7 @@ struct impl { uint64_t salt_len; uint8_t shared_secret[64]; size_t shared_secret_len; // Will be 32 (normal) or 64 (transient) - - //struct pw_rtsp_cipher_context *control_cipher_ctx; + struct pw_rtsp_cipher_context *cipher_ctx; uint16_t control_port; int control_fd; @@ -1019,7 +1018,7 @@ static int rtsp_setup_reply(void *data, int status, const struct spa_dict *heade int res; pw_log_info("setup status: %d", status); - + // TODO if ((str = spa_dict_lookup(headers, "Session")) == NULL) { pw_log_error("missing Session header"); return 0; @@ -1183,13 +1182,13 @@ hkdf_extract_expand(uint8_t *okm, size_t okm_len, const uint8_t *ikm, size_t ikm EVP_PKEY_CTX_free(pctx); return -1; } -/* -static pw_rtsp_cipher_context *ap_cipher_context_new(const uint8_t *shared_secret, size_t shared_secret_len, const char *enc_salt, const char *enc_info, const char *dec_salt, const char *dec_info) + +static struct pw_rtsp_cipher_context *ap_cipher_context_new(const uint8_t *shared_secret, size_t shared_secret_len, const char *enc_salt, const char *enc_info, const char *dec_salt, const char *dec_info) { struct pw_rtsp_cipher_context *cctx; int ret; - cctx = calloc(1, sizeof(struct pw_rtsp_cipher_context)); + cctx = calloc(1, sizeof(*cctx)); if (!cctx) goto error; ret = hkdf_extract_expand(cctx->encryption_key, sizeof(cctx->encryption_key), shared_secret, shared_secret_len, enc_salt, enc_info); @@ -1361,7 +1360,7 @@ static ssize_t ap_decrypt(uint8_t **plaintext, size_t *plaintext_len, return cipher_block - ciphertext; } -*/ + static int rtsp_do_setup(struct impl *impl) { int res; @@ -1387,7 +1386,7 @@ static int rtsp_do_setup(struct impl *impl) impl->timing_source = pw_loop_add_io(impl->loop, impl->timing_fd, SPA_IO_IN, false, on_timing_source_io, impl); - switch (impl->protocol) { + switch (impl->encryption) { case CRYPTO_PAIR_TRANSIENT: // Encryption/decryption of control channel const char *control_salt = AP_CONTROL_SALT; @@ -1400,7 +1399,7 @@ static int rtsp_do_setup(struct impl *impl) wplist_dict_add_uint(stream, "controlPort", impl->control_port); wplist_dict_add_uint(stream, "ct", impl->codec); // Compression type, 1 LPCM, 2 ALAC, 3 AAC, 4 AAC ELD, 32 OPUS wplist_dict_add_bool(stream, "isMedia", true); // ? - //wplist_dict_add_uint(stream, "latencyMax", 88200); // TODO how do these latencys work? + wplist_dict_add_uint(stream, "latencyMax", 88200); // ? wplist_dict_add_uint(stream, "latencyMin", RAOP_LATENCY_MIN); wplist_dict_add_data(stream, "shk", impl->shared_secret, impl->shared_secret_len); wplist_dict_add_uint(stream, "spf", FRAMES_PER_UDP_PACKET); @@ -1418,12 +1417,16 @@ static int rtsp_do_setup(struct impl *impl) const char *url = pw_rtsp_client_get_url(impl->rtsp); - //impl->control_cipher_ctx = ap_cipher_context_new(impl->shared_secret, impl->shared_secret_len, control_salt, enc_info, control_salt, dec_info); - //if (!impl->control_cipher_ctx) { - // pw_log_error("Could not create control cipher"); - // goto error; - //} - //struct pw_rtsp_cipher *cipher = ap_cipher_new(ap_decrypt, ap_encrypt); + impl->cipher_ctx = ap_cipher_context_new(impl->shared_secret, impl->shared_secret_len, control_salt, enc_info, control_salt, dec_info); + if (!impl->cipher_ctx) { + pw_log_error("Could not create control cipher"); + goto error; + } + + pw_rtsp_client_set_cipher_ctx(impl->rtsp, impl->cipher_ctx); + + pw_rtsp_client_set_encryption(impl->rtsp, ap_encrypt); + pw_rtsp_client_set_decryption(impl->rtsp, ap_decrypt); res = pw_rtsp_client_url_send(impl->rtsp, url, "SETUP", &impl->headers->dict, "application/x-apple-binary-plist", content, content_len, @@ -1855,8 +1858,8 @@ static int rtsp_ap2_pair_setup2_reply(void *data, int status, const struct spa_d // TODO pw_properties_set(impl->headers, "X-Apple-HKP", NULL); - //return rtsp_do_setup(impl); - return 0; + return rtsp_do_setup(impl); + //return 0; error: tlv_free(response); diff --git a/src/modules/module-raop/rtsp-client.c b/src/modules/module-raop/rtsp-client.c index c8e81e0a0..1c0a5f1a8 100644 --- a/src/modules/module-raop/rtsp-client.c +++ b/src/modules/module-raop/rtsp-client.c @@ -56,6 +56,9 @@ struct pw_rtsp_client { unsigned int need_flush:1; enum client_recv_state recv_state; + struct pw_rtsp_cipher_context *cipher_ctx; + ssize_t (*decrypt) (uint8_t **plaintext, size_t *plaintext_len, const uint8_t *ciphertext, size_t ciphertext_len, struct pw_rtsp_cipher_context *cctx); + ssize_t (*encrypt) (uint8_t **ciphertext, size_t *ciphertext_len, const uint8_t *plaintext, size_t plaintext_len, struct pw_rtsp_cipher_context *cctx); int status; char line_buf[1024]; size_t line_pos; @@ -92,12 +95,33 @@ struct pw_rtsp_client *pw_rtsp_client_new(struct pw_loop *main_loop, client->headers = pw_properties_new(NULL, NULL); pw_array_init(&client->content, 4096); client->recv_state = CLIENT_RECV_NONE; + client->cipher_ctx = NULL; + client->decrypt = NULL; + client->encrypt = NULL; pw_log_info("new client %p", client); return client; } +void pw_rtsp_client_set_decryption(struct pw_rtsp_client *client, + ssize_t (*decrypt) (uint8_t **plaintext, size_t *plaintext_len, const uint8_t *ciphertext, size_t ciphertext_len, struct pw_rtsp_cipher_context *cctx)) +{ + client->decrypt = decrypt; +} + +void pw_rtsp_client_set_encryption(struct pw_rtsp_client *client, + ssize_t (*encrypt) (uint8_t **ciphertext, size_t *ciphertext_len, const uint8_t *plaintext, size_t plaintext_len, struct pw_rtsp_cipher_context *cctx)) +{ + client->encrypt = encrypt; +} + +void pw_rtsp_client_set_cipher_ctx(struct pw_rtsp_client *client, + struct pw_rtsp_cipher_context *cipher_ctx) +{ + client->cipher_ctx = cipher_ctx; +} + void pw_rtsp_client_destroy(struct pw_rtsp_client *client) { pw_log_info("destroy client %p", client); @@ -154,6 +178,8 @@ int pw_rtsp_client_get_local_ip(struct pw_rtsp_client *client, static int handle_connect(struct pw_rtsp_client *client, int fd) { + pw_log_info("enter handle connect"); + int res, ip_version; socklen_t len; char local_ip[INET6_ADDRSTRLEN]; @@ -185,9 +211,12 @@ static int handle_connect(struct pw_rtsp_client *client, int fd) client->recv_state = CLIENT_RECV_STATUS; pw_properties_clear(client->headers); + pw_array_reset(&client->content); client->status = 0; client->line_pos = 0; client->content_length = 0; + client->decrypt = NULL; + client->encrypt = NULL; pw_rtsp_client_emit_connected(client); @@ -196,7 +225,7 @@ static int handle_connect(struct pw_rtsp_client *client, int fd) static int read_line(struct pw_rtsp_client *client, char **buf) { - int res; + int res, idx = 0; while (true) { uint8_t c; @@ -217,15 +246,17 @@ static int read_line(struct pw_rtsp_client *client, char **buf) client->line_pos = 0; if (buf) *buf = client->line_buf; - return 1; + return idx; } if (c == '\r') continue; - if (client->line_pos < sizeof(client->line_buf) - 1) + if (client->line_pos < sizeof(client->line_buf) - 1) { client->line_buf[client->line_pos++] = c; + idx++; + } client->line_buf[client->line_pos] = '\0'; } - return 0; + return idx; } static struct message *find_pending(struct pw_rtsp_client *client, uint32_t cseq) @@ -355,7 +386,7 @@ static int process_content(struct pw_rtsp_client *client) spa_assert((size_t) res <= client->content_length); client->content_length -= res; - pw_log_info("processing content (%ld bytes):\n%s", client->content.size, client->content.data); + pw_log_info("processing content (%ld bytes):\n%s", client->content.size, (char *)client->content.data); } if (client->content_length == 0) @@ -370,11 +401,24 @@ static int process_input(struct pw_rtsp_client *client) char *buf = NULL; int res; - if ((res = read_line(client, &buf)) <= 0) + if ((res = read_line(client, &buf)) < 0) { + pw_log_debug("ret 1: %d", res); return res; - - pw_log_debug("received line: %s", buf); - + } + pw_log_debug("received line (%ld bytes): %s", res, buf); + if (res > 0 && client->decrypt != NULL && client->cipher_ctx != NULL) { + pw_log_debug("decrypting"); + uint8_t *dec_buf = malloc(1024); + size_t dec_len; + ssize_t dec; + dec = client->decrypt(dec_buf, &dec_len, (const uint8_t *)buf, res, client->cipher_ctx); + if (dec < 0) { + pw_log_debug("ret 2"); + return dec; + } + buf = dec_buf; + pw_log_debug("plain line: %s", buf); + } switch (client->recv_state) { case CLIENT_RECV_STATUS: return process_status(client, buf); @@ -446,14 +490,17 @@ on_source_io(void *data, int fd, uint32_t mask) int res; if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { + pw_log_info("ERR"); res = -EPIPE; goto error; } if (mask & SPA_IO_IN) { + pw_log_info("IN"); if ((res = process_input(client)) < 0) goto error; } if (mask & SPA_IO_OUT || client->need_flush) { + pw_log_info("OUT"); if (client->connecting) { if ((res = handle_connect(client, fd)) < 0) goto error; @@ -553,6 +600,9 @@ int pw_rtsp_client_disconnect(struct pw_rtsp_client *client) client->url = NULL; free(client->session_id); client->session_id = NULL; + if (client->cipher_ctx != NULL) + free(client->cipher_ctx); + client->cipher_ctx = NULL; spa_list_consume(msg, &client->messages, link) { spa_list_remove(&msg->link); @@ -599,8 +649,19 @@ int pw_rtsp_client_url_send(struct pw_rtsp_client *client, const char *url, fclose(f); - msg->data = SPA_PTROFF(msg, sizeof(*msg), void); - msg->len = len - sizeof(*msg); + if (client->encrypt != NULL && client->cipher_ctx != NULL) { + uint8_t *enc_buf; + size_t enc_len; + ssize_t enc = client->encrypt(&enc_buf, &enc_len, SPA_PTROFF(msg, sizeof(*msg), void), len - sizeof(*msg), client->cipher_ctx); + if (enc < 0) + return enc; + msg->data = enc_buf; + msg->len = enc_len; + } + else { + msg->data = SPA_PTROFF(msg, sizeof(*msg), void); + msg->len = len - sizeof(*msg); + } msg->offset = 0; msg->reply = reply; msg->user_data = user_data; diff --git a/src/modules/module-raop/rtsp-client.h b/src/modules/module-raop/rtsp-client.h index 1b832cbcc..a407f0030 100644 --- a/src/modules/module-raop/rtsp-client.h +++ b/src/modules/module-raop/rtsp-client.h @@ -30,6 +30,15 @@ struct pw_rtsp_client_events { }; +struct pw_rtsp_cipher_context { + uint8_t encryption_key[32]; + uint8_t decryption_key[32]; + uint64_t encryption_counter; + uint64_t decryption_counter; + uint64_t encryption_counter_prev; + uint64_t decryption_counter_prev; +}; + struct pw_rtsp_client * pw_rtsp_client_new(struct pw_loop *main_loop, struct pw_properties *props, size_t user_data_size); @@ -64,6 +73,14 @@ int pw_rtsp_client_send(struct pw_rtsp_client *client, int (*reply) (void *user_data, int status, const struct spa_dict *headers, const struct pw_array *content), void *user_data); +void pw_rtsp_client_set_decryption(struct pw_rtsp_client *client, + ssize_t (*decrypt) (uint8_t **plaintext, size_t *plaintext_len, const uint8_t *ciphertext, size_t ciphertext_len, struct pw_rtsp_cipher_context *cctx)); + +void pw_rtsp_client_set_encryption(struct pw_rtsp_client *client, + ssize_t (*encrypt) (uint8_t **ciphertext, size_t *ciphertext_len, const uint8_t *plaintext, size_t plaintext_len, struct pw_rtsp_cipher_context *cctx)); + +void pw_rtsp_client_set_cipher_ctx(struct pw_rtsp_client *client, + struct pw_rtsp_cipher_context *cipher_ctx); #ifdef __cplusplus }