Bom galera, eu preciso assinar alguns arquivos .xml com assinatura digital através de certificados digitais (Arquivo, Token, SmartCard) consegui montar a seguinte classe:
public void assinarXML(String arquivoXML) {
String tokenCaminho;
String tokenNomeAmigavel;
String tokenSenha;try { //CERTIFICADO DIGITAL EM ARQUIVO tokenCaminho = "caminhoDoCertificado\\CertificadoDigital.pfx"; tokenNomeAmigavel = "NomeAmigavelDoCertificado"; tokenSenha = "senhaDoCertificado"; //CERTIFICADO DIGITAL EM SMARTCARD //tokenCaminho = ""; //tokenNomeAmigavel = ""; //tokenSenha = ""; //CORRIGI BUG DO TRANSFORM System.setProperty("javax.xml.transform.TransformerFactory", "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
//Create a DOM XMLSignatureFactory that will be used to generate the //enveloped signature. XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
//Create a Reference to the enveloped document (in this case, you //are signing the whole document, so a URI of "" signifies that, //and also specify the SHA1 digest algorithm and the ENVELOPED Transform. Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null, null);
//Create the SignedInfo. SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref));
// Load the KeyStore and get the signing key and certificate. KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream(tokenCaminho), tokenSenha.toCharArray()); KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(tokenNomeAmigavel, new KeyStore.PasswordProtection(tokenSenha.toCharArray())); X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
// Create the KeyInfo containing the X509Data. KeyInfoFactory kif = fac.getKeyInfoFactory(); List x509Content = new ArrayList(); x509Content.add(cert.getSubjectX500Principal().getName()); x509Content.add(cert); X509Data xd = kif.newX509Data(x509Content); KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
// Instantiate the document to be signed. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder().parse(new FileInputStream(arquivoXML));
// Create a DOMSignContext and specify the RSA PrivateKey and // location of the resulting XMLSignature's parent element. DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getDocumentElement());
// Create the XMLSignature, but don't sign it yet. XMLSignature signature = fac.newXMLSignature(si, ki);
// Marshal, generate, and sign the enveloped signature. signature.sign(dsc);
// Output the resulting document. OutputStream os = new FileOutputStream(arquivoXML); TransformerFactory tf = TransformerFactory.newInstance(); Transformer trans = tf.newTransformer(); trans.transform(new DOMSource(doc), new StreamResult(os)); } catch (NoSuchAlgorithmException | ParserConfigurationException | SAXException | KeyStoreException | CertificateException | UnrecoverableEntryException | InvalidAlgorithmParameterException | MarshalException | XMLSignatureException | TransformerConfigurationException e) { Logger.getLogger(MenuFiscal.class.getName()).log(Level.SEVERE, null, e); } catch (FileNotFoundException ex) { Logger.getLogger(MenuFiscal.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException | TransformerException ex) { Logger.getLogger(MenuFiscal.class.getName()).log(Level.SEVERE, null, ex); } }
Para certificados do tipo arquivo (.pfx e .p12) ele está funcionando perfeitamente, porém não consigo efetuar a assinatura usando um SmartCard, estou tentando alterar o código para efetuar ambas validações mas não obtive sucesso, toda ajuda é valida já revirei a internet. Agradeço desde já.