]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/thrift/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / thrift / lib / c_glib / src / thrift / c_glib / transport / thrift_ssl_socket.c
CommitLineData
f67539c2
TL
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#include <errno.h>
21#include <netdb.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25#include <sys/socket.h>
26#include <netinet/in.h>
27#include <openssl/ssl.h>
28#include <pthread.h>
29
30#include <glib-object.h>
31#include <glib.h>
32
33#include <thrift/c_glib/thrift.h>
34#include <thrift/c_glib/transport/thrift_transport.h>
35#include <thrift/c_glib/transport/thrift_socket.h>
36#include <thrift/c_glib/transport/thrift_ssl_socket.h>
37
38
39#if defined(WIN32)
40#define MUTEX_TYPE HANDLE
41#define MUTEX_SETUP(x) (x) = CreateMutex(NULL, FALSE, NULL)
42#define MUTEX_CLEANUP(x) CloseHandle(x)
43#define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE)
44#define MUTEX_UNLOCK(x) ReleaseMutex(x)
45#else
46#define MUTEX_TYPE pthread_mutex_t
47#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
48#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
49#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
50#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
51#endif
52
53#define OPENSSL_VERSION_NO_THREAD_ID 0x10000000L
54
55
56/* object properties */
57enum _ThriftSSLSocketProperties
58{
59 PROP_THRIFT_SSL_SOCKET_CONTEXT = 3,
60 PROP_THRIFT_SSL_SELF_SIGNED
61};
62
63/* To hold a global state management of openssl for all instances */
64static gboolean thrift_ssl_socket_openssl_initialized=FALSE;
65/* This array will store all of the mutexes available to OpenSSL. */
66static MUTEX_TYPE *thrift_ssl_socket_global_mutex_buf=NULL;
67
68
69/**
70 * OpenSSL uniq id function.
71 *
72 * @return thread id
73 */
74static unsigned long thrift_ssl_socket_static_id_function(void)
75{
76#if defined(WIN32)
77 return GetCurrentThreadId();
78#else
79 return ((unsigned long) pthread_self());
80#endif
81}
82
83static void thrift_ssl_socket_static_locking_callback(int mode, int n, const char* unk, int id) {
84 if (mode & CRYPTO_LOCK)
85 MUTEX_LOCK(thrift_ssl_socket_global_mutex_buf[n]);
86 else
87 MUTEX_UNLOCK(thrift_ssl_socket_global_mutex_buf[n]);
88}
89
90static int thrift_ssl_socket_static_thread_setup(void)
91{
92 int i;
93
94 thrift_ssl_socket_global_mutex_buf = malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
95 if (!thrift_ssl_socket_global_mutex_buf)
96 return 0;
97 for (i = 0; i < CRYPTO_num_locks( ); i++)
98 MUTEX_SETUP(thrift_ssl_socket_global_mutex_buf[i]);
99 CRYPTO_set_id_callback(thrift_ssl_socket_static_id_function);
100 CRYPTO_set_locking_callback(thrift_ssl_socket_static_locking_callback);
101 return 1;
102}
103
104static int thrift_ssl_socket_static_thread_cleanup(void)
105{
106 int i;
107 if (!thrift_ssl_socket_global_mutex_buf)
108 return 0;
109 CRYPTO_set_id_callback(NULL);
110 CRYPTO_set_locking_callback(NULL);
111 for (i = 0; i < CRYPTO_num_locks( ); i++)
112 MUTEX_CLEANUP(thrift_ssl_socket_global_mutex_buf[i]);
113 free(thrift_ssl_socket_global_mutex_buf);
114 thrift_ssl_socket_global_mutex_buf = NULL;
115 return 1;
116}
117
118/*
119static void* thrift_ssl_socket_dyn_lock_create_callback(const char* unk, int id) {
120 g_print("We should create a lock\n");
121 return NULL;
122}
123
124static void thrift_ssl_socket_dyn_lock_callback(int mode, void* lock, const char* unk, int id) {
125 if (lock != NULL) {
126 if (mode & CRYPTO_LOCK) {
127 g_printf("We should lock thread %d\n");
128 } else {
129 g_printf("We should unlock thread %d\n");
130 }
131 }
132}
133
134static void thrift_ssl_socket_dyn_lock_destroy_callback(void* lock, const char* unk, int id) {
135 g_printf("We must destroy the lock\n");
136}
137 */
138
139
140G_DEFINE_TYPE(ThriftSSLSocket, thrift_ssl_socket, THRIFT_TYPE_SOCKET)
141
142
143
144/**
145 * When there's a thread context attached, we pass the SSL socket context so it
146 * can check if the error is outside SSL, on I/O for example
147 * @param socket
148 * @param error_msg
149 * @param thrift_error_no
150 * @param ssl_error
151 * @param error
152 */
153static
154void thrift_ssl_socket_get_ssl_error(ThriftSSLSocket *socket, const guchar *error_msg, guint thrift_error_no, int ssl_error, GError **error)
155{
156 unsigned long error_code;
157 char buffer[1024];
158 int buffer_size=1024;
159 gboolean first_error = TRUE;
160 int ssl_error_type = SSL_get_error(socket->ssl, ssl_error);
161 if(ssl_error_type>0){
162 switch(ssl_error_type){
163 case SSL_ERROR_SSL:
164 buffer_size-=snprintf(buffer, buffer_size, "SSL %s: ", error_msg);
165 while ((error_code = ERR_get_error()) != 0 && buffer_size>1) {
166 const char* reason = ERR_reason_error_string(error_code);
167 if(reason!=NULL){
168 if(!first_error) {
169 buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "\n\t");
170 first_error=FALSE;
171 }
172 buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX(%s) -> %s", error_code, reason, SSL_state_string(socket->ssl));
173 }
174 }
175 break;
176 case SSL_ERROR_SYSCALL:
177 buffer_size-=snprintf(buffer, buffer_size, "%s: ", error_msg);
178 buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX -> %s", errno, strerror(errno));
179 break;
180 case SSL_ERROR_WANT_READ:
181 buffer_size-=snprintf(buffer, buffer_size, "%s: ", error_msg);
182 buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX -> %s", ssl_error_type, "Error while reading from underlaying layer");
183 break;
184 case SSL_ERROR_WANT_WRITE:
185 buffer_size-=snprintf(buffer, buffer_size, "%s: ", error_msg);
186 buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX -> %s", ssl_error_type, "Error while writting to underlaying layer");
187 break;
188
189 }
190 g_set_error (error, THRIFT_TRANSPORT_ERROR,
191 thrift_error_no, "%s", buffer);
192 }
193}
194
195/**
196 * For global SSL errors
197 * @param error_msg
198 * @param thrift_error_no
199 * @param error
200 */
201static
202void thrift_ssl_socket_get_error(const guchar *error_msg, guint thrift_error_no, GError **error)
203{
204 unsigned long error_code;
205 while ((error_code = ERR_get_error()) != 0) {
206 const char* reason = ERR_reason_error_string(error_code);
207 if (reason == NULL) {
208 g_set_error (error, THRIFT_TRANSPORT_ERROR,
209 thrift_error_no,
210 "SSL error %lX: %s", error_code, error_msg);
211 }else{
212 g_set_error (error, THRIFT_TRANSPORT_ERROR,
213 thrift_error_no,
214 "SSL error %lX %s: %s", error_code,reason, error_msg);
215 }
216 }
217}
218
219
220
221/* implements thrift_transport_is_open */
222gboolean
223thrift_ssl_socket_is_open (ThriftTransport *transport)
224{
225 return thrift_socket_is_open(transport);
226}
227
228/* overrides thrift_transport_peek */
229gboolean
230thrift_ssl_socket_peek (ThriftTransport *transport, GError **error)
231{
232 gboolean retval = FALSE;
233 ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
234 if (thrift_ssl_socket_is_open (transport))
235 {
236 int rc;
237 gchar byte;
238 rc = SSL_peek(ssl_socket->ssl, &byte, 1);
239 if (rc < 0) {
240 thrift_ssl_socket_get_ssl_error(ssl_socket, "Check socket data",
241 THRIFT_SSL_SOCKET_ERROR_SSL, rc, error);
242 }
243 if (rc == 0) {
244 ERR_clear_error();
245 }
246 retval = (rc > 0);
247 }
248 return retval;
249}
250
251/* implements thrift_transport_open */
252gboolean
253thrift_ssl_socket_open (ThriftTransport *transport, GError **error)
254{
255 ERR_clear_error();
256
257 if (!thrift_socket_open(transport, error)) {
258 return FALSE;
259 }
260
261 if (!THRIFT_SSL_SOCKET_GET_CLASS(transport)->handle_handshake(transport, error)) {
262 thrift_ssl_socket_close(transport, NULL);
263 return FALSE;
264 }
265
266 return TRUE;
267}
268
269/* implements thrift_transport_close */
270gboolean
271thrift_ssl_socket_close (ThriftTransport *transport, GError **error)
272{
273 gboolean retval = FALSE;
274 ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET(transport);
275 if(ssl_socket!=NULL && ssl_socket->ssl) {
276 int rc = SSL_shutdown(ssl_socket->ssl);
277/* if (rc < 0) {
278 int errno_copy = THRIFT_SSL_SOCKET_ERROR_SSL;
279 }*/
280 SSL_free(ssl_socket->ssl);
281 ssl_socket->ssl = NULL;
282 ERR_remove_state(0);
283 }
284 return thrift_socket_close(transport, error);
285}
286
287/* implements thrift_transport_read */
288gint32
289thrift_ssl_socket_read (ThriftTransport *transport, gpointer buf,
290 guint32 len, GError **error)
291{
292 guint maxRecvRetries_ = 10;
293 ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
294 guint bytes = 0;
295 guint retries = 0;
296 ThriftSocket *socket = THRIFT_SOCKET (transport);
297 g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET && ssl_socket->ssl!=NULL, FALSE);
298
299 for (retries=0; retries < maxRecvRetries_; retries++) {
300 bytes = SSL_read(ssl_socket->ssl, buf, len);
301 if (bytes >= 0)
302 break;
303 int errno_copy = THRIFT_GET_SOCKET_ERROR;
304 if (SSL_get_error(ssl_socket->ssl, bytes) == SSL_ERROR_SYSCALL) {
305 if (ERR_get_error() == 0 && errno_copy == THRIFT_EINTR) {
306 continue;
307 }
308 }else{
309 thrift_ssl_socket_get_ssl_error(ssl_socket, "Receive error",
310 THRIFT_SSL_SOCKET_ERROR_SSL, bytes, error);
311
312 }
313 return -1;
314 }
315 return bytes;
316}
317
318/* implements thrift_transport_read_end
319 * called when write is complete. nothing to do on our end. */
320gboolean
321thrift_ssl_socket_read_end (ThriftTransport *transport, GError **error)
322{
323 /* satisfy -Wall */
324 THRIFT_UNUSED_VAR (transport);
325 THRIFT_UNUSED_VAR (error);
326 return TRUE;
327}
328
329/* implements thrift_transport_write */
330gboolean
331thrift_ssl_socket_write (ThriftTransport *transport, const gpointer buf,
332 const guint32 len, GError **error)
333{
334 ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
335 gint ret = 0;
336 guint sent = 0;
337 ThriftSocket *socket = THRIFT_SOCKET (transport);
338 g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET && ssl_socket->ssl!=NULL, FALSE);
339
340 while (sent < len)
341 {
342 ret = SSL_write (ssl_socket->ssl, (guint8 *)buf + sent, len - sent);
343 if (ret < 0)
344 {
345 thrift_ssl_socket_get_ssl_error(ssl_socket, "Send error",
346 THRIFT_SSL_SOCKET_ERROR_SSL, ret, error);
347 return FALSE;
348 }
349 sent += ret;
350 }
351
352 return sent==len;
353}
354
355/* implements thrift_transport_write_end
356 * called when write is complete. nothing to do on our end. */
357gboolean
358thrift_ssl_socket_write_end (ThriftTransport *transport, GError **error)
359{
360 /* satisfy -Wall */
361 THRIFT_UNUSED_VAR (transport);
362 THRIFT_UNUSED_VAR (error);
363 return TRUE;
364}
365
366/* implements thrift_transport_flush
367 * flush pending data. since we are not buffered, this is a no-op */
368gboolean
369thrift_ssl_socket_flush (ThriftTransport *transport, GError **error)
370{
371 ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
372
373 ThriftSocket *socket = THRIFT_SOCKET (transport);
374 g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET && ssl_socket->ssl!=NULL, FALSE);
375
376 BIO* bio = SSL_get_wbio(ssl_socket->ssl);
377 if (bio == NULL) {
378 g_set_error (error, THRIFT_TRANSPORT_ERROR,
379 THRIFT_TRANSPORT_ERROR_SEND,
380 "failed to flush, wbio returned null");
381 return FALSE;
382 }
383 if (BIO_flush(bio) != 1) {
384 g_set_error (error, THRIFT_TRANSPORT_ERROR,
385 THRIFT_TRANSPORT_ERROR_SEND,
386 "failed to flush it returned error");
387 return FALSE;
388 }
389 return TRUE;
390}
391
392
393gboolean
394thrift_ssl_socket_handle_handshake(ThriftTransport * transport, GError **error)
395{
396 ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
397 ThriftSocket *socket = THRIFT_SOCKET (transport);
398 g_return_val_if_fail (thrift_transport_is_open (transport), FALSE);
399
400 if(THRIFT_SSL_SOCKET_GET_CLASS(ssl_socket)->create_ssl_context(transport, error)){
401 /*Context created*/
402 SSL_set_fd(ssl_socket->ssl, socket->sd);
403 int rc;
404 if(ssl_socket->server){
405 rc = SSL_accept(ssl_socket->ssl);
406 }else{
407 rc = SSL_connect(ssl_socket->ssl);
408 }
409 if (rc <= 0) {
410 thrift_ssl_socket_get_ssl_error(ssl_socket, "Error while connect/bind", THRIFT_SSL_SOCKET_ERROR_CONNECT_BIND, rc, error);
411 return FALSE;
412 }
413 }else
414 return FALSE;
415
416 return thrift_ssl_socket_authorize(transport, error);
417}
418
419gboolean
420thrift_ssl_socket_create_ssl_context(ThriftTransport * transport, GError **error)
421{
422 ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (transport);
423
424 if(socket->ctx!=NULL){
425 if(socket->ssl!=NULL) {
426 return TRUE;
427 }
428
429 socket->ssl = SSL_new(socket->ctx);
430 if (socket->ssl == NULL) {
431 g_set_error (error, THRIFT_TRANSPORT_ERROR,
432 THRIFT_SSL_SOCKET_ERROR_TRANSPORT,
433 "Unable to create default SSL context");
434 return FALSE;
435 }
436 }
437
438 return TRUE;
439}
440
441
442gboolean thrift_ssl_load_cert_from_file(ThriftSSLSocket *ssl_socket, const char *file_name)
443{
444 char error_buffer[255];
445 if (!thrift_ssl_socket_openssl_initialized) {
446 g_error("OpenSSL is not initialized yet");
447 return FALSE;
448 }
449 int rc = SSL_CTX_load_verify_locations(ssl_socket->ctx, file_name, NULL);
450 if (rc != 1) { /*verify authentication result*/
451 ERR_error_string_n(ERR_get_error(), error_buffer, 254);
452 g_warning("Load of certificates failed: %s!", error_buffer);
453 return FALSE;
454 }
455 return TRUE;
456}
457
458
459gboolean thrift_ssl_load_cert_from_buffer(ThriftSSLSocket *ssl_socket, const char chain_certs[])
460{
461 gboolean retval = FALSE;
462 /* Load chain of certs*/
463 X509 *cacert=NULL;
464 BIO *mem = BIO_new_mem_buf(chain_certs,strlen(chain_certs));
465 X509_STORE *cert_store = SSL_CTX_get_cert_store(ssl_socket->ctx);
466
467 if(cert_store!=NULL){
468 int index = 0;
469 while ((cacert = PEM_read_bio_X509(mem, NULL, 0, NULL))!=NULL) {
470 if(cacert) {
471 X509_STORE_add_cert(cert_store, cacert);
472 X509_free(cacert);
473 cacert=NULL;
474 } /* Free immediately */
475 index++;
476 }
477 retval=TRUE;
478 }
479 BIO_free(mem);
480 return retval;
481}
482
483gboolean
484thrift_ssl_socket_authorize(ThriftTransport * transport, GError **error)
485{
486 ThriftSocket *socket = THRIFT_SOCKET (transport);
487 ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
488 ThriftSSLSocketClass *cls = THRIFT_SSL_SOCKET_GET_CLASS(ssl_socket);
489 gboolean authorization_result = FALSE;
490
491 if(cls!=NULL && ssl_socket->ssl!=NULL){
492 int rc = SSL_get_verify_result(ssl_socket->ssl);
493 if (rc != X509_V_OK) { /* verify authentication result */
494 if (rc == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && ssl_socket->allow_selfsigned) {
495 g_debug("The certificate is a self-signed certificate and configuration allows it");
496 } else {
497 g_set_error (error,
498 THRIFT_TRANSPORT_ERROR,
499 THRIFT_SSL_SOCKET_ERROR_SSL_CERT_VALIDATION_FAILED,
500 "The certificate verification failed: %s (%d)", X509_verify_cert_error_string(rc), rc);
501 return FALSE;
502 }
503 }
504
505 X509* cert = SSL_get_peer_certificate(ssl_socket->ssl);
506 if (cert == NULL) {
507 if (SSL_get_verify_mode(ssl_socket->ssl) & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
508 g_set_error (error,
509 THRIFT_TRANSPORT_ERROR,
510 THRIFT_SSL_SOCKET_ERROR_SSL_CERT_VALIDATION_FAILED,
511 "No certificate present. Are you connecting SSL server?");
512 return FALSE;
513 }
514 g_debug("No certificate required");
515 return TRUE;
516 }
517
518 /* certificate is present, since we don't support access manager we are done */
519 if (cls->authorize_peer == NULL) {
520 X509_free(cert);
521 g_debug("Certificate presented but we're not checking it");
522 return TRUE;
523 } else {
524 /* both certificate and access manager are present */
525 struct sockaddr_storage sa;
526 socklen_t saLength = sizeof(struct sockaddr_storage);
527 if (getpeername(socket->sd, (struct sockaddr*)&sa, &saLength) != 0) {
528 sa.ss_family = AF_UNSPEC;
529 }
530 authorization_result = cls->authorize_peer(transport, cert, &sa, error);
531 }
532 if(cert != NULL) {
533 X509_free(cert);
534 }
535 }
536
537 return authorization_result;
538}
539
540
541/* initializes the instance */
542static void
543thrift_ssl_socket_init (ThriftSSLSocket *socket)
544{
545 GError *error = NULL;
546 socket->ssl = NULL;
547 socket->ctx = thrift_ssl_socket_context_initialize(SSLTLS, &error);
548 if(socket->ctx == NULL) {
549 g_info("The SSL context was not automatically initialized with protocol %d", SSLTLS);
550 if(error!=NULL){
551 g_info("Reported reason %s", error->message);
552 g_error_free (error);
553 }
554 }
555 socket->server = FALSE;
556 socket->allow_selfsigned = FALSE;
557
558}
559
560/* destructor */
561static void
562thrift_ssl_socket_finalize (GObject *object)
563{
564 ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (object);
565 GError *error=NULL;
566 if(socket!=NULL){
567 g_debug("Instance %p destroyed", (void *)socket);
568 if(socket->ssl != NULL)
569 {
570 thrift_ssl_socket_close(THRIFT_TRANSPORT(object), &error);
571 socket->ssl=NULL;
572 }
573
574 if(socket->ctx!=NULL){
575 g_debug("Freeing the context for the instance");
576 SSL_CTX_free(socket->ctx);
577 socket->ctx=NULL;
578 }
579 }
580
581 if (G_OBJECT_CLASS (thrift_ssl_socket_parent_class)->finalize)
582 (*G_OBJECT_CLASS (thrift_ssl_socket_parent_class)->finalize) (object);
583}
584
585/* property accessor */
586void
587thrift_ssl_socket_get_property (GObject *object, guint property_id,
588 GValue *value, GParamSpec *pspec)
589{
590 ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (object);
591 THRIFT_UNUSED_VAR (pspec);
592
593 switch (property_id)
594 {
595 case PROP_THRIFT_SSL_SOCKET_CONTEXT:
596 g_value_set_pointer (value, socket->ctx);
597 break;
598 }
599}
600
601/* property mutator */
602void
603thrift_ssl_socket_set_property (GObject *object, guint property_id,
604 const GValue *value, GParamSpec *pspec)
605{
606 ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (object);
607
608 THRIFT_UNUSED_VAR (pspec);
609 switch (property_id)
610 {
611 case PROP_THRIFT_SSL_SOCKET_CONTEXT:
612 if(socket->ctx!=NULL){
613 g_debug("Freeing the context since we are setting a new one");
614 SSL_CTX_free(socket->ctx);
615 }
616 socket->ctx = g_value_get_pointer(value); /* We copy the context */
617 break;
618
619 case PROP_THRIFT_SSL_SELF_SIGNED:
620 socket->allow_selfsigned = g_value_get_boolean(value);
621 break;
622 default:
623 g_warning("Trying to set property %i that doesn't exists!", property_id);
624 /* thrift_socket_set_property(object, property_id, value, pspec); */
625 break;
626 }
627}
628
629void
630thrift_ssl_socket_initialize_openssl(void)
631{
632 if(thrift_ssl_socket_openssl_initialized){
633 return;
634 }
635 thrift_ssl_socket_openssl_initialized=TRUE;
636 SSL_library_init();
637 ERR_load_crypto_strings();
638 SSL_load_error_strings();
639 ERR_load_BIO_strings();
640
641 /* Setup locking */
642 g_debug("We setup %d threads locks", thrift_ssl_socket_static_thread_setup());
643
644 /* dynamic locking
645 CRYPTO_set_dynlock_create_callback(thrift_ssl_socket_dyn_lock_create_callback);
646 CRYPTO_set_dynlock_lock_callback(thrift_ssl_socket_dyn_lock_callback);
647 CRYPTO_set_dynlock_destroy_callback(thrift_ssl_socket_dyn_lock_destroy_callback);
648 */
649}
650
651
652void thrift_ssl_socket_finalize_openssl(void)
653{
654 if (!thrift_ssl_socket_openssl_initialized) {
655 return;
656 }
657 thrift_ssl_socket_openssl_initialized = FALSE;
658
659 g_debug("We cleared %d threads locks", thrift_ssl_socket_static_thread_cleanup());
660 /* Not supported
661 CRYPTO_set_locking_callback(NULL);
662 CRYPTO_set_dynlock_create_callback(NULL);
663 CRYPTO_set_dynlock_lock_callback(NULL);
664 CRYPTO_set_dynlock_destroy_callback(NULL);
665 */
666 ERR_free_strings();
667 EVP_cleanup();
668 CRYPTO_cleanup_all_ex_data();
669 ERR_remove_state(0);
670}
671
672
673/* initializes the class */
674static void
675thrift_ssl_socket_class_init (ThriftSSLSocketClass *cls)
676{
677 ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
678 GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
679 GParamSpec *param_spec = NULL;
680
681 g_debug("Initialization of ThriftSSLSocketClass");
682 /* setup accessors and mutators */
683 gobject_class->get_property = thrift_ssl_socket_get_property;
684 gobject_class->set_property = thrift_ssl_socket_set_property;
685 param_spec = g_param_spec_pointer ("ssl_context",
686 "SSLContext",
687 "Set the SSL context for handshake with the remote host",
688 G_PARAM_READWRITE);
689 g_object_class_install_property (gobject_class, PROP_THRIFT_SSL_SOCKET_CONTEXT,
690 param_spec);
691 param_spec = g_param_spec_boolean ("ssl_accept_selfsigned",
692 "Accept Self Signed",
693 "Whether or not accept self signed certificate",
694 FALSE,
695 G_PARAM_READWRITE);
696 g_object_class_install_property (gobject_class, PROP_THRIFT_SSL_SELF_SIGNED,
697 param_spec);
698 /* Class methods */
699 cls->handle_handshake = thrift_ssl_socket_handle_handshake;
700 cls->create_ssl_context = thrift_ssl_socket_create_ssl_context;
701
702 /* Override */
703 gobject_class->finalize = thrift_ssl_socket_finalize;
704 ttc->is_open = thrift_ssl_socket_is_open;
705 ttc->peek = thrift_ssl_socket_peek;
706 ttc->open = thrift_ssl_socket_open;
707 ttc->close = thrift_ssl_socket_close;
708 ttc->read = thrift_ssl_socket_read;
709 ttc->read_end = thrift_ssl_socket_read_end;
710 ttc->write = thrift_ssl_socket_write;
711 ttc->write_end = thrift_ssl_socket_write_end;
712 ttc->flush = thrift_ssl_socket_flush;
713}
714
715
716/*
717 * Public API
718 */
719ThriftSSLSocket*
720thrift_ssl_socket_new(ThriftSSLSocketProtocol ssl_protocol, GError **error)
721{
722 ThriftSSLSocket *thriftSSLSocket = NULL;
723 SSL_CTX *ssl_context = NULL;
724 /* Create the context */
725 if((ssl_context=thrift_ssl_socket_context_initialize(ssl_protocol, error))==NULL){
726 g_warning("We cannot initialize context for protocol %d", ssl_protocol);
727 return thriftSSLSocket;
728 }
729
730 /* FIXME if the protocol is different? */
731 thriftSSLSocket = g_object_new (THRIFT_TYPE_SSL_SOCKET, "ssl_context", ssl_context, NULL);
732 return thriftSSLSocket;
733}
734
735ThriftSSLSocket*
736thrift_ssl_socket_new_with_host(ThriftSSLSocketProtocol ssl_protocol, gchar *hostname, guint port, GError **error)
737{
738 ThriftSSLSocket *thriftSSLSocket = NULL;
739 SSL_CTX *ssl_context = NULL;
740 /* Create the context */
741 if((ssl_context=thrift_ssl_socket_context_initialize(ssl_protocol, error))==NULL){
742 /* FIXME Do error control */
743 return thriftSSLSocket;
744 }
745 /* FIXME if the protocol is different? */
746 thriftSSLSocket = g_object_new (THRIFT_TYPE_SSL_SOCKET, "ssl_context", ssl_context, "hostname", hostname, "port", port, NULL);
747 return thriftSSLSocket;
748}
749
750void thrift_ssl_socket_set_manager(ThriftSSLSocket *ssl_socket, AUTHORIZATION_MANAGER_CALLBACK callback)
751{
752 ThriftSSLSocketClass *sslSocketClass = THRIFT_SSL_SOCKET_GET_CLASS (ssl_socket);
753 if(sslSocketClass){
754 sslSocketClass->authorize_peer = callback;
755 }
756}
757
758
759SSL_CTX*
760thrift_ssl_socket_context_initialize(ThriftSSLSocketProtocol ssl_protocol, GError **error)
761{
762 SSL_CTX* context = NULL;
763 switch(ssl_protocol){
764 case SSLTLS:
765 context = SSL_CTX_new(SSLv23_method());
766 break;
767#ifndef OPENSSL_NO_SSL3
768 case SSLv3:
769 context = SSL_CTX_new(SSLv3_method());
770 break;
771#endif
772 case TLSv1_0:
773 context = SSL_CTX_new(TLSv1_method());
774 break;
775 case TLSv1_1:
776 context = SSL_CTX_new(TLSv1_1_method());
777 break;
778 case TLSv1_2:
779 context = SSL_CTX_new(TLSv1_2_method());
780 break;
781 default:
782 g_set_error (error, THRIFT_TRANSPORT_ERROR,
783 THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE,
784 "The SSL protocol is unknown for %d", ssl_protocol);
785 return NULL;
786 break;
787 }
788
789 if (context == NULL) {
790 thrift_ssl_socket_get_error("No cipher overlay", THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE, error);
791 return NULL;
792 }
793 SSL_CTX_set_mode(context, SSL_MODE_AUTO_RETRY);
794
795 /* Disable horribly insecure SSLv2 and SSLv3 protocols but allow a handshake
796 with older clients so they get a graceful denial. */
797 if (ssl_protocol == SSLTLS) {
798 SSL_CTX_set_options(context, SSL_OP_NO_SSLv2);
799 SSL_CTX_set_options(context, SSL_OP_NO_SSLv3); /* THRIFT-3164 */
800 }
801
802 return context;
803}
804