add PKCS12 CA-cert friendly names extraction

This commit is contained in:
Alex Fabijanic 2017-09-28 20:32:41 -05:00
parent dfa32cc158
commit 43ee77f315
6 changed files with 109 additions and 30 deletions

View File

@ -39,6 +39,7 @@ class Crypto_API PKCS12Container
{
public:
typedef X509Certificate::List CAList;
typedef std::vector<std::string> CANameList;
explicit PKCS12Container(std::istream& istr, const std::string& password = "");
/// Creates the PKCS12Container object from a stream.
@ -80,8 +81,12 @@ public:
const std::string& getFriendlyName() const;
/// Returns the friendly name of the certificate bag.
const CANameList& getFriendlyNamesCA() const;
/// Returns a list of CA certificates friendly names.
private:
void load(PKCS12* pPKCS12, const std::string& password = "");
std::string extractFriendlyName(X509* pCert);
typedef std::unique_ptr<X509Certificate> CertPtr;
@ -89,7 +94,8 @@ private:
EVP_PKEY* _pKey = 0;
CertPtr _pX509Cert;
CAList _caCertList;
std::string _pkcsFriendlyname;
CANameList _caCertNames;
std::string _pkcsFriendlyName;
};
@ -113,7 +119,7 @@ inline const X509Certificate& PKCS12Container::getX509Certificate() const
inline const std::string& PKCS12Container::getFriendlyName() const
{
return _pkcsFriendlyname;
return _pkcsFriendlyName;
}
@ -123,6 +129,12 @@ inline const PKCS12Container::CAList& PKCS12Container::getCACerts() const
}
inline const PKCS12Container::CANameList& PKCS12Container::getFriendlyNamesCA() const
{
return _caCertNames;
}
inline bool PKCS12Container::hasKey() const
{
return _pKey != 0;

View File

@ -147,6 +147,9 @@ public:
void print(std::ostream& out) const;
/// Prints the certificate information to ostream.
void printAll(std::ostream& out) const;
/// Prints all the certificate names to ostream.
static List readPEM(const std::string& pemFileName);
/// Reads and returns a list of certificates from
/// the specified PEM file.

View File

@ -67,7 +67,8 @@ PKCS12Container::PKCS12Container(const PKCS12Container& other):
_pKey(EVPPKey::duplicate(other._pKey, &_pKey)),
_pX509Cert(new X509Certificate(*other._pX509Cert)),
_caCertList(other._caCertList),
_pkcsFriendlyname(other._pkcsFriendlyname)
_caCertNames(other._caCertNames),
_pkcsFriendlyName(other._pkcsFriendlyName)
{
}
@ -80,7 +81,8 @@ PKCS12Container& PKCS12Container::operator = (const PKCS12Container& other)
_pKey = EVPPKey::duplicate(other._pKey, &_pKey);
_pX509Cert.reset(new X509Certificate(*other._pX509Cert));
_caCertList = other._caCertList;
_pkcsFriendlyname = other._pkcsFriendlyname;
_caCertNames = other._caCertNames;
_pkcsFriendlyName = other._pkcsFriendlyName;
}
return *this;
}
@ -90,7 +92,8 @@ PKCS12Container::PKCS12Container(PKCS12Container&& other):
_pKey(other._pKey),
_pX509Cert(std::move(other._pX509Cert)),
_caCertList(std::move(other._caCertList)),
_pkcsFriendlyname(std::move(other._pkcsFriendlyname))
_caCertNames(std::move(other._caCertNames)),
_pkcsFriendlyName(std::move(other._pkcsFriendlyName))
{
other._pKey = 0;
}
@ -104,7 +107,8 @@ PKCS12Container& PKCS12Container::operator = (PKCS12Container&& other)
_pKey = other._pKey; other._pKey = 0;
_pX509Cert = std::move(other._pX509Cert);
_caCertList = std::move(other._caCertList);
_pkcsFriendlyname = std::move(other._pkcsFriendlyname);
_caCertNames = std::move(other._caCertNames);
_pkcsFriendlyName = std::move(other._pkcsFriendlyName);
}
return *this;
}
@ -116,6 +120,31 @@ PKCS12Container::~PKCS12Container()
}
std::string PKCS12Container::extractFriendlyName(X509* pCert)
{
std::string friendlyName;
if(pCert)
{
STACK_OF(PKCS12_SAFEBAG)*pBags = 0;
PKCS12_SAFEBAG*pBag = PKCS12_add_cert(&pBags, pCert);
if(pBag)
{
char* pBuffer = PKCS12_get_friendlyname(pBag);
if(pBuffer)
{
friendlyName = pBuffer;
OPENSSL_free(pBuffer);
}
if(pBags) sk_PKCS12_SAFEBAG_pop_free(pBags, PKCS12_SAFEBAG_free);
}
else throw OpenSSLException("PKCS12Container::extractFriendlyName()");
}
else throw NullPointerException("PKCS12Container::extractFriendlyName()");
return friendlyName;
}
void PKCS12Container::load(PKCS12* pPKCS12, const std::string& password)
{
if (pPKCS12)
@ -126,30 +155,25 @@ void PKCS12Container::load(PKCS12* pPKCS12, const std::string& password)
{
if (pCert)
{
STACK_OF(PKCS12_SAFEBAG)* pBags = 0;
_pX509Cert.reset(new X509Certificate(pCert, true));
PKCS12_SAFEBAG* pBag = PKCS12_add_cert(&pBags, pCert);
if (pBag)
{
char*pBuffer = PKCS12_get_friendlyname(pBag);
if(pBuffer)
{
_pkcsFriendlyname = pBuffer;
OPENSSL_free(pBuffer);
}else _pkcsFriendlyname.clear();
if(pBags) sk_PKCS12_SAFEBAG_pop_free(pBags, PKCS12_SAFEBAG_free);
}
else throw OpenSSLException();
_pkcsFriendlyName = extractFriendlyName(pCert);
}
else _pX509Cert.reset();
_caCertList.clear();
_caCertNames.clear();
if (pCA)
{
int certCount = sk_X509_num(pCA);
for (int i = 0; i < certCount; ++i)
{
_caCertList.push_back(X509Certificate(sk_X509_value(pCA, i), true));
X509* pX509 = sk_X509_value(pCA, i);
if (pX509)
{
_caCertList.push_back(X509Certificate(pX509, true));
_caCertNames.push_back(extractFriendlyName(pX509));
}
else throw OpenSSLException("PKCS12Container::load()");
}
}
}
@ -159,11 +183,12 @@ void PKCS12Container::load(PKCS12* pPKCS12, const std::string& password)
}
PKCS12_free(pPKCS12);
sk_X509_pop_free(pCA, X509_free);
X509_free(pCert);
if (pCert) X509_free(pCert);
poco_assert_dbg (_caCertList.size() == _caCertNames.size());
}
else
{
throw NullPointerException("PKCS12Container: struct PKCS12");
throw NullPointerException("PKCS12Container::load(): struct PKCS12");
}
}

