mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-06-02 21:38:58 -04:00
module-raop/rtsp-client: Add cipher support
This commit is contained in:
parent
b4b3a53384
commit
77437f5a79
3 changed files with 109 additions and 28 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue