1 /* -*- c-basic-offset: 8; -*- */
2 /* tls.c: TLS support functions
3 * $Id$
4 *
5 * Copyright (C) 2015-2019 Philipp Schafft <lion@lion.leolix.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <string.h>
27
28 #include <shout/shout.h>
29 #include "shout_private.h"
30
31 #ifndef XXX_HAVE_X509_check_host
32 # include <ctype.h>
33 #endif
34
35 struct _shout_tls {
36 SSL_CTX *ssl_ctx;
37 SSL *ssl;
38 int ssl_ret;
39 int cert_error;
40 /* only pointers into self, don't need to free them */
41 sock_t socket;
42 const char *host;
43 const char *ca_directory;
44 const char *ca_file;
45 const char *allowed_ciphers;
46 const char *client_certificate;
47 shout_tls_callback_t callback;
48 void *callback_userdata;
49 };
50
shout_tls_emit(shout_tls_t * tls,shout_event_t event,...)51 static int shout_tls_emit(shout_tls_t *tls, shout_event_t event, ...)
52 {
53 int ret;
54 va_list ap;
55
56 if (!tls)
57 return SHOUTERR_INSANE;
58
59 if (!tls->callback)
60 return SHOUT_CALLBACK_PASS;
61
62 va_start(ap, event);
63 ret = tls->callback(tls, event, tls->callback_userdata, ap);
64 va_end(ap);
65
66 return ret;
67 }
68
shout_tls_new(shout_t * self,sock_t socket)69 shout_tls_t *shout_tls_new(shout_t *self, sock_t socket)
70 {
71 shout_tls_t *tls = calloc(1, sizeof(shout_tls_t));
72 if (!tls)
73 return NULL;
74
75 tls->cert_error = SHOUTERR_RETRY;
76
77 tls->socket = socket;
78 tls->host = self->host;
79 tls->ca_directory = self->ca_directory;
80 tls->ca_file = self->ca_file;
81 tls->allowed_ciphers = self->allowed_ciphers;
82 tls->client_certificate = self->client_certificate;
83
84 return tls;
85 }
86
tls_setup(shout_tls_t * tls)87 static inline int tls_setup(shout_tls_t *tls)
88 {
89 long ssl_opts = 0;
90
91 #if OPENSSL_VERSION_NUMBER < 0x10100000L
92 SSL_library_init();
93 SSL_load_error_strings();
94 SSLeay_add_all_algorithms();
95 SSLeay_add_ssl_algorithms();
96
97 tls->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
98 ssl_opts |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; // Disable SSLv2 and SSLv3
99 #else
100 tls->ssl_ctx = SSL_CTX_new(TLS_client_method());
101 SSL_CTX_set_min_proto_version(tls->ssl_ctx, TLS1_VERSION);
102 #endif
103
104 #ifdef SSL_OP_NO_COMPRESSION
105 ssl_opts |= SSL_OP_NO_COMPRESSION; // Never use compression
106 #endif
107
108 if (!tls->ssl_ctx)
109 goto error;
110
111 /* Even though this function is called set, it adds the
112 * flags to the already existing flags (possibly default
113 * flags already set by OpenSSL)!
114 * Calling SSL_CTX_get_options is not needed here, therefore.
115 */
116 SSL_CTX_set_options(tls->ssl_ctx, ssl_opts);
117
118
119 SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
120 SSL_CTX_load_verify_locations(tls->ssl_ctx, tls->ca_file, tls->ca_directory);
121
122 SSL_CTX_set_verify(tls->ssl_ctx, SSL_VERIFY_NONE, NULL);
123
124 if (tls->client_certificate) {
125 if (SSL_CTX_use_certificate_file(tls->ssl_ctx, tls->client_certificate, SSL_FILETYPE_PEM) != 1)
126 goto error;
127 if (SSL_CTX_use_PrivateKey_file(tls->ssl_ctx, tls->client_certificate, SSL_FILETYPE_PEM) != 1)
128 goto error;
129 }
130
131 if (SSL_CTX_set_cipher_list(tls->ssl_ctx, tls->allowed_ciphers) <= 0)
132 goto error;
133
134 SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
135 SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_AUTO_RETRY);
136
137 tls->ssl = SSL_new(tls->ssl_ctx);
138 if (!tls->ssl)
139 goto error;
140
141 if (!SSL_set_fd(tls->ssl, tls->socket))
142 goto error;
143
144 SSL_set_tlsext_host_name(tls->ssl, tls->host);
145 SSL_set_connect_state(tls->ssl);
146 tls->ssl_ret = SSL_connect(tls->ssl);
147
148 return SHOUTERR_SUCCESS;
149
150 error:
151 if (tls->ssl)
152 SSL_free(tls->ssl);
153 if (tls->ssl_ctx)
154 SSL_CTX_free(tls->ssl_ctx);
155 return SHOUTERR_UNSUPPORTED;
156 }
157
158 #ifndef XXX_HAVE_X509_check_host
tls_check_pattern(const char * key,const char * pattern)159 static inline int tls_check_pattern(const char *key, const char *pattern)
160 {
161 for (; *key && *pattern; key++) {
162 if (*pattern == '*') {
163 for (; *pattern == '*'; pattern++) ;
164 for (; *key && *key != '.'; key++) ;
165 if (!*pattern && !*key)
166 return 1;
167 if (!*pattern || !*key)
168 return 0;
169 }
170
171 if (tolower(*key) != tolower(*pattern))
172 return 0;
173 pattern++;
174 }
175 return *key == 0 && *pattern == 0;
176 }
177
tls_check_host(X509 * cert,const char * hostname)178 static inline int tls_check_host(X509 *cert, const char *hostname)
179 {
180 char common_name[256] = "";
181 X509_NAME *xname = X509_get_subject_name(cert);
182 X509_NAME_ENTRY *xentry;
183 ASN1_STRING *sdata;
184 int i, j;
185 int ret;
186
187 ret = X509_NAME_get_text_by_NID(xname, NID_commonName, common_name, sizeof(common_name));
188 if (ret < 1 || (size_t)ret >= (sizeof(common_name)-1))
189 return SHOUTERR_TLSBADCERT;
190
191 if (!tls_check_pattern(hostname, common_name))
192 return SHOUTERR_TLSBADCERT;
193
194 /* check for inlined \0,
195 * see https://www.blackhat.com/html/bh-usa-09/bh-usa-09-archives.html#Marlinspike
196 */
197 for (i = -1; ; i = j) {
198 j = X509_NAME_get_index_by_NID(xname, NID_commonName, i);
199 if (j == -1)
200 break;
201 }
202
203 xentry = X509_NAME_get_entry(xname, i);
204 sdata = X509_NAME_ENTRY_get_data(xentry);
205
206 if ((size_t)ASN1_STRING_length(sdata) != strlen(common_name))
207 return SHOUTERR_TLSBADCERT;
208
209 return SHOUTERR_SUCCESS;
210 }
211 #endif
212
tls_check_cert(shout_tls_t * tls)213 static inline int tls_check_cert(shout_tls_t *tls)
214 {
215 X509 *cert = SSL_get_peer_certificate(tls->ssl);
216 int cert_ok = 0;
217 int ret;
218
219 if (tls->cert_error != SHOUTERR_RETRY)
220 return tls->cert_error;
221
222 if (!cert)
223 return SHOUTERR_TLSBADCERT;
224
225 ret = shout_tls_emit(tls, SHOUT_EVENT_TLS_CHECK_PEER_CERTIFICATE);
226 if (ret != SHOUT_CALLBACK_PASS)
227 return tls->cert_error = ret;
228
229 do {
230 if (SSL_get_verify_result(tls->ssl) != X509_V_OK)
231 break;
232
233 #ifdef XXX_HAVE_X509_check_host
234 if (X509_check_host(cert, tls->host, 0, 0, NULL) != 1)
235 break;
236 #else
237 if (tls_check_host(cert, tls->host) != SHOUTERR_SUCCESS)
238 break;
239 #endif
240
241 /* ok, all test passed... */
242 cert_ok = 1;
243 } while (0);
244
245 X509_free(cert);
246
247 if (cert_ok) {
248 tls->cert_error = SHOUTERR_SUCCESS;
249 } else {
250 tls->cert_error = SHOUTERR_TLSBADCERT;
251 }
252 return tls->cert_error;
253 }
254
tls_setup_process(shout_tls_t * tls)255 static inline int tls_setup_process(shout_tls_t *tls)
256 {
257 if (SSL_is_init_finished(tls->ssl))
258 return tls_check_cert(tls);
259 tls->ssl_ret = SSL_connect(tls->ssl);
260 if (SSL_is_init_finished(tls->ssl))
261 return tls_check_cert(tls);
262 if (!shout_tls_recoverable(tls))
263 return SHOUTERR_SOCKET;
264 return SHOUTERR_BUSY;
265 }
266
shout_tls_try_connect(shout_tls_t * tls)267 int shout_tls_try_connect(shout_tls_t *tls)
268 {
269 if (!tls->ssl)
270 tls_setup(tls);
271 if (tls->ssl)
272 return tls_setup_process(tls);
273 return SHOUTERR_UNSUPPORTED;
274 }
275
shout_tls_close(shout_tls_t * tls)276 int shout_tls_close(shout_tls_t *tls)
277 {
278 if (tls->ssl) {
279 SSL_shutdown(tls->ssl);
280 SSL_free(tls->ssl);
281 }
282 if (tls->ssl_ctx)
283 SSL_CTX_free(tls->ssl_ctx);
284 free(tls);
285 return SHOUTERR_SUCCESS;
286 }
287
shout_tls_read(shout_tls_t * tls,void * buf,size_t len)288 ssize_t shout_tls_read(shout_tls_t *tls, void *buf, size_t len)
289 {
290 return tls->ssl_ret = SSL_read(tls->ssl, buf, len);
291 }
292
shout_tls_write(shout_tls_t * tls,const void * buf,size_t len)293 ssize_t shout_tls_write(shout_tls_t *tls, const void *buf, size_t len)
294 {
295 return tls->ssl_ret = SSL_write(tls->ssl, buf, len);
296 }
297
shout_tls_recoverable(shout_tls_t * tls)298 int shout_tls_recoverable(shout_tls_t *tls)
299 {
300 int error = SSL_get_error(tls->ssl, tls->ssl_ret);
301 if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)
302 return 1;
303 return 0;
304 }
305
shout_tls_get_peer_certificate(shout_tls_t * tls,char ** buf)306 int shout_tls_get_peer_certificate(shout_tls_t *tls, char **buf)
307 {
308 X509 *cert;
309 BIO *bio;
310 unsigned char *data;
311 unsigned int len;
312
313
314 if (!tls || !buf)
315 return SHOUTERR_INSANE;
316
317 cert = SSL_get_peer_certificate(tls->ssl);
318 if (!cert)
319 return SHOUTERR_TLSBADCERT;
320
321 bio = BIO_new(BIO_s_mem());
322 if (!bio)
323 return SHOUTERR_MALLOC;
324
325 PEM_write_bio_X509(bio, cert);
326
327 len = BIO_get_mem_data(bio, &data);
328
329 if (len) {
330 *buf = malloc(len + 1);
331 memcpy(*buf, data, len);
332 (*buf)[len] = 0;
333 }
334
335 BIO_free(bio);
336
337 return SHOUTERR_SUCCESS;
338 }
339
shout_tls_get_peer_certificate_chain(shout_tls_t * tls,char ** buf)340 int shout_tls_get_peer_certificate_chain(shout_tls_t *tls, char **buf)
341 {
342 BIO *bio;
343 unsigned char *data;
344 unsigned int len;
345 int j, certs;
346 STACK_OF(X509) * chain;
347
348
349 if (!tls || !buf)
350 return SHOUTERR_INSANE;
351
352 chain = SSL_get_peer_cert_chain(tls->ssl);
353
354 certs = sk_X509_num(chain);
355
356 if (!certs)
357 return SHOUTERR_TLSBADCERT;
358
359 bio = BIO_new(BIO_s_mem());
360 if (!bio)
361 return SHOUTERR_MALLOC;
362
363 for(j = 0; j < certs; ++j) {
364 X509 *cert = sk_X509_value(chain, j);
365
366 PEM_write_bio_X509(bio, cert);
367
368 }
369
370 len = BIO_get_mem_data(bio, &data);
371
372 if (len) {
373 *buf = malloc(len + 1);
374 memcpy(*buf, data, len);
375 (*buf)[len] = 0;
376 }
377
378 BIO_free(bio);
379
380 return SHOUTERR_SUCCESS;
381 }
382
shout_tls_set_callback(shout_tls_t * tls,shout_tls_callback_t callback,void * userdata)383 int shout_tls_set_callback(shout_tls_t *tls, shout_tls_callback_t callback, void *userdata)
384 {
385 if (!tls)
386 return SHOUTERR_INSANE;
387
388 tls->callback = callback;
389 tls->callback_userdata = userdata;
390
391 return SHOUTERR_SUCCESS;
392 }
393