text: //
  // PKCS12ContainerTest.cpp
  //
  // Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
  // and Contributors.
  //
  // SPDX-License-Identifier:	BSL-1.0
  //
  
  
  #include "PKCS12ContainerTest.h"
  #include "CppUnit/TestCaller.h"
  #include "CppUnit/TestSuite.h"
  #include "Poco/Crypto/EVPPKey.h"
  #include "Poco/Crypto/RSAKey.h"
  #include "Poco/Crypto/KeyPairImpl.h"
  #include "Poco/Environment.h"
  #include "Poco/Path.h"
  #include "Poco/File.h"
  #include "Poco/TemporaryFile.h"
  #include <iostream>
  #include <sstream>
  #include <fstream>
  
  
  
  using namespace Poco::Crypto;
  using Poco::Environment;
  using Poco::Path;
  using Poco::File;
  using Poco::TemporaryFile;
  
  
  PKCS12ContainerTest::PKCS12ContainerTest(const std::string& name): CppUnit::TestCase(name)
  {
  }
  
  
  PKCS12ContainerTest::~PKCS12ContainerTest()
  {
  }
  
  
  void PKCS12ContainerTest::testFullPKCS12()
  {
  	try
  	{
  		std::string file = getTestFilesPath("full");
  		full(PKCS12Container(file.c_str(), "crypto"));
  
  		std::ifstream ifs(file.c_str(), std::ios::binary);
  		PKCS12Container pkcs(ifs, "crypto");
  		full(pkcs);
  
  		PKCS12Container pkcs2(pkcs);
  		full(pkcs2);
  
  		PKCS12Container pkcs3(pkcs);
  		pkcs3 = pkcs2;
  		full(pkcs3);
  
  #ifdef POCO_ENABLE_CPP11
  
  		pkcs3 = std::move(pkcs);
  		full(pkcs3);
  
  		PKCS12Container pkcs4(std::move(pkcs2));
  		full(pkcs4);
  
  #endif // POCO_ENABLE_CPP11
  
  	}
  	catch (Poco::Exception& ex)
  	{
  		std::cerr << ex.displayText() << std::endl;
  		throw;
  	}
  }
  
  
  void PKCS12ContainerTest::full(const PKCS12Container& pkcs12)
  {
  	assert ("vally" == pkcs12.getFriendlyName());
  
  	assert (pkcs12.hasKey());
  	EVPPKey pKey = pkcs12.getKey();
  	assert (EVP_PKEY_RSA == pKey.type());
  
  	RSAKey rsa(pkcs12);
  	assert (rsa.impl()->type() == KeyPairImpl::KT_RSA_IMPL);
  
  	assert (pkcs12.hasX509Certificate());
  	fullCert(pkcs12.getX509Certificate());
  
  	std::vector<int> certOrder;
  	for (int i = 0; i < 2; ++i) certOrder.push_back(i);
  	fullList(pkcs12.getCACerts(), pkcs12.getFriendlyNamesCA(), certOrder);
  }
  
  
  void PKCS12ContainerTest::fullCert(const X509Certificate& x509)
  {
  	std::string subjectName(x509.subjectName());
  	std::string issuerName(x509.issuerName());
  	std::string commonName(x509.commonName());
  	std::string country(x509.subjectName(X509Certificate::NID_COUNTRY));
  	std::string localityName(x509.subjectName(X509Certificate::NID_LOCALITY_NAME));
  	std::string stateOrProvince(x509.subjectName(X509Certificate::NID_STATE_OR_PROVINCE));
  	std::string organizationName(x509.subjectName(X509Certificate::NID_ORGANIZATION_NAME));
  	std::string organizationUnitName(x509.subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME));
  	std::string emailAddress(x509.subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS));
  	std::string serialNumber(x509.serialNumber());
  
  	assert (subjectName == "/C=CH/ST=Zug/O=Crypto Vally/CN=CV Server");
  	assert (issuerName == "/C=CH/ST=Zug/O=Crypto Vally/CN=CV Intermediate CA v3");
  	assert (commonName == "CV Server");
  	assert (country == "CH");
  	assert (localityName.empty());
  	assert (stateOrProvince == "Zug");
  	assert (organizationName == "Crypto Vally");
  	assert (organizationUnitName.empty());
  	assert (emailAddress.empty());
  	assert (serialNumber == "1000");
  	assert (x509.version() == 3);
  	assert (x509.signatureAlgorithm() == "sha256WithRSAEncryption");
  }
  
  
  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");
  	assert (caList[certOrder[0]].commonName() == "CV Root CA v3");
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_COUNTRY) == "CH");
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_LOCALITY_NAME).empty());
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_STATE_OR_PROVINCE) == "Zug");
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_ORGANIZATION_NAME) == "Crypto Vally");
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME).empty());
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS).empty());
  	assert (caList[certOrder[0]].serialNumber() == "C3ECA1FCEAA16055");
  	assert (caList[certOrder[0]].version() == 3);
  	assert (caList[certOrder[0]].signatureAlgorithm() == "sha256WithRSAEncryption");
  
  	assert (caList[certOrder[1]].subjectName() == "/C=CH/ST=Zug/O=Crypto Vally/CN=CV Intermediate CA v3");
  	assert (caList[certOrder[1]].issuerName() == "/C=CH/ST=Zug/O=Crypto Vally/CN=CV Root CA v3");
  	assert (caList[certOrder[1]].commonName() == "CV Intermediate CA v3");
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_COUNTRY) == "CH");
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_LOCALITY_NAME).empty());
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_STATE_OR_PROVINCE) == "Zug");
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_ORGANIZATION_NAME) == "Crypto Vally");
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME).empty());
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS).empty());
  	assert (caList[certOrder[1]].serialNumber() == "1000");
  	assert (caList[certOrder[1]].version() == 3);
  	assert (caList[certOrder[1]].signatureAlgorithm() == "sha256WithRSAEncryption");
  }
  
  
  void PKCS12ContainerTest::testCertsOnlyPKCS12()
  {
  	try
  	{
  		std::string file = getTestFilesPath("certs-only");
  		certsOnly(PKCS12Container(file.c_str(), "crypto"));
  
  		std::ifstream ifs(file.c_str(), std::ios::binary);
  		certsOnly(PKCS12Container(ifs, "crypto"));
  	}
  	catch (Poco::Exception& ex)
  	{
  		std::cerr << ex.displayText() << std::endl;
  		throw;
  	}
  }
  
  
  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(), pkcs12.getFriendlyNamesCA(), 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");
  	assert (caList[certOrder[0]].commonName() == "Let's Encrypt Authority X3");
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_COUNTRY) == "US");
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_LOCALITY_NAME).empty());
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_STATE_OR_PROVINCE).empty());
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_ORGANIZATION_NAME) == "Let's Encrypt");
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME).empty());
  	assert (caList[certOrder[0]].subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS).empty());
  	assert (caList[certOrder[0]].serialNumber() == "D3B17226342332DCF40528512AEC9C6A");
  	assert (caList[certOrder[0]].version() == 3);
  	assert (caList[certOrder[0]].signatureAlgorithm() == "sha256WithRSAEncryption");
  
  	assert (caList[certOrder[1]].subjectName() == "/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3");
  	assert (caList[certOrder[1]].issuerName() == "/O=Digital Signature Trust Co./CN=DST Root CA X3");
  	assert (caList[certOrder[1]].commonName() == "Let's Encrypt Authority X3");
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_COUNTRY) == "US");
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_LOCALITY_NAME).empty());
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_STATE_OR_PROVINCE).empty());
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_ORGANIZATION_NAME) == "Let's Encrypt");
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME).empty());
  	assert (caList[certOrder[1]].subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS).empty());
  	assert (caList[certOrder[1]].serialNumber() == "0A0141420000015385736A0B85ECA708");
  	assert (caList[certOrder[1]].version() == 3);
  	assert (caList[certOrder[1]].signatureAlgorithm() == "sha256WithRSAEncryption");
  
  	assert (caList[certOrder[2]].subjectName() == "/C=US/O=Internet Security Research Group/CN=ISRG Root X1");
  	assert (caList[certOrder[2]].issuerName() == "/C=US/O=Internet Security Research Group/CN=ISRG Root X1");
  	assert (caList[certOrder[2]].commonName() == "ISRG Root X1");
  	assert (caList[certOrder[2]].subjectName(X509Certificate::NID_COUNTRY) == "US");
  	assert (caList[certOrder[2]].subjectName(X509Certificate::NID_LOCALITY_NAME).empty());
  	assert (caList[certOrder[2]].subjectName(X509Certificate::NID_STATE_OR_PROVINCE).empty());
  	assert (caList[certOrder[2]].subjectName(X509Certificate::NID_ORGANIZATION_NAME) == "Internet Security Research Group");
  	assert (caList[certOrder[2]].subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME).empty());
  	assert (caList[certOrder[2]].subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS).empty());
  	assert (caList[certOrder[2]].serialNumber() == "8210CFB0D240E3594463E0BB63828B00");
  	assert (caList[certOrder[2]].version() == 3);
  	assert (caList[certOrder[2]].signatureAlgorithm() == "sha256WithRSAEncryption");
  
  	assert (caList[certOrder[3]].subjectName() == "/C=CH/ST=Zug/O=Crypto Vally/CN=CV Root CA v3");
  	assert (caList[certOrder[3]].issuerName() == "/C=CH/ST=Zug/O=Crypto Vally/CN=CV Root CA v3");
  	assert (caList[certOrder[3]].commonName() == "CV Root CA v3");
  	assert (caList[certOrder[3]].subjectName(X509Certificate::NID_COUNTRY) == "CH");
  	assert (caList[certOrder[3]].subjectName(X509Certificate::NID_LOCALITY_NAME).empty());
  	assert (caList[certOrder[3]].subjectName(X509Certificate::NID_STATE_OR_PROVINCE) == "Zug");
  	assert (caList[certOrder[3]].subjectName(X509Certificate::NID_ORGANIZATION_NAME) == "Crypto Vally");
  	assert (caList[certOrder[3]].subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME).empty());
  	assert (caList[certOrder[3]].subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS).empty());
  	assert (caList[certOrder[3]].serialNumber() == "C3ECA1FCEAA16055");
  	assert (caList[certOrder[3]].version() == 3);
  	assert (caList[certOrder[3]].signatureAlgorithm() == "sha256WithRSAEncryption");
  
  	assert (caList[certOrder[4]].subjectName() == "/C=CH/ST=Zug/O=Crypto Vally/CN=CV Intermediate CA v3");
  	assert (caList[certOrder[4]].issuerName() == "/C=CH/ST=Zug/O=Crypto Vally/CN=CV Root CA v3");
  	assert (caList[certOrder[4]].commonName() == "CV Intermediate CA v3");
  	assert (caList[certOrder[4]].subjectName(X509Certificate::NID_COUNTRY) == "CH");
  	assert (caList[certOrder[4]].subjectName(X509Certificate::NID_LOCALITY_NAME).empty());
  	assert (caList[certOrder[4]].subjectName(X509Certificate::NID_STATE_OR_PROVINCE) == "Zug");
  	assert (caList[certOrder[4]].subjectName(X509Certificate::NID_ORGANIZATION_NAME) == "Crypto Vally");
  	assert (caList[certOrder[4]].subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME).empty());
  	assert (caList[certOrder[4]].subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS).empty());
  	assert (caList[certOrder[4]].serialNumber()== "1000");
  	assert (caList[certOrder[4]].version() == 3);
  	assert (caList[certOrder[4]].signatureAlgorithm() == "sha256WithRSAEncryption");
  }
  
  
  void PKCS12ContainerTest::testPEMReadWrite()
  {
  	try
  	{
  		std::string file = getTestFilesPath("certs-only", "pem");
  		X509Certificate::List certsOnly = X509Certificate::readPEM(file);
  		assert (certsOnly.size() == 5);
  		// 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, PKCS12Container::CANameList(), certOrder);
  
  		TemporaryFile tmpFile;
  		X509Certificate::writePEM(tmpFile.path(), certsOnly);
  
  		certsOnly.clear();
  		certsOnly = X509Certificate::readPEM(tmpFile.path());
  		certsOnlyList(certsOnly, PKCS12Container::CANameList(), certOrder);
  
  		file = getTestFilesPath("full", "pem");
  		X509Certificate::List full = X509Certificate::readPEM(file);
  		assert (full.size() == 3);
  		fullCert(full[0]);
  		full.erase(full.begin());
  		assert (full.size() == 2);
  
  		certOrder.clear();
  		for(int i = (int)full.size() - 1; i >= 0; --i) certOrder.push_back(i);
  		fullList(full, PKCS12Container::CANameList(), certOrder);
  
  		TemporaryFile tmpFile2;
  		X509Certificate::writePEM(tmpFile2.path(), full);
  
  		full.clear();
  		full = X509Certificate::readPEM(tmpFile2.path());
  		fullList(full, PKCS12Container::CANameList(), certOrder);
  	}
  	catch (Poco::Exception& ex)
  	{
  		std::cerr << ex.displayText() << std::endl;
  		throw;
  	}
  }
  
  
  void PKCS12ContainerTest::setUp()
  {
  }
  
  
  void PKCS12ContainerTest::tearDown()
  {
  }
  
  
  std::string PKCS12ContainerTest::getTestFilesPath(const std::string& name, const std::string& ext)
  {
  	std::ostringstream ostr;
  	ostr << "data/" << name << '.' << ext;
  	std::string fileName(ostr.str());
  	Poco::Path path(fileName);
  	if (Poco::File(path).exists())
  	{
  		return fileName;
  	}
  
  	ostr.str("");
  	ostr << "/Crypto/testsuite/data/" << name << '.' << ext;
  	fileName = Poco::Environment::get("POCO_BASE") + ostr.str();
  	path = fileName;
  
  	if (!Poco::File(path).exists())
  	{
  		std::cerr << "Can't find " << fileName << std::endl;
  		throw Poco::NotFoundException("cannot locate directory containing valid Crypto test files");
  	}
  	return fileName;
  }
  
  
  CppUnit::Test* PKCS12ContainerTest::suite()
  {
  	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("PKCS12ContainerTest");
  
  	CppUnit_addTest(pSuite, PKCS12ContainerTest, testFullPKCS12);
  	CppUnit_addTest(pSuite, PKCS12ContainerTest, testCertsOnlyPKCS12);
  	CppUnit_addTest(pSuite, PKCS12ContainerTest, testPEMReadWrite);
  
  	return pSuite;
  }
  