diff -r d0f3a028347a -r 59927b2d3b75 loudmouth/src/lm-ssl-gnutls.c --- a/loudmouth/src/lm-ssl-gnutls.c Tue Feb 02 01:10:06 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,312 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2003-2006 Imendio AB - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include - -#include -#include - -#include "lm-debug.h" -#include "lm-error.h" -#include "lm-ssl-base.h" -#include "lm-ssl-internals.h" - -#ifdef HAVE_GNUTLS - -#include - -#define CA_PEM_FILE "/etc/ssl/certs/ca-certificates.crt" - -struct _LmSSL { - LmSSLBase base; - - gnutls_session gnutls_session; - gnutls_certificate_credentials gnutls_xcred; - gboolean started; -}; - -static gboolean ssl_verify_certificate (LmSSL *ssl, - const gchar *server); - -static gboolean -ssl_verify_certificate (LmSSL *ssl, const gchar *server) -{ - LmSSLBase *base; - unsigned int status; - int rc; - - base = LM_SSL_BASE (ssl); - - /* This verification function uses the trusted CAs in the credentials - * structure. So you must have installed one or more CA certificates. - */ - rc = gnutls_certificate_verify_peers2 (ssl->gnutls_session, &status); - - if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND) { - if (base->func (ssl, - LM_SSL_STATUS_NO_CERT_FOUND, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - - if (rc != 0) { - if (base->func (ssl, - LM_SSL_STATUS_GENERIC_ERROR, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - - if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND) { - if (base->func (ssl, - LM_SSL_STATUS_NO_CERT_FOUND, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - - if (status & GNUTLS_CERT_INVALID - || status & GNUTLS_CERT_REVOKED) { - if (base->func (ssl, LM_SSL_STATUS_UNTRUSTED_CERT, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - - if (gnutls_certificate_expiration_time_peers (ssl->gnutls_session) < time (0)) { - if (base->func (ssl, LM_SSL_STATUS_CERT_EXPIRED, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - - if (gnutls_certificate_activation_time_peers (ssl->gnutls_session) > time (0)) { - if (base->func (ssl, LM_SSL_STATUS_CERT_NOT_ACTIVATED, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - - if (gnutls_certificate_type_get (ssl->gnutls_session) == GNUTLS_CRT_X509) { - const gnutls_datum* cert_list; - guint cert_list_size; - size_t digest_size; - gnutls_x509_crt cert; - - cert_list = gnutls_certificate_get_peers (ssl->gnutls_session, &cert_list_size); - if (cert_list == NULL) { - if (base->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - - gnutls_x509_crt_init (&cert); - - if (gnutls_x509_crt_import (cert, &cert_list[0], - GNUTLS_X509_FMT_DER) != 0) { - if (base->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - - if (!gnutls_x509_crt_check_hostname (cert, server)) { - if (base->func (ssl, LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - - gnutls_x509_crt_deinit (cert); - - digest_size = sizeof (base->fingerprint); - - if (gnutls_fingerprint (GNUTLS_DIG_MD5, &cert_list[0], - base->fingerprint, - &digest_size) >= 0) { - if (base->expected_fingerprint && - memcmp (base->expected_fingerprint, - base->fingerprint, - digest_size) && - base->func (ssl, - LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - else if (base->func (ssl, LM_SSL_STATUS_GENERIC_ERROR, - base->func_data) != LM_SSL_RESPONSE_CONTINUE) { - return FALSE; - } - } - - return TRUE; -} - -/* From lm-ssl-protected.h */ - -LmSSL * -_lm_ssl_new (const gchar *expected_fingerprint, - LmSSLFunction ssl_function, - gpointer user_data, - GDestroyNotify notify) -{ - LmSSL *ssl; - - ssl = g_new0 (LmSSL, 1); - - _lm_ssl_base_init ((LmSSLBase *) ssl, - expected_fingerprint, - ssl_function, user_data, notify); - - return ssl; -} - -void -_lm_ssl_initialize (LmSSL *ssl) -{ - gnutls_global_init (); - gnutls_certificate_allocate_credentials (&ssl->gnutls_xcred); - gnutls_certificate_set_x509_trust_file(ssl->gnutls_xcred, - CA_PEM_FILE, - GNUTLS_X509_FMT_PEM); -} - -gboolean -_lm_ssl_begin (LmSSL *ssl, gint fd, const gchar *server, GError **error) -{ - int ret; - gboolean auth_ok = TRUE; - const int cert_type_priority[] = - { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 }; - const int compression_priority[] = - { GNUTLS_COMP_DEFLATE, GNUTLS_COMP_NULL, 0 }; - - gnutls_init (&ssl->gnutls_session, GNUTLS_CLIENT); - gnutls_set_default_priority (ssl->gnutls_session); - gnutls_certificate_type_set_priority (ssl->gnutls_session, - cert_type_priority); - gnutls_compression_set_priority (ssl->gnutls_session, - compression_priority); - gnutls_credentials_set (ssl->gnutls_session, - GNUTLS_CRD_CERTIFICATE, - ssl->gnutls_xcred); - - gnutls_transport_set_ptr (ssl->gnutls_session, - (gnutls_transport_ptr_t) fd); - - ret = gnutls_handshake (ssl->gnutls_session); - - if (ret >= 0) { - auth_ok = ssl_verify_certificate (ssl, server); - } - - if (ret < 0 || !auth_ok) { - char *errmsg; - - gnutls_perror (ret); - - if (!auth_ok) { - errmsg = "*** GNUTLS authentication error"; - } else { - errmsg = "*** GNUTLS handshake failed"; - } - - g_set_error (error, - LM_ERROR, LM_ERROR_CONNECTION_OPEN, - errmsg); - - return FALSE; - } - lm_verbose ("GNUTLS negotiated compression: %s", - gnutls_compression_get_name (gnutls_compression_get - (ssl->gnutls_session))); - - ssl->started = TRUE; - - return TRUE; -} - -GIOStatus -_lm_ssl_read (LmSSL *ssl, gchar *buf, gint len, gsize *bytes_read) -{ - GIOStatus status; - gint b_read; - - *bytes_read = 0; - b_read = gnutls_record_recv (ssl->gnutls_session, buf, len); - - if (b_read == GNUTLS_E_AGAIN) { - status = G_IO_STATUS_AGAIN; - } - else if (b_read == 0) { - status = G_IO_STATUS_EOF; - } - else if (b_read < 0) { - status = G_IO_STATUS_ERROR; - } else { - *bytes_read = (guint) b_read; - status = G_IO_STATUS_NORMAL; - } - - return status; -} - -gint -_lm_ssl_send (LmSSL *ssl, const gchar *str, gint len) -{ - gint bytes_written; - - bytes_written = gnutls_record_send (ssl->gnutls_session, str, len); - - while (bytes_written < 0) { - if (bytes_written != GNUTLS_E_INTERRUPTED && - bytes_written != GNUTLS_E_AGAIN) { - return -1; - } - - bytes_written = gnutls_record_send (ssl->gnutls_session, - str, len); - } - - return bytes_written; -} - -void -_lm_ssl_close (LmSSL *ssl) -{ - if (!ssl->started) - return; - - gnutls_deinit (ssl->gnutls_session); - gnutls_certificate_free_credentials (ssl->gnutls_xcred); - gnutls_global_deinit (); -} - -void -_lm_ssl_free (LmSSL *ssl) -{ - _lm_ssl_base_free_fields (LM_SSL_BASE (ssl)); - g_free (ssl); -} - -#endif /* HAVE_GNUTLS */