blob: d67789870d3351bbcbfe67b58a135baade6e585c [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file srtcp.c Secure Real-time Transport Control Protocol (SRTCP)
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_mbuf.h>
10#include <re_list.h>
11#include <re_hmac.h>
12#include <re_sha.h>
13#include <re_aes.h>
14#include <re_net.h>
15#include <re_srtp.h>
16#include "srtp.h"
17
18
19static int get_rtcp_ssrc(uint32_t *ssrc, struct mbuf *mb)
20{
21 if (mbuf_get_left(mb) < 8)
22 return EBADMSG;
23
24 mbuf_advance(mb, 4);
25 *ssrc = ntohl(mbuf_read_u32(mb));
26
27 return 0;
28}
29
30
31int srtcp_encrypt(struct srtp *srtp, struct mbuf *mb)
32{
33 struct srtp_stream *strm;
34 struct comp *rtcp;
35 uint32_t ssrc;
36 size_t start;
37 uint32_t ep = 0;
38 int err;
39
40 if (!srtp || !mb)
41 return EINVAL;
42
43 rtcp = &srtp->rtcp;
44 start = mb->pos;
45
46 err = get_rtcp_ssrc(&ssrc, mb);
47 if (err)
48 return err;
49
50 err = stream_get(&strm, srtp, ssrc);
51 if (err)
52 return err;
53
54 strm->rtcp_index = (strm->rtcp_index+1) & 0x7fffffff;
55
56 if (rtcp->aes && rtcp->mode == AES_MODE_CTR) {
57 union vect128 iv;
58 uint8_t *p = mbuf_buf(mb);
59
60 srtp_iv_calc(&iv, &rtcp->k_s, ssrc, strm->rtcp_index);
61
62 aes_set_iv(rtcp->aes, iv.u8);
63 err = aes_encr(rtcp->aes, p, p, mbuf_get_left(mb));
64 if (err)
65 return err;
66
67 ep = 1;
68 }
69 else if (rtcp->aes && rtcp->mode == AES_MODE_GCM) {
70
71 union vect128 iv;
72 uint8_t *p = mbuf_buf(mb);
73 uint8_t tag[GCM_TAGLEN];
74 const uint32_t ix_be = htonl(1<<31 | strm->rtcp_index);
75
76 srtp_iv_calc_gcm(&iv, &rtcp->k_s, ssrc, strm->rtcp_index);
77
78 aes_set_iv(rtcp->aes, iv.u8);
79
80 /* The RTCP Header and Index is Associated Data */
81 err = aes_encr(rtcp->aes, NULL, &mb->buf[start],
82 mb->pos - start);
83 err |= aes_encr(rtcp->aes, NULL,
84 (void *)&ix_be, sizeof(ix_be));
85 if (err)
86 return err;
87
88 err = aes_encr(rtcp->aes, p, p, mbuf_get_left(mb));
89 if (err)
90 return err;
91
92 err = aes_get_authtag(rtcp->aes, tag, sizeof(tag));
93 if (err)
94 return err;
95
96 mb->pos = mb->end;
97 err = mbuf_write_mem(mb, tag, sizeof(tag));
98 if (err)
99 return err;
100
101 ep = 1;
102 }
103
104 /* append E-bit and SRTCP-index */
105 mb->pos = mb->end;
106 err = mbuf_write_u32(mb, htonl(ep<<31 | strm->rtcp_index));
107 if (err)
108 return err;
109
110 if (rtcp->hmac) {
111 uint8_t tag[SHA_DIGEST_LENGTH];
112
113 mb->pos = start;
114
115 err = hmac_digest(rtcp->hmac, tag, sizeof(tag),
116 mbuf_buf(mb), mbuf_get_left(mb));
117 if (err)
118 return err;
119
120 mb->pos = mb->end;
121
122 err = mbuf_write_mem(mb, tag, rtcp->tag_len);
123 if (err)
124 return err;
125 }
126
127 mb->pos = start;
128
129 return 0;
130}
131
132
133int srtcp_decrypt(struct srtp *srtp, struct mbuf *mb)
134{
135 size_t start, eix_start, pld_start;
136 struct srtp_stream *strm;
137 struct comp *rtcp;
138 uint32_t v, ix;
139 uint32_t ssrc;
140 bool ep;
141 int err;
142
143 if (!srtp || !mb)
144 return EINVAL;
145
146 rtcp = &srtp->rtcp;
147 start = mb->pos;
148
149 err = get_rtcp_ssrc(&ssrc, mb);
150 if (err)
151 return err;
152
153 err = stream_get(&strm, srtp, ssrc);
154 if (err)
155 return err;
156
157 pld_start = mb->pos;
158
159 if (mbuf_get_left(mb) < (4 + rtcp->tag_len))
160 return EBADMSG;
161
162 /* Read out E-Bit, SRTCP-index and Authentication Tag */
163 eix_start = mb->end - (4 + rtcp->tag_len);
164 mb->pos = eix_start;
165 v = ntohl(mbuf_read_u32(mb));
166
167 ep = (v >> 31) & 1;
168 ix = v & 0x7fffffff;
169
170 if (rtcp->hmac) {
171 uint8_t tag[SHA_DIGEST_LENGTH], tag_pkt[SHA_DIGEST_LENGTH];
172 const size_t tag_start = mb->pos;
173
174 err = mbuf_read_mem(mb, tag_pkt, rtcp->tag_len);
175 if (err)
176 return err;
177
178 mb->pos = start;
179 mb->end = tag_start;
180
181 err = hmac_digest(rtcp->hmac, tag, sizeof(tag),
182 mbuf_buf(mb), mbuf_get_left(mb));
183 if (err)
184 return err;
185
186 if (0 != memcmp(tag, tag_pkt, rtcp->tag_len))
187 return EAUTH;
188
189 /*
190 * SRTCP replay protection is as defined in Section 3.3.2,
191 * but using the SRTCP index as the index i and a separate
192 * Replay List that is specific to SRTCP.
193 */
194 if (!srtp_replay_check(&strm->replay_rtcp, ix))
195 return EALREADY;
196 }
197
198 mb->end = eix_start;
199
200 if (rtcp->aes && ep && rtcp->mode == AES_MODE_CTR) {
201 union vect128 iv;
202 uint8_t *p;
203
204 mb->pos = pld_start;
205 p = mbuf_buf(mb);
206
207 srtp_iv_calc(&iv, &rtcp->k_s, ssrc, ix);
208
209 aes_set_iv(rtcp->aes, iv.u8);
210 err = aes_decr(rtcp->aes, p, p, mbuf_get_left(mb));
211 if (err)
212 return err;
213 }
214 else if (rtcp->aes && ep && rtcp->mode == AES_MODE_GCM) {
215
216 union vect128 iv;
217 size_t tag_start;
218 uint8_t *p;
219
220 srtp_iv_calc_gcm(&iv, &rtcp->k_s, ssrc, ix);
221
222 aes_set_iv(rtcp->aes, iv.u8);
223
224 /* The RTP Header is Associated Data */
225 err = aes_decr(rtcp->aes, NULL, &mb->buf[start],
226 pld_start - start);
227 err |= aes_decr(rtcp->aes, NULL, &mb->buf[eix_start], 4);
228 if (err)
229 return err;
230
231 mb->pos = pld_start;
232 p = mbuf_buf(mb);
233
234 if (mbuf_get_left(mb) < GCM_TAGLEN)
235 return EBADMSG;
236
237 tag_start = mb->end - GCM_TAGLEN;
238
239 err = aes_decr(rtcp->aes, p, p, tag_start - pld_start);
240 if (err)
241 return err;
242
243 err = aes_authenticate(rtcp->aes, &mb->buf[tag_start],
244 GCM_TAGLEN);
245 if (err)
246 return err;
247
248 mb->end = tag_start;
249 }
250
251 mb->pos = start;
252
253 return 0;
254}