diff --git a/NetSSL_OpenSSL/include/Poco/Net/Context.h b/NetSSL_OpenSSL/include/Poco/Net/Context.h index 35b640a45..6b06f9c79 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/Context.h +++ b/NetSSL_OpenSSL/include/Poco/Net/Context.h @@ -156,6 +156,10 @@ public: /// Specifies whether the builtin CA certificates from OpenSSL are used. /// Defaults to false. + bool ocspStaplingVerification; + /// Specifies whether Client should verify OCSP Response + /// Defaults to false. + std::string cipherList; /// Specifies the supported ciphers in OpenSSL notation. /// Defaults to "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH". @@ -395,7 +399,11 @@ public: /// When choosing a cipher, use the server's preferences instead of the client /// preferences. When not called, the SSL server will always follow the clients /// preferences. When called, the SSL/TLS server will choose following its own - /// preferences. + /// preferences. + + bool ocspStaplingResponseVerificationEnabled() const; + /// Returns true if automatic OCSP response + /// reception and verification is enabled for client connections private: void init(const Params& params); @@ -415,6 +423,7 @@ private: VerificationMode _mode; SSL_CTX* _pSSLContext; bool _extendedCertificateVerification; + bool _ocspStaplingResponseVerification; }; diff --git a/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h b/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h index 33a902a80..82817c7f7 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h +++ b/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h @@ -278,6 +278,11 @@ protected: /// Throws a InvalidStateException if not application instance /// is available. + static int verifyOCSPResponse(SSL *s, void *arg); + /// The return value of this method defines how errors in + /// verification are handled. Return 0 to terminate the handshake, + /// or 1 to continue despite the error. + private: SSLManager(); /// Creates the SSLManager. diff --git a/NetSSL_OpenSSL/src/Context.cpp b/NetSSL_OpenSSL/src/Context.cpp index 23a08af3b..4fb0e6480 100644 --- a/NetSSL_OpenSSL/src/Context.cpp +++ b/NetSSL_OpenSSL/src/Context.cpp @@ -34,6 +34,7 @@ Context::Params::Params(): verificationMode(VERIFY_RELAXED), verificationDepth(9), loadDefaultCAs(false), + ocspStaplingVerification(false), cipherList("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"), dhUse2048Bits(false) { @@ -44,7 +45,8 @@ Context::Context(Usage usage, const Params& params): _usage(usage), _mode(params.verificationMode), _pSSLContext(0), - _extendedCertificateVerification(true) + _extendedCertificateVerification(true), + _ocspStaplingResponseVerification(false) { init(params); } @@ -62,7 +64,8 @@ Context::Context( _usage(usage), _mode(verificationMode), _pSSLContext(0), - _extendedCertificateVerification(true) + _extendedCertificateVerification(true), + _ocspStaplingResponseVerification(false) { Params params; params.privateKeyFile = privateKeyFile; @@ -86,7 +89,8 @@ Context::Context( _usage(usage), _mode(verificationMode), _pSSLContext(0), - _extendedCertificateVerification(true) + _extendedCertificateVerification(true), + _ocspStaplingResponseVerification(false) { Params params; params.caLocation = caLocation; @@ -175,6 +179,11 @@ void Context::init(const Params& params) SSL_CTX_set_mode(_pSSLContext, SSL_MODE_AUTO_RETRY); SSL_CTX_set_session_cache_mode(_pSSLContext, SSL_SESS_CACHE_OFF); + if (!isForServerUse() && params.ocspStaplingVerification){ + _ocspStaplingResponseVerification = true; + SSL_CTX_set_tlsext_status_cb(_pSSLContext, &SSLManager::verifyOCSPResponse); + SSL_CTX_set_tlsext_status_arg(_pSSLContext, this); + } initDH(params.dhUse2048Bits, params.dhParamsFile); initECDH(params.ecdhCurve); } diff --git a/NetSSL_OpenSSL/src/SSLManager.cpp b/NetSSL_OpenSSL/src/SSLManager.cpp index bf5ef4600..7958652fe 100644 --- a/NetSSL_OpenSSL/src/SSLManager.cpp +++ b/NetSSL_OpenSSL/src/SSLManager.cpp @@ -25,6 +25,8 @@ #include "Poco/Util/Application.h" #include "Poco/Util/OptionException.h" +#include +#include namespace Poco { namespace Net { @@ -234,6 +236,123 @@ int SSLManager::privateKeyPassphraseCallback(char* pBuf, int size, int flag, voi return size; } +int SSLManager::verifyOCSPResponse(SSL *ssl, void *arg) +{ + Poco::Net::Context* pocoCtx = (Poco::Net::Context*)arg; + //Fetch the OSCP verify flag + bool ocspverifyFlag = pocoCtx->ocspStaplingResponseVerificationEnabled(); + + const unsigned char *resp; + int len = SSL_get_tlsext_status_ocsp_resp(ssl,&resp); + if (!resp) { + //OCSP response not received + return ocspverifyFlag ? 0 : 1; + } + + OCSP_RESPONSE *ocspResp = d2i_OCSP_RESPONSE(NULL,&resp,len); + if (!ocspResp) { + return 0; + } + + if (OCSP_response_status(ocspResp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + OCSP_RESPONSE_free(ocspResp); + return 0; + } + + OCSP_BASICRESP *basicResp = OCSP_response_get1_basic(ocspResp); + if (!basicResp) { + OCSP_RESPONSE_free(ocspResp); + return 0; + } + + X509 *peerCert = SSL_get_peer_certificate(ssl); + if (!peerCert) { + OCSP_BASICRESP_free(basicResp); + OCSP_RESPONSE_free(ocspResp); + return 0; + } + + X509 *peerIssuerCert = NULL; + STACK_OF(X509) *certChain = SSL_get_peer_cert_chain(ssl); + unsigned certChainLen = sk_X509_num(certChain); + for (int i= 0; i < certChainLen ; i++) { + if(!peerIssuerCert){ + X509 *issuer = sk_X509_value(certChain,i); + if (X509_check_issued(issuer,peerCert) == X509_V_OK){ + peerIssuerCert = issuer; + break; + } + } + } + if (!peerIssuerCert) { + X509_free(peerCert); + OCSP_BASICRESP_free(basicResp); + OCSP_RESPONSE_free(ocspResp); + return 0; + } + + STACK_OF(X509) *certs = sk_X509_new_null(); + if (certs) { + X509 *cert = X509_dup(peerIssuerCert); + if (cert && !sk_X509_push(certs,cert)) { + X509_free(cert); + sk_X509_free(certs); + certs = NULL; + } + } + + + X509_STORE *store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(ssl)); + + int verifyStatus = OCSP_basic_verify(basicResp,certs,store,OCSP_TRUSTOTHER); + + sk_X509_pop_free(certs, X509_free); + + if (verifyStatus <= 0) { + X509_free(peerCert); + OCSP_BASICRESP_free(basicResp); + OCSP_RESPONSE_free(ocspResp); + return 0; + } + + OCSP_CERTID *certId = OCSP_cert_to_id(NULL,peerCert,peerIssuerCert); + if (!certId) { + X509_free(peerCert); + OCSP_BASICRESP_free(basicResp); + OCSP_RESPONSE_free(ocspResp); + return 0; + } + + X509_free(peerCert); + + ASN1_GENERALIZEDTIME *revtime, *thisupd, *nextupd; + int certstatus,reason; + if (!OCSP_resp_find_status(basicResp,certId,&certstatus,&reason,&revtime,&thisupd,&nextupd)) { + OCSP_CERTID_free(certId); + OCSP_BASICRESP_free(basicResp); + OCSP_RESPONSE_free(ocspResp); + return 0; + } + + OCSP_CERTID_free(certId); + + if (certstatus != V_OCSP_CERTSTATUS_GOOD){ + OCSP_BASICRESP_free(basicResp); + OCSP_RESPONSE_free(ocspResp); + return 0; + } + + if (!OCSP_check_validity(thisupd,nextupd,5*60,-1)) { + OCSP_BASICRESP_free(basicResp); + OCSP_RESPONSE_free(ocspResp); + return 0; + } + + OCSP_BASICRESP_free(basicResp); + OCSP_RESPONSE_free(ocspResp); + + return 1; +} void SSLManager::initDefaultContext(bool server) { diff --git a/NetSSL_OpenSSL/src/SecureSocketImpl.cpp b/NetSSL_OpenSSL/src/SecureSocketImpl.cpp index 6dfc40727..8a2008288 100644 --- a/NetSSL_OpenSSL/src/SecureSocketImpl.cpp +++ b/NetSSL_OpenSSL/src/SecureSocketImpl.cpp @@ -163,6 +163,9 @@ void SecureSocketImpl::connectSSL(bool performHandshake) SSL_set_tlsext_host_name(_pSSL, _peerHostName.c_str()); } #endif + + if(_pContext->ocspStaplingResponseVerificationEnabled()) + SSL_set_tlsext_status_type(_pSSL, TLSEXT_STATUSTYPE_ocsp); if (_pSession) {