From 210bc6d30c914c0b08785f284fe6b9caed6854e4 Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Fri, 29 Sep 2017 18:20:10 -0500 Subject: [PATCH] add X509 version, serialNumber and signatureAlgorithm --- Crypto/Makefile | 2 ++ Crypto/include/Poco/Crypto/X509Certificate.h | 27 ++++++++++++++ Crypto/src/ECKeyImpl.cpp | 2 +- Crypto/src/OpenSSLInitializer.cpp | 4 ++- Crypto/src/X509Certificate.cpp | 38 ++++++++++++++++++++ Crypto/testsuite/Makefile | 2 ++ Crypto/testsuite/src/PKCS12ContainerTest.cpp | 34 +++++++++++++----- build/script/openssl_ver | 2 ++ 8 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 build/script/openssl_ver diff --git a/Crypto/Makefile b/Crypto/Makefile index 3e654d1b1..6eb3aafac 100644 --- a/Crypto/Makefile +++ b/Crypto/Makefile @@ -6,6 +6,8 @@ include $(POCO_BASE)/build/rules/global +include $(POCO_BASE)/build/script/openssl_ver + SYSLIBS += -lssl -lcrypto objects = Cipher CipherFactory CipherImpl CipherKey CipherKeyImpl \ diff --git a/Crypto/include/Poco/Crypto/X509Certificate.h b/Crypto/include/Poco/Crypto/X509Certificate.h index b79f949c2..9ef4a614b 100644 --- a/Crypto/include/Poco/Crypto/X509Certificate.h +++ b/Crypto/include/Poco/Crypto/X509Certificate.h @@ -83,6 +83,13 @@ public: ~X509Certificate(); /// Destroys the X509Certificate. + long version() const; + /// Returns the version of the certificate. + + const std::string& serialNumber() const; + /// Returns the certificate serial number as a + /// string in decimal encoding. + const std::string& issuerName() const; /// Returns the certificate issuer's distinguished name. @@ -144,6 +151,9 @@ public: const X509* certificate() const; /// Returns the underlying OpenSSL certificate. + std::string signatureAlgorithm() const; + /// Returns the certificate signature algorithm long name. + void print(std::ostream& out) const; /// Prints the certificate information to ostream. @@ -174,6 +184,7 @@ private: std::string _issuerName; std::string _subjectName; + std::string _serialNumber; X509* _pCert; OpenSSLInitializer _openSSLInitializer; }; @@ -182,6 +193,22 @@ private: // // inlines // + +inline long X509Certificate::version() const +{ + // This is defined by standards (X.509 et al) to be + // one less than the certificate version. + // So, eg. a version 3 certificate will return 2. + return X509_get_version(_pCert) + 1; +} + + +inline const std::string& X509Certificate::serialNumber() const +{ + return _serialNumber; +} + + inline const std::string& X509Certificate::issuerName() const { return _issuerName; diff --git a/Crypto/src/ECKeyImpl.cpp b/Crypto/src/ECKeyImpl.cpp index 74b305bf6..8acc005e8 100644 --- a/Crypto/src/ECKeyImpl.cpp +++ b/Crypto/src/ECKeyImpl.cpp @@ -195,7 +195,7 @@ std::string ECKeyImpl::getCurveName(int nid) } if (-1 == nid) nid = pCurves[0].nid; - int bufLen = 128; + const int bufLen = 128; char buf[bufLen]; std::memset(buf, 0, bufLen); OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(nid), 0); diff --git a/Crypto/src/OpenSSLInitializer.cpp b/Crypto/src/OpenSSLInitializer.cpp index 466110df7..4592c4c79 100644 --- a/Crypto/src/OpenSSLInitializer.cpp +++ b/Crypto/src/OpenSSLInitializer.cpp @@ -22,7 +22,9 @@ #if OPENSSL_VERSION_NUMBER >= 0x0907000L #include #endif - +#if defined(POCO_OS_FAMILY_WINDOWS) +#pragma message (OPENSSL_VERSION_TEXT) +#endif using Poco::RandomInputStream; using Poco::Thread; diff --git a/Crypto/src/X509Certificate.cpp b/Crypto/src/X509Certificate.cpp index 0240c7182..bea1e459e 100644 --- a/Crypto/src/X509Certificate.cpp +++ b/Crypto/src/X509Certificate.cpp @@ -77,6 +77,7 @@ X509Certificate::X509Certificate(X509* pCert, bool shared): X509Certificate::X509Certificate(const X509Certificate& cert): _issuerName(cert._issuerName), _subjectName(cert._subjectName), + _serialNumber(cert._serialNumber), _pCert(cert._pCert) { _pCert = X509_dup(_pCert); @@ -96,6 +97,7 @@ void X509Certificate::swap(X509Certificate& cert) using std::swap; swap(cert._issuerName, _issuerName); swap(cert._subjectName, _subjectName); + swap(cert._serialNumber, _serialNumber); swap(cert._pCert, _pCert); } @@ -199,6 +201,17 @@ void X509Certificate::init() _issuerName = buffer; X509_NAME_oneline(X509_get_subject_name(_pCert), buffer, sizeof(buffer)); _subjectName = buffer; + BIGNUM* pBN = ASN1_INTEGER_to_BN(X509_get_serialNumber(const_cast(_pCert)), 0); + if (pBN) + { + char* pSN = BN_bn2hex(pBN); + if (pSN) + { + _serialNumber = pSN; + OPENSSL_free(pSN); + } + BN_free(pBN); + } } @@ -296,6 +309,31 @@ bool X509Certificate::equals(const X509Certificate& otherCertificate) const } +std::string X509Certificate::signatureAlgorithm() const +{ + int sigNID = NID_undef; + +#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) + sigNID = X509_get_signature_nid(_pCert); +#else + poco_check_ptr(_pCert->sig_alg); + sigNID = OBJ_obj2nid(_pCert->sig_alg->algorithm); +#endif + + if (sigNID != NID_undef) + { + const char* pAlgName = OBJ_nid2ln(sigNID); + if (pAlgName) return std::string(pAlgName); + else throw OpenSSLException(Poco::format("X509Certificate::" + "signatureAlgorithm(): OBJ_nid2ln(%d)", sigNID)); + } + else + throw NotFoundException("X509Certificate::signatureAlgorithm()"); + + return ""; +} + + X509Certificate::List X509Certificate::readPEM(const std::string& pemFileName) { List caCertList; diff --git a/Crypto/testsuite/Makefile b/Crypto/testsuite/Makefile index 4bd251e08..b62a2f354 100644 --- a/Crypto/testsuite/Makefile +++ b/Crypto/testsuite/Makefile @@ -6,6 +6,8 @@ include $(POCO_BASE)/build/rules/global +include $(POCO_BASE)/build/script/openssl_ver + # Note: linking order is important, do not change it. ifeq ($(POCO_CONFIG),FreeBSD) SYSLIBS += -lssl -lcrypto -lz diff --git a/Crypto/testsuite/src/PKCS12ContainerTest.cpp b/Crypto/testsuite/src/PKCS12ContainerTest.cpp index 1f3b54a87..c8e4e8621 100644 --- a/Crypto/testsuite/src/PKCS12ContainerTest.cpp +++ b/Crypto/testsuite/src/PKCS12ContainerTest.cpp @@ -102,7 +102,7 @@ void PKCS12ContainerTest::fullCert(const X509Certificate& x509) 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.subjectName(X509Certificate::NID_SERIAL_NUMBER)); + 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"); @@ -113,7 +113,9 @@ void PKCS12ContainerTest::fullCert(const X509Certificate& x509) assert (organizationName == "Crypto Vally"); assert (organizationUnitName.empty()); assert (emailAddress.empty()); - assert (serialNumber.empty()); + assert (serialNumber == "1000"); + assert (x509.version() == 3); + assert (x509.signatureAlgorithm() == "sha256WithRSAEncryption"); } @@ -139,7 +141,9 @@ void PKCS12ContainerTest::fullList(const PKCS12Container::CAList& caList, 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]].subjectName(X509Certificate::NID_SERIAL_NUMBER).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"); @@ -150,7 +154,9 @@ void PKCS12ContainerTest::fullList(const PKCS12Container::CAList& caList, 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]].subjectName(X509Certificate::NID_SERIAL_NUMBER).empty()); + assert (caList[certOrder[1]].serialNumber() == "1000"); + assert (caList[certOrder[1]].version() == 3); + assert (caList[certOrder[1]].signatureAlgorithm() == "sha256WithRSAEncryption"); } @@ -208,7 +214,9 @@ void PKCS12ContainerTest::certsOnlyList(const PKCS12Container::CAList& caList, 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]].subjectName(X509Certificate::NID_SERIAL_NUMBER).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"); @@ -219,7 +227,9 @@ void PKCS12ContainerTest::certsOnlyList(const PKCS12Container::CAList& caList, 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]].subjectName(X509Certificate::NID_SERIAL_NUMBER).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"); @@ -230,7 +240,9 @@ void PKCS12ContainerTest::certsOnlyList(const PKCS12Container::CAList& caList, 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]].subjectName(X509Certificate::NID_SERIAL_NUMBER).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"); @@ -241,7 +253,9 @@ void PKCS12ContainerTest::certsOnlyList(const PKCS12Container::CAList& caList, 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]].subjectName(X509Certificate::NID_SERIAL_NUMBER).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"); @@ -252,7 +266,9 @@ void PKCS12ContainerTest::certsOnlyList(const PKCS12Container::CAList& caList, 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]].subjectName(X509Certificate::NID_SERIAL_NUMBER).empty()); + assert (caList[certOrder[4]].serialNumber()== "1000"); + assert (caList[certOrder[4]].version() == 3); + assert (caList[certOrder[4]].signatureAlgorithm() == "sha256WithRSAEncryption"); } diff --git a/build/script/openssl_ver b/build/script/openssl_ver new file mode 100644 index 000000000..14019ef0d --- /dev/null +++ b/build/script/openssl_ver @@ -0,0 +1,2 @@ +which_openssl := $(shell which openssl) +$(info $(shell $(which_openssl) version -a))