Validar arquivo assinado digitalmente

Pessoal, estou passando por um problema. Eu estou assinando um pdf usando um smartcard do Serasa. A assinatura em sí parece correta, só que para teste eu assinei um arquivo, alterei seu conteúdo(utilizando o software eXPert PDF Editor) e o método verifyCertificate() diz que o documento não foi alterado. Já achei alguns códigos na net e estão iguais ou parecidos com o meu. Alguém sabe como eu posso verificar se o documento foi alterado ou não? Detalhe, se eu abro esse arquivo que assinei(alterado) no Adobe Reader o mesmo diz que a assinatura é inválida(mensagem:Pelo menos uma assinatura é inválida).

[code]public static void signFile(String filenameforsign, String reason,
String location, String contact, PrivateKey key, Certificate[] chain) {
try {
PdfReader reader = new PdfReader(filenameforsign);

		FileOutputStream fout = new FileOutputStream(filenameforsign.substring(0,
				filenameforsign.lastIndexOf(".")) + "_assinado.pdf");
		PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0', null, true );
		PdfSignatureAppearance sap = stp.getSignatureAppearance();
		sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
		//sap.setReason("Outro autor");
		//sap.setLocation("Teste");
		sap.setVisibleSignature(new Rectangle(reader.getPageSize(1).getWidth()-80, reader.getPageSize(1).getHeight()-80, 
				reader.getPageSize(1).getWidth()-10, reader.getPageSize(1).getHeight()-10), 1, null);
		
		//sap.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
		/*sap.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_FORM_FILLING);
		
		PdfFormField sign2 = PdfFormField.createSignature(
		stp.getWriter());
        sign2.setWidget(new Rectangle(200, 600, 300, 640), null);
        //sign2.setFlags(PdfAnnotation.);
        sign2.setFieldName("sign2");
        sign2.setPage(1);
        stp.addAnnotation(sign2, 1);*/
                    
		
		stp.close();
	} catch (IOException ex) {
		ex.printStackTrace();
	} catch (DocumentException e) {
		e.printStackTrace();
	}
}

public void processSign( File file ) {
PrivateKey key = null;
java.security.cert.Certificate[] chain = null;
//carrega o certificado do smartcard
try {
byte[] pkcs11configBytes = pkcs11config.getBytes();
ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11configBytes);
Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream);

		Security.addProvider(pkcs11Provider);
		KeyStore ks = null;
		if ("".equals(this.keystoreType)) 
			ks = KeyStore.getInstance(KeyStore.getDefaultType());
		else 
			ks = KeyStore.getInstance(this.keystoreType);

		
		ks.load(null, this.getPin().toCharArray());
		String alias = (String)ks.aliases().nextElement();
		key = (PrivateKey)ks.getKey(alias,this.getPin().toCharArray()); 
		chain = ks.getCertificateChain(alias); 			
		
		X509Certificate certif = (X509Certificate)ks.getCertificate(alias);    
		System.out.println( "SN =     " + certif.getSerialNumber().toString(16) );    
		System.out.println( "Issuer = " + certif.getIssuerDN().toString() );    
		System.out.println( "subject= " + certif.getSubjectDN().toString() );
		
		// Assina um documento para teste
		signFile(file, key, chain);
		
	} catch (KeyStoreException e) { 
		e.printStackTrace(); 
	} catch (NoSuchAlgorithmException e) { 
		e.printStackTrace();
	} catch (CertificateException e) {
		e.printStackTrace();
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) { 
		e.printStackTrace(); 
	} catch (UnrecoverableKeyException e) { 
		e.printStackTrace();
	}
}

