Red Hat Application Migration Toolkit
package ee.sk.digidoc.factory; import ee.sk.digidoc.Base64Util; import ee.sk.digidoc.CertID; import ee.sk.digidoc.CertValue; import ee.sk.digidoc.DataFile; import ee.sk.digidoc.DataObjectFormat; import ee.sk.digidoc.DigiDocException; import ee.sk.digidoc.Identifier; import ee.sk.digidoc.ManifestFileEntry; import ee.sk.digidoc.Notary; import ee.sk.digidoc.OcspRef; import ee.sk.digidoc.Rdn; import ee.sk.digidoc.Reference; import ee.sk.digidoc.SigPolicyQualifier; import ee.sk.digidoc.Signature; import ee.sk.digidoc.SignedDoc; import ee.sk.digidoc.SignedProperties; import ee.sk.digidoc.SpUri; import ee.sk.digidoc.factory.NotaryFactory; import ee.sk.digidoc.factory.TrustServiceFactory; import ee.sk.utils.ConfigManager; import ee.sk.utils.ConvertUtils; import java.io.File; import java.math.BigInteger; import java.security.Provider; import java.security.Security; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import javax.crypto.Cipher; import org.apache.log4j.Logger; public class DigiDocVerifyFactory { private static Logger m_logger = Logger.getLogger(DigiDocVerifyFactory.class); private static boolean m_prvInited = false; private static final String DIG_TYPE_WARNING = "The current BDoc container uses weaker encryption method than officialy accepted in Estonia. We do not recommend you to add signature to this document. There is an option to re-sign this document in a new container."; private static final String DIGIDOC_VERIFY_ALGORITHM = "RSA/NONE/PKCS1Padding"; public static void initProvider() { try { if(!m_prvInited) { Provider ex = (Provider)Class.forName(ConfigManager.instance().getProperty("DIGIDOC_SECURITY_PROVIDER")).newInstance(); Security.addProvider(ex); m_prvInited = true; } } catch (Exception var1) { m_logger.error("Error initting provider: " + var1); } } public static boolean compareDigests(byte[] dig1, byte[] dig2) { boolean ok = dig1 != null && dig2 != null && dig1.length == dig2.length; for(int i = 0; ok && i < dig1.length; ++i) { if(dig1[i] != dig2[i]) { ok = false; } } return ok; } public static boolean verifyManifestEntries(SignedDoc sdoc, List lerrs) throws DigiDocException { boolean bOk = true; if(sdoc != null && sdoc.getFormat() != null && sdoc.getFormat().equals("BDOC")) { int j; boolean bF; int i; for(j = 0; j < sdoc.countDataFiles(); ++j) { DataFile mfe = sdoc.getDataFile(j); bF = false; if(sdoc.getManifest() != null) { for(i = 0; i < sdoc.getManifest().getNumFileEntries(); ++i) { ManifestFileEntry df = sdoc.getManifest().getFileEntry(i); if(df.getFullPath() != null && df.getFullPath().equals(mfe.getFileName())) { if(bF) { lerrs.add(new DigiDocException(180, "Duplicate ManifestFileEntry for: " + mfe.getFileName(), (Throwable)null)); bOk = false; } else { bF = true; } if(df.getMediaType() == null || mfe.getMimeType() == null || !df.getMediaType().equals(mfe.getMimeType())) { lerrs.add(new DigiDocException(181, "DataFile " + mfe.getFileName() + " mime-type: " + mfe.getMimeType() + " does not match manifest mime type: " + df.getMediaType(), (Throwable)null)); bOk = false; } } } } if(!bF) { lerrs.add(new DigiDocException(180, "Missing ManifestFileEntry for: " + mfe.getFileName(), (Throwable)null)); } } for(j = 0; j < sdoc.getManifest().getNumFileEntries(); ++j) { ManifestFileEntry var8 = sdoc.getManifest().getFileEntry(j); if(var8.getFullPath() == null || !var8.getFullPath().equals("/")) { bF = false; for(i = 0; i < sdoc.countDataFiles(); ++i) { DataFile var9 = sdoc.getDataFile(i); if(var8.getFullPath() != null && var8.getFullPath().equals(var9.getFileName())) { if(bF) { lerrs.add(new DigiDocException(180, "Duplicate DataFile: " + var9.getId() + " with name: " + var9.getFileName(), (Throwable)null)); bOk = false; } else { bF = true; } } } if(!bF) { lerrs.add(new DigiDocException(180, "Missing DataFile for ManifestFileEntry: " + var8.getFullPath(), (Throwable)null)); } } } } return bOk; } private static boolean verifyDataFileHash(SignedDoc sdoc, DataFile df, Reference ref, List lerrs) { boolean bOk = true; if(df != null) { if(m_logger.isDebugEnabled()) { m_logger.debug("Check digest for DF: " + df.getId() + " ref: " + (ref != null?ref.getUri():"NULL")); } String sDigType = ConfigManager.digAlg2Type(ref.getDigestAlgorithm()); if(m_logger.isDebugEnabled()) { m_logger.debug("Check digest for DF: " + df.getId() + " type: " + sDigType); } byte[] dfDig = null; try { dfDig = df.getDigestValueOfType(sDigType); } catch (DigiDocException var9) { lerrs.add(var9); bOk = false; m_logger.error("Error calculating hash for df: " + df.getId() + " - " + var9); var9.printStackTrace(); if(var9.getNestedException() != null) { var9.getNestedException().printStackTrace(); } } if(ref != null) { if(m_logger.isDebugEnabled()) { m_logger.debug("Compare digest: " + (dfDig != null?Base64Util.encode(dfDig, 0):"NONE") + " hex: " + (dfDig != null?ConvertUtils.bin2hex(dfDig):"NONE") + " alt digest: " + (df.getAltDigest() != null?Base64Util.encode(df.getAltDigest(), 0):"NONE") + " to: " + (ref.getDigestValue() != null?Base64Util.encode(ref.getDigestValue()):"NONE") + " hex: " + (ref.getDigestValue() != null?ConvertUtils.bin2hex(ref.getDigestValue()):"NONE")); } DigiDocException sFile = null; if(!SignedDoc.compareDigests(ref.getDigestValue(), dfDig)) { lerrs.add(sFile = new DigiDocException(79, "Bad digest for DataFile: " + df.getId(), (Throwable)null)); if(m_logger.isDebugEnabled()) { m_logger.debug("BAD DIGEST for DF: " + df.getId()); } bOk = false; } if(!bOk && df.getAltDigest() != null) { if(SignedDoc.compareDigests(ref.getDigestValue(), df.getAltDigest())) { if(m_logger.isDebugEnabled()) { m_logger.debug("DF: " + df.getId() + " alternate digest matches!"); m_logger.debug("GOOD ALT DIGEST for DF: " + df.getId()); } if(sFile != null) { lerrs.remove(sFile); } ref.getSignedInfo().getSignature().setAltDigestMatch(true); if(!ref.getSignedInfo().getSignature().getSignedDoc().getFormat().equals("SK-XML")) { lerrs.add(new DigiDocException(173, "Bad digest for DataFile: " + df.getId() + " alternate digest matches!", (Throwable)null)); } bOk = false; } } else if(m_logger.isDebugEnabled()) { m_logger.debug("GOOD DIGEST"); } } else { if(m_logger.isDebugEnabled()) { m_logger.debug("No Reference"); } lerrs.add(new DigiDocException(78, "No Reference element for DataFile: " + df.getId(), (Throwable)null)); bOk = false; } if(sdoc.getFormat().equals("BDOC")) { String sFile1 = df.getFileName(); if(sFile1 != null && sFile1.indexOf(47) != -1 || sFile1.indexOf(92) != -1) { File mfe = new File(sFile1); sFile1 = mfe.getName(); } ManifestFileEntry mfe1 = sdoc.getManifest().findFileEntryByPath(sFile1); if(m_logger.isDebugEnabled()) { m_logger.debug("DF: " + df.getId() + " file: " + sFile1 + " manifest-entry: " + (mfe1 != null?"OK":"NULL")); if(mfe1 == null) { if(m_logger.isDebugEnabled()) { m_logger.debug("No manifest.xml entry for: " + df.getFileName()); } lerrs.add(new DigiDocException(28, "No manifest.xml entry for: " + df.getFileName(), (Throwable)null)); bOk = false; } } } } else { if(m_logger.isDebugEnabled()) { m_logger.debug("Invalid data-file"); } bOk = false; } return bOk; } private static boolean verifySignedPropretiesHash(Signature sig, List lerrs) { boolean bOk = true; if(m_logger.isDebugEnabled()) { m_logger.debug("Verifying signed-props of: " + sig.getId()); } SignedProperties sp = sig.getSignedProperties(); boolean bSha1Check = ConfigManager.instance().getBooleanProperty("BDOC_SHA1_CHECK", true); if(sp != null) { Reference ref2 = sig.getSignedInfo().getReferenceForSignedProperties(sp); if(ref2 != null && sig.getSignedDoc().getFormat().equals("BDOC") && ref2.getDigestAlgorithm().equals("http://www.w3.org/2000/09/xmldsig#sha1") && ConfigManager.instance().getBooleanProperty("BDOC_SHA1_CHECK", true)) { lerrs.add(new DigiDocException(129, "The current BDoc container uses weaker encryption method than officialy accepted in Estonia. We do not recommend you to add signature to this document. There is an option to re-sign this document in a new container.", (Throwable)null)); if(m_logger.isInfoEnabled()) { m_logger.info("SignedProperties for signature: " + sig.getId() + " has weak digest type: " + ref2.getDigestAlgorithm()); } } if(ref2 != null) { byte[] spDig = null; try { spDig = sp.calculateDigest(); if(m_logger.isDebugEnabled()) { m_logger.debug("SignedProp real digest: " + Base64Util.encode(spDig, 0)); } } catch (DigiDocException var8) { lerrs.add(var8); bOk = false; } if(m_logger.isDebugEnabled()) { m_logger.debug("Compare it to: " + Base64Util.encode(ref2.getDigestValue(), 0)); } if(!SignedDoc.compareDigests(ref2.getDigestValue(), spDig)) { lerrs.add(new DigiDocException(79, "Bad digest for SignedProperties: " + sp.getId(), (Throwable)null)); if(m_logger.isDebugEnabled()) { m_logger.debug("BAD DIGEST for sig-prop"); } bOk = false; } else if(m_logger.isDebugEnabled()) { m_logger.debug("GOOD DIGEST"); } } else { if(m_logger.isDebugEnabled()) { m_logger.debug("No Reference element for SignedProperties: " + sp.getId()); } lerrs.add(new DigiDocException(80, "No Reference element for SignedProperties: " + sp.getId(), (Throwable)null)); bOk = false; } } else { if(m_logger.isDebugEnabled()) { m_logger.debug("No Reference element for SignedProperties: " + sp.getId()); } lerrs.add(new DigiDocException(80, "No Reference element for SignedProperties: " + (sp != null?sp.getId():"?"), (Throwable)null)); bOk = false; } return bOk; } public static boolean verify(byte[] digest, byte[] signature, X509Certificate cert, boolean bSoftCert, String sigMethod) throws DigiDocException { boolean rc = false; try { if(cert == null) { throw new DigiDocException(81, "Invalid or missing signers cert!", (Throwable)null); } java.security.Signature decdig; if(bSoftCert) { ConfigManager.instance(); String ex1 = ConfigManager.sigMeth2SigType(sigMethod); if(m_logger.isDebugEnabled()) { m_logger.debug("Verify xml:\n---\n" + new String(digest) + "\n---\n len: " + digest.length + " method: " + sigMethod + " sig-type: " + ex1 + "\n---\n" + ConvertUtils.bin2hex(signature) + " sig-len: " + signature.length); } if(ex1 == null) { throw new DigiDocException(81, "Signature method: " + sigMethod + " not provided!", (Throwable)null); } decdig = java.security.Signature.getInstance(ex1, ConfigManager.addProvider()); decdig.initVerify(cert.getPublicKey()); decdig.update(digest); rc = decdig.verify(signature); } else { if(m_logger.isDebugEnabled()) { m_logger.debug("Verify sig: " + signature.length + " bytes, alg: " + "RSA/NONE/PKCS1Padding" + " sig-alg: " + sigMethod); } Cipher ex = Cipher.getInstance("RSA/NONE/PKCS1Padding", "BC"); ex.init(2, cert); decdig = null; byte[] decdig1; try { decdig1 = ex.doFinal(signature); } catch (ArrayIndexOutOfBoundsException var11) { if(m_logger.isDebugEnabled()) { m_logger.debug("Invalid signature value. Signers cert and signature value don\'t match! - " + var11); } throw new DigiDocException(81, "Invalid signature value! Signers cert and signature value don\'t match!", var11); } String digType2 = ConfigManager.sigMeth2Type(sigMethod); String digType1 = ConvertUtils.findDigType(decdig1); if(m_logger.isDebugEnabled()) { m_logger.debug("Decrypted digest: \'" + SignedDoc.bin2hex(decdig1) + "\' len: " + decdig1.length + " has-pref: " + digType1 + " must-have: " + digType2 + " alg: " + sigMethod); } if(digType1 != null && digType1.equals("SHA-1-00")) { if(m_logger.isDebugEnabled()) { m_logger.debug("Invalid signature asn.1 prefix with 0x00 byte"); } throw new DigiDocException(174, "Invalid signature asn.1 prefix with 0x00 byte", (Throwable)null); } if(digType1 == null || digType2 != null && digType1 != null && !digType2.equals(digType1)) { if(m_logger.isDebugEnabled()) { m_logger.debug("Signature asn.1 prefix: " + digType1 + " does not match: " + digType2); } throw new DigiDocException(166, "Signature asn.1 prefix: " + digType1 + " does not match: " + digType2, (Throwable)null); } byte[] cdigest = ConvertUtils.removePrefix(decdig1); if(m_logger.isDebugEnabled()) { m_logger.debug("Signed digest: \'" + (cdigest != null?SignedDoc.bin2hex(cdigest):"NULL") + "\' calc-digest: \'" + SignedDoc.bin2hex(digest) + "\'"); } if(decdig1 != null && cdigest != null && decdig1.length == cdigest.length) { if(m_logger.isDebugEnabled()) { m_logger.debug("Signature value decrypted len: " + decdig1.length + " missing ASN.1 structure prefix"); } throw new DigiDocException(81, "Invalid signature value! Signature value decrypted len: " + decdig1.length + " missing ASN.1 structure prefix", (Throwable)null); } rc = compareDigests(digest, cdigest); } if(m_logger.isDebugEnabled()) { m_logger.debug("Result: " + rc); } if(!rc) { throw new DigiDocException(81, "Invalid signature value!", (Throwable)null); } } catch (DigiDocException var12) { throw var12; } catch (Exception var13) { DigiDocException.handleException(var13, 81); } return rc; } public static boolean verifySignatureValue(SignedDoc sdoc, Signature sig, List lerrs) { boolean bOk = true; if(m_logger.isDebugEnabled()) { m_logger.debug("Verifying signature value of: " + sig.getId()); } try { byte[] ex = sig.getSignedInfo().calculateDigest(); if(m_logger.isDebugEnabled()) { m_logger.debug("SignedInfo real digest: " + Base64Util.encode(ex, 0) + " hex: " + SignedDoc.bin2hex(ex)); } if(sdoc.getFormat().equals("BDOC") && (sig.getSignedInfo().getSignatureMethod().equals("http://www.w3.org/2000/09/xmldsig#rsa-sha1") || sig.getSignedInfo().getSignatureMethod().equals("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1")) && ConfigManager.instance().getBooleanProperty("BDOC_SHA1_CHECK", true)) { lerrs.add(new DigiDocException(129, "The current BDoc container uses weaker encryption method than officialy accepted in Estonia. We do not recommend you to add signature to this document. There is an option to re-sign this document in a new container.", (Throwable)null)); if(m_logger.isInfoEnabled()) { m_logger.info("Signature: " + sig.getId() + " has weak signature method: " + sig.getSignedInfo().getSignatureMethod()); } } if(sig.getSignatureValue() != null && sig.getSignatureValue().getValue() != null) { if(sdoc != null && sdoc.getFormat().equals("BDOC") && sig.isEllipticCurveSiganture()) { if(m_logger.isDebugEnabled()) { m_logger.debug("Verify sdoc: " + sdoc.getFormat() + "/" + sdoc.getVersion() + " prefs: " + sdoc.getXmlDsigNs() + "/" + sdoc.getAsicNs() + "/" + sdoc.getXadesNs()); } byte[] xml = sig.getSignedInfo().getOrigXml(); if(m_logger.isDebugEnabled()) { m_logger.debug("Verify xml:\n---\n" + new String(xml) + "\n---\n"); } bOk = verify(xml, sig.getSignatureValue().getValue(), sig.getKeyInfo().getSignersCertificate(), true, sig.getSignedInfo().getSignatureMethod()); } else { if(m_logger.isDebugEnabled()) { m_logger.debug("Verify sig: " + ConvertUtils.bin2hex(sig.getSignatureValue().getValue()) + " len: " + sig.getSignatureValue().getValue().length + " hlen: " + ConvertUtils.bin2hex(sig.getSignatureValue().getValue()).length()); } bOk = verify(ex, sig.getSignatureValue().getValue(), sig.getKeyInfo().getSignersCertificate(), false, sig.getSignedInfo().getSignatureMethod()); } if(m_logger.isDebugEnabled()) { m_logger.debug("GOOD DIGEST"); } } else { if(m_logger.isDebugEnabled()) { m_logger.debug("Missing signature value!"); } lerrs.add(new DigiDocException(38, "Missing signature value!", (Throwable)null)); bOk = false; } } catch (DigiDocException var6) { lerrs.add(var6); if(m_logger.isDebugEnabled()) { m_logger.debug("BAD DIGEST for sig-inf: " + sig.getId() + " - " + var6.toString()); m_logger.debug("TRACE: " + ConvertUtils.getTrace(var6)); m_logger.debug("sig-val-len: " + (sig.getSignatureValue() != null && sig.getSignatureValue().getValue() != null?sig.getSignatureValue().getValue().length:0)); m_logger.debug("signer: " + (sig.getKeyInfo() != null && sig.getKeyInfo().getSignersCertificate() != null?sig.getKeyInfo().getSignersCertificate().getSubjectDN().getName():"NULL")); } bOk = false; } return bOk; } public static boolean verifyCertificate(X509Certificate cert, X509Certificate caCert) throws DigiDocException { boolean rc = false; try { if(caCert != null) { cert.verify(caCert.getPublicKey()); rc = true; } } catch (Exception var4) { DigiDocException.handleException(var4, 94); } return rc; } public static boolean verifySignersCerificate(Signature sig, List lerrs) { boolean bOk = true; try { if(m_logger.isDebugEnabled()) { m_logger.debug("Verifying CA of signature: " + sig.getId() + " produced: " + ConvertUtils.date2string(sig.getSignatureProducedAtTime(), sig.getSignedDoc())); } boolean ex = ConfigManager.instance().getBooleanProperty("DIGIDOC_USE_LOCAL_TSL", false); TrustServiceFactory tslFac = ConfigManager.instance().getTslFactory(); if(sig.getKeyInfo().getSignersCertificate() == null) { lerrs.add(new DigiDocException(39, "Signers cert missing!", (Throwable)null)); return false; } X509Certificate caCert = tslFac.findCaForCert(sig.getKeyInfo().getSignersCertificate(), ex, sig.getSignatureProducedAtTime()); X509Certificate cert = sig.getKeyInfo().getSignersCertificate(); if(m_logger.isDebugEnabled()) { m_logger.debug("Check signer: " + cert.getSubjectDN().getName() + " issued by: " + cert.getIssuerDN().getName() + " SUB from: " + ConvertUtils.date2string(cert.getNotBefore(), sig.getSignedDoc()) + " to: " + ConvertUtils.date2string(cert.getNotAfter(), sig.getSignedDoc()) + " by CA: " + (caCert != null?caCert.getSubjectDN().getName():"NOT FOUND") + " CA from: " + (caCert != null?ConvertUtils.date2string(caCert.getNotBefore(), sig.getSignedDoc()):"?") + " to: " + (caCert != null?ConvertUtils.date2string(caCert.getNotAfter(), sig.getSignedDoc()):"?")); } if(caCert != null) { bOk = verifyCertificate(cert, caCert); if(m_logger.isDebugEnabled()) { m_logger.debug("Signer: " + ConvertUtils.getCommonName(sig.getKeyInfo().getSignersCertificate().getSubjectDN().getName()) + " is issued by trusted CA: " + (caCert != null?ConvertUtils.getCommonName(caCert.getSubjectDN().getName()):"NULL")); } } else { if(m_logger.isDebugEnabled()) { m_logger.debug("CA not found for: " + ConvertUtils.getCommonName(cert.getSubjectDN().getName())); } lerrs.add(new DigiDocException(39, "Signers cert not trusted, missing CA cert!", (Throwable)null)); bOk = false; } if(!ConfigManager.isSignatureKey(cert)) { if(m_logger.isDebugEnabled()) { m_logger.debug("Signers cert does not have non-repudiation bit set!"); } lerrs.add(new DigiDocException(162, "Signers cert does not have non-repudiation bit set!", (Throwable)null)); bOk = false; } CertID cid = sig.getCertIdOfType(1); if(cert != null && cid != null) { boolean bMatch = true; List aCertRdns = parseDN(ConvertUtils.convX509Name(cert.getIssuerX500Principal())); List aCertIdRdns = parseDN(cid.getIssuer()); if(m_logger.isDebugEnabled()) { m_logger.debug("Signed: " + cid.getIssuer() + " cert: " + ConvertUtils.convX509Name(cert.getIssuerX500Principal()) + " cert rdn-s: " + aCertRdns.size() + " signed rdn-s: " + aCertIdRdns.size()); } for(int i = 0; i < aCertIdRdns.size(); ++i) { Rdn r1 = (Rdn)aCertIdRdns.get(i); if(m_logger.isDebugEnabled()) { m_logger.debug("Signed RDN: " + r1.getId() + "/" + r1.getValue()); } boolean bF = false; for(int j = 0; j < aCertRdns.size(); ++j) { Rdn r2 = (Rdn)aCertRdns.get(j); if(r1.getId() != null && r2.getId() != null && r1.getId().equals(r2.getId()) && r1.getValue() != null && r2.getValue() != null && r1.getValue().equals(r2.getValue())) { bF = true; } } if(!bF && r1.getId() != null && (r1.getId().equals("CN") || r1.getId().equals("LT") || r1.getId().equals("ST") || r1.getId().equals("O") || r1.getId().equals("OU") || r1.getId().equals("C") || r1.getId().equals("STREET") || r1.getId().equals("DC") || r1.getId().equals("UID"))) { m_logger.error("No match for signed: " + r1.getId() + "/" + r1.getValue()); bMatch = false; } } if(!bMatch) { m_logger.error("Signers cert issuer DN: " + ConvertUtils.convX509Name(cert.getIssuerX500Principal()) + " and signed Issuername: " + cid.getIssuer() + " don\'t match"); lerrs.add(new DigiDocException(81, "Signing certificate issuer information does not match", (Throwable)null)); } if(cid.getSerial() != null) { if(m_logger.isDebugEnabled()) { m_logger.debug("Signed IssuerSerial: " + cid.getSerial().toString() + " cert serial: " + cert.getSerialNumber().toString()); } if(!cid.getSerial().equals(cert.getSerialNumber())) { m_logger.error("Signers cert issuer serial: " + cert.getSerialNumber().toString() + " and signed IssuerSerial: " + cid.getSerial().toString() + " don\'t match"); lerrs.add(new DigiDocException(81, "Signing certificate issuer information does not match", (Throwable)null)); } } } } catch (DigiDocException var16) { if(m_logger.isDebugEnabled()) { m_logger.debug("Signers certificate not trusted for: " + sig.getId()); } lerrs.add(var16); bOk = false; } return bOk; } public static boolean verifySigningTime(Signature sig, List lerrs) { boolean bOk = true; if(m_logger.isDebugEnabled()) { m_logger.debug("Verifying signing time signature: " + sig.getId()); } try { sig.getKeyInfo().getSignersCertificate().checkValidity(sig.getSignedProperties().getSigningTime()); if(m_logger.isDebugEnabled()) { m_logger.debug("Signers cert: " + ConvertUtils.getCommonName(sig.getKeyInfo().getSignersCertificate().getSubjectDN().getName()) + " was valid on: " + ConvertUtils.date2string(sig.getSignedProperties().getSigningTime(), sig.getSignedDoc())); } } catch (Exception var4) { m_logger.error("Signers certificate has expired for: " + sig.getId()); lerrs.add(new DigiDocException(82, "Signers certificate has expired!", (Throwable)null)); bOk = false; } return bOk; } public static boolean verifySignatureOCSP(Signature sig, List lerrs) { boolean bOk = true; if(m_logger.isDebugEnabled()) { m_logger.debug("Verifying OCSP for signature: " + sig.getId()); } try { if(sig.getUnsignedProperties() != null && sig.getUnsignedProperties().countNotaries() > 0) { CertValue ex = sig.getCertValueOfType(2); CertID cidOcsp = sig.getCertIdOfType(2); X509Certificate rCert = null; String sIssuer = null; BigInteger sSerial = null; Object cHash = null; if(ex != null) { rCert = ex.getCert(); } if(cidOcsp != null) { sIssuer = cidOcsp.getIssuer(); sSerial = cidOcsp.getSerial(); byte[] var20 = cidOcsp.getDigestValue(); } if(m_logger.isDebugEnabled()) { m_logger.debug("Responders cert: " + (rCert != null?rCert.getSerialNumber().toString():"NULL") + " - " + (rCert != null?rCert.getSubjectDN().getName():"NULL") + " complete cert refs nr: " + sSerial + " - " + sIssuer); } if(rCert == null) { if(m_logger.isDebugEnabled()) { m_logger.debug("No ocsp responder cert for: " + sig.getId()); } lerrs.add(new DigiDocException(53, "No notarys certificate!", (Throwable)null)); return false; } if(!rCert.getSerialNumber().equals(sSerial) && !sig.getSignedDoc().getFormat().equals("BDOC")) { if(m_logger.isDebugEnabled()) { m_logger.debug("Wrong notarys certificate: " + rCert.getSerialNumber() + " ref: " + sSerial); } lerrs.add(new DigiDocException(53, "Wrong notarys certificate: " + rCert.getSerialNumber() + " ref: " + sSerial, (Throwable)null)); bOk = false; } try { if(!sig.getSignedDoc().getFormat().equals("BDOC")) { byte[] ex1 = SignedDoc.digestOfType(rCert.getEncoded(), sig.getSignedDoc().getFormat().equals("BDOC")?"SHA-256":"SHA-1"); if(m_logger.isDebugEnabled()) { m_logger.debug("Not cert calc hash: " + Base64Util.encode(ex1, 0) + " cert-ref hash: " + Base64Util.encode(sig.getUnsignedProperties().getCompleteCertificateRefs().getCertDigestValue(), 0)); } if(!compareDigests(ex1, sig.getUnsignedProperties().getCompleteCertificateRefs().getCertDigestValue())) { lerrs.add(new DigiDocException(53, "Notary certificates digest doesn\'t match!", (Throwable)null)); if(m_logger.isDebugEnabled()) { m_logger.debug("Notary certificates digest doesn\'t match!"); } bOk = false; } if(sig.getSignedDoc().getFormat().equals("BDOC") && sig.getUnsignedProperties().getCompleteCertificateRefs().getCertDigestAlgorithm().equals("http://www.w3.org/2000/09/xmldsig#sha1") && ConfigManager.instance().getBooleanProperty("BDOC_SHA1_CHECK", true)) { lerrs.add(new DigiDocException(129, "The current BDoc container uses weaker encryption method than officialy accepted in Estonia. We do not recommend you to add signature to this document. There is an option to re-sign this document in a new container.", (Throwable)null)); if(m_logger.isInfoEnabled()) { m_logger.info("CompleteCertificateRefs for signature: " + sig.getId() + " has weak digest type: " + sig.getUnsignedProperties().getCompleteCertificateRefs().getCertDigestAlgorithm()); } } } } catch (DigiDocException var15) { lerrs.add(var15); bOk = false; } catch (Exception var16) { bOk = false; lerrs.add(new DigiDocException(53, "Error calculating notary certificate digest!", (Throwable)null)); } if(sig.getUnsignedProperties().countNotaries() > 1) { if(m_logger.isDebugEnabled()) { m_logger.debug("Currently supports only one OCSP"); } lerrs.add(new DigiDocException(70, "Currently supports only one OCSP", (Throwable)null)); bOk = false; } if(!sig.getSignedDoc().getFormat().equals("BDOC")) { try { for(int var21 = 0; var21 < sig.getUnsignedProperties().countNotaries(); ++var21) { if(m_logger.isDebugEnabled()) { m_logger.debug("Signature: " + sig.getId() + " not: " + var21 + " notaries: " + sig.getUnsignedProperties().countNotaries()); } Notary i = sig.getUnsignedProperties().getNotaryById(var21); byte[] not = i.getOcspResponseData(); if(m_logger.isDebugEnabled()) { m_logger.debug("OCSP value: " + i.getId() + " data: " + (not != null?not.length:0) + " bytes"); } if(not != null && not.length != 0) { OcspRef orf = sig.getUnsignedProperties().getCompleteRevocationRefs().getOcspRefByUri("#" + i.getId()); if(m_logger.isDebugEnabled()) { m_logger.debug("OCSP ref: " + (orf != null?orf.getUri():"NULL")); } if(orf == null) { lerrs.add(new DigiDocException(83, "No OCSP ref for uri: #" + i.getId(), (Throwable)null)); bOk = false; } else { if(m_logger.isDebugEnabled()) { m_logger.debug("OCSP data len: " + not.length); } byte[] digest1 = SignedDoc.digestOfType(not, !sig.getSignedDoc().getFormat().equals("BDOC") || !orf.getDigestAlgorithm().equals("http://www.w3.org/2001/04/xmlenc#sha256") && !orf.getDigestAlgorithm().equals("http://www.w3.org/2001/04/xmldsig-more#sha256")?"SHA-1":"SHA-256"); byte[] digest2 = orf.getDigestValue(); if(m_logger.isDebugEnabled()) { m_logger.debug("Check ocsp: " + i.getId() + " calc hash: " + Base64Util.encode(digest1, 0) + " refs-hash: " + Base64Util.encode(digest2, 0)); } if(!sig.getSignedDoc().getFormat().equals("SK-XML") && !compareDigests(digest1, digest2)) { lerrs.add(new DigiDocException(83, "Notarys digest doesn\'t match!", (Throwable)null)); if(m_logger.isDebugEnabled()) { m_logger.debug("Notarys digest doesn\'t match!"); } bOk = false; } if(sig.getSignedDoc().getFormat().equals("BDOC") && orf.getDigestAlgorithm().equals("http://www.w3.org/2000/09/xmldsig#sha1") && ConfigManager.instance().getBooleanProperty("BDOC_SHA1_CHECK", true)) { lerrs.add(new DigiDocException(129, "The current BDoc container uses weaker encryption method than officialy accepted in Estonia. We do not recommend you to add signature to this document. There is an option to re-sign this document in a new container.", (Throwable)null)); if(m_logger.isInfoEnabled()) { m_logger.info("CompleteRevocationRefs for signature: " + sig.getId() + " has weak digest type: " + orf.getDigestAlgorithm()); } } if(m_logger.isDebugEnabled()) { m_logger.debug("Check ocsp: " + i.getId() + " prodAt: " + (i.getProducedAt() != null?ConvertUtils.date2string(i.getProducedAt(), sig.getSignedDoc()):"NULL") + " orf prodAt: " + (orf.getProducedAt() != null?ConvertUtils.date2string(orf.getProducedAt(), sig.getSignedDoc()):"NULL")); } if(i.getProducedAt() != null && orf.getProducedAt() != null && !ConvertUtils.date2string(i.getProducedAt(), sig.getSignedDoc()).equals(ConvertUtils.date2string(orf.getProducedAt(), sig.getSignedDoc()))) { if(m_logger.isDebugEnabled()) { m_logger.debug("Notary: " + i.getId() + " producedAt: " + (i.getProducedAt() != null?ConvertUtils.date2string(i.getProducedAt(), sig.getSignedDoc()):"NULL") + " does not match OcpsRef-s producedAt: " + (orf.getProducedAt() != null?ConvertUtils.date2string(orf.getProducedAt(), sig.getSignedDoc()):"NULL")); } lerrs.add(new DigiDocException(70, "Notary: " + i.getId() + " producedAt: " + (i.getProducedAt() != null?ConvertUtils.date2string(i.getProducedAt(), sig.getSignedDoc()):"NULL") + " does not match OcpsRef-s producedAt: " + (orf.getProducedAt() != null?ConvertUtils.date2string(orf.getProducedAt(), sig.getSignedDoc()):"NULL"), (Throwable)null)); } } } else { lerrs.add(new DigiDocException(83, "OCSP value is empty!", (Throwable)null)); bOk = false; } } } catch (DigiDocException var18) { lerrs.add(var18); bOk = false; } } try { NotaryFactory var22 = ConfigManager.instance().getNotaryFactory(); for(int var23 = 0; var23 < sig.getUnsignedProperties().countNotaries(); ++var23) { Notary var24 = sig.getUnsignedProperties().getNotaryById(var23); if(m_logger.isDebugEnabled()) { m_logger.debug("Verify notary: " + var24.getId() + " ocsp: " + (var24.getOcspResponseData() != null?var24.getOcspResponseData().length:0) + " responder: " + var24.getResponderId()); } var22.parseAndVerifyResponse(sig, var24); } } catch (DigiDocException var17) { lerrs.add(var17); bOk = false; } } else { bOk = false; if(m_logger.isDebugEnabled()) { m_logger.debug("Signature has no OCSP confirmation!"); } lerrs.add(new DigiDocException(90, "Signature has no OCSP confirmation!", (Throwable)null)); } } catch (Exception var19) { if(m_logger.isDebugEnabled()) { m_logger.debug("Failed to verify OCSP for: " + sig.getId()); } lerrs.add(new DigiDocException(82, "Failed to verify OCSP for: " + sig.getId(), (Throwable)null)); bOk = false; } return bOk; } public static boolean verifySignature(SignedDoc sdoc, Signature sig, List lerrs) { boolean bOk = true; boolean b = false; initProvider(); if(m_logger.isDebugEnabled()) { m_logger.debug("Verifying signature: " + sig.getId() + " profile: " + sig.getProfile()); } if(sig.getProfile() != null && (sig.getProfile().equals("T") || sig.getProfile().equals("TS") || sig.getProfile().equals("TS-A"))) { if(m_logger.isDebugEnabled()) { m_logger.debug("T, TS and TSA profiles are currently not supported!"); } lerrs.add(new DigiDocException(81, "T, TS and TSA profiles are currently not supported!", (Throwable)null)); } int i; for(i = 0; i < sdoc.countDataFiles(); ++i) { DataFile ref = sdoc.getDataFile(i); if(m_logger.isDebugEnabled()) { m_logger.debug("Verifying DF: " + ref.getId() + " file: " + ref.getFileName()); } Reference dof = sig.getSignedInfo().getReferenceForDataFile(ref); if(dof != null && dof.getDigestAlgorithm() != null && sdoc.getFormat().equals("BDOC") && dof.getDigestAlgorithm().equals("http://www.w3.org/2000/09/xmldsig#sha1") && ConfigManager.instance().getBooleanProperty("BDOC_SHA1_CHECK", true)) { lerrs.add(new DigiDocException(129, "The current BDoc container uses weaker encryption method than officialy accepted in Estonia. We do not recommend you to add signature to this document. There is an option to re-sign this document in a new container.", (Throwable)null)); if(m_logger.isInfoEnabled()) { m_logger.info("DataFile: " + ref.getId() + " has weak digest type: " + dof.getDigestAlgorithm()); } } if(dof != null) { b = verifyDataFileHash(sdoc, ref, dof, lerrs); } else { b = false; lerrs.add(new DigiDocException(81, "Missing Reference for file: " + ref.getFileName(), (Throwable)null)); } if(!b) { bOk = false; } } for(i = 0; i < sdoc.countSignatures(); ++i) { sdoc.getSignature(i); for(int var15 = 0; var15 < sig.getSignedInfo().countReferences(); ++var15) { Reference ref1 = sig.getSignedInfo().getReference(var15); if(ref1.getType() == null && (!sdoc.getFormat().equals("BDOC") || ref1.getUri().indexOf("META-INF/manifest.xml") == -1) && (!sdoc.getFormat().equals("DIGIDOC-XML") && !sdoc.getFormat().equals("SK-XML") || ref1.getUri().indexOf("-MIME") == -1 && ref1.getUri().indexOf("-SignedProperties") == -1)) { boolean bFound = false; for(int l = 0; l < sdoc.countDataFiles(); ++l) { DataFile df = sdoc.getDataFile(l); String sFile = df.getFileName(); if(sFile != null && sFile.indexOf(47) != -1 || sFile.indexOf(92) != -1) { File fT = new File(sFile); sFile = fT.getName(); } if(ref1.getUri() != null) { if((sdoc.getFormat().equals("DIGIDOC-XML") || sdoc.getFormat().equals("SK-XML")) && ref1.getUri().startsWith("#") && df.getId().equals(ref1.getUri().substring(1))) { bFound = true; } if(sdoc.getFormat().equals("BDOC") && ref1.getUri().indexOf(sFile) != -1) { bFound = true; } } } if(!bFound) { if(m_logger.isInfoEnabled()) { m_logger.info("Missing DataFile for signature: " + sig.getId() + " reference " + ref1.getUri()); } lerrs.add(new DigiDocException(81, "Missing DataFile for signature: " + sig.getId() + " reference " + ref1.getUri(), (Throwable)null)); } } } } if(sdoc.getFormat().equals("BDOC")) { for(i = 0; i < sig.getSignedInfo().countReferences(); ++i) { Reference var14 = sig.getSignedInfo().getReference(i); if(!var14.getUri().startsWith("#")) { DataObjectFormat var16 = sig.getSignedInfo().getDataObjectFormatForReference(var14); if(var16 == null) { if(m_logger.isDebugEnabled()) { m_logger.debug("No DataObjectFormat element for Reference: " + var14.getId()); } lerrs.add(new DigiDocException(30, "No DataObjectFormat element for Reference: " + var14.getId(), (Throwable)null)); } } } } if(!sdoc.getFormat().equals("SK-XML")) { b = verifySignedPropretiesHash(sig, lerrs); } if(!b) { bOk = false; } b = verifySignatureValue(sdoc, sig, lerrs); if(!b) { bOk = false; } b = verifySigningTime(sig, lerrs); if(!b) { bOk = false; } b = verifySignersCerificate(sig, lerrs); if(!b) { bOk = false; } if(sdoc.getFormat().equals("BDOC")) { b = verifySignaturePolicies(sdoc, sig, lerrs); if(!b) { bOk = false; } } if(sdoc.getFormat().equals("SK-XML") || sdoc.getFormat().equals("DIGIDOC-XML") || sig.getProfile() != null && (sig.getProfile().equals("TM") || sig.getProfile().equals("TM-A") || sig.getProfile().equals("TS") || sig.getProfile().equals("TS-A"))) { b = verifySignatureOCSP(sig, lerrs); if(!b) { bOk = false; } } return bOk; } public static boolean verifySignaturePolicies(SignedDoc sdoc, Signature sig, List lerrs) { boolean bOk = false; if(m_logger.isInfoEnabled()) { m_logger.debug("Check signature: " + sig.getId() + " profile: " + sig.getProfile() + " format: " + sdoc.getFormat() + " policies"); } try { if(sig.getSignedProperties() != null && sig.getSignedProperties().getSignaturePolicyIdentifier() != null && sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId() != null && sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId().getSigPolicyId() != null && sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId().getSigPolicyId().getIdentifier() != null) { Identifier ex = sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId().getSigPolicyId().getIdentifier(); if(m_logger.isInfoEnabled()) { m_logger.debug("Signature: " + sig.getId() + " has policy: " + ex.getQualifier() + " uri: " + ex.getUri() + " hash: " + Base64Util.encode(sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId().getDigestValue())); } if(ex.getQualifier().equals(Identifier.OIDAsURN) && ex.getUri().equals("urn:oid:1.3.6.1.4.1.10015.1000.3.2.1")) { bOk = true; if(!compareDigests(sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId().getDigestValue(), Base64Util.decode("3Tl1oILSvOAWomdI9VeWV6IA/32eSXRUri9kPEz1IVs=")) && !compareDigests(sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId().getDigestValue(), Base64Util.decode("Ygw9Ex7wCSrep2Mnju+Ml3pOPZZBmd6vicQkvOQKxyo="))) { if(m_logger.isDebugEnabled()) { m_logger.debug("Signature: " + sig.getId() + " has invalid signature policy hash: " + Base64Util.encode(sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId().getDigestValue())); } lerrs.add(new DigiDocException(171, "Signature: " + sig.getId() + " has invalid signature policy hash: " + Base64Util.encode(sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId().getDigestValue()), (Throwable)null)); } boolean bUriOk = false; for(int i = 0; i < sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId().countSigPolicyQualifiers(); ++i) { SigPolicyQualifier spq = sig.getSignedProperties().getSignaturePolicyIdentifier().getSignaturePolicyId().getSigPolicyQualifier(i); if(spq instanceof SpUri) { SpUri sna = (SpUri)spq; if(sna.getUri() != null && sna.getUri().trim().length() > 0) { bUriOk = true; } } } if(!bUriOk) { bOk = false; if(m_logger.isDebugEnabled()) { m_logger.debug("Signature: " + sig.getId() + " has no signature policy uri!"); } lerrs.add(new DigiDocException(170, "Signature: " + sig.getId() + " has no nonce policy uri!", (Throwable)null)); } } else { if(m_logger.isDebugEnabled()) { m_logger.debug("Signature: " + sig.getId() + " has unknown policy: " + ex.getQualifier() + " uri: " + ex.getUri()); } lerrs.add(new DigiDocException(169, "Signature: " + sig.getId() + " has unknown policy: " + ex.getQualifier() + " uri: " + ex.getUri(), (Throwable)null)); } } else { if(m_logger.isDebugEnabled()) { m_logger.debug("No signature policy for sig: " + sig.getId()); } lerrs.add(new DigiDocException(168, "Signature: " + sig.getId() + " has no policy!", (Throwable)null)); } } catch (Exception var9) { if(m_logger.isDebugEnabled()) { m_logger.debug("Failed to verify sig policies: " + sig.getId() + " - " + var9); } lerrs.add(new DigiDocException(168, "Failed to verify sig policies: " + sig.getId() + " - " + var9, (Throwable)null)); bOk = false; } return bOk; } private static List findRdns(String dn, char chSep) { ArrayList lrdn = new ArrayList(); StringBuffer sbId = new StringBuffer(); StringBuffer sbVal = new StringBuffer(); boolean bId = true; for(int i = 0; dn != null && i < dn.length(); ++i) { char ch = dn.charAt(i); if((ch != chSep || i != 0 && dn.charAt(i - 1) == 92) && i != dn.length() - 1) { if(ch != 61 || i != 0 && dn.charAt(i - 1) == 92) { if(bId) { sbId.append(ch); } else { sbVal.append(ch); } } else { bId = false; } } else { if(i == dn.length() - 1 && !bId) { sbVal.append(ch); } if(sbId.length() > 0 && sbVal.length() > 0) { lrdn.add(new Rdn(sbId.toString(), (String)null, sbVal.toString())); } sbId = new StringBuffer(); sbVal = new StringBuffer(); bId = true; } } return lrdn; } public static List parseDN(String dn) { List al = findRdns(dn, ','); if(al.size() < 3) { al = findRdns(dn, '/'); } return al; } }