File: crypto.h

package info (click to toggle)
rtpengine 13.5.1.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,676 kB
  • sloc: ansic: 86,764; perl: 59,422; python: 3,193; sh: 1,030; makefile: 693; asm: 211
file content (291 lines) | stat: -rw-r--r-- 8,609 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#ifndef _CRYPTO_H_
#define _CRYPTO_H_

#include <sys/types.h>
#include <glib.h>

#include "compat.h"
#include "str.h"
#include "helpers.h"
#include "containers.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 *, uint32_t);
typedef int (*crypto_func_rtcp)(struct crypto_context *, struct rtcp_packet *, str *, uint32_t);
typedef int (*hash_func_rtp)(struct crypto_context *, char *out, str *in, uint32_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;
};

TYPED_GQUEUE(sdes, struct crypto_params_sdes)

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;


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(const struct crypto_params_sdes *cs, gconstpointer b)
{
	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, uint32_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, uint32_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, uint32_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, uint32_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_free(cps);
}
INLINE void crypto_params_sdes_queue_clear(sdes_q *q) {
	t_queue_clear_full(q, crypto_params_sdes_free);
}
INLINE void crypto_params_sdes_queue_copy(sdes_q *dst, const sdes_q *src) {
	for (auto_iter(l, src->head); l; l = l->next) {
		struct crypto_params_sdes *cps = l->data;
		struct crypto_params_sdes *cpy = g_new(__typeof(*cpy), 1);
		*cpy = *cps;
		cpy->params.mki = NULL;
		crypto_params_copy(&cpy->params, &cps->params, 1);
		t_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(str_case_ht sdes_only,
			str_case_ht 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 (t_hash_table_is_set(sdes_only))
	{
		if (!t_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 (t_hash_table_is_set(sdes_no) &&
		t_hash_table_lookup(sdes_no, &cps->name_str))
	{
		return 1;
	}

	return 0;
}

#include "main.h"
#include "log.h"
#include <inttypes.h>


typedef GString crypto_debug_string;

INLINE crypto_debug_string *crypto_debug_init(bool flag) {
	if (rtpe_config.common.log_levels[log_level_index_srtp] < LOG_DEBUG)
		return NULL;
	if (!flag)
		return NULL;
	return g_string_new("");
}
void __crypto_debug_printf(crypto_debug_string *gs, const char *fmt, ...) __attribute__((format(printf,2,3)));
#define crypto_debug_printf(gs, f, ...) \
	do { \
		if (gs) \
			__crypto_debug_printf(gs, f, ##__VA_ARGS__); \
	} while (0)
INLINE void crypto_debug_dump_raw(crypto_debug_string *gs, const char *b, int len) {
	for (int i = 0; i < len; i++)
		crypto_debug_printf(gs, "%02" PRIx8, (unsigned char) b[i]);
}
INLINE void crypto_debug_dump(crypto_debug_string *gs, const str *s) {
	crypto_debug_dump_raw(gs, s->s, s->len);
}
INLINE void crypto_debug_finish(crypto_debug_string *gs) {
	ilogs(srtp, LOG_NOTICE, "Crypto debug: %.*s", (int) gs->len, gs->str);
	g_string_free(gs, TRUE);
}

G_DEFINE_AUTOPTR_CLEANUP_FUNC(crypto_debug_string, crypto_debug_finish);



#endif