diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-10-20 21:41:59 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-10-20 21:44:45 +0200 |
commit | e733486d19f60cb2e7b579cc9f8e7b01625c79a7 (patch) | |
tree | 69b99375d08e501187890f016043ea7a0521d358 /extra/gnutls_openssl.c | |
parent | 8aad72ed69dbf8150c253de257e3633f1b0070ed (diff) | |
download | gnutls-e733486d19f60cb2e7b579cc9f8e7b01625c79a7.tar.gz |
libgnutls-extra is no more.
Diffstat (limited to 'extra/gnutls_openssl.c')
-rw-r--r-- | extra/gnutls_openssl.c | 912 |
1 files changed, 912 insertions, 0 deletions
diff --git a/extra/gnutls_openssl.c b/extra/gnutls_openssl.c new file mode 100644 index 0000000000..14121da9a8 --- /dev/null +++ b/extra/gnutls_openssl.c @@ -0,0 +1,912 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2008, 2010 Free Software Foundation, + * Inc. + * Copyright (c) 2002 Andrew McDonald <andrew@mcdonald.org.uk> + * + * This file is part of GnuTLS-EXTRA. + * + * GnuTLS-extra 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 3 of the License, or + * (at your option) any later version. + * + * GnuTLS-extra 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, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <gnutls/gnutls.h> +#include <openssl_compat.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "../lib/gnutls_int.h" +#include "../lib/random.h" +#include "../lib/gnutls_hash_int.h" + +/* In win32 X509_NAME is defined in wincrypt.h. + * undefine it to avoid the conflict with openssl.h. + */ +#ifdef X509_NAME +# undef X509_NAME +#endif +#include <gnutls/openssl.h> + +/* Gnulib re-defines shutdown on mingw. We only use it as a variable + name, so restore the original name. */ +#undef shutdown + +/* XXX: See lib/gnutls_int.h. */ +#define GNUTLS_POINTER_TO_INT(_) ((int) GNUTLS_POINTER_TO_INT_CAST (_)) +#define GNUTLS_INT_TO_POINTER(_) ((void*) GNUTLS_POINTER_TO_INT_CAST (_)) + +/* WARNING: Error functions aren't currently thread-safe */ + +static int last_error = 0; + +/* Library initialisation functions */ + +int +SSL_library_init (void) +{ + gnutls_global_init (); + /* NB: we haven't got anywhere to call gnutls_global_deinit() */ + return 1; +} + +void +OpenSSL_add_all_algorithms (void) +{ +} + + +/* SSL_CTX structure handling */ + +SSL_CTX * +SSL_CTX_new (SSL_METHOD * method) +{ + SSL_CTX *ctx; + + ctx = (SSL_CTX *) calloc (1, sizeof (SSL_CTX)); + ctx->method = method; + + return ctx; +} + +void +SSL_CTX_free (SSL_CTX * ctx) +{ + free (ctx->method); + free (ctx); +} + +int +SSL_CTX_set_default_verify_paths (SSL_CTX * ctx) +{ + return 0; +} + +int +SSL_CTX_use_certificate_file (SSL_CTX * ctx, const char *certfile, int type) +{ + ctx->certfile = (char *) calloc (1, strlen (certfile) + 1); + if (!ctx->certfile) + return -1; + memcpy (ctx->certfile, certfile, strlen (certfile)); + + ctx->certfile_type = type; + + return 1; +} + +int +SSL_CTX_use_PrivateKey_file (SSL_CTX * ctx, const char *keyfile, int type) +{ + ctx->keyfile = (char *) calloc (1, strlen (keyfile) + 1); + if (!ctx->keyfile) + return -1; + memcpy (ctx->keyfile, keyfile, strlen (keyfile)); + + ctx->keyfile_type = type; + + return 1; + +} + +void +SSL_CTX_set_verify (SSL_CTX * ctx, int verify_mode, + int (*verify_callback) (int, X509_STORE_CTX *)) +{ + ctx->verify_mode = verify_mode; + ctx->verify_callback = verify_callback; +} + +unsigned long +SSL_CTX_set_options (SSL_CTX * ctx, unsigned long options) +{ + return (ctx->options |= options); +} + +long +SSL_CTX_set_mode (SSL_CTX * ctx, long mode) +{ + return 0; +} + +int +SSL_CTX_set_cipher_list (SSL_CTX * ctx, const char *list) +{ + /* FIXME: ignore this for the moment */ + /* We're going to have to parse the "list" string to do this */ + /* It is a string, which in its simplest form is something like + "DES-CBC3-SHA:IDEA-CBC-MD5", but can be rather more complicated + (see OpenSSL's ciphers(1) manpage for details) */ + + return 1; +} + + +/* SSL_CTX statistics */ + +long +SSL_CTX_sess_number (SSL_CTX * ctx) +{ + return 0; +} + +long +SSL_CTX_sess_connect (SSL_CTX * ctx) +{ + return 0; +} + +long +SSL_CTX_sess_connect_good (SSL_CTX * ctx) +{ + return 0; +} + +long +SSL_CTX_sess_connect_renegotiate (SSL_CTX * ctx) +{ + return 0; +} + +long +SSL_CTX_sess_accept (SSL_CTX * ctx) +{ + return 0; +} + +long +SSL_CTX_sess_accept_good (SSL_CTX * ctx) +{ + return 0; +} + +long +SSL_CTX_sess_accept_renegotiate (SSL_CTX * ctx) +{ + return 0; +} + +long +SSL_CTX_sess_hits (SSL_CTX * ctx) +{ + return 0; +} + +long +SSL_CTX_sess_misses (SSL_CTX * ctx) +{ + return 0; +} + +long +SSL_CTX_sess_timeouts (SSL_CTX * ctx) +{ + return 0; +} + + + +/* SSL structure handling */ + +SSL * +SSL_new (SSL_CTX * ctx) +{ + SSL *ssl; + int err; + + ssl = (SSL *) calloc (1, sizeof (SSL)); + if (!ssl) + return NULL; + + err = gnutls_certificate_allocate_credentials (&ssl->gnutls_cred); + if (err < 0) + { + last_error = err; + free (ssl); + return NULL; + } + + gnutls_init (&ssl->gnutls_state, ctx->method->connend); + + gnutls_priority_set_direct (ssl->gnutls_state, + ctx->method->priority_string, NULL); + + gnutls_credentials_set (ssl->gnutls_state, GNUTLS_CRD_CERTIFICATE, + ssl->gnutls_cred); + if (ctx->certfile) + gnutls_certificate_set_x509_trust_file (ssl->gnutls_cred, + ctx->certfile, + ctx->certfile_type); + if (ctx->keyfile) + gnutls_certificate_set_x509_key_file (ssl->gnutls_cred, + ctx->certfile, ctx->keyfile, + ctx->keyfile_type); + ssl->ctx = ctx; + ssl->verify_mode = ctx->verify_mode; + ssl->verify_callback = ctx->verify_callback; + + ssl->options = ctx->options; + + ssl->rfd = (gnutls_transport_ptr_t) - 1; + ssl->wfd = (gnutls_transport_ptr_t) - 1; + + return ssl; +} + +void +SSL_free (SSL * ssl) +{ + gnutls_certificate_free_credentials (ssl->gnutls_cred); + gnutls_deinit (ssl->gnutls_state); + free (ssl); +} + +void +SSL_load_error_strings (void) +{ +} + +int +SSL_get_error (SSL * ssl, int ret) +{ + if (ret > 0) + return SSL_ERROR_NONE; + + return SSL_ERROR_ZERO_RETURN; +} + +int +SSL_set_fd (SSL * ssl, int fd) +{ + gnutls_transport_set_ptr (ssl->gnutls_state, GNUTLS_INT_TO_POINTER (fd)); + return 1; +} + +int +SSL_set_rfd (SSL * ssl, int fd) +{ + ssl->rfd = GNUTLS_INT_TO_POINTER (fd); + + if (ssl->wfd != (gnutls_transport_ptr_t) - 1) + gnutls_transport_set_ptr2 (ssl->gnutls_state, ssl->rfd, ssl->wfd); + + return 1; +} + +int +SSL_set_wfd (SSL * ssl, int fd) +{ + ssl->wfd = GNUTLS_INT_TO_POINTER (fd); + + if (ssl->rfd != (gnutls_transport_ptr_t) - 1) + gnutls_transport_set_ptr2 (ssl->gnutls_state, ssl->rfd, ssl->wfd); + + return 1; +} + +void +SSL_set_bio (SSL * ssl, BIO * rbio, BIO * wbio) +{ + gnutls_transport_set_ptr2 (ssl->gnutls_state, rbio->fd, wbio->fd); + /* free(BIO); ? */ +} + +void +SSL_set_connect_state (SSL * ssl) +{ +} + +int +SSL_pending (SSL * ssl) +{ + return gnutls_record_check_pending (ssl->gnutls_state); +} + +void +SSL_set_verify (SSL * ssl, int verify_mode, + int (*verify_callback) (int, X509_STORE_CTX *)) +{ + ssl->verify_mode = verify_mode; + ssl->verify_callback = verify_callback; +} + +const X509 * +SSL_get_peer_certificate (SSL * ssl) +{ + const gnutls_datum_t *cert_list; + unsigned int cert_list_size = 0; + + cert_list = gnutls_certificate_get_peers (ssl->gnutls_state, + &cert_list_size); + + return cert_list; +} + +/* SSL connection open/close/read/write functions */ + +int +SSL_connect (SSL * ssl) +{ + X509_STORE_CTX *store; + unsigned int cert_list_size = 0; + int err; + char x_priority[256]; + /* take options into account before connecting */ + + memset (x_priority, 0, sizeof (x_priority)); + if (ssl->options & SSL_OP_NO_TLSv1) + { + snprintf(x_priority, sizeof(x_priority), "%s:-VERS-TLS1.0", ssl->ctx->method->priority_string); + err = gnutls_priority_set_direct(ssl->gnutls_state, x_priority, NULL); + if (err < 0) + { + last_error = err; + return 0; + } + } + + err = gnutls_handshake (ssl->gnutls_state); + ssl->last_error = err; + + if (err < 0) + { + last_error = err; + return 0; + } + + store = (X509_STORE_CTX *) calloc (1, sizeof (X509_STORE_CTX)); + store->ssl = ssl; + store->cert_list = gnutls_certificate_get_peers (ssl->gnutls_state, + &cert_list_size); + + if (ssl->verify_callback) + { + ssl->verify_callback (1 /*FIXME*/, store); + } + ssl->state = SSL_ST_OK; + + err = store->error; + free (store); + + /* FIXME: deal with error from callback */ + + return 1; +} + +int +SSL_accept (SSL * ssl) +{ + X509_STORE_CTX *store; + unsigned int cert_list_size = 0; + int err; + char x_priority[256]; + /* take options into account before connecting */ + + memset (x_priority, 0, sizeof (x_priority)); + if (ssl->options & SSL_OP_NO_TLSv1) + { + snprintf(x_priority, sizeof(x_priority), "%s:-VERS-TLS1.0", ssl->ctx->method->priority_string); + err = gnutls_priority_set_direct(ssl->gnutls_state, x_priority, NULL); + if (err < 0) + { + last_error = err; + return 0; + } + } + + /* FIXME: dh params, do we want client cert? */ + + err = gnutls_handshake (ssl->gnutls_state); + ssl->last_error = err; + + if (err < 0) + { + last_error = err; + return 0; + } + + store = (X509_STORE_CTX *) calloc (1, sizeof (X509_STORE_CTX)); + store->ssl = ssl; + store->cert_list = gnutls_certificate_get_peers (ssl->gnutls_state, + &cert_list_size); + + if (ssl->verify_callback) + { + ssl->verify_callback (1 /*FIXME*/, store); + } + ssl->state = SSL_ST_OK; + + err = store->error; + free (store); + + /* FIXME: deal with error from callback */ + + return 1; +} + +int +SSL_shutdown (SSL * ssl) +{ + if (!ssl->shutdown) + { + gnutls_bye (ssl->gnutls_state, GNUTLS_SHUT_WR); + ssl->shutdown++; + } + else + { + gnutls_bye (ssl->gnutls_state, GNUTLS_SHUT_RDWR); + ssl->shutdown++; + } + + /* FIXME */ + return 1; +} + +int +SSL_read (SSL * ssl, void *buf, int len) +{ + int ret; + + ret = gnutls_record_recv (ssl->gnutls_state, buf, len); + ssl->last_error = ret; + + if (ret < 0) + { + last_error = ret; + return 0; + } + + return ret; +} + +int +SSL_write (SSL * ssl, const void *buf, int len) +{ + int ret; + + ret = gnutls_record_send (ssl->gnutls_state, buf, len); + ssl->last_error = ret; + + if (ret < 0) + { + last_error = ret; + return 0; + } + + return ret; +} + +int +SSL_want (SSL * ssl) +{ + return SSL_NOTHING; +} + + +/* SSL_METHOD functions */ + +SSL_METHOD * +SSLv23_client_method (void) +{ + SSL_METHOD *m; + m = (SSL_METHOD *) calloc (1, sizeof (SSL_METHOD)); + if (!m) + return NULL; + + strcpy(m->priority_string, "NONE:+VERS-TLS1.0:+VERS-SSL3.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL"); + + m->connend = GNUTLS_CLIENT; + + return m; +} + +SSL_METHOD * +SSLv23_server_method (void) +{ + SSL_METHOD *m; + m = (SSL_METHOD *) calloc (1, sizeof (SSL_METHOD)); + if (!m) + return NULL; + + strcpy(m->priority_string, "NONE:+VERS-TLS1.0:+VERS-SSL3.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL"); + m->connend = GNUTLS_SERVER; + + return m; +} + +SSL_METHOD * +SSLv3_client_method (void) +{ + SSL_METHOD *m; + m = (SSL_METHOD *) calloc (1, sizeof (SSL_METHOD)); + if (!m) + return NULL; + + strcpy(m->priority_string, "NONE:+VERS-SSL3.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL"); + m->connend = GNUTLS_CLIENT; + + return m; +} + +SSL_METHOD * +SSLv3_server_method (void) +{ + SSL_METHOD *m; + m = (SSL_METHOD *) calloc (1, sizeof (SSL_METHOD)); + if (!m) + return NULL; + + strcpy(m->priority_string, "NONE:+VERS-SSL3.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL"); + m->connend = GNUTLS_SERVER; + + return m; +} + +SSL_METHOD * +TLSv1_client_method (void) +{ + SSL_METHOD *m; + m = (SSL_METHOD *) calloc (1, sizeof (SSL_METHOD)); + if (!m) + return NULL; + + strcpy(m->priority_string, "NONE:+VERS-TLS1.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL"); + m->connend = GNUTLS_CLIENT; + + return m; +} + +SSL_METHOD * +TLSv1_server_method (void) +{ + SSL_METHOD *m; + m = (SSL_METHOD *) calloc (1, sizeof (SSL_METHOD)); + if (!m) + return NULL; + + strcpy(m->priority_string, "NONE:+VERS-TLS1.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL"); + m->connend = GNUTLS_SERVER; + + return m; +} + + +/* SSL_CIPHER functions */ + +SSL_CIPHER * +SSL_get_current_cipher (SSL * ssl) +{ + if (!ssl) + return NULL; + + ssl->ciphersuite.version = gnutls_protocol_get_version (ssl->gnutls_state); + ssl->ciphersuite.cipher = gnutls_cipher_get (ssl->gnutls_state); + ssl->ciphersuite.kx = gnutls_kx_get (ssl->gnutls_state); + ssl->ciphersuite.mac = gnutls_mac_get (ssl->gnutls_state); + ssl->ciphersuite.compression = gnutls_compression_get (ssl->gnutls_state); + ssl->ciphersuite.cert = gnutls_certificate_type_get (ssl->gnutls_state); + + return &(ssl->ciphersuite); +} + +const char * +SSL_CIPHER_get_name (SSL_CIPHER * cipher) +{ + if (!cipher) + return ("NONE"); + + return gnutls_cipher_suite_get_name (cipher->kx, + cipher->cipher, cipher->mac); +} + +int +SSL_CIPHER_get_bits (SSL_CIPHER * cipher, int *bits) +{ + int bit_result; + + if (!cipher) + return 0; + + bit_result = (8 * gnutls_cipher_get_key_size (cipher->cipher)); + + if (bits) + *bits = bit_result; + + return bit_result; +} + +const char * +SSL_CIPHER_get_version (SSL_CIPHER * cipher) +{ + const char *ret; + + if (!cipher) + return ("(NONE)"); + + ret = gnutls_protocol_get_name (cipher->version); + if (ret) + return ret; + + return ("unknown"); +} + +char * +SSL_CIPHER_description (SSL_CIPHER * cipher, char *buf, int size) +{ + char *tmpbuf; + int tmpsize; + int local_alloc; + + if (buf) + { + tmpbuf = buf; + tmpsize = size; + local_alloc = 0; + } + else + { + tmpbuf = (char *) malloc (128); + tmpsize = 128; + local_alloc = 1; + } + + if (snprintf (tmpbuf, tmpsize, "%s %s %s %s", + gnutls_protocol_get_name (cipher->version), + gnutls_kx_get_name (cipher->kx), + gnutls_cipher_get_name (cipher->cipher), + gnutls_mac_get_name (cipher->mac)) == -1) + { + if (local_alloc) + free (tmpbuf); + return (char *) "Buffer too small"; + } + + return tmpbuf; +} + + +/* X509 functions */ + +X509_NAME * +X509_get_subject_name (const X509 * cert) +{ + gnutls_x509_dn *dn; + dn = (gnutls_x509_dn *) calloc (1, sizeof (gnutls_x509_dn)); + if (gnutls_x509_extract_certificate_dn (cert, dn) < 0) + { + free (dn); + return NULL; + } + return dn; +} + +X509_NAME * +X509_get_issuer_name (const X509 * cert) +{ + gnutls_x509_dn *dn; + dn = (gnutls_x509_dn *) calloc (1, sizeof (gnutls_x509_dn)); + if (gnutls_x509_extract_certificate_issuer_dn (cert, dn) < 0) + { + free (dn); + return NULL; + } + return dn; +} + +char * +X509_NAME_oneline (gnutls_x509_dn * name, char *buf, int len) +{ + /* XXX openssl allocates buffer if buf == NULL */ + if (!buf) + return NULL; + memset (buf, 0, len); + + snprintf (buf, len - 1, + "C=%s, ST=%s, L=%s, O=%s, OU=%s, CN=%s/Email=%s", + name->country, name->state_or_province_name, + name->locality_name, name->organization, + name->organizational_unit_name, name->common_name, name->email); + return buf; +} + +void +X509_free (const X509 * cert) +{ + /* only get certificates as const items */ +} + + +/* BIO functions */ + +void +BIO_get_fd (gnutls_session_t gnutls_state, int *fd) +{ + gnutls_transport_ptr_t tmp = gnutls_transport_get_ptr (gnutls_state); + *fd = GNUTLS_POINTER_TO_INT (tmp); +} + +BIO * +BIO_new_socket (int sock, int close_flag) +{ + BIO *bio; + + bio = (BIO *) malloc (sizeof (BIO)); + if (!bio) + return NULL; + + bio->fd = GNUTLS_INT_TO_POINTER (sock); + + return bio; +} + + +/* error handling */ + +unsigned long +ERR_get_error (void) +{ + unsigned long ret; + + ret = -1 * last_error; + last_error = 0; + + return ret; +} + +const char * +ERR_error_string (unsigned long e, char *buf) +{ + return gnutls_strerror (-1 * e); +} + + +/* RAND functions */ + +int +RAND_status (void) +{ + return 1; +} + +void +RAND_seed (const void *buf, int num) +{ +} + +int +RAND_bytes (unsigned char *buf, int num) +{ + gnutls_rnd (GNUTLS_RND_RANDOM, buf, num); + return 1; +} + +int +RAND_pseudo_bytes (unsigned char *buf, int num) +{ + gnutls_rnd (GNUTLS_RND_NONCE, buf, num); + return 1; +} + +const char * +RAND_file_name (char *buf, size_t len) +{ + return ""; +} + +int +RAND_load_file (const char *name, long maxbytes) +{ + return maxbytes; +} + +int +RAND_write_file (const char *name) +{ + return 0; +} + +int +RAND_egd_bytes (const char *path, int bytes) +{ + /* fake it */ + return bytes; +} + + +/* message digest functions */ + +void +MD5_Init (MD5_CTX * ctx) +{ + ctx->handle = gnutls_malloc (sizeof (digest_hd_st)); + if (!ctx->handle) + abort (); + _gnutls_hash_init (ctx->handle, GNUTLS_DIG_MD5); +} + +void +MD5_Update (MD5_CTX * ctx, const void *buf, int len) +{ + _gnutls_hash (ctx->handle, buf, len); +} + +void +MD5_Final (unsigned char *md, MD5_CTX * ctx) +{ + _gnutls_hash_deinit (ctx->handle, md); + gnutls_free (ctx->handle); +} + +unsigned char * +MD5 (const unsigned char *buf, unsigned long len, unsigned char *md) +{ + if (!md) + return NULL; + + _gnutls_hash_fast (GNUTLS_DIG_MD5, buf, len, md); + + return md; +} + +void +RIPEMD160_Init (RIPEMD160_CTX * ctx) +{ + ctx->handle = gnutls_malloc (sizeof (digest_hd_st)); + if (!ctx->handle) + abort (); + _gnutls_hash_init (ctx->handle, GNUTLS_DIG_RMD160); +} + +void +RIPEMD160_Update (RIPEMD160_CTX * ctx, const void *buf, int len) +{ + _gnutls_hash (ctx->handle, buf, len); +} + +void +RIPEMD160_Final (unsigned char *md, RIPEMD160_CTX * ctx) +{ + _gnutls_hash_deinit (ctx->handle, md); + gnutls_free (ctx->handle); +} + +unsigned char * +RIPEMD160 (const unsigned char *buf, unsigned long len, unsigned char *md) +{ + if (!md) + return NULL; + + _gnutls_hash_fast (GNUTLS_DIG_RMD160, buf, len, md); + + return md; +} |