|
|
|
|
@@ -24,9 +24,11 @@
|
|
|
|
|
#include "Poco/StringTokenizer.h"
|
|
|
|
|
#include "Poco/Util/Application.h"
|
|
|
|
|
#include "Poco/Util/OptionException.h"
|
|
|
|
|
|
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
|
|
|
|
|
#include <openssl/ocsp.h>
|
|
|
|
|
#include <openssl/tls1.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Poco {
|
|
|
|
|
namespace Net {
|
|
|
|
|
@@ -236,124 +238,147 @@ int SSLManager::privateKeyPassphraseCallback(char* pBuf, int size, int flag, voi
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SSLManager::verifyOCSPResponse(SSL *ssl, void *arg)
|
|
|
|
|
|
|
|
|
|
int SSLManager::verifyOCSPResponseCallback(SSL* pSSL, void* arg)
|
|
|
|
|
{
|
|
|
|
|
Poco::Net::Context* pocoCtx = (Poco::Net::Context*)arg;
|
|
|
|
|
//Fetch the OSCP verify flag
|
|
|
|
|
bool ocspverifyFlag = pocoCtx->ocspStaplingResponseVerificationEnabled();
|
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
|
|
|
|
|
const long OCSP_VALIDITY_LEEWAY = 5*60;
|
|
|
|
|
|
|
|
|
|
const unsigned char *resp;
|
|
|
|
|
int len = SSL_get_tlsext_status_ocsp_resp(ssl,&resp);
|
|
|
|
|
if (!resp) {
|
|
|
|
|
//OCSP response not received
|
|
|
|
|
return ocspverifyFlag ? 0 : 1;
|
|
|
|
|
Poco::Net::Context* pContext = static_cast<Poco::Net::Context*>(arg);
|
|
|
|
|
|
|
|
|
|
// Fetch the OSCP verify flag
|
|
|
|
|
bool ocspVerifyFlag = pContext->ocspStaplingResponseVerificationEnabled();
|
|
|
|
|
|
|
|
|
|
const unsigned char* pResp;
|
|
|
|
|
int len = SSL_get_tlsext_status_ocsp_resp(pSSL, &pResp);
|
|
|
|
|
if (!pResp)
|
|
|
|
|
{
|
|
|
|
|
// OCSP response not received
|
|
|
|
|
return ocspVerifyFlag ? 0 : 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OCSP_RESPONSE *ocspResp = d2i_OCSP_RESPONSE(NULL,&resp,len);
|
|
|
|
|
if (!ocspResp) {
|
|
|
|
|
OCSP_RESPONSE* pOcspResp = d2i_OCSP_RESPONSE(NULL, &pResp, len);
|
|
|
|
|
if (!pOcspResp) return 0;
|
|
|
|
|
|
|
|
|
|
if (OCSP_response_status(pOcspResp) != OCSP_RESPONSE_STATUS_SUCCESSFUL)
|
|
|
|
|
{
|
|
|
|
|
OCSP_RESPONSE_free(pOcspResp);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (OCSP_response_status(ocspResp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
|
|
|
|
|
OCSP_RESPONSE_free(ocspResp);
|
|
|
|
|
OCSP_BASICRESP* pBasicResp = OCSP_response_get1_basic(pOcspResp);
|
|
|
|
|
if (!pBasicResp)
|
|
|
|
|
{
|
|
|
|
|
OCSP_RESPONSE_free(pOcspResp);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OCSP_BASICRESP *basicResp = OCSP_response_get1_basic(ocspResp);
|
|
|
|
|
if (!basicResp) {
|
|
|
|
|
OCSP_RESPONSE_free(ocspResp);
|
|
|
|
|
X509* pPeerCert = SSL_get_peer_certificate(pSSL);
|
|
|
|
|
if (!pPeerCert)
|
|
|
|
|
{
|
|
|
|
|
OCSP_BASICRESP_free(pBasicResp);
|
|
|
|
|
OCSP_RESPONSE_free(pOcspResp);
|
|
|
|
|
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;
|
|
|
|
|
X509* pPeerIssuerCert = NULL;
|
|
|
|
|
STACK_OF(X509)* pCertChain = SSL_get_peer_cert_chain(pSSL);
|
|
|
|
|
unsigned certChainLen = sk_X509_num(pCertChain);
|
|
|
|
|
for (int i= 0; i < certChainLen ; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!pPeerIssuerCert)
|
|
|
|
|
{
|
|
|
|
|
X509* pIssuerCert = sk_X509_value(pCertChain, i);
|
|
|
|
|
if (X509_check_issued(pIssuerCert, pPeerCert) == X509_V_OK)
|
|
|
|
|
{
|
|
|
|
|
pPeerIssuerCert = pIssuerCert;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!peerIssuerCert) {
|
|
|
|
|
X509_free(peerCert);
|
|
|
|
|
OCSP_BASICRESP_free(basicResp);
|
|
|
|
|
OCSP_RESPONSE_free(ocspResp);
|
|
|
|
|
if (!pPeerIssuerCert)
|
|
|
|
|
{
|
|
|
|
|
X509_free(pPeerCert);
|
|
|
|
|
OCSP_BASICRESP_free(pBasicResp);
|
|
|
|
|
OCSP_RESPONSE_free(pOcspResp);
|
|
|
|
|
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;
|
|
|
|
|
STACK_OF(X509)* pCerts = sk_X509_new_null();
|
|
|
|
|
if (pCerts)
|
|
|
|
|
{
|
|
|
|
|
X509* pCert = X509_dup(pPeerIssuerCert);
|
|
|
|
|
if (pCert && !sk_X509_push(pCerts, pCert))
|
|
|
|
|
{
|
|
|
|
|
X509_free(pCert);
|
|
|
|
|
sk_X509_free(pCerts);
|
|
|
|
|
pCerts = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
X509_STORE *store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(ssl));
|
|
|
|
|
X509_STORE* pStore = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(pSSL));
|
|
|
|
|
|
|
|
|
|
int verifyStatus = OCSP_basic_verify(basicResp,certs,store,OCSP_TRUSTOTHER);
|
|
|
|
|
int verifyStatus = OCSP_basic_verify(pBasicResp, pCerts, pStore, OCSP_TRUSTOTHER);
|
|
|
|
|
|
|
|
|
|
sk_X509_pop_free(certs, X509_free);
|
|
|
|
|
sk_X509_pop_free(pCerts, X509_free);
|
|
|
|
|
|
|
|
|
|
if (verifyStatus <= 0) {
|
|
|
|
|
X509_free(peerCert);
|
|
|
|
|
OCSP_BASICRESP_free(basicResp);
|
|
|
|
|
OCSP_RESPONSE_free(ocspResp);
|
|
|
|
|
if (verifyStatus <= 0)
|
|
|
|
|
{
|
|
|
|
|
X509_free(pPeerCert);
|
|
|
|
|
OCSP_BASICRESP_free(pBasicResp);
|
|
|
|
|
OCSP_RESPONSE_free(pOcspResp);
|
|
|
|
|
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);
|
|
|
|
|
OCSP_CERTID* pCertId = OCSP_cert_to_id(NULL, pPeerCert, pPeerIssuerCert);
|
|
|
|
|
if (!pCertId)
|
|
|
|
|
{
|
|
|
|
|
X509_free(pPeerCert);
|
|
|
|
|
OCSP_BASICRESP_free(pBasicResp);
|
|
|
|
|
OCSP_RESPONSE_free(pOcspResp);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
X509_free(peerCert);
|
|
|
|
|
X509_free(pPeerCert);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
ASN1_GENERALIZEDTIME* pRevTime;
|
|
|
|
|
ASN1_GENERALIZEDTIME* pThisUpdate;
|
|
|
|
|
ASN1_GENERALIZEDTIME* pNextUpdate;
|
|
|
|
|
int certStatus;
|
|
|
|
|
int reason;
|
|
|
|
|
if (!OCSP_resp_find_status(pBasicResp, pCertId, &certStatus, &reason, &pRevTime, &pThisUpdate, &pNextUpdate))
|
|
|
|
|
{
|
|
|
|
|
OCSP_CERTID_free(pCertId);
|
|
|
|
|
OCSP_BASICRESP_free(pBasicResp);
|
|
|
|
|
OCSP_RESPONSE_free(pOcspResp);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OCSP_CERTID_free(certId);
|
|
|
|
|
OCSP_CERTID_free(pCertId);
|
|
|
|
|
|
|
|
|
|
if (certstatus != V_OCSP_CERTSTATUS_GOOD){
|
|
|
|
|
OCSP_BASICRESP_free(basicResp);
|
|
|
|
|
OCSP_RESPONSE_free(ocspResp);
|
|
|
|
|
if (certStatus != V_OCSP_CERTSTATUS_GOOD)
|
|
|
|
|
{
|
|
|
|
|
OCSP_BASICRESP_free(pBasicResp);
|
|
|
|
|
OCSP_RESPONSE_free(pOcspResp);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!OCSP_check_validity(thisupd,nextupd,5*60,-1)) {
|
|
|
|
|
OCSP_BASICRESP_free(basicResp);
|
|
|
|
|
OCSP_RESPONSE_free(ocspResp);
|
|
|
|
|
if (!OCSP_check_validity(pThisUpdate, pNextUpdate, OCSP_VALIDITY_LEEWAY, -1))
|
|
|
|
|
{
|
|
|
|
|
OCSP_BASICRESP_free(pBasicResp);
|
|
|
|
|
OCSP_RESPONSE_free(pOcspResp);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OCSP_BASICRESP_free(basicResp);
|
|
|
|
|
OCSP_RESPONSE_free(ocspResp);
|
|
|
|
|
OCSP_BASICRESP_free(pBasicResp);
|
|
|
|
|
OCSP_RESPONSE_free(pOcspResp);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SSLManager::initDefaultContext(bool server)
|
|
|
|
|
{
|
|
|
|
|
if (server && _ptrDefaultServerContext) return;
|
|
|
|
|
|