/src/rtpproxy/modules/dtls_gw/rtpp_dtls.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 <assert.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/rand.h> |
38 | | |
39 | | #include "config_pp.h" |
40 | | |
41 | | #include "rtpp_module.h" |
42 | | #include "rtpp_codeptr.h" |
43 | | #include "rtpp_refcnt.h" |
44 | | #include "rtpp_str.h" |
45 | | |
46 | | #include "rtpp_dtls.h" |
47 | | #include "rtpp_dtls_util.h" |
48 | | #include "rtpp_dtls_conn.h" |
49 | | |
50 | | struct rtpp_dtls_priv { |
51 | | struct rtpp_dtls pub; |
52 | | const struct rtpp_cfg *cfsp; |
53 | | struct rtpp_minfo *mself; |
54 | | SSL_CTX *ctx; |
55 | | X509 *cert; |
56 | | char fingerprint[FP_DIGEST_STRBUF_LEN]; |
57 | | }; |
58 | | |
59 | | static const char * const srtp_profiles = |
60 | | "SRTP_AES128_CM_SHA1_80:" |
61 | | "SRTP_AES128_CM_SHA1_32:" |
62 | | "SRTP_AEAD_AES_128_GCM:" |
63 | | "SRTP_AEAD_AES_256_GCM"; |
64 | | |
65 | | const char * const cn = "dtls@rtpproxy"; |
66 | | const char * const ecname = "prime256v1"; |
67 | | |
68 | | struct rtpp_dtls_conn *rtpp_dtls_newconn(struct rtpp_dtls *, |
69 | | struct rtpp_stream *); |
70 | | |
71 | | static X509 *tls_set_selfsigned_ec(SSL_CTX *, const char *, const char *); |
72 | | static void tls_set_verify_client(SSL_CTX *); |
73 | | |
74 | | static void |
75 | | rtpp_dtls_dtor(struct rtpp_dtls_priv *pvt) |
76 | 4 | { |
77 | | |
78 | 4 | X509_free(pvt->cert); |
79 | 4 | SSL_CTX_free(pvt->ctx); |
80 | 4 | } |
81 | | |
82 | | struct rtpp_dtls * |
83 | | rtpp_dtls_ctor(const struct rtpp_cfg *cfsp, struct rtpp_minfo *mself) |
84 | 4 | { |
85 | 4 | struct rtpp_dtls_priv *pvt; |
86 | | |
87 | 4 | pvt = mod_rzmalloc(sizeof(*pvt), PVT_RCOFFS(pvt)); |
88 | 4 | if (pvt == NULL) { |
89 | 0 | goto e0; |
90 | 0 | } |
91 | 4 | pvt->ctx = SSL_CTX_new(DTLS_method()); |
92 | 4 | if (pvt->ctx == NULL) { |
93 | 0 | ERR_clear_error(); |
94 | 0 | goto e1; |
95 | 0 | } |
96 | 4 | pvt->cert = tls_set_selfsigned_ec(pvt->ctx, cn, ecname); |
97 | 4 | if (pvt->cert == NULL) { |
98 | 0 | ERR_clear_error(); |
99 | 0 | goto e2; |
100 | 0 | } |
101 | 4 | tls_set_verify_client(pvt->ctx); |
102 | 4 | if (SSL_CTX_set_tlsext_use_srtp(pvt->ctx, srtp_profiles) != 0) { |
103 | 0 | ERR_clear_error(); |
104 | 0 | goto e3; |
105 | 0 | } |
106 | 4 | if (rtpp_dtls_fp_gen(pvt->cert, pvt->fingerprint, |
107 | 4 | sizeof(pvt->fingerprint)) != 0) { |
108 | 0 | goto e3; |
109 | 0 | } |
110 | 4 | pvt->pub.fingerprint = pvt->fingerprint; |
111 | 4 | pvt->pub.newconn = &rtpp_dtls_newconn; |
112 | 4 | pvt->cfsp = cfsp; |
113 | 4 | pvt->mself = mself; |
114 | 4 | CALL_SMETHOD(pvt->pub.rcnt, attach, (rtpp_refcnt_dtor_t)rtpp_dtls_dtor, pvt); |
115 | 4 | return (&(pvt->pub)); |
116 | 0 | e3: |
117 | 0 | X509_free(pvt->cert); |
118 | 0 | e2: |
119 | 0 | SSL_CTX_free(pvt->ctx); |
120 | 0 | e1: |
121 | 0 | mod_free(pvt); |
122 | 0 | e0: |
123 | 0 | return (NULL); |
124 | 0 | } |
125 | | |
126 | | struct rtpp_dtls_conn * |
127 | | rtpp_dtls_newconn(struct rtpp_dtls *self, struct rtpp_stream *dtls_strmp) |
128 | 24.3k | { |
129 | 24.3k | struct rtpp_dtls_priv *pvt; |
130 | 24.3k | struct rtpp_dtls_conn *conn; |
131 | | |
132 | 24.3k | PUB2PVT(self, pvt); |
133 | | |
134 | 24.3k | conn = rtpp_dtls_conn_ctor(pvt->cfsp, pvt->ctx, dtls_strmp, pvt->mself); |
135 | 24.3k | return (conn); |
136 | 24.3k | } |
137 | | |
138 | | #ifndef OPENSSL_VERSION_MAJOR |
139 | | #define OPENSSL_VERSION_MAJOR 1 |
140 | | #endif |
141 | | |
142 | | static uint32_t |
143 | | dtls_rand_u32(void) |
144 | 4 | { |
145 | 4 | uint32_t v; |
146 | | |
147 | 4 | v = 0; |
148 | 4 | assert(RAND_bytes((unsigned char *)&v, sizeof(v)) == 1); |
149 | 4 | return v; |
150 | 4 | } |
151 | | |
152 | | static int |
153 | | verify_trust_all(int ok, X509_STORE_CTX *ctx) |
154 | 0 | { |
155 | 0 | (void)ok; |
156 | 0 | (void)ctx; |
157 | |
|
158 | 0 | return 1; /* We trust the certificate from peer */ |
159 | 0 | } |
160 | | |
161 | | static void |
162 | | tls_set_verify_client(SSL_CTX *ctx) |
163 | 4 | { |
164 | | |
165 | 4 | SSL_CTX_set_verify_depth(ctx, 0); |
166 | 4 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, |
167 | 4 | verify_trust_all); |
168 | 4 | } |
169 | | |
170 | | static X509 * |
171 | | tls_generate_cert(const char *cn) |
172 | 4 | { |
173 | 4 | X509 *cert; |
174 | 4 | X509_NAME *subj; |
175 | | |
176 | 4 | cert = X509_new(); |
177 | 4 | if (!cert) |
178 | 0 | goto e0; |
179 | | |
180 | 4 | if (!X509_set_version(cert, 2)) |
181 | 0 | goto e1; |
182 | | |
183 | 4 | if (!ASN1_INTEGER_set(X509_get_serialNumber(cert), dtls_rand_u32())) |
184 | 0 | goto e1; |
185 | | |
186 | 4 | subj = X509_NAME_new(); |
187 | 4 | if (!subj) |
188 | 0 | goto e1; |
189 | | |
190 | 4 | if (!X509_NAME_add_entry_by_txt(subj, "CN", MBSTRING_ASC, |
191 | 4 | (unsigned char *)cn, (int)strlen(cn), -1, 0)) |
192 | 0 | goto e2; |
193 | | |
194 | 4 | if (!X509_set_issuer_name(cert, subj) || |
195 | 4 | !X509_set_subject_name(cert, subj)) |
196 | 0 | goto e2; |
197 | | |
198 | 4 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L |
199 | 4 | if (!X509_gmtime_adj(X509_getm_notBefore(cert), -3600*24*365) || |
200 | 4 | !X509_gmtime_adj(X509_getm_notAfter(cert), 3600*24*365*10)) |
201 | 0 | goto e2; |
202 | | #else |
203 | | if (!X509_gmtime_adj(X509_get_notBefore(cert), -3600*24*365) || |
204 | | !X509_gmtime_adj(X509_get_notAfter(cert), 3600*24*365*10)) |
205 | | goto e2; |
206 | | #endif |
207 | | |
208 | 4 | X509_NAME_free(subj); |
209 | 4 | return (cert); |
210 | 0 | e2: |
211 | 0 | X509_NAME_free(subj); |
212 | 0 | e1: |
213 | 0 | X509_free(cert); |
214 | 0 | e0: |
215 | 0 | return (NULL); |
216 | 0 | } |
217 | | |
218 | | static X509 * |
219 | | tls_set_selfsigned_ec(SSL_CTX *ctx, const char *cn, const char *curve_n) |
220 | 4 | { |
221 | 4 | #if OPENSSL_VERSION_MAJOR < 3 |
222 | 4 | EC_KEY *eckey; |
223 | 4 | int eccgrp; |
224 | 4 | #endif |
225 | 4 | EVP_PKEY *key; |
226 | 4 | X509 *cert; |
227 | 4 | int r; |
228 | | |
229 | | #if OPENSSL_VERSION_MAJOR >= 3 |
230 | | key = EVP_EC_gen(curve_n); |
231 | | if (!key) { |
232 | | goto e0; |
233 | | } |
234 | | #else |
235 | 4 | key = EVP_PKEY_new(); |
236 | 4 | if (!key) |
237 | 0 | goto e0; |
238 | | |
239 | 4 | eccgrp = OBJ_txt2nid(curve_n); |
240 | 4 | if (eccgrp == NID_undef) |
241 | 0 | goto e1; |
242 | | |
243 | 4 | eckey = EC_KEY_new_by_curve_name(eccgrp); |
244 | 4 | if (!eckey) |
245 | 0 | goto e1; |
246 | | |
247 | 4 | if (!EC_KEY_generate_key(eckey)) |
248 | 0 | goto e2; |
249 | | |
250 | 4 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L |
251 | 4 | EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE); |
252 | | #else |
253 | | EC_KEY_set_asn1_flag(eckey, 0); |
254 | | #endif |
255 | | |
256 | 4 | if (!EVP_PKEY_set1_EC_KEY(key, eckey)) |
257 | 0 | goto e2; |
258 | 4 | #endif /* OPENSSL_VERSION_MAJOR */ |
259 | | |
260 | 4 | cert = tls_generate_cert(cn); |
261 | 4 | if (cert == NULL) |
262 | 0 | goto e2; |
263 | | |
264 | 4 | if (!X509_set_pubkey(cert, key)) |
265 | 0 | goto e3; |
266 | | |
267 | 4 | if (!X509_sign(cert, key, EVP_sha256())) |
268 | 0 | goto e3; |
269 | | |
270 | 4 | r = SSL_CTX_use_certificate(ctx, cert); |
271 | 4 | if (r != 1) |
272 | 0 | goto e3; |
273 | | |
274 | 4 | r = SSL_CTX_use_PrivateKey(ctx, key); |
275 | 4 | if (r != 1) |
276 | 0 | goto e3; |
277 | | |
278 | 4 | #if OPENSSL_VERSION_MAJOR < 3 |
279 | 4 | EC_KEY_free(eckey); |
280 | 4 | #endif |
281 | 4 | EVP_PKEY_free(key); |
282 | 4 | return cert; |
283 | 0 | e3: |
284 | 0 | X509_free(cert); |
285 | 0 | e2: |
286 | 0 | #if OPENSSL_VERSION_MAJOR < 3 |
287 | 0 | EC_KEY_free(eckey); |
288 | 0 | e1: |
289 | 0 | #endif |
290 | 0 | EVP_PKEY_free(key); |
291 | 0 | e0: |
292 | 0 | return (NULL); |
293 | 0 | } |