/src/rtpproxy/modules/dtls_gw/rtpp_dtls_conn.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2022 Sippy Software, Inc., http://www.sippysoft.com |
3 | | * Copyright (C) 2010 Alfred E. Heggestad |
4 | | * Copyright (C) 2010 Creytiv.com |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * 1. Redistributions of source code must retain the above copyright |
10 | | * notice, this list of conditions and the following disclaimer. |
11 | | * 2. Redistributions in binary form must reproduce the above copyright |
12 | | * notice, this list of conditions and the following disclaimer in the |
13 | | * documentation and/or other materials provided with the distribution. |
14 | | * |
15 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 | | * SUCH DAMAGE. |
26 | | * |
27 | | */ |
28 | | |
29 | | #include <sys/socket.h> |
30 | | #include <stddef.h> |
31 | | #include <stdint.h> |
32 | | #include <stdlib.h> |
33 | | #include <string.h> |
34 | | |
35 | | #include <openssl/ssl.h> |
36 | | #include <openssl/err.h> |
37 | | #include <openssl/srtp.h> |
38 | | |
39 | | #include <srtp2/srtp.h> |
40 | | |
41 | | #include "config_pp.h" |
42 | | |
43 | | #include "rtpp_module.h" |
44 | | #include "rtpp_debug.h" |
45 | | #include "rtpp_cfg.h" |
46 | | #include "rtpp_log.h" |
47 | | #include "rtpp_log_obj.h" |
48 | | #include "rtpp_netio_async.h" |
49 | | #include "rtpp_codeptr.h" |
50 | | #include "rtpp_refcnt.h" |
51 | | #include "rtpp_str.h" |
52 | | #include "rtpp_stream.h" |
53 | | #include "rtp.h" |
54 | | #include "rtpp_time.h" |
55 | | #include "rtp_packet.h" |
56 | | #include "rtpp_packetops.h" |
57 | | #include "rtpp_proc_async.h" |
58 | | #include "rtpp_threads.h" |
59 | | #include "rtpp_ssrc.h" |
60 | | #include "rtpp_timed.h" |
61 | | #include "rtpp_timed_task.h" |
62 | | #include "rtpp_codeptr.h" |
63 | | #include "advanced/packet_processor.h" |
64 | | #include "advanced/pproc_manager.h" |
65 | | #include "rtpp_refproxy.h" |
66 | | #include "rtpp_weakref.h" |
67 | | |
68 | | #include "rtpp_dtls_util.h" |
69 | | #include "rtpp_dtls_conn.h" |
70 | | |
71 | | enum rdc_state { |
72 | | RDC_INIT, |
73 | | RDC_CONNECTING, |
74 | | RDC_UP, |
75 | | RDC_DEAD |
76 | | }; |
77 | | |
78 | | enum srtp_suite { |
79 | | SRTP_AES_CM_128_HMAC_SHA1_32, |
80 | | SRTP_AES_CM_128_HMAC_SHA1_80, |
81 | | SRTP_F8_128_HMAC_SHA1_32, |
82 | | SRTP_F8_128_HMAC_SHA1_80, |
83 | | SRTP_AES_256_CM_HMAC_SHA1_32, |
84 | | SRTP_AES_256_CM_HMAC_SHA1_80, |
85 | | SRTP_AES_128_GCM, |
86 | | SRTP_AES_256_GCM, |
87 | | }; |
88 | | |
89 | | DEFINE_RAW_METHOD(set_srtp_policy, void, srtp_crypto_policy_t *); |
90 | | |
91 | | struct srtp_crypto_suite { |
92 | | const char *can_name; |
93 | | int key_size; |
94 | | int iv_size; |
95 | | int tag_size; |
96 | | srtp_sec_serv_t sec_serv; |
97 | | set_srtp_policy_t set_srtp_policy; |
98 | | }; |
99 | | |
100 | | const struct srtp_crypto_suite srtp_suites [] = { |
101 | | [SRTP_AES_CM_128_HMAC_SHA1_32] = {.can_name = "AES_CM_128_HMAC_SHA1_32", |
102 | | .sec_serv = sec_serv_conf_and_auth, .key_size = (128 / 8), |
103 | | .iv_size = (112 / 8), .tag_size = (32 / 8), |
104 | | .set_srtp_policy = srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32}, |
105 | | [SRTP_AES_CM_128_HMAC_SHA1_80] = {.can_name = "AES_CM_128_HMAC_SHA1_80", |
106 | | .sec_serv = sec_serv_conf_and_auth, .key_size = (128 / 8), |
107 | | .iv_size = (112 / 8), .tag_size = (80 / 8), |
108 | | .set_srtp_policy = srtp_crypto_policy_set_rtp_default}, |
109 | | [SRTP_F8_128_HMAC_SHA1_32] = {.can_name = "F8_128_HMAC_SHA1_32", |
110 | | .sec_serv = sec_serv_conf_and_auth, .key_size = (128 / 8), |
111 | | .iv_size = (112 / 8), .tag_size = (32 / 8)}, |
112 | | [SRTP_F8_128_HMAC_SHA1_80] = {.can_name = "F8_128_HMAC_SHA1_80", |
113 | | .sec_serv = sec_serv_conf_and_auth, .key_size = (128 / 8), |
114 | | .iv_size = (112 / 8), .tag_size = (80 / 8)}, |
115 | | [SRTP_AES_256_CM_HMAC_SHA1_32] = {.can_name = "AES_256_CM_HMAC_SHA1_32", |
116 | | .sec_serv = sec_serv_conf_and_auth, .key_size = (256 / 8), |
117 | | .iv_size = (112 / 8), .tag_size = (32 / 8), |
118 | | .set_srtp_policy = srtp_crypto_policy_set_aes_cm_256_hmac_sha1_32}, |
119 | | [SRTP_AES_256_CM_HMAC_SHA1_80] = {.can_name = "AES_256_CM_HMAC_SHA1_80", |
120 | | .sec_serv = sec_serv_conf_and_auth, .key_size = (256 / 8), |
121 | | .iv_size = (112 / 8), .tag_size = (80 / 8), |
122 | | .set_srtp_policy = srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80}, |
123 | | [SRTP_AES_128_GCM] = {.can_name = "AES_128_GCM", |
124 | | .sec_serv = sec_serv_conf_and_auth, .key_size = (128 / 8), |
125 | | .iv_size = (96 / 8), .tag_size = (128 / 8), |
126 | | .set_srtp_policy = srtp_crypto_policy_set_aes_gcm_128_16_auth}, |
127 | | [SRTP_AES_256_GCM] = {.can_name = "AES_256_GCM", |
128 | | .sec_serv = sec_serv_conf_and_auth, .key_size = (256 / 8), |
129 | | .iv_size = (96 / 8), .tag_size = (128 / 8), |
130 | | .set_srtp_policy = srtp_crypto_policy_set_aes_gcm_256_16_auth} |
131 | | }; |
132 | | |
133 | | struct rtpp_dtls_conn_priv { |
134 | | struct rtpp_dtls_conn pub; |
135 | | uint64_t dtls_strm_id; |
136 | | struct rtpp_timed *timed_cf; |
137 | | struct rtpp_weakref *streams_wrt; |
138 | | pthread_mutex_t state_lock; |
139 | | enum rdc_state state; |
140 | | enum rtpp_dtls_mode mode; |
141 | | SSL *ssl_ctx; |
142 | | srtp_t srtp_ctx_out; |
143 | | srtp_t srtp_ctx_in; |
144 | | BIO_METHOD *biomet; |
145 | | BIO *sbio_out; |
146 | | BIO *sbio_in; |
147 | | char fingerprint[FP_DIGEST_STRBUF_LEN]; |
148 | | uint32_t ssrc; |
149 | | struct rtpp_timed_task *ttp; |
150 | | struct rtpp_minfo *mself; |
151 | | }; |
152 | | |
153 | | static BIO_METHOD *bio_method_udp(void); |
154 | | static int tls_accept(struct rtpp_dtls_conn_priv *); |
155 | | static int tls_connect(struct rtpp_dtls_conn_priv *); |
156 | | static int check_timer(struct rtpp_dtls_conn_priv *); |
157 | | |
158 | | enum { |
159 | | MTU_DEFAULT = 1400, |
160 | | MTU_FALLBACK = 548, |
161 | | }; |
162 | | |
163 | | static void rtpp_dtls_conn_dtls_recv(struct rtpp_dtls_conn *, |
164 | | const struct rtp_packet *); |
165 | | static struct res_loc rtpp_dtls_conn_rtp_send(struct rtpp_dtls_conn *, |
166 | | struct pkt_proc_ctx *); |
167 | | static struct res_loc rtpp_dtls_conn_srtp_recv(struct rtpp_dtls_conn *, |
168 | | struct pkt_proc_ctx *); |
169 | | static enum rtpp_dtls_mode rtpp_dtls_conn_setmode(struct rtpp_dtls_conn *, |
170 | | const struct rdc_peer_spec *rdfsp); |
171 | | static void rtpp_dtls_conn_godead(struct rtpp_dtls_conn *); |
172 | | |
173 | | static int tls_srtp_keyinfo(SSL *, const struct srtp_crypto_suite **, |
174 | | uint8_t *, size_t, uint8_t *, size_t, struct rtpp_log *); |
175 | | static int tls_peer_fingerprint(SSL *, char *, size_t); |
176 | | |
177 | | DEFINE_SMETHODS(rtpp_dtls_conn, |
178 | | .dtls_recv = &rtpp_dtls_conn_dtls_recv, |
179 | | .rtp_send = &rtpp_dtls_conn_rtp_send, |
180 | | .srtp_recv = &rtpp_dtls_conn_srtp_recv, |
181 | | .setmode = &rtpp_dtls_conn_setmode, |
182 | | .godead = &rtpp_dtls_conn_godead, |
183 | | ); |
184 | | |
185 | | static void |
186 | | rtpp_dtls_conn_dtor(struct rtpp_dtls_conn_priv *pvt) |
187 | 28.7k | { |
188 | | |
189 | 28.7k | if (pvt->srtp_ctx_in != NULL) |
190 | 0 | srtp_dealloc(pvt->srtp_ctx_in); |
191 | 28.7k | if (pvt->srtp_ctx_out != NULL) |
192 | 0 | srtp_dealloc(pvt->srtp_ctx_out); |
193 | 28.7k | pthread_mutex_destroy(&pvt->state_lock); |
194 | | /* BIO_free(pvt->sbio_out); <- done by SSL_free() */ |
195 | | /* BIO_free(pvt->sbio_in); <- done by SSL_free() */ |
196 | 28.7k | SSL_free(pvt->ssl_ctx); |
197 | 28.7k | BIO_meth_free(pvt->biomet); |
198 | 28.7k | } |
199 | | |
200 | | struct rtpp_dtls_conn * |
201 | | rtpp_dtls_conn_ctor(const struct rtpp_cfg *cfsp, SSL_CTX *ctx, |
202 | | struct rtpp_stream *dtls_strmp, struct rtpp_minfo *mself) |
203 | 28.7k | { |
204 | 28.7k | struct rtpp_dtls_conn_priv *pvt; |
205 | | |
206 | 28.7k | pvt = mod_rzmalloc(sizeof(*pvt), PVT_RCOFFS(pvt)); |
207 | 28.7k | if (pvt == NULL) { |
208 | 0 | goto e0; |
209 | 0 | } |
210 | 28.7k | pvt->biomet = bio_method_udp(); |
211 | 28.7k | if (pvt->biomet == NULL) { |
212 | 0 | ERR_clear_error(); |
213 | 0 | goto e1; |
214 | 0 | } |
215 | 28.7k | pvt->ssl_ctx = SSL_new(ctx); |
216 | 28.7k | if (pvt->ssl_ctx == NULL) { |
217 | 0 | ERR_clear_error(); |
218 | 0 | goto e2; |
219 | 0 | } |
220 | 28.7k | pvt->sbio_in = BIO_new(BIO_s_mem()); |
221 | 28.7k | if (pvt->sbio_in == NULL) { |
222 | 0 | ERR_clear_error(); |
223 | 0 | goto e3; |
224 | 0 | } |
225 | 28.7k | pvt->sbio_out = BIO_new(pvt->biomet); |
226 | 28.7k | if (pvt->sbio_out == NULL) { |
227 | 0 | ERR_clear_error(); |
228 | 0 | goto e4; |
229 | 0 | } |
230 | 28.7k | if (pthread_mutex_init(&pvt->state_lock, NULL) != 0) { |
231 | 0 | goto e5; |
232 | 0 | } |
233 | 28.7k | BIO_set_data(pvt->sbio_out, pvt); |
234 | 28.7k | SSL_set_bio(pvt->ssl_ctx, pvt->sbio_in, pvt->sbio_out); |
235 | 28.7k | SSL_set_read_ahead(pvt->ssl_ctx, 1); |
236 | 28.7k | pvt->mode = RTPP_DTLS_ACTPASS; |
237 | 28.7k | pvt->state = RDC_INIT; |
238 | | /* Cannot grab refcount here, circular reference would ensue */ |
239 | | /* RTPP_OBJ_INCREF(dtls_strmp); */ |
240 | 28.7k | pvt->dtls_strm_id = dtls_strmp->stuid; |
241 | 28.7k | RTPP_OBJ_BORROW(&pvt->pub, cfsp->rtp_streams_wrt); |
242 | 28.7k | pvt->streams_wrt = cfsp->rtp_streams_wrt; |
243 | 28.7k | pvt->timed_cf = cfsp->rtpp_timed_cf; |
244 | 28.7k | PUBINST_FININIT(&pvt->pub, pvt, rtpp_dtls_conn_dtor); |
245 | 28.7k | pvt->mself = mself; |
246 | 28.7k | return (&(pvt->pub)); |
247 | 0 | e5: |
248 | 0 | BIO_free(pvt->sbio_out); |
249 | 0 | e4: |
250 | 0 | BIO_free(pvt->sbio_in); |
251 | 0 | e3: |
252 | 0 | SSL_free(pvt->ssl_ctx); |
253 | 0 | e2: |
254 | 0 | BIO_meth_free(pvt->biomet); |
255 | 0 | e1: |
256 | 0 | RTPP_OBJ_DECREF(&pvt->pub); |
257 | 0 | e0: |
258 | 0 | return (NULL); |
259 | 0 | } |
260 | | |
261 | | static enum rtpp_dtls_mode |
262 | | rtpp_dtls_conn_pickmode(enum rtpp_dtls_mode peer_mode) |
263 | 21.8k | { |
264 | | |
265 | 21.8k | switch (peer_mode) { |
266 | 0 | case RTPP_DTLS_ACTPASS: |
267 | 0 | return (RTPP_DTLS_PASSIVE); |
268 | 13.2k | case RTPP_DTLS_ACTIVE: |
269 | 13.2k | return (RTPP_DTLS_PASSIVE); |
270 | 8.54k | case RTPP_DTLS_PASSIVE: |
271 | 8.54k | return (RTPP_DTLS_ACTIVE); |
272 | 0 | default: |
273 | 0 | abort(); |
274 | 21.8k | } |
275 | | /* Not Reached */ |
276 | 21.8k | } |
277 | | |
278 | | static enum rtpp_dtls_mode |
279 | | rtpp_dtls_conn_setmode(struct rtpp_dtls_conn *self, |
280 | | const struct rdc_peer_spec *rdfsp) |
281 | 39.9k | { |
282 | 39.9k | struct rtpp_dtls_conn_priv *pvt; |
283 | 39.9k | enum rtpp_dtls_mode my_mode; |
284 | 39.9k | char *ep; |
285 | | |
286 | 39.9k | PUB2PVT(self, pvt); |
287 | | |
288 | 39.9k | pthread_mutex_lock(&pvt->state_lock); |
289 | | |
290 | 39.9k | if (rdfsp == NULL) { |
291 | 18.1k | goto out; |
292 | 18.1k | } |
293 | 21.8k | my_mode = rtpp_dtls_conn_pickmode(rdfsp->peer_mode); |
294 | 21.8k | if (my_mode != pvt->mode && pvt->state != RDC_INIT) { |
295 | 82 | RTPP_LOG(pvt->mself->log, RTPP_LOG_ERR, "%p: cannot change mode " |
296 | 82 | "from %d to %d when in the %d state", self, pvt->mode, my_mode, |
297 | 82 | pvt->state); |
298 | 82 | goto failed; |
299 | 82 | } |
300 | 21.7k | if (rdfsp->algorithm.len != FP_DIGEST_ALG_LEN || |
301 | 21.7k | memcmp(rdfsp->algorithm.s, FP_DIGEST_ALG, FP_DIGEST_ALG_LEN) != 0) { |
302 | 4.69k | RTPP_LOG(pvt->mself->log, RTPP_LOG_ERR, "unsupported fingerprint " |
303 | 9.38k | "algorithm: \"%.*s\"", FMTSTR(&rdfsp->algorithm)); |
304 | 4.69k | goto failed; |
305 | 4.69k | } |
306 | 17.0k | if (rdfsp->fingerprint->len != FP_FINGERPRINT_STR_LEN) { |
307 | 93 | RTPP_LOG(pvt->mself->log, RTPP_LOG_ERR, "invalid fingerprint " |
308 | 93 | "length: \"%lu\"", (unsigned long)rdfsp->fingerprint->len); |
309 | 93 | goto failed; |
310 | 93 | } |
311 | 16.9k | sprintf(pvt->fingerprint, "%.*s %.*s", FMTSTR(&rdfsp->algorithm), |
312 | 16.9k | FMTSTR(rdfsp->fingerprint)); |
313 | 16.9k | if (rdfsp->ssrc != NULL) { |
314 | 13.9k | uint32_t ssrc = strtoul(rdfsp->ssrc->s, &ep, 10); |
315 | 13.9k | if (ep == rdfsp->ssrc->s || ep[0] != '\0') { |
316 | 100 | RTPP_LOG(pvt->mself->log, RTPP_LOG_ERR, "invalid ssrc: %.*s", |
317 | 200 | FMTSTR(rdfsp->ssrc)); |
318 | 100 | goto failed; |
319 | 100 | } |
320 | 13.8k | pvt->ssrc = ssrc; |
321 | 13.8k | } |
322 | 16.8k | if (my_mode == RTPP_DTLS_ACTIVE && pvt->state == RDC_INIT) { |
323 | 7.52k | pvt->state = RDC_CONNECTING; |
324 | 7.52k | if (tls_connect(pvt) != 0) { |
325 | 188 | goto failed; |
326 | 188 | } |
327 | 7.52k | } |
328 | 16.6k | pvt->mode = my_mode; |
329 | 34.8k | out: |
330 | 34.8k | pthread_mutex_unlock(&pvt->state_lock); |
331 | 34.8k | return (pvt->mode); |
332 | 5.15k | failed: |
333 | 5.15k | pthread_mutex_unlock(&pvt->state_lock); |
334 | 5.15k | return (RTPP_DTLS_MODERR); |
335 | 16.6k | } |
336 | | |
337 | | static srtp_t |
338 | | setup_srtp_stream(const struct srtp_crypto_suite *suite, uint8_t *key, |
339 | | uint32_t ssrc, struct rtpp_log *log) |
340 | 0 | { |
341 | 0 | srtp_policy_t policy; |
342 | 0 | srtp_t srtp_ctx; |
343 | 0 | int err; |
344 | |
|
345 | 0 | memset(&policy, '\0', sizeof(policy)); |
346 | 0 | suite->set_srtp_policy(&policy.rtp); |
347 | 0 | suite->set_srtp_policy(&policy.rtcp); |
348 | 0 | policy.key = key; |
349 | 0 | policy.window_size = 128; |
350 | 0 | policy.rtp.auth_tag_len = suite->tag_size; |
351 | 0 | policy.rtp.sec_serv = policy.rtcp.sec_serv = suite->sec_serv; |
352 | |
|
353 | 0 | if (ssrc == SSRC_BAD) { |
354 | 0 | policy.ssrc.type = ssrc_any_inbound; |
355 | 0 | } else { |
356 | 0 | policy.ssrc.type = ssrc_specific; |
357 | 0 | policy.ssrc.value = ssrc; |
358 | 0 | } |
359 | |
|
360 | 0 | err = srtp_create(&srtp_ctx, &policy); |
361 | 0 | if (err != srtp_err_status_ok || srtp_ctx == NULL) { |
362 | 0 | RTPP_LOG(log, RTPP_LOG_ERR, "srtp_create() failed"); |
363 | 0 | return (NULL); |
364 | 0 | } |
365 | 0 | return (srtp_ctx); |
366 | 0 | } |
367 | | |
368 | | static void |
369 | | rtpp_dtls_conn_dtls_recv(struct rtpp_dtls_conn *self, |
370 | | const struct rtp_packet *pktp) |
371 | 31.7k | { |
372 | 31.7k | struct rtpp_dtls_conn_priv *pvt; |
373 | 31.7k | int r, err; |
374 | 31.7k | uint8_t cli_key[32+14], srv_key[32+14]; |
375 | 31.7k | const struct srtp_crypto_suite *suite; |
376 | 31.7k | char srv_fingerprint[FP_DIGEST_STRBUF_LEN]; |
377 | | |
378 | 31.7k | PUB2PVT(self, pvt); |
379 | | |
380 | 31.7k | pthread_mutex_lock(&pvt->state_lock); |
381 | | |
382 | 31.7k | switch (pvt->state) { |
383 | 5.54k | case RDC_INIT: |
384 | 5.54k | pvt->state = RDC_CONNECTING; |
385 | 5.54k | break; |
386 | 25.6k | case RDC_CONNECTING: |
387 | 25.6k | case RDC_UP: |
388 | 25.6k | break; |
389 | 635 | case RDC_DEAD: |
390 | 635 | goto out; |
391 | 31.7k | } |
392 | | |
393 | 31.1k | r = BIO_write(pvt->sbio_in, pktp->data.buf, pktp->size); |
394 | 31.1k | if (r <= 0) { |
395 | 0 | RTPP_LOG(pvt->mself->log, RTPP_LOG_ERR, "receive bio write error: %i", r); |
396 | 0 | ERR_clear_error(); |
397 | 0 | goto out; |
398 | 0 | } |
399 | 31.1k | if (SSL_get_state(pvt->ssl_ctx) != TLS_ST_OK) { |
400 | 31.1k | if (pvt->state == RDC_UP) { |
401 | 0 | goto godead; |
402 | 0 | } |
403 | 31.1k | if (pvt->mode == RTPP_DTLS_ACTIVE) |
404 | 10.3k | err = tls_connect(pvt); |
405 | 20.7k | else |
406 | 20.7k | err = tls_accept(pvt); |
407 | 31.1k | if (err) { |
408 | 4.86k | goto godead; |
409 | 4.86k | } |
410 | | |
411 | | #if 0 |
412 | | RTPP_LOG(pvt->mself->log, RTPP_LOG_DBUG, "%s: state=0x%04x", |
413 | | "server", SSL_get_state(pvt->ssl_ctx)); |
414 | | #endif |
415 | | |
416 | | /* TLS connection is established */ |
417 | 26.2k | if (SSL_get_state(pvt->ssl_ctx) != TLS_ST_OK) |
418 | 26.2k | goto out; |
419 | | |
420 | 0 | err = tls_srtp_keyinfo(pvt->ssl_ctx, &suite, cli_key, sizeof(cli_key), |
421 | 0 | srv_key, sizeof(srv_key), pvt->mself->log); |
422 | 0 | if (err != 0) { |
423 | 0 | goto godead; |
424 | 0 | } |
425 | | |
426 | 0 | err = tls_peer_fingerprint(pvt->ssl_ctx, srv_fingerprint, |
427 | 0 | sizeof(srv_fingerprint)); |
428 | 0 | if (err != 0) { |
429 | 0 | goto godead; |
430 | 0 | } |
431 | | |
432 | 0 | if (pvt->fingerprint[0] != '\0' && |
433 | 0 | strcmp(pvt->fingerprint, srv_fingerprint) != 0) { |
434 | 0 | RTPP_LOG(pvt->mself->log, RTPP_LOG_ERR, "fingerprint verification failed"); |
435 | 0 | goto godead; |
436 | 0 | } |
437 | | |
438 | 0 | pvt->srtp_ctx_out = setup_srtp_stream(suite, |
439 | 0 | pvt->mode == RTPP_DTLS_ACTIVE ? cli_key : srv_key, SSRC_BAD, |
440 | 0 | pvt->mself->log); |
441 | 0 | if (pvt->srtp_ctx_out == NULL) { |
442 | 0 | goto godead; |
443 | 0 | } |
444 | 0 | pvt->srtp_ctx_in = setup_srtp_stream(suite, |
445 | 0 | pvt->mode == RTPP_DTLS_ACTIVE ? srv_key : cli_key, pvt->ssrc, |
446 | 0 | pvt->mself->log); |
447 | 0 | if (pvt->srtp_ctx_in == NULL) { |
448 | 0 | goto godead; |
449 | 0 | } |
450 | | |
451 | | #if 0 |
452 | | RTPP_LOG(pvt->mself->log, RTPP_LOG_DBUG, |
453 | | "DTLS connection is established with %s key: %s", suite->can_name, |
454 | | pvt->fingerprint); |
455 | | #endif |
456 | 0 | pvt->state = RDC_UP; |
457 | 0 | } |
458 | 0 | goto out; |
459 | 4.86k | godead: |
460 | 4.86k | RTPP_LOG(pvt->mself->log, RTPP_LOG_DBUG, "DTLS connection is dead: %p", |
461 | 4.86k | pvt); |
462 | 4.86k | pvt->state = RDC_DEAD; |
463 | 31.7k | out: |
464 | 31.7k | pthread_mutex_unlock(&pvt->state_lock); |
465 | 31.7k | } |
466 | | |
467 | | #if SRTP_PROTECT_NARGS == 4 |
468 | | #define SRTP_PROTECT(a, b, c) srtp_protect(a, b, c, 0) |
469 | | #define SRTCP_PROTECT(a, b, c) srtp_protect_rtcp(a, b, c, 0) |
470 | | #else |
471 | | #define SRTP_PROTECT(a, b, c) srtp_protect(a, b, c) |
472 | | #define SRTCP_PROTECT(a, b, c) srtp_protect_rtcp(a, b, c) |
473 | | #endif |
474 | | |
475 | | static struct res_loc |
476 | | rtpp_dtls_conn_rtp_send(struct rtpp_dtls_conn *self, struct pkt_proc_ctx *pktxp) |
477 | 167k | { |
478 | 167k | struct res_loc status; |
479 | 167k | #if defined(SRTP_PROTECT_LASTARG) |
480 | 167k | SRTP_PROTECT_LASTARG len; |
481 | | #else |
482 | | size_t len; |
483 | | #endif |
484 | 167k | struct rtpp_dtls_conn_priv *pvt; |
485 | | |
486 | 167k | PUB2PVT(self, pvt); |
487 | | |
488 | 167k | if (pvt->state != RDC_UP) { |
489 | 167k | return (RES_HERE(-1)); |
490 | 167k | } |
491 | | |
492 | 0 | len = pktxp->pktp->size; |
493 | 0 | if (rtpp_is_rtcp_tst(pktxp)) { |
494 | 0 | status = RES_HERE(SRTCP_PROTECT(pvt->srtp_ctx_out, pktxp->pktp->data.buf, &len)); |
495 | 0 | } else { |
496 | 0 | status = RES_HERE(SRTP_PROTECT(pvt->srtp_ctx_out, pktxp->pktp->data.buf, &len)); |
497 | 0 | } |
498 | 0 | if (status.v) { |
499 | 0 | status.v = -1; |
500 | 0 | return (status); |
501 | 0 | } |
502 | 0 | pktxp->pktp->size = len; |
503 | 0 | CALL_SMETHOD(pktxp->strmp_in->pproc_manager, handleat, pktxp, |
504 | 0 | PPROC_ORD_ENCRYPT + 1); |
505 | 0 | return (RES_HERE(0)); |
506 | 0 | } |
507 | | |
508 | | static struct res_loc |
509 | | rtpp_dtls_conn_srtp_recv(struct rtpp_dtls_conn *self, struct pkt_proc_ctx *pktxp) |
510 | 93.7k | { |
511 | 93.7k | struct res_loc status; |
512 | 93.7k | #if defined(SRTP_PROTECT_LASTARG) |
513 | 93.7k | SRTP_PROTECT_LASTARG len; |
514 | | #else |
515 | | size_t len; |
516 | | #endif |
517 | 93.7k | struct rtpp_dtls_conn_priv *pvt; |
518 | | |
519 | 93.7k | PUB2PVT(self, pvt); |
520 | | |
521 | 93.7k | if (pvt->state != RDC_UP) { |
522 | 93.7k | return (RES_HERE(-1)); |
523 | 93.7k | } |
524 | | |
525 | 0 | len = pktxp->pktp->size; |
526 | 0 | if (rtpp_is_rtcp_tst(pktxp)) { |
527 | 0 | status = RES_HERE(srtp_unprotect_rtcp(pvt->srtp_ctx_in, pktxp->pktp->data.buf, &len)); |
528 | 0 | } else { |
529 | 0 | status = RES_HERE(srtp_unprotect(pvt->srtp_ctx_in, pktxp->pktp->data.buf, &len)); |
530 | 0 | } |
531 | 0 | if (status.v) { |
532 | 0 | status.v = -1; |
533 | 0 | return (status); |
534 | 0 | } |
535 | 0 | pktxp->pktp->size = len; |
536 | 0 | CALL_SMETHOD(pktxp->strmp_in->pproc_manager, handleat, pktxp, |
537 | 0 | PPROC_ORD_DECRYPT + 1); |
538 | 0 | return (RES_HERE(0)); |
539 | 0 | } |
540 | | |
541 | | static int |
542 | | bio_write(BIO *b, const char *buf, int len) |
543 | 11.9k | { |
544 | 11.9k | struct rtpp_dtls_conn_priv *pvt = BIO_get_data(b); |
545 | 11.9k | struct rtp_packet *packet; |
546 | 11.9k | struct rtpp_stream *dtls_strmp; |
547 | | |
548 | 11.9k | dtls_strmp = CALL_SMETHOD(pvt->streams_wrt, get_by_idx, pvt->dtls_strm_id); |
549 | 11.9k | if (dtls_strmp == NULL) |
550 | 0 | goto e0; |
551 | 11.9k | if (len > MAX_RPKT_LEN || !CALL_SMETHOD(dtls_strmp, issendable)) |
552 | 1.69k | goto e1; |
553 | 10.3k | packet = rtp_packet_alloc(); |
554 | 10.3k | if (packet == NULL) |
555 | 0 | goto e1; |
556 | 10.3k | memcpy(packet->data.buf, buf, len); |
557 | 10.3k | packet->size = len; |
558 | 10.3k | CALL_SMETHOD(dtls_strmp, send_pkt, NULL, packet); |
559 | 10.3k | RTPP_OBJ_DECREF(dtls_strmp); |
560 | 10.3k | return (len); |
561 | 1.69k | e1: |
562 | 1.69k | RTPP_OBJ_DECREF(dtls_strmp); |
563 | 1.69k | e0: |
564 | 1.69k | return (-1); |
565 | 1.69k | } |
566 | | |
567 | | static long |
568 | | bio_ctrl(BIO *b, int cmd, long num, void *ptr) |
569 | 74.4k | { |
570 | 74.4k | (void)b; |
571 | 74.4k | (void)num; |
572 | 74.4k | (void)ptr; |
573 | | |
574 | 74.4k | switch (cmd) { |
575 | | |
576 | 10.3k | case BIO_CTRL_FLUSH: |
577 | | /* The OpenSSL library needs this */ |
578 | 10.3k | return 1; |
579 | | |
580 | 0 | #if defined (BIO_CTRL_DGRAM_QUERY_MTU) |
581 | 7.52k | case BIO_CTRL_DGRAM_QUERY_MTU: |
582 | 7.52k | return MTU_DEFAULT; |
583 | 0 | #endif |
584 | | |
585 | 0 | #if defined (BIO_CTRL_DGRAM_GET_FALLBACK_MTU) |
586 | 0 | case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: |
587 | 0 | return MTU_FALLBACK; |
588 | 74.4k | #endif |
589 | 74.4k | } |
590 | | |
591 | 56.6k | return 0; |
592 | 74.4k | } |
593 | | |
594 | | static int |
595 | | bio_create(BIO *b) |
596 | 28.7k | { |
597 | 28.7k | BIO_set_init(b, 1); |
598 | 28.7k | BIO_set_data(b, NULL); |
599 | 28.7k | BIO_set_flags(b, 0); |
600 | | |
601 | 28.7k | return (1); |
602 | 28.7k | } |
603 | | |
604 | | |
605 | | static int |
606 | | bio_destroy(BIO *b) |
607 | 28.7k | { |
608 | | |
609 | 28.7k | BIO_set_init(b, 0); |
610 | 28.7k | BIO_set_data(b, NULL); |
611 | 28.7k | BIO_set_flags(b, 0); |
612 | | |
613 | 28.7k | return (1); |
614 | 28.7k | } |
615 | | |
616 | | static BIO_METHOD * |
617 | | bio_method_udp(void) |
618 | 28.7k | { |
619 | 28.7k | BIO_METHOD *method; |
620 | | |
621 | 28.7k | method = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "udp_send"); |
622 | 28.7k | if (!method) { |
623 | 0 | return NULL; |
624 | 0 | } |
625 | | |
626 | 28.7k | BIO_meth_set_write(method, bio_write); |
627 | 28.7k | BIO_meth_set_ctrl(method, bio_ctrl); |
628 | 28.7k | BIO_meth_set_create(method, bio_create); |
629 | 28.7k | BIO_meth_set_destroy(method, bio_destroy); |
630 | | |
631 | 28.7k | return (method); |
632 | 28.7k | } |
633 | | |
634 | | static int |
635 | | tls_print_error(const char *str, size_t len, void *arg) |
636 | 5.05k | { |
637 | 5.05k | struct rtpp_log *log = arg; |
638 | 5.05k | RTPP_LOG(log, RTPP_LOG_ERR, "%.*s", (int)len, str); |
639 | | |
640 | 5.05k | return 1; |
641 | 5.05k | } |
642 | | |
643 | | |
644 | | static void |
645 | | tls_flush_error(struct rtpp_log *log) |
646 | 38.6k | { |
647 | | |
648 | 38.6k | ERR_print_errors_cb(tls_print_error, log); |
649 | 38.6k | } |
650 | | |
651 | | static int |
652 | | tls_accept(struct rtpp_dtls_conn_priv *pvt) |
653 | 20.7k | { |
654 | 20.7k | int r; |
655 | | |
656 | 20.7k | RTPP_DBG_ASSERT(rtpp_mutex_islocked(&pvt->state_lock)); |
657 | | |
658 | 20.7k | ERR_clear_error(); |
659 | | |
660 | 20.7k | r = SSL_accept(pvt->ssl_ctx); |
661 | 20.7k | if (r <= 0) { |
662 | 20.7k | const int ssl_err = SSL_get_error(pvt->ssl_ctx, r); |
663 | | |
664 | 20.7k | tls_flush_error(pvt->mself->log); |
665 | | |
666 | 20.7k | switch (ssl_err) { |
667 | 17.4k | case SSL_ERROR_WANT_READ: |
668 | 17.4k | break; |
669 | | |
670 | 3.35k | default: |
671 | 3.35k | RTPP_LOG(pvt->mself->log, RTPP_LOG_ERR, "accept error: %i", |
672 | 3.35k | ssl_err); |
673 | 3.35k | return (-1); |
674 | 20.7k | } |
675 | 20.7k | } |
676 | | |
677 | 17.4k | if (check_timer(pvt) != 0) |
678 | 0 | return (-1); |
679 | | |
680 | 17.4k | return (0); |
681 | 17.4k | } |
682 | | |
683 | | static enum rtpp_timed_cb_rvals |
684 | | rtpp_dtls_conn_timeout(double dtime, void *arg) |
685 | 0 | { |
686 | 0 | struct rtpp_dtls_conn_priv *pvt = arg; |
687 | |
|
688 | 0 | pthread_mutex_lock(&pvt->state_lock); |
689 | |
|
690 | 0 | if (pvt->ttp == NULL) { |
691 | | /* Lost race with check_timer() */ |
692 | 0 | goto done; |
693 | 0 | } |
694 | | |
695 | 0 | RTPP_OBJ_DECREF(pvt->ttp); |
696 | 0 | pvt->ttp = NULL; |
697 | 0 | if (pvt->state != RDC_CONNECTING) |
698 | 0 | goto done; |
699 | 0 | if (DTLSv1_handle_timeout(pvt->ssl_ctx) >= 0) { |
700 | 0 | if (check_timer(pvt) != 0) |
701 | 0 | pvt->state = RDC_DEAD; |
702 | 0 | } else { |
703 | 0 | ERR_clear_error(); |
704 | 0 | pvt->state = RDC_DEAD; |
705 | 0 | } |
706 | 0 | done: |
707 | 0 | pthread_mutex_unlock(&pvt->state_lock); |
708 | 0 | return (CB_LAST); |
709 | 0 | } |
710 | | |
711 | | static int |
712 | | check_timer(struct rtpp_dtls_conn_priv *pvt) |
713 | 33.6k | { |
714 | 33.6k | int err; |
715 | 33.6k | struct timeval tv = {0, 0}; |
716 | | |
717 | 33.6k | RTPP_DBG_ASSERT(rtpp_mutex_islocked(&pvt->state_lock)); |
718 | | |
719 | 33.6k | err = DTLSv1_get_timeout(pvt->ssl_ctx, &tv); |
720 | 33.6k | if (err == 1 && pvt->ttp != NULL) |
721 | 8.86k | return (0); |
722 | 24.7k | if (err == 1) { |
723 | 7.33k | double to = timeval2dtime(&tv); |
724 | 7.33k | pvt->ttp = CALL_SMETHOD(pvt->timed_cf, schedule_rc, to, |
725 | 7.33k | pvt->pub.rcnt, rtpp_dtls_conn_timeout, NULL, pvt); |
726 | 7.33k | if (pvt->ttp == NULL) |
727 | 0 | return (-1); |
728 | 17.4k | } else if (pvt->ttp != NULL) { |
729 | 0 | CALL_METHOD(pvt->ttp, cancel); |
730 | 0 | RTPP_OBJ_DECREF(pvt->ttp); |
731 | 0 | pvt->ttp = NULL; |
732 | 0 | } |
733 | | |
734 | 24.7k | return (0); |
735 | 24.7k | } |
736 | | |
737 | | static int |
738 | | tls_connect(struct rtpp_dtls_conn_priv *pvt) |
739 | 17.9k | { |
740 | 17.9k | int r; |
741 | | |
742 | 17.9k | RTPP_DBG_ASSERT(rtpp_mutex_islocked(&pvt->state_lock)); |
743 | | |
744 | 17.9k | ERR_clear_error(); |
745 | | |
746 | 17.9k | r = SSL_connect(pvt->ssl_ctx); |
747 | 17.9k | if (r <= 0) { |
748 | 17.9k | const int ssl_err = SSL_get_error(pvt->ssl_ctx, r); |
749 | | |
750 | 17.9k | tls_flush_error(pvt->mself->log); |
751 | | |
752 | 17.9k | switch (ssl_err) { |
753 | 16.2k | case SSL_ERROR_WANT_READ: |
754 | 16.2k | break; |
755 | | |
756 | 1.70k | default: |
757 | 1.70k | RTPP_LOG(pvt->mself->log, RTPP_LOG_ERR, "connect error: %i", |
758 | 1.70k | ssl_err); |
759 | 1.70k | return (-1); |
760 | 17.9k | } |
761 | 17.9k | } |
762 | | |
763 | 16.2k | check_timer(pvt); |
764 | | |
765 | 16.2k | return (0); |
766 | 17.9k | } |
767 | | |
768 | | static void |
769 | | mem_secclean(void *data, size_t size) |
770 | 0 | { |
771 | 0 | memset(data, 0, size); |
772 | | /* Insert an asm statement that may potentially depend |
773 | | * on the memory contents that were affected by memset. |
774 | | * This prevents optimizing away the memset. */ |
775 | 0 | __asm__ __volatile__("" : : "r" (data), "r" (size) : "memory"); |
776 | 0 | } |
777 | | |
778 | | static int |
779 | | tls_srtp_keyinfo(SSL *ssl_ctx, const struct srtp_crypto_suite **suite, |
780 | | uint8_t *cli_key, size_t cli_key_size, uint8_t *srv_key, |
781 | | size_t srv_key_size, struct rtpp_log *log) |
782 | 0 | { |
783 | 0 | static const char *label = "EXTRACTOR-dtls_srtp"; |
784 | 0 | size_t size; |
785 | 0 | SRTP_PROTECTION_PROFILE *sel; |
786 | 0 | uint8_t keymat[256], *p; |
787 | |
|
788 | 0 | sel = SSL_get_selected_srtp_profile(ssl_ctx); |
789 | 0 | if (!sel) { |
790 | 0 | ERR_clear_error(); |
791 | 0 | RTPP_LOG(log, RTPP_LOG_ERR, |
792 | 0 | "SSL_get_selected_srtp_profile() failed"); |
793 | 0 | return (-1); |
794 | 0 | } |
795 | | |
796 | 0 | switch (sel->id) { |
797 | 0 | case SRTP_AES128_CM_SHA1_80: |
798 | 0 | *suite = &srtp_suites[SRTP_AES_CM_128_HMAC_SHA1_80]; |
799 | 0 | break; |
800 | | |
801 | 0 | case SRTP_AES128_CM_SHA1_32: |
802 | 0 | *suite = &srtp_suites[SRTP_AES_CM_128_HMAC_SHA1_32]; |
803 | 0 | break; |
804 | | |
805 | 0 | case SRTP_AES128_F8_SHA1_80: |
806 | 0 | *suite = &srtp_suites[SRTP_F8_128_HMAC_SHA1_80]; |
807 | 0 | break; |
808 | | |
809 | 0 | case SRTP_AES128_F8_SHA1_32: |
810 | 0 | *suite = &srtp_suites[SRTP_F8_128_HMAC_SHA1_32]; |
811 | 0 | break; |
812 | | |
813 | 0 | #ifdef SRTP_AEAD_AES_128_GCM |
814 | 0 | case SRTP_AEAD_AES_128_GCM: |
815 | 0 | *suite = &srtp_suites[SRTP_AES_128_GCM]; |
816 | 0 | break; |
817 | 0 | #endif |
818 | | |
819 | 0 | #ifdef SRTP_AEAD_AES_256_GCM |
820 | 0 | case SRTP_AEAD_AES_256_GCM: |
821 | 0 | *suite = &srtp_suites[SRTP_AES_256_GCM]; |
822 | 0 | break; |
823 | 0 | #endif |
824 | | |
825 | 0 | default: |
826 | 0 | abort(); |
827 | 0 | } |
828 | | |
829 | 0 | size = (*suite)->key_size + (*suite)->iv_size; |
830 | |
|
831 | 0 | if (cli_key_size < size || srv_key_size < size) |
832 | 0 | abort(); |
833 | | |
834 | 0 | if (sizeof(keymat) < (2 * size)) |
835 | 0 | abort(); |
836 | | |
837 | 0 | if (SSL_export_keying_material(ssl_ctx, keymat, 2 * size, label, |
838 | 0 | strlen(label), NULL, 0, 0) != 1) { |
839 | 0 | ERR_clear_error(); |
840 | 0 | RTPP_LOG(log, RTPP_LOG_ERR, |
841 | 0 | "SSL_export_keying_material() failed"); |
842 | 0 | return (-1); |
843 | 0 | } |
844 | | |
845 | 0 | p = keymat; |
846 | |
|
847 | 0 | memcpy(cli_key, p, (*suite)->key_size); |
848 | 0 | p += (*suite)->key_size; |
849 | 0 | memcpy(srv_key, p, (*suite)->key_size); |
850 | 0 | p += (*suite)->key_size; |
851 | 0 | memcpy(cli_key + (*suite)->key_size, p, (*suite)->iv_size); |
852 | 0 | p += (*suite)->iv_size; |
853 | 0 | memcpy(srv_key + (*suite)->key_size, p, (*suite)->iv_size); |
854 | |
|
855 | 0 | mem_secclean(keymat, sizeof(keymat)); |
856 | |
|
857 | 0 | return (0); |
858 | 0 | } |
859 | | |
860 | | static int |
861 | | tls_peer_fingerprint(SSL *ssl_ctx, char *buf, size_t size) |
862 | 0 | { |
863 | 0 | X509 *cert; |
864 | 0 | int err; |
865 | |
|
866 | 0 | cert = SSL_get_peer_certificate(ssl_ctx); |
867 | 0 | if (cert == NULL) |
868 | 0 | return (-1); |
869 | | |
870 | 0 | err = rtpp_dtls_fp_gen(cert, buf, size); |
871 | |
|
872 | 0 | X509_free(cert); |
873 | |
|
874 | 0 | return (err); |
875 | 0 | } |
876 | | |
877 | | static void |
878 | | rtpp_dtls_conn_godead(struct rtpp_dtls_conn *self) |
879 | 28.7k | { |
880 | 28.7k | struct rtpp_dtls_conn_priv *pvt; |
881 | | |
882 | 28.7k | PUB2PVT(self, pvt); |
883 | | |
884 | 28.7k | pthread_mutex_lock(&pvt->state_lock); |
885 | 28.7k | pvt->state = RDC_DEAD; |
886 | 28.7k | if (pvt->ttp != NULL) { |
887 | 7.33k | CALL_METHOD(pvt->ttp, cancel); |
888 | 7.33k | RTPP_OBJ_DECREF(pvt->ttp); |
889 | 7.33k | pvt->ttp = NULL; |
890 | 7.33k | } |
891 | 28.7k | pthread_mutex_unlock(&pvt->state_lock); |
892 | 28.7k | } |