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