Validar arquivo assinado digitalmente

7 respostas
J

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).

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();) {
//		    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]);
		}*/
	}

Agradeço a ajuda!

7 Respostas

J

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

A

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

A

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

T
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
T

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?

T

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).

P

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.

Criado 14 de outubro de 2010
Ultima resposta 31 de out. de 2022
Respostas 7
Participantes 6