/* * Copyright 2006-2017 ICEsoft Technologies Canada Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.icepdf.core.pobjects.acroform.signature; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.jce.provider.X509CertParser; import org.icepdf.core.pobjects.StringObject; import org.icepdf.core.pobjects.acroform.SignatureDictionary; import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; import org.icepdf.core.util.Utils; import javax.crypto.Cipher; import java.io.ByteArrayInputStream; import java.security.cert.X509Certificate; /** * "adbe.x509.rsa_sha1" * In this case, the Contents key contains a DER-encoded PKCS#1 [11] * binary data object representing the signature obtained as the RSA * encryption of the byte range SHA-1 digest with the signer's * private key. When using PKCS#1, the certificate chain of the * signer is included with other signature information in the signed * document. */ public class Pkcs1Validator extends AbstractPkcsValidator { public Pkcs1Validator(SignatureFieldDictionary signatureFieldDictionary) throws SignatureIntegrityException { super(signatureFieldDictionary); } public void init() throws SignatureIntegrityException { SignatureDictionary signatureDictionary = signatureFieldDictionary.getSignatureDictionary(); announceSignatureType(signatureDictionary); // start the decode of the raw type. StringObject stringObject = signatureDictionary.getContents(); // make sure we don't loose any bytes converting the string in the raw. byte[] cmsData = Utils.convertByteCharSequenceToByteArray(stringObject.getLiteralString()); // get the certificate stringObject = signatureDictionary.getCertString(); // make sure we don't loose any bytes converting the string in the raw. byte[] certsKey = Utils.convertByteCharSequenceToByteArray(stringObject.getLiteralString()); try { X509CertParser x509CertParser = new X509CertParser(); x509CertParser.engineInit(new ByteArrayInputStream(certsKey)); certificateChain = x509CertParser.engineReadAll(); signerCertificate = (X509Certificate) certificateChain.iterator().next(); // content data is encrypted using the cert above. ASN1InputStream asn1InputStream = new ASN1InputStream(new ByteArrayInputStream(cmsData)); ASN1Primitive tmp = asn1InputStream.readObject(); messageDigest = ((ASN1OctetString) tmp).getOctets(); String provider = signatureDictionary.getFilter().getName(); digestAlgorithmIdentifier = OIWObjectIdentifiers.idSHA1.getId(); signatureAlgorithmIdentifier = PKCSObjectIdentifiers.rsaEncryption.getId(); // basic creation and public key check which should throw any format errors. createSignature(signerCertificate.getPublicKey(), provider, signatureAlgorithmIdentifier, digestAlgorithmIdentifier); // Use RSA/ECB/NoPadding do decrypt the message digest Cipher asymmetricCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // initialize your cipher asymmetricCipher.init(Cipher.DECRYPT_MODE, signerCertificate.getPublicKey()); // assuming, cipherText is a byte array containing your encrypted message messageDigest = asymmetricCipher.doFinal(messageDigest); // trim the padding bytes if (messageDigest.length > 20) { // You can create the ASN.1 BER encoding of an MD5, SHA-1, or SHA-256 value by prepending these strings to // the 16-byte or 20-byte hash values, respectively: // We always assume sha1 which is: // ref: sha1 : X'30213009 06052B0E 03021A05 000414' // ref: SHA-256: X'3031300D 06096086 48016503 04020105 000420' // ref: MD5: X'3020300C 06082A86 4886F70D 02050500 0410' byte[] trunkedMD = new byte[20]; System.arraycopy(messageDigest, 15, trunkedMD, 0, 20); messageDigest = trunkedMD; } } catch (Exception e) { throw new SignatureIntegrityException(e); } initialized = true; } @Override public void validate() throws SignatureIntegrityException { validateDocument(); } }