Java tutorial
/* * Copyright 2015 Lus Diogo Zambujo, Micael Sousa Farinha and Miguel Frade * * This file is part of aCCinaPDF. * * aCCinaPDF is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * aCCinaPDF is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with aCCinaPDF. If not, see <http://www.gnu.org/licenses/>. * */ package controller; import model.Settings; import accinapdf.ACCinaPDF; import com.itextpdf.text.BaseColor; import model.CCSignatureSettings; import model.CCAlias; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Element; import com.itextpdf.text.ExceptionConverter; import com.itextpdf.text.FontFactory; import com.itextpdf.text.Image; import com.itextpdf.text.Phrase; import com.itextpdf.text.Rectangle; import com.itextpdf.text.error_messages.MessageLocalization; import com.itextpdf.text.pdf.AcroFields; import com.itextpdf.text.pdf.BaseFont; import com.itextpdf.text.pdf.ColumnText; import com.itextpdf.text.pdf.PdfDictionary; import com.itextpdf.text.pdf.PdfEncryption; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfSignatureAppearance; import com.itextpdf.text.pdf.PdfStamper; import com.itextpdf.text.pdf.PdfTemplate; import com.itextpdf.text.pdf.PdfWriter; import com.itextpdf.text.pdf.security.CertificateUtil; import com.itextpdf.text.pdf.security.CertificateVerification; import com.itextpdf.text.pdf.security.CrlClient; import com.itextpdf.text.pdf.security.ExternalDigest; import com.itextpdf.text.pdf.security.ExternalSignature; import com.itextpdf.text.pdf.security.KeyStoreUtil; import com.itextpdf.text.pdf.security.MakeSignature; import com.itextpdf.text.pdf.security.OcspClient; import com.itextpdf.text.pdf.security.OcspClientBouncyCastle; import com.itextpdf.text.pdf.security.PdfPKCS7; import com.itextpdf.text.pdf.security.PrivateKeySignature; import com.itextpdf.text.pdf.security.ProviderDigest; import com.itextpdf.text.pdf.security.SignaturePermissions; import com.itextpdf.text.pdf.security.TSAClient; import com.itextpdf.text.pdf.security.TSAClientBouncyCastle; import exception.AliasException; import exception.KeyStoreNotLoadedException; import exception.LibraryNotFoundException; import exception.LibraryNotLoadedException; import exception.RevisionExtractionException; import exception.SignatureFailedException; import java.awt.Font; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.net.URL; import java.security.CodeSource; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Security; import java.security.UnrecoverableKeyException; import java.security.cert.CRL; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.PKIXParameters; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.logging.Level; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.smartcardio.Card; import javax.smartcardio.CardChannel; import javax.smartcardio.CardTerminal; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; import javax.smartcardio.TerminalFactory; import javax.swing.JFileChooser; import listener.SignatureListener; import listener.ValidationListener; import model.CertificateStatus; import model.SignatureValidation; import org.apache.commons.lang3.SystemUtils; import org.apache.commons.lang3.text.WordUtils; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.Extensions; import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; import org.bouncycastle.cert.ocsp.BasicOCSPResp; import org.bouncycastle.cert.ocsp.CertificateID; import org.bouncycastle.cert.ocsp.OCSPException; import org.bouncycastle.cert.ocsp.OCSPReq; import org.bouncycastle.cert.ocsp.OCSPReqBuilder; import org.bouncycastle.cert.ocsp.OCSPResp; import org.bouncycastle.cert.ocsp.RevokedStatus; import org.bouncycastle.cert.ocsp.SingleResp; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.ocsp.UnknownStatus; import org.bouncycastle.operator.OperatorException; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; import org.bouncycastle.tsp.TimeStampToken; import sun.security.pkcs11.SunPKCS11; import view.MultipleValidationDialog; /** * * @author Diogo */ public class CCInstance { private static final String SIGNATURE_CREATOR = "aCCinaPDF"; private static final String KEYSTORE_PATH = "/keystore/aCCinaPDF_cacerts"; private KeyStore ks; private KeyStore pkcs11ks; private SunPKCS11 pkcs11Provider; private final ArrayList<CCAlias> aliasList = new ArrayList<>(); private static CCInstance instance; public CCInstance() { Security.addProvider(new BouncyCastleProvider()); } public static void newIstance() { instance = new CCInstance(); } public static final CCInstance getInstance() { return instance; } public final ArrayList<CCAlias> loadKeyStoreAndAliases() throws LibraryNotLoadedException, KeyStoreNotLoadedException, CertificateException, KeyStoreException, LibraryNotFoundException, AliasException { String pkcs11config = "name = SmartCard\n library = "; String path = null; if (SystemUtils.IS_OS_WINDOWS) { path = System.getenv("HOMEDRIVE") + "\\windows\\system32\\pteidpkcs11.dll"; } else if (SystemUtils.IS_OS_LINUX) { path = "/usr/local/lib/libpteidpkcs11.so"; } else if (SystemUtils.IS_OS_MAC_OSX) { path = "/usr/local/lib/pteidpkcs11.bundle"; } if (null == path) { throw new LibraryNotLoadedException(Bundle.getBundle().getString("unknownOS")); } else if (new File(path).exists()) { pkcs11config += path; } else { String res = userLoadLibraryPKCS11(); if (null != res) { pkcs11config += res; } throw new LibraryNotFoundException(Bundle.getBundle().getString("libraryNotFound")); } final byte[] pkcs11configBytes; try { pkcs11configBytes = pkcs11config.getBytes(); } catch (Exception eiie) { Logger.getLogger().addEntry(eiie); throw new LibraryNotFoundException(Bundle.getBundle().getString("libraryDoesNotExist")); } final ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11configBytes); try { pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream); pkcs11Provider.setCallbackHandler(new CallbackHandler() { @Override public void handle(javax.security.auth.callback.Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (javax.security.auth.callback.Callback c : callbacks) { if (c instanceof PasswordCallback) { ((PasswordCallback) c).setPassword(null); } } } }); } catch (Exception eiie) { Logger.getLogger().addEntry(eiie); throw new LibraryNotLoadedException(Bundle.getBundle().getString("libraryNotLoaded")); } Security.addProvider(pkcs11Provider); try { pkcs11ks = KeyStore.getInstance("PKCS11"); pkcs11ks.load(null, null); } catch (Exception e) { Logger.getLogger().addEntry(e); throw new KeyStoreNotLoadedException(Bundle.getBundle().getString("keystoreNotLoaded")); } final Enumeration aliasesEnum = pkcs11ks.aliases(); aliasList.clear(); while (aliasesEnum.hasMoreElements()) { final String alias = (String) aliasesEnum.nextElement(); if (null != alias) { if (alias.isEmpty()) { throw new AliasException(Bundle.getBundle().getString("blankAlias")); } else { final Certificate[] certChain = pkcs11ks.getCertificateChain(alias); if (null != certChain) { if (CCAlias.ASSINATURA.equals(alias)) { if (0 == certChain.length) { throw new CertificateException(Bundle.getBundle().getString("chainInvalidFormat")); } else { final Certificate cert = certChain[0]; try { ((X509Certificate) cert).checkValidity(); if (1 <= certChain.length) { final CCAlias ccAliasTemp = new CCAlias(alias, certChain); aliasList.add(ccAliasTemp); } } catch (CertificateExpiredException cee) { Logger.getLogger().addEntry(cee); throw new CertificateException(Bundle.getBundle().getString("aliasCertificate") + " " + alias + " " + Bundle.getBundle().getString("expired") + "!"); } catch (CertificateNotYetValidException cee) { Logger.getLogger().addEntry(cee); throw new CertificateException( Bundle.getBundle().getString("aliasCertificate") + " " + alias + " " + Bundle.getBundle().getString("notYetValid") + "!"); } } } } } } } return aliasList; } public final ArrayList<CCAlias> getAliasList() { return aliasList; } private PrivateKey getPrivateKeyFromAlias(final String alias) { try { final PrivateKey pkey = (PrivateKey) pkcs11ks.getKey(alias, null); return pkey; } catch (KeyStoreException e) { controller.Logger.getLogger().addEntry(e); } catch (NoSuchAlgorithmException e) { controller.Logger.getLogger().addEntry(e); } catch (UnrecoverableKeyException e) { controller.Logger.getLogger().addEntry(e); } catch (Exception e) { controller.Logger.getLogger().addEntry(e); } return null; } public final Certificate[] getCompleteTrustedCertificateChain(final X509Certificate x509c) throws KeyStoreException, IOException, FileNotFoundException, NoSuchAlgorithmException, CertificateException, InvalidAlgorithmParameterException { final ArrayList<X509Certificate> certChainList = new ArrayList<>(); certChainList.add(x509c); X509Certificate temp = x509c; while (true) { X509Certificate issuer = (X509Certificate) hasTrustedIssuerCertificate(temp); if (null != issuer) { if (temp.equals(issuer)) { break; } certChainList.add(issuer); temp = issuer; } else { break; } } final Certificate[] certificateChain = new Certificate[certChainList.size()]; for (int i = 0; i < certChainList.size(); i++) { certificateChain[i] = certChainList.get(i); } return certificateChain; } public final boolean signPdf(final String pdfPath, final String destination, final CCSignatureSettings settings, final SignatureListener sl) throws CertificateException, IOException, DocumentException, KeyStoreException, SignatureFailedException, FileNotFoundException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { PrivateKey pk; final PdfReader reader = new PdfReader(pdfPath); pk = getPrivateKeyFromAlias(settings.getCcAlias().getAlias()); if (getCertificationLevel(pdfPath) == PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED) { String message = Bundle.getBundle().getString("fileDoesNotAllowChanges"); if (sl != null) { sl.onSignatureComplete(pdfPath, false, message); } throw new SignatureFailedException(message); } if (reader.getNumberOfPages() - 1 < settings.getPageNumber()) { settings.setPageNumber(reader.getNumberOfPages() - 1); } if (null == pk) { String message = Bundle.getBundle().getString("noSmartcardFound"); if (sl != null) { sl.onSignatureComplete(pdfPath, false, message); } throw new CertificateException(message); } if (null == pkcs11ks.getCertificateChain(settings.getCcAlias().getAlias())) { String message = Bundle.getBundle().getString("certificateNullChain"); if (sl != null) { sl.onSignatureComplete(pdfPath, false, message); } throw new CertificateException(message); } final ArrayList<Certificate> embeddedCertificateChain = settings.getCcAlias().getCertificateChain(); final Certificate owner = embeddedCertificateChain.get(0); final Certificate lastCert = embeddedCertificateChain.get(embeddedCertificateChain.size() - 1); if (null == owner) { String message = Bundle.getBundle().getString("certificateNameUnknown"); if (sl != null) { sl.onSignatureComplete(pdfPath, false, message); } throw new CertificateException(message); } final X509Certificate X509C = ((X509Certificate) lastCert); final Calendar now = Calendar.getInstance(); final Certificate[] filledMissingCertsFromChainInTrustedKeystore = getCompleteTrustedCertificateChain( X509C); final Certificate[] fullCertificateChain; if (filledMissingCertsFromChainInTrustedKeystore.length < 2) { fullCertificateChain = new Certificate[embeddedCertificateChain.size()]; for (int i = 0; i < embeddedCertificateChain.size(); i++) { fullCertificateChain[i] = embeddedCertificateChain.get(i); } } else { fullCertificateChain = new Certificate[embeddedCertificateChain.size() + filledMissingCertsFromChainInTrustedKeystore.length - 1]; int i = 0; for (i = 0; i < embeddedCertificateChain.size(); i++) { fullCertificateChain[i] = embeddedCertificateChain.get(i); } for (int f = 1; f < filledMissingCertsFromChainInTrustedKeystore.length; f++, i++) { fullCertificateChain[i] = filledMissingCertsFromChainInTrustedKeystore[f]; } } // Leitor e Stamper FileOutputStream os = null; try { os = new FileOutputStream(destination); } catch (FileNotFoundException e) { String message = Bundle.getBundle().getString("outputFileError"); if (sl != null) { sl.onSignatureComplete(pdfPath, false, message); } throw new IOException(message); } // Aparncia da Assinatura final char pdfVersion; switch (Settings.getSettings().getPdfVersion()) { case "/1.2": pdfVersion = PdfWriter.VERSION_1_2; break; case "/1.3": pdfVersion = PdfWriter.VERSION_1_3; break; case "/1.4": pdfVersion = PdfWriter.VERSION_1_4; break; case "/1.5": pdfVersion = PdfWriter.VERSION_1_5; break; case "/1.6": pdfVersion = PdfWriter.VERSION_1_6; break; case "/1.7": pdfVersion = PdfWriter.VERSION_1_7; break; default: pdfVersion = PdfWriter.VERSION_1_7; } final PdfStamper stamper = (getNumberOfSignatures(pdfPath) == 0 ? PdfStamper.createSignature(reader, os, pdfVersion) : PdfStamper.createSignature(reader, os, pdfVersion, null, true)); final PdfSignatureAppearance appearance = stamper.getSignatureAppearance(); appearance.setSignDate(now); appearance.setReason(settings.getReason()); appearance.setLocation(settings.getLocation()); appearance.setCertificationLevel(settings.getCertificationLevel()); appearance.setSignatureCreator(SIGNATURE_CREATOR); appearance.setCertificate(owner); final String fieldName = settings.getPrefix() + " " + (1 + getNumberOfSignatures(pdfPath)); if (settings.isVisibleSignature()) { appearance.setVisibleSignature(settings.getPositionOnDocument(), settings.getPageNumber() + 1, fieldName); appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.DESCRIPTION); if (null != settings.getAppearance().getImageLocation()) { appearance.setImage(Image.getInstance(settings.getAppearance().getImageLocation())); } com.itextpdf.text.Font font = new com.itextpdf.text.Font(FontFactory .getFont(settings.getAppearance().getFontLocation(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 0) .getBaseFont()); font.setColor(new BaseColor(settings.getAppearance().getFontColor().getRGB())); if (settings.getAppearance().isBold() && settings.getAppearance().isItalic()) { font.setStyle(Font.BOLD + Font.ITALIC); } else if (settings.getAppearance().isBold()) { font.setStyle(Font.BOLD); } else if (settings.getAppearance().isItalic()) { font.setStyle(Font.ITALIC); } else { font.setStyle(Font.PLAIN); } appearance.setLayer2Font(font); String text = ""; if (settings.getAppearance().isShowName()) { if (!settings.getCcAlias().getName().isEmpty()) { text += settings.getCcAlias().getName() + "\n"; } } if (settings.getAppearance().isShowReason()) { if (!settings.getReason().isEmpty()) { text += settings.getReason() + "\n"; } } if (settings.getAppearance().isShowLocation()) { if (!settings.getLocation().isEmpty()) { text += settings.getLocation() + "\n"; } } if (settings.getAppearance().isShowDate()) { DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); SimpleDateFormat sdf = new SimpleDateFormat("Z"); text += df.format(now.getTime()) + " " + sdf.format(now.getTime()) + "\n"; } if (!settings.getText().isEmpty()) { text += settings.getText(); } PdfTemplate layer2 = appearance.getLayer(2); Rectangle rect = settings.getPositionOnDocument(); Rectangle sr = new Rectangle(rect.getWidth(), rect.getHeight()); float size = ColumnText.fitText(font, text, sr, 1024, PdfWriter.RUN_DIRECTION_DEFAULT); ColumnText ct = new ColumnText(layer2); ct.setRunDirection(PdfWriter.RUN_DIRECTION_DEFAULT); ct.setAlignment(Element.ALIGN_MIDDLE); int align; switch (settings.getAppearance().getAlign()) { case 0: align = Element.ALIGN_LEFT; break; case 1: align = Element.ALIGN_CENTER; break; case 2: align = Element.ALIGN_RIGHT; break; default: align = Element.ALIGN_LEFT; } ct.setSimpleColumn(new Phrase(text, font), sr.getLeft(), sr.getBottom(), sr.getRight(), sr.getTop(), size, align); ct.go(); } else { appearance.setVisibleSignature(new Rectangle(0, 0, 0, 0), 1, fieldName); } // CRL <- Pesado! final ArrayList<CrlClient> crlList = null; // OCSP OcspClient ocspClient = new OcspClientBouncyCastle(); // TimeStamp TSAClient tsaClient = null; if (settings.isTimestamp()) { tsaClient = new TSAClientBouncyCastle(settings.getTimestampServer(), null, null); } final String hashAlg = getHashAlgorithm(X509C.getSigAlgName()); final ExternalSignature es = new PrivateKeySignature(pk, hashAlg, pkcs11Provider.getName()); final ExternalDigest digest = new ProviderDigest(pkcs11Provider.getName()); try { MakeSignature.signDetached(appearance, digest, es, fullCertificateChain, crlList, ocspClient, tsaClient, 0, MakeSignature.CryptoStandard.CMS); if (sl != null) { sl.onSignatureComplete(pdfPath, true, ""); } return true; } catch (Exception e) { os.flush(); os.close(); new File(destination).delete(); if ("sun.security.pkcs11.wrapper.PKCS11Exception: CKR_FUNCTION_CANCELED".equals(e.getMessage())) { throw new SignatureFailedException(Bundle.getBundle().getString("userCanceled")); } else if ("sun.security.pkcs11.wrapper.PKCS11Exception: CKR_GENERAL_ERROR".equals(e.getMessage())) { throw new SignatureFailedException(Bundle.getBundle().getString("noPermissions")); } else if (e instanceof ExceptionConverter) { String message = Bundle.getBundle().getString("timestampFailed"); if (sl != null) { sl.onSignatureComplete(pdfPath, false, message); } throw new SignatureFailedException(message); } else { if (sl != null) { sl.onSignatureComplete(pdfPath, false, Bundle.getBundle().getString("unknownErrorLog")); } controller.Logger.getLogger().addEntry(e); } return false; } } public final int getNumberOfSignatures(final String pdfPath) { final KeyStore keystore = KeyStoreUtil.loadCacertsKeyStore(); try { keystore.load(null, null); final PdfReader reader = new PdfReader(pdfPath); final int numSigs = reader.getAcroFields().getSignatureNames().size(); reader.close(); return numSigs; } catch (IOException ex) { controller.Logger.getLogger().addEntry(ex); } catch (NoSuchAlgorithmException ex) { controller.Logger.getLogger().addEntry(ex); } catch (CertificateException ex) { controller.Logger.getLogger().addEntry(ex); } return -1; } public final ArrayList<SignatureValidation> validatePDF(final String file, final ValidationListener vl) throws IOException, DocumentException, GeneralSecurityException { this.validating = true; final PdfReader reader = new PdfReader(file); final AcroFields af = reader.getAcroFields(); final ArrayList names = af.getSignatureNames(); final ArrayList<SignatureValidation> validateList = new ArrayList<>(); X509Certificate x509c = null; Security.setProperty("ocsp.enable", "true"); System.setProperty("com.sun.security.enableCRLDP", "true"); boolean nextValid = true; for (Object o : names) { if (!validating) { return null; } final String name = (String) o; final PdfPKCS7 pk = af.verifySignature(name, "BC"); final Certificate pkc[] = pk.getCertificates(); x509c = (X509Certificate) pkc[pkc.length - 1]; final Certificate[] aL = pkc;//getCompleteCertificateChain(x509c); if (null == aL || 0 == aL.length) { return null; } CertificateStatus ocspCertificateStatus = CertificateStatus.UNCHECKED; BasicOCSPResp ocspResp = pk.getOcsp(); if (null != ocspResp && pk.isRevocationValid()) { for (SingleResp singleResp : ocspResp.getResponses()) { if (null == singleResp.getCertStatus()) { ocspCertificateStatus = CertificateStatus.OK; } else if (singleResp.getCertStatus() instanceof RevokedStatus) { if (ocspResp.getProducedAt() .before(((RevokedStatus) singleResp.getCertStatus()).getRevocationTime())) { ocspCertificateStatus = CertificateStatus.OK; } else { ocspCertificateStatus = CertificateStatus.REVOKED; } } else if (singleResp.getCertStatus() instanceof UnknownStatus) { ocspCertificateStatus = CertificateStatus.UNKNOWN; } } } CertificateStatus crlCertificateStatus = CertificateStatus.UNCHECKED; Collection<CRL> crlResp = pk.getCRLs(); if (null != crlResp) { boolean revoked = false; for (CRL crl : crlResp) { if (crl.isRevoked(x509c)) { revoked = true; } } crlCertificateStatus = revoked ? CertificateStatus.REVOKED : CertificateStatus.OK; } if (ocspCertificateStatus.equals(CertificateStatus.UNCHECKED) && crlCertificateStatus.equals(CertificateStatus.UNCHECKED)) { if (pkc.length == 1) { Certificate[] completeChain = getCompleteTrustedCertificateChain(x509c); if (completeChain.length == 1) { ocspCertificateStatus = CertificateStatus.UNCHAINED; } else { ocspCertificateStatus = CertificateStatus.CHAINED_LOCALLY; } } } final TimeStampToken tst = pk.getTimeStampToken(); boolean validTimestamp = false; if (null != tst) { final boolean hasTimestamp = pk.verifyTimestampImprint(); validTimestamp = hasTimestamp && CertificateVerification.verifyTimestampCertificates(tst, ks, null); } PdfDictionary pdfDic = reader.getAcroFields().getSignatureDictionary(name); SignaturePermissions sp = new SignaturePermissions(pdfDic, null); boolean isValid; if (nextValid) { isValid = pk.verify(); } else { isValid = false; } List<AcroFields.FieldPosition> posList = af.getFieldPositions(name); final SignatureValidation signature = new SignatureValidation(file, name, pk, !pk.verify(), af.signatureCoversWholeDocument(name), af.getRevision(name), af.getTotalRevisions(), reader.getCertificationLevel(), ocspCertificateStatus, crlCertificateStatus, validTimestamp, posList, sp, isValid); validateList.add(signature); if (null != vl) { vl.onValidationComplete(signature); } if (!sp.isFillInAllowed()) { nextValid = false; } } return validateList; } public File extractRevision(final String filePath, final String revision) throws IOException, RevisionExtractionException { final PdfReader reader = new PdfReader(filePath); final AcroFields af = reader.getAcroFields(); final File fout = File.createTempFile("temp", " - " + WordUtils.capitalize(Bundle.getBundle().getString("revision")) + ": " + revision + ".pdf"); final FileOutputStream os = new FileOutputStream(fout); final byte bb[] = new byte[1028]; final InputStream ip = af.extractRevision(revision); if (null == ip) { throw new RevisionExtractionException(); } int n = 0; while ((n = ip.read(bb)) > 0) { os.write(bb, 0, n); } os.close(); ip.close(); return fout; } private String userLoadLibraryPKCS11() { JFileChooser fileChooser = new JFileChooser(); fileChooser.setDialogTitle(Bundle.getBundle().getString("openLibrary")); int userSelection = fileChooser.showSaveDialog(null); if (userSelection == JFileChooser.APPROVE_OPTION) { String dest = fileChooser.getSelectedFile().getAbsolutePath(); File file = new File(dest); if (file.exists()) { return dest; } } return null; } private KeyStore defaultKs; public KeyStore getDefaultKeystore() { if (null == defaultKs) { final InputStream fis = CCInstance.class.getResourceAsStream(KEYSTORE_PATH); defaultKs = null; try { defaultKs = KeyStore.getInstance(KeyStore.getDefaultType()); defaultKs.load(fis, null); } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException ex) { } } return defaultKs; } public KeyStore getKeystore() { return this.ks; } public void setKeystore(KeyStore ks) { this.ks = ks; } public ArrayList<Certificate> getTrustedCertificatesFromKeystore(KeyStore keystore) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, InvalidAlgorithmParameterException { final PKIXParameters params = new PKIXParameters(keystore); final ArrayList<Certificate> alTrustedCertificates = new ArrayList<>(); for (final TrustAnchor ta : params.getTrustAnchors()) { Certificate cert = (Certificate) ta.getTrustedCert(); alTrustedCertificates.add(cert); } return alTrustedCertificates; } public Certificate hasTrustedIssuerCertificate(final X509Certificate x509c) { ArrayList<Certificate> alTrustedCertificates; try { alTrustedCertificates = getTrustedCertificatesFromKeystore(getKeystore()); } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | InvalidAlgorithmParameterException ex) { return null; } if (alTrustedCertificates.isEmpty()) { return null; } for (final Certificate c : alTrustedCertificates) { try { final X509Certificate x509cc = (X509Certificate) c; if (x509c.getIssuerX500Principal().equals(x509cc.getSubjectX500Principal())) { return c; } } catch (Exception e) { return null; } } return null; } public boolean isTrustedCertificate(final X509Certificate x509c) { ArrayList<Certificate> alTrustedCertificates; try { alTrustedCertificates = getTrustedCertificatesFromKeystore(getKeystore()); } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | InvalidAlgorithmParameterException ex) { return false; } if (alTrustedCertificates.isEmpty()) { return false; } for (final Certificate c : alTrustedCertificates) { try { final X509Certificate x509cc = (X509Certificate) c; if (x509c.getSubjectX500Principal().equals(x509cc.getSubjectX500Principal())) { return true; } } catch (Exception e) { return false; } } return false; } public final String getCurrentFolder() { final CodeSource cs = ACCinaPDF.class.getProtectionDomain().getCodeSource(); File f = null; try { f = new File(cs.getLocation().toURI().getPath()); } catch (URISyntaxException ex) { return null; } return f.getParentFile().getPath(); } private String getHashAlgorithm(String sigAlgName) { if (sigAlgName.toLowerCase().contains("with")) { final String[] parts; parts = sigAlgName.split("with"); if (2 == parts.length) { if ("SHA1".equalsIgnoreCase(parts[0])) { return "SHA-1"; } else if ("SHA2".equalsIgnoreCase(parts[0])) { return "SHA-2"; } else if ("SHA3".equalsIgnoreCase(parts[0])) { return "SHA-3"; } else if ("SHA128".equalsIgnoreCase(parts[0])) { return "SHA-128"; } else if ("SHA256".equalsIgnoreCase(parts[0])) { return "SHA-256"; } else if ("SHA384".equalsIgnoreCase(parts[0])) { return "SHA-384"; } else if ("SHA512".equalsIgnoreCase(parts[0])) { return "SHA-512"; } else { return parts[0]; } } } return sigAlgName; } public final int getCertificationLevel(final String filename) throws IOException { final PdfReader reader = new PdfReader(filename); final int certLevel = reader.getCertificationLevel(); reader.close(); return certLevel; } private boolean validating; public void setValidating(boolean validating) { this.validating = validating; } private OCSPResp getOcspResponse(X509Certificate checkCert, X509Certificate rootCert) throws GeneralSecurityException, OCSPException, IOException, OperatorException { if (checkCert == null || rootCert == null) { return null; } String url = CertificateUtil.getOCSPURL(checkCert); if (url == null) { return null; } try { OCSPReq request = generateOCSPRequest(rootCert, checkCert.getSerialNumber()); byte[] array = request.getEncoded(); URL urlt = new URL(url); HttpURLConnection con = (HttpURLConnection) urlt.openConnection(); con.setRequestProperty("Content-Type", "application/ocsp-request"); con.setRequestProperty("Accept", "application/ocsp-response"); con.setDoOutput(true); OutputStream out = con.getOutputStream(); try (DataOutputStream dataOut = new DataOutputStream(new BufferedOutputStream(out))) { dataOut.write(array); dataOut.flush(); } if (con.getResponseCode() / 100 != 2) { throw new IOException( MessageLocalization.getComposedMessage("invalid.http.response.1", con.getResponseCode())); } //Get Response InputStream in = (InputStream) con.getContent(); return new OCSPResp(in); } catch (Exception e) { return null; } } private static OCSPReq generateOCSPRequest(X509Certificate issuerCert, BigInteger serialNumber) throws OCSPException, IOException, OperatorException, CertificateEncodingException { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); CertificateID id = new CertificateID( new JcaDigestCalculatorProviderBuilder().build().get(CertificateID.HASH_SHA1), new JcaX509CertificateHolder(issuerCert), serialNumber); OCSPReqBuilder gen = new OCSPReqBuilder(); gen.addRequest(id); Extension ext = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString(new DEROctetString(PdfEncryption.createDocumentId()).getEncoded())); gen.setRequestExtensions(new Extensions(new Extension[] { ext })); return gen.build(); } public String getCertificateProperty(X500Name x500name, String property) { String cn = ""; LdapName ldapDN = null; try { ldapDN = new LdapName(x500name.toString()); } catch (InvalidNameException ex) { java.util.logging.Logger.getLogger(MultipleValidationDialog.class.getName()).log(Level.SEVERE, null, ex); } for (Rdn rdn : ldapDN.getRdns()) { if (rdn.getType().equals(property)) { cn = rdn.getValue().toString(); } } return cn; } }