You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rtpengine/include/crypto.h

297 lines
8.4 KiB

#ifndef _CRYPTO_H_
#define _CRYPTO_H_
#include <sys/types.h>
#include <glib.h>
#include "compat.h"
#include "str.h"
#include "aux.h"
#define SRTP_MAX_MASTER_KEY_LEN 32
#define SRTP_MAX_MASTER_SALT_LEN 14
#define SRTP_MAX_SESSION_KEY_LEN 32
#define SRTP_MAX_SESSION_SALT_LEN 14
#define SRTP_MAX_SESSION_AUTH_LEN 20
struct crypto_context;
struct rtp_header;
struct rtcp_packet;
typedef int (*crypto_func_rtp)(struct crypto_context *, struct rtp_header *, str *, uint64_t);
typedef int (*crypto_func_rtcp)(struct crypto_context *, struct rtcp_packet *, str *, uint64_t);
typedef int (*hash_func_rtp)(struct crypto_context *, char *out, str *in, uint64_t);
typedef int (*hash_func_rtcp)(struct crypto_context *, char *out, str *in);
typedef int (*session_key_init_func)(struct crypto_context *);
typedef int (*session_key_cleanup_func)(struct crypto_context *);
struct crypto_suite {
const char *name;
const char *dtls_name;
unsigned int
master_key_len,
master_salt_len,
session_key_len, /* n_e */
session_salt_len, /* n_s */
srtp_auth_tag, /* n_a */
srtcp_auth_tag,
srtp_auth_key_len, /* n_a */
srtcp_auth_key_len;
unsigned long long int
srtp_lifetime,
srtcp_lifetime;
int kernel_cipher;
int kernel_hmac;
crypto_func_rtp encrypt_rtp,
decrypt_rtp;
crypto_func_rtcp encrypt_rtcp,
decrypt_rtcp;
hash_func_rtp hash_rtp;
hash_func_rtcp hash_rtcp;
session_key_init_func session_key_init;
session_key_cleanup_func session_key_cleanup;
//const char *dtls_profile_code; // unused
const EVP_CIPHER *aes_evp;
unsigned int idx; // filled in during crypto_init_main()
str name_str; // same as `name`
const EVP_CIPHER *(*aead_evp)(void);
};
struct crypto_session_params {
unsigned int unencrypted_srtcp:1,
unencrypted_srtp:1,
unauthenticated_srtp:1;
};
struct crypto_params {
const struct crypto_suite *crypto_suite;
/* we only support one master key for now */
unsigned char master_key[SRTP_MAX_MASTER_KEY_LEN];
unsigned char master_salt[SRTP_MAX_MASTER_SALT_LEN];
unsigned char *mki;
unsigned int mki_len;
struct crypto_session_params session_params;
};
struct crypto_params_sdes {
struct crypto_params params;
unsigned int tag;
};
struct crypto_context {
struct crypto_params params;
char session_key[SRTP_MAX_SESSION_KEY_LEN]; /* k_e */
char session_salt[SRTP_MAX_SESSION_SALT_LEN]; /* k_s */
char session_auth_key[SRTP_MAX_SESSION_AUTH_LEN];
/* XXX replay list */
/* <from, to>? */
void *session_key_ctx[2];
unsigned int have_session_key:1;
};
extern const struct crypto_suite *crypto_suites;
extern const unsigned int num_crypto_suites;
extern __thread GString *crypto_debug_string;
void crypto_init_main(void);
const struct crypto_suite *crypto_find_suite(const str *);
int crypto_gen_session_key(struct crypto_context *, str *, unsigned char, unsigned int);
void crypto_dump_keys(struct crypto_context *in, struct crypto_context *out);
char *crypto_params_sdes_dump(const struct crypto_params_sdes *, char **);
/**
* A function which compares two crypto suite names in str format.
* Recommended to be used in combination with:
* g_queue_find_custom() or g_list_find_custom()
*/
INLINE int crypto_params_sdes_cmp(gconstpointer a, gconstpointer b)
{
const struct crypto_params_sdes * cs = a;
return str_cmp_str(&cs->params.crypto_suite->name_str, (str *) b);
}
INLINE int crypto_encrypt_rtp(struct crypto_context *c, struct rtp_header *rtp,
str *payload, uint64_t index)
{
return c->params.crypto_suite->encrypt_rtp(c, rtp, payload, index);
}
INLINE int crypto_decrypt_rtp(struct crypto_context *c, struct rtp_header *rtp,
str *payload, uint64_t index)
{
return c->params.crypto_suite->decrypt_rtp(c, rtp, payload, index);
}
INLINE int crypto_encrypt_rtcp(struct crypto_context *c, struct rtcp_packet *rtcp,
str *payload, uint64_t index)
{
return c->params.crypto_suite->encrypt_rtcp(c, rtcp, payload, index);
}
INLINE int crypto_decrypt_rtcp(struct crypto_context *c, struct rtcp_packet *rtcp,
str *payload, uint64_t index)
{
return c->params.crypto_suite->decrypt_rtcp(c, rtcp, payload, index);
}
INLINE int crypto_init_session_key(struct crypto_context *c) {
return c->params.crypto_suite->session_key_init(c);
}
INLINE int crypto_cleanup_session_key(struct crypto_context *c) {
if (c->params.crypto_suite->session_key_cleanup)
return c->params.crypto_suite->session_key_cleanup(c);
return 0;
}
INLINE void crypto_params_cleanup(struct crypto_params *p) {
if (p->mki)
free(p->mki);
p->mki = NULL;
}
INLINE void crypto_cleanup(struct crypto_context *c) {
crypto_params_cleanup(&c->params);
if (!c->params.crypto_suite)
return;
crypto_cleanup_session_key(c);
c->have_session_key = 0;
c->params.crypto_suite = NULL;
}
INLINE void crypto_reset(struct crypto_context *c) {
crypto_cleanup(c);
}
INLINE void crypto_params_copy(struct crypto_params *o, const struct crypto_params *i, int copy_sp) {
struct crypto_session_params sp;
crypto_params_cleanup(o);
if (!copy_sp)
sp = o->session_params;
*o = *i;
if (!copy_sp)
o->session_params = sp;
if (o->mki_len > 255)
o->mki_len = 0;
if (o->mki_len) {
o->mki = malloc(i->mki_len);
memcpy(o->mki, i->mki, i->mki_len);
}
}
INLINE void crypto_init(struct crypto_context *c, const struct crypto_params *p) {
crypto_cleanup(c);
if (p)
crypto_params_copy(&c->params, p, 1);
}
INLINE int crypto_params_cmp(const struct crypto_params *a, const struct crypto_params *b) {
if (a->crypto_suite != b->crypto_suite)
return 1;
if (!a->crypto_suite)
return 0;
if (memcmp(a->master_key, b->master_key, a->crypto_suite->master_key_len))
return 1;
if (memcmp(a->master_salt, b->master_salt, a->crypto_suite->master_salt_len))
return 1;
if (a->mki_len != b->mki_len)
return 1;
if (a->mki_len && memcmp(a->mki, b->mki, a->mki_len))
return 1;
if (memcmp(&a->session_params, &b->session_params, sizeof(a->session_params)))
return 1;
return 0;
}
INLINE void crypto_params_sdes_free(struct crypto_params_sdes *cps) {
crypto_params_cleanup(&cps->params);
g_slice_free1(sizeof(*cps), cps);
}
INLINE void crypto_params_sdes_queue_clear(GQueue *q) {
g_queue_clear_full(q, (GDestroyNotify) crypto_params_sdes_free);
}
INLINE void crypto_params_sdes_queue_copy(GQueue *dst, const GQueue *src) {
for (const GList *l = src->head; l; l = l->next) {
struct crypto_params_sdes *cps = l->data;
struct crypto_params_sdes *cpy = g_slice_alloc(sizeof(*cpy));
*cpy = *cps;
cpy->params.mki = NULL;
crypto_params_copy(&cpy->params, &cps->params, 1);
g_queue_push_tail(dst, cpy);
}
}
/**
* Checks whether to apply policies according to: sdes_no / sdes_only
* returns: 1 - to not apply / 0 - to apply
*/
INLINE int crypto_params_sdes_check_limitations(GHashTable * sdes_only,
GHashTable * sdes_no,
const struct crypto_suite *cps) {
/* if 'SDES-only-' flag(s) present, then
* accept only those SDES suites mentioned in the 'SDES-only-',
* all the rest will be dropped / not added.
* This takes precedence over 'SDES-no-'.
*
* We mustn't check the 'flags->sdes_no' at all, if 'flags->sdes_only' is set. */
if (sdes_only)
{
if (!g_hash_table_lookup(sdes_only, &cps->name_str))
return 1;
}
/* if 'SDES-no-' flag(s) present, then
* remove SDES-no suites from offered ones */
else if (sdes_no &&
g_hash_table_lookup(sdes_no, &cps->name_str))
{
return 1;
}
return 0;
}
#include "main.h"
#include "log.h"
#include <inttypes.h>
INLINE void crypto_debug_init(int flag) {
if (rtpe_config.common.log_levels[log_level_index_srtp] < LOG_DEBUG)
return;
if (crypto_debug_string)
g_string_free(crypto_debug_string, TRUE);
crypto_debug_string = NULL;
if (!flag)
return;
crypto_debug_string = g_string_new("");
}
void __crypto_debug_printf(const char *fmt, ...) __attribute__((format(printf,1,2)));
#define crypto_debug_printf(f, ...) \
if (crypto_debug_string) \
__crypto_debug_printf(f, ##__VA_ARGS__)
INLINE void crypto_debug_dump_raw(const char *b, int len) {
for (int i = 0; i < len; i++)
crypto_debug_printf("%02" PRIx8, (unsigned char) b[i]);
}
INLINE void crypto_debug_dump(const str *s) {
crypto_debug_dump_raw(s->s, s->len);
}
INLINE void crypto_debug_finish(void) {
if (!crypto_debug_string)
return;
ilogs(srtp, LOG_NOTICE, "Crypto debug: %.*s", (int) crypto_debug_string->len, crypto_debug_string->str);
g_string_free(crypto_debug_string, TRUE);
crypto_debug_string = NULL;
}
#endif