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
============
Vincent Richard <vincent@vincent-richard.net>
Vincent Richard <vincent@vmime.org>
Project owner and creator. VMime was created in 1998, and publicly released
under the GNU GPL license in 2003.
@ -28,9 +28,10 @@ AUTHORS file.
- Zarafa <http://developer.zarafa.com/VmimePatches>
- Bartek Szurgot <vempirelord@wp.pl, http://baszerr.org>
- 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
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
INCLUDE(FindGnuTLS)
INCLUDE(FindOpenSSL)
INCLUDE(CheckFunctionExists)
@ -457,7 +458,7 @@ CHECK_FUNCTION_EXISTS(gnutls_priority_set_direct VMIME_HAVE_GNUTLS_PRIORITY_FUNC
OPTION(
VMIME_HAVE_TLS_SUPPORT
"SSL/TLS support (requires GNU TLS library)"
"SSL/TLS support (requires either GNU TLS or OpenSSL library)"
ON
)
@ -467,6 +468,11 @@ OPTION(
ON
)
OPTION(
VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
"Use OpenSSL library for SSL/TLS support"
OFF
)
IF(VMIME_HAVE_TLS_SUPPORT)
@ -492,6 +498,23 @@ IF(VMIME_HAVE_TLS_SUPPORT)
SET(VMIME_PKGCONFIG_CFLAGS "${VMIME_PKGCONFIG_CFLAGS} ${GNUTLS_INCLUDE_DIR}")
SET(VMIME_PKGCONFIG_REQUIRES "${VMIME_PKGCONFIG_REQUIRES} libgnutls")
ELSEIF(VMIME_TLS_SUPPORT_LIB_IS_OPENSSL)
INCLUDE_DIRECTORIES(
${INCLUDE_DIRECTORIES}
${OPENSSL_INCLUDE_DIR}
)
TARGET_LINK_LIBRARIES(
${VMIME_LIBRARY_NAME}
${TARGET_LINK_LIBRARIES}
${OPENSSL_LIBRARIES}
)
SET(VMIME_PKGCONFIG_LIBS "${VMIME_PKGCONFIG_LIBS} ${OPENSSL_LIBRARIES}")
SET(VMIME_PKGCONFIG_CFLAGS "${VMIME_PKGCONFIG_CFLAGS} ${OPENSSL_INCLUDE_DIR}")
SET(VMIME_PKGCONFIG_REQUIRES "${VMIME_PKGCONFIG_REQUIRES} libopenssl")
ELSE()
MESSAGE(FATAL_ERROR "TLS support is enabled, but no TLS/SSL library was selected/found")
@ -535,8 +558,14 @@ ENDIF()
# POSIX-specific checks
INCLUDE(CheckFunctionExists)
INCLUDE(CheckSymbolExists)
CHECK_FUNCTION_EXISTS(getaddrinfo VMIME_HAVE_GETADDRINFO)
CHECK_FUNCTION_EXISTS(gettid VMIME_HAVE_GETTID)
CHECK_FUNCTION_EXISTS(syscall VMIME_HAVE_SYSCALL)
CHECK_SYMBOL_EXISTS(SYS_gettid sys/syscall.h VMIME_HAVE_SYSCALL_GETTID)
FIND_PACKAGE(Threads)
FIND_LIBRARY(PTHREAD pthread)

View File

@ -137,6 +137,8 @@ libvmime_sources = [
'utility/stringUtils.cpp', 'utility/stringUtils.hpp',
'utility/url.cpp', 'utility/url.hpp',
'utility/urlUtils.cpp', 'utility/urlUtils.hpp',
'utility/sync/autoLock.hpp',
'utility/sync/criticalSection.cpp', 'utility/sync/criticalSection.hpp',
# -- encoder
'utility/encoder/encoder.cpp', 'utility/encoder/encoder.hpp',
'utility/encoder/sevenBitEncoder.cpp', 'utility/encoder/sevenBitEncoder.hpp',
@ -210,12 +212,19 @@ libvmime_messaging_sources = [
libvmime_net_tls_sources = [
'net/tls/TLSSession.cpp', 'net/tls/TLSSession.hpp',
'net/tls/TLSSocket.cpp', 'net/tls/TLSSocket.hpp',
'net/tls/gnutls/TLSSession_GnuTLS.cpp', 'net/tls/gnutls/TLSSession_GnuTLS.hpp',
'net/tls/gnutls/TLSSocket_GnuTLS.cpp', 'net/tls/gnutls/TLSSocket_GnuTLS.hpp',
'net/tls/openssl/TLSSession_OpenSSL.cpp', 'net/tls/openssl/TLSSession_OpenSSL.hpp',
'net/tls/openssl/TLSSocket_OpenSSL.cpp', 'net/tls/openssl/TLSSocket_OpenSSL.hpp',
'net/tls/openssl/OpenSSLInitializer.cpp', 'net/tls/openssl/OpenSSLInitializer.hpp',
'net/tls/TLSSecuredConnectionInfos.cpp', 'net/tls/TLSSecuredConnectionInfos.hpp',
'security/cert/certificateChain.cpp', 'security/cert/certificateChain.hpp',
'security/cert/certificateVerifier.hpp',
'security/cert/defaultCertificateVerifier.cpp', 'security/cert/defaultCertificateVerifier.hpp',
'security/cert/certificate.hpp',
'security/cert/X509Certificate.cpp', 'security/cert/X509Certificate.hpp'
'security/cert/X509Certificate.cpp', 'security/cert/X509Certificate.hpp',
'security/cert/gnutls/X509Certificate_GnuTLS.cpp', 'security/cert/gnutls/X509Certificate_GnuTLS.hpp',
'security/cert/openssl/X509Certificate_OpenSSL.cpp', 'security/cert/openssl/X509Certificate_OpenSSL.hpp'
]
libvmime_messaging_proto_sources = [
@ -282,12 +291,14 @@ libvmime_platforms_sources = {
'posix':
[
'platforms/posix/posixChildProcess.cpp', 'platforms/posix/posixChildProcess.hpp',
'platforms/posix/posixCriticalSection.cpp', 'platforms/posix/posixCriticalSection.hpp',
'platforms/posix/posixFile.cpp', 'platforms/posix/posixFile.hpp',
'platforms/posix/posixHandler.cpp', 'platforms/posix/posixHandler.hpp',
'platforms/posix/posixSocket.cpp', 'platforms/posix/posixSocket.hpp'
],
'windows':
[
'platforms/windows/windowsCriticalSection.cpp', 'platforms/windows/windowsCriticalSection.hpp',
'platforms/windows/windowsFile.cpp', 'platforms/windows/windowsFile.hpp',
'platforms/windows/windowsHandler.cpp', 'platforms/windows/windowsHandler.hpp',
'platforms/windows/windowsSocket.cpp', 'platforms/windows/windowsSocket.hpp'
@ -590,6 +601,7 @@ env.Append(CXXFLAGS = ['-Wpointer-arith'])
env.Append(CXXFLAGS = ['-Wold-style-cast'])
env.Append(CXXFLAGS = ['-Wconversion'])
env.Append(CXXFLAGS = ['-Wcast-align'])
env.Append(CXXFLAGS = ['-Wno-long-long']) # OpenSSL
#env.Append(CXXFLAGS = ['-Wshadow'])
env.Append(TARFLAGS = ['-c'])
@ -614,6 +626,7 @@ if env['with_sasl'] == 'yes':
env.ParseConfig('pkg-config --cflags --libs ' + libgsasl_pc)
if env['with_tls'] == 'yes':
# GnuTLS
libgnutls_pc = string.strip(os.popen("pkg-config --list-all | grep '^libgnutls[ ]' | cut -f 1 -d ' '").read())
if len(libgnutls_pc) == 0:
@ -625,6 +638,15 @@ if env['with_tls'] == 'yes':
env.ParseConfig('pkg-config --cflags --libs ' + libgnutls_pc)
# OpenSSL
libopenssl_pc = string.strip(os.popen("pkg-config --list-all | grep '^openssl[ ]' | cut -f 1 -d ' '").read())
if len(libopenssl_pc) == 0:
print "ERROR: OpenSSL development package is not installed\n"
Exit(1)
env.ParseConfig('pkg-config --cflags --libs ' + libopenssl_pc)
env.Append(CXXFLAGS = ['-pthread'])
# Generate help text for command line options
@ -806,6 +828,7 @@ config_hpp.write('// -- TLS/SSL support\n')
if env['with_tls'] == 'yes':
config_hpp.write('#define VMIME_HAVE_TLS_SUPPORT 1\n')
config_hpp.write('#define VMIME_TLS_SUPPORT_LIB_IS_GNUTLS 1\n')
config_hpp.write('#define VMIME_TLS_SUPPORT_LIB_IS_OPENSSL 0\n')
config_hpp.write('#define VMIME_HAVE_GNUTLS_PRIORITY_FUNCS 1\n')
else:
config_hpp.write('#define VMIME_HAVE_TLS_SUPPORT 0\n')
@ -834,8 +857,13 @@ for platform in libvmime_platforms_sources:
if not platform in platforms:
config_hpp.write('#define VMIME_PLATFORM_IS_' + string.upper(platform) + ' 0\n')
config_hpp.write('#define VMIME_HAVE_GETADDRINFO 1\n')
config_hpp.write('#define VMIME_HAVE_PTHREAD 1\n')
config_hpp.write("""
#define VMIME_HAVE_GETADDRINFO 1
#define VMIME_HAVE_PTHREAD 1
#define VMIME_HAVE_GETTID 0
#define VMIME_HAVE_SYSCALL 1
#define VMIME_HAVE_SYSCALL_GETTID 1
""")
config_hpp.write('\n')
config_hpp.write('// Miscellaneous flags\n')

View File

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

View File

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

View File

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

View File

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

View File

@ -24,268 +24,19 @@
#include "vmime/config.hpp"
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#include <gnutls/gnutls.h>
#if GNUTLS_VERSION_NUMBER < 0x030000
#include <gnutls/extra.h>
#endif
// Dependency on gcrypt is not needed since GNU TLS version 2.12.
// See here: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=638651
#if GNUTLS_VERSION_NUMBER <= 0x020b00
# define VMIME_GNUTLS_NEEDS_GCRYPT 1
#endif
#if VMIME_HAVE_PTHREAD
# include <pthread.h>
# if VMIME_GNUTLS_NEEDS_GCRYPT
# include <gcrypt.h>
# endif
# include <errno.h>
#endif // VMIME_HAVE_PTHREAD
#include "vmime/net/tls/TLSSession.hpp"
#include "vmime/exception.hpp"
// Enable GnuTLS debugging by defining GNUTLS_DEBUG
//#define GNUTLS_DEBUG 1
#include <sstream>
#include <iomanip>
#if VMIME_DEBUG && GNUTLS_DEBUG
#include <iostream>
#endif // VMIME_DEBUG && GNUTLS_DEBUG
#if VMIME_HAVE_PTHREAD && VMIME_GNUTLS_NEEDS_GCRYPT && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL)
extern "C"
{
GCRY_THREAD_OPTION_PTHREAD_IMPL;
}
#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL
namespace vmime {
namespace net {
namespace tls {
#ifndef VMIME_BUILDING_DOC
// Initialize GNU TLS library
struct TLSGlobal
TLSSession::TLSSession()
{
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
#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"
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "vmime/net/tls/TLSSocket.hpp"
#include "vmime/net/tls/TLSSession.hpp"
#include "vmime/platform.hpp"
#include "vmime/security/cert/X509Certificate.hpp"
namespace vmime {
@ -43,375 +35,10 @@ namespace net {
namespace tls {
TLSSocket::TLSSocket(ref <TLSSession> session, ref <socket> sok)
: m_session(session), m_wrapped(sok), m_connected(false),
m_handshaking(false), m_ex(NULL)
{
gnutls_transport_set_ptr(*m_session->m_gnutlsSession, this);
gnutls_transport_set_push_function(*m_session->m_gnutlsSession, gnutlsPushFunc);
gnutls_transport_set_pull_function(*m_session->m_gnutlsSession, gnutlsPullFunc);
}
TLSSocket::~TLSSocket()
{
if (m_ex)
{
delete m_ex;
m_ex = NULL;
}
try
{
disconnect();
}
catch (...)
{
// Don't throw exception in destructor
}
}
void TLSSocket::connect(const string& address, const port_t port)
{
m_wrapped->connect(address, port);
handshake(NULL);
m_connected = true;
}
void TLSSocket::disconnect()
{
if (m_connected)
{
gnutls_bye(*m_session->m_gnutlsSession, GNUTLS_SHUT_RDWR);
m_wrapped->disconnect();
m_connected = false;
}
}
bool TLSSocket::isConnected() const
{
return m_wrapped->isConnected() && m_connected;
}
TLSSocket::size_type TLSSocket::getBlockSize() const
{
return 16384; // 16 KB
}
void TLSSocket::receive(string& buffer)
{
const int size = receiveRaw(m_buffer, sizeof(m_buffer));
buffer = vmime::string(m_buffer, size);
}
void TLSSocket::send(const string& buffer)
{
sendRaw(buffer.data(), buffer.length());
}
TLSSocket::size_type TLSSocket::receiveRaw(char* buffer, const size_type count)
{
const ssize_t ret = gnutls_record_recv
(*m_session->m_gnutlsSession,
buffer, static_cast <size_t>(count));
if (m_ex)
internalThrow();
if (ret < 0)
{
if (ret == GNUTLS_E_AGAIN)
return 0;
TLSSession::throwTLSException("gnutls_record_recv", ret);
}
return static_cast <int>(ret);
}
void TLSSocket::sendRaw(const char* buffer, const size_type count)
{
gnutls_record_send
(*m_session->m_gnutlsSession,
buffer, static_cast <size_t>(count));
if (m_ex)
internalThrow();
}
void TLSSocket::handshake(ref <timeoutHandler> toHandler)
{
if (toHandler)
toHandler->resetTimeOut();
// Start handshaking process
m_handshaking = true;
m_toHandler = toHandler;
try
{
while (true)
{
const int ret = gnutls_handshake(*m_session->m_gnutlsSession);
if (m_ex)
internalThrow();
if (ret < 0)
{
if (ret == GNUTLS_E_AGAIN ||
ret == GNUTLS_E_INTERRUPTED)
{
// Non-fatal error
platform::getHandler()->wait();
}
else
{
TLSSession::throwTLSException("gnutls_handshake", ret);
}
}
else
{
// Successful handshake
break;
}
}
}
catch (...)
{
m_handshaking = false;
m_toHandler = NULL;
throw;
}
m_handshaking = false;
m_toHandler = NULL;
// Verify server's certificate(s)
ref <security::cert::certificateChain> certs = getPeerCertificates();
if (certs == NULL)
throw exceptions::tls_exception("No peer certificate.");
m_session->getCertificateVerifier()->verify(certs);
m_connected = true;
}
ssize_t TLSSocket::gnutlsPushFunc
(gnutls_transport_ptr trspt, const void* data, size_t len)
{
TLSSocket* sok = reinterpret_cast <TLSSocket*>(trspt);
try
{
sok->m_wrapped->sendRaw
(reinterpret_cast <const char*>(data), static_cast <int>(len));
}
catch (exception& e)
{
// Workaround for bad behaviour when throwing C++ exceptions
// from C functions (GNU TLS)
sok->m_ex = e.clone();
return -1;
}
return len;
}
ssize_t TLSSocket::gnutlsPullFunc
(gnutls_transport_ptr trspt, void* data, size_t len)
{
TLSSocket* sok = reinterpret_cast <TLSSocket*>(trspt);
try
{
// Workaround for cross-platform asynchronous handshaking:
// gnutls_handshake() only returns GNUTLS_E_AGAIN if recv()
// returns -1 and errno is set to EGAIN...
if (sok->m_handshaking)
{
while (true)
{
const ssize_t ret = static_cast <ssize_t>
(sok->m_wrapped->receiveRaw
(reinterpret_cast <char*>(data),
static_cast <int>(len)));
if (ret == 0)
{
// No data available yet
platform::getHandler()->wait();
}
else
{
return ret;
}
// Check whether the time-out delay is elapsed
if (sok->m_toHandler && sok->m_toHandler->isTimeOut())
{
if (!sok->m_toHandler->handleTimeOut())
throw exceptions::operation_timed_out();
sok->m_toHandler->resetTimeOut();
}
}
}
else
{
const ssize_t n = static_cast <ssize_t>
(sok->m_wrapped->receiveRaw
(reinterpret_cast <char*>(data),
static_cast <int>(len)));
if (n == 0)
return GNUTLS_E_AGAIN; // This seems like a hack, really...
return n;
}
}
catch (exception& e)
{
// Workaround for bad behaviour when throwing C++ exceptions
// from C functions (GNU TLS)
sok->m_ex = e.clone();
return -1;
}
}
ref <security::cert::certificateChain> TLSSocket::getPeerCertificates() const
{
unsigned int certCount = 0;
const gnutls_datum* rawData = gnutls_certificate_get_peers
(*m_session->m_gnutlsSession, &certCount);
if (rawData == NULL)
return NULL;
// Try X.509
gnutls_x509_crt* x509Certs = new gnutls_x509_crt[certCount];
for (unsigned int i = 0; i < certCount; ++i)
{
gnutls_x509_crt_init(x509Certs + i);
int res = gnutls_x509_crt_import(x509Certs[i], rawData + i,
GNUTLS_X509_FMT_DER);
if (res < 0)
{
// XXX more fine-grained error reporting?
delete [] x509Certs;
return NULL;
}
}
{
std::vector <ref <security::cert::certificate> > certs;
bool error = false;
for (unsigned int i = 0 ; i < certCount ; ++i)
{
size_t dataSize = 0;
gnutls_x509_crt_export(x509Certs[i],
GNUTLS_X509_FMT_DER, NULL, &dataSize);
std::vector <byte_t> data(dataSize);
gnutls_x509_crt_export(x509Certs[i],
GNUTLS_X509_FMT_DER, &data[0], &dataSize);
ref <security::cert::X509Certificate> cert =
security::cert::X509Certificate::import(&data[0], dataSize);
if (cert != NULL)
certs.push_back(cert);
else
error = true;
gnutls_x509_crt_deinit(x509Certs[i]);
}
delete [] x509Certs;
if (error)
return NULL;
return vmime::create <security::cert::certificateChain>(certs);
}
delete [] x509Certs;
return NULL;
}
// Following is a workaround for C++ exceptions to pass correctly between
// C and C++ calls.
//
// gnutls_record_recv() calls TLSSocket::gnutlsPullFunc, and exceptions
// thrown by the socket can not be caught.
#ifndef VMIME_BUILDING_DOC
class TLSSocket_DeleteExWrapper : public object
{
public:
TLSSocket_DeleteExWrapper(exception* ex) : m_ex(ex) { }
~TLSSocket_DeleteExWrapper() { delete m_ex; }
private:
exception* m_ex;
};
#endif // VMIME_BUILDING_DOC
void TLSSocket::internalThrow()
{
static std::vector <ref <TLSSocket_DeleteExWrapper> > exToDelete;
if (m_ex)
{
// Reset the current exception pointer to prevent the same
// exception from being thrown again later
exception* ex = m_ex;
m_ex = NULL;
// To avoid memory leaks
exToDelete.push_back(vmime::create <TLSSocket_DeleteExWrapper>(ex));
throw *ex;
}
}
} // tls
} // net
} // vmime
#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT

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 <time.h>
#include "vmime/platforms/posix/posixCriticalSection.hpp"
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <locale.h>
#include <langinfo.h>
@ -39,10 +41,15 @@
#include <sys/types.h>
#include <sys/stat.h>
#if VMIME_HAVE_SYSCALL
# include <sys/syscall.h>
#endif
#include <netdb.h>
#include <string.h>
#include <cassert>
#include <cstdlib>
#if VMIME_HAVE_PTHREAD
# include <pthread.h>
@ -217,6 +224,18 @@ unsigned int posixHandler::getProcessId() const
}
unsigned int posixHandler::getThreadId() const
{
#if VMIME_HAVE_GETTID
return static_cast <unsigned int>(::gettid());
#elif VMIME_HAVE_SYSCALL && VMIME_HAVE_SYSCALL_GETTID
return static_cast <unsigned int>(::syscall(SYS_gettid));
#else
#error We have no implementation of getThreadId() for this platform!
#endif
}
#if VMIME_HAVE_MESSAGING_FEATURES
ref <vmime::net::socketFactory> posixHandler::getSocketFactory()
@ -261,6 +280,29 @@ void posixHandler::wait() const
}
void posixHandler::generateRandomBytes(unsigned char* buffer, const unsigned int count)
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd != -1)
{
read(fd, buffer, count);
close(fd);
}
else // fallback
{
for (unsigned int i = 0 ; i < count ; ++i)
buffer[i] = static_cast <unsigned char>(rand() % 255);
}
}
ref <utility::sync::criticalSection> posixHandler::createCriticalSection()
{
return vmime::create <posixCriticalSection>();
}
} // posix
} // platforms
} // vmime

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/windowsCriticalSection.hpp"
#include <time.h>
#include <locale.h>
#include <process.h>
@ -239,6 +241,12 @@ unsigned int windowsHandler::getProcessId() const
}
unsigned int windowsHandler::getThreadId() cont
{
return static_cast <unsigned int>(::GetCurrentThreadId());
}
#if VMIME_HAVE_MESSAGING_FEATURES
ref <vmime::net::socketFactory> windowsHandler::getSocketFactory()
@ -272,6 +280,21 @@ void windowsHandler::wait() const
}
void windowsHandler::generateRandomBytes(unsigned char* buffer, const unsigned int count)
{
HCRYPTPROV cryptProvider = 0;
CryptAcquireContext(&cryptProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
CryptGenRandom(cryptProvider, static_cast <unsigned long>(count), static_cast <unsigned char*>(buffer));
CryptReleaseContext(cryptProvider, 0);
}
ref <utility::sync::criticalSection> posixHandler::createCriticalSection()
{
return vmime::create <windowsCriticalSection>();
}
} // posix
} // platforms
} // vmime

