Add X509CertificateInfo to poppler
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6aaaa76..4eb74a3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -395,6 +395,7 @@
   poppler/ViewerPreferences.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 0000000..dc78631
--- /dev/null
+++ b/poppler/CertificateInfo.cc
@@ -0,0 +1,127 @@
+//========================================================================
+//
+// CertificateInfo.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2018 Chinmoy Ranjan Pradhan <chinmoyrp65@gmail.com>
+//
+//========================================================================
+
+#include "CertificateInfo.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+X509CertificateInfo::X509CertificateInfo()
+{
+  memset(&issuer_info, 0, sizeof issuer_info);
+  memset(&subject_info, 0, sizeof subject_info);
+  cert_serial = nullptr;
+  cert_der = nullptr;
+  ku_extensions = KU_NONE;
+  cert_version = -1;
+  is_self_signed = false;
+}
+
+X509CertificateInfo::~X509CertificateInfo()
+{
+  free(issuer_info.commonName);
+  free(issuer_info.distinguishedName);
+  free(issuer_info.email);
+  free(issuer_info.organization);
+  free(subject_info.commonName);
+  free(subject_info.distinguishedName);
+  free(subject_info.email);
+  free(subject_info.organization);
+}
+
+int X509CertificateInfo::getVersion() const
+{
+  return cert_version;
+}
+
+GooString *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;
+}
+
+GooString *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(GooString *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(GooString *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 0000000..3010d13
--- /dev/null
+++ b/poppler/CertificateInfo.h
@@ -0,0 +1,98 @@
+//========================================================================
+//
+// CertificateInfo.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2018 Chinmoy Ranjan Pradhan <chinmoyrp65@gmail.com>
+//
+//========================================================================
+
+#ifndef CERTIFICATEINFO_H
+#define CERTIFICATEINFO_H
+
+#include <time.h>
+#include "goo/GooString.h"
+
+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 PublicKeyInfo {
+    GooString *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;
+  GooString *getSerialNumber() const;
+  EntityInfo getIssuerInfo() const;
+  Validity getValidity() const;
+  EntityInfo getSubjectInfo() const;
+  PublicKeyInfo getPublicKeyInfo() const;
+  unsigned int getKeyUsageExtensions() const;
+  GooString *getCertificateDER() const;
+  bool getIsSelfSigned() const;
+
+  /* SETTERS */
+  void setVersion(int);
+  void setSerialNumber(GooString *);
+  void setIssuerInfo(EntityInfo);
+  void setValidity(Validity);
+  void setSubjectInfo(EntityInfo);
+  void setPublicKeyInfo(PublicKeyInfo);
+  void setKeyUsageExtensions(unsigned int);
+  void setCertificateDER(GooString *);
+  void setIsSelfSigned(bool);
+
+private:
+  X509CertificateInfo(const X509CertificateInfo &);
+  X509CertificateInfo& operator=(const X509CertificateInfo &);
+
+  EntityInfo issuer_info;
+  EntityInfo subject_info;
+  PublicKeyInfo public_key_info;
+  Validity cert_validity;
+  GooString *cert_serial;
+  GooString *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 fc4ce88..51caa4d 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1761,6 +1761,7 @@
 
   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 116aab9..87ca859 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -10,6 +10,7 @@
 // Copyright 2015 Markus Kilås <digital@markuspage.com>
 // Copyright 2017 Sebastian Rasmussen <sebras@gmail.com>
 // Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
+// Copyright 2018 Chinmoy Ranjan Pradhan <chinmoyrp65@protonmail.com>
 //
 //========================================================================
 
@@ -18,6 +19,8 @@
 #include "SignatureHandler.h"
 #include "goo/gmem.h"
 #include <secmod.h>
+#include <keyhi.h>
+#include <secder.h>
 
 #include <dirent.h>
 #include <Error.h>
@@ -78,6 +81,104 @@
   return static_cast<time_t>(sTime/1000000);
 }
 
+void SignatureHandler::getEntityInfo(X509CertificateInfo::EntityInfo *info, CERTName *entityName)
+{
+  if (!info || !entityName)
+    return;
+
+  memset(info, 0, sizeof *info);
+
+  char *dn = CERT_NameToAscii(entityName);
+  if (dn) {
+      info->distinguishedName = copyString(dn);
+      PORT_Free(dn);
+  }
+
+  char *cn = CERT_GetCommonName(entityName);
+  if (cn) {
+    info->commonName = copyString(cn);
+    PORT_Free(cn);
+  }
+
+  char *email = CERT_GetCertEmailAddress(entityName);
+  if (email) {
+    info->email = copyString(email);
+    PORT_Free(email);
+  }
+
+  char *org = CERT_GetOrgName(entityName);
+  if (org) {
+    info->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(SECItemToGooString(cert->serialNumber));
+
+  //issuer info
+  X509CertificateInfo::EntityInfo issuerInfo;
+  getEntityInfo(&issuerInfo, &cert->issuer);
+  certInfo->setIssuerInfo(issuerInfo);
+
+  //validity
+  PRTime notBefore, notAfter;
+  CERT_GetCertTimes(cert, &notBefore, &notAfter);
+  X509CertificateInfo::Validity certValidity;
+  certValidity.notBefore = static_cast<time_t>(notBefore/1000000);
+  certValidity.notAfter = static_cast<time_t>(notAfter/1000000);
+  certInfo->setValidity(certValidity);
+
+  //subject info
+  X509CertificateInfo::EntityInfo subjectInfo;
+  getEntityInfo(&subjectInfo, &cert->subject);
+  certInfo->setSubjectInfo(subjectInfo);
+
+  //public key info
+  X509CertificateInfo::PublicKeyInfo pkInfo;
+  SECKEYPublicKey *pk = CERT_ExtractPublicKey(cert);
+  switch (pk->keyType)
+  {
+    case rsaKey:
+      pkInfo.publicKey = SECItemToGooString(pk->u.rsa.modulus);
+      pkInfo.publicKeyType = RSAKEY;
+      break;
+    case dsaKey:
+      pkInfo.publicKey = SECItemToGooString(pk->u.dsa.publicValue);
+      pkInfo.publicKeyType = DSAKEY;
+      break;
+    case ecKey:
+      pkInfo.publicKey = SECItemToGooString(pk->u.ec.publicValue);
+      pkInfo.publicKeyType = ECKEY;
+      break;
+    default:
+      pkInfo.publicKey = SECItemToGooString(cert->subjectPublicKeyInfo.subjectPublicKey);
+      pkInfo.publicKeyType = OTHERKEY;
+      break;
+  }
+  pkInfo.publicKeyStrength = SECKEY_PublicKeyStrengthInBits(pk);
+  certInfo->setPublicKeyInfo(pkInfo);
+
+  certInfo->setKeyUsageExtensions(cert->keyUsage);
+  certInfo->setCertificateDER(SECItemToGooString(cert->derCert));
+  certInfo->setIsSelfSigned(CERT_CompareName(&cert->subject, &cert->issuer) == SECEqual);
+
+  return certInfo;
+}
+
 
 GooString *SignatureHandler::getDefaultFirefoxCertDB_Linux()
 {
@@ -96,9 +197,9 @@
   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 +212,7 @@
 /**
  * Initialise NSS
  */
-void SignatureHandler::init_nss() 
+void SignatureHandler::init_nss()
 {
   GooString *certDBPath = getDefaultFirefoxCertDB_Linux();
   bool initSuccess = false;
@@ -372,3 +473,8 @@
       return CERTIFICATE_GENERIC_ERROR;
   }
 }
+
+GooString *SignatureHandler::SECItemToGooString(SECItem secItem)
+{
+  return new GooString((const char *)secItem.data, secItem.len);
+}
diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h
index 3b2f62b..5c47d24 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 <nspr.h>
@@ -44,11 +45,14 @@
   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 GooString *SECItemToGooString(SECItem secItem);
+
 private:
   SignatureHandler(const SignatureHandler &);
   SignatureHandler& operator=(const SignatureHandler &);
@@ -61,6 +65,7 @@
   NSSCMSSignedData *CMS_SignedDataCreate(NSSCMSMessage * cms_msg);
   NSSCMSSignerInfo *CMS_SignerInfoCreate(NSSCMSSignedData * cms_sig_data);
   HASHContext * initHashContext();
+  void getEntityInfo(X509CertificateInfo::EntityInfo *info, CERTName *entityName);
 
   unsigned int hash_length;
   SECItem CMSitem;
diff --git a/poppler/SignatureInfo.cc b/poppler/SignatureInfo.cc
index 11e47e5..3be9160 100644
--- a/poppler/SignatureInfo.cc
+++ b/poppler/SignatureInfo.cc
@@ -15,6 +15,7 @@
 #include <config.h>
 
 #include "SignatureInfo.h"
+#include "CertificateInfo.h"
 #include "goo/gmem.h"
 #include <stdlib.h>
 #include <string.h>
@@ -31,6 +32,7 @@
 {
   sig_status = SIGNATURE_NOT_VERIFIED;
   cert_status = CERTIFICATE_NOT_VERIFIED;
+  cert_info = nullptr;
   signer_name = nullptr;
   subject_dn = nullptr;
   location = nullptr;
@@ -44,6 +46,7 @@
 {
   sig_status = sig_val_status;
   cert_status = cert_val_status;
+  cert_info = nullptr;
   signer_name = nullptr;
   subject_dn = nullptr;
   location = nullptr;
@@ -59,6 +62,7 @@
   free(reason);
   free(signer_name);
   free(subject_dn);
+  delete cert_info;
 }
 
 /* GETTERS */
@@ -103,6 +107,11 @@
   return signing_time;
 }
 
+X509CertificateInfo *SignatureInfo::getCertificateInfo()
+{
+  return cert_info;
+}
+
 /* SETTERS */
 
 void SignatureInfo::setSignatureValStatus(enum SignatureValidationStatus sig_val_status)
@@ -148,3 +157,8 @@
 {
   signing_time = signingTime;
 }
+
+void SignatureInfo::setCertificateInfo(X509CertificateInfo *certInfo)
+{
+  cert_info = certInfo;
+}
diff --git a/poppler/SignatureInfo.h b/poppler/SignatureInfo.h
index f4554c6..de79062 100644
--- a/poppler/SignatureInfo.h
+++ b/poppler/SignatureInfo.h
@@ -39,6 +39,8 @@
   CERTIFICATE_NOT_VERIFIED
 };
 
+class X509CertificateInfo;
+
 class SignatureInfo {
 public:
   SignatureInfo();
@@ -55,6 +57,7 @@
   int getHashAlgorithm(); // Returns a NSS3 HASH_HashType or -1 if compiled without NSS3
   time_t getSigningTime();
   bool isSubfilterSupported() { return sig_subfilter_supported; }
+  X509CertificateInfo *getCertificateInfo();
 
   /* SETTERS */
   void setSignatureValStatus(enum SignatureValidationStatus );
@@ -66,6 +69,7 @@
   void setHashAlgorithm(int);
   void setSigningTime(time_t);
   void setSubFilterSupport(bool isSupported) { sig_subfilter_supported = isSupported; }
+  void setCertificateInfo(X509CertificateInfo *);
 
 private:
   SignatureInfo(const SignatureInfo &);
@@ -73,6 +77,7 @@
 
   SignatureValidationStatus sig_status;
   CertificateValidationStatus cert_status;
+  X509CertificateInfo *cert_info;
   char *signer_name;
   char *subject_dn;
   char *location;