OpenSSL support (thanks to Mehmet Bozkurt).

This commit is contained in:
Vincent Richard 2012-11-03 09:27:12 +01:00
parent cce1c28bce
commit bc63892291
39 changed files with 3557 additions and 963 deletions

View File

@ -2,7 +2,7 @@
VMIME AUTHOR VMIME AUTHOR
============ ============
Vincent Richard <vincent@vincent-richard.net> Vincent Richard <vincent@vmime.org>
Project owner and creator. VMime was created in 1998, and publicly released Project owner and creator. VMime was created in 1998, and publicly released
under the GNU GPL license in 2003. under the GNU GPL license in 2003.
@ -28,9 +28,10 @@ AUTHORS file.
- Zarafa <http://developer.zarafa.com/VmimePatches> - Zarafa <http://developer.zarafa.com/VmimePatches>
- Bartek Szurgot <vempirelord@wp.pl, http://baszerr.org> - Bartek Szurgot <vempirelord@wp.pl, http://baszerr.org>
- Achim Brandt <http://sourceforge.net/users/a-brandt/> - Achim Brandt <http://sourceforge.net/users/a-brandt/>
- Mehmet Bozkurt <mehmet.bozkurt78@gmail.com> (OpenSSL support)
Please apologize if I have forgotten someone here. ;) Send me an email Please apologize if I have forgotten someone here. ;) Send me an email
to <vincent@vincent-richard.net> if you want your name to be listed. to <vincent@vmime.org> if you want your name to be listed.
See SVN Changelog for full list. See Changelogs for full list.

View File

@ -448,6 +448,7 @@ ENDIF()
# SSL/TLS support # SSL/TLS support
INCLUDE(FindGnuTLS) INCLUDE(FindGnuTLS)
INCLUDE(FindOpenSSL)
INCLUDE(CheckFunctionExists) INCLUDE(CheckFunctionExists)
@ -457,7 +458,7 @@ CHECK_FUNCTION_EXISTS(gnutls_priority_set_direct VMIME_HAVE_GNUTLS_PRIORITY_FUNC
OPTION( OPTION(
VMIME_HAVE_TLS_SUPPORT VMIME_HAVE_TLS_SUPPORT
"SSL/TLS support (requires GNU TLS library)" "SSL/TLS support (requires either GNU TLS or OpenSSL library)"
ON ON
) )
@ -467,6 +468,11 @@ OPTION(
ON ON
) )
OPTION(
VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
"Use OpenSSL library for SSL/TLS support"
OFF
)
IF(VMIME_HAVE_TLS_SUPPORT) 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_CFLAGS "${VMIME_PKGCONFIG_CFLAGS} ${GNUTLS_INCLUDE_DIR}")
SET(VMIME_PKGCONFIG_REQUIRES "${VMIME_PKGCONFIG_REQUIRES} libgnutls") 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() ELSE()
MESSAGE(FATAL_ERROR "TLS support is enabled, but no TLS/SSL library was selected/found") MESSAGE(FATAL_ERROR "TLS support is enabled, but no TLS/SSL library was selected/found")
@ -535,8 +558,14 @@ ENDIF()
# POSIX-specific checks # POSIX-specific checks
INCLUDE(CheckFunctionExists) INCLUDE(CheckFunctionExists)
INCLUDE(CheckSymbolExists)
CHECK_FUNCTION_EXISTS(getaddrinfo VMIME_HAVE_GETADDRINFO) 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_PACKAGE(Threads)
FIND_LIBRARY(PTHREAD pthread) FIND_LIBRARY(PTHREAD pthread)

View File

