/* Copyright (C) 2001 Marco d'Itri <md@linux.it>
* Copyright (C) 2001-2004 Andrew McDonald <andrew@mcdonald.org.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#ifdef HAVE_GNUTLS_OPENSSL_H
#include <gnutls/openssl.h>
#endif
#include "mutt.h"
#include "mutt_socket.h"
#include "mutt_curses.h"
#include "mutt_menu.h"
#include "mutt_ssl.h"
#include "mutt_regex.h"
/* certificate error bitmap values */
#define CERTERR_VALID 0
#define CERTERR_EXPIRED 1
#define CERTERR_NOTYETVALID 2
#define CERTERR_REVOKED 4
#define CERTERR_NOTTRUSTED 8
#define CERTERR_HOSTNAME 16
#define CERTERR_SIGNERNOTCA 32
#define CERTERR_INSECUREALG 64
/* deprecated types compatibility */
#ifndef HAVE_GNUTLS_CERTIFICATE_CREDENTIALS_T
typedef gnutls_certificate_credentials gnutls_certificate_credentials_t;
#endif
#ifndef HAVE_GNUTLS_CERTIFICATE_STATUS_T
typedef gnutls_certificate_status gnutls_certificate_status_t;
#endif
#ifndef HAVE_GNUTLS_DATUM_T
typedef gnutls_datum gnutls_datum_t;
#endif
#ifndef HAVE_GNUTLS_DIGEST_ALGORITHM_T
typedef gnutls_digest_algorithm gnutls_digest_algorithm_t;
#endif
#ifndef HAVE_GNUTLS_SESSION_T
typedef gnutls_session gnutls_session_t;
#endif
#ifndef HAVE_GNUTLS_TRANSPORT_PTR_T
typedef gnutls_transport_ptr gnutls_transport_ptr_t;
#endif
#ifndef HAVE_GNUTLS_X509_CRT_T
typedef gnutls_x509_crt gnutls_x509_crt_t;
#endif
typedef struct _tlssockdata
{
gnutls_session_t state;
gnutls_certificate_credentials_t xcred;
}
tlssockdata;
/* local prototypes */
static int tls_socket_read (CONNECTION* conn, char* buf, size_t len);
static int tls_socket_write (CONNECTION* conn, const char* buf, size_t len);
static int tls_socket_open (CONNECTION* conn);
static int tls_socket_close (CONNECTION* conn);
static int tls_starttls_close (CONNECTION* conn);
static int tls_init (void);
static int tls_negotiate (CONNECTION* conn);
static int tls_check_certificate (CONNECTION* conn);
static int tls_init (void)
{
static unsigned char init_complete = 0;
int err;
if (init_complete)
return 0;
err = gnutls_global_init();
if (err < 0)
{
mutt_error ("gnutls_global_init: %s", gnutls_strerror(err));
mutt_sleep (2);
return -1;
}
init_complete = 1;
return 0;
}
int mutt_ssl_socket_setup (CONNECTION* conn)
{
if (tls_init() < 0)
return -1;
conn->conn_open = tls_socket_open;
conn->conn_read = tls_socket_read;
conn->conn_write = tls_socket_write;
conn->conn_close = tls_socket_close;
conn->conn_poll = raw_socket_poll;
return 0;
}
static int tls_socket_read (CONNECTION* conn, char* buf, size_t len)
{
tlssockdata *data = conn->sockdata;
int ret;
if (!data)
{
mutt_error (_("Error: no TLS socket open"));
mutt_sleep (2);
return -1;
}
do {
ret = gnutls_record_recv (data->state, buf, len);
if (ret < 0 && gnutls_error_is