1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*  Fluent Bit
4  *  ==========
5  *  Copyright (C) 2019-2020 The Fluent Bit Authors
6  *  Copyright (C) 2015-2018 Treasure Data Inc.
7  *
8  *  Licensed under the Apache License, Version 2.0 (the "License");
9  *  you may not use this file except in compliance with the License.
10  *  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *  Unless required by applicable law or agreed to in writing, software
15  *  distributed under the License is distributed on an "AS IS" BASIS,
16  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  *  See the License for the specific language governing permissions and
18  *  limitations under the License.
19  */
20 
21 #include <fluent-bit/flb_info.h>
22 #include <fluent-bit/flb_compat.h>
23 #include <fluent-bit/tls/flb_tls.h>
24 
25 #include <openssl/ssl.h>
26 #include <openssl/err.h>
27 #include <openssl/opensslv.h>
28 
29 /*
30  * OPENSSL_VERSION_NUMBER has the following semantics
31  *
32  *     0x010100000L   M = major  F = fix    S = status
33  *       MMNNFFPPS    N = minor  P = patch
34  */
35 #define OPENSSL_1_1_0 0x010100000L
36 
37 /*
38  * RHEL-family distrbutions do not provide system certificates in
39  * a format that OpenSSL's CAPath can read, but do provide a single
40  * packed cert in /etc/certs.
41  *
42  * Use the bundled cert as the default trusted CA.
43  */
44 #define RHEL_DEFAULT_CA "/etc/ssl/certs/ca-bundle.crt"
45 
46 /* OpenSSL library context */
47 struct tls_context {
48     int debug_level;
49     SSL_CTX *ctx;
50     pthread_mutex_t mutex;
51 };
52 
53 struct tls_session {
54     SSL *ssl;
55     int fd;
56     struct tls_context *parent;    /* parent struct tls_context ref */
57 };
58 
59 
tls_init(void)60 static int tls_init(void)
61 {
62 /*
63  * Explicit initialization is needed for older versions of
64  * OpenSSL (before v1.1.0).
65  *
66  * https://wiki.openssl.org/index.php/Library_Initialization
67  */
68 #if OPENSSL_VERSION_NUMBER < OPENSSL_1_1_0
69     OPENSSL_add_all_algorithms_noconf();
70     SSL_load_error_strings();
71     SSL_library_init();
72 #endif
73     return 0;
74 }
75 
tls_info_callback(const SSL * s,int where,int ret)76 static void tls_info_callback(const SSL *s, int where, int ret)
77 {
78     int w;
79     int fd;
80     const char *str;
81 
82     fd = SSL_get_fd(s);
83     w = where & ~SSL_ST_MASK;
84     if (w & SSL_ST_CONNECT) {
85         str = "SSL_connect";
86     }
87     else if (w & SSL_ST_ACCEPT) {
88         str = "SSL_accept";
89     }
90     else {
91         str = "undefined";
92     }
93 
94     if (where & SSL_CB_LOOP) {
95         flb_debug("[tls] connection #%i %s: %s",
96                   fd, str, SSL_state_string_long(s));
97     }
98     else if (where & SSL_CB_ALERT) {
99         str = (where & SSL_CB_READ) ? "read" : "write";
100         flb_debug("[tls] connection #%i SSL3 alert %s:%s:%s",
101                   fd, str,
102                   SSL_alert_type_string_long(ret),
103                   SSL_alert_desc_string_long(ret));
104     }
105     else if (where & SSL_CB_EXIT) {
106         if (ret == 0) {
107             flb_error("[tls] connection #%i %s: failed in %s",
108                       fd, str, SSL_state_string_long(s));
109         }
110         else if (ret < 0) {
111             ret = SSL_get_error(s, ret);
112             if (ret == SSL_ERROR_WANT_WRITE) {
113                 flb_debug("[tls] connection #%i WANT_WRITE", fd);
114             }
115             else if (ret == SSL_ERROR_WANT_READ) {
116                 flb_debug("[tls] connection #%i WANT_READ", fd);
117             }
118             else {
119                 flb_error("[tls] connection #%i %s: error in %s",
120                           fd, str, SSL_state_string_long(s));
121             }
122         }
123     }
124 }
125 
tls_context_destroy(void * ctx_backend)126 static void tls_context_destroy(void *ctx_backend)
127 {
128     struct tls_context *ctx = ctx_backend;
129 
130     pthread_mutex_lock(&ctx->mutex);
131     SSL_CTX_free(ctx->ctx);
132     pthread_mutex_unlock(&ctx->mutex);
133 
134     flb_free(ctx);
135 }
136 
load_system_certificates(struct tls_context * ctx)137 static int load_system_certificates(struct tls_context *ctx)
138 {
139     int ret;
140     const char ca_path[] = "/etc/ssl/certs/";
141 
142     /* For Windows use specific API to read the certs store */
143 #ifdef _MSC_VER
144     //return windows_load_system_certificates(ctx);
145 #endif
146 
147     if (access(RHEL_DEFAULT_CA, R_OK) == 0) {
148         ret = SSL_CTX_load_verify_locations(ctx->ctx, RHEL_DEFAULT_CA, ca_path);
149     }
150     else {
151         ret = SSL_CTX_load_verify_locations(ctx->ctx, NULL, ca_path);
152     }
153 
154     if (ret != 1) {
155         ERR_print_errors_fp(stderr);
156     }
157     return 0;
158 }
159 
tls_context_create(int verify,int debug,const char * vhost,const char * ca_path,const char * ca_file,const char * crt_file,const char * key_file,const char * key_passwd)160 static void *tls_context_create(int verify, int debug,
161                                 const char *vhost,
162                                 const char *ca_path,
163                                 const char *ca_file, const char *crt_file,
164                                 const char *key_file, const char *key_passwd)
165 {
166     int ret;
167     SSL_CTX *ssl_ctx;
168     struct tls_context *ctx;
169 
170     /*
171      * Init library ? based in the documentation on OpenSSL >= 1.1.0 is not longer
172      * necessary since the library will initialize it self:
173      *
174      * https://wiki.openssl.org/index.php/Library_Initialization
175      */
176 
177     /* Create OpenSSL context */
178 #if OPENSSL_VERSION_NUMBER < OPENSSL_1_1_0
179     /*
180      * SSLv23_method() is actually an equivalent of TLS_client_method()
181      * in OpenSSL v1.0.x.
182      *
183      * https://www.openssl.org/docs/man1.0.2/man3/SSLv23_method.html
184      */
185     ssl_ctx = SSL_CTX_new(SSLv23_client_method());
186 #else
187     ssl_ctx = SSL_CTX_new(TLS_client_method());
188 #endif
189     if (!ssl_ctx) {
190         flb_error("[openssl] could not create context");
191         return NULL;
192     }
193 
194     ctx = flb_calloc(1, sizeof(struct tls_context));
195     if (!ctx) {
196         flb_errno();
197         return NULL;
198     }
199     ctx->ctx = ssl_ctx;
200     ctx->debug_level = debug;
201     pthread_mutex_init(&ctx->mutex, NULL);
202 
203     /* Verify peer: by default OpenSSL always verify peer */
204     if (verify == FLB_FALSE) {
205         SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
206     }
207     else {
208         SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
209     }
210 
211     /* ca_path | ca_file */
212     if (ca_path) {
213         ret = SSL_CTX_load_verify_locations(ctx->ctx, NULL, ca_path);
214         if (ret != 1) {
215             flb_error("[tls] ca_path'%s' %lu: %s",
216                       ca_path,
217                       ERR_get_error(),
218                       ERR_error_string(ERR_get_error(), NULL));
219             goto error;
220         }
221     }
222     else if (ca_file) {
223         ret = SSL_CTX_load_verify_locations(ctx->ctx, ca_file, NULL);
224         if (ret != 1) {
225             flb_error("[tls] ca_file '%s' %lu: %s",
226                       ca_file,
227                       ERR_get_error(),
228                       ERR_error_string(ERR_get_error(), NULL));
229             goto error;
230         }
231     }
232     else {
233         load_system_certificates(ctx);
234     }
235 
236     /* crt_file */
237     if (crt_file) {
238         ret = SSL_CTX_use_certificate_chain_file(ssl_ctx, crt_file);
239 		if (ret != 1) {
240             flb_error("[tls] crt_file '%s' %lu: %s",
241                       crt_file,
242                       ERR_get_error(),
243                       ERR_error_string(ERR_get_error(), NULL));
244             goto error;
245         }
246     }
247 
248     /* key_file */
249     if (key_file) {
250         if (key_passwd) {
251             SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx,
252                                                    (void *) key_passwd);
253         }
254         ret = SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file,
255                                           SSL_FILETYPE_PEM);
256         if (ret != 1) {
257             flb_error("[tls] key_file '%s' %lu: %s",
258                       key_file,
259                       ERR_get_error(),
260                       ERR_error_string(ERR_get_error(), NULL));
261         }
262 
263         /* Make sure the key and certificate file match */
264         if (SSL_CTX_check_private_key(ssl_ctx) != 1) {
265             flb_error("[tls] private_key '%s' and password don't match",
266                       key_file);
267             goto error;
268         }
269     }
270 
271     return ctx;
272 
273  error:
274     tls_context_destroy(ctx);
275     return NULL;
276 }
277 
tls_session_create(struct flb_tls * tls,struct flb_upstream_conn * u_conn)278 static void *tls_session_create(struct flb_tls *tls,
279                                 struct flb_upstream_conn *u_conn)
280 {
281     struct tls_session *session;
282     struct tls_context *ctx = tls->ctx;
283     SSL *ssl;
284 
285     session = flb_calloc(1, sizeof(struct tls_session));
286     if (!session) {
287         flb_errno();
288         return NULL;
289     }
290     session->parent = ctx;
291 
292     pthread_mutex_lock(&ctx->mutex);
293     ssl = SSL_new(ctx->ctx);
294 
295     if (!ssl) {
296         flb_error("[openssl] could create new SSL context");
297         flb_free(session);
298         pthread_mutex_unlock(&ctx->mutex);
299         return NULL;
300     }
301     session->ssl = ssl;
302     session->fd = u_conn->fd;
303     SSL_set_fd(ssl, u_conn->fd);
304 
305     /*
306      * TLS Debug Levels:
307      *
308      *  0: No debug,
309      *  1: Error
310      *  2: State change
311      *  3: Informational
312      *  4: Verbose
313      */
314     if (tls->debug == 1) {
315         SSL_set_info_callback(session->ssl, tls_info_callback);
316     }
317     SSL_set_connect_state(ssl);
318     pthread_mutex_unlock(&ctx->mutex);
319     return session;
320 }
321 
tls_session_destroy(void * session)322 static int tls_session_destroy(void *session)
323 {
324     struct tls_session *ptr = session;
325     struct tls_context *ctx;
326 
327     if (!ptr) {
328         return 0;
329     }
330     ctx = ptr->parent;
331 
332     pthread_mutex_lock(&ctx->mutex);
333 
334     if (flb_socket_error(ptr->fd) == 0) {
335         SSL_shutdown(ptr->ssl);
336         SSL_shutdown(ptr->ssl);
337     }
338     SSL_free(ptr->ssl);
339     flb_free(ptr);
340 
341     pthread_mutex_unlock(&ctx->mutex);
342 
343     return 0;
344 }
345 
tls_net_read(struct flb_upstream_conn * u_conn,void * buf,size_t len)346 static int tls_net_read(struct flb_upstream_conn *u_conn,
347                         void *buf, size_t len)
348 {
349     int ret;
350     struct tls_session *session = (struct tls_session *) u_conn->tls_session;
351     struct tls_context *ctx;
352 
353     ctx = session->parent;
354     pthread_mutex_lock(&ctx->mutex);
355 
356     ret = SSL_read(session->ssl, buf, len);
357     if (ret <= 0) {
358         ret = SSL_get_error(session->ssl, ret);
359         if (ret == SSL_ERROR_WANT_READ) {
360             ret = FLB_TLS_WANT_READ;
361         }
362         else if (ret < 0) {
363             ret = -1;
364         }
365     }
366 
367     pthread_mutex_unlock(&ctx->mutex);
368     return ret;
369 }
370 
tls_net_write(struct flb_upstream_conn * u_conn,const void * data,size_t len)371 static int tls_net_write(struct flb_upstream_conn *u_conn,
372                          const void *data, size_t len)
373 {
374     int ret;
375     size_t total = 0;
376     struct tls_session *session = (struct tls_session *) u_conn->tls_session;
377     struct tls_context *ctx;
378 
379     ctx = session->parent;
380     pthread_mutex_lock(&ctx->mutex);
381 
382     ret = SSL_write(session->ssl,
383                     (unsigned char *) data + total,
384                     len - total);
385     if (ret <= 0) {
386         ret = SSL_get_error(session->ssl, ret);
387         if (ret == SSL_ERROR_WANT_WRITE) {
388             ret = FLB_TLS_WANT_WRITE;
389         }
390         else if (ret == SSL_ERROR_WANT_READ) {
391             ret = FLB_TLS_WANT_READ;
392         }
393         else {
394             ret = -1;
395         }
396     }
397 
398     pthread_mutex_unlock(&ctx->mutex);
399 
400     /* Update counter and check if we need to continue writing */
401     return ret;
402 }
403 
tls_net_handshake(struct flb_tls * tls,void * ptr_session)404 static int tls_net_handshake(struct flb_tls *tls, void *ptr_session)
405 {
406     int ret = 0;
407     struct tls_session *session = ptr_session;
408     struct tls_context *ctx;
409 
410     ctx = session->parent;
411     pthread_mutex_lock(&ctx->mutex);
412 
413     if (tls->vhost) {
414         SSL_set_tlsext_host_name(session->ssl, tls->vhost);
415     }
416 
417     ret = SSL_connect(session->ssl);
418     if (ret != 1) {
419         ret = SSL_get_error(session->ssl, ret);
420         if (ret != SSL_ERROR_WANT_READ &&
421             ret != SSL_ERROR_WANT_WRITE) {
422             ret = SSL_get_error(session->ssl, ret);
423             pthread_mutex_unlock(&ctx->mutex);
424             return -1;
425         }
426 
427         if (ret == SSL_ERROR_WANT_WRITE) {
428             pthread_mutex_unlock(&ctx->mutex);
429             return FLB_TLS_WANT_WRITE;
430         }
431         else if (ret == SSL_ERROR_WANT_READ) {
432             pthread_mutex_unlock(&ctx->mutex);
433             return FLB_TLS_WANT_READ;
434         }
435     }
436 
437     pthread_mutex_unlock(&ctx->mutex);
438     flb_trace("[tls] connection and handshake OK");
439     return 0;
440 }
441 
442 /* OpenSSL backend registration */
443 static struct flb_tls_backend tls_openssl = {
444     .name            = "openssl",
445     .context_create  = tls_context_create,
446     .context_destroy = tls_context_destroy,
447     .session_create  = tls_session_create,
448     .session_destroy = tls_session_destroy,
449     .net_read        = tls_net_read,
450     .net_write       = tls_net_write,
451     .net_handshake   = tls_net_handshake
452 };
453