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