diff --git a/iped-app/resources/config/conf/CategoriesConfig.json b/iped-app/resources/config/conf/CategoriesConfig.json index bdbd5eb63c..44861b5dc4 100644 --- a/iped-app/resources/config/conf/CategoriesConfig.json +++ b/iped-app/resources/config/conf/CategoriesConfig.json @@ -75,6 +75,7 @@ ]}, {"name": "Databases", "mimes": ["application/x-edb", "application/x-edb-table", "application/irpf", "application/x-msaccess", "application/x-dbf", "application/vnd.oasis.opendocument.database", "application/x-sqlite3", "application/x-mysql-db", "application/x-berkeley-db", "application/x-mssql-data", "application/x-database-table"]}, {"name": "Compressed Archives", "mimes": ["application/x-tika-ooxml", "application/zlib", "application/applefile", "application/vnd.ms-tnef", "application/zip", "application/x-rar-compressed", "application/x-tar", "application/gzip", "application/x-gzip", "application/x-xz", "application/x-bzip", "application/x-bzip2", "application/x-7z-compressed", "application/x-arj", "application/x-gtar", "application/x-archive", "application/x-cpio", "application/x-tika-unix-dump", "application/x-snappy-framed", "application/x-snappy", "application/x-snappy-raw", "application/x-compress", "application/x-java-pack200", "application/x-lzma", "application/x-lz4", "application/x-lz4-block", "application/x-brotli", "application/zstd", "application/deflate64", "image/x-emf-compressed", "application/x-lzfse"]}, + {"name": "Signed Archives", "mimes": ["application/pkcs7-mime", "application/pkcs7-signature"]}, {"name": "Contacts", "mimes": ["text/x-vcard", "application/x-vcard-html", "application/windows-adress-book", "application/outlook-contact", "application/x-livecontacts", "application/x-livecontacts-table", "contact/x-skype-contact", "application/x-whatsapp-wadb", "application/x-whatsapp-contactsv2", "contact/x-whatsapp-contact", "application/x-ufed-html-contacts", "application/x-ufed-contact", "contact/x-telegram-contact", "application/x-ios-addressbook-db", "application/x-win10-mail-contact"]}, {"name": "Chats", "categories":[ {"name": "WhatsApp", "mimes":["application/x-whatsapp-db", "application/x-whatsapp-chatstorage", "application/x-whatsapp-chat","application/x-ufed-chat-whatsapp","application/x-ufed-chat-preview-whatsapp"]}, @@ -89,7 +90,7 @@ {"name": "Others Chats", "mimes":["application/x-ufed-html-chats", "application/x-ufed-chats-txt", "application/x-ufed-chat", "application/x-ufed-chat-preview"]} ]}, {"name": "USN Journal", "mimes": ["application/x-usnjournal-$J", "application/x-usnjournal-report-html", "application/x-usnjournal-report-csv", "application/x-usnjournal-registry"]}, - {"name": "Programs and Libraries", "mimes": ["application/java-archive", "application/x-dosexec", "application/x-msdownload", "application/x-bat", "application/vnd.ms-cab-compressed", "application/x-font-ttf", "application/pkcs7-signature", "application/vnd.ms-htmlhelp", "application/java-vm", "application/vnd.ms-pki.seccat", "application/x-ms-installer", "application/x-ufed-html-apps", "application/x-ufed-installedapplication"]}, + {"name": "Programs and Libraries", "mimes": ["application/java-archive", "application/x-dosexec", "application/x-msdownload", "application/x-bat", "application/vnd.ms-cab-compressed", "application/x-font-ttf", "application/vnd.ms-htmlhelp", "application/java-vm", "application/vnd.ms-pki.seccat", "application/x-ms-installer", "application/x-ufed-html-apps", "application/x-ufed-installedapplication"]}, {"name": "Unallocated", "mimes": ["application/x-unallocated"]}, {"name": "File Slacks", "mimes": ["application/x-fileslack"]}, {"name": "Plain Texts", "mimes": ["text"], "categories":[ diff --git a/iped-app/resources/config/conf/CategoriesToExpand.txt b/iped-app/resources/config/conf/CategoriesToExpand.txt index 0ebc3d2fdb..ef5c3e394a 100644 --- a/iped-app/resources/config/conf/CategoriesToExpand.txt +++ b/iped-app/resources/config/conf/CategoriesToExpand.txt @@ -18,6 +18,7 @@ GDrive Synced Files OLE files Georeferenced Files Peer-to-peer +Signed Archives #Event Files # Generates registry reports: diff --git a/iped-app/resources/config/conf/MakePreviewConfig.txt b/iped-app/resources/config/conf/MakePreviewConfig.txt index 271edf63b4..09f526ec68 100644 --- a/iped-app/resources/config/conf/MakePreviewConfig.txt +++ b/iped-app/resources/config/conf/MakePreviewConfig.txt @@ -8,6 +8,7 @@ supportedMimes = application/x-msaccess; application/x-lnk; application/x-firefo supportedMimes = application/x-sqlite3; application/sqlite-skype; application/x-win10-timeline; application/x-gdrive-cloud-graph; application/x-gdrive-snapshot supportedMimes = application/x-whatsapp-db; application/x-whatsapp-db-f; application/x-whatsapp-chatstorage; application/x-whatsapp-chatstorage-f; application/x-shareaza-searches-dat; application/x-msie-cache supportedMimes = application/x-prefetch; text/x-vcard; application/x-bittorrent-resume-dat; application/x-bittorrent; application/x-emule-preferences-dat +supportedMimes = application/x-x509-cert # List of mimetypes which parsers insert links to other case items into preview supportedMimesWithLinks = application/x-emule; application/x-emule-part-met; application/x-ares-galaxy; application/x-shareaza-library-dat \ No newline at end of file diff --git a/iped-app/resources/config/conf/ParserConfig.xml b/iped-app/resources/config/conf/ParserConfig.xml index e613913f76..6aa7ccc680 100644 --- a/iped-app/resources/config/conf/ParserConfig.xml +++ b/iped-app/resources/config/conf/ParserConfig.xml @@ -347,6 +347,20 @@ + + + + application/pkcs7-mime + application/pkcs7-signature + + PKCS7Parser + + iped.parsers.security.CertificateParser; + org.apache.tika.parser.crypto.Pkcs7Parser; + + + + application/skype application/irpf diff --git a/iped-app/resources/localization/iped-parsers-messages.properties b/iped-app/resources/localization/iped-parsers-messages.properties index 388bc9b039..050a5da2a1 100644 --- a/iped-app/resources/localization/iped-parsers-messages.properties +++ b/iped-app/resources/localization/iped-parsers-messages.properties @@ -318,4 +318,17 @@ TelegramReport.joinedByRequest=User joined by Request TelegramReport.ChannelMigratedFromGroup=This channel migrated from a group TelegramReport.RecoveredGroup=Recovered deleted group P2P.FoundInPedoHashDB=* Red lines mean the hashes were found in child porn alert hash databases. -Win10Mail.NotFound=Not Found \ No newline at end of file +Win10Mail.NotFound=Not Found +CertificateParser.SubjectX500=Subject(X500) +CertificateParser.Subject=Subject +CertificateParser.Version=Version +CertificateParser.SerialNumber=Serial Number +CertificateParser.SignatureAlgorithm=Signature Algorithm +CertificateParser.IssuerX500=Issuer(X500) +CertificateParser.Issuer=Issuer +CertificateParser.ValidFrom=Valid from +CertificateParser.ValidTo=Valit to +CertificateParser.AlternativeNames=Alternative names +CertificateParser.Details=Details +CertificateParser.Certificate=Certificate +CertificateParser.NOALTNAMES=This certificate has no alternative names. diff --git a/iped-app/resources/localization/iped-parsers-messages_de_DE.properties b/iped-app/resources/localization/iped-parsers-messages_de_DE.properties index c75b7e1e40..f869ae5a77 100644 --- a/iped-app/resources/localization/iped-parsers-messages_de_DE.properties +++ b/iped-app/resources/localization/iped-parsers-messages_de_DE.properties @@ -319,3 +319,16 @@ TelegramReport.ChannelMigratedFromGroup=Dieser Kanal ist aus einer Gruppe hervor TelegramReport.RecoveredGroup=wiederhergestellte gelöschte Gruppe P2P.FoundInPedoHashDB=* Rote Zeile bedeutet, dass der Hash in der KiPo Hash-Datenbank gefunden wurde. Win10Mail.NotFound=Nicht gefunden +CertificateParser.SubjectX500=Subject(X500)(TBT) +CertificateParser.Subject=Subject(TBT) +CertificateParser.Version=Version(TBT) +CertificateParser.SerialNumber=Serial Number(TBT) +CertificateParser.SignatureAlgorithm=Signature Algorithm(TBT) +CertificateParser.IssuerX500=Issuer(X500)(TBT) +CertificateParser.Issuer=Issuer(TBT) +CertificateParser.ValidFrom=Valid from(TBT) +CertificateParser.ValidTo=Valit to(TBT) +CertificateParser.AlternativeNames=Alternative names(TBT) +CertificateParser.Details=Details(TBT) +CertificateParser.Certificate=Certificate(TBT) +CertificateParser.NOALTNAMES=This certificate has no alternative names.(TBT) diff --git a/iped-app/resources/localization/iped-parsers-messages_es_AR.properties b/iped-app/resources/localization/iped-parsers-messages_es_AR.properties index c0596fe8cb..c1fe806c4a 100644 --- a/iped-app/resources/localization/iped-parsers-messages_es_AR.properties +++ b/iped-app/resources/localization/iped-parsers-messages_es_AR.properties @@ -319,3 +319,16 @@ TelegramReport.ChannelMigratedFromGroup=Este canal ha migrado desde un grupo TelegramReport.RecoveredGroup=Grupo borrado recuperado P2P.FoundInPedoHashDB=* Las líneas rojas significan que los hashtags se encontraron en bases de datos de hashtags de alertas de pornografía infantil. Win10Mail.NotFound=No encontrado +CertificateParser.SubjectX500=Subject(X500)(TBT) +CertificateParser.Subject=Subject(TBT) +CertificateParser.Version=Version(TBT) +CertificateParser.SerialNumber=Serial Number(TBT) +CertificateParser.SignatureAlgorithm=Signature Algorithm(TBT) +CertificateParser.IssuerX500=Issuer(X500)(TBT) +CertificateParser.Issuer=Issuer(TBT) +CertificateParser.ValidFrom=Valid from(TBT) +CertificateParser.ValidTo=Valit to(TBT) +CertificateParser.AlternativeNames=Alternative names(TBT) +CertificateParser.Details=Details(TBT) +CertificateParser.Certificate=Certificate(TBT) +CertificateParser.NOALTNAMES=This certificate has no alternative names.(TBT) diff --git a/iped-app/resources/localization/iped-parsers-messages_it_IT.properties b/iped-app/resources/localization/iped-parsers-messages_it_IT.properties index db8a50e075..a18296efdb 100644 --- a/iped-app/resources/localization/iped-parsers-messages_it_IT.properties +++ b/iped-app/resources/localization/iped-parsers-messages_it_IT.properties @@ -319,3 +319,16 @@ TelegramReport.ChannelMigratedFromGroup=Questo canale è migrato da un gruppo TelegramReport.RecoveredGroup=Gruppo cancellato recuperato P2P.FoundInPedoHashDB=* Le linee rosse indicano che gli hash sono stati trovati nel child porn alert hash databases. Win10Mail.NotFound=Non trovato +CertificateParser.SubjectX500=Subject(X500)(TBT) +CertificateParser.Subject=Subject(TBT) +CertificateParser.Version=Version(TBT) +CertificateParser.SerialNumber=Serial Number(TBT) +CertificateParser.SignatureAlgorithm=Signature Algorithm(TBT) +CertificateParser.IssuerX500=Issuer(X500)(TBT) +CertificateParser.Issuer=Issuer(TBT) +CertificateParser.ValidFrom=Valid from(TBT) +CertificateParser.ValidTo=Valit to(TBT) +CertificateParser.AlternativeNames=Alternative names(TBT) +CertificateParser.Details=Details(TBT) +CertificateParser.Certificate=Certificate(TBT) +CertificateParser.NOALTNAMES=This certificate has no alternative names.(TBT) diff --git a/iped-app/resources/localization/iped-parsers-messages_pt_BR.properties b/iped-app/resources/localization/iped-parsers-messages_pt_BR.properties index 7826525f39..bc88d2104f 100644 --- a/iped-app/resources/localization/iped-parsers-messages_pt_BR.properties +++ b/iped-app/resources/localization/iped-parsers-messages_pt_BR.properties @@ -319,3 +319,17 @@ TelegramReport.ChannelMigratedFromGroup=Este canal migrou de um grupo TelegramReport.RecoveredGroup=Grupo apagado recuperado P2P.FoundInPedoHashDB=* Linhas em vermelho indicam que os hashes foram encontrados em bases de hashes de alerta de pornografia infantil Win10Mail.NotFound=Não Encontrado +CertificateParser.SubjectX500=Sujeito(X500) +CertificateParser.Subject=Sujeito +CertificateParser.Version=Versão +CertificateParser.SerialNumber=Número de série +CertificateParser.SignatureAlgorithm=Algoritmo da assinature +CertificateParser.IssuerX500=Emissor(X500) +CertificateParser.Issuer=Emissor +CertificateParser.ValidFrom=Válido desde +CertificateParser.ValidTo=Válido até +CertificateParser.AlternativeNames=Nomes alternativos +CertificateParser.Details=Detalhes +CertificateParser.Certificate=Certificado +CertificateParser.NOALTNAMES=Este certificado não contém nomes alternativos. + diff --git a/iped-parsers/iped-parsers-impl/pom.xml b/iped-parsers/iped-parsers-impl/pom.xml index 278c7d4f45..ef959fff31 100644 --- a/iped-parsers/iped-parsers-impl/pom.xml +++ b/iped-parsers/iped-parsers-impl/pom.xml @@ -28,6 +28,12 @@ 3.8.0 test + + + org.bouncycastle + bcutil-jdk18on + 1.76 + org.apache.tika tika-parsers-standard-package diff --git a/iped-parsers/iped-parsers-impl/src/main/java/iped/parsers/security/CertificateParser.java b/iped-parsers/iped-parsers-impl/src/main/java/iped/parsers/security/CertificateParser.java index 1e38432717..0505261d0a 100644 --- a/iped-parsers/iped-parsers-impl/src/main/java/iped/parsers/security/CertificateParser.java +++ b/iped-parsers/iped-parsers-impl/src/main/java/iped/parsers/security/CertificateParser.java @@ -22,6 +22,8 @@ import javax.xml.bind.DatatypeConverter; import org.apache.tika.exception.TikaException; +import org.apache.tika.extractor.EmbeddedDocumentExtractor; +import org.apache.tika.extractor.ParsingEmbeddedDocumentExtractor; import org.apache.tika.io.TemporaryResources; import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.HttpHeaders; @@ -38,33 +40,63 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1String; import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cms.CMSException; +import org.bouncycastle.cms.CMSSignedDataParser; +import org.bouncycastle.cms.SignerInformation; +import org.bouncycastle.cms.SignerInformationStore; +import org.bouncycastle.operator.DigestCalculatorProvider; +import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; +import org.bouncycastle.util.Store; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import iped.parsers.util.Messages; +import iped.parsers.util.MetadataUtil; public class CertificateParser extends AbstractParser { /** * */ private static final long serialVersionUID = 1L; + + public static final MediaType X509_MIME = MediaType.application("x-x509-cert"); + + // these are old mimetypes before TIKA had implemented its mimetype + // x-x509-ca-cert + @Deprecated public static final MediaType PEM_MIME = MediaType.application("x-pem-file"); + @Deprecated public static final MediaType DER_MIME = MediaType.application("pkix-cert"); + private static final MediaType PKCS7_MIME = MediaType.application("pkcs7-mime"); public static final MediaType PKCS7_SIGNATURE = MediaType.application("pkcs7-signature"); private static Set SUPPORTED_TYPES = null; - public static final Property NOTBEFORE = Property.internalDate("certificate:notbefore"); //$NON-NLS-1$ - public static final Property NOTAFTER = Property.internalDate("certificate:notafter"); //$NON-NLS-1$ + public static final Property NOTBEFORE = Property.internalDate("certificate:notBefore"); //$NON-NLS-1$ + public static final Property NOTAFTER = Property.internalDate("certificate:notAfter"); //$NON-NLS-1$ public static final String ISSUER = "certificate:issuer"; //$NON-NLS-1$ + public static final String X500_ISSUER = "certificate:X500Issuer"; public static final String SUBJECT = "certificate:subject"; //$NON-NLS-1$ + public static final String X500_SUBJECT = "certificate:X500Subject"; //$NON-NLS-1$ + public static final String SIGNERS = "certificate:Signers"; //$NON-NLS-1$ public static final Property ISSUBJECTAUTHORITY = Property.internalBoolean("certificate:subjectIsCertAuthority"); //$NON-NLS-1$ public static final String NOALTNAMES = "This certificate has no alternative names."; + + public CertificateParser() { + MetadataUtil.setMetadataType(NOTBEFORE.getName(), Date.class); + MetadataUtil.setMetadataType(NOTAFTER.getName(), Date.class); + } + @Override public Set getSupportedTypes(ParseContext arg0) { if (SUPPORTED_TYPES == null) { Set set = new HashSet<>(); set.add(PEM_MIME); set.add(DER_MIME); + set.add(X509_MIME); set.add(PKCS7_MIME); set.add(PKCS7_SIGNATURE); SUPPORTED_TYPES = set; @@ -87,16 +119,50 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, String mimeType = metadata.get("Indexer-Content-Type"); if (mimeType.equals(PKCS7_SIGNATURE.toString())) { + EmbeddedDocumentExtractor extractor = context.get(EmbeddedDocumentExtractor.class, + new ParsingEmbeddedDocumentExtractor(context)); try (InputStream certStream = new FileInputStream(file)) { CertPath p = cf.generateCertPath(certStream, "PKCS7"); List certs = p.getCertificates(); - XHTMLContentHandler xhtml = new XHTMLContentHandler(handler, metadata); - xhtml.startDocument(); + + // extracts certificates for (Iterator iterator = certs.iterator(); iterator.hasNext();) { cert = (X509Certificate) iterator.next(); - generateCertificateHtml(cert, xhtml); + + Metadata certMetadata = new Metadata(); + certMetadata.add(TikaCoreProperties.RESOURCE_NAME_KEY, + cert.getSubjectX500Principal().getName()); + + extractor.parseEmbedded(new ByteArrayInputStream(cert.getEncoded()), new DefaultHandler(), + certMetadata, + true); } - xhtml.endDocument(); + } + try (InputStream certStream = new FileInputStream(file)) { + DigestCalculatorProvider digestCalculatorProvider = new JcaDigestCalculatorProviderBuilder() + .setProvider("BC").build(); + CMSSignedDataParser sp = new CMSSignedDataParser(digestCalculatorProvider, certStream); + // extracts certificates + Store certStore = sp.getCertificates(); + SignerInformationStore signers = sp.getSignerInfos(); + + Collection c = signers.getSigners(); + Iterator it = c.iterator(); + + List certificates = new ArrayList(); + while (it.hasNext()) { + SignerInformation signer = (SignerInformation) it.next(); + Collection certCollection = certStore.getMatches(signer.getSID()); + + Iterator certIt = certCollection.iterator(); + X509CertificateHolder certHolder = (X509CertificateHolder) certIt.next(); + + metadata.add(SIGNERS, + certHolder.getSubject().toString()); + } + } catch (CMSException e) { + // ignores as this content does not seem to hold any data (as is the case with + // certificates with full certification path } } else { InputStream certStream = null; @@ -110,83 +176,108 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, } XHTMLContentHandler xhtml = new XHTMLContentHandler(handler, metadata); xhtml.startDocument(); + xhtml.startElement("head"); //$NON-NLS-1$ + xhtml.startElement("style"); //$NON-NLS-1$ + xhtml.characters("table {border-collapse: collapse;} table, td, th {border: 1px solid black;}"); //$NON-NLS-1$ + xhtml.endElement("style"); //$NON-NLS-1$ + xhtml.endElement("head"); //$NON-NLS-1$ generateCertificateHtml(cert, xhtml); xhtml.endDocument(); - } - metadata.set(NOTBEFORE, cert.getNotBefore()); - metadata.set(NOTAFTER, cert.getNotAfter()); - metadata.set(ISSUER, cert.getIssuerX500Principal().getName()); - metadata.set(SUBJECT, cert.getSubjectX500Principal().getName()); - if (cert.getBasicConstraints() <= -1) { - metadata.set(ISSUBJECTAUTHORITY, Boolean.FALSE.toString()); - } else { - metadata.set(ISSUBJECTAUTHORITY, Boolean.TRUE.toString()); + metadata.set(NOTBEFORE, cert.getNotBefore()); + metadata.set(NOTAFTER, cert.getNotAfter()); + + metadata.set(X500_ISSUER, cert.getIssuerX500Principal().getName()); + metadata.set(ISSUER, cert.getIssuerDN().getName()); + metadata.set(X500_SUBJECT, cert.getSubjectX500Principal().getName()); + metadata.set(SUBJECT, cert.getSubjectDN().getName()); + if (cert.getBasicConstraints() <= -1) { + metadata.set(ISSUBJECTAUTHORITY, Boolean.FALSE.toString()); + } else { + metadata.set(ISSUBJECTAUTHORITY, Boolean.TRUE.toString()); + } + metadata.set(HttpHeaders.CONTENT_TYPE, "text/plain"); + metadata.set(TikaCoreProperties.TITLE, Messages.getString("CertificateParser.Certificate") + ":" + + cert.getSubjectX500Principal().getName()); } - metadata.set(HttpHeaders.CONTENT_TYPE, "text/plain"); - metadata.set(TikaCoreProperties.TITLE, "Certificado:" + cert.getSubjectX500Principal().getName()); + } catch (Exception e) { + e.printStackTrace(); throw new TikaException("Invalid or unkown certificate format.", e); } finally { tis.close(); } } + static private String CSS = "th {text-align:left; font-family: Arial, sans-serif; background-color: rgb(240, 240, 240);} "; + private void generateCertificateHtml(X509Certificate cert, XHTMLContentHandler xhtml) throws UnsupportedEncodingException, SAXException { - xhtml.startElement("table"); + xhtml.startElement("style"); + xhtml.characters(CSS); + xhtml.endElement("style"); + xhtml.startElement("table border='1'"); xhtml.startElement("tr"); xhtml.startElement("th"); - xhtml.characters("Propriedade"); - xhtml.endElement("th"); - xhtml.startElement("th"); - xhtml.characters("Valor"); + xhtml.characters(Messages.getString("CertificateParser.SubjectX500"));// "Subject X500" xhtml.endElement("th"); - xhtml.endElement("tr"); - - xhtml.startElement("tr"); - xhtml.startElement("td"); - xhtml.characters("Subject"); - xhtml.endElement("td"); xhtml.startElement("td"); xhtml.characters(cert.getSubjectX500Principal().getName()); xhtml.endElement("td"); xhtml.endElement("tr"); xhtml.startElement("tr"); + xhtml.startElement("th"); + xhtml.characters(Messages.getString("CertificateParser.Subject"));// "Subject" + xhtml.endElement("th"); xhtml.startElement("td"); - xhtml.characters("Version"); + xhtml.characters(cert.getSubjectDN().getName()); xhtml.endElement("td"); + xhtml.endElement("tr"); + + xhtml.startElement("tr"); + xhtml.startElement("th"); + xhtml.characters(Messages.getString("CertificateParser.Version"));// "Version" + xhtml.endElement("th"); xhtml.startElement("td"); xhtml.characters(Integer.toString(cert.getVersion())); xhtml.endElement("td"); xhtml.endElement("tr"); xhtml.startElement("tr"); - xhtml.startElement("td"); - xhtml.characters("Serial Number"); - xhtml.endElement("td"); + xhtml.startElement("th"); + xhtml.characters(Messages.getString("CertificateParser.SerialNumber"));// "Serial Number" + xhtml.endElement("th"); xhtml.startElement("td"); xhtml.characters(cert.getSerialNumber().toString()); xhtml.endElement("td"); xhtml.endElement("tr"); xhtml.startElement("tr"); - xhtml.startElement("td"); - xhtml.characters("Signature Algorithm"); - xhtml.endElement("td"); + xhtml.startElement("th"); + xhtml.characters(Messages.getString("CertificateParser.SignatureAlgorithm"));// "Signature Algorithm" + xhtml.endElement("th"); xhtml.startElement("td"); xhtml.characters(cert.getSigAlgName()); xhtml.endElement("td"); xhtml.endElement("tr"); xhtml.startElement("tr"); + xhtml.startElement("th"); + xhtml.characters(Messages.getString("CertificateParser.IssuerX500"));// "Issuer X500" + xhtml.endElement("th"); xhtml.startElement("td"); - xhtml.characters("Issuer"); + xhtml.characters(cert.getIssuerX500Principal().getName()); xhtml.endElement("td"); + xhtml.endElement("tr"); + + xhtml.startElement("tr"); + xhtml.startElement("th"); + xhtml.characters(Messages.getString("CertificateParser.Issuer"));// "Issuer" + xhtml.endElement("th"); xhtml.startElement("td"); xhtml.characters(cert.getIssuerX500Principal().getName()); xhtml.endElement("td"); @@ -194,27 +285,27 @@ private void generateCertificateHtml(X509Certificate cert, XHTMLContentHandler x DateFormat df = DateFormat.getDateTimeInstance(); xhtml.startElement("tr"); - xhtml.startElement("td"); - xhtml.characters("Valid from"); - xhtml.endElement("td"); + xhtml.startElement("th"); + xhtml.characters(Messages.getString("CertificateParser.ValidFrom"));// "Valid from" + xhtml.endElement("th"); xhtml.startElement("td"); xhtml.characters(df.format(cert.getNotBefore())); xhtml.endElement("td"); xhtml.endElement("tr"); xhtml.startElement("tr"); - xhtml.startElement("td"); - xhtml.characters("Valid to"); - xhtml.endElement("td"); + xhtml.startElement("th"); + xhtml.characters(Messages.getString("CertificateParser.ValidTo"));// "Valid to" + xhtml.endElement("th"); xhtml.startElement("td"); xhtml.characters(df.format(cert.getNotAfter())); xhtml.endElement("td"); xhtml.endElement("tr"); xhtml.startElement("tr"); - xhtml.startElement("td"); - xhtml.characters("Alternative Names:"); - xhtml.endElement("td"); + xhtml.startElement("th"); + xhtml.characters(Messages.getString("CertificateParser.AlternativeNames"));// "Alternative Names:" + xhtml.endElement("th"); xhtml.startElement("td"); List altNamesStrs = getAltNames(cert); for (String altNameStr : altNamesStrs) { @@ -224,6 +315,21 @@ private void generateCertificateHtml(X509Certificate cert, XHTMLContentHandler x } xhtml.endElement("td"); xhtml.endElement("tr"); + xhtml.endElement("table"); + + xhtml.startElement("table"); + xhtml.startElement("tr"); + xhtml.startElement("th"); + xhtml.characters(Messages.getString("CertificateParser.Details")); + xhtml.endElement("th"); + xhtml.endElement("tr"); + xhtml.startElement("tr"); + xhtml.startElement("td"); + xhtml.startElement("pre"); + xhtml.characters(cert.toString()); + xhtml.endElement("pre"); + xhtml.endElement("td"); + xhtml.endElement("tr"); xhtml.endElement("table"); @@ -242,10 +348,10 @@ private List getAltNames(X509Certificate cert) { ASN1Sequence altNameSeq = getAltnameSequence(altNameBytes); final ASN1TaggedObject obj = (ASN1TaggedObject) altNameSeq.getObjectAt(1); if (obj != null) { - ASN1Primitive prim = obj.getObject(); + ASN1Primitive prim = obj.getLoadedObject(); // can be tagged one more time if (prim instanceof ASN1TaggedObject) { - prim = ASN1TaggedObject.getInstance(((ASN1TaggedObject) prim)).getObject(); + prim = ASN1TaggedObject.getInstance(((ASN1TaggedObject) prim)).getLoadedObject(); } if (prim instanceof ASN1OctetString) { @@ -258,9 +364,14 @@ private List getAltNames(X509Certificate cert) { altNamesStrs.add(altNameStr); } } + if (itemType == 1) { + altNamesStrs.add(sanItem.get(1).toString()); + } } } - altNamesStrs.add(NOALTNAMES); + if (altNamesStrs.size() == 0) { + altNamesStrs.add(Messages.getString("CertificateParser.NOALTNAMES")); + } } catch (IOException | CertificateParsingException e) { // ignore error. } diff --git a/iped-parsers/iped-parsers-impl/src/test/java/iped/parsers/security/CertificateParserTest.java b/iped-parsers/iped-parsers-impl/src/test/java/iped/parsers/security/CertificateParserTest.java index 15a967b990..94f1291a9b 100644 --- a/iped-parsers/iped-parsers-impl/src/test/java/iped/parsers/security/CertificateParserTest.java +++ b/iped-parsers/iped-parsers-impl/src/test/java/iped/parsers/security/CertificateParserTest.java @@ -2,10 +2,15 @@ import java.io.IOException; import java.io.InputStream; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.text.DateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import org.apache.tika.exception.TikaException; +import org.apache.tika.extractor.EmbeddedDocumentExtractor; import org.apache.tika.metadata.Metadata; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.parser.ParseContext; @@ -17,6 +22,7 @@ import com.google.common.net.HttpHeaders; import iped.parsers.standard.StandardParser; +import iped.parsers.util.Messages; import junit.framework.TestCase; public class CertificateParserTest extends TestCase { @@ -50,40 +56,39 @@ public void testCertificateParsingDER() throws IOException, SAXException, TikaEx try (InputStream stream = getStream("test-files/test_serverCert.der")) { parser.parse(stream, handler, metadata, context); String hts = handler.toString(); - assertTrue(hts.contains("Propriedade")); - assertTrue(hts.contains("Valor")); - assertTrue(hts.contains("Subject")); + assertTrue(hts.contains(Messages.getString("CertificateParser.Subject"))); assertTrue(hts.contains( "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR")); - assertTrue(hts.contains("Version")); + assertTrue(hts.contains(Messages.getString("CertificateParser.Version"))); assertTrue(hts.contains("3")); - assertTrue(hts.contains("Serial Number")); + assertTrue(hts.contains(Messages.getString("CertificateParser.SerialNumber"))); assertTrue(hts.contains("12677675471164634689")); - assertTrue(hts.contains("Signature Algorithm")); + assertTrue(hts.contains(Messages.getString("CertificateParser.SignatureAlgorithm"))); assertTrue(hts.contains("SHA1withRSA")); - assertTrue(hts.contains("Issuer")); + assertTrue(hts.contains(Messages.getString("CertificateParser.Issuer"))); assertTrue(hts.contains( "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR")); - assertTrue(hts.contains("Valid from")); + assertTrue(hts.contains(Messages.getString("CertificateParser.ValidFrom"))); DateFormat df = DateFormat.getDateTimeInstance(); assertTrue(hts.contains(df.format(new Date(1622568518000L)))); - assertTrue(hts.contains("Valid to")); + assertTrue(hts.contains(Messages.getString("CertificateParser.ValidTo"))); assertTrue(hts.contains(df.format(new Date(1625160518000L)))); - assertTrue(hts.contains("Alternative Names:")); - assertTrue(hts.contains("This certificate has no alternative names.")); + assertTrue(hts.contains(Messages.getString("CertificateParser.AlternativeNames"))); + assertTrue(hts.contains(Messages.getString("CertificateParser.NOALTNAMES"))); assertEquals( "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", - metadata.get(CertificateParser.SUBJECT)); + metadata.get(CertificateParser.X500_SUBJECT)); assertEquals("2021-07-01", metadata.get(CertificateParser.NOTAFTER).substring(0, 10)); assertEquals( - "Certificado:1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", + Messages.getString("CertificateParser.Certificate") + + ":1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", metadata.get(TikaCoreProperties.TITLE)); assertEquals(CertificateParser.DER_MIME.toString(), metadata.get(StandardParser.INDEXER_CONTENT_TYPE)); assertEquals("true", metadata.get(CertificateParser.ISSUBJECTAUTHORITY)); assertEquals( "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", - metadata.get(CertificateParser.ISSUER)); + metadata.get(CertificateParser.X500_ISSUER)); assertEquals("2021-06-01", metadata.get(CertificateParser.NOTBEFORE).substring(0, 10)); assertEquals("text/plain", metadata.get(HttpHeaders.CONTENT_TYPE)); @@ -104,40 +109,39 @@ public void testCertificateParsingPEM() throws IOException, SAXException, TikaEx parser.parse(stream, handler, metadata, context); String hts = handler.toString(); - assertTrue(hts.contains("Propriedade")); - assertTrue(hts.contains("Valor")); - assertTrue(hts.contains("Subject")); + assertTrue(hts.contains(Messages.getString("CertificateParser.Subject"))); assertTrue(hts.contains( "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR")); - assertTrue(hts.contains("Version")); + assertTrue(hts.contains(Messages.getString("CertificateParser.Version"))); assertTrue(hts.contains("3")); - assertTrue(hts.contains("Serial Number")); + assertTrue(hts.contains(Messages.getString("CertificateParser.SerialNumber"))); assertTrue(hts.contains("12677675471164634689")); - assertTrue(hts.contains("Signature Algorithm")); + assertTrue(hts.contains(Messages.getString("CertificateParser.SignatureAlgorithm"))); assertTrue(hts.contains("SHA1withRSA")); - assertTrue(hts.contains("Issuer")); + assertTrue(hts.contains(Messages.getString("CertificateParser.Issuer"))); assertTrue(hts.contains( "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR")); - assertTrue(hts.contains("Valid from")); + assertTrue(hts.contains(Messages.getString("CertificateParser.ValidFrom"))); DateFormat df = DateFormat.getDateTimeInstance(); assertTrue(hts.contains(df.format(new Date(1622568518000L)))); - assertTrue(hts.contains("Valid to")); + assertTrue(hts.contains(Messages.getString("CertificateParser.ValidTo"))); assertTrue(hts.contains(df.format(new Date(1625160518000L)))); - assertTrue(hts.contains("Alternative Names:")); - assertTrue(hts.contains("This certificate has no alternative names.")); + assertTrue(hts.contains(Messages.getString("CertificateParser.AlternativeNames"))); + assertTrue(hts.contains(Messages.getString("CertificateParser.NOALTNAMES"))); assertEquals( "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", - metadata.get(CertificateParser.SUBJECT)); + metadata.get(CertificateParser.X500_SUBJECT)); assertEquals("2021-07-01", metadata.get(CertificateParser.NOTAFTER).substring(0, 10)); assertEquals( - "Certificado:1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", + Messages.getString("CertificateParser.Certificate") + + ":1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", metadata.get(TikaCoreProperties.TITLE)); assertEquals(CertificateParser.PEM_MIME.toString(), metadata.get(StandardParser.INDEXER_CONTENT_TYPE)); assertEquals("true", metadata.get(CertificateParser.ISSUBJECTAUTHORITY)); assertEquals( "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", - metadata.get(CertificateParser.ISSUER)); + metadata.get(CertificateParser.X500_ISSUER)); assertEquals("2021-06-01", metadata.get(CertificateParser.NOTBEFORE).substring(0, 10)); assertEquals("text/plain", metadata.get(HttpHeaders.CONTENT_TYPE)); @@ -154,46 +158,40 @@ public void testCertificateParsingPKCS7() throws IOException, SAXException, Tika ContentHandler handler = new BodyContentHandler(); ParseContext context = new ParseContext(); parser.getSupportedTypes(context); - try (InputStream stream = getStream("test-files/test_serverPKCS7.p7b")) { - parser.parse(stream, handler, metadata, context); - String hts = handler.toString(); - assertTrue(hts.contains("Propriedade")); - assertTrue(hts.contains("Valor")); - assertTrue(hts.contains("Subject")); - assertTrue(hts.contains( - "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR")); - assertTrue(hts.contains("Version")); - assertTrue(hts.contains("3")); - assertTrue(hts.contains("Serial Number")); - assertTrue(hts.contains("12677675471164634689")); - assertTrue(hts.contains("Signature Algorithm")); - assertTrue(hts.contains("SHA1withRSA")); - assertTrue(hts.contains("Issuer")); - assertTrue(hts.contains( - "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR")); - assertTrue(hts.contains("Valid from")); - DateFormat df = DateFormat.getDateTimeInstance(); - assertTrue(hts.contains(df.format(new Date(1622568518000L)))); - assertTrue(hts.contains("Valid to")); - assertTrue(hts.contains(df.format(new Date(1625160518000L)))); - assertTrue(hts.contains("Alternative Names:")); - assertTrue(hts.contains("This certificate has no alternative names.")); + List exceptions = new ArrayList<>(); + List certificates = new ArrayList<>(); + List metadatas = new ArrayList<>(); - assertEquals( - "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", - metadata.get(CertificateParser.SUBJECT)); - assertEquals("2021-07-01", metadata.get(CertificateParser.NOTAFTER).substring(0, 10)); - assertEquals( - "Certificado:1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", - metadata.get(TikaCoreProperties.TITLE)); - assertEquals(CertificateParser.PKCS7_SIGNATURE.toString(), metadata.get(StandardParser.INDEXER_CONTENT_TYPE)); - assertEquals("true", metadata.get(CertificateParser.ISSUBJECTAUTHORITY)); - assertEquals( - "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR", - metadata.get(CertificateParser.ISSUER)); - assertEquals("2021-06-01", metadata.get(CertificateParser.NOTBEFORE).substring(0, 10)); - assertEquals("text/plain", metadata.get(HttpHeaders.CONTENT_TYPE)); + context.set(EmbeddedDocumentExtractor.class, new EmbeddedDocumentExtractor() { + @Override + public boolean shouldParseEmbedded(Metadata arg0) { + return true; + } + + @Override + public void parseEmbedded(InputStream stream, ContentHandler arg1, Metadata metadata, boolean arg3) + throws SAXException, IOException { + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(stream); + certificates.add(cert); + } catch (Exception e) { + exceptions.add(e); + } finally { + } + } + }); + + try (InputStream stream = getStream("test-files/test_serverPKCS7.p7b")) { + parser.parse(stream, handler, metadata, context); + + assertEquals(exceptions.size(), 0); + assertEquals(certificates.size(), 1); + assertEquals(certificates.get(0).getSubjectDN().toString(), + "EMAILADDRESS=guilhermeandreuce@gmail.com, CN=pf.gov.br, OU=PF, O=Polícia Federal, L=Asa Sul, ST=Brasília, C=BR"); + assertEquals(certificates.get(0).getSubjectX500Principal().getName(), + "1.2.840.113549.1.9.1=#161b6775696c6865726d65616e64726575636540676d61696c2e636f6d,CN=pf.gov.br,OU=PF,O=Polícia Federal,L=Asa Sul,ST=Brasília,C=BR"); }