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