1 /**
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 
get_rtcp_ssrc(uint32_t * ssrc,struct mbuf * mb)19 static 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 
srtcp_encrypt(struct srtp * srtp,struct mbuf * mb)31 int 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 
srtcp_decrypt(struct srtp * srtp,struct mbuf * mb)133 int 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 }
255