View File

@ -345,4 +345,21 @@ void X509Certificate::print(std::ostream& out) const
}
void X509Certificate::printAll(std::ostream& out) const
{
//char * X509_NAME_oneline(const X509_NAME *a, char *buf, int size);
X509_NAME *subj = X509_get_subject_name(_pCert);
std::cout << "=====================" << std::endl;
for (int i = 0; i < X509_NAME_entry_count(subj); ++i)
{
X509_NAME_ENTRY* e = X509_NAME_get_entry(subj, i);
ASN1_STRING* d = X509_NAME_ENTRY_get_data(e);
unsigned char* str = ASN1_STRING_data(d);
std::cout << (char*) str << std::endl;
}
std::cout << "=====================" << std::endl;
}
} } // namespace Poco::Crypto

View File

@ -85,7 +85,7 @@ void PKCS12ContainerTest::full(const PKCS12Container& pkcs12)
std::vector<int> certOrder;
for (int i = 0; i < 2; ++i) certOrder.push_back(i);
fullList(pkcs12.getCACerts(), certOrder);
fullList(pkcs12.getCACerts(), pkcs12.getFriendlyNamesCA(), certOrder);
}
@ -115,9 +115,17 @@ void PKCS12ContainerTest::fullCert(const X509Certificate& x509)
}
void PKCS12ContainerTest::fullList(const PKCS12Container::CAList& caList, const std::vector<int>& certOrder)
void PKCS12ContainerTest::fullList(const PKCS12Container::CAList& caList,
const PKCS12Container::CANameList& caNamesList, const std::vector<int>& certOrder)
{
assert (certOrder.size() == caList.size());
assert ((0 == caNamesList.size()) || (certOrder.size() == caNamesList.size()));
if (caNamesList.size())
{
assert (caNamesList[certOrder[0]].empty());
assert (caNamesList[certOrder[1]].empty());
}
assert (caList[certOrder[0]].subjectName() == "/C=CH/ST=Zug/O=Crypto Vally/CN=CV Root CA v3");
assert (caList[certOrder[0]].issuerName() == "/C=CH/ST=Zug/O=Crypto Vally/CN=CV Root CA v3");
@ -165,16 +173,28 @@ void PKCS12ContainerTest::certsOnly(const PKCS12Container& pkcs12)
{
assert (!pkcs12.hasKey());
assert (!pkcs12.hasX509Certificate());
assert (pkcs12.getFriendlyName().empty());
std::vector<int> certOrder;
for (int i = 0; i < 5; ++i) certOrder.push_back(i);
certsOnlyList(pkcs12.getCACerts(), certOrder);
certsOnlyList(pkcs12.getCACerts(), pkcs12.getFriendlyNamesCA(), certOrder);
}
void PKCS12ContainerTest::certsOnlyList(const PKCS12Container::CAList& caList, const std::vector<int>& certOrder)
void PKCS12ContainerTest::certsOnlyList(const PKCS12Container::CAList& caList,
const PKCS12Container::CANameList& caNamesList, const std::vector<int>& certOrder)
{
assert (certOrder.size() == caList.size());
assert ((0 == caNamesList.size()) || (certOrder.size() == caNamesList.size()));
if (caNamesList.size())
{
assert (caNamesList[certOrder[0]].empty());
assert (caNamesList[certOrder[1]].empty());
assert (caNamesList[certOrder[2]].empty());
assert (caNamesList[certOrder[3]] == "vally-ca");
assert (caNamesList[certOrder[4]] == "vally-ca");
}
assert (caList[certOrder[0]].subjectName() == "/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3");
assert (caList[certOrder[0]].issuerName() == "/C=US/O=Internet Security Research Group/CN=ISRG Root X1");
@ -243,14 +263,14 @@ void PKCS12ContainerTest::testPEMReadWrite()
// PEM is written by openssl in reverse order from p12
std::vector<int> certOrder;
for(int i = (int)certsOnly.size() - 1; i >= 0; --i) certOrder.push_back(i);
certsOnlyList(certsOnly, certOrder);
certsOnlyList(certsOnly, PKCS12Container::CANameList(), certOrder);
TemporaryFile tmpFile;
X509Certificate::writePEM(tmpFile.path(), certsOnly);
certsOnly.clear();
certsOnly = X509Certificate::readPEM(tmpFile.path());
certsOnlyList(certsOnly, certOrder);
certsOnlyList(certsOnly, PKCS12Container::CANameList(), certOrder);
file = getTestFilesPath("full", "pem");
X509Certificate::List full = X509Certificate::readPEM(file);
@ -261,14 +281,14 @@ void PKCS12ContainerTest::testPEMReadWrite()
certOrder.clear();
for(int i = (int)full.size() - 1; i >= 0; --i) certOrder.push_back(i);
fullList(full, certOrder);
fullList(full, PKCS12Container::CANameList(), certOrder);
TemporaryFile tmpFile2;
X509Certificate::writePEM(tmpFile2.path(), full);
full.clear();
full = X509Certificate::readPEM(tmpFile2.path());
fullList(full, certOrder);
fullList(full, PKCS12Container::CANameList(), certOrder);
}
catch (Poco::Exception& ex)
{

View File

@ -45,10 +45,12 @@ private:
const std::string& ext = "p12");
void certsOnly(const Poco::Crypto::PKCS12Container& pkcs12);
void certsOnlyList(const Poco::Crypto::PKCS12Container::CAList& caList,
const Poco::Crypto::PKCS12Container::CANameList& caNamesList,
const std::vector<int>& certOrder);
void full(const Poco::Crypto::PKCS12Container& pkcs12);
void fullCert(const Poco::Crypto::X509Certificate& x509);
void fullList(const Poco::Crypto::PKCS12Container::CAList& caList,
const Poco::Crypto::PKCS12Container::CANameList& caNamesList,
const std::vector<int>& certOrder);
};