blob: 7625126b46a82c9f9208301d7441a0a19b9e187a [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file srtp.c Secure Real-time Transport Protocol (SRTP)
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <string.h>
7#include <re_types.h>
8#include <re_fmt.h>
9#include <re_mem.h>
10#include <re_mbuf.h>
11#include <re_list.h>
12#include <re_hmac.h>
13#include <re_sha.h>
14#include <re_aes.h>
15#include <re_sa.h>
16#include <re_rtp.h>
17#include <re_srtp.h>
18#include "srtp.h"
19
20
21/** SRTP protocol values */
22enum {
23 MAX_KEYLEN = 32, /**< Maximum keylength in bytes */
24};
25
26
27static inline int seq_diff(uint16_t x, uint16_t y)
28{
29 return (int)y - (int)x;
30}
31
32
33static int comp_init(struct comp *c, unsigned offs,
34 const uint8_t *key, size_t key_b,
35 const uint8_t *s, size_t s_b,
36 size_t tag_len, bool encrypted, bool hash,
37 enum aes_mode mode)
38{
39 uint8_t k_e[MAX_KEYLEN], k_a[SHA_DIGEST_LENGTH];
40 int err = 0;
41
42 if (key_b > sizeof(k_e))
43 return EINVAL;
44
45 if (tag_len > SHA_DIGEST_LENGTH)
46 return EINVAL;
47
48 c->tag_len = tag_len;
49 c->mode = mode;
50
51 err |= srtp_derive(k_e, key_b, 0x00+offs, key, key_b, s, s_b);
52 err |= srtp_derive(k_a, sizeof(k_a), 0x01+offs, key, key_b, s, s_b);
53 err |= srtp_derive(c->k_s.u8, 14, 0x02+offs, key, key_b, s, s_b);
54 if (err)
55 return err;
56
57 if (encrypted) {
58 err = aes_alloc(&c->aes, mode, k_e, key_b*8, NULL);
59 if (err)
60 return err;
61 }
62
63 if (hash) {
64 err = hmac_create(&c->hmac, HMAC_HASH_SHA1, k_a, sizeof(k_a));
65 if (err)
66 return err;
67 }
68
69 return err;
70}
71
72
73static void destructor(void *arg)
74{
75 struct srtp *srtp = arg;
76
77 mem_deref(srtp->rtp.aes);
78 mem_deref(srtp->rtcp.aes);
79 mem_deref(srtp->rtp.hmac);
80 mem_deref(srtp->rtcp.hmac);
81
82 list_flush(&srtp->streaml);
83}
84
85
86int srtp_alloc(struct srtp **srtpp, enum srtp_suite suite,
87 const uint8_t *key, size_t key_bytes, int flags)
88{
89 struct srtp *srtp;
90 const uint8_t *master_salt;
91 size_t cipher_bytes, salt_bytes, auth_bytes;
92 enum aes_mode mode;
93 bool hash;
94 int err = 0;
95
96 if (!srtpp || !key)
97 return EINVAL;
98
99 switch (suite) {
100
101 case SRTP_AES_CM_128_HMAC_SHA1_80:
102 mode = AES_MODE_CTR;
103 cipher_bytes = 16;
104 salt_bytes = 14;
105 auth_bytes = 10;
106 hash = true;
107 break;
108
109 case SRTP_AES_CM_128_HMAC_SHA1_32:
110 mode = AES_MODE_CTR;
111 cipher_bytes = 16;
112 salt_bytes = 14;
113 auth_bytes = 4;
114 hash = true;
115 break;
116
117 case SRTP_AES_256_CM_HMAC_SHA1_80:
118 mode = AES_MODE_CTR;
119 cipher_bytes = 32;
120 salt_bytes = 14;
121 auth_bytes = 10;
122 hash = true;
123 break;
124
125 case SRTP_AES_256_CM_HMAC_SHA1_32:
126 mode = AES_MODE_CTR;
127 cipher_bytes = 32;
128 salt_bytes = 14;
129 auth_bytes = 4;
130 hash = true;
131 break;
132
133 case SRTP_AES_128_GCM:
134 mode = AES_MODE_GCM;
135 cipher_bytes = 16;
136 salt_bytes = 12;
137 auth_bytes = 0;
138 hash = false;
139 break;
140
141 case SRTP_AES_256_GCM:
142 mode = AES_MODE_GCM;
143 cipher_bytes = 32;
144 salt_bytes = 12;
145 auth_bytes = 0;
146 hash = false;
147 break;
148
149 default:
150 return ENOTSUP;
151 };
152
153 if ((cipher_bytes + salt_bytes) != key_bytes)
154 return EINVAL;
155
156 master_salt = &key[cipher_bytes];
157
158 srtp = mem_zalloc(sizeof(*srtp), destructor);
159 if (!srtp)
160 return ENOMEM;
161
162 err |= comp_init(&srtp->rtp, 0, key, cipher_bytes,
163 master_salt, salt_bytes, auth_bytes,
164 true, hash, mode);
165 err |= comp_init(&srtp->rtcp, 3, key, cipher_bytes,
166 master_salt, salt_bytes, auth_bytes,
167 !(flags & SRTP_UNENCRYPTED_SRTCP), hash, mode);
168 if (err)
169 goto out;
170
171 out:
172 if (err)
173 mem_deref(srtp);
174 else
175 *srtpp = srtp;
176
177 return err;
178}
179
180
181int srtp_encrypt(struct srtp *srtp, struct mbuf *mb)
182{
183 struct srtp_stream *strm;
184 struct rtp_header hdr;
185 struct comp *comp;
186 size_t start;
187 uint64_t ix;
188 int err;
189
190 if (!srtp || !mb)
191 return EINVAL;
192
193 comp = &srtp->rtp;
194
195 start = mb->pos;
196
197 err = rtp_hdr_decode(&hdr, mb);
198 if (err)
199 return err;
200
201 err = stream_get_seq(&strm, srtp, hdr.ssrc, hdr.seq);
202 if (err)
203 return err;
204
205 /* Roll-Over Counter (ROC) */
206 if (seq_diff(strm->s_l, hdr.seq) <= -32768) {
207 strm->roc++;
208 strm->s_l = 0;
209 }
210
211 ix = 65536ULL * strm->roc + hdr.seq;
212
213 if (comp->aes && comp->mode == AES_MODE_CTR) {
214 union vect128 iv;
215 uint8_t *p = mbuf_buf(mb);
216
217 srtp_iv_calc(&iv, &comp->k_s, strm->ssrc, ix);
218
219 aes_set_iv(comp->aes, iv.u8);
220 err = aes_encr(comp->aes, p, p, mbuf_get_left(mb));
221 if (err)
222 return err;
223 }
224 else if (comp->aes && comp->mode == AES_MODE_GCM) {
225 union vect128 iv;
226 uint8_t *p = mbuf_buf(mb);
227 uint8_t tag[GCM_TAGLEN];
228
229 srtp_iv_calc_gcm(&iv, &comp->k_s, strm->ssrc, ix);
230
231 aes_set_iv(comp->aes, iv.u8);
232
233 /* The RTP Header is Associated Data */
234 err = aes_encr(comp->aes, NULL, &mb->buf[start],
235 mb->pos - start);
236 if (err)
237 return err;
238
239 err = aes_encr(comp->aes, p, p, mbuf_get_left(mb));
240 if (err)
241 return err;
242
243 err = aes_get_authtag(comp->aes, tag, sizeof(tag));
244 if (err)
245 return err;
246
247 mb->pos = mb->end;
248 err = mbuf_write_mem(mb, tag, sizeof(tag));
249 if (err)
250 return err;
251 }
252
253 if (comp->hmac) {
254 const size_t tag_start = mb->end;
255 uint8_t tag[SHA_DIGEST_LENGTH];
256
257 mb->pos = tag_start;
258
259 err = mbuf_write_u32(mb, htonl(strm->roc));
260 if (err)
261 return err;
262
263 mb->pos = start;
264
265 err = hmac_digest(comp->hmac, tag, sizeof(tag),
266 mbuf_buf(mb), mbuf_get_left(mb));
267 if (err)
268 return err;
269
270 mb->pos = mb->end = tag_start;
271
272 err = mbuf_write_mem(mb, tag, comp->tag_len);
273 if (err)
274 return err;
275 }
276
277 if (hdr.seq > strm->s_l)
278 strm->s_l = hdr.seq;
279
280 mb->pos = start;
281
282 return 0;
283}
284
285
286int srtp_decrypt(struct srtp *srtp, struct mbuf *mb)
287{
288 struct srtp_stream *strm;
289 struct rtp_header hdr;
290 struct comp *comp;
291 uint64_t ix;
292 size_t start;
293 int diff;
294 int err;
295
296 if (!srtp || !mb)
297 return EINVAL;
298
299 comp = &srtp->rtp;
300
301 start = mb->pos;
302
303 err = rtp_hdr_decode(&hdr, mb);
304 if (err)
305 return err;
306
307 err = stream_get_seq(&strm, srtp, hdr.ssrc, hdr.seq);
308 if (err)
309 return err;
310
311 diff = seq_diff(strm->s_l, hdr.seq);
312 if (diff > 32768)
313 return ETIMEDOUT;
314
315 /* Roll-Over Counter (ROC) */
316 if (diff <= -32768) {
317 strm->roc++;
318 strm->s_l = 0;
319 }
320
321 ix = srtp_get_index(strm->roc, strm->s_l, hdr.seq);
322
323 if (comp->hmac) {
324 uint8_t tag_calc[SHA_DIGEST_LENGTH];
325 uint8_t tag_pkt[SHA_DIGEST_LENGTH];
326 size_t pld_start, tag_start;
327
328 if (mbuf_get_left(mb) < comp->tag_len)
329 return EBADMSG;
330
331 pld_start = mb->pos;
332 tag_start = mb->end - comp->tag_len;
333
334 mb->pos = tag_start;
335
336 err = mbuf_read_mem(mb, tag_pkt, comp->tag_len);
337 if (err)
338 return err;
339
340 mb->pos = mb->end = tag_start;
341
342 err = mbuf_write_u32(mb, htonl(strm->roc));
343 if (err)
344 return err;
345
346 mb->pos = start;
347
348 err = hmac_digest(comp->hmac, tag_calc, sizeof(tag_calc),
349 mbuf_buf(mb), mbuf_get_left(mb));
350 if (err)
351 return err;
352
353 mb->pos = pld_start;
354 mb->end = tag_start;
355
356 if (0 != memcmp(tag_calc, tag_pkt, comp->tag_len))
357 return EAUTH;
358
359 /*
360 * 3.3.2. Replay Protection
361 *
362 * Secure replay protection is only possible when
363 * integrity protection is present.
364 */
365 if (!srtp_replay_check(&strm->replay_rtp, ix))
366 return EALREADY;
367 }
368
369 if (comp->aes && comp->mode == AES_MODE_CTR) {
370
371 union vect128 iv;
372 uint8_t *p = mbuf_buf(mb);
373
374 srtp_iv_calc(&iv, &comp->k_s, strm->ssrc, ix);
375
376 aes_set_iv(comp->aes, iv.u8);
377 err = aes_decr(comp->aes, p, p, mbuf_get_left(mb));
378 if (err)
379 return err;
380 }
381 else if (comp->aes && comp->mode == AES_MODE_GCM) {
382
383 union vect128 iv;
384 uint8_t *p = mbuf_buf(mb);
385 size_t tag_start;
386
387 srtp_iv_calc_gcm(&iv, &comp->k_s, strm->ssrc, ix);
388
389 aes_set_iv(comp->aes, iv.u8);
390
391 /* The RTP Header is Associated Data */
392 err = aes_decr(comp->aes, NULL, &mb->buf[start],
393 mb->pos - start);
394 if (err)
395 return err;
396
397 if (mbuf_get_left(mb) < GCM_TAGLEN)
398 return EBADMSG;
399
400 tag_start = mb->end - GCM_TAGLEN;
401
402 err = aes_decr(comp->aes, p, p, tag_start - mb->pos);
403 if (err)
404 return err;
405
406 err = aes_authenticate(comp->aes, &mb->buf[tag_start],
407 GCM_TAGLEN);
408 if (err)
409 return err;
410
411 mb->end = tag_start;
412
413 /*
414 * 3.3.2. Replay Protection
415 *
416 * Secure replay protection is only possible when
417 * integrity protection is present.
418 */
419 if (!srtp_replay_check(&strm->replay_rtp, ix))
420 return EALREADY;
421
422 }
423
424 if (hdr.seq > strm->s_l)
425 strm->s_l = hdr.seq;
426
427 mb->pos = start;
428
429 return 0;
430}