aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Richard <[email protected]>2012-11-03 08:27:12 +0000
committerVincent Richard <[email protected]>2012-11-03 08:27:12 +0000
commitbc63892291ecf245dd210e236ab14f12e31baef8 (patch)
tree031bc486b0cafc527f516e6890105521bc7f2afc
parentMigrated build system to CMake. Conditional file compilation. Automatic selec... (diff)
downloadvmime-bc63892291ecf245dd210e236ab14f12e31baef8.tar.gz
vmime-bc63892291ecf245dd210e236ab14f12e31baef8.zip
OpenSSL support (thanks to Mehmet Bozkurt).
-rw-r--r--AUTHORS7
-rw-r--r--CMakeLists.txt31
-rw-r--r--SConstruct34
-rw-r--r--cmake/config.hpp.cmake4
-rw-r--r--src/net/imap/IMAPConnection.cpp4
-rw-r--r--src/net/pop3/POP3Store.cpp4
-rw-r--r--src/net/smtp/SMTPTransport.cpp4
-rw-r--r--src/net/tls/TLSSession.cpp256
-rw-r--r--src/net/tls/TLSSocket.cpp377
-rw-r--r--src/net/tls/gnutls/TLSSession_GnuTLS.cpp304
-rw-r--r--src/net/tls/gnutls/TLSSocket_GnuTLS.cpp424
-rwxr-xr-xsrc/net/tls/openssl/OpenSSLInitializer.cpp152
-rwxr-xr-xsrc/net/tls/openssl/TLSSession_OpenSSL.cpp138
-rwxr-xr-xsrc/net/tls/openssl/TLSSocket_OpenSSL.cpp416
-rwxr-xr-xsrc/platforms/posix/posixCriticalSection.cpp67
-rw-r--r--src/platforms/posix/posixHandler.cpp44
-rwxr-xr-xsrc/platforms/windows/windowsCriticalSection.cpp67
-rw-r--r--src/platforms/windows/windowsHandler.cpp23
-rw-r--r--src/security/cert/X509Certificate.cpp228
-rw-r--r--src/security/cert/gnutls/X509Certificate_GnuTLS.cpp278
-rwxr-xr-xsrc/security/cert/openssl/X509Certificate_OpenSSL.cpp467
-rwxr-xr-xsrc/utility/sync/criticalSection.cpp44
-rw-r--r--vmime/net/tls/TLSSession.hpp30
-rw-r--r--vmime/net/tls/TLSSocket.hpp59
-rw-r--r--vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp89
-rw-r--r--vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp113
-rwxr-xr-xvmime/net/tls/openssl/OpenSSLInitializer.hpp102
-rwxr-xr-xvmime/net/tls/openssl/TLSSession_OpenSSL.hpp106
-rwxr-xr-xvmime/net/tls/openssl/TLSSocket_OpenSSL.hpp116
-rw-r--r--vmime/platform.hpp19
-rwxr-xr-xvmime/platforms/posix/posixCriticalSection.hpp69
-rw-r--r--vmime/platforms/posix/posixHandler.hpp5
-rwxr-xr-xvmime/platforms/windows/windowsCriticalSection.hpp68
-rw-r--r--vmime/platforms/windows/windowsHandler.hpp5
-rw-r--r--vmime/security/cert/X509Certificate.hpp40
-rw-r--r--vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp91
-rw-r--r--vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp104
-rwxr-xr-xvmime/utility/sync/autoLock.hpp66
-rwxr-xr-xvmime/utility/sync/criticalSection.hpp65
39 files changed, 3557 insertions, 963 deletions
diff --git a/AUTHORS b/AUTHORS
index bbddb306..98406a08 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,7 +2,7 @@
VMIME AUTHOR
============
-Vincent Richard <[email protected]>
+Vincent Richard <[email protected]>
Project owner and creator. VMime was created in 1998, and publicly released
under the GNU GPL license in 2003.
@@ -28,9 +28,10 @@ AUTHORS file.
- Zarafa <http://developer.zarafa.com/VmimePatches>
- Bartek Szurgot <[email protected], http://baszerr.org>
- Achim Brandt <http://sourceforge.net/users/a-brandt/>
+ - Mehmet Bozkurt <[email protected]> (OpenSSL support)
Please apologize if I have forgotten someone here. ;) Send me an email
-to <[email protected]> if you want your name to be listed.
+to <[email protected]> if you want your name to be listed.
-See SVN Changelog for full list.
+See Changelogs for full list.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index af636051..5be9ca32 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -448,6 +448,7 @@ ENDIF()
# SSL/TLS support
INCLUDE(FindGnuTLS)
+INCLUDE(FindOpenSSL)
INCLUDE(CheckFunctionExists)
@@ -457,7 +458,7 @@ CHECK_FUNCTION_EXISTS(gnutls_priority_set_direct VMIME_HAVE_GNUTLS_PRIORITY_FUNC
OPTION(
VMIME_HAVE_TLS_SUPPORT
- "SSL/TLS support (requires GNU TLS library)"
+ "SSL/TLS support (requires either GNU TLS or OpenSSL library)"
ON
)
@@ -467,6 +468,11 @@ OPTION(
ON
)
+OPTION(
+ VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+ "Use OpenSSL library for SSL/TLS support"
+ OFF
+)
IF(VMIME_HAVE_TLS_SUPPORT)
@@ -492,6 +498,23 @@ IF(VMIME_HAVE_TLS_SUPPORT)
SET(VMIME_PKGCONFIG_CFLAGS "${VMIME_PKGCONFIG_CFLAGS} ${GNUTLS_INCLUDE_DIR}")
SET(VMIME_PKGCONFIG_REQUIRES "${VMIME_PKGCONFIG_REQUIRES} libgnutls")
+ ELSEIF(VMIME_TLS_SUPPORT_LIB_IS_OPENSSL)
+
+ INCLUDE_DIRECTORIES(
+ ${INCLUDE_DIRECTORIES}
+ ${OPENSSL_INCLUDE_DIR}
+ )
+
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ )
+
+ SET(VMIME_PKGCONFIG_LIBS "${VMIME_PKGCONFIG_LIBS} ${OPENSSL_LIBRARIES}")
+ SET(VMIME_PKGCONFIG_CFLAGS "${VMIME_PKGCONFIG_CFLAGS} ${OPENSSL_INCLUDE_DIR}")
+ SET(VMIME_PKGCONFIG_REQUIRES "${VMIME_PKGCONFIG_REQUIRES} libopenssl")
+
ELSE()
MESSAGE(FATAL_ERROR "TLS support is enabled, but no TLS/SSL library was selected/found")
@@ -535,8 +558,14 @@ ENDIF()
# POSIX-specific checks
INCLUDE(CheckFunctionExists)
+INCLUDE(CheckSymbolExists)
+
CHECK_FUNCTION_EXISTS(getaddrinfo VMIME_HAVE_GETADDRINFO)
+CHECK_FUNCTION_EXISTS(gettid VMIME_HAVE_GETTID)
+CHECK_FUNCTION_EXISTS(syscall VMIME_HAVE_SYSCALL)
+CHECK_SYMBOL_EXISTS(SYS_gettid sys/syscall.h VMIME_HAVE_SYSCALL_GETTID)
+
FIND_PACKAGE(Threads)
FIND_LIBRARY(PTHREAD pthread)
diff --git a/SConstruct b/SConstruct
index 0415ed79..31228ed4 100644
--- a/SConstruct
+++ b/SConstruct
@@ -137,6 +137,8 @@ libvmime_sources = [
'utility/stringUtils.cpp', 'utility/stringUtils.hpp',
'utility/url.cpp', 'utility/url.hpp',
'utility/urlUtils.cpp', 'utility/urlUtils.hpp',
+ 'utility/sync/autoLock.hpp',
+ 'utility/sync/criticalSection.cpp', 'utility/sync/criticalSection.hpp',
# -- encoder
'utility/encoder/encoder.cpp', 'utility/encoder/encoder.hpp',
'utility/encoder/sevenBitEncoder.cpp', 'utility/encoder/sevenBitEncoder.hpp',
@@ -210,12 +212,19 @@ libvmime_messaging_sources = [
libvmime_net_tls_sources = [
'net/tls/TLSSession.cpp', 'net/tls/TLSSession.hpp',
'net/tls/TLSSocket.cpp', 'net/tls/TLSSocket.hpp',
+ 'net/tls/gnutls/TLSSession_GnuTLS.cpp', 'net/tls/gnutls/TLSSession_GnuTLS.hpp',
+ 'net/tls/gnutls/TLSSocket_GnuTLS.cpp', 'net/tls/gnutls/TLSSocket_GnuTLS.hpp',
+ 'net/tls/openssl/TLSSession_OpenSSL.cpp', 'net/tls/openssl/TLSSession_OpenSSL.hpp',
+ 'net/tls/openssl/TLSSocket_OpenSSL.cpp', 'net/tls/openssl/TLSSocket_OpenSSL.hpp',
+ 'net/tls/openssl/OpenSSLInitializer.cpp', 'net/tls/openssl/OpenSSLInitializer.hpp',
'net/tls/TLSSecuredConnectionInfos.cpp', 'net/tls/TLSSecuredConnectionInfos.hpp',
'security/cert/certificateChain.cpp', 'security/cert/certificateChain.hpp',
'security/cert/certificateVerifier.hpp',
'security/cert/defaultCertificateVerifier.cpp', 'security/cert/defaultCertificateVerifier.hpp',
'security/cert/certificate.hpp',
- 'security/cert/X509Certificate.cpp', 'security/cert/X509Certificate.hpp'
+ 'security/cert/X509Certificate.cpp', 'security/cert/X509Certificate.hpp',
+ 'security/cert/gnutls/X509Certificate_GnuTLS.cpp', 'security/cert/gnutls/X509Certificate_GnuTLS.hpp',
+ 'security/cert/openssl/X509Certificate_OpenSSL.cpp', 'security/cert/openssl/X509Certificate_OpenSSL.hpp'
]
libvmime_messaging_proto_sources = [
@@ -282,12 +291,14 @@ libvmime_platforms_sources = {
'posix':
[
'platforms/posix/posixChildProcess.cpp', 'platforms/posix/posixChildProcess.hpp',
+ 'platforms/posix/posixCriticalSection.cpp', 'platforms/posix/posixCriticalSection.hpp',
'platforms/posix/posixFile.cpp', 'platforms/posix/posixFile.hpp',
'platforms/posix/posixHandler.cpp', 'platforms/posix/posixHandler.hpp',
'platforms/posix/posixSocket.cpp', 'platforms/posix/posixSocket.hpp'
],
'windows':
[
+ 'platforms/windows/windowsCriticalSection.cpp', 'platforms/windows/windowsCriticalSection.hpp',
'platforms/windows/windowsFile.cpp', 'platforms/windows/windowsFile.hpp',
'platforms/windows/windowsHandler.cpp', 'platforms/windows/windowsHandler.hpp',
'platforms/windows/windowsSocket.cpp', 'platforms/windows/windowsSocket.hpp'
@@ -590,6 +601,7 @@ env.Append(CXXFLAGS = ['-Wpointer-arith'])
env.Append(CXXFLAGS = ['-Wold-style-cast'])
env.Append(CXXFLAGS = ['-Wconversion'])
env.Append(CXXFLAGS = ['-Wcast-align'])
+env.Append(CXXFLAGS = ['-Wno-long-long']) # OpenSSL
#env.Append(CXXFLAGS = ['-Wshadow'])
env.Append(TARFLAGS = ['-c'])
@@ -614,6 +626,7 @@ if env['with_sasl'] == 'yes':
env.ParseConfig('pkg-config --cflags --libs ' + libgsasl_pc)
if env['with_tls'] == 'yes':
+ # GnuTLS
libgnutls_pc = string.strip(os.popen("pkg-config --list-all | grep '^libgnutls[ ]' | cut -f 1 -d ' '").read())
if len(libgnutls_pc) == 0:
@@ -625,6 +638,15 @@ if env['with_tls'] == 'yes':
env.ParseConfig('pkg-config --cflags --libs ' + libgnutls_pc)
+ # OpenSSL
+ libopenssl_pc = string.strip(os.popen("pkg-config --list-all | grep '^openssl[ ]' | cut -f 1 -d ' '").read())
+
+ if len(libopenssl_pc) == 0:
+ print "ERROR: OpenSSL development package is not installed\n"
+ Exit(1)
+
+ env.ParseConfig('pkg-config --cflags --libs ' + libopenssl_pc)
+
env.Append(CXXFLAGS = ['-pthread'])
# Generate help text for command line options
@@ -806,6 +828,7 @@ config_hpp.write('// -- TLS/SSL support\n')
if env['with_tls'] == 'yes':
config_hpp.write('#define VMIME_HAVE_TLS_SUPPORT 1\n')
config_hpp.write('#define VMIME_TLS_SUPPORT_LIB_IS_GNUTLS 1\n')
+ config_hpp.write('#define VMIME_TLS_SUPPORT_LIB_IS_OPENSSL 0\n')
config_hpp.write('#define VMIME_HAVE_GNUTLS_PRIORITY_FUNCS 1\n')
else:
config_hpp.write('#define VMIME_HAVE_TLS_SUPPORT 0\n')
@@ -834,8 +857,13 @@ for platform in libvmime_platforms_sources:
if not platform in platforms:
config_hpp.write('#define VMIME_PLATFORM_IS_' + string.upper(platform) + ' 0\n')
-config_hpp.write('#define VMIME_HAVE_GETADDRINFO 1\n')
-config_hpp.write('#define VMIME_HAVE_PTHREAD 1\n')
+config_hpp.write("""
+#define VMIME_HAVE_GETADDRINFO 1
+#define VMIME_HAVE_PTHREAD 1
+#define VMIME_HAVE_GETTID 0
+#define VMIME_HAVE_SYSCALL 1
+#define VMIME_HAVE_SYSCALL_GETTID 1
+""")
config_hpp.write('\n')
config_hpp.write('// Miscellaneous flags\n')
diff --git a/cmake/config.hpp.cmake b/cmake/config.hpp.cmake
index 66c26b6c..0b54fe97 100644
--- a/cmake/config.hpp.cmake
+++ b/cmake/config.hpp.cmake
@@ -43,6 +43,7 @@ typedef unsigned @VMIME_32BIT_TYPE@ vmime_uint32;
// -- TLS/SSL support
#cmakedefine01 VMIME_HAVE_TLS_SUPPORT
#cmakedefine01 VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+#cmakedefine01 VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
#define VMIME_HAVE_GNUTLS_PRIORITY_FUNCS @VMIME_HAVE_GNUTLS_PRIORITY_FUNCS@
// -- Messaging support
#cmakedefine01 VMIME_HAVE_MESSAGING_FEATURES
@@ -57,6 +58,9 @@ typedef unsigned @VMIME_32BIT_TYPE@ vmime_uint32;
#cmakedefine01 VMIME_PLATFORM_IS_WINDOWS
#cmakedefine01 VMIME_HAVE_PTHREAD
#cmakedefine01 VMIME_HAVE_GETADDRINFO
+#cmakedefine01 VMIME_HAVE_GETTID
+#cmakedefine01 VMIME_HAVE_SYSCALL
+#cmakedefine01 VMIME_HAVE_SYSCALL_GETTID
#define VMIME_SENDMAIL_PATH "@VMIME_SENDMAIL_PATH@"
diff --git a/src/net/imap/IMAPConnection.cpp b/src/net/imap/IMAPConnection.cpp
index 9cb81d8c..6c8b400e 100644
--- a/src/net/imap/IMAPConnection.cpp
+++ b/src/net/imap/IMAPConnection.cpp
@@ -111,7 +111,7 @@ void IMAPConnection::connect()
if (store->isIMAPS()) // dedicated port/IMAPS
{
ref <tls::TLSSession> tlsSession =
- vmime::create <tls::TLSSession>(store->getCertificateVerifier());
+ tls::TLSSession::create(store->getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket);
@@ -460,7 +460,7 @@ void IMAPConnection::startTLS()
}
ref <tls::TLSSession> tlsSession =
- vmime::create <tls::TLSSession>(m_store.acquire()->getCertificateVerifier());
+ tls::TLSSession::create(m_store.acquire()->getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket);
diff --git a/src/net/pop3/POP3Store.cpp b/src/net/pop3/POP3Store.cpp
index 51181ece..8233cdb2 100644
--- a/src/net/pop3/POP3Store.cpp
+++ b/src/net/pop3/POP3Store.cpp
@@ -151,7 +151,7 @@ void POP3Store::connect()
if (m_isPOP3S) // dedicated port/POP3S
{
ref <tls::TLSSession> tlsSession =
- vmime::create <tls::TLSSession>(getCertificateVerifier());
+ tls::TLSSession::create(getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket);
@@ -550,7 +550,7 @@ void POP3Store::startTLS()
throw exceptions::command_error("STLS", response);
ref <tls::TLSSession> tlsSession =
- vmime::create <tls::TLSSession>(getCertificateVerifier());
+ tls::TLSSession::create(getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket);
diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp
index 64028d1c..e658ecb7 100644
--- a/src/net/smtp/SMTPTransport.cpp
+++ b/src/net/smtp/SMTPTransport.cpp
@@ -114,7 +114,7 @@ void SMTPTransport::connect()
if (m_isSMTPS) // dedicated port/SMTPS
{
ref <tls::TLSSession> tlsSession =
- vmime::create <tls::TLSSession>(getCertificateVerifier());
+ tls::TLSSession::create(getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket);
@@ -463,7 +463,7 @@ void SMTPTransport::startTLS()
throw exceptions::command_error("STARTTLS", resp->getText());
ref <tls::TLSSession> tlsSession =
- vmime::create <tls::TLSSession>(getCertificateVerifier());
+ tls::TLSSession::create(getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket);
diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp
index 31149396..44e8a0f4 100644
--- a/src/net/tls/TLSSession.cpp
+++ b/src/net/tls/TLSSession.cpp
@@ -24,268 +24,19 @@
#include "vmime/config.hpp"
-#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
-#include <gnutls/gnutls.h>
-#if GNUTLS_VERSION_NUMBER < 0x030000
-#include <gnutls/extra.h>
-#endif
-
-
-// Dependency on gcrypt is not needed since GNU TLS version 2.12.
-// See here: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=638651
-#if GNUTLS_VERSION_NUMBER <= 0x020b00
-# define VMIME_GNUTLS_NEEDS_GCRYPT 1
-#endif
-
-#if VMIME_HAVE_PTHREAD
-# include <pthread.h>
-# if VMIME_GNUTLS_NEEDS_GCRYPT
-# include <gcrypt.h>
-# endif
-# include <errno.h>
-#endif // VMIME_HAVE_PTHREAD
-
#include "vmime/net/tls/TLSSession.hpp"
-#include "vmime/exception.hpp"
-
-
-// Enable GnuTLS debugging by defining GNUTLS_DEBUG
-//#define GNUTLS_DEBUG 1
-
-
-#include <sstream>
-#include <iomanip>
-
-#if VMIME_DEBUG && GNUTLS_DEBUG
- #include <iostream>
-#endif // VMIME_DEBUG && GNUTLS_DEBUG
-
-
-#if VMIME_HAVE_PTHREAD && VMIME_GNUTLS_NEEDS_GCRYPT && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL)
-extern "C"
-{
- GCRY_THREAD_OPTION_PTHREAD_IMPL;
-}
-#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL
-
namespace vmime {
namespace net {
namespace tls {
-#ifndef VMIME_BUILDING_DOC
-
-// Initialize GNU TLS library
-struct TLSGlobal
-{
- TLSGlobal()
- {
-#if VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL)
- #if VMIME_GNUTLS_NEEDS_GCRYPT
- gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
- #endif // VMIME_GNUTLS_NEEDS_GCRYPT
-#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL
-
- 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 <security::cert::certificateVerifier> cv)
- : m_certVerifier(cv)
+TLSSession::TLSSession()
{
- 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.
-#if VMIME_HAVE_GNUTLS_PRIORITY_FUNCS
- gnutls_dh_set_prime_bits(*m_gnutlsSession, 128);
-
- if ((res = gnutls_priority_set_direct
- (*m_gnutlsSession, "NORMAL:%SSL3_RECORD_VERSION", NULL)) != 0)
- {
- if ((res = gnutls_priority_set_direct
- (*m_gnutlsSession, "NORMAL", NULL)) != 0)
- {
- throwTLSException
- ("gnutls_priority_set_direct", res);
- }
- }
-
-#else // !VMIME_HAVE_GNUTLS_PRIORITY_FUNCS
-
- 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);
-
-#endif // !VMIME_HAVE_GNUTLS_PRIORITY_FUNCS
-
- // 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 <security::cert::certificateVerifier> TLSSession::getCertificateVerifier()
-{
- return m_certVerifier;
-}
-
-
-void TLSSession::throwTLSException(const string& fname, const int code)
-{
- std::ostringstream msg;
-
- msg << fname + "() returned code ";
- msg << std::hex << code;
- msg << ": ";
- msg << gnutls_strerror(code);
-
- throw exceptions::tls_exception(msg.str());
}
@@ -294,5 +45,4 @@ void TLSSession::throwTLSException(const string& fname, const int code)
} // vmime
-#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
-
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/src/net/tls/TLSSocket.cpp b/src/net/tls/TLSSocket.cpp
index 6fa8d02d..266834bf 100644
--- a/src/net/tls/TLSSocket.cpp
+++ b/src/net/tls/TLSSocket.cpp
@@ -24,18 +24,10 @@
#include "vmime/config.hpp"
-#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
#include "vmime/net/tls/TLSSocket.hpp"
-#include "vmime/net/tls/TLSSession.hpp"
-
-#include "vmime/platform.hpp"
-
-#include "vmime/security/cert/X509Certificate.hpp"
namespace vmime {
@@ -43,375 +35,10 @@ namespace net {
namespace tls {
-TLSSocket::TLSSocket(ref <TLSSession> session, ref <socket> sok)
- : m_session(session), m_wrapped(sok), m_connected(false),
- m_handshaking(false), m_ex(NULL)
-{
- gnutls_transport_set_ptr(*m_session->m_gnutlsSession, this);
-
- gnutls_transport_set_push_function(*m_session->m_gnutlsSession, gnutlsPushFunc);
- gnutls_transport_set_pull_function(*m_session->m_gnutlsSession, gnutlsPullFunc);
-}
-
-
-TLSSocket::~TLSSocket()
-{
- if (m_ex)
- {
- delete m_ex;
- m_ex = NULL;
- }
-
- try
- {
- disconnect();
- }
- catch (...)
- {
- // Don't throw exception in destructor
- }
-}
-
-
-void TLSSocket::connect(const string& address, const port_t port)
-{
- m_wrapped->connect(address, port);
-
- handshake(NULL);
-
- m_connected = true;
-}
-
-
-void TLSSocket::disconnect()
-{
- if (m_connected)
- {
- gnutls_bye(*m_session->m_gnutlsSession, GNUTLS_SHUT_RDWR);
-
- m_wrapped->disconnect();
-
- m_connected = false;
- }
-}
-
-
-bool TLSSocket::isConnected() const
-{
- return m_wrapped->isConnected() && m_connected;
-}
-
-
-TLSSocket::size_type TLSSocket::getBlockSize() const
-{
- return 16384; // 16 KB
-}
-
-
-void TLSSocket::receive(string& buffer)
-{
- const int size = receiveRaw(m_buffer, sizeof(m_buffer));
- buffer = vmime::string(m_buffer, size);
-}
-
-
-void TLSSocket::send(const string& buffer)
-{
- sendRaw(buffer.data(), buffer.length());
-}
-
-
-TLSSocket::size_type TLSSocket::receiveRaw(char* buffer, const size_type count)
-{
- const ssize_t ret = gnutls_record_recv
- (*m_session->m_gnutlsSession,
- buffer, static_cast <size_t>(count));
-
- if (m_ex)
- internalThrow();
-
- if (ret < 0)
- {
- if (ret == GNUTLS_E_AGAIN)
- return 0;
-
- TLSSession::throwTLSException("gnutls_record_recv", ret);
- }
-
- return static_cast <int>(ret);
-}
-
-
-void TLSSocket::sendRaw(const char* buffer, const size_type count)
-{
- gnutls_record_send
- (*m_session->m_gnutlsSession,
- buffer, static_cast <size_t>(count));
-
- if (m_ex)
- internalThrow();
-}
-
-
-void TLSSocket::handshake(ref <timeoutHandler> toHandler)
-{
- if (toHandler)
- toHandler->resetTimeOut();
-
- // Start handshaking process
- m_handshaking = true;
- m_toHandler = toHandler;
-
- try
- {
- while (true)
- {
- const int ret = gnutls_handshake(*m_session->m_gnutlsSession);
-
- if (m_ex)
- internalThrow();
-
- if (ret < 0)
- {
- if (ret == GNUTLS_E_AGAIN ||
- ret == GNUTLS_E_INTERRUPTED)
- {
- // Non-fatal error
- platform::getHandler()->wait();
- }
- else
- {
- TLSSession::throwTLSException("gnutls_handshake", ret);
- }
- }
- else
- {
- // Successful handshake
- break;
- }
- }
- }
- catch (...)
- {
- m_handshaking = false;
- m_toHandler = NULL;
-
- throw;
- }
-
- m_handshaking = false;
- m_toHandler = NULL;
-
- // Verify server's certificate(s)
- ref <security::cert::certificateChain> certs = getPeerCertificates();
-
- if (certs == NULL)
- throw exceptions::tls_exception("No peer certificate.");
-
- m_session->getCertificateVerifier()->verify(certs);
-
- m_connected = true;
-}
-
-
-ssize_t TLSSocket::gnutlsPushFunc
- (gnutls_transport_ptr trspt, const void* data, size_t len)
-{
- TLSSocket* sok = reinterpret_cast <TLSSocket*>(trspt);
-
- try
- {
- sok->m_wrapped->sendRaw
- (reinterpret_cast <const char*>(data), static_cast <int>(len));
- }
- catch (exception& e)
- {
- // Workaround for bad behaviour when throwing C++ exceptions
- // from C functions (GNU TLS)
- sok->m_ex = e.clone();
- return -1;
- }
-
- return len;
-}
-
-
-ssize_t TLSSocket::gnutlsPullFunc
- (gnutls_transport_ptr trspt, void* data, size_t len)
-{
- TLSSocket* sok = reinterpret_cast <TLSSocket*>(trspt);
-
- try
- {
- // Workaround for cross-platform asynchronous handshaking:
- // gnutls_handshake() only returns GNUTLS_E_AGAIN if recv()
- // returns -1 and errno is set to EGAIN...
- if (sok->m_handshaking)
- {
- while (true)
- {
- const ssize_t ret = static_cast <ssize_t>
- (sok->m_wrapped->receiveRaw
- (reinterpret_cast <char*>(data),
- static_cast <int>(len)));
-
- if (ret == 0)
- {
- // No data available yet
- platform::getHandler()->wait();
- }
- else
- {
- return ret;
- }
-
- // Check whether the time-out delay is elapsed
- if (sok->m_toHandler && sok->m_toHandler->isTimeOut())
- {
- if (!sok->m_toHandler->handleTimeOut())
- throw exceptions::operation_timed_out();
-
- sok->m_toHandler->resetTimeOut();
- }
- }
- }
- else
- {
- const ssize_t n = static_cast <ssize_t>
- (sok->m_wrapped->receiveRaw
- (reinterpret_cast <char*>(data),
- static_cast <int>(len)));
-
- if (n == 0)
- return GNUTLS_E_AGAIN; // This seems like a hack, really...
-
- return n;
- }
- }
- catch (exception& e)
- {
- // Workaround for bad behaviour when throwing C++ exceptions
- // from C functions (GNU TLS)
- sok->m_ex = e.clone();
- return -1;
- }
-}
-
-
-ref <security::cert::certificateChain> TLSSocket::getPeerCertificates() const
-{
- unsigned int certCount = 0;
- const gnutls_datum* rawData = gnutls_certificate_get_peers
- (*m_session->m_gnutlsSession, &certCount);
-
- if (rawData == NULL)
- return NULL;
-
- // Try X.509
- gnutls_x509_crt* x509Certs = new gnutls_x509_crt[certCount];
-
- for (unsigned int i = 0; i < certCount; ++i)
- {
- gnutls_x509_crt_init(x509Certs + i);
-
- int res = gnutls_x509_crt_import(x509Certs[i], rawData + i,
- GNUTLS_X509_FMT_DER);
-
- if (res < 0)
- {
- // XXX more fine-grained error reporting?
- delete [] x509Certs;
- return NULL;
- }
- }
-
- {
- std::vector <ref <security::cert::certificate> > certs;
- bool error = false;
-
- for (unsigned int i = 0 ; i < certCount ; ++i)
- {
- size_t dataSize = 0;
-
- gnutls_x509_crt_export(x509Certs[i],
- GNUTLS_X509_FMT_DER, NULL, &dataSize);
-
- std::vector <byte_t> data(dataSize);
-
- gnutls_x509_crt_export(x509Certs[i],
- GNUTLS_X509_FMT_DER, &data[0], &dataSize);
-
- ref <security::cert::X509Certificate> cert =
- security::cert::X509Certificate::import(&data[0], dataSize);
-
- if (cert != NULL)
- certs.push_back(cert);
- else
- error = true;
-
- gnutls_x509_crt_deinit(x509Certs[i]);
- }
-
- delete [] x509Certs;
-
- if (error)
- return NULL;
-
- return vmime::create <security::cert::certificateChain>(certs);
- }
-
- delete [] x509Certs;
-
- return NULL;
-}
-
-
-// Following is a workaround for C++ exceptions to pass correctly between
-// C and C++ calls.
-//
-// gnutls_record_recv() calls TLSSocket::gnutlsPullFunc, and exceptions
-// thrown by the socket can not be caught.
-
-#ifndef VMIME_BUILDING_DOC
-
-class TLSSocket_DeleteExWrapper : public object
-{
-public:
-
- TLSSocket_DeleteExWrapper(exception* ex) : m_ex(ex) { }
- ~TLSSocket_DeleteExWrapper() { delete m_ex; }
-
-private:
-
- exception* m_ex;
-};
-
-#endif // VMIME_BUILDING_DOC
-
-
-void TLSSocket::internalThrow()
-{
- static std::vector <ref <TLSSocket_DeleteExWrapper> > exToDelete;
-
- if (m_ex)
- {
- // Reset the current exception pointer to prevent the same
- // exception from being thrown again later
- exception* ex = m_ex;
- m_ex = NULL;
-
- // To avoid memory leaks
- exToDelete.push_back(vmime::create <TLSSocket_DeleteExWrapper>(ex));
-
- throw *ex;
- }
-}
-
-
} // tls
} // net
} // vmime
-#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/src/net/tls/gnutls/TLSSession_GnuTLS.cpp b/src/net/tls/gnutls/TLSSession_GnuTLS.cpp
new file mode 100644
index 00000000..644a74ec
--- /dev/null
+++ b/src/net/tls/gnutls/TLSSession_GnuTLS.cpp
@@ -0,0 +1,304 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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 "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include <gnutls/gnutls.h>
+#if GNUTLS_VERSION_NUMBER < 0x030000
+#include <gnutls/extra.h>
+#endif
+
+
+// Dependency on gcrypt is not needed since GNU TLS version 2.12.
+// See here: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=638651
+#if GNUTLS_VERSION_NUMBER <= 0x020b00
+# define VMIME_GNUTLS_NEEDS_GCRYPT 1
+#endif
+
+#if VMIME_HAVE_PTHREAD
+# include <pthread.h>
+# if VMIME_GNUTLS_NEEDS_GCRYPT
+# include <gcrypt.h>
+# endif
+# include <errno.h>
+#endif // VMIME_HAVE_PTHREAD
+
+#include "vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp"
+#include "vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp"
+
+#include "vmime/exception.hpp"
+
+
+// Enable GnuTLS debugging by defining GNUTLS_DEBUG
+//#define GNUTLS_DEBUG 1
+
+
+#include <sstream>
+#include <iomanip>
+
+#if VMIME_DEBUG && GNUTLS_DEBUG
+ #include <iostream>
+#endif // VMIME_DEBUG && GNUTLS_DEBUG
+
+
+#if VMIME_HAVE_PTHREAD && VMIME_GNUTLS_NEEDS_GCRYPT && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL)
+extern "C"
+{
+ GCRY_THREAD_OPTION_PTHREAD_IMPL;
+}
+#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+// Initialize GNU TLS library
+struct TLSGlobal
+{
+ TLSGlobal()
+ {
+#if VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL)
+ #if VMIME_GNUTLS_NEEDS_GCRYPT
+ gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+ #endif // VMIME_GNUTLS_NEEDS_GCRYPT
+#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL
+
+ 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
+
+
+
+// static
+ref <TLSSession> TLSSession::create(ref <security::cert::certificateVerifier> cv)
+{
+ return vmime::create <TLSSession_GnuTLS>(cv);
+}
+
+
+TLSSession_GnuTLS::TLSSession_GnuTLS(ref <security::cert::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.
+#if HAVE_GNUTLS_PRIORITY_FUNCS
+ gnutls_dh_set_prime_bits(*m_gnutlsSession, 128);
+
+ if ((res = gnutls_priority_set_direct
+ (*m_gnutlsSession, "NORMAL:%SSL3_RECORD_VERSION", NULL)) != 0)
+ {
+ if ((res = gnutls_priority_set_direct
+ (*m_gnutlsSession, "NORMAL", NULL)) != 0)
+ {
+ throwTLSException
+ ("gnutls_priority_set_direct", res);
+ }
+ }
+
+#else // !HAVE_GNUTLS_PRIORITY_FUNCS
+
+ 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);
+
+#endif // !HAVE_GNUTLS_PRIORITY_FUNCS
+
+ // 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_GnuTLS::TLSSession_GnuTLS(const TLSSession_GnuTLS&)
+ : TLSSession()
+{
+ // Not used
+}
+
+
+TLSSession_GnuTLS::~TLSSession_GnuTLS()
+{
+ if (m_gnutlsSession)
+ {
+ gnutls_deinit(*m_gnutlsSession);
+
+ delete m_gnutlsSession;
+ m_gnutlsSession = NULL;
+ }
+}
+
+
+ref <TLSSocket> TLSSession_GnuTLS::getSocket(ref <socket> sok)
+{
+ return TLSSocket::wrap(thisRef().dynamicCast <TLSSession>(), sok);
+}
+
+
+ref <security::cert::certificateVerifier> TLSSession_GnuTLS::getCertificateVerifier()
+{
+ return m_certVerifier;
+}
+
+
+void TLSSession_GnuTLS::throwTLSException(const string& fname, const int code)
+{
+ std::ostringstream msg;
+
+ msg << fname + "() returned code ";
+ msg << std::hex << code;
+ msg << ": ";
+ msg << gnutls_strerror(code);
+
+ throw exceptions::tls_exception(msg.str());
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
diff --git a/src/net/tls/gnutls/TLSSocket_GnuTLS.cpp b/src/net/tls/gnutls/TLSSocket_GnuTLS.cpp
new file mode 100644
index 00000000..35e1d415
--- /dev/null
+++ b/src/net/tls/gnutls/TLSSocket_GnuTLS.cpp
@@ -0,0 +1,424 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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 "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp"
+#include "vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/security/cert/X509Certificate.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+// static
+ref <TLSSocket> TLSSocket::wrap(ref <TLSSession> session, ref <socket> sok)
+{
+ return vmime::create <TLSSocket_GnuTLS>
+ (session.dynamicCast <TLSSession_GnuTLS>(), sok);
+}
+
+
+TLSSocket_GnuTLS::TLSSocket_GnuTLS(ref <TLSSession_GnuTLS> session, ref <socket> sok)
+ : m_session(session), m_wrapped(sok), m_connected(false),
+ m_handshaking(false), m_ex(NULL)
+{
+ gnutls_transport_set_ptr(*m_session->m_gnutlsSession, this);
+
+ gnutls_transport_set_push_function(*m_session->m_gnutlsSession, gnutlsPushFunc);
+ gnutls_transport_set_pull_function(*m_session->m_gnutlsSession, gnutlsPullFunc);
+}
+
+
+TLSSocket_GnuTLS::~TLSSocket_GnuTLS()
+{
+ if (m_ex)
+ {
+ delete m_ex;
+ m_ex = NULL;
+ }
+
+ try
+ {
+ disconnect();
+ }
+ catch (...)
+ {
+ // Don't throw exception in destructor
+ }
+}
+
+
+void TLSSocket_GnuTLS::connect(const string& address, const port_t port)
+{
+ m_wrapped->connect(address, port);
+
+ handshake(NULL);
+
+ m_connected = true;
+}
+
+
+void TLSSocket_GnuTLS::disconnect()
+{
+ if (m_connected)
+ {
+ gnutls_bye(*m_session->m_gnutlsSession, GNUTLS_SHUT_RDWR);
+
+ m_wrapped->disconnect();
+
+ m_connected = false;
+ }
+}
+
+
+bool TLSSocket_GnuTLS::isConnected() const
+{
+ return m_wrapped->isConnected() && m_connected;
+}
+
+
+TLSSocket::size_type TLSSocket_GnuTLS::getBlockSize() const
+{
+ return 16384; // 16 KB
+}
+
+
+void TLSSocket_GnuTLS::receive(string& buffer)
+{
+ const int size = receiveRaw(m_buffer, sizeof(m_buffer));
+ buffer = vmime::string(m_buffer, size);
+}
+
+
+void TLSSocket_GnuTLS::send(const string& buffer)
+{
+ sendRaw(buffer.data(), buffer.length());
+}
+
+
+TLSSocket::size_type TLSSocket_GnuTLS::receiveRaw(char* buffer, const size_type count)
+{
+ const ssize_t ret = gnutls_record_recv
+ (*m_session->m_gnutlsSession,
+ buffer, static_cast <size_t>(count));
+
+ if (m_ex)
+ internalThrow();
+
+ if (ret < 0)
+ {
+ if (ret == GNUTLS_E_AGAIN)
+ return 0;
+
+ TLSSession_GnuTLS::throwTLSException("gnutls_record_recv", ret);
+ }
+
+ return static_cast <int>(ret);
+}
+
+
+void TLSSocket_GnuTLS::sendRaw(const char* buffer, const size_type count)
+{
+ gnutls_record_send
+ (*m_session->m_gnutlsSession,
+ buffer, static_cast <size_t>(count));
+
+ if (m_ex)
+ internalThrow();
+}
+
+
+void TLSSocket_GnuTLS::handshake(ref <timeoutHandler> toHandler)
+{
+ if (toHandler)
+ toHandler->resetTimeOut();
+
+ // Start handshaking process
+ m_handshaking = true;
+ m_toHandler = toHandler;
+
+ try
+ {
+ while (true)
+ {
+ const int ret = gnutls_handshake(*m_session->m_gnutlsSession);
+
+ if (m_ex)
+ internalThrow();
+
+ if (ret < 0)
+ {
+ if (ret == GNUTLS_E_AGAIN ||
+ ret == GNUTLS_E_INTERRUPTED)
+ {
+ // Non-fatal error
+ platform::getHandler()->wait();
+ }
+ else
+ {
+ TLSSession_GnuTLS::throwTLSException("gnutls_handshake", ret);
+ }
+ }
+ else
+ {
+ // Successful handshake
+ break;
+ }
+ }
+ }
+ catch (...)
+ {
+ m_handshaking = false;
+ m_toHandler = NULL;
+
+ throw;
+ }
+
+ m_handshaking = false;
+ m_toHandler = NULL;
+
+ // Verify server's certificate(s)
+ ref <security::cert::certificateChain> certs = getPeerCertificates();
+
+ if (certs == NULL)
+ throw exceptions::tls_exception("No peer certificate.");
+
+ m_session->getCertificateVerifier()->verify(certs);
+
+ m_connected = true;
+}
+
+
+ssize_t TLSSocket_GnuTLS::gnutlsPushFunc
+ (gnutls_transport_ptr trspt, const void* data, size_t len)
+{
+ TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt);
+
+ try
+ {
+ sok->m_wrapped->sendRaw
+ (reinterpret_cast <const char*>(data), static_cast <int>(len));
+ }
+ catch (exception& e)
+ {
+ // Workaround for bad behaviour when throwing C++ exceptions
+ // from C functions (GNU TLS)
+ sok->m_ex = e.clone();
+ return -1;
+ }
+
+ return len;
+}
+
+
+ssize_t TLSSocket_GnuTLS::gnutlsPullFunc
+ (gnutls_transport_ptr trspt, void* data, size_t len)
+{
+ TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt);
+
+ try
+ {
+ // Workaround for cross-platform asynchronous handshaking:
+ // gnutls_handshake() only returns GNUTLS_E_AGAIN if recv()
+ // returns -1 and errno is set to EGAIN...
+ if (sok->m_handshaking)
+ {
+ while (true)
+ {
+ const ssize_t ret = static_cast <ssize_t>
+ (sok->m_wrapped->receiveRaw
+ (reinterpret_cast <char*>(data),
+ static_cast <int>(len)));
+
+ if (ret == 0)
+ {
+ // No data available yet
+ platform::getHandler()->wait();
+ }
+ else
+ {
+ return ret;
+ }
+
+ // Check whether the time-out delay is elapsed
+ if (sok->m_toHandler && sok->m_toHandler->isTimeOut())
+ {
+ if (!sok->m_toHandler->handleTimeOut())
+ throw exceptions::operation_timed_out();
+
+ sok->m_toHandler->resetTimeOut();
+ }
+ }
+ }
+ else
+ {
+ const ssize_t n = static_cast <ssize_t>
+ (sok->m_wrapped->receiveRaw
+ (reinterpret_cast <char*>(data),
+ static_cast <int>(len)));
+
+ if (n == 0)
+ return GNUTLS_E_AGAIN; // This seems like a hack, really...
+
+ return n;
+ }
+ }
+ catch (exception& e)
+ {
+ // Workaround for bad behaviour when throwing C++ exceptions
+ // from C functions (GNU TLS)
+ sok->m_ex = e.clone();
+ return -1;
+ }
+}
+
+
+ref <security::cert::certificateChain> TLSSocket_GnuTLS::getPeerCertificates() const
+{
+ unsigned int certCount = 0;
+ const gnutls_datum* rawData = gnutls_certificate_get_peers
+ (*m_session->m_gnutlsSession, &certCount);
+
+ if (rawData == NULL)
+ return NULL;
+
+ // Try X.509
+ gnutls_x509_crt* x509Certs = new gnutls_x509_crt[certCount];
+
+ for (unsigned int i = 0; i < certCount; ++i)
+ {
+ gnutls_x509_crt_init(x509Certs + i);
+
+ int res = gnutls_x509_crt_import(x509Certs[i], rawData + i,
+ GNUTLS_X509_FMT_DER);
+
+ if (res < 0)
+ {
+ // XXX more fine-grained error reporting?
+ delete [] x509Certs;
+ return NULL;
+ }
+ }
+
+ {
+ std::vector <ref <security::cert::certificate> > certs;
+ bool error = false;
+
+ for (unsigned int i = 0 ; i < certCount ; ++i)
+ {
+ size_t dataSize = 0;
+
+ gnutls_x509_crt_export(x509Certs[i],
+ GNUTLS_X509_FMT_DER, NULL, &dataSize);
+
+ std::vector <byte_t> data(dataSize);
+
+ gnutls_x509_crt_export(x509Certs[i],
+ GNUTLS_X509_FMT_DER, &data[0], &dataSize);
+
+ ref <security::cert::X509Certificate> cert =
+ security::cert::X509Certificate::import(&data[0], dataSize);
+
+ if (cert != NULL)
+ certs.push_back(cert);
+ else
+ error = true;
+
+ gnutls_x509_crt_deinit(x509Certs[i]);
+ }
+
+ delete [] x509Certs;
+
+ if (error)
+ return NULL;
+
+ return vmime::create <security::cert::certificateChain>(certs);
+ }
+
+ delete [] x509Certs;
+
+ return NULL;
+}
+
+
+// Following is a workaround for C++ exceptions to pass correctly between
+// C and C++ calls.
+//
+// gnutls_record_recv() calls TLSSocket::gnutlsPullFunc, and exceptions
+// thrown by the socket can not be caught.
+
+#ifndef VMIME_BUILDING_DOC
+
+class TLSSocket_DeleteExWrapper : public object
+{
+public:
+
+ TLSSocket_DeleteExWrapper(exception* ex) : m_ex(ex) { }
+ ~TLSSocket_DeleteExWrapper() { delete m_ex; }
+
+private:
+
+ exception* m_ex;
+};
+
+#endif // VMIME_BUILDING_DOC
+
+
+void TLSSocket_GnuTLS::internalThrow()
+{
+ static std::vector <ref <TLSSocket_DeleteExWrapper> > exToDelete;
+
+ if (m_ex)
+ {
+ // Reset the current exception pointer to prevent the same
+ // exception from being thrown again later
+ exception* ex = m_ex;
+ m_ex = NULL;
+
+ // To avoid memory leaks
+ exToDelete.push_back(vmime::create <TLSSocket_DeleteExWrapper>(ex));
+
+ throw *ex;
+ }
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
diff --git a/src/net/tls/openssl/OpenSSLInitializer.cpp b/src/net/tls/openssl/OpenSSLInitializer.cpp
new file mode 100755
index 00000000..ec23ceb4
--- /dev/null
+++ b/src/net/tls/openssl/OpenSSLInitializer.cpp
@@ -0,0 +1,152 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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 "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
+
+#include "vmime/utility/sync/autoLock.hpp"
+#include "vmime/utility/sync/criticalSection.hpp"
+
+#include "vmime/platform.hpp"
+
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x0907000L
+# include <openssl/conf.h>
+#endif
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+ref <vmime::utility::sync::criticalSection >* OpenSSLInitializer::sm_mutexes;
+int OpenSSLInitializer::sm_initCount(0);
+
+
+OpenSSLInitializer::OpenSSLInitializer()
+{
+ initialize();
+}
+
+
+OpenSSLInitializer::~OpenSSLInitializer()
+{
+ uninitialize();
+}
+
+
+// static
+ref <vmime::utility::sync::criticalSection> OpenSSLInitializer::getMutex()
+{
+ static ref <vmime::utility::sync::criticalSection> criticalSection
+ = vmime::platform::getHandler()->createCriticalSection();
+
+ return criticalSection;
+}
+
+
+// static
+void OpenSSLInitializer::initialize()
+{
+ ref <vmime::utility::sync::criticalSection> mutex = getMutex();
+ vmime::utility::sync::autoLock <vmime::utility::sync::criticalSection> lock(mutex);
+
+ if (++sm_initCount == 1)
+ {
+#if OPENSSL_VERSION_NUMBER >= 0x0907000L
+ OPENSSL_config(NULL);
+#endif
+
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+
+ unsigned char seed[SEEDSIZE];
+ vmime::platform::getHandler()->generateRandomBytes(seed, SEEDSIZE);
+ RAND_seed(seed, SEEDSIZE);
+
+ int numMutexes = CRYPTO_num_locks();
+ sm_mutexes = new ref <vmime::utility::sync::criticalSection>[numMutexes];
+
+ for (int i = 0 ; i < numMutexes ; ++i)
+ sm_mutexes[i] = vmime::platform::getHandler()->createCriticalSection();
+
+ CRYPTO_set_locking_callback(&OpenSSLInitializer::lock);
+ CRYPTO_set_id_callback(&OpenSSLInitializer::id);
+ }
+}
+
+
+// static
+void OpenSSLInitializer::uninitialize()
+{
+ ref <vmime::utility::sync::criticalSection> mutex = getMutex();
+ vmime::utility::sync::autoLock <vmime::utility::sync::criticalSection> lock(mutex);
+
+ if (--sm_initCount == 0)
+ {
+ EVP_cleanup();
+ ERR_free_strings();
+
+ CRYPTO_set_locking_callback(NULL);
+ CRYPTO_set_id_callback(NULL);
+
+ delete [] sm_mutexes;
+ }
+}
+
+
+// static
+void OpenSSLInitializer::lock(int mode, int n, const char* /* file */, int /* line */)
+{
+ if (mode & CRYPTO_LOCK)
+ sm_mutexes[n]->lock();
+ else
+ sm_mutexes[n]->unlock();
+}
+
+
+// static
+unsigned long OpenSSLInitializer::id()
+{
+ return vmime::platform::getHandler()->getThreadId();
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
diff --git a/src/net/tls/openssl/TLSSession_OpenSSL.cpp b/src/net/tls/openssl/TLSSession_OpenSSL.cpp
new file mode 100755
index 00000000..e03c90f6
--- /dev/null
+++ b/src/net/tls/openssl/TLSSession_OpenSSL.cpp
@@ -0,0 +1,138 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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 "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#if VMIME_HAVE_PTHREAD
+# include <pthread.h>
+# include <gcrypt.h>
+# include <errno.h>
+#endif // VMIME_HAVE_PTHREAD
+
+#include "vmime/net/tls/openssl/TLSSession_OpenSSL.hpp"
+#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
+
+#include "vmime/exception.hpp"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+// Thread-safe OpenSSL initialization
+static OpenSSLInitializer g_openSSLGlobal;
+
+
+// static
+ref <TLSSession> TLSSession::create(ref <security::cert::certificateVerifier> cv)
+{
+ return vmime::create <TLSSession_OpenSSL>(cv);
+}
+
+
+TLSSession_OpenSSL::TLSSession_OpenSSL(ref <vmime::security::cert::certificateVerifier> cv)
+ : m_sslctx(0), m_certVerifier(cv)
+{
+ m_sslctx = SSL_CTX_new(SSLv23_client_method());
+ SSL_CTX_set_options(m_sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
+}
+
+
+TLSSession_OpenSSL::TLSSession_OpenSSL(const TLSSession_OpenSSL&)
+ : TLSSession()
+{
+ // Not used
+}
+
+
+TLSSession_OpenSSL::~TLSSession_OpenSSL()
+{
+ SSL_CTX_free(m_sslctx);
+}
+
+
+ref <TLSSocket> TLSSession_OpenSSL::getSocket(ref <socket> sok)
+{
+ return TLSSocket::wrap(thisRef().dynamicCast <TLSSession>(), sok);
+}
+
+
+ref <security::cert::certificateVerifier> TLSSession_OpenSSL::getCertificateVerifier()
+{
+ return m_certVerifier;
+}
+
+
+void TLSSession_OpenSSL::usePrivateKeyFile(const vmime::string& keyfile)
+{
+ if (SSL_CTX_use_PrivateKey_file(m_sslctx, keyfile.c_str(), SSL_FILETYPE_PEM) != 1)
+ {
+ unsigned long errCode = ERR_get_error();
+ char buffer[256];
+ ERR_error_string_n(errCode, buffer, sizeof(buffer));
+ vmime::string sslErr(buffer);
+ std::ostringstream oss;
+ oss << "Error loading private key from file " << keyfile;
+ oss << " - msg: " << sslErr;
+ throw exceptions::certificate_exception(oss.str());
+ }
+}
+
+
+void TLSSession_OpenSSL::useCertificateChainFile(const vmime::string& chainFile)
+{
+ if (SSL_CTX_use_certificate_chain_file(m_sslctx, chainFile.c_str()) != 1)
+ {
+ unsigned long errCode = ERR_get_error();
+ char buffer[256];
+ ERR_error_string_n(errCode, buffer, sizeof(buffer));
+ vmime::string sslErr(buffer);
+ std::ostringstream oss;
+ oss << "Error loading certificate from file " << chainFile;
+ oss << " - msg: " << sslErr;
+ throw exceptions::certificate_exception(oss.str());
+ }
+}
+
+
+SSL_CTX* TLSSession_OpenSSL::getContext() const
+{
+ return m_sslctx;
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
diff --git a/src/net/tls/openssl/TLSSocket_OpenSSL.cpp b/src/net/tls/openssl/TLSSocket_OpenSSL.cpp
new file mode 100755
index 00000000..cbd1f9fd
--- /dev/null
+++ b/src/net/tls/openssl/TLSSocket_OpenSSL.cpp
@@ -0,0 +1,416 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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 "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp"
+#include "vmime/net/tls/openssl/TLSSession_OpenSSL.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp"
+
+#include <vector>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+// static
+ref <TLSSocket> TLSSocket::wrap(ref <TLSSession> session, ref <socket> sok)
+{
+ return vmime::create <TLSSocket_OpenSSL>
+ (session.dynamicCast <TLSSession_OpenSSL>(), sok);
+}
+
+
+TLSSocket_OpenSSL::TLSSocket_OpenSSL(ref <TLSSession_OpenSSL> session, ref <socket> sok)
+ : m_session(session), m_wrapped(sok), m_connected(false), m_ssl(0)
+{
+}
+
+
+TLSSocket_OpenSSL::~TLSSocket_OpenSSL()
+{
+ try
+ {
+ disconnect();
+
+ if (m_ssl)
+ {
+ SSL_free(m_ssl);
+ m_ssl = 0;
+ }
+ }
+ catch (...)
+ {
+ // Don't throw in destructor
+ }
+}
+
+
+void TLSSocket_OpenSSL::createSSLHandle()
+{
+ if (m_wrapped->isConnected())
+ {
+ static BIO_METHOD customBIOMethod;
+ ::memset(&customBIOMethod, 0, sizeof(customBIOMethod));
+
+ customBIOMethod.type = 100 | BIO_TYPE_SOURCE_SINK;
+ customBIOMethod.name = "vmime::socket glue";
+ customBIOMethod.bwrite = bio_write;
+ customBIOMethod.bread = bio_read;
+ customBIOMethod.bputs = bio_puts;
+ customBIOMethod.bgets = bio_gets;
+ customBIOMethod.ctrl = bio_ctrl;
+ customBIOMethod.create = bio_create;
+ customBIOMethod.destroy = bio_destroy;
+
+ BIO* sockBio = BIO_new(&customBIOMethod);
+ sockBio->ptr = this;
+
+ m_ssl = SSL_new(m_session->getContext());
+
+ if (!m_ssl)
+ {
+ BIO_free(sockBio);
+ throw exceptions::tls_exception("Cannot create SSL object");
+ }
+
+ SSL_set_bio(m_ssl, sockBio, sockBio);
+ SSL_set_connect_state(m_ssl);
+ }
+ else
+ {
+ throw exceptions::tls_exception("Unconnected socket error");
+ }
+}
+
+
+void TLSSocket_OpenSSL::connect(const string& address, const port_t port)
+{
+ m_wrapped->connect(address, port);
+
+ createSSLHandle();
+
+ handshake(NULL);
+
+ m_connected = true;
+}
+
+
+void TLSSocket_OpenSSL::disconnect()
+{
+ if (m_connected)
+ {
+ if (m_ssl)
+ {
+ // Don't shut down the socket more than once.
+ int shutdownState = SSL_get_shutdown(m_ssl);
+ bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN;
+
+ if (!shutdownSent)
+ SSL_shutdown(m_ssl);
+ }
+
+ m_wrapped->disconnect();
+ m_connected = false;
+ }
+}
+
+
+bool TLSSocket_OpenSSL::isConnected() const
+{
+ return m_wrapped->isConnected() && m_connected;
+}
+
+
+TLSSocket::size_type TLSSocket_OpenSSL::getBlockSize() const
+{
+ return 16384; // 16 KB
+}
+
+
+void TLSSocket_OpenSSL::receive(string& buffer)
+{
+ const int size = receiveRaw(m_buffer, sizeof(m_buffer));
+ buffer = vmime::string(m_buffer, size);
+}
+
+
+void TLSSocket_OpenSSL::send(const string& buffer)
+{
+ sendRaw(buffer.data(), buffer.length());
+}
+
+
+TLSSocket::size_type TLSSocket_OpenSSL::receiveRaw(char* buffer, const size_type count)
+{
+ int rc = SSL_read(m_ssl, buffer, count);
+ handleError(rc);
+ return rc;
+}
+
+
+void TLSSocket_OpenSSL::sendRaw(const char* buffer, const size_type count)
+{
+ int rc = SSL_write(m_ssl, buffer, count);
+ handleError(rc);
+}
+
+
+void TLSSocket_OpenSSL::handshake(ref <timeoutHandler> toHandler)
+{
+ if (toHandler)
+ toHandler->resetTimeOut();
+
+ // Start handshaking process
+ m_toHandler = toHandler;
+
+ if (!m_ssl)
+ createSSLHandle();
+
+ try
+ {
+ // int ret = SSL_connect(m_ssl);
+ int ret = SSL_do_handshake(m_ssl);
+ handleError(ret);
+ }
+ catch (...)
+ {
+ SSL_free(m_ssl);
+ m_ssl = 0;
+ m_toHandler = NULL;
+ throw;
+ }
+
+ m_toHandler = NULL;
+
+ // Verify server's certificate(s)
+ ref <security::cert::certificateChain> certs = getPeerCertificates();
+
+ if (certs == NULL)
+ throw exceptions::tls_exception("No peer certificate.");
+
+ m_session->getCertificateVerifier()->verify(certs);
+
+ m_connected = true;
+}
+
+
+ref <security::cert::certificateChain> TLSSocket_OpenSSL::getPeerCertificates() const
+{
+ STACK_OF(X509)* chain = SSL_get_peer_cert_chain(m_ssl);
+
+ if (chain == NULL)
+ return NULL;
+
+ int certCount = sk_X509_num(chain);
+
+ if (certCount == 0)
+ return NULL;
+
+ bool error = false;
+ std::vector <ref <security::cert::certificate> > certs;
+
+ for (int i = 0; i < certCount && !error; i++)
+ {
+ ref <vmime::security::cert::X509Certificate> cert =
+ vmime::security::cert::X509Certificate_OpenSSL::importInternal(sk_X509_value(chain, i));
+
+ if (cert)
+ certs.push_back(cert);
+ else
+ error = true;
+ }
+
+ if (error)
+ return NULL;
+
+ return vmime::create <security::cert::certificateChain>(certs);
+}
+
+
+void TLSSocket_OpenSSL::handleError(int rc)
+{
+ if (rc > 0) return;
+
+ int sslError = SSL_get_error(m_ssl, rc);
+ long lastError = ERR_get_error();
+
+ switch (sslError)
+ {
+ case SSL_ERROR_ZERO_RETURN:
+ return;
+
+ case SSL_ERROR_SYSCALL:
+ {
+ if (lastError == 0)
+ {
+ if (rc == 0)
+ throw exceptions::tls_exception("SSL connection unexpectedly closed");
+ else
+ {
+ vmime::string msg;
+ std::ostringstream oss(msg);
+ oss << "The BIO reported an error: %d" << rc;
+ oss.flush();
+ throw exceptions::tls_exception(oss.str());
+ }
+ }
+ break;
+ }
+
+ //// Follwoing errors should not occur
+ // With SSL_MODE_AUTO_RETRY these should not happen
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ // This happens only for BIOs of type BIO_s_connect() or BIO_s_accept()
+ case SSL_ERROR_WANT_CONNECT:
+ case SSL_ERROR_WANT_ACCEPT:
+ // SSL_CTX_set_client_cert_cb related, not used
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ default:
+
+ if (lastError == 0)
+ {
+ throw exceptions::tls_exception("Unexpected SSL IO error");
+ }
+ else
+ {
+ char buffer[256];
+ ERR_error_string_n(lastError, buffer, sizeof(buffer));
+ vmime::string msg(buffer);
+ throw exceptions::tls_exception(msg);
+ }
+
+ break;
+ }
+}
+
+
+// Implementation of custom BIO methods
+
+
+// static
+int TLSSocket_OpenSSL::bio_write(BIO* bio, const char* buf, int len)
+{
+ if (buf == NULL || len <= 0)
+ return 0;
+
+ TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(bio->ptr);
+
+ sok->m_wrapped->sendRaw(buf, len);
+
+ return len;
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_read(BIO* bio, char* buf, int len)
+{
+ if (buf == NULL || len <= 0)
+ return 0;
+
+ TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(bio->ptr);
+
+ const int n = sok->m_wrapped->receiveRaw(buf, len);
+
+ if (n == 0)
+ BIO_set_retry_read(bio); // This seems like a hack, really...
+ else
+ BIO_clear_retry_flags(bio);
+
+ return n;
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_puts(BIO* bio, const char* str)
+{
+ return bio_write(bio, str, strlen(str));
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_gets(BIO* /* bio */, char* /* buf */, int /* len */)
+{
+ return -1;
+}
+
+
+// static
+long TLSSocket_OpenSSL::bio_ctrl(BIO* /* bio */, int cmd, long /* num */, void* /* ptr */)
+{
+ if (cmd == BIO_CTRL_FLUSH)
+ {
+ // OpenSSL library needs this
+ return 1;
+ }
+
+ return 0;
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_create(BIO* bio)
+{
+ bio->init = 1;
+ bio->num = 0;
+ bio->ptr = NULL;
+ bio->flags = 0;
+
+ return 1;
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_destroy(BIO* bio)
+{
+ if (bio == NULL)
+ return 0;
+
+ bio->ptr = NULL;
+ bio->init = 0;
+ bio->flags = 0;
+
+ return 1;
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
diff --git a/src/platforms/posix/posixCriticalSection.cpp b/src/platforms/posix/posixCriticalSection.cpp
new file mode 100755
index 00000000..83649fc0
--- /dev/null
+++ b/src/platforms/posix/posixCriticalSection.cpp
@@ -0,0 +1,67 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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 "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX
+
+
+#include "vmime/platforms/posix/posixCriticalSection.hpp"
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+posixCriticalSection::posixCriticalSection()
+{
+ pthread_mutex_init(&m_cs, NULL);
+}
+
+
+posixCriticalSection::~posixCriticalSection()
+{
+ pthread_mutex_destroy(&m_cs);
+}
+
+
+void posixCriticalSection::lock()
+{
+ pthread_mutex_lock(&m_cs);
+}
+
+
+void posixCriticalSection::unlock()
+{
+ pthread_mutex_unlock(&m_cs);
+}
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX
diff --git a/src/platforms/posix/posixHandler.cpp b/src/platforms/posix/posixHandler.cpp
index 8629b1e2..50428b70 100644
--- a/src/platforms/posix/posixHandler.cpp
+++ b/src/platforms/posix/posixHandler.cpp
@@ -29,8 +29,10 @@
#include "vmime/platforms/posix/posixHandler.hpp"
-#include <time.h>
+#include "vmime/platforms/posix/posixCriticalSection.hpp"
+#include <time.h>
+#include <fcntl.h>
#include <unistd.h>
#include <locale.h>
#include <langinfo.h>
@@ -39,10 +41,15 @@
#include <sys/types.h>
#include <sys/stat.h>
+#if VMIME_HAVE_SYSCALL
+# include <sys/syscall.h>
+#endif
+
#include <netdb.h>
#include <string.h>
#include <cassert>
+#include <cstdlib>
#if VMIME_HAVE_PTHREAD
# include <pthread.h>
@@ -217,6 +224,18 @@ unsigned int posixHandler::getProcessId() const
}
+unsigned int posixHandler::getThreadId() const
+{
+#if VMIME_HAVE_GETTID
+ return static_cast <unsigned int>(::gettid());
+#elif VMIME_HAVE_SYSCALL && VMIME_HAVE_SYSCALL_GETTID
+ return static_cast <unsigned int>(::syscall(SYS_gettid));
+#else
+ #error We have no implementation of getThreadId() for this platform!
+#endif
+}
+
+
#if VMIME_HAVE_MESSAGING_FEATURES
ref <vmime::net::socketFactory> posixHandler::getSocketFactory()
@@ -261,6 +280,29 @@ void posixHandler::wait() const
}
+void posixHandler::generateRandomBytes(unsigned char* buffer, const unsigned int count)
+{
+ int fd = open("/dev/urandom", O_RDONLY);
+
+ if (fd != -1)
+ {
+ read(fd, buffer, count);
+ close(fd);
+ }
+ else // fallback
+ {
+ for (unsigned int i = 0 ; i < count ; ++i)
+ buffer[i] = static_cast <unsigned char>(rand() % 255);
+ }
+}
+
+
+ref <utility::sync::criticalSection> posixHandler::createCriticalSection()
+{
+ return vmime::create <posixCriticalSection>();
+}
+
+
} // posix
} // platforms
} // vmime
diff --git a/src/platforms/windows/windowsCriticalSection.cpp b/src/platforms/windows/windowsCriticalSection.cpp
new file mode 100755
index 00000000..d3aebd09
--- /dev/null
+++ b/src/platforms/windows/windowsCriticalSection.cpp
@@ -0,0 +1,67 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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 "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS
+
+
+#include "vmime/platforms/windows/windowsCriticalSection.hpp"
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+windowsCriticalSection::windowsCriticalSection()
+{
+ InitializeCriticalSectionAndSpinCount(&m_cs, 0x400);
+}
+
+
+windowsCriticalSection::~windowsCriticalSection()
+{
+ DeleteCriticalSection(&m_cs)
+}
+
+
+void windowsCriticalSection::lock()
+{
+ EnterCriticalSection(&m_cs);
+}
+
+
+void windowsCriticalSection::unlock()
+{
+ LeaveCriticalSection(&m_cs);
+}
+
+
+} // windows
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS
diff --git a/src/platforms/windows/windowsHandler.cpp b/src/platforms/windows/windowsHandler.cpp
index 1ed4025b..824589b7 100644
--- a/src/platforms/windows/windowsHandler.cpp
+++ b/src/platforms/windows/windowsHandler.cpp
@@ -29,6 +29,8 @@
#include "vmime/platforms/windows/windowsHandler.hpp"
+#include "vmime/platforms/windows/windowsCriticalSection.hpp"
+
#include <time.h>
#include <locale.h>
#include <process.h>
@@ -239,6 +241,12 @@ unsigned int windowsHandler::getProcessId() const
}
+unsigned int windowsHandler::getThreadId() cont
+{
+ return static_cast <unsigned int>(::GetCurrentThreadId());
+}
+
+
#if VMIME_HAVE_MESSAGING_FEATURES
ref <vmime::net::socketFactory> windowsHandler::getSocketFactory()
@@ -272,6 +280,21 @@ void windowsHandler::wait() const
}
+void windowsHandler::generateRandomBytes(unsigned char* buffer, const unsigned int count)
+{
+ HCRYPTPROV cryptProvider = 0;
+ CryptAcquireContext(&cryptProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+ CryptGenRandom(cryptProvider, static_cast <unsigned long>(count), static_cast <unsigned char*>(buffer));
+ CryptReleaseContext(cryptProvider, 0);
+}
+
+
+ref <utility::sync::criticalSection> posixHandler::createCriticalSection()
+{
+ return vmime::create <windowsCriticalSection>();
+}
+
+
} // posix
} // platforms
} // vmime
diff --git a/src/security/cert/X509Certificate.cpp b/src/security/cert/X509Certificate.cpp
index 8df4e5e8..4b177f13 100644
--- a/src/security/cert/X509Certificate.cpp
+++ b/src/security/cert/X509Certificate.cpp
@@ -21,14 +21,13 @@
// the GNU General Public License cover the whole combination.
//
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
+#include "vmime/config.hpp"
-#include <ctime>
-#include "vmime/security/cert/X509Certificate.hpp"
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
-#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
+#include "vmime/security/cert/X509Certificate.hpp"
namespace vmime {
@@ -36,225 +35,8 @@ namespace security {
namespace cert {
-#ifndef VMIME_BUILDING_DOC
-
-struct X509CertificateInternalData
-{
- X509CertificateInternalData()
- {
- gnutls_x509_crt_init(&cert);
- }
-
- ~X509CertificateInternalData()
- {
- gnutls_x509_crt_deinit(cert);
- }
-
-
- gnutls_x509_crt cert;
-};
-
-#endif // VMIME_BUILDING_DOC
-
-
-X509Certificate::X509Certificate()
- : m_data(new X509CertificateInternalData)
-{
-}
-
-
-X509Certificate::X509Certificate(const X509Certificate&)
- : certificate(), m_data(NULL)
-{
- // Not used
-}
-
-
X509Certificate::~X509Certificate()
{
- delete m_data;
-}
-
-
-// static
-ref <X509Certificate> X509Certificate::import(utility::inputStream& is)
-{
- byteArray bytes;
- utility::stream::value_type chunk[4096];
-
- while (!is.eof())
- {
- const int len = is.read(chunk, sizeof(chunk));
- bytes.insert(bytes.end(), chunk, chunk + len);
- }
-
- return import(&bytes[0], bytes.size());
-}
-
-
-// static
-ref <X509Certificate> X509Certificate::import
- (const byte_t* data, const unsigned int length)
-{
- gnutls_datum buffer;
- buffer.data = const_cast <byte_t*>(data);
- buffer.size = length;
-
- // Try DER format
- ref <X509Certificate> derCert = vmime::create <X509Certificate>();
-
- if (gnutls_x509_crt_import(derCert->m_data->cert, &buffer, GNUTLS_X509_FMT_DER) >= 0)
- return derCert;
-
- // Try PEM format
- ref <X509Certificate> pemCert = vmime::create <X509Certificate>();
-
- if (gnutls_x509_crt_import(pemCert->m_data->cert, &buffer, GNUTLS_X509_FMT_PEM) >= 0)
- return pemCert;
-
- return NULL;
-}
-
-
-void X509Certificate::write
- (utility::outputStream& os, const Format format) const
-{
- size_t dataSize = 0;
- gnutls_x509_crt_fmt fmt = GNUTLS_X509_FMT_DER;
-
- switch (format)
- {
- case FORMAT_DER: fmt = GNUTLS_X509_FMT_DER; break;
- case FORMAT_PEM: fmt = GNUTLS_X509_FMT_PEM; break;
- }
-
- gnutls_x509_crt_export(m_data->cert, fmt, NULL, &dataSize);
-
- std::vector <byte_t> data(dataSize);
-
- gnutls_x509_crt_export(m_data->cert, fmt, &data[0], &dataSize);
-
- os.write(reinterpret_cast <utility::stream::value_type*>(&data[0]), dataSize);
-}
-
-
-const byteArray X509Certificate::getSerialNumber() const
-{
- char serial[64];
- size_t serialSize = sizeof(serial);
-
- gnutls_x509_crt_get_serial(m_data->cert, serial, &serialSize);
-
- return byteArray(serial, serial + serialSize);
-}
-
-
-bool X509Certificate::checkIssuer(ref <const X509Certificate> issuer) const
-{
- return (gnutls_x509_crt_check_issuer
- (m_data->cert, issuer->m_data->cert) >= 1);
-}
-
-
-bool X509Certificate::verify(ref <const X509Certificate> caCert) const
-{
- unsigned int verify = 0;
-
- const int res = gnutls_x509_crt_verify
- (m_data->cert, &(caCert->m_data->cert), 1,
- GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
- &verify);
-
- return (res == 0 && verify == 0);
-}
-
-
-const datetime X509Certificate::getActivationDate() const
-{
- const time_t t = gnutls_x509_crt_get_activation_time(m_data->cert);
- return datetime(t);
-}
-
-
-const datetime X509Certificate::getExpirationDate() const
-{
- const time_t t = gnutls_x509_crt_get_expiration_time(m_data->cert);
- return datetime(t);
-}
-
-
-const byteArray X509Certificate::getFingerprint(const DigestAlgorithm algo) const
-{
- gnutls_digest_algorithm galgo;
-
- switch (algo)
- {
- case DIGEST_MD5:
-
- galgo = GNUTLS_DIG_MD5;
- break;
-
- default:
- case DIGEST_SHA1:
-
- galgo = GNUTLS_DIG_SHA;
- break;
- }
-
- size_t bufferSize = 0;
- gnutls_x509_crt_get_fingerprint
- (m_data->cert, galgo, NULL, &bufferSize);
-
- std::vector <byte_t> buffer(bufferSize);
-
- if (gnutls_x509_crt_get_fingerprint
- (m_data->cert, galgo, &buffer[0], &bufferSize) == 0)
- {
- byteArray res;
- res.insert(res.end(), &buffer[0], &buffer[0] + bufferSize);
-
- return res;
- }
-
- return byteArray();
-}
-
-
-const byteArray X509Certificate::getEncoded() const
-{
- byteArray bytes;
- utility::outputStreamByteArrayAdapter os(bytes);
-
- write(os, FORMAT_DER);
-
- return bytes;
-}
-
-
-const string X509Certificate::getType() const
-{
- return "X.509";
-}
-
-
-int X509Certificate::getVersion() const
-{
- return gnutls_x509_crt_get_version(m_data->cert);
-}
-
-
-bool X509Certificate::equals(ref <const certificate> other) const
-{
- ref <const X509Certificate> otherX509 =
- other.dynamicCast <const X509Certificate>();
-
- if (!otherX509)
- return false;
-
- const byteArray fp1 = getFingerprint(DIGEST_MD5);
- const byteArray fp2 = otherX509->getFingerprint(DIGEST_MD5);
-
- return fp1 == fp2;
}
@@ -262,3 +44,5 @@ bool X509Certificate::equals(ref <const certificate> other) const
} // security
} // vmime
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/src/security/cert/gnutls/X509Certificate_GnuTLS.cpp b/src/security/cert/gnutls/X509Certificate_GnuTLS.cpp
new file mode 100644
index 00000000..739b03f1
--- /dev/null
+++ b/src/security/cert/gnutls/X509Certificate_GnuTLS.cpp
@@ -0,0 +1,278 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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 "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include <ctime>
+
+#include "vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp"
+
+#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+struct GnuTLSX509CertificateInternalData
+{
+ GnuTLSX509CertificateInternalData()
+ {
+ gnutls_x509_crt_init(&cert);
+ }
+
+ ~GnuTLSX509CertificateInternalData()
+ {
+ gnutls_x509_crt_deinit(cert);
+ }
+
+
+ gnutls_x509_crt cert;
+};
+
+#endif // VMIME_BUILDING_DOC
+
+
+X509Certificate_GnuTLS::X509Certificate_GnuTLS()
+ : m_data(new GnuTLSX509CertificateInternalData)
+{
+}
+
+
+X509Certificate_GnuTLS::X509Certificate_GnuTLS(const X509Certificate&)
+ : certificate(), m_data(NULL)
+{
+ // Not used
+}
+
+
+X509Certificate_GnuTLS::~X509Certificate_GnuTLS()
+{
+ delete m_data;
+}
+
+
+// static
+ref <X509Certificate> X509Certificate::import(utility::inputStream& is)
+{
+ byteArray bytes;
+ utility::stream::value_type chunk[4096];
+
+ while (!is.eof())
+ {
+ const int len = is.read(chunk, sizeof(chunk));
+ bytes.insert(bytes.end(), chunk, chunk + len);
+ }
+
+ return import(&bytes[0], bytes.size());
+}
+
+
+// static
+ref <X509Certificate> X509Certificate::import
+ (const byte_t* data, const unsigned int length)
+{
+ gnutls_datum buffer;
+ buffer.data = const_cast <byte_t*>(data);
+ buffer.size = length;
+
+ // Try DER format
+ ref <X509Certificate> derCert = vmime::create <X509Certificate_GnuTLS>();
+
+ if (gnutls_x509_crt_import(derCert->m_data->cert, &buffer, GNUTLS_X509_FMT_DER) >= 0)
+ return derCert;
+
+ // Try PEM format
+ ref <X509Certificate> pemCert = vmime::create <X509Certificate_GnuTLS>();
+
+ if (gnutls_x509_crt_import(pemCert->m_data->cert, &buffer, GNUTLS_X509_FMT_PEM) >= 0)
+ return pemCert;
+
+ return NULL;
+}
+
+
+void X509Certificate_GnuTLS::write
+ (utility::outputStream& os, const Format format) const
+{
+ size_t dataSize = 0;
+ gnutls_x509_crt_fmt fmt = GNUTLS_X509_FMT_DER;
+
+ switch (format)
+ {
+ case FORMAT_DER: fmt = GNUTLS_X509_FMT_DER; break;
+ case FORMAT_PEM: fmt = GNUTLS_X509_FMT_PEM; break;
+ }
+
+ gnutls_x509_crt_export(m_data->cert, fmt, NULL, &dataSize);
+
+ std::vector <byte_t> data(dataSize);
+
+ gnutls_x509_crt_export(m_data->cert, fmt, &data[0], &dataSize);
+
+ os.write(reinterpret_cast <utility::stream::value_type*>(&data[0]), dataSize);
+}
+
+
+const byteArray X509Certificate_GnuTLS::getSerialNumber() const
+{
+ char serial[64];
+ size_t serialSize = sizeof(serial);
+
+ gnutls_x509_crt_get_serial(m_data->cert, serial, &serialSize);
+
+ return byteArray(serial, serial + serialSize);
+}
+
+
+bool X509Certificate_GnuTLS::checkIssuer(ref <const X509Certificate> issuer_) const
+{
+ ref <const X509Certificate_GnuTLS> issuer =
+ issuer.dynamicCast <const OpenSSLX509Certificate_GnuTLS>();
+
+ return (gnutls_x509_crt_check_issuer
+ (m_data->cert, issuer->m_data->cert) >= 1);
+}
+
+
+bool X509Certificate_GnuTLS::verify(ref <const X509Certificate> caCert_) const
+{
+ ref <const X509Certificate_GnuTLS> caCert =
+ caCert_.dynamicCast <const X509Certificate_GnuTLS>();
+
+ unsigned int verify = 0;
+
+ const int res = gnutls_x509_crt_verify
+ (m_data->cert, &(caCert->m_data->cert), 1,
+ GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
+ &verify);
+
+ return (res == 0 && verify == 0);
+}
+
+
+const datetime X509Certificate_GnuTLS::getActivationDate() const
+{
+ const time_t t = gnutls_x509_crt_get_activation_time(m_data->cert);
+ return datetime(t);
+}
+
+
+const datetime X509Certificate_GnuTLS::getExpirationDate() const
+{
+ const time_t t = gnutls_x509_crt_get_expiration_time(m_data->cert);
+ return datetime(t);
+}
+
+
+const byteArray X509Certificate_GnuTLS::getFingerprint(const DigestAlgorithm algo) const
+{
+ gnutls_digest_algorithm galgo;
+
+ switch (algo)
+ {
+ case DIGEST_MD5:
+
+ galgo = GNUTLS_DIG_MD5;
+ break;
+
+ default:
+ case DIGEST_SHA1:
+
+ galgo = GNUTLS_DIG_SHA;
+ break;
+ }
+
+ size_t bufferSize = 0;
+ gnutls_x509_crt_get_fingerprint
+ (m_data->cert, galgo, NULL, &bufferSize);
+
+ std::vector <byte_t> buffer(bufferSize);
+
+ if (gnutls_x509_crt_get_fingerprint
+ (m_data->cert, galgo, &buffer[0], &bufferSize) == 0)
+ {
+ byteArray res;
+ res.insert(res.end(), &buffer[0], &buffer[0] + bufferSize);
+
+ return res;
+ }
+
+ return byteArray();
+}
+
+
+const byteArray X509Certificate_GnuTLS::getEncoded() const
+{
+ byteArray bytes;
+ utility::outputStreamByteArrayAdapter os(bytes);
+
+ write(os, FORMAT_DER);
+
+ return bytes;
+}
+
+
+const string X509Certificate_GnuTLS::getType() const
+{
+ return "X.509";
+}
+
+
+int X509Certificate_GnuTLS::getVersion() const
+{
+ return gnutls_x509_crt_get_version(m_data->cert);
+}
+
+
+bool X509Certificate_GnuTLS::equals(ref <const certificate> other) const
+{
+ ref <const X509Certificate_GnuTLS> otherX509 =
+ other.dynamicCast <const X509Certificate_GnuTLS>();
+
+ if (!otherX509)
+ return false;
+
+ const byteArray fp1 = getFingerprint(DIGEST_MD5);
+ const byteArray fp2 = otherX509->getFingerprint(DIGEST_MD5);
+
+ return fp1 == fp2;
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
diff --git a/src/security/cert/openssl/X509Certificate_OpenSSL.cpp b/src/security/cert/openssl/X509Certificate_OpenSSL.cpp
new file mode 100755
index 00000000..dacb006e
--- /dev/null
+++ b/src/security/cert/openssl/X509Certificate_OpenSSL.cpp
@@ -0,0 +1,467 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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 "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include <cstdio>
+#include <ctime>
+#include <map>
+#include <algorithm>
+
+#include "vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp"
+
+#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
+
+#include "vmime/exception.hpp"
+
+#include <openssl/x509.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+class monthMap
+{
+public:
+
+ monthMap()
+ {
+ m_monthMap["jan"] = vmime::datetime::JAN;
+ m_monthMap["feb"] = vmime::datetime::FEB;
+ m_monthMap["mar"] = vmime::datetime::MAR;
+ m_monthMap["apr"] = vmime::datetime::APR;
+ m_monthMap["may"] = vmime::datetime::MAY;
+ m_monthMap["jun"] = vmime::datetime::JUN;
+ m_monthMap["jul"] = vmime::datetime::JUL;
+ m_monthMap["aug"] = vmime::datetime::AUG;
+ m_monthMap["sep"] = vmime::datetime::SEP;
+ m_monthMap["oct"] = vmime::datetime::OCT;
+ m_monthMap["nov"] = vmime::datetime::NOV;
+ m_monthMap["dec"] = vmime::datetime::DEC;
+ }
+
+ int getMonth(vmime::string mstr)
+ {
+ std::transform(mstr.begin(), mstr.end(), mstr.begin(), ::tolower);
+
+ std::map <vmime::string, vmime::datetime::Months>::const_iterator
+ c_it = m_monthMap.find(mstr);
+
+ if (c_it != m_monthMap.end())
+ return c_it->second;
+
+ return -1;
+ }
+
+private:
+
+ std::map<vmime::string, vmime::datetime::Months> m_monthMap;
+};
+
+static monthMap sg_monthMap;
+
+
+
+struct OpenSSLX509CertificateInternalData
+{
+ OpenSSLX509CertificateInternalData()
+ {
+ cert = 0;
+ }
+
+ ~OpenSSLX509CertificateInternalData()
+ {
+ if (cert)
+ X509_free(cert);
+ }
+
+ X509* cert;
+};
+
+#endif // VMIME_BUILDING_DOC
+
+
+X509Certificate_OpenSSL::X509Certificate_OpenSSL()
+ : m_data(new OpenSSLX509CertificateInternalData)
+{
+}
+
+
+X509Certificate_OpenSSL::X509Certificate_OpenSSL(X509* cert)
+ : m_data(new OpenSSLX509CertificateInternalData)
+{
+ m_data->cert = X509_dup(cert);
+}
+
+
+X509Certificate_OpenSSL::X509Certificate_OpenSSL(const X509Certificate_OpenSSL&)
+ : X509Certificate(), m_data(NULL)
+{
+ // Not used
+}
+
+
+X509Certificate_OpenSSL::~X509Certificate_OpenSSL()
+{
+ delete m_data;
+}
+
+
+// static
+ref <X509Certificate> X509Certificate_OpenSSL::importInternal(X509* cert)
+{
+ if (cert)
+ return vmime::create <X509Certificate_OpenSSL>(reinterpret_cast <X509 *>(cert));
+
+ return NULL;
+}
+
+
+// static
+ref <X509Certificate> X509Certificate::import(utility::inputStream& is)
+{
+ byteArray bytes;
+ utility::stream::value_type chunk[4096];
+
+ while (!is.eof())
+ {
+ const int len = is.read(chunk, sizeof(chunk));
+ bytes.insert(bytes.end(), chunk, chunk + len);
+ }
+
+ return import(&bytes[0], bytes.size());
+}
+
+
+// static
+ref <X509Certificate> X509Certificate::import
+ (const byte_t* data, const unsigned int length)
+{
+ ref <X509Certificate_OpenSSL> cert = vmime::create <X509Certificate_OpenSSL>();
+
+ BIO* membio = BIO_new_mem_buf(const_cast <byte_t*>(data), length);
+
+ if (!PEM_read_bio_X509(membio, &(cert->m_data->cert), 0, 0))
+ {
+ BIO_vfree(membio);
+ return NULL;
+ }
+
+ BIO_vfree(membio);
+
+ return cert;
+}
+
+
+void X509Certificate_OpenSSL::write
+ (utility::outputStream& os, const Format format) const
+{
+ BIO* membio = 0;
+ int dataSize = 0;
+ unsigned char* out = 0;
+
+ if (format == FORMAT_DER)
+ {
+ if ((dataSize = i2d_X509(m_data->cert, &out)) < 0)
+ goto err;
+
+ os.write(reinterpret_cast <utility::stream::value_type*>(out), dataSize);
+ os.flush();
+ OPENSSL_free(out);
+ }
+ else if (format == FORMAT_PEM)
+ {
+ membio = BIO_new(BIO_s_mem());
+ BIO_set_close(membio, BIO_CLOSE);
+
+ if (!PEM_write_bio_X509(membio, m_data->cert))
+ goto pem_err;
+
+ dataSize = BIO_get_mem_data(membio, &out);
+ os.write(reinterpret_cast <utility::stream::value_type*>(out), dataSize);
+ os.flush();
+ BIO_vfree(membio);
+ }
+ else
+ {
+ throw vmime::exceptions::unsupported_certificate_type("Unknown cert type");
+ }
+
+ return; // #### Early Return ####
+
+pem_err:
+ {
+ if (membio)
+ BIO_vfree(membio);
+ }
+
+err:
+ {
+ char errstr[256];
+ long ec = ERR_get_error();
+ ERR_error_string(ec, errstr);
+ throw vmime::exceptions::certificate_exception(
+ "OpenSSLX509Certificate_OpenSSL::write exception - " + string(errstr));
+ }
+}
+
+
+const byteArray X509Certificate_OpenSSL::getSerialNumber() const
+{
+ ASN1_INTEGER *serial = X509_get_serialNumber(m_data->cert);
+ BIGNUM *bnser = ASN1_INTEGER_to_BN(serial, NULL);
+ int n = BN_num_bytes(bnser);
+ byte_t* outbuf = new byte_t[n];
+ BN_bn2bin(bnser, outbuf);
+ byteArray ser(outbuf, outbuf + n);
+ delete [] outbuf;
+ BN_free(bnser);
+ return ser;
+}
+
+
+bool X509Certificate_OpenSSL::checkIssuer(ref <const X509Certificate> cert_) const
+{
+ ref <const X509Certificate_OpenSSL> cert =
+ cert_.dynamicCast <const X509Certificate_OpenSSL>();
+
+ // Get issuer for this cert
+ BIO *out;
+ unsigned char *issuer;
+
+ out = BIO_new(BIO_s_mem());
+ X509_NAME_print_ex(out, X509_get_issuer_name(m_data->cert), 0, XN_FLAG_RFC2253);
+ int n = BIO_get_mem_data(out, &issuer);
+ vmime::string thisIssuerName((char*)issuer, n);
+ BIO_free(out);
+
+ // Get subject of issuer
+ unsigned char *subject;
+ out = BIO_new(BIO_s_mem());
+ X509_NAME_print_ex(out, X509_get_subject_name(cert->m_data->cert), 0, XN_FLAG_RFC2253);
+ n = BIO_get_mem_data(out, &subject);
+ vmime::string subjOfIssuer((char*)subject, n);
+ BIO_free(out);
+
+ return subjOfIssuer == thisIssuerName;
+}
+
+
+bool X509Certificate_OpenSSL::verify(ref <const X509Certificate> caCert_) const
+{
+ ref <const X509Certificate_OpenSSL> caCert =
+ caCert_.dynamicCast <const X509Certificate_OpenSSL>();
+
+
+ bool verified = false;
+ bool error = true;
+
+ X509_STORE *store = X509_STORE_new();
+
+ if (store)
+ {
+ X509_STORE_CTX *verifyCtx = X509_STORE_CTX_new();
+
+ if (verifyCtx)
+ {
+ if (X509_STORE_add_cert(store, caCert->m_data->cert))
+ {
+ X509_STORE_CTX_init(verifyCtx, store, m_data->cert, NULL);
+
+ int ret = X509_verify_cert(verifyCtx);
+
+ if (ret == 1)
+ {
+ verified = true;
+ error = false;
+ }
+ else if (ret == 0)
+ {
+ verified = false;
+ error = false;
+ }
+
+ //X509_verify_cert_error_string(vrfy_ctx->error)
+
+ X509_STORE_CTX_free(verifyCtx);
+ }
+ }
+
+ X509_STORE_free(store);
+ }
+
+ return verified && !error;
+}
+
+
+const datetime X509Certificate_OpenSSL::convertX509Date(void* time) const
+{
+ char* buffer;
+ BIO* out = BIO_new(BIO_s_mem());
+ BIO_set_close(out, BIO_CLOSE);
+
+ ASN1_TIME* asn1_time = reinterpret_cast<ASN1_TIME*>(time);
+ ASN1_TIME_print(out, asn1_time);
+
+ int sz = BIO_get_mem_data(out, &buffer);
+ char* dest = new char[sz + 1];
+ dest[sz] = 0;
+ memcpy(dest, buffer, sz);
+ vmime::string t(dest);
+
+ BIO_free(out);
+ delete dest;
+
+ if (t.size() > 0)
+ {
+ char month[4] = {0};
+ char zone[4] = {0};
+ int day, hour, minute, second, year;
+ int nrconv = sscanf(t.c_str(), "%s %2d %02d:%02d:%02d %d%s", month, &day, &hour, &minute, &second,&year,zone);
+
+ if (nrconv >= 6)
+ return datetime(year, sg_monthMap.getMonth(vmime::string(month)), day, hour, minute, second);
+ }
+
+ // let datetime try and parse it
+ return datetime(t);
+}
+
+
+const datetime X509Certificate_OpenSSL::getActivationDate() const
+{
+ return convertX509Date(X509_get_notBefore(m_data->cert));
+}
+
+
+const datetime X509Certificate_OpenSSL::getExpirationDate() const
+{
+ return convertX509Date(X509_get_notAfter(m_data->cert));
+}
+
+
+const byteArray X509Certificate_OpenSSL::getFingerprint(const DigestAlgorithm algo) const
+{
+ BIO *out;
+ int j;
+ unsigned int n;
+ const EVP_MD *digest;
+ unsigned char * fingerprint, *result;
+ unsigned char md[EVP_MAX_MD_SIZE];
+
+ switch (algo)
+ {
+ case DIGEST_MD5:
+
+ digest = EVP_md5();
+ break;
+
+ default:
+ case DIGEST_SHA1:
+
+ digest = EVP_sha1();
+ break;
+ }
+
+ out = BIO_new(BIO_s_mem());
+ BIO_set_close(out, BIO_CLOSE);
+
+ if (X509_digest(m_data->cert, digest, md, &n))
+ {
+ for (j=0; j<(int)n; j++)
+ {
+ BIO_printf (out, "%02X",md[j]);
+ if (j+1 != (int)n) BIO_printf(out, ":");
+ }
+ }
+
+ n = BIO_get_mem_data(out, &fingerprint);
+ result = new unsigned char[n];
+ memcpy (result, fingerprint, n);
+ BIO_free(out);
+
+ byteArray res;
+ res.insert(res.end(), &result[0], &result[0] + n);
+
+ delete [] result;
+
+ return res;
+}
+
+
+const byteArray X509Certificate_OpenSSL::getEncoded() const
+{
+ byteArray bytes;
+ utility::outputStreamByteArrayAdapter os(bytes);
+
+ write(os, FORMAT_DER);
+
+ return bytes;
+}
+
+
+const string X509Certificate_OpenSSL::getType() const
+{
+ return "X.509";
+}
+
+
+int X509Certificate_OpenSSL::getVersion() const
+{
+ return (int)X509_get_version(m_data->cert);
+}
+
+
+bool X509Certificate_OpenSSL::equals(ref <const certificate> other) const
+{
+ ref <const X509Certificate_OpenSSL> otherX509 =
+ other.dynamicCast <const X509Certificate_OpenSSL>();
+
+ if (!otherX509)
+ return false;
+
+ const byteArray fp1 = getFingerprint(DIGEST_MD5);
+ const byteArray fp2 = otherX509->getFingerprint(DIGEST_MD5);
+
+ return fp1 == fp2;
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
diff --git a/src/utility/sync/criticalSection.cpp b/src/utility/sync/criticalSection.cpp
new file mode 100755
index 00000000..642467f1
--- /dev/null
+++ b/src/utility/sync/criticalSection.cpp
@@ -0,0 +1,44 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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 "vmime/utility/sync/criticalSection.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace sync {
+
+
+criticalSection::criticalSection()
+{
+}
+
+
+criticalSection::~criticalSection()
+{
+}
+
+
+} // sync
+} // utility
+} // vmime
diff --git a/vmime/net/tls/TLSSession.hpp b/vmime/net/tls/TLSSession.hpp
index 75241c8c..8946e521 100644
--- a/vmime/net/tls/TLSSession.hpp
+++ b/vmime/net/tls/TLSSession.hpp
@@ -28,7 +28,7 @@
#include "vmime/config.hpp"
-#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#include "vmime/types.hpp"
@@ -47,19 +47,15 @@ namespace tls {
*/
class TLSSession : public object
{
- friend class TLSSocket;
-
public:
- ~TLSSession();
-
/** Create and initialize a new TLS session.
*
* @param cv object responsible for verifying certificates
* sent by the server
* @return a new TLS session
*/
- TLSSession(ref <security::cert::certificateVerifier> cv);
+ static ref <TLSSession> create(ref <security::cert::certificateVerifier> cv);
/** Create a new socket that adds a TLS security layer around
* an existing socket. You should create only one socket
@@ -68,27 +64,20 @@ public:
* @param sok socket to wrap
* @return TLS socket wrapper
*/
- ref <TLSSocket> getSocket(ref <socket> sok);
+ virtual ref <TLSSocket> getSocket(ref <socket> sok) = 0;
/** Get the object responsible for verifying certificates when
* using secured connections (TLS/SSL).
*/
- ref <security::cert::certificateVerifier> getCertificateVerifier();
+ virtual ref <security::cert::certificateVerifier> getCertificateVerifier() = 0;
-private:
-
- TLSSession(const TLSSession&);
+protected:
- static void throwTLSException(const string& fname, const int code);
+ TLSSession();
+private:
-#ifdef LIBGNUTLS_VERSION
- gnutls_session* m_gnutlsSession;
-#else
- void* m_gnutlsSession;
-#endif // LIBGNUTLS_VERSION
-
- ref <security::cert::certificateVerifier> m_certVerifier;
+ TLSSession(const TLSSession&);
};
@@ -97,7 +86,6 @@ private:
} // vmime
-#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#endif // VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED
-
diff --git a/vmime/net/tls/TLSSocket.hpp b/vmime/net/tls/TLSSocket.hpp
index e88d424c..bcc5d085 100644
--- a/vmime/net/tls/TLSSocket.hpp
+++ b/vmime/net/tls/TLSSocket.hpp
@@ -28,7 +28,7 @@
#include "vmime/config.hpp"
-#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#include "vmime/exception.hpp"
@@ -51,9 +51,7 @@ class TLSSession;
*/
class TLSSocket : public socket
{
- friend class vmime::creator;
-
-protected:
+public:
/** Create a new socket object that adds a security layer
* around an existing socket.
@@ -61,12 +59,7 @@ protected:
* @param session TLS session
* @param sok socket to wrap
*/
- TLSSocket(ref <TLSSession> session, ref <socket> sok);
-
-public:
-
- ~TLSSocket();
-
+ static ref <TLSSocket> wrap(ref <TLSSession> session, ref <socket> sok);
/** Starts a TLS handshake on this connection.
*
@@ -74,53 +67,14 @@ public:
* during the negociation process, exceptions::operation_timed_out
* if a time-out occurs
*/
- void handshake(ref <timeoutHandler> toHandler = NULL);
+ virtual void handshake(ref <timeoutHandler> toHandler = NULL) = 0;
/** Return the peer's certificate (chain) as sent by the peer.
*
* @return server certificate chain, or NULL if the handshake
* has not been performed yet
*/
- ref <security::cert::certificateChain> getPeerCertificates() const;
-
-
- // Implementation of 'socket'
- void connect(const string& address, const port_t port);
- void disconnect();
- bool isConnected() const;
-
- void receive(string& buffer);
- size_type receiveRaw(char* buffer, const size_type count);
-
- void send(const string& buffer);
- void sendRaw(const char* buffer, const size_type count);
-
- size_type getBlockSize() const;
-
-private:
-
- void internalThrow();
-
-#ifdef LIBGNUTLS_VERSION
- static ssize_t gnutlsPushFunc(gnutls_transport_ptr trspt, const void* data, size_t len);
- static ssize_t gnutlsPullFunc(gnutls_transport_ptr trspt, void* data, size_t len);
-#else
- static int gnutlsPushFunc(void* trspt, const void* data, size_t len);
- static int gnutlsPullFunc(void* trspt, void* data, size_t len);
-#endif // LIBGNUTLS_VERSION
-
-
- ref <TLSSession> m_session;
- ref <socket> m_wrapped;
-
- bool m_connected;
-
- char m_buffer[65536];
-
- bool m_handshaking;
- ref <timeoutHandler> m_toHandler;
-
- exception* m_ex;
+ virtual ref <security::cert::certificateChain> getPeerCertificates() const = 0;
};
@@ -129,7 +83,6 @@ private:
} // vmime
-#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#endif // VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED
-
diff --git a/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp b/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp
new file mode 100644
index 00000000..d34054dd
--- /dev/null
+++ b/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp
@@ -0,0 +1,89 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSSession.hpp"
+#include "vmime/net/tls/TLSSocket.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession_GnuTLS : public TLSSession
+{
+ friend class TLSSocket_GnuTLS;
+
+public:
+
+ TLSSession_GnuTLS(ref <security::cert::certificateVerifier> cv);
+ ~TLSSession_GnuTLS();
+
+
+ ref <TLSSocket> getSocket(ref <socket> sok);
+
+ ref <security::cert::certificateVerifier> getCertificateVerifier();
+
+private:
+
+ TLSSession_GnuTLS(const TLSSession_GnuTLS&);
+
+ static void throwTLSException(const string& fname, const int code);
+
+
+#ifdef LIBGNUTLS_VERSION
+ gnutls_session* m_gnutlsSession;
+#else
+ void* m_gnutlsSession;
+#endif // LIBGNUTLS_VERSION
+
+ ref <security::cert::certificateVerifier> m_certVerifier;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED
+
diff --git a/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp b/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp
new file mode 100644
index 00000000..729923f3
--- /dev/null
+++ b/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp
@@ -0,0 +1,113 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/net/tls/TLSSocket.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession;
+class TLSSession_GnuTLS;
+
+
+class TLSSocket_GnuTLS : public TLSSocket
+{
+ friend class vmime::creator;
+
+public:
+
+ TLSSocket_GnuTLS(ref <TLSSession_GnuTLS> session, ref <socket> sok);
+ ~TLSSocket_GnuTLS();
+
+
+ void handshake(ref <timeoutHandler> toHandler = NULL);
+
+ ref <security::cert::certificateChain> getPeerCertificates() const;
+
+ // Implementation of 'socket'
+ void connect(const string& address, const port_t port);
+ void disconnect();
+ bool isConnected() const;
+
+ void receive(string& buffer);
+ size_type receiveRaw(char* buffer, const size_type count);
+
+ void send(const string& buffer);
+ void sendRaw(const char* buffer, const size_type count);
+
+ size_type getBlockSize() const;
+
+private:
+
+ void internalThrow();
+
+#ifdef LIBGNUTLS_VERSION
+ static ssize_t gnutlsPushFunc(gnutls_transport_ptr trspt, const void* data, size_t len);
+ static ssize_t gnutlsPullFunc(gnutls_transport_ptr trspt, void* data, size_t len);
+#else
+ static int gnutlsPushFunc(void* trspt, const void* data, size_t len);
+ static int gnutlsPullFunc(void* trspt, void* data, size_t len);
+#endif // LIBGNUTLS_VERSION
+
+
+ ref <TLSSession_GnuTLS> m_session;
+ ref <socket> m_wrapped;
+
+ bool m_connected;
+
+ char m_buffer[65536];
+
+ bool m_handshaking;
+ ref <timeoutHandler> m_toHandler;
+
+ exception* m_ex;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED
+
diff --git a/vmime/net/tls/openssl/OpenSSLInitializer.hpp b/vmime/net/tls/openssl/OpenSSLInitializer.hpp
new file mode 100755
index 00000000..65c0aac6
--- /dev/null
+++ b/vmime/net/tls/openssl/OpenSSLInitializer.hpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED
+#define VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+#include <vector>
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/utility/sync/criticalSection.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+/** Class responsible for setting up OpenSSL
+ */
+class OpenSSLInitializer
+{
+
+public:
+
+ /** Automatically initialize OpenSSL
+ */
+ OpenSSLInitializer();
+
+ /** Automatically uninitialize OpenSSL
+ */
+ ~OpenSSLInitializer();
+
+protected:
+
+ /** Initializes the OpenSSL lib
+ */
+ static void initialize();
+
+ /** Shutdown the OpenSSL lib
+ */
+ static void uninitialize();
+
+
+ static ref <vmime::utility::sync::criticalSection> getMutex();
+
+ enum
+ {
+ SEEDSIZE = 256
+ };
+
+
+ // OpenSSL multithreading support
+ static void lock(int mode, int n, const char* file, int line);
+ static unsigned long id();
+
+private:
+
+ static ref <vmime::utility::sync::criticalSection >* sm_mutexes;
+ static int sm_initCount;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED
+
diff --git a/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp b/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp
new file mode 100755
index 00000000..1765597b
--- /dev/null
+++ b/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp
@@ -0,0 +1,106 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSSession.hpp"
+#include "vmime/net/tls/TLSSocket.hpp"
+
+
+#include <openssl/ssl.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession_OpenSSL : public TLSSession
+{
+ friend class TLSSocket_OpenSSL;
+
+public:
+
+ TLSSession_OpenSSL(const ref <security::cert::certificateVerifier> cv);
+ ~TLSSession_OpenSSL();
+
+
+ ref <TLSSocket> getSocket(ref <socket> sok);
+
+ ref <security::cert::certificateVerifier> getCertificateVerifier();
+
+
+ /** Set the private key to use if server requires a client certificate.
+ *
+ * @param keyfile Path to the private key in PEM format
+ * @param passwd_callback If the private key is stored encrypted the
+ */
+ void usePrivateKeyFile(const vmime::string& keyfile);
+
+ /** Supply the certificate chain to present if requested by
+ * server.
+ *
+ * @param chainFile File in PEM format holding certificate chain
+ */
+ void useCertificateChainFile(const vmime::string& chainFile);
+
+ /** Get a pointer to the SSL_CTX used for this session.
+ *
+ * @return the SSL_CTX used for all connections created with this session
+ */
+ SSL_CTX* getContext() const;
+
+private:
+
+ TLSSession_OpenSSL(const TLSSession_OpenSSL&);
+
+ SSL_CTX* m_sslctx;
+
+ ref <security::cert::certificateVerifier> m_certVerifier;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED
+
diff --git a/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp b/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp
new file mode 100755
index 00000000..401fad12
--- /dev/null
+++ b/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp
@@ -0,0 +1,116 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/net/tls/TLSSocket.hpp"
+
+#include <openssl/ssl.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession;
+class TLSSession_OpenSSL;
+
+
+class TLSSocket_OpenSSL : public TLSSocket
+{
+ friend class vmime::creator;
+
+public:
+
+ TLSSocket_OpenSSL(ref <TLSSession_OpenSSL> session, ref <socket> sok);
+ ~TLSSocket_OpenSSL();
+
+
+ void handshake(ref <timeoutHandler> toHandler = NULL);
+
+ ref <security::cert::certificateChain> getPeerCertificates() const;
+
+ // Implementation of 'socket'
+ void connect(const string& address, const port_t port);
+ void disconnect();
+ bool isConnected() const;
+
+ void receive(string& buffer);
+ size_type receiveRaw(char* buffer, const size_type count);
+
+ void send(const string& buffer);
+ void sendRaw(const char* buffer, const size_type count);
+
+ size_type getBlockSize() const;
+
+private:
+
+ static int bio_write(BIO* bio, const char* buf, int len);
+ static int bio_read(BIO* bio, char* buf, int len);
+ static int bio_puts(BIO* bio, const char* str);
+ static int bio_gets(BIO* bio, char* buf, int len);
+ static long bio_ctrl(BIO* bio, int cmd, long num, void* ptr);
+ static int bio_create(BIO* bio);
+ static int bio_destroy(BIO* bio);
+
+ void createSSLHandle();
+
+ void handleError(int rc);
+
+ ref <TLSSession_OpenSSL> m_session;
+
+ ref <socket> m_wrapped;
+
+ bool m_connected;
+
+ char m_buffer[65536];
+
+ ref <timeoutHandler> m_toHandler;
+
+ SSL* m_ssl;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED
+
diff --git a/vmime/platform.hpp b/vmime/platform.hpp
index 2063268e..86ce8ee0 100644
--- a/vmime/platform.hpp
+++ b/vmime/platform.hpp
@@ -40,6 +40,8 @@
#include "vmime/utility/childProcess.hpp"
#endif
+#include "vmime/utility/sync/criticalSection.hpp"
+
namespace vmime
{
@@ -89,6 +91,13 @@ public:
*/
virtual unsigned int getProcessId() const = 0;
+ /** Return an unique identifier for the current thread.
+ * Used for multi-threading synchronization.
+ *
+ * @return current thread id
+ */
+ virtual unsigned int getThreadId() const = 0;
+
/** Return the charset used on the system.
*
* @return locale charset
@@ -126,6 +135,16 @@ public:
virtual ref <utility::childProcessFactory> getChildProcessFactory() = 0;
#endif
+ /** Fills a buffer with cryptographically random bytes.
+ *
+ * @param buffer buffer to fill in with random bytes
+ * @param count number of random bytes to write in buffer
+ */
+ virtual void generateRandomBytes(unsigned char* buffer, const unsigned int count) = 0;
+
+ /** Creates and initializes a critical section.
+ */
+ virtual ref <utility::sync::criticalSection> createCriticalSection() = 0;
};
diff --git a/vmime/platforms/posix/posixCriticalSection.hpp b/vmime/platforms/posix/posixCriticalSection.hpp
new file mode 100755
index 00000000..16dd9cd3
--- /dev/null
+++ b/vmime/platforms/posix/posixCriticalSection.hpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED
+#define VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX
+
+
+#include "vmime/utility/sync/criticalSection.hpp"
+
+
+#include <unistd.h>
+#include <pthread.h>
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+class posixCriticalSection : public utility::sync::criticalSection
+{
+public:
+
+ posixCriticalSection();
+ ~posixCriticalSection();
+
+ void lock();
+ void unlock();
+
+private:
+
+ pthread_mutex_t m_cs;
+};
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX
+
+#endif // VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED
diff --git a/vmime/platforms/posix/posixHandler.hpp b/vmime/platforms/posix/posixHandler.hpp
index 80cfb650..b6ef3df6 100644
--- a/vmime/platforms/posix/posixHandler.hpp
+++ b/vmime/platforms/posix/posixHandler.hpp
@@ -64,6 +64,7 @@ public:
const vmime::string getHostName() const;
unsigned int getProcessId() const;
+ unsigned int getThreadId() const;
#if VMIME_HAVE_MESSAGING_FEATURES
ref <vmime::net::socketFactory> getSocketFactory();
@@ -77,6 +78,10 @@ public:
void wait() const;
+ void generateRandomBytes(unsigned char* buffer, const unsigned int count);
+
+ ref <utility::sync::criticalSection> createCriticalSection();
+
private:
#if VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime/platforms/windows/windowsCriticalSection.hpp b/vmime/platforms/windows/windowsCriticalSection.hpp
new file mode 100755
index 00000000..0da3dafb
--- /dev/null
+++ b/vmime/platforms/windows/windowsCriticalSection.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_PLATFORMS_WINDOWS_CRITICALSECTION_HPP_INCLUDED
+#define VMIME_PLATFORMS_WINDOWS_CRITICALSECTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS
+
+
+#include "vmime/utility/sync/criticalSection.hpp"
+
+
+#include <windows.h>
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+class windowsCriticalSection : public utility::sync::criticalSection
+{
+public:
+
+ windowsCriticalSection();
+ ~windowsCriticalSection();
+
+ void lock();
+ void unlock();
+
+private:
+
+ CRITICAL_SECTION m_cs;
+};
+
+
+} // windows
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS
+
+#endif // VMIME_PLATFORMS_WINDOWS_CRITICALSECTION_HPP_INCLUDED
diff --git a/vmime/platforms/windows/windowsHandler.hpp b/vmime/platforms/windows/windowsHandler.hpp
index 4f0150f8..ceccae2b 100644
--- a/vmime/platforms/windows/windowsHandler.hpp
+++ b/vmime/platforms/windows/windowsHandler.hpp
@@ -63,6 +63,7 @@ public:
const vmime::string getHostName() const;
unsigned int getProcessId() const;
+ unsigned int getThreadId() const;
#if VMIME_HAVE_MESSAGING_FEATURES
ref <vmime::net::socketFactory> getSocketFactory();
@@ -76,6 +77,10 @@ public:
void wait() const;
+ void generateRandomBytes(unsigned char* buffer, const unsigned int count);
+
+ ref <utility::sync::criticalSection> createCriticalSection();
+
private:
#if VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime/security/cert/X509Certificate.hpp b/vmime/security/cert/X509Certificate.hpp
index 48fc882c..b7f0b946 100644
--- a/vmime/security/cert/X509Certificate.hpp
+++ b/vmime/security/cert/X509Certificate.hpp
@@ -25,6 +25,12 @@
#define VMIME_SECURITY_CERT_X509CERTIFICATE_HPP_INCLUDED
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
#include "vmime/security/cert/certificate.hpp"
#include "vmime/utility/stream.hpp"
@@ -42,13 +48,6 @@ namespace cert {
*/
class X509Certificate : public certificate
{
- friend class vmime::creator;
-
-protected:
-
- X509Certificate();
- X509Certificate(const X509Certificate&);
-
public:
~X509Certificate();
@@ -90,7 +89,7 @@ public:
* @param os output stream into which write data
* @param format output format
*/
- void write(utility::outputStream& os, const Format format) const;
+ virtual void write(utility::outputStream& os, const Format format) const = 0;
/** Returns the X.509 certificate's serial number. This is obtained
* by the X.509 Certificate 'serialNumber' field. Serial is not
@@ -99,7 +98,7 @@ public:
*
* @return serial number of this certificate
*/
- const byteArray getSerialNumber() const;
+ virtual const byteArray getSerialNumber() const = 0;
/** Checks if this certificate has the given issuer.
*
@@ -107,45 +106,34 @@ public:
* @return true if this certificate was issued by the given issuer,
* false otherwise
*/
- bool checkIssuer(ref <const X509Certificate> issuer) const;
+ virtual bool checkIssuer(ref <const X509Certificate> issuer) const = 0;
/** Verifies this certificate against a given trusted one.
*
* @param caCert a certificate that is considered to be trusted one
* @return true if the verification succeeded, false otherwise
*/
- bool verify(ref <const X509Certificate> caCert) const;
+ virtual bool verify(ref <const X509Certificate> caCert) const = 0;
/** Gets the expiration date of this certificate. This is the date
* at which this certificate will not be valid anymore.
*
* @return expiration date of this certificate
*/
- const datetime getExpirationDate() const;
+ virtual const datetime getExpirationDate() const = 0;
/** Gets the activation date of this certificate. This is the date
* at which this certificate will be valid.
*
* @return activation date of this certificate
*/
- const datetime getActivationDate() const;
+ virtual const datetime getActivationDate() const = 0;
/** Returns the fingerprint of this certificate.
*
* @return the fingerprint of this certificate
*/
- const byteArray getFingerprint(const DigestAlgorithm algo) const;
-
-
- // Implementation of 'certificate'
- const byteArray getEncoded() const;
- const string getType() const;
- int getVersion() const;
- bool equals(ref <const certificate> other) const;
-
-private:
-
- struct X509CertificateInternalData* m_data;
+ virtual const byteArray getFingerprint(const DigestAlgorithm algo) const = 0;
};
@@ -154,5 +142,7 @@ private:
} // vmime
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
#endif // VMIME_SECURITY_CERT_X509CERTIFICATE_HPP_INCLUDED
diff --git a/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp b/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp
new file mode 100644
index 00000000..c720c1fb
--- /dev/null
+++ b/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp
@@ -0,0 +1,91 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_SECURITY_CERT_X509CERTIFICATE_GNUTLS_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_X509CERTIFICATE_GNUTLS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/security/cert/X509Certificate.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+class X509Certificate_GnuTLS : public X509Certificate
+{
+ friend class vmime::creator;
+ friend class X509Certificate;
+
+protected:
+
+ X509Certificate_GnuTLS();
+ X509Certificate_GnuTLS(const X509Certificate&);
+
+public:
+
+ ~X509Certificate_GnuTLS();
+
+
+ void write(utility::outputStream& os, const Format format) const;
+
+ const byteArray getSerialNumber() const;
+
+ bool checkIssuer(ref <const X509Certificate> issuer) const;
+
+ bool verify(ref <const X509Certificate> caCert) const;
+
+ const datetime getExpirationDate() const;
+ const datetime getActivationDate() const;
+
+ const byteArray getFingerprint(const DigestAlgorithm algo) const;
+
+
+ // Implementation of 'certificate'
+ const byteArray getEncoded() const;
+ const string getType() const;
+ int getVersion() const;
+ bool equals(ref <const certificate> other) const;
+
+private:
+
+ struct GnuTLSX509CertificateInternalData* m_data;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+#endif // VMIME_SECURITY_CERT_X509CERTIFICATE_GNUTLS_HPP_INCLUDED
+
diff --git a/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp b/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp
new file mode 100644
index 00000000..d9083b06
--- /dev/null
+++ b/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp
@@ -0,0 +1,104 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_SECURITY_CERT_X509CERTIFICATE_OPENSSL_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_X509CERTIFICATE_OPENSSL_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/security/cert/X509Certificate.hpp"
+
+#include <openssl/x509.h>
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+class X509Certificate_OpenSSL : public X509Certificate
+{
+ friend class vmime::creator;
+ friend class X509Certificate;
+
+protected:
+
+ X509Certificate_OpenSSL();
+ X509Certificate_OpenSSL(X509* cert);
+ X509Certificate_OpenSSL(const X509Certificate_OpenSSL&);
+
+public:
+
+ ~X509Certificate_OpenSSL();
+
+
+ void write(utility::outputStream& os, const Format format) const;
+
+ const byteArray getSerialNumber() const;
+
+ bool checkIssuer(ref <const X509Certificate> issuer) const;
+
+ bool verify(ref <const X509Certificate> caCert) const;
+
+ const datetime getExpirationDate() const;
+ const datetime getActivationDate() const;
+
+ const byteArray getFingerprint(const DigestAlgorithm algo) const;
+
+
+ static ref <X509Certificate> importInternal(X509* cert);
+
+
+ // Implementation of 'certificate'
+ const byteArray getEncoded() const;
+ const string getType() const;
+ int getVersion() const;
+ bool equals(ref <const certificate> other) const;
+
+private:
+
+ /** Internal utility function to convert ASN1_TIME
+ * structs to vmime::datetime
+ *
+ * @param pointer to ASN1_TIME struct to convert
+ */
+ const datetime convertX509Date(void* time) const;
+
+ struct OpenSSLX509CertificateInternalData* m_data;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_SECURITY_CERT_X509CERTIFICATE_OPENSSL_HPP_INCLUDED
+
diff --git a/vmime/utility/sync/autoLock.hpp b/vmime/utility/sync/autoLock.hpp
new file mode 100755
index 00000000..1675b78f
--- /dev/null
+++ b/vmime/utility/sync/autoLock.hpp
@@ -0,0 +1,66 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_UTILITY_SYNC_AUTOLOCK_HPP_INCLUDED
+#define VMIME_UTILITY_SYNC_AUTOLOCK_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace sync {
+
+
+/** Critical section wrapper class
+ */
+
+template <class M>
+class autoLock : public object
+{
+public:
+
+ autoLock(ref <M> mutex)
+ : m_mutex(mutex)
+ {
+ m_mutex->lock();
+ }
+
+ ~autoLock()
+ {
+ m_mutex->unlock();
+ }
+
+private:
+
+ ref <M> m_mutex;
+};
+
+
+} // sync
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_SYNC_AUTOLOCK_HPP_INCLUDED
diff --git a/vmime/utility/sync/criticalSection.hpp b/vmime/utility/sync/criticalSection.hpp
new file mode 100755
index 00000000..6a2dc52b
--- /dev/null
+++ b/vmime/utility/sync/criticalSection.hpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2009 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 3 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.
+//
+
+#ifndef VMIME_UTILITY_SYNC_CRITICALSECTION_HPP_INCLUDED
+#define VMIME_UTILITY_SYNC_CRITICALSECTION_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace sync {
+
+
+/** Critical section class.
+ */
+
+class criticalSection : public object
+{
+public:
+
+ virtual ~criticalSection();
+
+ /** Enters the critical section.
+ */
+ virtual void lock() = 0;
+
+ /** Leaves the critical section.
+ */
+ virtual void unlock() = 0;
+
+protected:
+
+ criticalSection();
+ criticalSection(criticalSection&);
+};
+
+
+} // sync
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_SYNC_CRITICALSECTION_HPP_INCLUDED