diff --git a/kernel-module/xt_MEDIAPROXY.c b/kernel-module/xt_MEDIAPROXY.c index cfb43293a..c1ad96236 100644 --- a/kernel-module/xt_MEDIAPROXY.c +++ b/kernel-module/xt_MEDIAPROXY.c @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -100,6 +103,63 @@ static void table_push(struct mediaproxy_table *); static struct mediaproxy_target *get_target(struct mediaproxy_table *, u_int16_t); + + + + +struct mp_crypto_context { + spinlock_t lock; /* protects roc and last_index */ + unsigned char session_key[16]; + unsigned char session_salt[14]; + unsigned char session_auth_key[20]; + u_int32_t roc; +}; + +struct mediaproxy_target { + atomic_t refcnt; + u_int32_t table; + struct mediaproxy_target_info target; + + spinlock_t stats_lock; + struct mediaproxy_stats stats; + + struct mp_crypto_context decrypt; + struct mp_crypto_context encrypt; +}; + +struct mediaproxy_table { + atomic_t refcnt; + rwlock_t target_lock; + pid_t pid; + + u_int32_t id; + struct proc_dir_entry *proc; + struct proc_dir_entry *status; + struct proc_dir_entry *control; + struct proc_dir_entry *list; + struct proc_dir_entry *blist; + + struct mediaproxy_target **target[256]; + + unsigned int buckets; + unsigned int targets; +}; + +struct mp_cipher { + const char *name; +}; + +struct mp_hmac { + const char *name; +}; + + + + + + + + static const struct file_operations proc_control_ops = { .write = proc_control_write, .open = proc_control_open, @@ -125,7 +185,7 @@ static const struct file_operations proc_blist_ops = { .release = proc_blist_close, }; -static struct seq_operations proc_list_seq_ops = { +static const struct seq_operations proc_list_seq_ops = { .start = proc_list_start, .next = proc_list_next, .stop = proc_list_stop, @@ -139,13 +199,40 @@ static const struct file_operations proc_main_list_ops = { .release = seq_release, }; -static struct seq_operations proc_main_list_seq_ops = { +static const struct seq_operations proc_main_list_seq_ops = { .start = proc_main_list_start, .next = proc_main_list_next, .stop = proc_main_list_stop, .show = proc_main_list_show, }; +static const struct mp_cipher mp_ciphers[] = { + [MPC_INVALID] = { + .name = NULL, + }, + [MPC_NULL] = { + .name = "NULL", + }, + [MPC_AES_CM] = { + .name = "AES-CM", + }, + [MPC_AES_F8] = { + .name = "AES-F8", + }, +}; + +static const struct mp_hmac mp_hmacs[] = { + [MPH_INVALID] = { + .name = NULL, + }, + [MPH_NULL] = { + .name = "NULL", + }, + [MPH_HMAC_SHA1] = { + .name = "HMAC-SHA1", + }, +}; + @@ -740,6 +827,171 @@ static int is_valid_address(struct mp_address *mpa) { +static int validate_srtp(struct mediaproxy_srtp *s) { + if (s->cipher <= MPC_INVALID) + return -1; + if (s->cipher >= __MPC_LAST) + return -1; + if (s->hmac <= MPH_INVALID) + return -1; + if (s->hmac >= __MPH_LAST) + return -1; + if (s->auth_tag_len > 20) + return -1; + if (s->mki_len > 128) + return -1; + return 0; +} + + + +static void aes_ctr_128(unsigned char *out, const unsigned char *in, int in_len, + struct crypto_cipher *tfm, const char *iv) +{ + unsigned char ivx[16]; + unsigned char key_block[16]; + unsigned char *p, *q; + unsigned int left; + int i; + u_int64_t *pi, *qi, *ki; + + if (!tfm) + return; + + memcpy(ivx, iv, 16); + pi = (void *) in; + qi = (void *) out; + ki = (void *) key_block; + left = in_len; + + while (left) { + crypto_cipher_encrypt_one(tfm, key_block, ivx); + + if (unlikely(left < 16)) { + p = (void *) pi; + q = (void *) qi; + for (i = 0; i < 16; i++) { + *q++ = *p++ ^ key_block[i]; + left--; + if (!left) + goto done; + } + panic("BUG!"); + } + + *qi++ = *pi++ ^ ki[0]; + *qi++ = *pi++ ^ ki[1]; + left -= 16; + + for (i = 15; i >= 0; i--) { + ivx[i]++; + if (likely(ivx[i])) + break; + } + } + +done: + ; +} + +static int aes_ctr_128_no_ctx(unsigned char *out, const char *in, int in_len, + const unsigned char *key, const unsigned char *iv) +{ + struct crypto_cipher *tfm; + + tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + crypto_cipher_setkey(tfm, key, 16); + aes_ctr_128(out, in, in_len, tfm, iv); + + crypto_free_cipher(tfm); + return 0; +} + +static int prf_n(unsigned char *out, int len, const unsigned char *key, const unsigned char *x) { + unsigned char iv[16]; + unsigned char o[32]; + unsigned char in[32]; + int in_len, ret; + + memcpy(iv, x, 14); + iv[14] = iv[15] = 0; + in_len = len > 16 ? 32 : 16; + memset(in, 0, in_len); + + ret = aes_ctr_128_no_ctx(o, in, in_len, key, iv); + if (ret) + return ret; + + memcpy(out, o, len); + + return 0; +} + +static int gen_session_key(unsigned char *out, int len, struct mediaproxy_srtp *s, unsigned char label) { + unsigned char key_id[7]; + unsigned char x[14]; + int i, ret; + + memset(key_id, 0, sizeof(key_id)); + + key_id[0] = label; + + memcpy(x, s->master_salt, 14); + for (i = 13 - 6; i < 14; i++) + x[i] = key_id[i - (13 - 6)] ^ x[i]; + + ret = prf_n(out, len, s->master_key, x); + if (ret) + return ret; + return 0; +} + + + + +static int gen_session_keys(struct mp_crypto_context *c, struct mediaproxy_srtp *s) { + int ret; + + if (s->cipher == MPC_NULL) + return 0; + ret = gen_session_key(c->session_key, 16, s, 0x00); + if (ret) + return ret; + ret = gen_session_key(c->session_auth_key, 20, s, 0x01); + if (ret) + return ret; + ret = gen_session_key(c->session_salt, 14, s, 0x02); + if (ret) + return ret; + + DBG("master key %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + s->master_key[0], s->master_key[1], s->master_key[2], s->master_key[3], + s->master_key[4], s->master_key[5], s->master_key[6], s->master_key[7], + s->master_key[8], s->master_key[9], s->master_key[10], s->master_key[11], + s->master_key[12], s->master_key[13], s->master_key[14], s->master_key[15]); + DBG("master salt %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + s->master_salt[0], s->master_salt[1], s->master_salt[2], s->master_salt[3], + s->master_salt[4], s->master_salt[5], s->master_salt[6], s->master_salt[7], + s->master_salt[8], s->master_salt[9], s->master_salt[10], s->master_salt[11], + s->master_salt[12], s->master_salt[13]); + DBG("session key %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + c->session_key[0], c->session_key[1], c->session_key[2], c->session_key[3], + c->session_key[4], c->session_key[5], c->session_key[6], c->session_key[7], + c->session_key[8], c->session_key[9], c->session_key[10], c->session_key[11], + c->session_key[12], c->session_key[13], c->session_key[14], c->session_key[15]); + DBG("session salt %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + c->session_salt[0], c->session_salt[1], c->session_salt[2], c->session_salt[3], + c->session_salt[4], c->session_salt[5], c->session_salt[6], c->session_salt[7], + c->session_salt[8], c->session_salt[9], c->session_salt[10], c->session_salt[11], + c->session_salt[12], c->session_salt[13]); + return 0; +} + + + static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target_info *i, int update) { unsigned char hi, lo; @@ -763,6 +1015,10 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target if (i->mirror_addr.family != i->src_addr.family) return -EINVAL; } + if (validate_srtp(&i->decrypt)) + return -EINVAL; + if (validate_srtp(&i->encrypt)) + return -EINVAL; DBG("Creating new target\n"); @@ -774,8 +1030,18 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target g->table = t->id; atomic_set(&g->refcnt, 1); spin_lock_init(&g->stats_lock); + spin_lock_init(&g->decrypt.lock); + spin_lock_init(&g->encrypt.lock); memcpy(&g->target, i, sizeof(*i)); + err = gen_session_keys(&g->decrypt, &g->target.decrypt); + if (err) + goto fail2; + err = gen_session_keys(&g->encrypt, &g->target.encrypt); + if (err) + goto fail2; + + err = -ENOMEM; if (update) gp = NULL; else { @@ -982,7 +1248,7 @@ static ssize_t proc_control_write(struct file *file, const char __user *buf, siz int err; if (buflen != sizeof(msg)) - return -EINVAL; + return -EIO; inode = file->f_path.dentry->d_inode; pde = PDE(inode); diff --git a/kernel-module/xt_MEDIAPROXY.h b/kernel-module/xt_MEDIAPROXY.h index d91f46957..0e0d3fa7e 100644 --- a/kernel-module/xt_MEDIAPROXY.h +++ b/kernel-module/xt_MEDIAPROXY.h @@ -24,6 +24,35 @@ struct mp_address { u_int16_t port; }; +enum mediaproxy_cipher { + MPC_INVALID = 0, + MPC_NULL, + MPC_AES_CM, + MPC_AES_F8, + + __MPC_LAST +}; + +enum mediaproxy_hmac { + MPH_INVALID = 0, + MPH_NULL, + MPH_HMAC_SHA1, + + __MPH_LAST +}; + +struct mediaproxy_srtp { + enum mediaproxy_cipher cipher; + enum mediaproxy_hmac hmac; + unsigned char master_key[16]; + unsigned char master_salt[14]; + u_int64_t mki; + u_int64_t last_index; + unsigned int auth_tag_len; /* in bytes */ + unsigned int mki_len; +}; + + struct mediaproxy_target_info { u_int16_t target_port; @@ -32,6 +61,9 @@ struct mediaproxy_target_info { struct mp_address mirror_addr; + struct mediaproxy_srtp decrypt; + struct mediaproxy_srtp encrypt; + unsigned char tos; }; @@ -51,35 +83,5 @@ struct mediaproxy_list_entry { struct mediaproxy_stats stats; }; -#ifdef __KERNEL__ - -struct mediaproxy_target { - atomic_t refcnt; - u_int32_t table; - struct mediaproxy_target_info target; - - spinlock_t stats_lock; - struct mediaproxy_stats stats; -}; - -struct mediaproxy_table { - atomic_t refcnt; - rwlock_t target_lock; - pid_t pid; - - u_int32_t id; - struct proc_dir_entry *proc; - struct proc_dir_entry *status; - struct proc_dir_entry *control; - struct proc_dir_entry *list; - struct proc_dir_entry *blist; - - struct mediaproxy_target **target[256]; - - unsigned int buckets; - unsigned int targets; -}; - -#endif #endif