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