public void verifyCertificate() throws Exception {
//KeyStore kall = PdfPKCS7.loadCacertsKeyStore();
KeyStore kall = KeyStore.getInstance(KeyStore.getDefaultType());

// CertificateFactory cf = CertificateFactory.getInstance(“X509”);
// Collection col = cf.generateCertificates(new FileInputStream(“self.p7b”));
// KeyStore kall = KeyStore.getInstance(KeyStore.getDefaultType());
// kall.load(null, null);
// for (Iterator it = col.iterator(); it.hasNext():wink: {
// X509Certificate cert = (X509Certificate)it.next();
// kall.setCertificateEntry(cert.getSerialNumber().toString(Character.MAX_RADIX), cert);
// }

	PdfReader reader = new PdfReader(pdfFileSigned);
	
	/*PrintWriter out = new PrintWriter(new FileOutputStream(VERIFICATION));
    PdfReader reader = new PdfReader(SIGNED2);*/
    AcroFields af = reader.getAcroFields();
    ArrayList<String> names = af.getSignatureNames();
    for (String name : names) {
    	System.out.println("Signature name: " + name);
    	System.out.println("Signature covers whole document: " + af.signatureCoversWholeDocument(name));
    	System.out.println("Document revision: " + af.getRevision(name) + " of " + af.getTotalRevisions());
        PdfPKCS7 pk = af.verifySignature(name);
        Calendar cal = pk.getSignDate();
        Certificate[] pkc = pk.getCertificates();
        System.out.println("Subject: " + PdfPKCS7.getSubjectFields(pk.getSigningCertificate()));
        System.out.println("Revision modified: " + !pk.verify());
        Object fails[] = PdfPKCS7.verifyCertificates(pkc, kall, null, cal);
        if (fails == null)
        	System.out.println("Certificates verified against the KeyStore");
        else
        	System.out.println("Certificate failed: " + fails[1]);    
    }		
	/*AcroFields af = reader.getAcroFields();		
	ArrayList names = af.getSignatureNames();
	for (int k = 0; k < names.size(); ++k) {
	   String name = (String)names.get(k);
	   System.out.println("Signature name: " + name);
	   System.out.println("Signature covers whole document: " + af.signatureCoversWholeDocument(name));
	   System.out.println("Document revision: " + af.getRevision(name) + " of " + af.getTotalRevisions());
	   // Start revision extraction
	   FileOutputStream out = new FileOutputStream("revision_" + af.getRevision(name) + ".pdf");
	   byte bb[] = new byte[8192];
	   InputStream ip = af.extractRevision(name);
	   int n = 0;
	   while ((n = ip.read(bb)) > 0)
	      out.write(bb, 0, n);
	   out.close();
	   ip.close();
	   // End revision extraction
	   PdfPKCS7 pk = af.verifySignature(name);
	   Calendar cal = pk.getSignDate();
	   Certificate pkc[] = pk.getCertificates();
	   System.out.println("Subject: " + PdfPKCS7.getSubjectFields(pk.getSigningCertificate()));
	   System.out.println("Document modified: " + !pk.verify());
	   Object fails[] = PdfPKCS7.verifyCertificates(pkc, kall, null, cal);
	   if (fails == null)
	       System.out.println("Certificates verified against the KeyStore");
	   else
	       System.out.println("Certificate failed: " + fails[1]);
	}*/
}[/code]

Agradeço a ajuda!

Galera, eu vi alguns aplicativos que simplesmente assinavam mais não validavam se um arquivo fora alterado ou não. Deixavam isso para o Adobe Reader.
Alguém teve de implementar a verificação? Sabem se o código que postei já seria o suficiente (digo suficiente porque ao meu ver deveria funcionar)ou eu teria de fazer essa verificação mesmo? Pegando o Hash encriptado com a chave privada e comparando com o Hash do arquivo recebido?
Valeu

Olá, estou passando pelo mesmo problema !!!
Alguem tem alguma solução ???

Opa. Fala ae galera!
Vocês fizeram a implementação da validação da assinatura visual via código? Ou deixaram via Adobe mesmo?

Pelo código postado estão apenas verificando os certificados, que independente de o documento mudar ou não continuarão válidos a não ser que sejam revogados
PdfPKCS7.verifyCertificates(pkc, kall, null, cal);
o que deve ser verificado é a assinatura (ou seja o hash)
pk.verify();
faz isso, se alguma alteração for feita no documento depois da assinatura
pk.verify();
irá retorna false

Valeu, a resposta do tsblackboy me ajudou bastante…

Agora tenho uma dúvida, preciso gravar a HASH dessa assinatura, como posso dar um get na Hash gerada?

Em um PDF assinado temos uma assinatura digital empacotada no campo dicionario do PDF, o código apresentado desempacota essas assinaturas e disponibiliza em um PdfPKCS7 (PKCS7 é um empacotamento utilizado pela assinatura digital definido na rfc5652). a classe PdfPKCS7 permite extrair algumas informações, mas outras não são disponibilizadas, neste caso o jeito é descer o nível e pegar os bytes do pacote PKCS7 retornado pelo método getEncodedPKCS7() e utilizar o BouncyCastle (ou outra API) para recuperar as outras informações.

A RFC diz o seguinte do pacote PKCS7, para dados assinados :

SignedData ::= SEQUENCE {
version CMSVersion,
digestAlgorithms DigestAlgorithmIdentifiers,
encapContentInfo EncapsulatedContentInfo,
certificates [0] IMPLICIT CertificateSet OPTIONAL,
crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
signerInfos SignerInfos }

DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier

SignerInfos ::= SET OF SignerInfo

SignerInfo ::= SEQUENCE {
version CMSVersion,
sid SignerIdentifier,
digestAlgorithm DigestAlgorithmIdentifier,
signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
signatureAlgorithm SignatureAlgorithmIdentifier,
signature SignatureValue,
unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL }

Se desejas recuperar a assinatura = hash criptografado, deves recuperar o SignerInfo do pacote PKCS7 e depois recuperar o SignatureValue.

No BouncyCastle procura pela classe SignedData, elas te darão acesso ao SignerInfo através do método getSignerInfos(), depois é só passar o retorno para classe SignerInfo e usar os métodos dela para recuperar as demais informações (getEncryptedDigest() de SignerInfo deve retornar o hash assinado).

Boa tarde pessoal,

Desculpe a pergunta, que pra vocês deve ser muito fácil, mas como sou extremamente novo no java preciso da ajuda de vocês para resolvero o seguinte problema:
Tenho um arquivo PDF assinado com um certificado digital e preciso obter as informações deste certificado, nome do proprietario, data da assinatura essas coisa, alguem pode me ajudar por favor.