loudmouth/src/lm-ssl-openssl.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
       
     2 /*
       
     3  * Copyright (C) 2006 Imendio AB
       
     4  *  and/or its subsidiary/subsidiaries. All rights reserved.
       
     5  *
       
     6  * This program is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Lesser General Public License as
       
     8  * published by the Free Software Foundation; either version 2 of the
       
     9  * License, or (at your option) any later version.
       
    10  *
       
    11  * This program is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Lesser General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Lesser General Public
       
    17  * License along with this program; if not, write to the
       
    18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    19  * Boston, MA 02111-1307, USA.
       
    20  */
       
    21 
       
    22 #include <config.h>
       
    23 
       
    24 #include <stdio.h>
       
    25 #include <string.h>
       
    26 #include <unistd.h>
       
    27 #include <glib.h>
       
    28 
       
    29 #include "lm-debug.h"
       
    30 #include "lm-error.h"
       
    31 #include "lm-ssl-base.h"
       
    32 #include "lm-ssl-internals.h"
       
    33 
       
    34 #ifdef EMULATOR
       
    35 #include "libloudmouth_wsd_solution.h"
       
    36 GET_STATIC_VAR_FROM_TLS(initialized, lm_ssl_openssl, gboolean)
       
    37   #define initialized (*GET_WSD_VAR_NAME(initialized, lm_ssl_openssl, s) () )
       
    38 #endif
       
    39 #ifdef HAVE_OPENSSL
       
    40 
       
    41 #include <openssl/ssl.h>
       
    42 #include <openssl/err.h>
       
    43 
       
    44 #define LM_SSL_CN_MAX		63
       
    45 
       
    46 struct _LmSSL {
       
    47 	LmSSLBase base;
       
    48 
       
    49 	SSL_METHOD *ssl_method;
       
    50 	SSL_CTX *ssl_ctx;
       
    51 	SSL *ssl;
       
    52 	/*BIO *bio;*/
       
    53 };
       
    54 
       
    55 int ssl_verify_cb (int preverify_ok, X509_STORE_CTX *x509_ctx);
       
    56 
       
    57 static gboolean ssl_verify_certificate (LmSSL *ssl, const gchar *server);
       
    58 static GIOStatus ssl_io_status_from_return (LmSSL *ssl, gint error);
       
    59 
       
    60 /*static char _ssl_error_code[11];*/
       
    61 
       
    62 static void
       
    63 ssl_print_state (LmSSL *ssl, const char *func, int val)
       
    64 {
       
    65 	unsigned long errid;
       
    66 	const char *errmsg;
       
    67 
       
    68 	switch (SSL_get_error(ssl->ssl, val)) {
       
    69 		case SSL_ERROR_NONE:
       
    70 			g_warning ("%s(): %i / SSL_ERROR_NONE",
       
    71 				   func, val);
       
    72 			break;
       
    73 		case SSL_ERROR_ZERO_RETURN:
       
    74 			g_warning ("%s(): %i / SSL_ERROR_ZERO_RETURN",
       
    75 				   func, val);
       
    76 			break;
       
    77 		case SSL_ERROR_WANT_READ:
       
    78 			g_warning ("%s(): %i / SSL_ERROR_WANT_READ",
       
    79 				   func, val);
       
    80 			break;
       
    81 		case SSL_ERROR_WANT_WRITE:
       
    82 			g_warning ("%s(): %i / SSL_ERROR_WANT_WRITE",
       
    83 				   func, val);
       
    84 			break;
       
    85 		case SSL_ERROR_WANT_X509_LOOKUP:
       
    86 			g_warning ("%s(): %i / SSL_ERROR_WANT_X509_LOOKUP",
       
    87 				   func, val);
       
    88 			break;
       
    89 		case SSL_ERROR_SYSCALL:
       
    90 			g_warning ("%s(): %i / SSL_ERROR_SYSCALL",
       
    91 				   func, val);
       
    92 			break;
       
    93 		case SSL_ERROR_SSL:
       
    94 			g_warning ("%s(): %i / SSL_ERROR_SSL",
       
    95 				   func, val);
       
    96 			break;
       
    97 	}
       
    98 	do {
       
    99 		errid = ERR_get_error();
       
   100 		if (errid) {
       
   101 			errmsg = ERR_error_string(errid, NULL);
       
   102 			g_warning ("\t%s", errmsg);
       
   103 		}
       
   104 	} while (errid != 0);
       
   105 }
       
   106 
       
   107 /*static const char *
       
   108 ssl_get_x509_err (long verify_res)
       
   109 {
       
   110 	sprintf(_ssl_error_code, "%ld", verify_res);
       
   111 	return _ssl_error_code;
       
   112 }*/
       
   113 
       
   114 	
       
   115 int
       
   116 ssl_verify_cb (int preverify_ok, X509_STORE_CTX *x509_ctx)
       
   117 {
       
   118 	/* As this callback doesn't get auxiliary pointer parameter we
       
   119 	 * cannot really use this. However, we can retrieve results later. */
       
   120     UNUSED_FORMAL_PARAM(preverify_ok);
       
   121     UNUSED_FORMAL_PARAM(x509_ctx);
       
   122 	return 1;
       
   123 }
       
   124 
       
   125 static gboolean
       
   126 ssl_verify_certificate (LmSSL *ssl, const gchar *server)
       
   127 {
       
   128 	gboolean retval = TRUE;
       
   129 	LmSSLBase *base;
       
   130 	long verify_res;
       
   131 	unsigned int digest_len;
       
   132 	X509 *srv_crt;
       
   133 	gchar *cn;
       
   134 	X509_NAME *crt_subj;
       
   135 
       
   136   return TRUE ; // hack - to bypass certificate verification error- Pankaj
       
   137 /*
       
   138 	base = LM_SSL_BASE(ssl);
       
   139 
       
   140 	//g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
       
   141 	//       "%s: Cipher: %s/%s/%i\n",
       
   142 	//       __FILE__,
       
   143 	//       SSL_get_cipher_version(ssl->ssl),
       
   144 	//       SSL_get_cipher_name(ssl->ssl),
       
   145 	//       SSL_get_cipher_bits(ssl->ssl, NULL));
       
   146 	
       
   147 	lm_verbose("\n[ssl_verify_certificate]:Cipher: %s/%s/%i\n",
       
   148 	       SSL_get_cipher_version(ssl->ssl),
       
   149 	       SSL_get_cipher_name(ssl->ssl),
       
   150 	       SSL_get_cipher_bits(ssl->ssl, NULL));
       
   151 
       
   152 	verify_res = SSL_get_verify_result(ssl->ssl);
       
   153 	srv_crt = SSL_get_peer_certificate(ssl->ssl);
       
   154 	if (base->expected_fingerprint != NULL) {
       
   155 		X509_digest(srv_crt, EVP_md5(), (guchar *) base->fingerprint,
       
   156 			&digest_len);
       
   157 		if (memcmp(base->expected_fingerprint, base->fingerprint,
       
   158 			digest_len) != 0) {
       
   159 			if (base->func(ssl,
       
   160 				LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH,
       
   161 				base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
       
   162 				return FALSE;
       
   163 			}
       
   164 		}
       
   165 	}
       
   166     //g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
       
   167 	  //     "%s: SSL_get_verify_result() = %ld\n",
       
   168 	  //     __FILE__,
       
   169 	  //     verify_res);
       
   170 	lm_verbose("[ssl_verify_certificate]: SSL_get_verify_result() = %ld\n", verify_res);
       
   171 	switch (verify_res) {
       
   172 		case X509_V_OK:
       
   173 			break;
       
   174 		case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
       
   175 			// special case for self signed certificates? 
       
   176 		case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
       
   177 		case X509_V_ERR_UNABLE_TO_GET_CRL:
       
   178 		case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
       
   179 			if (base->func(ssl,
       
   180 				LM_SSL_STATUS_NO_CERT_FOUND,
       
   181 				base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
       
   182 				retval = FALSE;
       
   183 			}
       
   184 			break;
       
   185 		case X509_V_ERR_INVALID_CA:
       
   186 		case X509_V_ERR_CERT_UNTRUSTED:
       
   187 		case X509_V_ERR_CERT_REVOKED:
       
   188 			if (base->func(ssl,
       
   189 				LM_SSL_STATUS_UNTRUSTED_CERT,
       
   190 				base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
       
   191 				retval = FALSE;
       
   192 			}
       
   193 			break;
       
   194 		case X509_V_ERR_CERT_NOT_YET_VALID:
       
   195 		case X509_V_ERR_CRL_NOT_YET_VALID:
       
   196 			if (base->func(ssl,
       
   197 				LM_SSL_STATUS_CERT_NOT_ACTIVATED,
       
   198 				base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
       
   199 				retval = FALSE;
       
   200 			}
       
   201 			break;
       
   202 		case X509_V_ERR_CERT_HAS_EXPIRED:
       
   203 		case X509_V_ERR_CRL_HAS_EXPIRED:
       
   204 			if (base->func(ssl,
       
   205 				LM_SSL_STATUS_CERT_EXPIRED,
       
   206 				base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
       
   207 				retval = FALSE;
       
   208 			}
       
   209 			break;
       
   210 		default:
       
   211 			if (base->func(ssl, LM_SSL_STATUS_GENERIC_ERROR,
       
   212 				base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
       
   213 				retval = FALSE;
       
   214 			}
       
   215 	}
       
   216 	//if (retval == FALSE) {
       
   217 	//	g_set_error (error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
       
   218 	//		ssl_get_x509_err(verify_res), NULL);
       
   219 	//}
       
   220 	crt_subj = X509_get_subject_name(srv_crt);
       
   221 	cn = (gchar *) g_malloc0(LM_SSL_CN_MAX + 1);
       
   222 	
       
   223 	if (X509_NAME_get_text_by_NID(crt_subj, NID_commonName, cn, LM_SSL_CN_MAX) > 0) {
       
   224 		gchar *domain = cn;
       
   225 
       
   226 		//g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
       
   227 		//      "%s: server = '%s', cn = '%s'\n",
       
   228 		//      __FILE__, server, cn);
       
   229 		lm_verbose("%s: server = '%s', cn = '%s'\n",
       
   230 		      __FILE__, server, cn);
       
   231 		
       
   232 		if ((cn[0] == '*') && (cn[1] == '.')) {
       
   233 			domain = strstr (cn, server);
       
   234 		}
       
   235 
       
   236 		if ((domain == NULL) || (strncmp (server, domain, LM_SSL_CN_MAX) != 0)) {
       
   237 			if (base->func (ssl,
       
   238 					LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
       
   239 					base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
       
   240 				retval = FALSE;
       
   241 			}
       
   242     	}
       
   243 	} else {
       
   244 		g_warning ("X509_NAME_get_text_by_NID() failed");
       
   245 	}
       
   246 
       
   247 	//g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, 
       
   248 	//       "%s:\n\tIssuer: %s\n\tSubject: %s\n\tFor: %s\n",
       
   249 	//       __FILE__,
       
   250 	//       X509_NAME_oneline(X509_get_issuer_name(srv_crt), NULL, 0),
       
   251 	//       X509_NAME_oneline(X509_get_subject_name(srv_crt), NULL, 0),
       
   252 	//       cn);
       
   253 	       
       
   254 	lm_verbose("%s:\n\tIssuer: %s\n\tSubject: %s\n\tFor: %s\n",
       
   255 	       __FILE__,
       
   256 	       X509_NAME_oneline(X509_get_issuer_name(srv_crt), NULL, 0),
       
   257 	       X509_NAME_oneline(X509_get_subject_name(srv_crt), NULL, 0),
       
   258 	       cn);
       
   259 
       
   260 	g_free(cn);
       
   261 	
       
   262 	//return TRUE ; // hack - to bypass certificate verification error- Pankaj
       
   263 	return retval;
       
   264 	*/
       
   265 }
       
   266 
       
   267 static GIOStatus
       
   268 ssl_io_status_from_return (LmSSL *ssl, gint ret)
       
   269 {
       
   270 	gint      error;
       
   271 	GIOStatus status;
       
   272 
       
   273 	if (ret > 0) return G_IO_STATUS_NORMAL;
       
   274 
       
   275 	error = SSL_get_error(ssl->ssl, ret);
       
   276 	switch (error) {
       
   277 		case SSL_ERROR_WANT_READ:
       
   278 		case SSL_ERROR_WANT_WRITE:
       
   279 			status = G_IO_STATUS_AGAIN;
       
   280 			break;
       
   281 		case SSL_ERROR_ZERO_RETURN:
       
   282 			status = G_IO_STATUS_EOF;
       
   283 			break;
       
   284 		default:
       
   285 			status = G_IO_STATUS_ERROR;
       
   286 	}
       
   287 
       
   288 	return status;
       
   289 }
       
   290 
       
   291 /* From lm-ssl-protected.h */
       
   292 
       
   293 LmSSL *
       
   294 _lm_ssl_new (const gchar    *expected_fingerprint,
       
   295 	    LmSSLFunction   ssl_function,
       
   296 	    gpointer        user_data,
       
   297 	    GDestroyNotify  notify)
       
   298 {
       
   299 	LmSSL *ssl;
       
   300 
       
   301 	ssl = g_new0 (LmSSL, 1);
       
   302 
       
   303 	_lm_ssl_base_init ((LmSSLBase *) ssl,
       
   304 			   expected_fingerprint,
       
   305 			   ssl_function, user_data, notify);
       
   306 
       
   307 	return ssl;
       
   308 }
       
   309 
       
   310 void
       
   311 _lm_ssl_initialize (LmSSL *ssl) 
       
   312 {
       
   313 #ifndef EMULATOR
       
   314 	static gboolean initialized = FALSE;
       
   315 #endif
       
   316 	/*const char *cert_file = NULL;*/
       
   317 
       
   318 	if (!initialized) {
       
   319 		SSL_library_init();
       
   320 		/* FIXME: Is this needed when we are not in debug? */
       
   321 		SSL_load_error_strings();
       
   322 		initialized = TRUE;
       
   323 	}
       
   324 
       
   325 	ssl->ssl_method = TLSv1_client_method();
       
   326 	if (ssl->ssl_method == NULL) {
       
   327 		g_warning ("TLSv1_client_method() == NULL");
       
   328 		abort();
       
   329 	}
       
   330 	ssl->ssl_ctx = SSL_CTX_new(ssl->ssl_method);
       
   331 	if (ssl->ssl_ctx == NULL) {
       
   332 		g_warning ("SSL_CTX_new() == NULL");
       
   333 		abort();
       
   334 	}
       
   335 	/*if (access("/etc/ssl/cert.pem", R_OK) == 0)
       
   336 		cert_file = "/etc/ssl/cert.pem";
       
   337 	if (!SSL_CTX_load_verify_locations(ssl->ssl_ctx,
       
   338 		cert_file, "/etc/ssl/certs")) {
       
   339 		g_warning("SSL_CTX_load_verify_locations() failed");
       
   340 	}*/
       
   341 	SSL_CTX_set_default_verify_paths (ssl->ssl_ctx);
       
   342 	SSL_CTX_set_verify (ssl->ssl_ctx, SSL_VERIFY_PEER, ssl_verify_cb);
       
   343 }
       
   344 
       
   345 gboolean
       
   346 _lm_ssl_begin (LmSSL *ssl, gint fd, const gchar *server, GError **error)
       
   347 {
       
   348 	gint ssl_ret;
       
   349 	GIOStatus status;
       
   350 
       
   351 	if (!ssl->ssl_ctx) {
       
   352 		g_set_error (error,
       
   353 			     LM_ERROR, LM_ERROR_CONNECTION_OPEN,
       
   354 			     "No SSL Context for OpenSSL");
       
   355 		return FALSE;
       
   356 	}
       
   357 
       
   358 	ssl->ssl = SSL_new(ssl->ssl_ctx);
       
   359 	if (ssl->ssl == NULL) {
       
   360 		g_warning ("SSL_new() == NULL");
       
   361 		g_set_error(error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
       
   362 			    "SSL_new()");
       
   363 		return FALSE;
       
   364 	}
       
   365 
       
   366 	if (!SSL_set_fd (ssl->ssl, fd)) {
       
   367 		g_warning ("SSL_set_fd() failed");
       
   368 		g_set_error(error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
       
   369 			"SSL_set_fd()");
       
   370 		return FALSE;
       
   371 	}
       
   372 	/*ssl->bio = BIO_new_socket (fd, BIO_NOCLOSE);
       
   373 	if (ssl->bio == NULL) {
       
   374 		g_warning("BIO_new_socket() failed");
       
   375 		g_set_error(error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
       
   376 			"BIO_new_socket()");
       
   377 		return FALSE;
       
   378 	}
       
   379 	SSL_set_bio(ssl->ssl, ssl->bio, ssl->bio);*/
       
   380 
       
   381 	do {
       
   382 		ssl_ret = SSL_connect(ssl->ssl);
       
   383 		if (ssl_ret <= 0) {
       
   384 			status = ssl_io_status_from_return(ssl, ssl_ret);
       
   385 			if (status != G_IO_STATUS_AGAIN) {
       
   386 				lm_verbose("[_lm_ssl_begin] errno for ssl connect:[%d], ssl_ret[%d]\n", errno, ssl_ret);
       
   387 				lm_verbose("\n[_lm_ssl_begin] ssl_io_status_from_return return status failed..:[%d]\n", status);
       
   388 				ssl_print_state(ssl, "SSL_connect",
       
   389 					ssl_ret);
       
   390 				g_set_error(error, LM_ERROR,
       
   391 					LM_ERROR_CONNECTION_OPEN,
       
   392 					"SSL_connect()");
       
   393 				return FALSE;
       
   394 			}
       
   395 		}
       
   396 	} while (ssl_ret <= 0);
       
   397 
       
   398 	lm_verbose("\n[_lm_ssl_begin] errno for ssl connect:[%d], ssl_ret[%d]\n", errno, ssl_ret);
       
   399 	// log
       
   400 	{
       
   401 	long verify_res;	
       
   402 	verify_res = SSL_get_verify_result(ssl->ssl);
       
   403 	lm_verbose("[_lm_ssl_begin]: After SSL Connect : SSL_get_verify_result() = %ld\n", verify_res);
       
   404 	}
       
   405 
       
   406 	if (!ssl_verify_certificate (ssl, server)) {
       
   407 		g_set_error (error, LM_ERROR, LM_ERROR_CONNECTION_OPEN,
       
   408 			"*** SSL certificate verification failed");
       
   409 		return FALSE;
       
   410 	}
       
   411 	
       
   412 	return TRUE; 
       
   413 }
       
   414 
       
   415 GIOStatus
       
   416 _lm_ssl_read (LmSSL *ssl, gchar *buf, gint len, gsize *bytes_read)
       
   417 {
       
   418 	GIOStatus status;
       
   419 	gint ssl_ret;
       
   420 
       
   421 	*bytes_read = 0;
       
   422 	ssl_ret = SSL_read(ssl->ssl, buf, len);
       
   423 	status = ssl_io_status_from_return(ssl, ssl_ret);
       
   424 	if (status == G_IO_STATUS_NORMAL) {
       
   425 		*bytes_read = ssl_ret;
       
   426 	}
       
   427 	
       
   428 	return status;
       
   429 }
       
   430 
       
   431 gint
       
   432 _lm_ssl_send (LmSSL *ssl, const gchar *str, gint len)
       
   433 {
       
   434 	GIOStatus status;
       
   435 	gint ssl_ret;
       
   436 
       
   437 	do {
       
   438 		ssl_ret = SSL_write(ssl->ssl, str, len);
       
   439 		if (ssl_ret <= 0) {
       
   440 			status = ssl_io_status_from_return(ssl, ssl_ret);
       
   441 			if (status != G_IO_STATUS_AGAIN)
       
   442 				return -1;
       
   443 		}
       
   444 	} while (ssl_ret <= 0);
       
   445 
       
   446 	return ssl_ret;
       
   447 }
       
   448 
       
   449 void 
       
   450 _lm_ssl_close (LmSSL *ssl)
       
   451 {
       
   452 	if (ssl->ssl != NULL) {
       
   453 		SSL_shutdown(ssl->ssl);
       
   454 		SSL_free(ssl->ssl);
       
   455 		ssl->ssl = NULL;
       
   456 	}
       
   457 }
       
   458 
       
   459 void
       
   460 _lm_ssl_free (LmSSL *ssl)
       
   461 {
       
   462 	SSL_CTX_free(ssl->ssl_ctx);
       
   463 	ssl->ssl_ctx = NULL;
       
   464 
       
   465 	_lm_ssl_base_free_fields (LM_SSL_BASE(ssl));
       
   466 	g_free (ssl);
       
   467 }
       
   468 
       
   469 #endif /* HAVE_GNUTLS */