[
https://issues.apache.org/jira/browse/THRIFT-3369?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15192913#comment-15192913
]
ASF GitHub Bot commented on THRIFT-3369:
----------------------------------------
Github user gadLinux commented on a diff in the pull request:
https://github.com/apache/thrift/pull/930#discussion_r55967730
--- Diff: lib/c_glib/test/testtransportsslsocket.c ---
@@ -0,0 +1,579 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <netdb.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport.h>
+#include <thrift/c_glib/transport/thrift_server_transport.h>
+#include <thrift/c_glib/transport/thrift_server_socket.h>
+#include <thrift/c_glib/transport/thrift_ssl_socket.h>
+
+//#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+#define TEST_DATA { "GET / HTTP/1.1\n\n" }
+
+
+/* substituted functions to test failures of system and library calls */
+static int socket_error = 0;
+int
+my_socket(int domain, int type, int protocol)
+{
+ if (socket_error == 0)
+ {
+ return socket (domain, type, protocol);
+ }
+ return -1;
+}
+
+static int recv_error = 0;
+ssize_t
+my_recv(int socket, void *buffer, size_t length, int flags)
+{
+ if (recv_error == 0)
+ {
+ return recv (socket, buffer, length, flags);
+ }
+ return -1;
+}
+
+static int send_error = 0;
+ssize_t
+my_send(int socket, const void *buffer, size_t length, int flags)
+{
+ if (send_error == 0)
+ {
+ return send (socket, buffer, length, flags);
+ }
+ return -1;
+}
+
+#define socket my_socket
+#define recv my_recv
+#define send my_send
+#include "../src/thrift/c_glib/transport/thrift_ssl_socket.c"
+#undef socket
+#undef recv
+#undef send
+
+static void thrift_ssl_socket_server (const int port);
+
+/* test object creation and destruction */
+static void
+test_ssl_create_and_destroy(void)
+{
+ gchar *hostname = NULL;
+ guint port = 0;
+
+ GObject *object = NULL;
+ object = g_object_new (THRIFT_TYPE_SSL_SOCKET, NULL);
+ assert (object != NULL);
+ g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port,
NULL);
+ g_free (hostname);
+ g_object_unref (object);
+}
+
+static void
+test_ssl_create_and_set_properties(void)
+{
+ gchar *hostname = NULL;
+ guint port = 0;
+ SSL_CTX* ssl_ctx= NULL;
+ GError *error=NULL;
+
+ GObject *object = NULL;
+ object = thrift_ssl_socket_new(SSLTLS, &error);
+ g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port,
"ssl_context", &ssl_ctx, NULL);
+ assert (ssl_ctx!=NULL);
+
+ g_free (hostname);
+ g_object_unref (object);
+}
+
+static void
+test_ssl_open_and_close(void)
+{
+ ThriftSSLSocket *tSSLSocket = NULL;
+ ThriftTransport *transport = NULL;
+ GError *error=NULL;
+
+ /* open a connection and close it */
+ tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost",
51188, &error);
+
+ transport = THRIFT_TRANSPORT (tSSLSocket);
+ thrift_ssl_socket_open (transport, NULL);
+ assert (thrift_ssl_socket_is_open (transport) == TRUE);
+ thrift_ssl_socket_close (transport, NULL);
+ assert (thrift_ssl_socket_is_open (transport) == FALSE);
+
+ /* test close failure */
+ THRIFT_SOCKET(tSSLSocket)->sd = -1;
+ thrift_ssl_socket_close (transport, NULL);
+ g_object_unref (tSSLSocket);
+
+ /* try a hostname lookup failure */
+ tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS,
"localhost.broken", 51188, &error);
+ transport = THRIFT_TRANSPORT (tSSLSocket);
+ assert (thrift_ssl_socket_open (transport, &error) == FALSE);
+ g_object_unref (tSSLSocket);
+ g_error_free (error);
+ error = NULL;
+
+ /* try an error call to socket() */
+ tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost",
51188, &error);
+ transport = THRIFT_TRANSPORT (tSSLSocket);
+ socket_error = 1;
+ assert (thrift_ssl_socket_open (transport, &error) == FALSE);
+ socket_error = 0;
+ g_object_unref (tSSLSocket);
+ g_error_free (error);
+}
+
+
+
+/**
+ * Print the common name of certificate
+ */
+unsigned char * get_cn_name(X509_NAME* const name)
+{
+ int idx = -1;
+ unsigned char *utf8 = NULL;
+
+ do
+ {
+ if(!name) break; /* failed */
+
+ idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
+ if(!(idx > -1)) break; /* failed */
+
+ X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx);
+ if(!entry) break; /* failed */
+
+ ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
+ if(!data) break; /* failed */
+
+ int length = ASN1_STRING_to_UTF8(&utf8, data);
+ if(!utf8 || !(length > 0)) break; /* failed */
+
+ } while (0);
+ return utf8;
+}
+
+/*
+ * Handle IPV4 and IPV6 addr
+ */
+void *get_in_addr(struct sockaddr *sa)
+{
+ if (sa->sa_family == AF_INET)
+ return &(((struct sockaddr_in*)sa)->sin_addr);
+ return &(((struct sockaddr_in6*)sa)->sin6_addr);
+}
+
+int verify_ip(char * hostname, struct sockaddr_storage *addr)
+{
+ struct addrinfo *addr_info,*p;
+ struct addrinfo hints;
+ int res;
+ int retval = 0;
+
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
+ hints.ai_socktype = SOCK_STREAM;
+
+
+ if ( (res = getaddrinfo(hostname, NULL, &hints, &addr_info) ) != 0)
+ {
+ // get the host info
+ g_error("Cannot get the host address");
+ return retval;
+ }
+ // loop through all the results and connect to the first we can
+ char dnshost[INET6_ADDRSTRLEN]; // bigger addr supported IPV6
+ char socket_ip[INET6_ADDRSTRLEN];
+ if(inet_ntop(addr->ss_family, get_in_addr(addr), socket_ip,
INET6_ADDRSTRLEN)==socket_ip){
+ g_debug("We are connected to host %s checking against
certificate...", socket_ip);
+ int sizeip = socket_ip!=NULL ? strlen(socket_ip) : 0;
+ for(p = addr_info; p != NULL; p = p->ai_next) {
+ if(inet_ntop(p->ai_family, get_in_addr((struct sockaddr
*)p->ai_addr), dnshost, INET6_ADDRSTRLEN)==dnshost){
+ if(dnshost!=NULL){
+ g_info("DNS address [%i -> %s]",
p->ai_addr, dnshost);
+ if(!strncmp(dnshost, socket_ip,
sizeip)){
+ retval=1;
+ break; // if we get here, we
must have connected successfully
+ }
+ }
+ }
+ }
+ }
+
+ if(addr_info)
+ freeaddrinfo(addr_info);
+
+ return retval;
+}
+
+static void
+read_from_file(char *buffer, long size, const char *file_name)
+{
+ char ch;
+ long index=0;
+ FILE *fp;
+
+ fp = fopen(file_name,"r"); // read mode
+
+ if( fp == NULL )
+ {
+ perror("Error while opening the file.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("The contents of %s file are :\n", file_name);
+
+ while(index<size && ( ch = fgetc(fp) ) != EOF ){
+ buffer[index++] = ch;
+ }
+
+ fclose(fp);
+}
+
+#define ISSUER_CN_PINNING "Level2"
+#define SUBJECT_CN_PINNING "owncloud.level2crm.com"
+#define CERT_SERIAL_NUMBER "3"
+
+gboolean verify_certificate_sn(X509 *cert, const unsigned char
*serial_number)
+{
+ gboolean retval = FALSE;
+
+ ASN1_INTEGER *serial = X509_get_serialNumber(cert);
+
+ BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
+ if (!bn) {
+ fprintf(stderr, "unable to convert ASN1INTEGER to BN\n");
+ return EXIT_FAILURE;
+ }
+ char *tmp = BN_bn2dec(bn);
+ if (!tmp) {
+ g_warning(stderr, "unable to convert BN to decimal string.\n");
+ BN_free(bn);
+ return EXIT_FAILURE;
+ }
+// if (strlen(tmp) >= len) {
+// g_warn(stderr, "buffer length shorter than serial number\n");
+// BN_free(bn);
+// OPENSSL_free(tmp);
+// return EXIT_FAILURE;
+// }
+ if(!strncmp(serial_number, tmp, strlen(serial_number))){
+ retval=TRUE;
+ }else{
+ g_warning("Serial number is not valid");
+ }
+
+ BN_free(bn);
+ OPENSSL_free(tmp);
+ return retval;
+}
+
+gboolean my_access_manager(ThriftTransport * transport, X509 *cert, struct
sockaddr_storage *addr, GError **error)
+{
+ ThriftSSLSocket *sslSocket = THRIFT_SSL_SOCKET (transport);
+
+ g_info("Processing access to the server");
+ X509_NAME* iname = cert ? X509_get_issuer_name(cert) : NULL;
+ X509_NAME* sname = cert ? X509_get_subject_name(cert) : NULL;
+
+ /* Issuer is the authority we trust that warrants nothing useful */
+ const unsigned char * issuer = get_cn_name(iname);
+ if(issuer){
+ gboolean valid = TRUE;
+ g_info("Issuer (cn) %s", issuer);
+
+ // Issuer pinning
+ if(strncmp(ISSUER_CN_PINNING, issuer,
strlen(ISSUER_CN_PINNING))){
+ g_warning("The Issuer of the certificate is not valid");
+ valid=FALSE;
+ }
+ OPENSSL_free(issuer);
+ if(!valid)
+ return valid;
+ }
+
+
+ /* Subject is who the certificate is issued to by the authority */
+ const unsigned char * subject = get_cn_name(sname);
+ if(subject){
+ g_info("Subject (cn) %s", subject);
+ gboolean valid = TRUE;
+
+ // Subject pinning
+ if(strncmp(SUBJECT_CN_PINNING, subject,
strlen(SUBJECT_CN_PINNING))){
+ g_warning("The subject of the certificate is not
valid");
+ valid=FALSE;
+ }
+
+ if(!valid)
+ return valid;
+
+ // Host pinning
+ if(verify_ip(subject, addr)){
+ g_info("Verified subject");
+ }else{
+ g_info("Cannot verify subject");
+ valid=FALSE;
+ }
+ OPENSSL_free(subject);
+
+ if(!valid)
+ return valid;
+ }
+
+ if(!verify_certificate_sn(cert, CERT_SERIAL_NUMBER)){
+ return FALSE;
+ }else{
+ g_info("Verified serial number");
+ }
+
+ return TRUE;
+
+}
+
+
+
+
+
+static void
+test_ssl_authorization_manager(void)
+{
+ int status=0;
+ pid_t pid;
+ ThriftSSLSocket *tSSLsocket = NULL;
+ ThriftTransport *transport = NULL;
+ // int port = 51199;
+ int port = 443;
+ GError *error=NULL;
+
+ guchar buf[17] = TEST_DATA; /* a buffer */
+
+ // pid = fork ();
+ // assert ( pid >= 0 );
+ //
+ // if ( pid == 0 )
+ // {
+ // /* child listens */
+ // thrift_ssl_socket_server (port);
+ // exit (0);
+ // } else {
+ /* parent connects, wait a bit for the socket to be created */
+ sleep (1);
+
+ // Test against level2 owncloud certificate
+ tSSLsocket = thrift_ssl_socket_new_with_host(SSLTLS,
"owncloud.level2crm.com", port, &error);
+ thrift_ssl_socket_set_manager(tSSLsocket, my_access_manager);
// Install pinning manager
+ //thrift_ssl_load_cert_from_file(tSSLsocket,
"./owncloud.level2crm.pem");
+ unsigned char cert_buffer[65534];
+ read_from_file(cert_buffer, 65534, "./owncloud.level2crm.pem");
+ if(!thrift_ssl_load_cert_from_buffer(tSSLsocket, cert_buffer)){
+ g_warning("Certificates cannot be loaded!");
+ }
+
+ transport = THRIFT_TRANSPORT (tSSLsocket);
+ assert (thrift_ssl_socket_open (transport, NULL) == TRUE);
+ assert (thrift_ssl_socket_is_open (transport));
+
+ thrift_ssl_socket_write (transport, buf, 17, NULL);
+
+ /* write fail */
+ send_error = 1;
+ // thrift_ssl_socket_write (transport, buf, 1, NULL);
+ // send_error = 0;
+
+ // thrift_ssl_socket_write_end (transport, NULL);
+ // thrift_ssl_socket_flush (transport, NULL);
+ thrift_ssl_socket_close (transport, NULL);
+ g_object_unref (tSSLsocket);
+
+ // assert ( wait (&status) == pid );
+ assert ( status == 0 );
+ // }
+}
+
+
+/* test ThriftSocket's peek() implementation */
+//static void
+//test_ssl_peek(void)
+//{
+// gint status;
+// pid_t pid;
+// guint port = 51199;
+// gchar data = 'A';
+// ThriftTransport *client_transport;
+// GError *error = NULL;
+//
+// client_transport = g_object_new (THRIFT_TYPE_SSL_SOCKET,
+// "hostname", "localhost",
+// "port", port,
+// NULL);
+//
+// /* thrift_transport_peek returns FALSE when the socket is closed */
+// g_assert (thrift_transport_is_open (client_transport) == FALSE);
+// g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
+// g_assert (error == NULL);
+//
+// pid = fork ();
--- End diff --
This is because Server part was not ready. If I remember well. I will see
also to this.
> Implement SSL/TLS support on C with c_glib
> ------------------------------------------
>
> Key: THRIFT-3369
> URL: https://issues.apache.org/jira/browse/THRIFT-3369
> Project: Thrift
> Issue Type: Improvement
> Components: C glib - Library
> Affects Versions: 0.9.1, 0.9.2, 0.9.3, 1.0
> Reporter: Gonzalo Aguilar
> Labels: features, patch
> Fix For: 0.10.0, 1.0
>
>
> Implement SSL/TLS based on plain openssl instead of going through the way
> defined in THRIFT-1016.
> This help us to maintain a reference implementation and later switch over GIO
> or whatever is defined. But also does not add any other dependencies to the
> project. So bare minimum installation for supporting SSL/TLS is there and
> aligned with CPP counterpart.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)