mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-20 22:31:31 +02:00
NetSSL library refactoring
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// AcceptCertificateHandler.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/AcceptCertificateHandler.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/AcceptCertificateHandler.cpp#11 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: AcceptCertificateHandler
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -41,7 +41,7 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
AcceptCertificateHandler::AcceptCertificateHandler(bool server):InvalidCertificateHandler(server)
|
||||
AcceptCertificateHandler::AcceptCertificateHandler(bool server): InvalidCertificateHandler(server)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -51,4 +51,10 @@ AcceptCertificateHandler::~AcceptCertificateHandler()
|
||||
}
|
||||
|
||||
|
||||
void AcceptCertificateHandler::onInvalidCertificate(const void*, VerificationErrorArgs& errorCert)
|
||||
{
|
||||
errorCert.setIgnoreError(true);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// CertificateHandlerFactory.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/CertificateHandlerFactory.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/CertificateHandlerFactory.cpp#9 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: CertificateHandlerFactory
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// CertificateHandlerFactoryMgr.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/CertificateHandlerFactoryMgr.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/CertificateHandlerFactoryMgr.cpp#10 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: CertificateHandlerFactoryMgr
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// ConsoleCertificateHandler.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/ConsoleCertificateHandler.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/ConsoleCertificateHandler.cpp#11 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: ConsoleCertificateHandler
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -42,7 +42,7 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
ConsoleCertificateHandler::ConsoleCertificateHandler(bool server):InvalidCertificateHandler(server)
|
||||
ConsoleCertificateHandler::ConsoleCertificateHandler(bool server): InvalidCertificateHandler(server)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -55,13 +55,14 @@ ConsoleCertificateHandler::~ConsoleCertificateHandler()
|
||||
void ConsoleCertificateHandler::onInvalidCertificate(const void*, VerificationErrorArgs& errorCert)
|
||||
{
|
||||
const X509Certificate& aCert = errorCert.certificate();
|
||||
std::cout << " Certificate:\n";
|
||||
std::cout << "----------------\n";
|
||||
std::cout << " IssuerName: \t" << aCert.issuerName() << "\n";
|
||||
std::cout << " SubjectName:\t" << aCert.subjectName() << "\n\n";
|
||||
std::cout << "\n";
|
||||
std::cout << "WARNING: Certificate verification failed\n";
|
||||
std::cout << "----------------------------------------\n";
|
||||
std::cout << "Issuer Name: " << aCert.issuerName() << "\n";
|
||||
std::cout << "Subject Name: " << aCert.subjectName() << "\n\n";
|
||||
std::cout << "The certificate yielded the error: " << errorCert.errorMessage() << "\n\n";
|
||||
std::cout << "The error occurred at in the certificate chain at position " << errorCert.errorDepth() << "\n";
|
||||
std::cout << "Accept the certificate? (y,n)";
|
||||
std::cout << "The error occurred in the certificate chain at position " << errorCert.errorDepth() << "\n";
|
||||
std::cout << "Accept the certificate (y,n)? ";
|
||||
char c;
|
||||
std::cin >> c;
|
||||
if (c == 'y' || c == 'Y')
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// Context.cpp
|
||||
//
|
||||
// $Id: //poco/1.3/NetSSL_OpenSSL/src/Context.cpp#2 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/Context.cpp#17 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: Context
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/Net/Utility.h"
|
||||
#include "Poco/File.h"
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
@@ -44,79 +45,82 @@
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
|
||||
using Poco::File;
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
Context::Context(
|
||||
const std::string& privateKeyFile,
|
||||
const std::string& caLocation,
|
||||
bool isServerContext,
|
||||
VerificationMode verMode,
|
||||
int verificationDepth,
|
||||
bool loadCAFromDefaultPath,
|
||||
const std::string& cypherList):_pSSLContext(0), _mode(verMode), _server(isServerContext)
|
||||
Usage usage,
|
||||
const std::string& privateKeyFile,
|
||||
const std::string& certificateFile,
|
||||
const std::string& caLocation,
|
||||
VerificationMode verificationMode,
|
||||
int verificationDepth,
|
||||
bool loadDefaultCAs,
|
||||
const std::string& cypherList):
|
||||
_usage(usage),
|
||||
_mode(verificationMode),
|
||||
_pSSLContext(0)
|
||||
{
|
||||
|
||||
_pSSLContext = SSL_CTX_new(SSLv23_method());
|
||||
if (!_pSSLContext) throw SSLException("Cannot create SSL_CTX object");
|
||||
SSL_CTX_set_default_passwd_cb(_pSSLContext, &SSLManager::privateKeyPasswdCallback);
|
||||
|
||||
Utility::clearErrorStack();
|
||||
|
||||
int errCode = 0;
|
||||
if (!caLocation.empty())
|
||||
{
|
||||
File aFile(caLocation);
|
||||
Poco::File aFile(caLocation);
|
||||
if (aFile.isDirectory())
|
||||
errCode = SSL_CTX_load_verify_locations(_pSSLContext, 0, caLocation.c_str());
|
||||
else
|
||||
errCode = SSL_CTX_load_verify_locations(_pSSLContext, caLocation.c_str(), 0);
|
||||
if (errCode != 1)
|
||||
{
|
||||
std::string msg = Utility::getLastError();
|
||||
SSL_CTX_free(_pSSLContext);
|
||||
_pSSLContext = 0;
|
||||
throw SSLContextException(std::string("Failed to load CA file/directory from ") + caLocation);
|
||||
throw SSLContextException(std::string("Cannot load CA file/directory at ") + caLocation, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (loadCAFromDefaultPath)
|
||||
if (loadDefaultCAs)
|
||||
{
|
||||
errCode = SSL_CTX_set_default_verify_paths(_pSSLContext);
|
||||
if (errCode != 1)
|
||||
{
|
||||
std::string msg = Utility::getLastError();
|
||||
SSL_CTX_free(_pSSLContext);
|
||||
_pSSLContext = 0;
|
||||
throw SSLContextException(std::string("Failed to load CA file/directory from default location"));
|
||||
throw SSLContextException("Cannot load default CA certificates", msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (!privateKeyFile.empty())
|
||||
{
|
||||
errCode = SSL_CTX_use_certificate_chain_file(_pSSLContext, privateKeyFile.c_str());
|
||||
if (errCode != 1)
|
||||
{
|
||||
SSL_CTX_free(_pSSLContext);
|
||||
_pSSLContext = 0;
|
||||
throw SSLContextException(std::string("Error loading certificate from file ") + privateKeyFile);
|
||||
}
|
||||
File tmp(privateKeyFile);
|
||||
poco_assert (tmp.exists());
|
||||
errCode = SSL_CTX_use_PrivateKey_file(_pSSLContext, privateKeyFile.c_str(), SSL_FILETYPE_PEM);
|
||||
if (errCode != 1)
|
||||
{
|
||||
std::string msg = Utility::getLastError();
|
||||
SSL_CTX_free(_pSSLContext);
|
||||
_pSSLContext = 0;
|
||||
throw SSLContextException(std::string("Error loading private key from file ") + privateKeyFile);
|
||||
throw SSLContextException(std::string("Error loading private key from file ") + privateKeyFile, msg);
|
||||
}
|
||||
}
|
||||
int flags = (int)verMode;
|
||||
if (verMode == VERIFY_STRICT || verMode == VERIFY_ONCE)
|
||||
flags |= SSL_VERIFY_PEER;
|
||||
if (serverContext())
|
||||
SSL_CTX_set_verify(_pSSLContext, flags, &SSLManager::verifyServerCallback);
|
||||
|
||||
if (!certificateFile.empty())
|
||||
{
|
||||
errCode = SSL_CTX_use_certificate_chain_file(_pSSLContext, certificateFile.c_str());
|
||||
if (errCode != 1)
|
||||
{
|
||||
std::string errMsg = Utility::getLastError();
|
||||
SSL_CTX_free(_pSSLContext);
|
||||
throw SSLContextException(std::string("Error loading certificate from file ") + privateKeyFile, errMsg);
|
||||
}
|
||||
}
|
||||
|
||||
if (usage == SERVER_USE)
|
||||
SSL_CTX_set_verify(_pSSLContext, verificationMode, &SSLManager::verifyServerCallback);
|
||||
else
|
||||
SSL_CTX_set_verify(_pSSLContext, flags, &SSLManager::verifyClientCallback);
|
||||
SSL_CTX_set_verify(_pSSLContext, verificationMode, &SSLManager::verifyClientCallback);
|
||||
|
||||
SSL_CTX_set_verify_depth(_pSSLContext, verificationDepth);
|
||||
SSL_CTX_set_mode(_pSSLContext, SSL_MODE_AUTO_RETRY);
|
||||
}
|
||||
@@ -124,11 +128,7 @@ Context::Context(
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
if (_pSSLContext)
|
||||
{
|
||||
SSL_CTX_free(_pSSLContext);
|
||||
_pSSLContext = 0;
|
||||
}
|
||||
SSL_CTX_free(_pSSLContext);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// HTTPSClientSession.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/HTTPSClientSession.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/HTTPSClientSession.cpp#13 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: HTTPSClient
|
||||
// Module: HTTPSClientSession
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -37,12 +37,9 @@
|
||||
#include "Poco/Net/HTTPSClientSession.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/Net/HTTPRequest.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
#include "Poco/Net/HTTPHeaderStream.h"
|
||||
#include "Poco/Net/HTTPStream.h"
|
||||
#include "Poco/Net/HTTPFixedLengthStream.h"
|
||||
#include "Poco/Net/HTTPChunkedStream.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
|
||||
@@ -56,24 +53,47 @@ namespace Net {
|
||||
|
||||
|
||||
HTTPSClientSession::HTTPSClientSession():
|
||||
HTTPClientSession(SecureStreamSocket())
|
||||
HTTPClientSession(SecureStreamSocket()),
|
||||
_pContext(SSLManager::instance().defaultClientContext())
|
||||
{
|
||||
setPort(Utility::HTTPS_PORT);
|
||||
setPort(HTTPS_PORT);
|
||||
}
|
||||
|
||||
|
||||
HTTPSClientSession::HTTPSClientSession(const SecureStreamSocket& socket):
|
||||
HTTPClientSession(socket)
|
||||
HTTPClientSession(socket),
|
||||
_pContext(socket.context())
|
||||
{
|
||||
setPort(Utility::HTTPS_PORT);
|
||||
setPort(HTTPS_PORT);
|
||||
}
|
||||
|
||||
|
||||
HTTPSClientSession::HTTPSClientSession(const std::string& host, Poco::UInt16 port):
|
||||
HTTPClientSession(SecureStreamSocket())
|
||||
HTTPClientSession(SecureStreamSocket()),
|
||||
_pContext(SSLManager::instance().defaultClientContext())
|
||||
{
|
||||
setHost(host);
|
||||
setPort(port);
|
||||
SecureStreamSocket sss(socket());
|
||||
sss.setPeerHostName(host);
|
||||
}
|
||||
|
||||
|
||||
HTTPSClientSession::HTTPSClientSession(Context::Ptr pContext):
|
||||
HTTPClientSession(SecureStreamSocket(pContext)),
|
||||
_pContext(pContext)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HTTPSClientSession::HTTPSClientSession(const std::string& host, Poco::UInt16 port, Context::Ptr pContext):
|
||||
HTTPClientSession(SecureStreamSocket(pContext)),
|
||||
_pContext(pContext)
|
||||
{
|
||||
setHost(host);
|
||||
setPort(port);
|
||||
SecureStreamSocket sss(socket());
|
||||
sss.setPeerHostName(host);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,26 +102,45 @@ HTTPSClientSession::~HTTPSClientSession()
|
||||
}
|
||||
|
||||
|
||||
std::string HTTPSClientSession::getHostInfo() const
|
||||
X509Certificate HTTPSClientSession::serverCertificate()
|
||||
{
|
||||
std::string result("https://");
|
||||
result.append(getHost());
|
||||
result.append(":");
|
||||
result.append(NumberFormatter::format(getPort()));
|
||||
return result;
|
||||
SecureStreamSocket sss(socket());
|
||||
return sss.peerCertificate();
|
||||
}
|
||||
|
||||
|
||||
std::string HTTPSClientSession::proxyRequestPrefix() const
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
void HTTPSClientSession::connect(const SocketAddress& address)
|
||||
{
|
||||
if (!getProxyHost().empty())
|
||||
if (getProxyHost().empty())
|
||||
{
|
||||
StreamSocket& aSock = socket();
|
||||
SecureStreamSocketImpl* pImplSock = dynamic_cast<SecureStreamSocketImpl*>(aSock.impl());
|
||||
poco_check_ptr (pImplSock);
|
||||
pImplSock->setTunnelEndPoint(getHost(), getPort());
|
||||
HTTPSession::connect(address);
|
||||
}
|
||||
else
|
||||
{
|
||||
HTTPClientSession proxySession(address);
|
||||
proxySession.setHost(getProxyHost());
|
||||
proxySession.setPort(getProxyPort());
|
||||
SocketAddress targetAddress(getHost(), getPort());
|
||||
HTTPRequest proxyRequest(HTTPRequest::HTTP_CONNECT, targetAddress.toString(), HTTPMessage::HTTP_1_1);
|
||||
HTTPResponse proxyResponse;
|
||||
proxyRequest.set("Proxy-Connection", "keep-alive");
|
||||
proxyRequest.set("Host", getHost());
|
||||
proxySession.setKeepAlive(true);
|
||||
proxySession.sendRequest(proxyRequest);
|
||||
proxySession.receiveResponse(proxyResponse);
|
||||
if (proxyResponse.getStatus() != HTTPResponse::HTTP_OK)
|
||||
throw HTTPException("Cannot establish proxy connection", proxyResponse.getReason());
|
||||
|
||||
StreamSocket proxySocket(proxySession.detachSocket());
|
||||
SecureStreamSocket secureSocket = SecureStreamSocket::attach(proxySocket, getHost(), _pContext);
|
||||
attachSocket(secureSocket);
|
||||
}
|
||||
HTTPSession::connect(address);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// HTTPSSessionInstantiator.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/HTTPSSessionInstantiator.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/HTTPSSessionInstantiator.cpp#9 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: HTTPSClient
|
||||
// Module: HTTPSSessionInstantiator
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// HTTPSStreamFactory.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp#10 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: HTTPSClient
|
||||
// Module: HTTPSStreamFactory
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -118,14 +118,14 @@ std::istream* HTTPSStreamFactory::open(const URI& uri)
|
||||
}
|
||||
else if (res.getStatus() == HTTPResponse::HTTP_USEPROXY && !retry)
|
||||
{
|
||||
//The requested resource MUST be accessed through the proxy
|
||||
//given by the Location field. The Location field gives the
|
||||
//URI of the proxy. The recipient is expected to repeat this
|
||||
//single request via the proxy. 305 responses MUST only be generated by origin servers.
|
||||
// The requested resource MUST be accessed through the proxy
|
||||
// given by the Location field. The Location field gives the
|
||||
// URI of the proxy. The recipient is expected to repeat this
|
||||
// single request via the proxy. 305 responses MUST only be generated by origin servers.
|
||||
// only use for one single request!
|
||||
proxyUri.resolve(res.get("Location"));
|
||||
delete pSession; pSession = 0;
|
||||
retry = true; //only allow useproxy once
|
||||
retry = true; // only allow useproxy once
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// InvalidCertificateHandler.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/InvalidCertificateHandler.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/InvalidCertificateHandler.cpp#11 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: InvalidCertificateHandler
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// KeyConsoleHandler.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/KeyConsoleHandler.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/KeyConsoleHandler.cpp#11 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: KeyConsoleHandler
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -54,7 +54,7 @@ KeyConsoleHandler::~KeyConsoleHandler()
|
||||
|
||||
void KeyConsoleHandler::onPrivateKeyRequested(const void* pSender, std::string& privateKey)
|
||||
{
|
||||
std::cout << "Please enter the pass-phrase for the private key: ";
|
||||
std::cout << "Please enter the passphrase for the private key: ";
|
||||
std::cin >> privateKey;
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// KeyFileHandler.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/KeyFileHandler.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/KeyFileHandler.cpp#12 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: KeyFileHandler
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -63,12 +63,12 @@ void KeyFileHandler::onPrivateKeyRequested(const void* pSender, std::string& pri
|
||||
{
|
||||
Poco::Util::LayeredConfiguration& config = Poco::Util::Application::instance().config();
|
||||
std::string prefix = serverSide() ? SSLManager::CFG_SERVER_PREFIX : SSLManager::CFG_CLIENT_PREFIX;
|
||||
if (!config.hasProperty(prefix+CFG_PRIV_KEY_FILE))
|
||||
if (!config.hasProperty(prefix + CFG_PRIV_KEY_FILE))
|
||||
{
|
||||
throw Poco::Util::EmptyOptionException(std::string("Missing Configuration Entry: ") + prefix+CFG_PRIV_KEY_FILE);
|
||||
throw Poco::Util::EmptyOptionException(std::string("Missing Configuration Entry: ") + prefix + CFG_PRIV_KEY_FILE);
|
||||
}
|
||||
|
||||
privateKey = config.getString(prefix+CFG_PRIV_KEY_FILE);
|
||||
privateKey = config.getString(prefix + CFG_PRIV_KEY_FILE);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// PrivateKeyFactory.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/PrivateKeyFactory.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/PrivateKeyFactory.cpp#9 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: PrivateKeyFactory
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// PrivateKeyFactoryMgr.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/PrivateKeyFactoryMgr.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/PrivateKeyFactoryMgr.cpp#10 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: PrivateKeyFactoryMgr
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// PrivateKeyPassphraseHandler.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/PrivateKeyPassphraseHandler.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/PrivateKeyPassphraseHandler.cpp#8 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: PrivateKeyPassphraseHandler
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// SSLException.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/SSLException.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/SSLException.cpp#10 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: SSLException
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -42,9 +42,10 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
POCO_IMPLEMENT_EXCEPTION(SSLException, NetException, "SSLException")
|
||||
POCO_IMPLEMENT_EXCEPTION(SSLContextException, SSLException, "SSLContextException")
|
||||
POCO_IMPLEMENT_EXCEPTION(InvalidCertificateException, SSLException, "InvalidCertificateException")
|
||||
POCO_IMPLEMENT_EXCEPTION(SSLException, NetException, "SSL Exception")
|
||||
POCO_IMPLEMENT_EXCEPTION(SSLContextException, SSLException, "SSL context exception")
|
||||
POCO_IMPLEMENT_EXCEPTION(InvalidCertificateException, SSLException, "Invalid certficate")
|
||||
POCO_IMPLEMENT_EXCEPTION(CertificateValidationException, SSLException, "Certificate validation error")
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// SSLInitializer.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/SSLInitializer.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/SSLInitializer.cpp#11 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: SSLInitializer
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// SSLManager.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/SSLManager.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/SSLManager.cpp#14 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: SSLManager
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "Poco/Net/Utility.h"
|
||||
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
|
||||
#include "Poco/Net/SSLInitializer.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/SingletonHolder.h"
|
||||
#include "Poco/Delegate.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
@@ -51,6 +52,7 @@ namespace Net {
|
||||
|
||||
|
||||
const std::string SSLManager::CFG_PRIV_KEY_FILE("privateKeyFile");
|
||||
const std::string SSLManager::CFG_CERTIFICATE_FILE("certificateFile");
|
||||
const std::string SSLManager::CFG_CA_LOCATION("caConfig");
|
||||
const std::string SSLManager::CFG_VER_MODE("verificationMode");
|
||||
const Context::VerificationMode SSLManager::VAL_VER_MODE(Context::VERIFY_STRICT);
|
||||
@@ -79,12 +81,6 @@ SSLManager::~SSLManager()
|
||||
PrivateKeyPassPhrase.clear();
|
||||
ClientVerificationError.clear();
|
||||
ServerVerificationError.clear();
|
||||
_ptrServerPassPhraseHandler = 0;
|
||||
_ptrServerCertificateHandler = 0;
|
||||
_ptrDefaultServerContext = 0;
|
||||
_ptrClientPassPhraseHandler = 0;
|
||||
_ptrClientCertificateHandler = 0;
|
||||
_ptrDefaultClientContext = 0;
|
||||
SSLInitializer::uninitialize();
|
||||
}
|
||||
|
||||
@@ -96,7 +92,7 @@ SSLManager& SSLManager::instance()
|
||||
}
|
||||
|
||||
|
||||
void SSLManager::initializeServer(PrivateKeyPassphraseHandlerPtr& ptrPassPhraseHandler, InvalidCertificateHandlerPtr& ptrHandler, ContextPtr ptrContext)
|
||||
void SSLManager::initializeServer(PrivateKeyPassphraseHandlerPtr ptrPassPhraseHandler, InvalidCertificateHandlerPtr ptrHandler, Context::Ptr ptrContext)
|
||||
{
|
||||
_ptrServerPassPhraseHandler = ptrPassPhraseHandler;
|
||||
_ptrServerCertificateHandler = ptrHandler;
|
||||
@@ -104,7 +100,7 @@ void SSLManager::initializeServer(PrivateKeyPassphraseHandlerPtr& ptrPassPhraseH
|
||||
}
|
||||
|
||||
|
||||
void SSLManager::initializeClient(PrivateKeyPassphraseHandlerPtr& ptrPassPhraseHandler, InvalidCertificateHandlerPtr& ptrHandler, ContextPtr ptrContext)
|
||||
void SSLManager::initializeClient(PrivateKeyPassphraseHandlerPtr ptrPassPhraseHandler, InvalidCertificateHandlerPtr ptrHandler, Context::Ptr ptrContext)
|
||||
{
|
||||
_ptrClientPassPhraseHandler = ptrPassPhraseHandler;
|
||||
_ptrClientCertificateHandler = ptrHandler;
|
||||
@@ -112,7 +108,7 @@ void SSLManager::initializeClient(PrivateKeyPassphraseHandlerPtr& ptrPassPhraseH
|
||||
}
|
||||
|
||||
|
||||
SSLManager::ContextPtr SSLManager::defaultServerContext()
|
||||
Context::Ptr SSLManager::defaultServerContext()
|
||||
{
|
||||
if (!_ptrDefaultServerContext)
|
||||
initDefaultContext(true);
|
||||
@@ -121,7 +117,7 @@ SSLManager::ContextPtr SSLManager::defaultServerContext()
|
||||
}
|
||||
|
||||
|
||||
SSLManager::ContextPtr SSLManager::defaultClientContext()
|
||||
Context::Ptr SSLManager::defaultClientContext()
|
||||
{
|
||||
if (!_ptrDefaultClientContext)
|
||||
initDefaultContext(false);
|
||||
@@ -210,34 +206,31 @@ void SSLManager::initDefaultContext(bool server)
|
||||
|
||||
Poco::Util::LayeredConfiguration& config = Poco::Util::Application::instance().config();
|
||||
std::string prefix = server ? CFG_SERVER_PREFIX : CFG_CLIENT_PREFIX;
|
||||
if (!config.hasProperty(prefix+CFG_PRIV_KEY_FILE))
|
||||
{
|
||||
throw Poco::Util::EmptyOptionException(std::string("Missing Configuration Entry: ") + prefix+CFG_PRIV_KEY_FILE);
|
||||
}
|
||||
|
||||
// mandatory options
|
||||
std::string privKeyFile = config.getString(prefix+CFG_PRIV_KEY_FILE);
|
||||
std::string caLocation = config.getString(prefix+CFG_CA_LOCATION);
|
||||
std::string privKeyFile = config.getString(prefix + CFG_PRIV_KEY_FILE, "");
|
||||
std::string certFile = config.getString(prefix + CFG_CERTIFICATE_FILE, privKeyFile);
|
||||
std::string caLocation = config.getString(prefix + CFG_CA_LOCATION, "");
|
||||
|
||||
if (certFile.empty() && privKeyFile.empty())
|
||||
throw SSLException("Configuration error: no certificate file has been specified.");
|
||||
|
||||
// optional options for which we have defaults defined
|
||||
Context::VerificationMode verMode = VAL_VER_MODE;
|
||||
if (config.hasProperty(prefix+CFG_VER_MODE))
|
||||
if (config.hasProperty(prefix + CFG_VER_MODE))
|
||||
{
|
||||
// either: none, relaxed, strict, once
|
||||
std::string mode = config.getString(prefix+CFG_VER_MODE);
|
||||
std::string mode = config.getString(prefix + CFG_VER_MODE);
|
||||
verMode = Utility::convertVerificationMode(mode);
|
||||
}
|
||||
|
||||
int verDepth = config.getInt(prefix+CFG_VER_DEPTH, VAL_VER_DEPTH);
|
||||
bool loadDefCA = config.getBool(prefix+CFG_ENABLE_DEFAULT_CA, VAL_ENABLE_DEFAULT_CA);
|
||||
std::string cypherList = config.getString(prefix+CFG_CYPHER_LIST, VAL_CYPHER_LIST);
|
||||
int verDepth = config.getInt(prefix + CFG_VER_DEPTH, VAL_VER_DEPTH);
|
||||
bool loadDefCA = config.getBool(prefix + CFG_ENABLE_DEFAULT_CA, VAL_ENABLE_DEFAULT_CA);
|
||||
std::string cypherList = config.getString(prefix + CFG_CYPHER_LIST, VAL_CYPHER_LIST);
|
||||
if (server)
|
||||
{
|
||||
_ptrDefaultServerContext = new Context(privKeyFile, caLocation, server, verMode, verDepth, loadDefCA, cypherList);
|
||||
}
|
||||
_ptrDefaultServerContext = new Context(Context::SERVER_USE, privKeyFile, certFile, caLocation, verMode, verDepth, loadDefCA, cypherList);
|
||||
else
|
||||
{
|
||||
_ptrDefaultClientContext = new Context(privKeyFile, caLocation, server, verMode, verDepth, loadDefCA, cypherList);
|
||||
}
|
||||
_ptrDefaultClientContext = new Context(Context::CLIENT_USE, privKeyFile, certFile, caLocation, verMode, verDepth, loadDefCA, cypherList);
|
||||
}
|
||||
|
||||
|
||||
@@ -256,7 +249,7 @@ void SSLManager::initPassPhraseHandler(bool server)
|
||||
std::string prefix = server ? CFG_SERVER_PREFIX : CFG_CLIENT_PREFIX;
|
||||
Poco::Util::LayeredConfiguration& config = Poco::Util::Application::instance().config();
|
||||
|
||||
std::string className(config.getString(prefix+CFG_DELEGATE_HANDLER, VAL_DELEGATE_HANDLER));
|
||||
std::string className(config.getString(prefix + CFG_DELEGATE_HANDLER, VAL_DELEGATE_HANDLER));
|
||||
|
||||
const PrivateKeyFactory* pFactory = 0;
|
||||
if (privateKeyFactoryMgr().hasFactory(className))
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// SecureServerSocket.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/SecureServerSocket.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/SecureServerSocket.cpp#12 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLSockets
|
||||
// Module: SecureServerSocket
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "Poco/Net/SecureServerSocket.h"
|
||||
#include "Poco/Net/SecureServerSocketImpl.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
|
||||
@@ -48,7 +49,13 @@ namespace Net {
|
||||
|
||||
|
||||
SecureServerSocket::SecureServerSocket():
|
||||
ServerSocket(new SecureServerSocketImpl, true)
|
||||
ServerSocket(new SecureServerSocketImpl(SSLManager::instance().defaultServerContext()), true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SecureServerSocket::SecureServerSocket(Context::Ptr pContext):
|
||||
ServerSocket(new SecureServerSocketImpl(pContext), true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -62,7 +69,15 @@ SecureServerSocket::SecureServerSocket(const Socket& socket):
|
||||
|
||||
|
||||
SecureServerSocket::SecureServerSocket(const SocketAddress& address, int backlog):
|
||||
ServerSocket(new SecureServerSocketImpl, true)
|
||||
ServerSocket(new SecureServerSocketImpl(SSLManager::instance().defaultServerContext()), true)
|
||||
{
|
||||
impl()->bind(address, true);
|
||||
impl()->listen(backlog);
|
||||
}
|
||||
|
||||
|
||||
SecureServerSocket::SecureServerSocket(const SocketAddress& address, int backlog, Context::Ptr pContext):
|
||||
ServerSocket(new SecureServerSocketImpl(pContext), true)
|
||||
{
|
||||
impl()->bind(address, true);
|
||||
impl()->listen(backlog);
|
||||
@@ -70,7 +85,16 @@ SecureServerSocket::SecureServerSocket(const SocketAddress& address, int backlog
|
||||
|
||||
|
||||
SecureServerSocket::SecureServerSocket(Poco::UInt16 port, int backlog):
|
||||
ServerSocket(new SecureServerSocketImpl, true)
|
||||
ServerSocket(new SecureServerSocketImpl(SSLManager::instance().defaultServerContext()), true)
|
||||
{
|
||||
IPAddress wildcardAddr;
|
||||
SocketAddress address(wildcardAddr, port);
|
||||
impl()->bind(address, true);
|
||||
impl()->listen(backlog);
|
||||
}
|
||||
|
||||
SecureServerSocket::SecureServerSocket(Poco::UInt16 port, int backlog, Context::Ptr pContext):
|
||||
ServerSocket(new SecureServerSocketImpl(pContext), true)
|
||||
{
|
||||
IPAddress wildcardAddr;
|
||||
SocketAddress address(wildcardAddr, port);
|
||||
@@ -110,4 +134,10 @@ StreamSocket SecureServerSocket::acceptConnection()
|
||||
}
|
||||
|
||||
|
||||
Context::Ptr SecureServerSocket::context() const
|
||||
{
|
||||
return static_cast<SecureServerSocketImpl*>(impl())->context();
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// SecureServerSocketImpl.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/SecureServerSocketImpl.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/SecureServerSocketImpl.cpp#9 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLSockets
|
||||
// Module: SecureServerSocketImpl
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -41,7 +41,8 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
SecureServerSocketImpl::SecureServerSocketImpl()
|
||||
SecureServerSocketImpl::SecureServerSocketImpl(Context::Ptr pContext):
|
||||
_impl(new ServerSocketImpl, pContext)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -53,78 +54,76 @@ SecureServerSocketImpl::~SecureServerSocketImpl()
|
||||
|
||||
SocketImpl* SecureServerSocketImpl::acceptConnection(SocketAddress& clientAddr)
|
||||
{
|
||||
return _socket.acceptConnection(clientAddr);
|
||||
return _impl.acceptConnection(clientAddr);
|
||||
}
|
||||
|
||||
|
||||
void SecureServerSocketImpl::connect(const SocketAddress& address)
|
||||
{
|
||||
_socket.connect(address);
|
||||
setSockfd(_socket.sockfd());
|
||||
throw Poco::InvalidAccessException("Cannot connect() a SecureServerSocket");
|
||||
}
|
||||
|
||||
|
||||
void SecureServerSocketImpl::connect(const SocketAddress& address, const Poco::Timespan& timeout)
|
||||
{
|
||||
_socket.connect(address, timeout);
|
||||
setSockfd(_socket.sockfd());
|
||||
throw Poco::InvalidAccessException("Cannot connect() a SecureServerSocket");
|
||||
}
|
||||
|
||||
|
||||
void SecureServerSocketImpl::connectNB(const SocketAddress& address)
|
||||
{
|
||||
_socket.connectNB(address);
|
||||
setSockfd(_socket.sockfd());
|
||||
throw Poco::InvalidAccessException("Cannot connect() a SecureServerSocket");
|
||||
}
|
||||
|
||||
|
||||
void SecureServerSocketImpl::bind(const SocketAddress& address, bool reuseAddress)
|
||||
{
|
||||
_socket.bind(address, reuseAddress);
|
||||
_impl.bind(address, reuseAddress);
|
||||
reset(_impl.sockfd());
|
||||
}
|
||||
|
||||
|
||||
void SecureServerSocketImpl::listen(int backlog)
|
||||
{
|
||||
_socket.listen(backlog);
|
||||
setSockfd(_socket.sockfd());
|
||||
_impl.listen(backlog);
|
||||
reset(_impl.sockfd());
|
||||
}
|
||||
|
||||
|
||||
void SecureServerSocketImpl::close()
|
||||
{
|
||||
invalidate();
|
||||
_socket.close();
|
||||
reset();
|
||||
_impl.close();
|
||||
}
|
||||
|
||||
|
||||
int SecureServerSocketImpl::sendBytes(const void* buffer, int length, int flags)
|
||||
{
|
||||
return _socket.sendBytes(buffer, length, flags);
|
||||
throw Poco::InvalidAccessException("Cannot sendBytes() on a SecureServerSocket");
|
||||
}
|
||||
|
||||
|
||||
int SecureServerSocketImpl::receiveBytes(void* buffer, int length, int flags)
|
||||
{
|
||||
return _socket.receiveBytes(buffer, length, flags);
|
||||
throw Poco::InvalidAccessException("Cannot receiveBytes() on a SecureServerSocket");
|
||||
}
|
||||
|
||||
|
||||
int SecureServerSocketImpl::sendTo(const void* buffer, int length, const SocketAddress& address, int flags)
|
||||
{
|
||||
return _socket.sendTo(buffer, length, address, flags);
|
||||
throw Poco::InvalidAccessException("Cannot sendTo() on a SecureServerSocket");
|
||||
}
|
||||
|
||||
|
||||
int SecureServerSocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
|
||||
{
|
||||
return _socket.receiveFrom(buffer, length, address, flags);
|
||||
throw Poco::InvalidAccessException("Cannot receiveFrom() on a SecureServerSocket");
|
||||
}
|
||||
|
||||
|
||||
void SecureServerSocketImpl::sendUrgent(unsigned char data)
|
||||
{
|
||||
return _socket.sendUrgent(data);
|
||||
throw Poco::InvalidAccessException("Cannot sendUrgent() on a SecureServerSocket");
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// SecureSocketImpl.cpp
|
||||
//
|
||||
// $Id: //poco/1.3/NetSSL_OpenSSL/src/SecureSocketImpl.cpp#6 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/SecureSocketImpl.cpp#29 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLSockets
|
||||
// Module: SecureSocketImpl
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -36,19 +36,19 @@
|
||||
|
||||
#include "Poco/Net/SecureSocketImpl.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/Net/Context.h"
|
||||
#include "Poco/Net/X509Certificate.h"
|
||||
#include "Poco/Net/Utility.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/StreamSocketImpl.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/Net/DNS.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/NumberParser.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/RegularExpression.h"
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/err.h>
|
||||
#include <set>
|
||||
|
||||
|
||||
using Poco::IOException;
|
||||
@@ -62,29 +62,17 @@ using Poco::Timespan;
|
||||
#define POCO_BIO_set_nbio_accept(b,n) BIO_ctrl(b,BIO_C_SET_ACCEPT,1,(void*)((n)?"a":NULL))
|
||||
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
static void getCertNames (X509*, std::string& commonName, std::set<std::string>& DNSNames);
|
||||
|
||||
|
||||
SecureSocketImpl::SecureSocketImpl():_pBIO(0), _pSSL(0)
|
||||
SecureSocketImpl::SecureSocketImpl(Poco::AutoPtr<SocketImpl> pSocketImpl, Context::Ptr pContext):
|
||||
_pSSL(0),
|
||||
_pSocket(pSocketImpl),
|
||||
_pContext(pContext)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SecureSocketImpl::SecureSocketImpl(SSL *pSSL): _pSSL(pSSL)
|
||||
{
|
||||
poco_check_ptr (_pSSL);
|
||||
|
||||
_pBIO = SSL_get_rbio(_pSSL);
|
||||
poco_check_ptr (_pBIO);
|
||||
int tmpSocket = 0;
|
||||
BIO_get_fd(_pBIO, &tmpSocket);
|
||||
setSockfd(tmpSocket);
|
||||
|
||||
poco_check_ptr (_pSocket);
|
||||
poco_check_ptr (_pContext);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,540 +84,305 @@ SecureSocketImpl::~SecureSocketImpl()
|
||||
|
||||
SocketImpl* SecureSocketImpl::acceptConnection(SocketAddress& clientAddr)
|
||||
{
|
||||
poco_assert (sockfd() != POCO_INVALID_SOCKET);
|
||||
poco_check_ptr (_pBIO);
|
||||
poco_assert (!_pSSL);
|
||||
|
||||
BIO* pClient = 0;
|
||||
int rc = 0;
|
||||
StreamSocket ss = _pSocket->acceptConnection(clientAddr);
|
||||
Poco::AutoPtr<SecureStreamSocketImpl> pSecureStreamSocketImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(ss.impl()), _pContext);
|
||||
pSecureStreamSocketImpl->acceptSSL();
|
||||
pSecureStreamSocketImpl->duplicate();
|
||||
return pSecureStreamSocketImpl;
|
||||
}
|
||||
|
||||
do
|
||||
|
||||
void SecureSocketImpl::acceptSSL()
|
||||
{
|
||||
poco_assert (!_pSSL);
|
||||
|
||||
BIO* pBIO = BIO_new(BIO_s_socket());
|
||||
if (!pBIO) throw SSLException("Cannot create BIO object");
|
||||
BIO_set_fd(pBIO, _pSocket->sockfd(), BIO_NOCLOSE);
|
||||
|
||||
_pSSL = SSL_new(_pContext->sslContext());
|
||||
if (!_pSSL)
|
||||
{
|
||||
rc = BIO_do_accept(_pBIO);
|
||||
BIO_free(pBIO);
|
||||
throw SSLException("Cannot create SSL object");
|
||||
}
|
||||
while (rc <= 0 && _socket.lastError() == POCO_EINTR);
|
||||
SSL_set_bio(_pSSL, pBIO, pBIO);
|
||||
|
||||
if (rc > 0)
|
||||
try
|
||||
{
|
||||
pClient = BIO_pop(_pBIO);
|
||||
poco_check_ptr (pClient);
|
||||
|
||||
SSL* pSSL = SSL_new(SSLManager::instance().defaultServerContext()->sslContext());
|
||||
if (pSSL)
|
||||
if (_pSocket->getBlocking())
|
||||
{
|
||||
SSL_set_accept_state(pSSL);
|
||||
SSL_set_bio(pSSL, pClient, pClient);
|
||||
int err = SSL_accept(pSSL);
|
||||
|
||||
int err = SSL_accept(_pSSL);
|
||||
if (err > 0)
|
||||
{
|
||||
SecureStreamSocketImpl* pSI = new SecureStreamSocketImpl(pSSL);
|
||||
clientAddr = pSI->peerAddress();
|
||||
std::string clientName = clientAddr.host().toString();
|
||||
|
||||
if (X509_V_OK != postConnectionCheck(true, pSSL, clientName))
|
||||
std::string clientName = _pSocket->peerAddress().host().toString();
|
||||
long certErr = verifyCertificate(clientName);
|
||||
if (certErr != X509_V_OK)
|
||||
{
|
||||
delete pSI;
|
||||
pSI = 0;
|
||||
SSL_shutdown(pSSL);
|
||||
SSL_free(pSSL);
|
||||
pClient = 0;
|
||||
SocketImpl::error("postConnectionCheck failed"); // will throw
|
||||
std::string msg = Utility::convertCertificateError(certErr);
|
||||
throw CertificateValidationException("Unacceptable certificate from " + clientName, msg);
|
||||
}
|
||||
|
||||
return pSI;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string errMsg = Utility::convertSSLError(pSSL, err);
|
||||
SSL_shutdown(pSSL);
|
||||
SSL_free(pSSL);
|
||||
SocketImpl::error(std::string("failed to acceptConnection: ") + errMsg);
|
||||
handleError(err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BIO_free(pClient);
|
||||
SSL_set_accept_state(_pSSL);
|
||||
}
|
||||
|
||||
}
|
||||
SocketImpl::error(); // will throw
|
||||
return 0;
|
||||
catch (...)
|
||||
{
|
||||
SSL_shutdown(_pSSL);
|
||||
SSL_free(_pSSL);
|
||||
_pSSL = 0;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::connect(const SocketAddress& address)
|
||||
void SecureSocketImpl::connect(const SocketAddress& address, const std::string& hostName)
|
||||
{
|
||||
if (sockfd() == POCO_INVALID_SOCKET)
|
||||
{
|
||||
if (!_pBIO)
|
||||
_pBIO = BIO_new(BIO_s_connect());
|
||||
}
|
||||
poco_assert (!_pSSL);
|
||||
|
||||
int rc = 0;
|
||||
do
|
||||
{
|
||||
BIO_set_conn_hostname(_pBIO, address.host().toString().c_str());
|
||||
int tmp = address.port();
|
||||
BIO_set_conn_int_port(_pBIO, &tmp);
|
||||
rc = BIO_do_connect(_pBIO); // returns 1 in case of ok!
|
||||
}
|
||||
while (rc != 1 && _socket.lastError() == POCO_EINTR);
|
||||
|
||||
if (rc != 1) SocketImpl::error(address.toString());
|
||||
|
||||
establishTunnel();
|
||||
connectSSL(address);
|
||||
poco_check_ptr (_pSSL);
|
||||
_pSocket->connect(address);
|
||||
connectSSL(hostName);
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::connect(const SocketAddress& address, const Poco::Timespan& timeout)
|
||||
void SecureSocketImpl::connect(const SocketAddress& address, const std::string& hostName, const Poco::Timespan& timeout)
|
||||
{
|
||||
poco_assert (sockfd() == POCO_INVALID_SOCKET);
|
||||
poco_assert (_pSSL == 0);
|
||||
poco_assert (_pBIO == 0);
|
||||
poco_assert (!_pSSL);
|
||||
|
||||
_pBIO = BIO_new(BIO_s_connect());
|
||||
POCO_BIO_set_nbio_accept(_pBIO, 1); // set nonblocking
|
||||
_pSocket->connect(address, timeout);
|
||||
connectSSL(hostName);
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::connectNB(const SocketAddress& address, const std::string& hostName)
|
||||
{
|
||||
poco_assert (!_pSSL);
|
||||
|
||||
_pSocket->connectNB(address);
|
||||
connectSSL(hostName);
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::connectSSL(const std::string& hostName)
|
||||
{
|
||||
poco_assert (!_pSSL);
|
||||
poco_assert (_pSocket->initialized());
|
||||
|
||||
BIO* pBIO = BIO_new(BIO_s_socket());
|
||||
if (!pBIO) throw SSLException("Cannot create SSL BIO object");
|
||||
BIO_set_fd(pBIO, _pSocket->sockfd(), BIO_NOCLOSE);
|
||||
|
||||
_pSSL = SSL_new(_pContext->sslContext());
|
||||
if (!_pSSL)
|
||||
{
|
||||
BIO_free(pBIO);
|
||||
throw SSLException("Cannot create SSL object");
|
||||
}
|
||||
SSL_set_bio(_pSSL, pBIO, pBIO);
|
||||
|
||||
try
|
||||
{
|
||||
BIO_set_conn_hostname(_pBIO, address.host().toString().c_str());
|
||||
int tmp = address.port();
|
||||
BIO_set_conn_int_port(_pBIO, &tmp);
|
||||
int rc = BIO_do_connect(_pBIO); // returns 1 in case of ok!
|
||||
|
||||
if (rc != 1)
|
||||
if (_pSocket->getBlocking())
|
||||
{
|
||||
if (_socket.lastError() != POCO_EINPROGRESS && _socket.lastError() != POCO_EWOULDBLOCK)
|
||||
SocketImpl::error(address.toString());
|
||||
if (!_socket.poll(timeout, SocketImpl::SELECT_READ | SocketImpl::SELECT_WRITE))
|
||||
throw Poco::TimeoutException("connect timed out", address.toString());
|
||||
int err = _socket.socketError();
|
||||
if (err != 0) SocketImpl::error(err);
|
||||
int ret = SSL_connect(_pSSL);
|
||||
handleError(ret);
|
||||
|
||||
long certErr = verifyCertificate(hostName);
|
||||
if (certErr != X509_V_OK)
|
||||
{
|
||||
std::string msg = Utility::convertCertificateError(certErr);
|
||||
throw InvalidCertificateException(msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SSL_set_connect_state(_pSSL);
|
||||
}
|
||||
|
||||
establishTunnel();
|
||||
connectSSL(address);
|
||||
poco_check_ptr (_pSSL);
|
||||
}
|
||||
catch (Poco::Exception&)
|
||||
catch (...)
|
||||
{
|
||||
POCO_BIO_set_nbio_accept(_pBIO, 0);
|
||||
SSL_free(_pSSL);
|
||||
_pSSL = 0;
|
||||
throw;
|
||||
}
|
||||
POCO_BIO_set_nbio_accept(_pBIO, 0);
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::connectNB(const SocketAddress& address)
|
||||
{
|
||||
if (sockfd() == POCO_INVALID_SOCKET)
|
||||
{
|
||||
if(!_pBIO)
|
||||
_pBIO = BIO_new(BIO_s_connect());
|
||||
}
|
||||
|
||||
POCO_BIO_set_nbio_accept(_pBIO, 1); //setnonBlocking
|
||||
BIO_set_conn_hostname(_pBIO, address.host().toString().c_str());
|
||||
int tmp = address.port();
|
||||
BIO_set_conn_int_port(_pBIO, &tmp);
|
||||
|
||||
int rc = BIO_do_connect(_pBIO); // returns 1 in case of ok!
|
||||
|
||||
if (rc != 1)
|
||||
{
|
||||
if (_socket.lastError() != POCO_EINPROGRESS && _socket.lastError() != POCO_EWOULDBLOCK)
|
||||
SocketImpl::error(address.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
establishTunnel();
|
||||
connectSSL(address);
|
||||
poco_check_ptr (_pSSL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::bind(const SocketAddress& address, bool reuseAddress)
|
||||
{
|
||||
_socket.bind(address, reuseAddress);
|
||||
poco_check_ptr (_pSocket);
|
||||
|
||||
_pSocket->bind(address, reuseAddress);
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::listen(int backlog)
|
||||
{
|
||||
_socket.listen(backlog);
|
||||
_pBIO = BIO_new (BIO_s_accept());
|
||||
BIO_set_fd(_pBIO, (int)sockfd(), BIO_CLOSE);
|
||||
poco_check_ptr (_pSocket);
|
||||
|
||||
_pSocket->listen(backlog);
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::shutdown()
|
||||
{
|
||||
if (_pSSL)
|
||||
{
|
||||
// if we can't get a clean SSL shutdown after 10
|
||||
// attempts, something's probably wrong with the
|
||||
// peer and we give up.
|
||||
int rc;
|
||||
int attempts = 0;
|
||||
do
|
||||
{
|
||||
rc = SSL_shutdown(_pSSL);
|
||||
++attempts;
|
||||
}
|
||||
while (rc == 0 && attempts < 10);
|
||||
if (rc < 0) handleError(rc);
|
||||
SSL_clear(_pSSL);
|
||||
SSL_free(_pSSL);
|
||||
_pSSL = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::close()
|
||||
{
|
||||
if (_pSSL)
|
||||
{
|
||||
if (SSL_get_shutdown(_pSSL) & SSL_RECEIVED_SHUTDOWN)
|
||||
{
|
||||
SSL_shutdown(_pSSL);
|
||||
}
|
||||
else
|
||||
{
|
||||
SSL_clear(_pSSL);
|
||||
}
|
||||
SSL_free(_pSSL); // frees _pBIO
|
||||
_pSSL = 0;
|
||||
_pBIO = 0;
|
||||
}
|
||||
|
||||
if (_pBIO)
|
||||
{
|
||||
BIO_free_all(_pBIO); //free all, even BIOs for pending connections
|
||||
_pBIO = 0;
|
||||
}
|
||||
invalidate(); // the socket is already invalid, although the fd still contains a meaningful value, correct that
|
||||
shutdown();
|
||||
_pSocket->close();
|
||||
}
|
||||
|
||||
|
||||
int SecureSocketImpl::sendBytes(const void* buffer, int length, int flags)
|
||||
{
|
||||
poco_assert (sockfd() != POCO_INVALID_SOCKET);
|
||||
if (!_pSSL)
|
||||
throw SSLException("Cannot write to closed/uninitialized socket");
|
||||
poco_assert (_pSocket->initialized());
|
||||
poco_check_ptr (_pSSL);
|
||||
|
||||
int rc;
|
||||
do
|
||||
{
|
||||
rc = SSL_write(_pSSL, buffer, length);
|
||||
if (rc < 0)
|
||||
{
|
||||
std::string errMsg = Utility::convertSSLError(_pSSL, rc);
|
||||
}
|
||||
}
|
||||
while (rc < 0 && _socket.lastError() == POCO_EINTR);
|
||||
if (rc < 0) SocketImpl::error();
|
||||
while (rc <= 0 && _pSocket->lastError() == POCO_EINTR);
|
||||
if (rc <= 0)
|
||||
{
|
||||
return handleError(rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int SecureSocketImpl::receiveBytes(void* buffer, int length, int flags)
|
||||
{
|
||||
if (sockfd() == POCO_INVALID_SOCKET || !_pSSL)
|
||||
throw SSLException("Cannot read from closed/uninitialized socket");
|
||||
poco_assert (_pSocket->initialized());
|
||||
poco_check_ptr (_pSSL);
|
||||
|
||||
int rc;
|
||||
bool renegotiating = false;
|
||||
do
|
||||
{
|
||||
rc = SSL_read(_pSSL, buffer, length);
|
||||
if (rc <= 0)
|
||||
{
|
||||
switch (SSL_get_error(_pSSL, rc))
|
||||
{
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
// connection closed
|
||||
close();
|
||||
break;
|
||||
case SSL_ERROR_NONE:
|
||||
case SSL_ERROR_WANT_WRITE: //renegotiation
|
||||
case SSL_ERROR_WANT_READ: //renegotiation
|
||||
renegotiating = true;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (rc < 0 && _socket.lastError() == POCO_EINTR);
|
||||
if (rc < 0)
|
||||
while (rc <= 0 && _pSocket->lastError() == POCO_EINTR);
|
||||
if (rc <= 0)
|
||||
{
|
||||
if (renegotiating || _socket.lastError() == POCO_EAGAIN || _socket.lastError() == POCO_ETIMEDOUT)
|
||||
throw TimeoutException();
|
||||
else
|
||||
SocketImpl::error("failed to read bytes");
|
||||
return handleError(rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int SecureSocketImpl::sendTo(const void* buffer, int length, const SocketAddress& address, int flags)
|
||||
long SecureSocketImpl::verifyCertificate(const std::string& hostName)
|
||||
{
|
||||
throw NetException("sendTo not possible with SSL");
|
||||
}
|
||||
|
||||
|
||||
int SecureSocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
|
||||
{
|
||||
throw NetException("receiveFrom not possible with SSL");
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::sendUrgent(unsigned char data)
|
||||
{
|
||||
// SSL doesn't support out-of-band data
|
||||
sendBytes(reinterpret_cast<const void*>(&data), sizeof(data));
|
||||
}
|
||||
|
||||
|
||||
long SecureSocketImpl::postConnectionCheck(bool server, SSL* pSSL, const std::string& hostName)
|
||||
{
|
||||
static std::string locHost("127.0.0.1");
|
||||
|
||||
SSLManager& mgr = SSLManager::instance();
|
||||
SSLManager::ContextPtr pContext = server? mgr.defaultServerContext(): mgr.defaultClientContext();
|
||||
Context::VerificationMode mode = pContext->verificationMode();
|
||||
if (hostName == locHost && mode != Context::VERIFY_STRICT)
|
||||
return X509_V_OK;
|
||||
|
||||
X509* cert = 0;
|
||||
X509_NAME* subj = 0;
|
||||
|
||||
if (mode == Context::VERIFY_NONE) // should we allow none on the client side?
|
||||
Context::VerificationMode mode = _pContext->verificationMode();
|
||||
if (mode == Context::VERIFY_NONE || isLocalHost(hostName) && mode != Context::VERIFY_STRICT)
|
||||
{
|
||||
return X509_V_OK;
|
||||
}
|
||||
|
||||
cert = SSL_get_peer_certificate(pSSL);
|
||||
return postConnectionCheck(pContext, cert, hostName);
|
||||
X509* pCert = SSL_get_peer_certificate(_pSSL);
|
||||
if (pCert)
|
||||
{
|
||||
X509Certificate cert(pCert);
|
||||
return cert.verify(hostName);
|
||||
}
|
||||
else return X509_V_OK;
|
||||
}
|
||||
|
||||
|
||||
long SecureSocketImpl::postConnectionCheck(SSLManager::ContextPtr pContext, X509* pCert, const std::string& hostName)
|
||||
|
||||
bool SecureSocketImpl::isLocalHost(const std::string& hostName)
|
||||
{
|
||||
static std::string locHost("127.0.0.1");
|
||||
SocketAddress addr(hostName, 0);
|
||||
return addr.host().isLoopback();
|
||||
}
|
||||
|
||||
SSLManager& mgr = SSLManager::instance();
|
||||
bool server = pContext->serverContext();
|
||||
Context::VerificationMode mode = pContext->verificationMode();
|
||||
if (hostName == locHost && mode != Context::VERIFY_STRICT)
|
||||
return X509_V_OK;
|
||||
|
||||
X509* cert = pCert;
|
||||
X509_NAME* subj = 0;
|
||||
char* host = const_cast<char*>(hostName.c_str());
|
||||
|
||||
int extcount=0;
|
||||
X509* SecureSocketImpl::peerCertificate() const
|
||||
{
|
||||
if (_pSSL)
|
||||
return SSL_get_peer_certificate(_pSSL);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mode == Context::VERIFY_NONE) // should we allow none on the client side?
|
||||
|
||||
int SecureSocketImpl::handleError(int rc)
|
||||
{
|
||||
if (rc > 0) return rc;
|
||||
|
||||
int sslError = SSL_get_error(_pSSL, rc);
|
||||
switch (sslError)
|
||||
{
|
||||
return X509_V_OK;
|
||||
}
|
||||
|
||||
// note: the check is used by the client, so as long we don't set None at the client we reject
|
||||
// cases where no certificate/incomplete info is presented by the server
|
||||
if ((!cert || !host) && mode != Context::VERIFY_NONE)
|
||||
{
|
||||
if (cert)
|
||||
X509_free(cert);
|
||||
return X509_V_ERR_APPLICATION_VERIFICATION;
|
||||
}
|
||||
|
||||
std::string commonName;
|
||||
std::set<std::string> dnsNames;
|
||||
getCertNames(cert, commonName, dnsNames);
|
||||
bool ok = (dnsNames.find(hostName) != dnsNames.end());
|
||||
|
||||
char data[256];
|
||||
if (!ok && (subj = X509_get_subject_name(cert)) && X509_NAME_get_text_by_NID(subj, NID_commonName, data, 256) > 0)
|
||||
{
|
||||
data[255] = 0;
|
||||
|
||||
std::string strData(data); // commonName can contain wildcards like *.appinf.com
|
||||
try
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return 0;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return SecureStreamSocket::ERR_SSL_WANT_READ;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return SecureStreamSocket::ERR_SSL_WANT_WRITE;
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
// these should not occur
|
||||
poco_bugcheck();
|
||||
return rc;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
case SSL_ERROR_SSL:
|
||||
{
|
||||
// two cases: strData contains wildcards or not
|
||||
if (SecureSocketImpl::containsWildcards(strData))
|
||||
long lastError = ERR_get_error();
|
||||
if (lastError == 0)
|
||||
{
|
||||
// a compare by IPAddress is not possible with wildcards
|
||||
// only allow compare by name
|
||||
const HostEntry& heData = DNS::resolve(hostName);
|
||||
ok = SecureSocketImpl::matchByAlias(strData, heData);
|
||||
if (rc == 0)
|
||||
{
|
||||
throw SSLException("The underlying socket connection has been unexpectedly closed");
|
||||
}
|
||||
else if (rc == -1)
|
||||
{
|
||||
SecureStreamSocketImpl::error("The BIO reported an error");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// it depends on hostname if we compare by IP or by alias
|
||||
IPAddress ip;
|
||||
if (IPAddress::tryParse(hostName, ip))
|
||||
{
|
||||
// compare by IP
|
||||
const HostEntry& heData = DNS::resolve(strData);
|
||||
const HostEntry::AddressList& addr = heData.addresses();
|
||||
HostEntry::AddressList::const_iterator it = addr.begin();
|
||||
HostEntry::AddressList::const_iterator itEnd = addr.end();
|
||||
for (; it != itEnd && !ok; ++it)
|
||||
{
|
||||
ok = (*it == ip);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// compare by name
|
||||
const HostEntry& heData = DNS::resolve(hostName);
|
||||
ok = SecureSocketImpl::matchByAlias(strData, heData);
|
||||
}
|
||||
char buffer[256];
|
||||
ERR_error_string_n(lastError, buffer, sizeof(buffer));
|
||||
std::string msg(buffer);
|
||||
throw SSLException(msg);
|
||||
}
|
||||
}
|
||||
catch(HostNotFoundException&)
|
||||
{
|
||||
if (cert)
|
||||
X509_free(cert);
|
||||
return X509_V_ERR_APPLICATION_VERIFICATION;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cert)
|
||||
X509_free(cert);
|
||||
|
||||
// we already have a verify callback registered so no need to ask twice SSL_get_verify_result(pSSL);
|
||||
if (ok)
|
||||
return X509_V_OK;
|
||||
|
||||
return X509_V_ERR_APPLICATION_VERIFICATION;
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::connectSSL(const SocketAddress& address)
|
||||
{
|
||||
if (!_pSSL)
|
||||
{
|
||||
_pSSL = SSL_new(SSLManager::instance().defaultClientContext()->sslContext());
|
||||
SSL_set_bio(_pSSL, _pBIO, _pBIO);
|
||||
}
|
||||
std::string errMsg;
|
||||
|
||||
int ret = SSL_connect(_pSSL);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
errMsg = Utility::convertSSLError(_pSSL, ret);
|
||||
throw SSLException(errMsg);
|
||||
}
|
||||
|
||||
std::string serverName = address.host().toString();
|
||||
long errCode = 0;
|
||||
if (_endHost.empty())
|
||||
postConnectionCheck(false, _pSSL, serverName);
|
||||
else
|
||||
postConnectionCheck(false, _pSSL, _endHost);
|
||||
bool err = false;
|
||||
|
||||
if (errCode != X509_V_OK)
|
||||
{
|
||||
err = true;
|
||||
errMsg = Utility::convertCertificateError(errCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
int tmpSocket=0;
|
||||
BIO_get_fd(_pBIO,&tmpSocket);
|
||||
poco_assert (-1 != tmpSocket);
|
||||
setSockfd(tmpSocket);
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
SSL_free(_pSSL); // dels _pBIO too
|
||||
_pSSL = 0;
|
||||
_pBIO = 0;
|
||||
invalidate();
|
||||
throw InvalidCertificateException(errMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SecureSocketImpl::establishTunnel()
|
||||
{
|
||||
if (!_endHost.empty())
|
||||
{
|
||||
poco_check_ptr (_pBIO);
|
||||
// send CONNECT proxyHost:proxyPort HTTP/1.0\r\n\r\n
|
||||
std::string connect("CONNECT ");
|
||||
connect.append(_endHost);
|
||||
connect.append(":");
|
||||
connect.append(Poco::NumberFormatter::format(_endPort));
|
||||
connect.append(" HTTP/1.0\r\n\r\n");
|
||||
int rc = BIO_write(_pBIO, (const void*) connect.c_str(), (int)(connect.length()*sizeof(char)));
|
||||
if (rc != connect.length())
|
||||
throw SSLException("Failed to establish connection to proxy");
|
||||
// get the response
|
||||
char resp[512];
|
||||
rc = BIO_read(_pBIO, resp, 512*sizeof(char));
|
||||
std::string response(resp);
|
||||
if (response.find("200") == std::string::npos)
|
||||
throw SSLException("Failed to establish connection to proxy");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SecureSocketImpl::containsWildcards(const std::string& commonName)
|
||||
{
|
||||
return (commonName.find('*') != std::string::npos || commonName.find('?') != std::string::npos);
|
||||
}
|
||||
|
||||
|
||||
bool SecureSocketImpl::matchByAlias(const std::string& alias, const HostEntry& heData)
|
||||
{
|
||||
// fix wildcards
|
||||
std::string aliasRep = Poco::replace(alias, "*", ".*");
|
||||
Poco::replaceInPlace(aliasRep, "..*", ".*");
|
||||
Poco::replaceInPlace(aliasRep, "?", ".?");
|
||||
Poco::replaceInPlace(aliasRep, "..?", ".?");
|
||||
// compare by name
|
||||
Poco::RegularExpression expr(aliasRep);
|
||||
bool found = false;
|
||||
const HostEntry::AliasList& aliases = heData.aliases();
|
||||
HostEntry::AliasList::const_iterator it = aliases.begin();
|
||||
HostEntry::AliasList::const_iterator itEnd = aliases.end();
|
||||
for (; it != itEnd && !found; ++it)
|
||||
{
|
||||
found = expr.match(*it);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
getCertNames (X509 *certificate,
|
||||
std::string& common_name,
|
||||
std::set<std::string>& DNS_names)
|
||||
{
|
||||
DNS_names.clear ();
|
||||
common_name.clear ();
|
||||
if (certificate == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (STACK_OF (GENERAL_NAME) * names = static_cast<STACK_OF (GENERAL_NAME)
|
||||
*>
|
||||
(X509_get_ext_d2i (certificate, NID_subject_alt_name, 0, 0)))
|
||||
{
|
||||
for (int i = 0; i < sk_GENERAL_NAME_num (names); ++i)
|
||||
{
|
||||
const GENERAL_NAME *name = sk_GENERAL_NAME_value (names, i);
|
||||
if (name->type == GEN_DNS)
|
||||
{
|
||||
const char *data = reinterpret_cast<char *>
|
||||
(ASN1_STRING_data (name->d.ia5));
|
||||
size_t len = ASN1_STRING_length (name->d.ia5);
|
||||
DNS_names.insert (std::string (data, len));
|
||||
}
|
||||
}
|
||||
GENERAL_NAMES_free (names);
|
||||
}
|
||||
|
||||
if (X509_NAME * subj = X509_get_subject_name (certificate))
|
||||
{
|
||||
char buffer[256];
|
||||
X509_NAME_get_text_by_NID (subj, NID_commonName,
|
||||
buffer, sizeof buffer);
|
||||
common_name = std::string (buffer);
|
||||
if (DNS_names.empty ())
|
||||
{
|
||||
DNS_names.insert (common_name);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// SecureStreamSocket.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/SecureStreamSocket.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/SecureStreamSocket.cpp#11 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLSockets
|
||||
// Module: SecureStreamSocket
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/SocketImpl.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/Exception.h"
|
||||
|
||||
|
||||
@@ -48,18 +49,47 @@ namespace Net {
|
||||
|
||||
|
||||
SecureStreamSocket::SecureStreamSocket():
|
||||
StreamSocket(new SecureStreamSocketImpl)
|
||||
StreamSocket(new SecureStreamSocketImpl(SSLManager::instance().defaultClientContext()))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocket::SecureStreamSocket(Context::Ptr pContext):
|
||||
StreamSocket(new SecureStreamSocketImpl(pContext))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocket::SecureStreamSocket(const SocketAddress& address):
|
||||
StreamSocket(new SecureStreamSocketImpl)
|
||||
StreamSocket(new SecureStreamSocketImpl(SSLManager::instance().defaultClientContext()))
|
||||
{
|
||||
connect(address);
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocket::SecureStreamSocket(const SocketAddress& address, const std::string& hostName):
|
||||
StreamSocket(new SecureStreamSocketImpl(SSLManager::instance().defaultClientContext()))
|
||||
{
|
||||
static_cast<SecureStreamSocketImpl*>(impl())->setPeerHostName(hostName);
|
||||
connect(address);
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocket::SecureStreamSocket(const SocketAddress& address, Context::Ptr pContext):
|
||||
StreamSocket(new SecureStreamSocketImpl(pContext))
|
||||
{
|
||||
connect(address);
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocket::SecureStreamSocket(const SocketAddress& address, const std::string& hostName, Context::Ptr pContext):
|
||||
StreamSocket(new SecureStreamSocketImpl(pContext))
|
||||
{
|
||||
static_cast<SecureStreamSocketImpl*>(impl())->setPeerHostName(hostName);
|
||||
connect(address);
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocket::SecureStreamSocket(const Socket& socket):
|
||||
StreamSocket(socket)
|
||||
{
|
||||
@@ -91,4 +121,66 @@ SecureStreamSocket& SecureStreamSocket::operator = (const Socket& socket)
|
||||
}
|
||||
|
||||
|
||||
X509Certificate SecureStreamSocket::peerCertificate() const
|
||||
{
|
||||
return static_cast<SecureStreamSocketImpl*>(impl())->peerCertificate();
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocket::setPeerHostName(const std::string& hostName)
|
||||
{
|
||||
static_cast<SecureStreamSocketImpl*>(impl())->setPeerHostName(hostName);
|
||||
}
|
||||
|
||||
|
||||
const std::string& SecureStreamSocket::getPeerHostName() const
|
||||
{
|
||||
return static_cast<SecureStreamSocketImpl*>(impl())->getPeerHostName();
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocket SecureStreamSocket::attach(const StreamSocket& streamSocket)
|
||||
{
|
||||
SecureStreamSocketImpl* pImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(streamSocket.impl()), SSLManager::instance().defaultClientContext());
|
||||
SecureStreamSocket result(pImpl);
|
||||
pImpl->connectSSL();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocket SecureStreamSocket::attach(const StreamSocket& streamSocket, Context::Ptr pContext)
|
||||
{
|
||||
SecureStreamSocketImpl* pImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(streamSocket.impl()), pContext);
|
||||
SecureStreamSocket result(pImpl);
|
||||
pImpl->connectSSL();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocket SecureStreamSocket::attach(const StreamSocket& streamSocket, const std::string& peerHostName)
|
||||
{
|
||||
SecureStreamSocketImpl* pImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(streamSocket.impl()), SSLManager::instance().defaultClientContext());
|
||||
SecureStreamSocket result(pImpl);
|
||||
result.setPeerHostName(peerHostName);
|
||||
pImpl->connectSSL();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocket SecureStreamSocket::attach(const StreamSocket& streamSocket, const std::string& peerHostName, Context::Ptr pContext)
|
||||
{
|
||||
SecureStreamSocketImpl* pImpl = new SecureStreamSocketImpl(static_cast<StreamSocketImpl*>(streamSocket.impl()), pContext);
|
||||
SecureStreamSocket result(pImpl);
|
||||
result.setPeerHostName(peerHostName);
|
||||
pImpl->connectSSL();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Context::Ptr SecureStreamSocket::context() const
|
||||
{
|
||||
return static_cast<SecureStreamSocketImpl*>(impl())->context();
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// SecureStreamSocketImpl.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/SecureStreamSocketImpl.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/SecureStreamSocketImpl.cpp#9 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLSockets
|
||||
// Module: SecureStreamSocketImpl
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -35,72 +35,92 @@
|
||||
|
||||
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
SecureStreamSocketImpl::SecureStreamSocketImpl()
|
||||
SecureStreamSocketImpl::SecureStreamSocketImpl(Context::Ptr pContext):
|
||||
_impl(new StreamSocketImpl, pContext)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocketImpl::SecureStreamSocketImpl(SSL* _pSSL): _socket(_pSSL)
|
||||
SecureStreamSocketImpl::SecureStreamSocketImpl(StreamSocketImpl* pStreamSocket, Context::Ptr pContext):
|
||||
_impl(pStreamSocket, pContext)
|
||||
{
|
||||
setSockfd(_socket.sockfd());
|
||||
pStreamSocket->duplicate();
|
||||
reset(_impl.sockfd());
|
||||
}
|
||||
|
||||
|
||||
SecureStreamSocketImpl::~SecureStreamSocketImpl()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
SocketImpl* SecureStreamSocketImpl::acceptConnection(SocketAddress& clientAddr)
|
||||
{
|
||||
return _socket.acceptConnection(clientAddr);
|
||||
throw Poco::InvalidAccessException("Cannot acceptConnection() on a SecureStreamSocketImpl");
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::acceptSSL()
|
||||
{
|
||||
_impl.acceptSSL();
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::connect(const SocketAddress& address)
|
||||
{
|
||||
_socket.connect(address);
|
||||
setSockfd(_socket.sockfd());
|
||||
if (_peerHostName.empty()) _peerHostName = address.host().toString();
|
||||
_impl.connect(address, _peerHostName);
|
||||
reset(_impl.sockfd());
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::connect(const SocketAddress& address, const Poco::Timespan& timeout)
|
||||
{
|
||||
_socket.connect(address, timeout);
|
||||
setSockfd(_socket.sockfd());
|
||||
if (_peerHostName.empty()) _peerHostName = address.host().toString();
|
||||
_impl.connect(address, _peerHostName, timeout);
|
||||
reset(_impl.sockfd());
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::connectNB(const SocketAddress& address)
|
||||
{
|
||||
_socket.connectNB(address);
|
||||
setSockfd(_socket.sockfd());
|
||||
if (_peerHostName.empty()) _peerHostName = address.host().toString();
|
||||
_impl.connectNB(address, _peerHostName);
|
||||
reset(_impl.sockfd());
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::connectSSL()
|
||||
{
|
||||
if (_peerHostName.empty()) _peerHostName = peerAddress().host().toString();
|
||||
_impl.connectSSL(_peerHostName);
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::bind(const SocketAddress& address, bool reuseAddress)
|
||||
{
|
||||
_socket.bind(address, reuseAddress);
|
||||
throw Poco::InvalidAccessException("Cannot bind() a SecureStreamSocketImpl");
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::listen(int backlog)
|
||||
{
|
||||
_socket.listen(backlog);
|
||||
setSockfd(_socket.sockfd());
|
||||
throw Poco::InvalidAccessException("Cannot listen() on a SecureStreamSocketImpl");
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::close()
|
||||
{
|
||||
invalidate();
|
||||
_socket.close();
|
||||
reset();
|
||||
_impl.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +130,7 @@ int SecureStreamSocketImpl::sendBytes(const void* buffer, int length, int flags)
|
||||
int remaining = length;
|
||||
while (remaining > 0)
|
||||
{
|
||||
int n = _socket.sendBytes(p, length, flags);
|
||||
int n = _impl.sendBytes(p, length, flags);
|
||||
p += n;
|
||||
remaining -= n;
|
||||
}
|
||||
@@ -120,25 +140,57 @@ int SecureStreamSocketImpl::sendBytes(const void* buffer, int length, int flags)
|
||||
|
||||
int SecureStreamSocketImpl::receiveBytes(void* buffer, int length, int flags)
|
||||
{
|
||||
return _socket.receiveBytes(buffer, length, flags);
|
||||
return _impl.receiveBytes(buffer, length, flags);
|
||||
}
|
||||
|
||||
|
||||
int SecureStreamSocketImpl::sendTo(const void* buffer, int length, const SocketAddress& address, int flags)
|
||||
{
|
||||
return _socket.sendTo(buffer, length, address, flags);
|
||||
throw Poco::InvalidAccessException("Cannot sendTo() on a SecureStreamSocketImpl");
|
||||
}
|
||||
|
||||
|
||||
int SecureStreamSocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
|
||||
{
|
||||
return _socket.receiveFrom(buffer, length, address, flags);
|
||||
throw Poco::InvalidAccessException("Cannot receiveFrom() on a SecureStreamSocketImpl");
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::sendUrgent(unsigned char data)
|
||||
{
|
||||
return _socket.sendUrgent(data);
|
||||
throw Poco::InvalidAccessException("Cannot sendUrgent() on a SecureStreamSocketImpl");
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::shutdownReceive()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::shutdownSend()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::shutdown()
|
||||
{
|
||||
_impl.shutdown();
|
||||
}
|
||||
|
||||
|
||||
void SecureStreamSocketImpl::setPeerHostName(const std::string& peerHostName)
|
||||
{
|
||||
_peerHostName = peerHostName;
|
||||
}
|
||||
|
||||
|
||||
X509Certificate SecureStreamSocketImpl::peerCertificate() const
|
||||
{
|
||||
X509* pCert = _impl.peerCertificate();
|
||||
if (pCert)
|
||||
return X509Certificate(pCert);
|
||||
else
|
||||
throw SSLException("No certificate available yet");
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// Utility.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/Utility.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/Utility.cpp#13 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: Utility
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -44,9 +44,6 @@ namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
int Utility::HTTPS_PORT = 443;
|
||||
|
||||
|
||||
Context::VerificationMode Utility::convertVerificationMode(const std::string& vMode)
|
||||
{
|
||||
std::string mode = Poco::toLower(vMode);
|
||||
@@ -61,7 +58,7 @@ Context::VerificationMode Utility::convertVerificationMode(const std::string& vM
|
||||
else if (mode == "once")
|
||||
verMode = Context::VERIFY_ONCE;
|
||||
else
|
||||
throw Poco::Util::OptionException(std::string("Wrong value >") + vMode + std::string("< for a verificationMode. Can only be none, relaxed, strict or once."));
|
||||
throw Poco::InvalidArgumentException("Invalid verification mode. Should be relaxed, strict or once but got", vMode);
|
||||
|
||||
return verMode;
|
||||
}
|
||||
@@ -74,61 +71,22 @@ std::string Utility::convertCertificateError(long errCode)
|
||||
}
|
||||
|
||||
|
||||
std::string Utility::convertSSLError(SSL* pSSL, int errCode)
|
||||
std::string Utility::getLastError()
|
||||
{
|
||||
|
||||
std::string errMsg;
|
||||
if (errCode > 0) return "no error";
|
||||
|
||||
int connectErr = SSL_get_error(pSSL, errCode);
|
||||
long lErr = 0;
|
||||
char buf[512];
|
||||
|
||||
switch (connectErr)
|
||||
unsigned long errCode = ERR_get_error();
|
||||
if (errCode != 0)
|
||||
{
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
// connection closed
|
||||
errMsg = "connection closed by server";
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
errMsg = "want read";
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
errMsg = "want write";
|
||||
break;
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
errMsg = "want connect";
|
||||
break;
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
errMsg = "want accept";
|
||||
break;
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
errMsg = "want lookup";
|
||||
break;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
errMsg = "syscall";
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
lErr = ERR_get_error();
|
||||
if (errCode == 0)
|
||||
{
|
||||
errMsg = "EOF was observed";
|
||||
}
|
||||
else if (errCode == -1)
|
||||
{
|
||||
errMsg = "The underlying BIO reported an I/O error";
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_error_string_n(lErr, buf, 512);
|
||||
errMsg = buf;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errMsg = "none";
|
||||
char buffer[256];
|
||||
ERR_error_string_n(errCode, buffer, sizeof(buffer));
|
||||
return std::string(buffer);
|
||||
}
|
||||
else return "No error";
|
||||
}
|
||||
|
||||
return errMsg;
|
||||
|
||||
void Utility::clearErrorStack()
|
||||
{
|
||||
ERR_clear_error();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// VerificationErrorArgs.cpp
|
||||
//
|
||||
// $Id: //poco/svn/NetSSL_OpenSSL/src/VerificationErrorArgs.cpp#1 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/VerificationErrorArgs.cpp#9 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: VerificationErrorArgs
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// X509Certificate.cpp
|
||||
//
|
||||
// $Id: //poco/1.3/NetSSL_OpenSSL/src/X509Certificate.cpp#2 $
|
||||
// $Id: //poco/Main/NetSSL_OpenSSL/src/X509Certificate.cpp#13 $
|
||||
//
|
||||
// Library: NetSSL_OpenSSL
|
||||
// Package: SSLCore
|
||||
// Module: X509Certificate
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
@@ -37,69 +37,93 @@
|
||||
#include "Poco/Net/X509Certificate.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/Net/SecureSocketImpl.h"
|
||||
#include "Poco/Net/DNS.h"
|
||||
#include "Poco/TemporaryFile.h"
|
||||
#include "Poco/FileStream.h"
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/RegularExpression.h"
|
||||
#include "Poco/DateTimeParser.h"
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(const std::string& file):
|
||||
_issuerName(),
|
||||
_subjectName(),
|
||||
_pCert(0),
|
||||
_file(file)
|
||||
X509Certificate::X509Certificate(std::istream& istr):
|
||||
_pCert(0)
|
||||
{
|
||||
// copy certificate to a temporary file so that it
|
||||
// can be read by OpenSSL.
|
||||
Poco::TemporaryFile certFile;
|
||||
std::string path = certFile.path();
|
||||
Poco::FileOutputStream ostr(path);
|
||||
Poco::StreamCopier::copyStream(istr, ostr);
|
||||
ostr.close();
|
||||
|
||||
BIO *pBIO = BIO_new(BIO_s_file());
|
||||
if (!pBIO) throw SSLException("Cannot create BIO for reading certificate file");
|
||||
if (!BIO_read_filename(pBIO, path.c_str()))
|
||||
{
|
||||
BIO_free(pBIO);
|
||||
throw Poco::OpenFileException("Cannot open certificate file for reading");
|
||||
}
|
||||
|
||||
_pCert = PEM_read_bio_X509(pBIO, 0, 0, 0);
|
||||
BIO_free(pBIO);
|
||||
|
||||
if (!_pCert) throw SSLException("Faild to load certificate");
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(const std::string& path):
|
||||
_pCert(0)
|
||||
{
|
||||
BIO *fp=BIO_new(BIO_s_file());
|
||||
const char* pFN = file.c_str();
|
||||
BIO_read_filename(fp, (void*)pFN);
|
||||
if (!fp)
|
||||
throw Poco::PathNotFoundException("Failed to open " + file);
|
||||
try
|
||||
BIO *pBIO = BIO_new(BIO_s_file());
|
||||
if (!pBIO) throw SSLException("Cannot create BIO for reading certificate file");
|
||||
if (!BIO_read_filename(pBIO, path.c_str()))
|
||||
{
|
||||
_pCert = PEM_read_bio_X509(fp,0,0,0);
|
||||
BIO_free(pBIO);
|
||||
throw Poco::OpenFileException("Cannot open certificate file for reading");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
BIO_free(fp);
|
||||
throw;
|
||||
}
|
||||
if (!_pCert)
|
||||
throw SSLException("Faild to load certificate from " + file);
|
||||
initialize();
|
||||
|
||||
_pCert = PEM_read_bio_X509(pBIO, 0, 0, 0);
|
||||
BIO_free(pBIO);
|
||||
|
||||
if (!_pCert) throw SSLException("Faild to load certificate from " + path);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(X509* pCert):
|
||||
_issuerName(),
|
||||
_subjectName(),
|
||||
_pCert(pCert),
|
||||
_file()
|
||||
_pCert(pCert)
|
||||
{
|
||||
poco_check_ptr(_pCert);
|
||||
initialize();
|
||||
|
||||
_pCert = X509_dup(_pCert);
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
X509Certificate::X509Certificate(const X509Certificate& cert):
|
||||
_issuerName(cert._issuerName),
|
||||
_subjectName(cert._subjectName),
|
||||
_pCert(cert._pCert),
|
||||
_file(cert._file)
|
||||
_pCert(cert._pCert)
|
||||
{
|
||||
if (!_file.empty())
|
||||
_pCert = X509_dup(_pCert);
|
||||
_pCert = X509_dup(_pCert);
|
||||
}
|
||||
|
||||
|
||||
X509Certificate& X509Certificate::operator=(const X509Certificate& cert)
|
||||
X509Certificate& X509Certificate::operator = (const X509Certificate& cert)
|
||||
{
|
||||
if (this != &cert)
|
||||
{
|
||||
X509Certificate c(cert);
|
||||
swap(c);
|
||||
}
|
||||
X509Certificate tmp(cert);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -107,7 +131,6 @@ X509Certificate& X509Certificate::operator=(const X509Certificate& cert)
|
||||
void X509Certificate::swap(X509Certificate& cert)
|
||||
{
|
||||
using std::swap;
|
||||
swap(cert._file, _file);
|
||||
swap(cert._issuerName, _issuerName);
|
||||
swap(cert._subjectName, _subjectName);
|
||||
swap(cert._pCert, _pCert);
|
||||
@@ -116,25 +139,161 @@ void X509Certificate::swap(X509Certificate& cert)
|
||||
|
||||
X509Certificate::~X509Certificate()
|
||||
{
|
||||
if (!_file.empty() && _pCert)
|
||||
X509_free(_pCert);
|
||||
X509_free(_pCert);
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::initialize()
|
||||
void X509Certificate::init()
|
||||
{
|
||||
char data[256];
|
||||
X509_NAME_oneline(X509_get_issuer_name(_pCert), data, 256);
|
||||
_issuerName = data;
|
||||
X509_NAME_oneline(X509_get_subject_name(_pCert), data, 256);
|
||||
_subjectName = data;
|
||||
char buffer[NAME_BUFFER_SIZE];
|
||||
X509_NAME_oneline(X509_get_issuer_name(_pCert), buffer, sizeof(buffer));
|
||||
_issuerName = buffer;
|
||||
X509_NAME_oneline(X509_get_subject_name(_pCert), buffer, sizeof(buffer));
|
||||
_subjectName = buffer;
|
||||
}
|
||||
|
||||
|
||||
bool X509Certificate::verify(const std::string& hostName, Poco::SharedPtr<Context> ptr)
|
||||
long X509Certificate::verify(const std::string& hostName) const
|
||||
{
|
||||
std::string commonName;
|
||||
std::set<std::string> dnsNames;
|
||||
extractNames(commonName, dnsNames);
|
||||
bool ok = (dnsNames.find(hostName) != dnsNames.end());
|
||||
|
||||
char buffer[NAME_BUFFER_SIZE];
|
||||
X509_NAME* subj = 0;
|
||||
if (!ok && (subj = X509_get_subject_name(_pCert)) && X509_NAME_get_text_by_NID(subj, NID_commonName, buffer, sizeof(buffer)) > 0)
|
||||
{
|
||||
buffer[NAME_BUFFER_SIZE - 1] = 0;
|
||||
std::string commonName(buffer); // commonName can contain wildcards like *.appinf.com
|
||||
try
|
||||
{
|
||||
// two cases: strData contains wildcards or not
|
||||
if (containsWildcards(commonName))
|
||||
{
|
||||
// a compare by IPAddress is not possible with wildcards
|
||||
// only allow compare by name
|
||||
const HostEntry& heData = DNS::resolve(hostName);
|
||||
ok = matchByAlias(commonName, heData);
|
||||
}
|
||||
else
|
||||
{
|
||||
// it depends on hostName if we compare by IP or by alias
|
||||
IPAddress ip;
|
||||
if (IPAddress::tryParse(hostName, ip))
|
||||
{
|
||||
// compare by IP
|
||||
const HostEntry& heData = DNS::resolve(commonName);
|
||||
const HostEntry::AddressList& addr = heData.addresses();
|
||||
HostEntry::AddressList::const_iterator it = addr.begin();
|
||||
HostEntry::AddressList::const_iterator itEnd = addr.end();
|
||||
for (; it != itEnd && !ok; ++it)
|
||||
{
|
||||
ok = (*it == ip);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// compare by name
|
||||
const HostEntry& heData = DNS::resolve(hostName);
|
||||
ok = matchByAlias(commonName, heData);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (HostNotFoundException&)
|
||||
{
|
||||
return X509_V_ERR_APPLICATION_VERIFICATION;
|
||||
}
|
||||
}
|
||||
|
||||
// we already have a verify callback registered so no need to ask twice SSL_get_verify_result(pSSL);
|
||||
if (ok)
|
||||
return X509_V_OK;
|
||||
else
|
||||
return X509_V_ERR_APPLICATION_VERIFICATION;
|
||||
}
|
||||
|
||||
|
||||
bool X509Certificate::containsWildcards(const std::string& commonName)
|
||||
{
|
||||
X509* pCert = X509_dup(_pCert);
|
||||
return (X509_V_OK == SecureSocketImpl::postConnectionCheck(ptr, pCert, hostName));
|
||||
return (commonName.find('*') != std::string::npos || commonName.find('?') != std::string::npos);
|
||||
}
|
||||
|
||||
|
||||
bool X509Certificate::matchByAlias(const std::string& alias, const HostEntry& heData)
|
||||
{
|
||||
// fix wildcards
|
||||
std::string aliasRep = Poco::replace(alias, "*", ".*");
|
||||
Poco::replaceInPlace(aliasRep, "..*", ".*");
|
||||
Poco::replaceInPlace(aliasRep, "?", ".?");
|
||||
Poco::replaceInPlace(aliasRep, "..?", ".?");
|
||||
// compare by name
|
||||
Poco::RegularExpression expr(aliasRep);
|
||||
bool found = false;
|
||||
const HostEntry::AliasList& aliases = heData.aliases();
|
||||
HostEntry::AliasList::const_iterator it = aliases.begin();
|
||||
HostEntry::AliasList::const_iterator itEnd = aliases.end();
|
||||
for (; it != itEnd && !found; ++it)
|
||||
{
|
||||
found = expr.match(*it);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
std::string X509Certificate::commonName() const
|
||||
{
|
||||
if (X509_NAME* subj = X509_get_subject_name(_pCert))
|
||||
{
|
||||
char buffer[NAME_BUFFER_SIZE];
|
||||
X509_NAME_get_text_by_NID(subj, NID_commonName, buffer, sizeof(buffer));
|
||||
return std::string(buffer);
|
||||
}
|
||||
else return std::string();
|
||||
}
|
||||
|
||||
|
||||
void X509Certificate::extractNames(std::string& cmnName, std::set<std::string>& domainNames) const
|
||||
{
|
||||
domainNames.clear();
|
||||
if (STACK_OF(GENERAL_NAME)* names = static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(_pCert, NID_subject_alt_name, 0, 0)))
|
||||
{
|
||||
for (int i = 0; i < sk_GENERAL_NAME_num(names); ++i)
|
||||
{
|
||||
const GENERAL_NAME* name = sk_GENERAL_NAME_value(names, i);
|
||||
if (name->type == GEN_DNS)
|
||||
{
|
||||
const char* data = reinterpret_cast<char*>(ASN1_STRING_data(name->d.ia5));
|
||||
std::size_t len = ASN1_STRING_length(name->d.ia5);
|
||||
domainNames.insert(std::string(data, len));
|
||||
}
|
||||
}
|
||||
GENERAL_NAMES_free(names);
|
||||
}
|
||||
|
||||
cmnName = commonName();
|
||||
if (!cmnName.empty() && domainNames.empty())
|
||||
{
|
||||
domainNames.insert(cmnName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Poco::DateTime X509Certificate::validFrom() const
|
||||
{
|
||||
ASN1_TIME* certTime = X509_get_notBefore(_pCert);
|
||||
std::string dateTime(reinterpret_cast<char*>(certTime->data));
|
||||
int tzd;
|
||||
return DateTimeParser::parse("%y%m%d%H%M%S", dateTime, tzd);
|
||||
}
|
||||
|
||||
|
||||
Poco::DateTime X509Certificate::expiresOn() const
|
||||
{
|
||||
ASN1_TIME* certTime = X509_get_notAfter(_pCert);
|
||||
std::string dateTime(reinterpret_cast<char*>(certTime->data));
|
||||
int tzd;
|
||||
return DateTimeParser::parse("%y%m%d%H%M%S", dateTime, tzd);
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user