From 1eab833d7b2d10eea1fd4b2f81e58dc41b0783e9 Mon Sep 17 00:00:00 2001 From: Chinmoy Ranjan Pradhan Date: Tue, 17 Jul 2018 18:18:30 +0000 Subject: [PATCH] Add X509CertificateInfo to poppler --- CMakeLists.txt | 1 + poppler/CertificateInfo.cc | 125 ++++++++++++++++++++++++++++++++++++ poppler/CertificateInfo.h | 103 +++++++++++++++++++++++++++++ poppler/Form.cc | 1 + poppler/SignatureHandler.cc | 112 ++++++++++++++++++++++++++++++-- poppler/SignatureHandler.h | 5 ++ poppler/SignatureInfo.cc | 10 +++ poppler/SignatureInfo.h | 4 ++ 8 files changed, 357 insertions(+), 4 deletions(-) create mode 100644 poppler/CertificateInfo.cc create mode 100644 poppler/CertificateInfo.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b94037b..4c856c3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,6 +400,7 @@ set(poppler_SRCS poppler/XpdfPluginAPI.cc poppler/Movie.cc poppler/Rendition.cc + poppler/CertificateInfo.cc ) set(poppler_LIBS ${FREETYPE_LIBRARIES}) if(ENABLE_SPLASH) diff --git a/poppler/CertificateInfo.cc b/poppler/CertificateInfo.cc new file mode 100644 index 00000000..4025f021 --- /dev/null +++ b/poppler/CertificateInfo.cc @@ -0,0 +1,125 @@ +//======================================================================== +// +// CertificateInfo.cc +// +// This file is licensed under the GPLv2 or later +// +// Copyright 2018 Chinmoy Ranjan Pradhan +// +//======================================================================== + +#include "CertificateInfo.h" + +#include +#include + +X509CertificateInfo::X509CertificateInfo() +{ + memset(&issuer_info, 0, sizeof issuer_info); + memset(&subject_info, 0, sizeof subject_info); + memset(&cert_serial, 0, sizeof cert_serial); + memset(&cert_der, 0, sizeof cert_der); + ku_extensions = KU_NONE; + cert_version = -1; + is_self_signed = false; +} + +X509CertificateInfo::~X509CertificateInfo() +{ + free(issuer_info.commonName); + free(issuer_info.email); + free(issuer_info.organization); + free(subject_info.commonName); + free(subject_info.email); + free(subject_info.organization); +} + +int X509CertificateInfo::getVersion() const +{ + return cert_version; +} + +X509CertificateInfo::CertItem X509CertificateInfo::getSerialNumber() const +{ + return cert_serial; +} + +X509CertificateInfo::EntityInfo X509CertificateInfo::getIssuerInfo() const +{ + return issuer_info; +} + +X509CertificateInfo::Validity X509CertificateInfo::getValidity() const +{ + return cert_validity; +} + +X509CertificateInfo::EntityInfo X509CertificateInfo::getSubjectInfo() const +{ + return subject_info; +} + +X509CertificateInfo::PublicKeyInfo X509CertificateInfo::getPublicKeyInfo() const +{ + return public_key_info; +} + +unsigned int X509CertificateInfo::getKeyUsageExtensions() const +{ + return ku_extensions; +} + +X509CertificateInfo::CertItem X509CertificateInfo::getCertificateDER() const +{ + return cert_der; +} + +bool X509CertificateInfo::getIsSelfSigned() const +{ + return is_self_signed; +} + +void X509CertificateInfo::setVersion(int version) +{ + cert_version = version; +} + +void X509CertificateInfo::setSerialNumber(CertItem serialNumber) +{ + cert_serial = serialNumber; +} + +void X509CertificateInfo::setIssuerInfo(EntityInfo issuerInfo) +{ + issuer_info = issuerInfo; +} + +void X509CertificateInfo::setValidity(Validity validity) +{ + cert_validity = validity; +} + +void X509CertificateInfo::setSubjectInfo(EntityInfo subjectInfo) +{ + subject_info = subjectInfo; +} + +void X509CertificateInfo::setPublicKeyInfo(PublicKeyInfo pkInfo) +{ + public_key_info = pkInfo; +} + +void X509CertificateInfo::setKeyUsageExtensions(unsigned int keyUsages) +{ + ku_extensions = keyUsages; +} + +void X509CertificateInfo::setCertificateDER(CertItem certDer) +{ + cert_der = certDer; +} + +void X509CertificateInfo::setIsSelfSigned(bool isSelfSigned) +{ + is_self_signed = isSelfSigned; +} diff --git a/poppler/CertificateInfo.h b/poppler/CertificateInfo.h new file mode 100644 index 00000000..66ddecdb --- /dev/null +++ b/poppler/CertificateInfo.h @@ -0,0 +1,103 @@ +//======================================================================== +// +// CertificateInfo.h +// +// This file is licensed under the GPLv2 or later +// +// Copyright 2018 Chinmoy Ranjan Pradhan +// +//======================================================================== + +#ifndef CERTIFICATEINFO_H +#define CERTIFICATEINFO_H + +#include + +enum CertificateKeyUsageExtension +{ + KU_DIGITAL_SIGNATURE = 0x80, + KU_NON_REPUDIATION = 0x40, + KU_KEY_ENCIPHERMENT = 0x20, + KU_DATA_ENCIPHERMENT = 0x10, + KU_KEY_AGREEMENT = 0x08, + KU_KEY_CERT_SIGN = 0x04, + KU_CRL_SIGN = 0x02, + KU_ENCIPHER_ONLY = 0x01, + KU_NONE = 0x00 +}; + +enum PublicKeyType +{ + RSAKEY, + DSAKEY, + ECKEY, + OTHERKEY +}; + +class X509CertificateInfo { +public: + X509CertificateInfo(); + ~X509CertificateInfo(); + + struct CertItem + { + const char *data; + unsigned int len; + }; + + struct PublicKeyInfo { + CertItem publicKey; + PublicKeyType publicKeyType; + unsigned int publicKeyStrength; // in bits + }; + + struct EntityInfo { + char *commonName; + char *distinguishedName; + char *email; + char *organization; + }; + + struct Validity { + time_t notBefore; + time_t notAfter; + }; + + /* GETTERS */ + int getVersion() const; + CertItem getSerialNumber() const; + EntityInfo getIssuerInfo() const; + Validity getValidity() const; + EntityInfo getSubjectInfo() const; + PublicKeyInfo getPublicKeyInfo() const; + unsigned int getKeyUsageExtensions() const; + CertItem getCertificateDER() const; + bool getIsSelfSigned() const; + + /* SETTERS */ + void setVersion(int); + void setSerialNumber(CertItem); + void setIssuerInfo(EntityInfo); + void setValidity(Validity); + void setSubjectInfo(EntityInfo); + void setPublicKeyInfo(PublicKeyInfo); + void setKeyUsageExtensions(unsigned int); + void setCertificateDER(CertItem); + void setIsSelfSigned(bool); + +private: + X509CertificateInfo(const X509CertificateInfo &); + X509CertificateInfo& operator=(const X509CertificateInfo &); + + EntityInfo issuer_info; + EntityInfo subject_info; + PublicKeyInfo public_key_info; + Validity cert_validity; + CertItem cert_serial; + CertItem cert_der; + unsigned int ku_extensions; + int cert_version; + bool is_self_signed; +}; + +#endif diff --git a/poppler/Form.cc b/poppler/Form.cc index 1b2888e9..c5960fdd 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -1763,6 +1763,7 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for cert_val_state = signature_handler.validateCertificate(validationTime); signature_info->setCertificateValStatus(SignatureHandler::NSS_CertTranslate(cert_val_state)); + signature_info->setCertificateInfo(signature_handler.getCertificateInfo()); #endif return signature_info; diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc index 6ddd1a84..bf8025f0 100644 --- a/poppler/SignatureHandler.cc +++ b/poppler/SignatureHandler.cc @@ -18,6 +18,8 @@ #include "SignatureHandler.h" #include "goo/gmem.h" #include +#include +#include #include #include @@ -78,6 +80,100 @@ time_t SignatureHandler::getSigningTime() return static_cast(sTime/1000000); } +void SignatureHandler::getEntityInfo(X509CertificateInfo::EntityInfo *entity, CERTCertificate *cert) +{ + if (!entity || !cert) + return; + + memset(entity, 0, sizeof *entity); + + entity->distinguishedName = cert->issuerName; + + char *email = CERT_GetCertEmailAddress(&cert->issuer); + if (email) { + entity->email = copyString(email); + PORT_Free(email); + } + + char *cn = CERT_GetCommonName(&cert->issuer); + if (cn) { + entity->commonName = copyString(cn); + PORT_Free(cn); + } + + char *org = CERT_GetOrgName(&cert->issuer); + if (org) { + entity->organization = copyString(org); + PORT_Free(org); + } +} + +X509CertificateInfo *SignatureHandler::getCertificateInfo() +{ + if (!CMSSignerInfo) + return nullptr; + + CERTCertificate *cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB()); + if (!cert) + return nullptr; + + X509CertificateInfo *certInfo = new X509CertificateInfo; + if (!certInfo) + return nullptr; + + certInfo->setVersion(DER_GetInteger(&cert->version) + 1); + certInfo->setSerialNumber(SECItemToCertItem(cert->serialNumber)); + + //issuer info + X509CertificateInfo::EntityInfo issuerInfo; + getEntityInfo(&issuerInfo, cert); + certInfo->setIssuerInfo(issuerInfo); + + //validity + PRTime notBefore, notAfter; + CERT_GetCertTimes(cert, ¬Before, ¬After); + X509CertificateInfo::Validity certValidity; + certValidity.notBefore = static_cast(notBefore/1000000); + certValidity.notAfter = static_cast(notAfter/1000000); + certInfo->setValidity(certValidity); + + //subject info + X509CertificateInfo::EntityInfo subjectInfo; + getEntityInfo(&subjectInfo, cert); + certInfo->setSubjectInfo(subjectInfo); + + //public key info + X509CertificateInfo::PublicKeyInfo pkInfo; + SECKEYPublicKey *pk = CERT_ExtractPublicKey(cert); + switch (pk->keyType) + { + case rsaKey: + pkInfo.publicKey = SECItemToCertItem(pk->u.rsa.modulus); + pkInfo.publicKeyType = RSAKEY; + break; + case dsaKey: + pkInfo.publicKey = SECItemToCertItem(pk->u.dsa.publicValue); + pkInfo.publicKeyType = DSAKEY; + break; + case ecKey: + pkInfo.publicKey = SECItemToCertItem(pk->u.ec.publicValue); + pkInfo.publicKeyType = ECKEY; + break; + default: + pkInfo.publicKey = SECItemToCertItem(cert->subjectPublicKeyInfo.subjectPublicKey); + pkInfo.publicKeyType = OTHERKEY; + break; + } + pkInfo.publicKeyStrength = SECKEY_PublicKeyStrengthInBits(pk); + certInfo->setPublicKeyInfo(pkInfo); + + certInfo->setKeyUsageExtensions(cert->keyUsage); + certInfo->setCertificateDER(SECItemToCertItem(cert->derCert)); + certInfo->setIsSelfSigned(CERT_CompareName(&cert->subject, &cert->issuer) == SECEqual); + + return certInfo; +} + GooString *SignatureHandler::getDefaultFirefoxCertDB_Linux() { @@ -96,9 +192,9 @@ GooString *SignatureHandler::getDefaultFirefoxCertDB_Linux() do { if ((subFolder = readdir(toSearchIn)) != nullptr) { if (strstr(subFolder->d_name, "default") != nullptr) { - finalPath = homePath->append(subFolder->d_name); - closedir(toSearchIn); - return finalPath; + finalPath = homePath->append(subFolder->d_name); + closedir(toSearchIn); + return finalPath; } } } while (subFolder != nullptr); @@ -111,7 +207,7 @@ GooString *SignatureHandler::getDefaultFirefoxCertDB_Linux() /** * Initialise NSS */ -void SignatureHandler::init_nss() +void SignatureHandler::init_nss() { GooString *certDBPath = getDefaultFirefoxCertDB_Linux(); if (certDBPath == nullptr) { @@ -370,3 +466,11 @@ CertificateValidationStatus SignatureHandler::NSS_CertTranslate(SECErrorCodes ns return CERTIFICATE_GENERIC_ERROR; } } + +X509CertificateInfo::CertItem SignatureHandler::SECItemToCertItem(SECItem secItem) +{ + X509CertificateInfo::CertItem item; + item.data = (const char *)secItem.data; + item.len = secItem.len; + return item; +} diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h index 3b2f62b9..4fcc2345 100644 --- a/poppler/SignatureHandler.h +++ b/poppler/SignatureHandler.h @@ -16,6 +16,7 @@ #include "goo/GooString.h" #include "SignatureInfo.h" +#include "CertificateInfo.h" /* NSPR Headers */ #include @@ -44,11 +45,14 @@ public: NSSCMSVerificationStatus validateSignature(); // Use -1 as validation_time for now SECErrorCodes validateCertificate(time_t validation_time); + X509CertificateInfo *getCertificateInfo(); //Translate NSS error codes static SignatureValidationStatus NSS_SigTranslate(NSSCMSVerificationStatus nss_code); static CertificateValidationStatus NSS_CertTranslate(SECErrorCodes nss_code); + static X509CertificateInfo::CertItem SECItemToCertItem(SECItem secItem); + private: SignatureHandler(const SignatureHandler &); SignatureHandler& operator=(const SignatureHandler &); @@ -61,6 +65,7 @@ private: NSSCMSSignedData *CMS_SignedDataCreate(NSSCMSMessage * cms_msg); NSSCMSSignerInfo *CMS_SignerInfoCreate(NSSCMSSignedData * cms_sig_data); HASHContext * initHashContext(); + void getEntityInfo(X509CertificateInfo::EntityInfo *entity, CERTCertificate *cert); unsigned int hash_length; SECItem CMSitem; diff --git a/poppler/SignatureInfo.cc b/poppler/SignatureInfo.cc index 7ca8b969..cb741f9f 100644 --- a/poppler/SignatureInfo.cc +++ b/poppler/SignatureInfo.cc @@ -14,6 +14,7 @@ #include #include "SignatureInfo.h" +#include "CertificateInfo.h" #include "goo/gmem.h" #include #include @@ -30,6 +31,7 @@ SignatureInfo::SignatureInfo() { sig_status = SIGNATURE_NOT_VERIFIED; cert_status = CERTIFICATE_NOT_VERIFIED; + cert_info = nullptr; signer_name = nullptr; subject_dn = nullptr; hash_type = HASH_AlgNULL; @@ -41,6 +43,7 @@ SignatureInfo::SignatureInfo(SignatureValidationStatus sig_val_status, Certifica { sig_status = sig_val_status; cert_status = cert_val_status; + cert_info = nullptr; signer_name = nullptr; subject_dn = nullptr; hash_type = HASH_AlgNULL; @@ -51,6 +54,8 @@ SignatureInfo::SignatureInfo(SignatureValidationStatus sig_val_status, Certifica SignatureInfo::~SignatureInfo() { free(signer_name); + if (cert_info) + delete cert_info; } /* GETTERS */ @@ -117,3 +122,8 @@ void SignatureInfo::setSigningTime(time_t signingTime) { signing_time = signingTime; } + +void SignatureInfo::setCertificateInfo(X509CertificateInfo *certInfo) +{ + cert_info = certInfo; +} diff --git a/poppler/SignatureInfo.h b/poppler/SignatureInfo.h index 35e7568c..3eee4000 100644 --- a/poppler/SignatureInfo.h +++ b/poppler/SignatureInfo.h @@ -38,6 +38,8 @@ enum CertificateValidationStatus CERTIFICATE_NOT_VERIFIED }; +class X509CertificateInfo; + class SignatureInfo { public: SignatureInfo(); @@ -61,6 +63,7 @@ public: void setHashAlgorithm(int); void setSigningTime(time_t); void setSubFilterSupport(bool isSupported) { sig_subfilter_supported = isSupported; } + void setCertificateInfo(X509CertificateInfo *); private: SignatureInfo(const SignatureInfo &); @@ -68,6 +71,7 @@ private: SignatureValidationStatus sig_status; CertificateValidationStatus cert_status; + X509CertificateInfo *cert_info; char *signer_name; const char *subject_dn; int hash_type; -- 2.17.0