NetSSL provides a socket class implementation that utilizes the Schannel API on Windows 32-bit platforms.
Adding NetSSL support to your existing POCO client application is simply a matter of creating a SecureSocketStream instead of a SocketStream:
#include "Poco/Net/SocketAddress.h" #include "Poco/Net/SecureStreamSocket.h" [...] Poco::Net::SocketAddress sa("localhost", 8888); Poco::Net::SecureStreamSocket secureSocket(sa);
In most cases one will not work directly with a SecureStreamSocket, instead one will use a HTTPSStreamFactory and the URIStreamOpener to create an input stream:
#include "Poco/Net/HTTPSStreamFactory.h" #include "Poco/URI.h" #include "Poco/URIStreamOpener.h" [...] // register the factory at the very beginning of your application Poco::Net::HTTPSStreamFactory::registerFactory(); Poco::URI uri("https://wwww.myserver.com"); std::auto_ptr<std::istream> pStr(Poco::URIStreamOpener::defaultOpener().open(uri)); // creates an HTTPS input stream
Before using the NetSSL library one must provide a configuration. NetSSL supports two different configuration options:
If you configure via a configuration file the initialization of the NetSSL library is delayed until the very first SSLSocket is created, or more precisely: the first call to Poco::Net::SSLManager::instance().defaultClientContext() performs the initialization.
The following parameters are supported in NetSSL:
An example for a clientapp.properties configuration file would be:
schannel.client.certName = schannel.client.verificationMode = relaxed schannel.client.trustRoots = true schannel.client.securityAlgo = tls1+ssl3 schannel.client.revocationChecking = false schannel.client.invalidCertificateHandler.name = AcceptCertificateHandler
The same configuration can be set manually in the source code:
std::string certName; // empty means no cert bool trustRoots = true; bool revocationCheck = false; bool isServer = false; SharedPtr<InvalidCertificateHandler> ptrCert = new AcceptCertificateHandler(isServer); SharedPtr<Context> ptrContext = new Context(isServer, certName, Context::SA_SSL3_TLS1, Context::VERIFY_RELAXED, revocationCheck, trustRoots); SSLManager::instance().initializeClient(ptrCert, ptrContext);
Windows 98/ME ignores the revocationCheck flag.
The schannel.client.invalidCertificateHandler.name allows users to provide their own callback code. An InvalidCertificateHandler is invoked whenever an error occurs verifying the certificate. The user must then inspect and accept/reject the certificate in the callback.
One can install one's own InvalidCertificateHandler by implementing the Poco::Net::InvalidCertificateHandler interface. Each subclass must provide a constructor that takes as input a single parameter bool handleErrorsOnServerSide. This flag tells the certificate handler if it is used on the server side or by the client:
namespace Poco { namespace Net { class NetSSL_API InvalidCertificateHandler { public: InvalidCertificateHandler(bool handleErrorsOnServerSide); /// Creates the InvalidCertificateHandler. /// Set handleErrorsOnServerSide to true if the certificate handler is used on the server side. /// Automatically registers at one of the SSLManager::VerificationError events. virtual ~InvalidCertificateHandler(); /// Destroys the InvalidCertificateHandler. virtual void onInvalidCertificate(const void* pSender, VerificationErrorArgs& errorCert) = 0; /// Receives the questionable certificate in parameter errorCert. If one wants to accept the /// certificate, call errorCert.setIgnoreError(true). protected: bool _handleErrorsOnServerSide; /// Stores if the certificate handler gets invoked by the server (i.e. a client certificate is wrong) /// or the client (a server certificate is wrong) }; } }
The onInvalidCertificate method tells the caller via the out parameter errorCert if it accepts the certificate. The most simple example is the implementation of the AcceptCertificateHandler:
void AcceptCertificateHandler::onInvalidCertificate(const void*, VerificationErrorArgs& errorCert) { // no check, auto-accept errorCert.setIgnoreError(true); }
Note that you must export your own InvalidCertificateHandlers in the startup code of your application. In this example we register a class MyGuiHandler:
Poco::Net::SSLManager::instance().certificateHandlerFactoryMgr().setFactory("MyGuiHandler", new Poco::Net::CertificateHandlerFactoryImpl<MyGuiHandler>());
NetSSL itself offers some predefined invalid certificate handlers which are always available:
Note that the predefined handlers are very simple. It is highly recommended that you write your own one!
After the context was initialized (either explicitly in the source code or implicitly from a configuration file by calling SSLManager::instance().defaultClientContext()), one has the possibility to add trusted certificates to the context. If a certificate is added explicitly to the context, it is automatically trustworthy as a CA, i.e. no expiry checking is performed!
#include "Poco/Net/Context.h" #include "Poco/Net/SSLManager.h" PCCERT_CONTEXT pCert = 0; // init pCert somehow [...] SSLManager::instance().defaultClientContext().addTrustedCert(pCert);