aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/tls/TLSSession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/tls/TLSSession.cpp')
-rw-r--r--src/net/tls/TLSSession.cpp342
1 files changed, 342 insertions, 0 deletions
diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp
new file mode 100644
index 00000000..fb84714c
--- /dev/null
+++ b/src/net/tls/TLSSession.cpp
@@ -0,0 +1,342 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2005 Vincent Richard <[email protected]>
+//
+// 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.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include <gnutls/gnutls.h>
+#include <gnutls/extra.h>
+
+#include "vmime/net/tls/TLSSession.hpp"
+
+#include "vmime/exception.hpp"
+
+
+// Enable GnuTLS debugging by defining GNUTLS_DEBUG
+//#define GNUTLS_DEBUG 1
+
+
+#if VMIME_DEBUG && GNUTLS_DEBUG
+ #include <iostream>
+#endif // VMIME_DEBUG && GNUTLS_DEBUG
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+// Initialize GNU TLS library
+struct TLSGlobal
+{
+ TLSGlobal()
+ {
+ gnutls_global_init();
+ //gnutls_global_init_extra();
+
+#if VMIME_DEBUG && GNUTLS_DEBUG
+ gnutls_global_set_log_function(TLSLogFunc);
+ gnutls_global_set_log_level(10);
+#endif // VMIME_DEBUG && GNUTLS_DEBUG
+
+ gnutls_anon_allocate_client_credentials(&anonCred);
+ gnutls_certificate_allocate_credentials(&certCred);
+ }
+
+ ~TLSGlobal()
+ {
+ gnutls_anon_free_client_credentials(anonCred);
+ gnutls_certificate_free_credentials(certCred);
+
+ gnutls_global_deinit();
+ }
+
+#if VMIME_DEBUG && GNUTLS_DEBUG
+
+ static void TLSLogFunc(int level, const char *str)
+ {
+ std::cerr << "GNUTLS: [" << level << "] " << str << std::endl;
+ }
+
+#endif // VMIME_DEBUG && GNUTLS_DEBUG
+
+
+ gnutls_anon_client_credentials anonCred;
+ gnutls_certificate_credentials certCred;
+};
+
+static TLSGlobal g_gnutlsGlobal;
+
+
+#endif // VMIME_BUILDING_DOC
+
+
+
+TLSSession::TLSSession(ref <certificateVerifier> cv)
+ : m_certVerifier(cv)
+{
+ int res;
+
+ m_gnutlsSession = new gnutls_session;
+
+ if (gnutls_init(m_gnutlsSession, GNUTLS_CLIENT) != 0)
+ throw std::bad_alloc();
+
+ // Sets some default priority on the ciphers, key exchange methods,
+ // macs and compression methods.
+ gnutls_set_default_priority(*m_gnutlsSession);
+
+ // Sets the priority on the certificate types supported by gnutls.
+ // Priority is higher for types specified before others. After
+ // specifying the types you want, you must append a 0.
+ const int certTypePriority[] = { GNUTLS_CRT_X509, 0 };
+
+ res = gnutls_certificate_type_set_priority
+ (*m_gnutlsSession, certTypePriority);
+
+ if (res < 0)
+ {
+ throwTLSException
+ ("gnutls_certificate_type_set_priority", res);
+ }
+
+ // Sets the priority on the protocol types
+ const int protoPriority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
+
+ res = gnutls_protocol_set_priority(*m_gnutlsSession, protoPriority);
+
+ if (res < 0)
+ {
+ throwTLSException
+ ("gnutls_certificate_type_set_priority", res);
+ }
+
+ // Priority on the ciphers
+ const int cipherPriority[] =
+ {
+ GNUTLS_CIPHER_ARCFOUR_128,
+ GNUTLS_CIPHER_3DES_CBC,
+ GNUTLS_CIPHER_AES_128_CBC,
+ GNUTLS_CIPHER_AES_256_CBC,
+ GNUTLS_CIPHER_ARCFOUR_40,
+ GNUTLS_CIPHER_RC2_40_CBC,
+ GNUTLS_CIPHER_DES_CBC,
+ 0
+ };
+
+ gnutls_cipher_set_priority(*m_gnutlsSession, cipherPriority);
+
+ // Priority on MACs
+ const int macPriority[] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0};
+
+ gnutls_mac_set_priority(*m_gnutlsSession, macPriority);
+
+ // Priority on key exchange methods
+ const int kxPriority[] =
+ {
+ GNUTLS_KX_RSA,
+ GNUTLS_KX_DHE_DSS,
+ GNUTLS_KX_DHE_RSA,
+ GNUTLS_KX_ANON_DH,
+ GNUTLS_KX_SRP,
+ GNUTLS_KX_RSA_EXPORT,
+ GNUTLS_KX_SRP_RSA,
+ GNUTLS_KX_SRP_DSS,
+ 0
+ };
+
+ gnutls_kx_set_priority(*m_gnutlsSession, kxPriority);
+
+ // Priority on compression methods
+ const int compressionPriority[] =
+ {
+ GNUTLS_COMP_ZLIB,
+ //GNUTLS_COMP_LZO,
+ GNUTLS_COMP_NULL,
+ 0
+ };
+
+ gnutls_compression_set_priority(*m_gnutlsSession, compressionPriority);
+
+ // Initialize credentials
+ gnutls_credentials_set(*m_gnutlsSession,
+ GNUTLS_CRD_ANON, &g_gnutlsGlobal.anonCred);
+
+ gnutls_credentials_set(*m_gnutlsSession,
+ GNUTLS_CRD_CERTIFICATE, &g_gnutlsGlobal.certCred);
+}
+
+
+TLSSession::TLSSession(const TLSSession&)
+ : object()
+{
+ // Not used
+}
+
+
+TLSSession::~TLSSession()
+{
+ if (m_gnutlsSession)
+ {
+ gnutls_deinit(*m_gnutlsSession);
+
+ delete m_gnutlsSession;
+ m_gnutlsSession = NULL;
+ }
+}
+
+
+ref <TLSSocket> TLSSession::getSocket(ref <socket> sok)
+{
+ return vmime::create <TLSSocket>
+ (thisRef().dynamicCast <TLSSession>(), sok);
+}
+
+
+ref <tls::certificateVerifier> TLSSession::getCertificateVerifier()
+{
+ return m_certVerifier;
+}
+
+
+void TLSSession::throwTLSException(const string& fname, const int code)
+{
+ string msg = fname + "() returned ";
+
+#define ERROR(x) \
+ case x: msg += #x; break;
+
+ switch (code)
+ {
+ ERROR(GNUTLS_E_SUCCESS)
+ ERROR(GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM)
+ ERROR(GNUTLS_E_UNKNOWN_CIPHER_TYPE)
+ ERROR(GNUTLS_E_LARGE_PACKET)
+ ERROR(GNUTLS_E_UNSUPPORTED_VERSION_PACKET)
+ ERROR(GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
+ ERROR(GNUTLS_E_INVALID_SESSION)
+ ERROR(GNUTLS_E_FATAL_ALERT_RECEIVED)
+ ERROR(GNUTLS_E_UNEXPECTED_PACKET)
+ ERROR(GNUTLS_E_WARNING_ALERT_RECEIVED)
+ ERROR(GNUTLS_E_ERROR_IN_FINISHED_PACKET)
+ ERROR(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET)
+ ERROR(GNUTLS_E_UNKNOWN_CIPHER_SUITE)
+ ERROR(GNUTLS_E_UNWANTED_ALGORITHM)
+ ERROR(GNUTLS_E_MPI_SCAN_FAILED)
+ ERROR(GNUTLS_E_DECRYPTION_FAILED)
+ ERROR(GNUTLS_E_MEMORY_ERROR)
+ ERROR(GNUTLS_E_DECOMPRESSION_FAILED)
+ ERROR(GNUTLS_E_COMPRESSION_FAILED)
+ ERROR(GNUTLS_E_AGAIN)
+ ERROR(GNUTLS_E_EXPIRED)
+ ERROR(GNUTLS_E_DB_ERROR)
+ ERROR(GNUTLS_E_SRP_PWD_ERROR)
+ ERROR(GNUTLS_E_INSUFFICIENT_CREDENTIALS)
+ ERROR(GNUTLS_E_HASH_FAILED)
+ ERROR(GNUTLS_E_BASE64_DECODING_ERROR)
+ ERROR(GNUTLS_E_MPI_PRINT_FAILED)
+ ERROR(GNUTLS_E_REHANDSHAKE)
+ ERROR(GNUTLS_E_GOT_APPLICATION_DATA)
+ ERROR(GNUTLS_E_RECORD_LIMIT_REACHED)
+ ERROR(GNUTLS_E_ENCRYPTION_FAILED)
+ ERROR(GNUTLS_E_PK_ENCRYPTION_FAILED)
+ ERROR(GNUTLS_E_PK_DECRYPTION_FAILED)
+ ERROR(GNUTLS_E_PK_SIGN_FAILED)
+ ERROR(GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION)
+ ERROR(GNUTLS_E_KEY_USAGE_VIOLATION)
+ ERROR(GNUTLS_E_NO_CERTIFICATE_FOUND)
+ ERROR(GNUTLS_E_INVALID_REQUEST)
+ ERROR(GNUTLS_E_SHORT_MEMORY_BUFFER)
+ ERROR(GNUTLS_E_INTERRUPTED)
+ ERROR(GNUTLS_E_PUSH_ERROR)
+ ERROR(GNUTLS_E_PULL_ERROR)
+ ERROR(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER)
+ ERROR(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ ERROR(GNUTLS_E_PKCS1_WRONG_PAD)
+ ERROR(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION)
+ ERROR(GNUTLS_E_INTERNAL_ERROR)
+ ERROR(GNUTLS_E_DH_PRIME_UNACCEPTABLE)
+ ERROR(GNUTLS_E_FILE_ERROR)
+ ERROR(GNUTLS_E_TOO_MANY_EMPTY_PACKETS)
+ ERROR(GNUTLS_E_UNKNOWN_PK_ALGORITHM)
+ ERROR(GNUTLS_E_INIT_LIBEXTRA)
+ ERROR(GNUTLS_E_LIBRARY_VERSION_MISMATCH)
+ ERROR(GNUTLS_E_NO_TEMPORARY_RSA_PARAMS)
+ ERROR(GNUTLS_E_LZO_INIT_FAILED)
+ ERROR(GNUTLS_E_NO_COMPRESSION_ALGORITHMS)
+ ERROR(GNUTLS_E_NO_CIPHER_SUITES)
+ ERROR(GNUTLS_E_OPENPGP_GETKEY_FAILED)
+ ERROR(GNUTLS_E_PK_SIG_VERIFY_FAILED)
+ ERROR(GNUTLS_E_ILLEGAL_SRP_USERNAME)
+ ERROR(GNUTLS_E_SRP_PWD_PARSING_ERROR)
+ ERROR(GNUTLS_E_NO_TEMPORARY_DH_PARAMS)
+ ERROR(GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
+ ERROR(GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND)
+ ERROR(GNUTLS_E_ASN1_DER_ERROR)
+ ERROR(GNUTLS_E_ASN1_VALUE_NOT_FOUND)
+ ERROR(GNUTLS_E_ASN1_GENERIC_ERROR)
+ ERROR(GNUTLS_E_ASN1_VALUE_NOT_VALID)
+ ERROR(GNUTLS_E_ASN1_TAG_ERROR)
+ ERROR(GNUTLS_E_ASN1_TAG_IMPLICIT)
+ ERROR(GNUTLS_E_ASN1_TYPE_ANY_ERROR)
+ ERROR(GNUTLS_E_ASN1_SYNTAX_ERROR)
+ ERROR(GNUTLS_E_ASN1_DER_OVERFLOW)
+ ERROR(GNUTLS_E_OPENPGP_TRUSTDB_VERSION_UNSUPPORTED)
+ ERROR(GNUTLS_E_OPENPGP_UID_REVOKED)
+ ERROR(GNUTLS_E_CERTIFICATE_ERROR)
+ //ERROR(GNUTLS_E_X509_CERTIFICATE_ERROR)
+ ERROR(GNUTLS_E_CERTIFICATE_KEY_MISMATCH)
+ ERROR(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE)
+ ERROR(GNUTLS_E_X509_UNKNOWN_SAN)
+ ERROR(GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED)
+ ERROR(GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE)
+ ERROR(GNUTLS_E_UNKNOWN_HASH_ALGORITHM)
+ ERROR(GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE)
+ ERROR(GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE)
+ ERROR(GNUTLS_E_INVALID_PASSWORD)
+ ERROR(GNUTLS_E_MAC_VERIFY_FAILED)
+ ERROR(GNUTLS_E_CONSTRAINT_ERROR)
+ ERROR(GNUTLS_E_BASE64_ENCODING_ERROR)
+ ERROR(GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY)
+ //ERROR(GNUTLS_E_INCOMPATIBLE_CRYPTO_LIBRARY)
+ ERROR(GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY)
+ ERROR(GNUTLS_E_OPENPGP_KEYRING_ERROR)
+ ERROR(GNUTLS_E_X509_UNSUPPORTED_OID)
+ //ERROR(GNUTLS_E_RANDOM_FAILED)
+ ERROR(GNUTLS_E_UNIMPLEMENTED_FEATURE)
+
+ default:
+
+ msg += "unknown error";
+ break;
+ }
+
+#undef ERROR
+
+ throw exceptions::tls_exception(msg);
+}
+
+
+} // tls
+} // net
+} // vmime
+