mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-23 00:07:59 +02:00
fixed certificate name verification
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
// $Id$
|
// $Id$
|
||||||
//
|
//
|
||||||
// Library: Crypto
|
// Library: NetSSL_Win
|
||||||
// Package: Certificate
|
// Package: Certificate
|
||||||
// Module: X509Certificate
|
// Module: X509Certificate
|
||||||
//
|
//
|
||||||
@@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
#include "Poco/Net/NetSSL.h"
|
#include "Poco/Net/NetSSL.h"
|
||||||
#include "Poco/DateTime.h"
|
#include "Poco/DateTime.h"
|
||||||
#include "Poco/SharedPtr.h"
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <istream>
|
||||||
#include <wincrypt.h>
|
#include <wincrypt.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -51,6 +51,10 @@ public:
|
|||||||
/// Creates the X509Certificate object by reading
|
/// Creates the X509Certificate object by reading
|
||||||
/// a certificate in PEM or DER format from a file.
|
/// a certificate in PEM or DER format from a file.
|
||||||
|
|
||||||
|
explicit X509Certificate(std::istream& istr);
|
||||||
|
/// Creates the X509Certificate object by reading
|
||||||
|
/// a certificate in PEM or DER format from a stream.
|
||||||
|
|
||||||
X509Certificate(const std::string& certName, const std::string& certStoreName, bool useMachineStore = false);
|
X509Certificate(const std::string& certName, const std::string& certStoreName, bool useMachineStore = false);
|
||||||
/// Creates the X509Certificate object by loading
|
/// Creates the X509Certificate object by loading
|
||||||
/// a certificate from the specified certificate store.
|
/// a certificate from the specified certificate store.
|
||||||
@@ -116,9 +120,8 @@ public:
|
|||||||
/// the issuer given by issuerCertificate. This can be
|
/// the issuer given by issuerCertificate. This can be
|
||||||
/// used to validate a certificate chain.
|
/// used to validate a certificate chain.
|
||||||
///
|
///
|
||||||
/// Verifies if the certificate has been signed with the
|
/// Verifies that the given certificate is contained in the
|
||||||
/// issuer's private key, using the public key from the issuer
|
/// certificate's issuer certificate chain.
|
||||||
/// certificate.
|
|
||||||
///
|
///
|
||||||
/// Returns true if verification against the issuer certificate
|
/// Returns true if verification against the issuer certificate
|
||||||
/// was successful, false otherwise.
|
/// was successful, false otherwise.
|
||||||
@@ -141,7 +144,6 @@ public:
|
|||||||
///
|
///
|
||||||
/// Returns true if verification succeeded, or false otherwise.
|
/// Returns true if verification succeeded, or false otherwise.
|
||||||
|
|
||||||
|
|
||||||
const PCCERT_CONTEXT system() const;
|
const PCCERT_CONTEXT system() const;
|
||||||
/// Returns the underlying WinCrypt certificate.
|
/// Returns the underlying WinCrypt certificate.
|
||||||
|
|
||||||
@@ -154,6 +156,7 @@ protected:
|
|||||||
|
|
||||||
void loadCertificate(const std::string& certName, const std::string& certStoreName, bool useMachineStore);
|
void loadCertificate(const std::string& certName, const std::string& certStoreName, bool useMachineStore);
|
||||||
void importCertificate(const std::string& certPath);
|
void importCertificate(const std::string& certPath);
|
||||||
|
void importCertificate(std::istream& istr);
|
||||||
void importCertificate(const char* pBuffer, std::size_t size);
|
void importCertificate(const char* pBuffer, std::size_t size);
|
||||||
void importPEMCertificate(const char* pBuffer, std::size_t size);
|
void importPEMCertificate(const char* pBuffer, std::size_t size);
|
||||||
void importDERCertificate(const char* pBuffer, std::size_t size);
|
void importDERCertificate(const char* pBuffer, std::size_t size);
|
||||||
@@ -162,11 +165,6 @@ protected:
|
|||||||
static bool matchWildcard(const std::string& alias, const std::string& hostName);
|
static bool matchWildcard(const std::string& alias, const std::string& hostName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
|
||||||
{
|
|
||||||
NAME_BUFFER_SIZE = 256
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string _issuerName;
|
std::string _issuerName;
|
||||||
std::string _subjectName;
|
std::string _subjectName;
|
||||||
PCCERT_CONTEXT _pCert;
|
PCCERT_CONTEXT _pCert;
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
#include "Poco/Net/FTPStreamFactory.h"
|
#include "Poco/Net/FTPStreamFactory.h"
|
||||||
#include "Poco/Net/SSLManager.h"
|
#include "Poco/Net/SSLManager.h"
|
||||||
#include "Poco/Net/ConsoleCertificateHandler.h"
|
#include "Poco/Net/ConsoleCertificateHandler.h"
|
||||||
|
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
// $Id$
|
// $Id$
|
||||||
//
|
//
|
||||||
// Library: Crypto
|
// Library: NetSSL_Win
|
||||||
// Package: Certificate
|
// Package: Certificate
|
||||||
// Module: X509Certificate
|
// Module: X509Certificate
|
||||||
//
|
//
|
||||||
@@ -42,6 +42,13 @@ X509Certificate::X509Certificate(const std::string& path):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
X509Certificate::X509Certificate(std::istream& istr):
|
||||||
|
_pCert(0)
|
||||||
|
{
|
||||||
|
importCertificate(istr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
X509Certificate::X509Certificate(const std::string& certName, const std::string& certStoreName, bool useMachineStore):
|
X509Certificate::X509Certificate(const std::string& certName, const std::string& certStoreName, bool useMachineStore):
|
||||||
_pCert(0)
|
_pCert(0)
|
||||||
{
|
{
|
||||||
@@ -106,11 +113,55 @@ X509Certificate::~X509Certificate()
|
|||||||
|
|
||||||
void X509Certificate::init()
|
void X509Certificate::init()
|
||||||
{
|
{
|
||||||
wchar_t data[256];
|
std::string name = issuerName(NID_COUNTRY);
|
||||||
CertGetNameStringW(_pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, data, 256);
|
if (!name.empty())
|
||||||
Poco::UnicodeConverter::convert(data, _issuerName);
|
{
|
||||||
CertGetNameStringW(_pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, data, 256);
|
_issuerName += "/C=";
|
||||||
Poco::UnicodeConverter::convert(data, _subjectName);
|
_issuerName += name;
|
||||||
|
}
|
||||||
|
name = issuerName(NID_STATE_OR_PROVINCE);
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
_issuerName += "/ST=";
|
||||||
|
_issuerName += name;
|
||||||
|
}
|
||||||
|
name = issuerName(NID_ORGANIZATION_NAME);
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
_issuerName += "/O=";
|
||||||
|
_issuerName += name;
|
||||||
|
}
|
||||||
|
name = issuerName(NID_COMMON_NAME);
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
_issuerName += "/CN=";
|
||||||
|
_issuerName += name;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = subjectName(NID_COUNTRY);
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
_subjectName += "/C=";
|
||||||
|
_subjectName += name;
|
||||||
|
}
|
||||||
|
name = subjectName(NID_STATE_OR_PROVINCE);
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
_subjectName += "/ST=";
|
||||||
|
_subjectName += name;
|
||||||
|
}
|
||||||
|
name = subjectName(NID_ORGANIZATION_NAME);
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
_subjectName += "/O=";
|
||||||
|
_subjectName += name;
|
||||||
|
}
|
||||||
|
name = subjectName(NID_COMMON_NAME);
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
_subjectName += "/CN=";
|
||||||
|
_subjectName += name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -123,9 +174,10 @@ std::string X509Certificate::commonName() const
|
|||||||
std::string X509Certificate::issuerName(NID nid) const
|
std::string X509Certificate::issuerName(NID nid) const
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
wchar_t data[256];
|
DWORD size = CertGetNameStringW(_pCert, CERT_NAME_ATTR_TYPE, CERT_NAME_ISSUER_FLAG, nid2oid(nid), 0, 0);
|
||||||
CertGetNameStringW(_pCert, CERT_NAME_ATTR_TYPE, CERT_NAME_ISSUER_FLAG, nid2oid(nid), data, 256);
|
Poco::Buffer<wchar_t> data(size);
|
||||||
Poco::UnicodeConverter::convert(data, result);
|
CertGetNameStringW(_pCert, CERT_NAME_ATTR_TYPE, CERT_NAME_ISSUER_FLAG, nid2oid(nid), data.begin(), size);
|
||||||
|
Poco::UnicodeConverter::convert(data.begin(), result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,9 +185,10 @@ std::string X509Certificate::issuerName(NID nid) const
|
|||||||
std::string X509Certificate::subjectName(NID nid) const
|
std::string X509Certificate::subjectName(NID nid) const
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
wchar_t data[256];
|
DWORD size = CertGetNameStringW(_pCert, CERT_NAME_ATTR_TYPE, 0, nid2oid(nid), 0, 0);
|
||||||
CertGetNameStringW(_pCert, CERT_NAME_ATTR_TYPE, 0, nid2oid(nid), data, 256);
|
Poco::Buffer<wchar_t> data(size);
|
||||||
Poco::UnicodeConverter::convert(data, result);
|
CertGetNameStringW(_pCert, CERT_NAME_ATTR_TYPE, 0, nid2oid(nid), data.begin(), size);
|
||||||
|
Poco::UnicodeConverter::convert(data.begin(), result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +235,7 @@ void X509Certificate::extractNames(std::string& cmnName, std::set<std::string>&
|
|||||||
PCERT_ALT_NAME_INFO pNameInfo = reinterpret_cast<PCERT_ALT_NAME_INFO>(buffer.begin());
|
PCERT_ALT_NAME_INFO pNameInfo = reinterpret_cast<PCERT_ALT_NAME_INFO>(buffer.begin());
|
||||||
for (int i = 0; i < pNameInfo->cAltEntry; i++)
|
for (int i = 0; i < pNameInfo->cAltEntry; i++)
|
||||||
{
|
{
|
||||||
std::wstring waltName(pNameInfo->rgAltEntry->pwszDNSName);
|
std::wstring waltName(pNameInfo->rgAltEntry[i].pwszDNSName);
|
||||||
std::string altName;
|
std::string altName;
|
||||||
Poco::UnicodeConverter::toUTF8(waltName, altName);
|
Poco::UnicodeConverter::toUTF8(waltName, altName);
|
||||||
domainNames.insert(altName);
|
domainNames.insert(altName);
|
||||||
@@ -213,68 +266,40 @@ Poco::DateTime X509Certificate::expiresOn() const
|
|||||||
|
|
||||||
bool X509Certificate::issuedBy(const X509Certificate& issuerCertificate) const
|
bool X509Certificate::issuedBy(const X509Certificate& issuerCertificate) const
|
||||||
{
|
{
|
||||||
class CertStoreHandle
|
CERT_CHAIN_PARA chainPara;
|
||||||
{
|
PCCERT_CHAIN_CONTEXT pChainContext = 0;
|
||||||
public:
|
std::memset(&chainPara, 0, sizeof(chainPara));
|
||||||
CertStoreHandle(HCERTSTORE hStore):
|
chainPara.cbSize = sizeof(chainPara);
|
||||||
_hStore(hStore)
|
|
||||||
|
if (!CertGetCertificateChain(
|
||||||
|
NULL,
|
||||||
|
_pCert,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&chainPara,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&pChainContext))
|
||||||
{
|
{
|
||||||
|
throw SSLException("Cannot get certificate chain", subjectName(), GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
~CertStoreHandle()
|
|
||||||
{
|
|
||||||
if (_hStore) CertCloseStore(_hStore, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
HCERTSTORE handle() const
|
|
||||||
{
|
|
||||||
return _hStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
HCERTSTORE _hStore;
|
|
||||||
};
|
|
||||||
|
|
||||||
CertStoreHandle caStore(CertOpenSystemStoreW(0, L"CA"));
|
|
||||||
CertStoreHandle rootStore(CertOpenSystemStoreW(0, L"ROOT"));
|
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
PCCERT_CONTEXT pIssuer;
|
for (DWORD i = 0; i < pChainContext->cChain && !result; i++)
|
||||||
PCCERT_CONTEXT pIssued = _pCert;
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
DWORD flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
|
for (DWORD k = 0; k < pChainContext->rgpChain[i]->cElement && !result; k++)
|
||||||
pIssuer = 0;
|
|
||||||
if (caStore.handle())
|
|
||||||
{
|
{
|
||||||
pIssuer = CertGetIssuerCertificateFromStore(caStore.handle(), pIssued, 0, &flags);
|
PCCERT_CONTEXT pChainCert = pChainContext->rgpChain[i]->rgpElement[k]->pCertContext;
|
||||||
}
|
if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, issuerCertificate.system()->pCertInfo, pChainCert->pCertInfo))
|
||||||
if (!pIssuer && rootStore.handle())
|
|
||||||
{
|
{
|
||||||
pIssuer = CertGetIssuerCertificateFromStore(rootStore.handle(), pIssued, 0, &flags);
|
if (CertComparePublicKeyInfo(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &issuerCertificate.system()->pCertInfo->SubjectPublicKeyInfo, &pChainCert->pCertInfo->SubjectPublicKeyInfo))
|
||||||
}
|
|
||||||
if (pIssuer)
|
|
||||||
{
|
|
||||||
X509Certificate issuer(pIssuer);
|
|
||||||
if (flags & CERT_STORE_NO_CRL_FLAG)
|
|
||||||
flags &= ~(CERT_STORE_NO_CRL_FLAG | CERT_STORE_REVOCATION_FLAG);
|
|
||||||
if (flags)
|
|
||||||
break;
|
|
||||||
if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, issuerCertificate.system()->pCertInfo, issuer.system()->pCertInfo))
|
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pIssuer->pCertInfo, pIssued->pCertInfo))
|
|
||||||
{
|
|
||||||
// reached self-signed certificate
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else break;
|
|
||||||
}
|
}
|
||||||
while (pIssuer);
|
}
|
||||||
|
CertFreeCertificateChain(pChainContext);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,8 +351,8 @@ void X509Certificate::loadCertificate(const std::string& certName, const std::st
|
|||||||
CERT_RDN_ATTR cert_rdn_attr;
|
CERT_RDN_ATTR cert_rdn_attr;
|
||||||
cert_rdn_attr.pszObjId = szOID_COMMON_NAME;
|
cert_rdn_attr.pszObjId = szOID_COMMON_NAME;
|
||||||
cert_rdn_attr.dwValueType = CERT_RDN_ANY_TYPE;
|
cert_rdn_attr.dwValueType = CERT_RDN_ANY_TYPE;
|
||||||
cert_rdn_attr.Value.cbData = (DWORD) certName.size();
|
cert_rdn_attr.Value.cbData = static_cast<DWORD>(certName.size());
|
||||||
cert_rdn_attr.Value.pbData = (BYTE *) certName.c_str();
|
cert_rdn_attr.Value.pbData = reinterpret_cast<BYTE*>(const_cast<char*>(certName.c_str()));
|
||||||
|
|
||||||
CERT_RDN cert_rdn;
|
CERT_RDN cert_rdn;
|
||||||
cert_rdn.cRDNAttr = 1;
|
cert_rdn.cRDNAttr = 1;
|
||||||
@@ -358,6 +383,18 @@ void X509Certificate::importCertificate(const std::string& certPath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void X509Certificate::importCertificate(std::istream& istr)
|
||||||
|
{
|
||||||
|
std::string data;
|
||||||
|
Poco::StreamCopier::copyToString(istr, data);
|
||||||
|
if (!data.empty())
|
||||||
|
{
|
||||||
|
importCertificate(data.data(), data.size());
|
||||||
|
}
|
||||||
|
else throw Poco::IOException("failed to read certificate from stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void X509Certificate::importCertificate(const char* pBuffer, std::size_t size)
|
void X509Certificate::importCertificate(const char* pBuffer, std::size_t size)
|
||||||
{
|
{
|
||||||
if (std::memcmp(pBuffer, "-----BEGIN CERTIFICATE-----", 27) == 0)
|
if (std::memcmp(pBuffer, "-----BEGIN CERTIFICATE-----", 27) == 0)
|
||||||
|
Reference in New Issue
Block a user