@ -137,6 +137,8 @@ libvmime_sources = [
'utility/stringUtils.cpp', 'utility/stringUtils.hpp', 'utility/stringUtils.cpp', 'utility/stringUtils.hpp',
'utility/url.cpp', 'utility/url.hpp', 'utility/url.cpp', 'utility/url.hpp',
'utility/urlUtils.cpp', 'utility/urlUtils.hpp', 'utility/urlUtils.cpp', 'utility/urlUtils.hpp',
'utility/sync/autoLock.hpp',
'utility/sync/criticalSection.cpp', 'utility/sync/criticalSection.hpp',
# -- encoder # -- encoder
'utility/encoder/encoder.cpp', 'utility/encoder/encoder.hpp', 'utility/encoder/encoder.cpp', 'utility/encoder/encoder.hpp',
'utility/encoder/sevenBitEncoder.cpp', 'utility/encoder/sevenBitEncoder.hpp', 'utility/encoder/sevenBitEncoder.cpp', 'utility/encoder/sevenBitEncoder.hpp',
@ -210,12 +212,19 @@ libvmime_messaging_sources = [
libvmime_net_tls_sources = [ libvmime_net_tls_sources = [
'net/tls/TLSSession.cpp', 'net/tls/TLSSession.hpp', 'net/tls/TLSSession.cpp', 'net/tls/TLSSession.hpp',
'net/tls/TLSSocket.cpp', 'net/tls/TLSSocket.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', 'net/tls/TLSSecuredConnectionInfos.cpp', 'net/tls/TLSSecuredConnectionInfos.hpp',
'security/cert/certificateChain.cpp', 'security/cert/certificateChain.hpp', 'security/cert/certificateChain.cpp', 'security/cert/certificateChain.hpp',
'security/cert/certificateVerifier.hpp', 'security/cert/certificateVerifier.hpp',
'security/cert/defaultCertificateVerifier.cpp', 'security/cert/defaultCertificateVerifier.hpp', 'security/cert/defaultCertificateVerifier.cpp', 'security/cert/defaultCertificateVerifier.hpp',
'security/cert/certificate.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 = [ libvmime_messaging_proto_sources = [
@ -282,12 +291,14 @@ libvmime_platforms_sources = {
'posix': 'posix':
[ [
'platforms/posix/posixChildProcess.cpp', 'platforms/posix/posixChildProcess.hpp', '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/posixFile.cpp', 'platforms/posix/posixFile.hpp',
'platforms/posix/posixHandler.cpp', 'platforms/posix/posixHandler.hpp', 'platforms/posix/posixHandler.cpp', 'platforms/posix/posixHandler.hpp',
'platforms/posix/posixSocket.cpp', 'platforms/posix/posixSocket.hpp' 'platforms/posix/posixSocket.cpp', 'platforms/posix/posixSocket.hpp'
], ],
'windows': 'windows':
[ [
'platforms/windows/windowsCriticalSection.cpp', 'platforms/windows/windowsCriticalSection.hpp',
'platforms/windows/windowsFile.cpp', 'platforms/windows/windowsFile.hpp', 'platforms/windows/windowsFile.cpp', 'platforms/windows/windowsFile.hpp',
'platforms/windows/windowsHandler.cpp', 'platforms/windows/windowsHandler.hpp', 'platforms/windows/windowsHandler.cpp', 'platforms/windows/windowsHandler.hpp',
'platforms/windows/windowsSocket.cpp', 'platforms/windows/windowsSocket.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 = ['-Wold-style-cast'])
env.Append(CXXFLAGS = ['-Wconversion']) env.Append(CXXFLAGS = ['-Wconversion'])
env.Append(CXXFLAGS = ['-Wcast-align']) env.Append(CXXFLAGS = ['-Wcast-align'])
env.Append(CXXFLAGS = ['-Wno-long-long']) # OpenSSL
#env.Append(CXXFLAGS = ['-Wshadow']) #env.Append(CXXFLAGS = ['-Wshadow'])
env.Append(TARFLAGS = ['-c']) env.Append(TARFLAGS = ['-c'])
@ -614,6 +626,7 @@ if env['with_sasl'] == 'yes':
env.ParseConfig('pkg-config --cflags --libs ' + libgsasl_pc) env.ParseConfig('pkg-config --cflags --libs ' + libgsasl_pc)
if env['with_tls'] == 'yes': if env['with_tls'] == 'yes':
# GnuTLS
libgnutls_pc = string.strip(os.popen("pkg-config --list-all | grep '^libgnutls[ ]' | cut -f 1 -d ' '").read()) libgnutls_pc = string.strip(os.popen("pkg-config --list-all | grep '^libgnutls[ ]' | cut -f 1 -d ' '").read())
if len(libgnutls_pc) == 0: if len(libgnutls_pc) == 0:
@ -625,6 +638,15 @@ if env['with_tls'] == 'yes':
env.ParseConfig('pkg-config --cflags --libs ' + libgnutls_pc) 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']) env.Append(CXXFLAGS = ['-pthread'])
# Generate help text for command line options # Generate help text for command line options
@ -806,6 +828,7 @@ config_hpp.write('// -- TLS/SSL support\n')
if env['with_tls'] == 'yes': if env['with_tls'] == 'yes':
config_hpp.write('#define VMIME_HAVE_TLS_SUPPORT 1\n') 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_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') config_hpp.write('#define VMIME_HAVE_GNUTLS_PRIORITY_FUNCS 1\n')
else: else:
config_hpp.write('#define VMIME_HAVE_TLS_SUPPORT 0\n') 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: if not platform in platforms:
config_hpp.write('#define VMIME_PLATFORM_IS_' + string.upper(platform) + ' 0\n') config_hpp.write('#define VMIME_PLATFORM_IS_' + string.upper(platform) + ' 0\n')
config_hpp.write('#define VMIME_HAVE_GETADDRINFO 1\n') config_hpp.write("""
config_hpp.write('#define VMIME_HAVE_PTHREAD 1\n') #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('\n')
config_hpp.write('// Miscellaneous flags\n') config_hpp.write('// Miscellaneous flags\n')

View File

@ -43,6 +43,7 @@ typedef unsigned @VMIME_32BIT_TYPE@ vmime_uint32;
// -- TLS/SSL support // -- TLS/SSL support
#cmakedefine01 VMIME_HAVE_TLS_SUPPORT #cmakedefine01 VMIME_HAVE_TLS_SUPPORT
#cmakedefine01 VMIME_TLS_SUPPORT_LIB_IS_GNUTLS #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@ #define VMIME_HAVE_GNUTLS_PRIORITY_FUNCS @VMIME_HAVE_GNUTLS_PRIORITY_FUNCS@
// -- Messaging support // -- Messaging support
#cmakedefine01 VMIME_HAVE_MESSAGING_FEATURES #cmakedefine01 VMIME_HAVE_MESSAGING_FEATURES
@ -57,6 +58,9 @@ typedef unsigned @VMIME_32BIT_TYPE@ vmime_uint32;
#cmakedefine01 VMIME_PLATFORM_IS_WINDOWS #cmakedefine01 VMIME_PLATFORM_IS_WINDOWS
#cmakedefine01 VMIME_HAVE_PTHREAD #cmakedefine01 VMIME_HAVE_PTHREAD
#cmakedefine01 VMIME_HAVE_GETADDRINFO #cmakedefine01 VMIME_HAVE_GETADDRINFO
#cmakedefine01 VMIME_HAVE_GETTID
#cmakedefine01 VMIME_HAVE_SYSCALL
#cmakedefine01 VMIME_HAVE_SYSCALL_GETTID
#define VMIME_SENDMAIL_PATH "@VMIME_SENDMAIL_PATH@" #define VMIME_SENDMAIL_PATH "@VMIME_SENDMAIL_PATH@"

View File

@ -111,7 +111,7 @@ void IMAPConnection::connect()
if (store->isIMAPS()) // dedicated port/IMAPS if (store->isIMAPS()) // dedicated port/IMAPS
{ {
ref <tls::TLSSession> tlsSession = ref <tls::TLSSession> tlsSession =
vmime::create <tls::TLSSession>(store->getCertificateVerifier()); tls::TLSSession::create(store->getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket = ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket); tlsSession->getSocket(m_socket);
@ -460,7 +460,7 @@ void IMAPConnection::startTLS()
} }
ref <tls::TLSSession> tlsSession = ref <tls::TLSSession> tlsSession =
vmime::create <tls::TLSSession>(m_store.acquire()->getCertificateVerifier()); tls::TLSSession::create(m_store.acquire()->getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket = ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket); tlsSession->getSocket(m_socket);

View File

@ -151,7 +151,7 @@ void POP3Store::connect()
if (m_isPOP3S) // dedicated port/POP3S if (m_isPOP3S) // dedicated port/POP3S
{ {
ref <tls::TLSSession> tlsSession = ref <tls::TLSSession> tlsSession =
vmime::create <tls::TLSSession>(getCertificateVerifier()); tls::TLSSession::create(getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket = ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket); tlsSession->getSocket(m_socket);
@ -550,7 +550,7 @@ void POP3Store::startTLS()
throw exceptions::command_error("STLS", response); throw exceptions::command_error("STLS", response);
ref <tls::TLSSession> tlsSession = ref <tls::TLSSession> tlsSession =
vmime::create <tls::TLSSession>(getCertificateVerifier()); tls::TLSSession::create(getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket = ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket); tlsSession->getSocket(m_socket);

View File

@ -114,7 +114,7 @@ void SMTPTransport::connect()
if (m_isSMTPS) // dedicated port/SMTPS if (m_isSMTPS) // dedicated port/SMTPS
{ {
ref <tls::TLSSession> tlsSession = ref <tls::TLSSession> tlsSession =
vmime::create <tls::TLSSession>(getCertificateVerifier()); tls::TLSSession::create(getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket = ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket); tlsSession->getSocket(m_socket);
@ -463,7 +463,7 @@ void SMTPTransport::startTLS()
throw exceptions::command_error("STARTTLS", resp->getText()); throw exceptions::command_error("STARTTLS", resp->getText());
ref <tls::TLSSession> tlsSession = ref <tls::TLSSession> tlsSession =
vmime::create <tls::TLSSession>(getCertificateVerifier()); tls::TLSSession::create(getCertificateVerifier());
ref <tls::TLSSocket> tlsSocket = ref <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket); tlsSession->getSocket(m_socket);

View File

@ -24,268 +24,19 @@
#include "vmime/config.hpp" #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/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 vmime {
namespace net { namespace net {
namespace tls { namespace tls {
#ifndef VMIME_BUILDING_DOC TLSSession::TLSSession()
// 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)
{
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 } // 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

View File

@ -24,18 +24,10 @@
#include "vmime/config.hpp" #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/TLSSocket.hpp"
#include "vmime/net/tls/TLSSession.hpp"
#include "vmime/platform.hpp"
#include "vmime/security/cert/X509Certificate.hpp"
namespace vmime { namespace vmime {
@ -43,375 +35,10 @@ namespace net {
namespace tls { 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 } // tls
} // net } // net
} // vmime } // 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

View File

@ -0,0 +1,304 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,424 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,152 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,138 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,416 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,67 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -29,8 +29,10 @@
#include "vmime/platforms/posix/posixHandler.hpp" #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 <unistd.h>
#include <locale.h> #include <locale.h>
#include <langinfo.h> #include <langinfo.h>
@ -39,10 +41,15 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#if VMIME_HAVE_SYSCALL
# include <sys/syscall.h>
#endif
#include <netdb.h> #include <netdb.h>
#include <string.h> #include <string.h>
#include <cassert> #include <cassert>
#include <cstdlib>
#if VMIME_HAVE_PTHREAD #if VMIME_HAVE_PTHREAD
# include <pthread.h> # 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 #if VMIME_HAVE_MESSAGING_FEATURES
ref <vmime::net::socketFactory> posixHandler::getSocketFactory() 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 } // posix
} // platforms } // platforms
} // vmime } // vmime

View File

@ -0,0 +1,67 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -29,6 +29,8 @@
#include "vmime/platforms/windows/windowsHandler.hpp" #include "vmime/platforms/windows/windowsHandler.hpp"
#include "vmime/platforms/windows/windowsCriticalSection.hpp"
#include <time.h> #include <time.h>
#include <locale.h> #include <locale.h>
#include <process.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 #if VMIME_HAVE_MESSAGING_FEATURES
ref <vmime::net::socketFactory> windowsHandler::getSocketFactory() 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 } // posix
} // platforms } // platforms
} // vmime } // vmime

View File

@ -21,240 +21,22 @@
// the GNU General Public License cover the whole combination. // the GNU General Public License cover the whole combination.
// //
#include <gnutls/gnutls.h> #include "vmime/config.hpp"
#include <gnutls/x509.h>
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#include <ctime>
#include "vmime/security/cert/X509Certificate.hpp" #include "vmime/security/cert/X509Certificate.hpp"
#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
namespace vmime { namespace vmime {
namespace security { namespace security {
namespace cert { 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() 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 } // security
} // vmime } // vmime
#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT

View File

@ -0,0 +1,278 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,467 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,44 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -28,7 +28,7 @@
#include "vmime/config.hpp" #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" #include "vmime/types.hpp"
@ -47,19 +47,15 @@ namespace tls {
*/ */
class TLSSession : public object class TLSSession : public object
{ {
friend class TLSSocket;
public: public:
~TLSSession();
/** Create and initialize a new TLS session. /** Create and initialize a new TLS session.
* *
* @param cv object responsible for verifying certificates * @param cv object responsible for verifying certificates
* sent by the server * sent by the server
* @return a new TLS session * @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 /** Create a new socket that adds a TLS security layer around
* an existing socket. You should create only one socket * an existing socket. You should create only one socket
@ -68,27 +64,20 @@ public:
* @param sok socket to wrap * @param sok socket to wrap
* @return TLS socket wrapper * @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 /** Get the object responsible for verifying certificates when
* using secured connections (TLS/SSL). * using secured connections (TLS/SSL).
*/ */
ref <security::cert::certificateVerifier> getCertificateVerifier(); virtual ref <security::cert::certificateVerifier> getCertificateVerifier() = 0;
protected:
TLSSession();
private: private:
TLSSession(const TLSSession&); TLSSession(const TLSSession&);
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;
}; };
@ -97,7 +86,6 @@ private:
} // vmime } // 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 #endif // VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED

View File

@ -28,7 +28,7 @@
#include "vmime/config.hpp" #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" #include "vmime/exception.hpp"
@ -51,9 +51,7 @@ class TLSSession;
*/ */
class TLSSocket : public socket class TLSSocket : public socket
{ {
friend class vmime::creator; public:
protected:
/** Create a new socket object that adds a security layer /** Create a new socket object that adds a security layer
* around an existing socket. * around an existing socket.
@ -61,12 +59,7 @@ protected:
* @param session TLS session * @param session TLS session
* @param sok socket to wrap * @param sok socket to wrap
*/ */
TLSSocket(ref <TLSSession> session, ref <socket> sok); static ref <TLSSocket> wrap(ref <TLSSession> session, ref <socket> sok);
public:
~TLSSocket();
/** Starts a TLS handshake on this connection. /** Starts a TLS handshake on this connection.
* *
@ -74,53 +67,14 @@ public:
* during the negociation process, exceptions::operation_timed_out * during the negociation process, exceptions::operation_timed_out
* if a time-out occurs * 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 the peer's certificate (chain) as sent by the peer.
* *
* @return server certificate chain, or NULL if the handshake * @return server certificate chain, or NULL if the handshake
* has not been performed yet * has not been performed yet
*/ */
ref <security::cert::certificateChain> getPeerCertificates() const; virtual ref <security::cert::certificateChain> getPeerCertificates() const = 0;
// 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;
}; };
@ -129,7 +83,6 @@ private:
} // vmime } // 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 #endif // VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED

View File

@ -0,0 +1,89 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,113 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,102 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,106 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,116 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -40,6 +40,8 @@
#include "vmime/utility/childProcess.hpp" #include "vmime/utility/childProcess.hpp"
#endif #endif
#include "vmime/utility/sync/criticalSection.hpp"
namespace vmime namespace vmime
{ {
@ -89,6 +91,13 @@ public:
*/ */
virtual unsigned int getProcessId() const = 0; 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 the charset used on the system.
* *
* @return locale charset * @return locale charset
@ -126,6 +135,16 @@ public:
virtual ref <utility::childProcessFactory> getChildProcessFactory() = 0; virtual ref <utility::childProcessFactory> getChildProcessFactory() = 0;
#endif #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;
}; };

View File

@ -0,0 +1,69 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -64,6 +64,7 @@ public:
const vmime::string getHostName() const; const vmime::string getHostName() const;
unsigned int getProcessId() const; unsigned int getProcessId() const;
unsigned int getThreadId() const;
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
ref <vmime::net::socketFactory> getSocketFactory(); ref <vmime::net::socketFactory> getSocketFactory();
@ -77,6 +78,10 @@ public:
void wait() const; void wait() const;
void generateRandomBytes(unsigned char* buffer, const unsigned int count);
ref <utility::sync::criticalSection> createCriticalSection();
private: private:
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES

View File

@ -0,0 +1,68 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -63,6 +63,7 @@ public:
const vmime::string getHostName() const; const vmime::string getHostName() const;
unsigned int getProcessId() const; unsigned int getProcessId() const;
unsigned int getThreadId() const;
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
ref <vmime::net::socketFactory> getSocketFactory(); ref <vmime::net::socketFactory> getSocketFactory();
@ -76,6 +77,10 @@ public:
void wait() const; void wait() const;
void generateRandomBytes(unsigned char* buffer, const unsigned int count);
ref <utility::sync::criticalSection> createCriticalSection();
private: private:
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES

View File

@ -25,6 +25,12 @@
#define VMIME_SECURITY_CERT_X509CERTIFICATE_HPP_INCLUDED #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/security/cert/certificate.hpp"
#include "vmime/utility/stream.hpp" #include "vmime/utility/stream.hpp"
@ -42,13 +48,6 @@ namespace cert {
*/ */
class X509Certificate : public certificate class X509Certificate : public certificate
{ {
friend class vmime::creator;
protected:
X509Certificate();
X509Certificate(const X509Certificate&);
public: public:
~X509Certificate(); ~X509Certificate();
@ -90,7 +89,7 @@ public:
* @param os output stream into which write data * @param os output stream into which write data
* @param format output format * @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 /** Returns the X.509 certificate's serial number. This is obtained
* by the X.509 Certificate 'serialNumber' field. Serial is not * by the X.509 Certificate 'serialNumber' field. Serial is not
@ -99,7 +98,7 @@ public:
* *
* @return serial number of this certificate * @return serial number of this certificate
*/ */
const byteArray getSerialNumber() const; virtual const byteArray getSerialNumber() const = 0;
/** Checks if this certificate has the given issuer. /** Checks if this certificate has the given issuer.
* *
@ -107,45 +106,34 @@ public:
* @return true if this certificate was issued by the given issuer, * @return true if this certificate was issued by the given issuer,
* false otherwise * 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. /** Verifies this certificate against a given trusted one.
* *
* @param caCert a certificate that is considered to be trusted one * @param caCert a certificate that is considered to be trusted one
* @return true if the verification succeeded, false otherwise * @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 /** Gets the expiration date of this certificate. This is the date
* at which this certificate will not be valid anymore. * at which this certificate will not be valid anymore.
* *
* @return expiration date of this certificate * @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 /** Gets the activation date of this certificate. This is the date
* at which this certificate will be valid. * at which this certificate will be valid.
* *
* @return activation date of this certificate * @return activation date of this certificate
*/ */
const datetime getActivationDate() const; virtual const datetime getActivationDate() const = 0;
/** Returns the fingerprint of this certificate. /** Returns the fingerprint of this certificate.
* *
* @return the fingerprint of this certificate * @return the fingerprint of this certificate
*/ */
const byteArray getFingerprint(const DigestAlgorithm algo) const; virtual const byteArray getFingerprint(const DigestAlgorithm algo) const = 0;
// 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;
}; };
@ -154,5 +142,7 @@ private:
} // vmime } // vmime
#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#endif // VMIME_SECURITY_CERT_X509CERTIFICATE_HPP_INCLUDED #endif // VMIME_SECURITY_CERT_X509CERTIFICATE_HPP_INCLUDED

View File

@ -0,0 +1,91 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,104 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

66
vmime/utility/sync/autoLock.hpp Executable file
View File

@ -0,0 +1,66 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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

View File

@ -0,0 +1,65 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2009 Vincent Richard <vincent@vincent-richard.net>
//
// 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