View File

@ -21,240 +21,22 @@
// the GNU General Public License cover the whole combination.
//
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "vmime/config.hpp"
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#include <ctime>
#include "vmime/security/cert/X509Certificate.hpp"
#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
namespace vmime {
namespace security {
namespace cert {
#ifndef VMIME_BUILDING_DOC
struct X509CertificateInternalData
{
X509CertificateInternalData()
{
gnutls_x509_crt_init(&cert);
}
~X509CertificateInternalData()
{
gnutls_x509_crt_deinit(cert);
}
gnutls_x509_crt cert;
};
#endif // VMIME_BUILDING_DOC
X509Certificate::X509Certificate()
: m_data(new X509CertificateInternalData)
{
}
X509Certificate::X509Certificate(const X509Certificate&)
: certificate(), m_data(NULL)
{
// Not used
}
X509Certificate::~X509Certificate()
{
delete m_data;
}
// static
ref <X509Certificate> X509Certificate::import(utility::inputStream& is)
{
byteArray bytes;
utility::stream::value_type chunk[4096];
while (!is.eof())
{
const int len = is.read(chunk, sizeof(chunk));
bytes.insert(bytes.end(), chunk, chunk + len);
}
return import(&bytes[0], bytes.size());
}
// static
ref <X509Certificate> X509Certificate::import
(const byte_t* data, const unsigned int length)
{
gnutls_datum buffer;
buffer.data = const_cast <byte_t*>(data);
buffer.size = length;
// Try DER format
ref <X509Certificate> derCert = vmime::create <X509Certificate>();
if (gnutls_x509_crt_import(derCert->m_data->cert, &buffer, GNUTLS_X509_FMT_DER) >= 0)
return derCert;
// Try PEM format
ref <X509Certificate> pemCert = vmime::create <X509Certificate>();
if (gnutls_x509_crt_import(pemCert->m_data->cert, &buffer, GNUTLS_X509_FMT_PEM) >= 0)
return pemCert;
return NULL;
}
void X509Certificate::write
(utility::outputStream& os, const Format format) const
{
size_t dataSize = 0;
gnutls_x509_crt_fmt fmt = GNUTLS_X509_FMT_DER;
switch (format)
{
case FORMAT_DER: fmt = GNUTLS_X509_FMT_DER; break;
case FORMAT_PEM: fmt = GNUTLS_X509_FMT_PEM; break;
}
gnutls_x509_crt_export(m_data->cert, fmt, NULL, &dataSize);
std::vector <byte_t> data(dataSize);
gnutls_x509_crt_export(m_data->cert, fmt, &data[0], &dataSize);
os.write(reinterpret_cast <utility::stream::value_type*>(&data[0]), dataSize);
}
const byteArray X509Certificate::getSerialNumber() const
{
char serial[64];
size_t serialSize = sizeof(serial);
gnutls_x509_crt_get_serial(m_data->cert, serial, &serialSize);
return byteArray(serial, serial + serialSize);
}
bool X509Certificate::checkIssuer(ref <const X509Certificate> issuer) const
{
return (gnutls_x509_crt_check_issuer
(m_data->cert, issuer->m_data->cert) >= 1);
}
bool X509Certificate::verify(ref <const X509Certificate> caCert) const
{
unsigned int verify = 0;
const int res = gnutls_x509_crt_verify
(m_data->cert, &(caCert->m_data->cert), 1,
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
&verify);
return (res == 0 && verify == 0);
}
const datetime X509Certificate::getActivationDate() const
{
const time_t t = gnutls_x509_crt_get_activation_time(m_data->cert);
return datetime(t);
}
const datetime X509Certificate::getExpirationDate() const
{
const time_t t = gnutls_x509_crt_get_expiration_time(m_data->cert);
return datetime(t);
}
const byteArray X509Certificate::getFingerprint(const DigestAlgorithm algo) const
{
gnutls_digest_algorithm galgo;
switch (algo)
{
case DIGEST_MD5:
galgo = GNUTLS_DIG_MD5;
break;
default:
case DIGEST_SHA1:
galgo = GNUTLS_DIG_SHA;
break;
}
size_t bufferSize = 0;
gnutls_x509_crt_get_fingerprint
(m_data->cert, galgo, NULL, &bufferSize);
std::vector <byte_t> buffer(bufferSize);
if (gnutls_x509_crt_get_fingerprint
(m_data->cert, galgo, &buffer[0], &bufferSize) == 0)
{
byteArray res;
res.insert(res.end(), &buffer[0], &buffer[0] + bufferSize);
return res;
}
return byteArray();
}
const byteArray X509Certificate::getEncoded() const
{
byteArray bytes;
utility::outputStreamByteArrayAdapter os(bytes);
write(os, FORMAT_DER);
return bytes;
}
const string X509Certificate::getType() const
{
return "X.509";
}
int X509Certificate::getVersion() const
{
return gnutls_x509_crt_get_version(m_data->cert);
}
bool X509Certificate::equals(ref <const certificate> other) const
{
ref <const X509Certificate> otherX509 =
other.dynamicCast <const X509Certificate>();
if (!otherX509)
return false;
const byteArray fp1 = getFingerprint(DIGEST_MD5);
const byteArray fp2 = otherX509->getFingerprint(DIGEST_MD5);
return fp1 == fp2;
}
@ -262,3 +44,5 @@ bool X509Certificate::equals(ref <const certificate> other) const
} // security
} // vmime
#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT

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

View File

@ -28,7 +28,7 @@
#include "vmime/config.hpp"
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#include "vmime/exception.hpp"
@ -51,9 +51,7 @@ class TLSSession;
*/
class TLSSocket : public socket
{
friend class vmime::creator;
protected:
public:
/** Create a new socket object that adds a security layer
* around an existing socket.
@ -61,12 +59,7 @@ protected:
* @param session TLS session
* @param sok socket to wrap
*/
TLSSocket(ref <TLSSession> session, ref <socket> sok);
public:
~TLSSocket();
static ref <TLSSocket> wrap(ref <TLSSession> session, ref <socket> sok);
/** Starts a TLS handshake on this connection.
*
@ -74,53 +67,14 @@ public:
* during the negociation process, exceptions::operation_timed_out
* if a time-out occurs
*/
void handshake(ref <timeoutHandler> toHandler = NULL);
virtual void handshake(ref <timeoutHandler> toHandler = NULL) = 0;
/** Return the peer's certificate (chain) as sent by the peer.
*
* @return server certificate chain, or NULL if the handshake
* has not been performed yet
*/
ref <security::cert::certificateChain> getPeerCertificates() const;
// Implementation of 'socket'
void connect(const string& address, const port_t port);
void disconnect();
bool isConnected() const;
void receive(string& buffer);
size_type receiveRaw(char* buffer, const size_type count);
void send(const string& buffer);
void sendRaw(const char* buffer, const size_type count);
size_type getBlockSize() const;
private:
void internalThrow();
#ifdef LIBGNUTLS_VERSION
static ssize_t gnutlsPushFunc(gnutls_transport_ptr trspt, const void* data, size_t len);
static ssize_t gnutlsPullFunc(gnutls_transport_ptr trspt, void* data, size_t len);
#else
static int gnutlsPushFunc(void* trspt, const void* data, size_t len);
static int gnutlsPullFunc(void* trspt, void* data, size_t len);
#endif // LIBGNUTLS_VERSION
ref <TLSSession> m_session;
ref <socket> m_wrapped;
bool m_connected;
char m_buffer[65536];
bool m_handshaking;
ref <timeoutHandler> m_toHandler;
exception* m_ex;
virtual ref <security::cert::certificateChain> getPeerCertificates() const = 0;
};
@ -129,7 +83,6 @@ private:
} // vmime
#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
#endif // VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED

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"
#endif
#include "vmime/utility/sync/criticalSection.hpp"
namespace vmime
{
@ -89,6 +91,13 @@ public:
*/
virtual unsigned int getProcessId() const = 0;
/** Return an unique identifier for the current thread.
* Used for multi-threading synchronization.
*
* @return current thread id
*/
virtual unsigned int getThreadId() const = 0;
/** Return the charset used on the system.
*
* @return locale charset
@ -126,6 +135,16 @@ public:
virtual ref <utility::childProcessFactory> getChildProcessFactory() = 0;
#endif
/** Fills a buffer with cryptographically random bytes.
*
* @param buffer buffer to fill in with random bytes
* @param count number of random bytes to write in buffer
*/
virtual void generateRandomBytes(unsigned char* buffer, const unsigned int count) = 0;
/** Creates and initializes a critical section.
*/
virtual ref <utility::sync::criticalSection> createCriticalSection() = 0;
};

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

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

View File

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

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