Consegui terminar os métodos que eu queria. Fiz dois métodos que recebem uma string com o xml e retornam uma String como o xml assinado. O primeiro pega um enviNFe e assina todas as NFe dentro dele. O outro assina o elemento raíz do xml, servindo para o cancelamento e para a inutilização da nota.
aqui vai o método para assinar o enviNFe:
public static String assinarEnviNFe(String xml) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
// Document docs = builder.parse(new File(
// "c:/xml/430802017886010001735500000000010000030371-nfe.xml"));
Document doc = factory.newDocumentBuilder().parse(
new ByteArrayInputStream(xml.getBytes()));
// 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.
ArrayList transformList = new ArrayList();
TransformParameterSpec tps = null;
Transform envelopedTransform = fac.newTransform(Transform.ENVELOPED,
tps);
Transform c14NTransform = fac.newTransform(
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315", tps);
transformList.add(envelopedTransform);
transformList.add(c14NTransform);
// Load the KeyStore and get the signing key and certificate.
String configName = "/token.cfg";
Provider p = new sun.security.pkcs11.SunPKCS11(configName);
Security.addProvider(p);
char[] pin = { 's', 'a', 'f', 'e', 'w', 'e', 'b' };
KeyStore ks = KeyStore.getInstance("pkcs11", p);
ks.load(null, pin);
KeyStore.PrivateKeyEntry pkEntry = null;
Enumeration aliasesEnum = ks.aliases();
PrivateKey privateKey = null;
while (aliasesEnum.hasMoreElements()) {
String alias = (String) aliasesEnum.nextElement();
System.out.println(alias);
if (ks.isKeyEntry(alias)) {
pkEntry = (KeyStore.PrivateKeyEntry) ks
.getEntry(alias, new KeyStore.PasswordProtection(
"safeweb".toCharArray()));
privateKey = pkEntry.getPrivateKey();
break;
}
}
X509Certificate cert = (X509Certificate) pkEntry.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));
for (int i = 0; i < doc.getDocumentElement()
.getElementsByTagName("NFe").getLength(); i++) {
assinarNFE(fac, transformList, privateKey, ki, doc, i);
}
// Output the resulting document.
ByteArrayOutputStream os = new ByteArrayOutputStream();
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(os));
return os.toString();
}
private static void assinarNFE(XMLSignatureFactory fac,
ArrayList transformList, PrivateKey privateKey, KeyInfo ki,
Document doc, int i) throws Exception {
// Obtem elemento do documento a ser assinado, será criado uma
// REFERENCE para o mesmo
NodeList elements = doc.getElementsByTagName("infNFe");
Element el = (Element) elements.item(i);
String id = el.getAttribute("Id");
// doc.getDocumentElement().removeAttribute("xmlns:ns2");
// ((Element)
// doc.getDocumentElement().getElementsByTagName("NFe").item(0))
// .setAttribute("xmlns", "http://www.portalfiscal.inf.br/nfe");
// Create a DOM XMLSignatureFactory that will be used to
// generate the enveloped signature.
Reference ref = fac.newReference("#" + id, fac.newDigestMethod(
DigestMethod.SHA1, null), transformList, null, null);
// Create the SignedInfo.
SignedInfo si = fac
.newSignedInfo(fac.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null), fac
.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
// Create the XMLSignature, but don't sign it yet.
XMLSignature signature = fac.newXMLSignature(si, ki);
// Marshal, generate, and sign the enveloped signature.
// Create a DOMSignContext and specify the RSA PrivateKey and
// location of the resulting XMLSignature's parent element.
DOMSignContext dsc = new DOMSignContext(privateKey, doc
.getDocumentElement().getElementsByTagName("NFe").item(i));
signature.sign(dsc);
}
este aqui assina o elemento raiz do xml:
public static String assinarRaiz(String xml) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
// Document docs = builder.parse(new File(
// "c:/xml/430802017886010001735500000000010000030371-nfe.xml"));
Document doc = factory.newDocumentBuilder().parse(
new ByteArrayInputStream(xml.getBytes()));
doc.getDocumentElement().removeAttribute("xmlns:ns2");
// NodeList elements = doc.getElementsByTagName("infNFe");
Node element = doc.getDocumentElement().getFirstChild()
.getNextSibling();
// elements.getLength();
Element el = (Element) element;
// Element el =
// doc.getDocumentElement().getFirstChild().getChildNodes();
String id = el.getAttribute("Id");
// 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.
ArrayList transformList = new ArrayList();
TransformParameterSpec tps = null;
Transform envelopedTransform = fac.newTransform(Transform.ENVELOPED,
tps);
Transform c14NTransform = fac.newTransform(
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315", tps);
transformList.add(envelopedTransform);
transformList.add(c14NTransform);
// Load the KeyStore and get the signing key and certificate.
String configName = "/token.cfg";
Provider p = new sun.security.pkcs11.SunPKCS11(configName);
Security.addProvider(p);
char[] pin = { 's', 'a', 'f', 'e', 'w', 'e', 'b' };
KeyStore ks = KeyStore.getInstance("pkcs11", p);
ks.load(null, pin);
KeyStore.PrivateKeyEntry pkEntry = null;
Enumeration aliasesEnum = ks.aliases();
PrivateKey privateKey = null;
while (aliasesEnum.hasMoreElements()) {
String alias = (String) aliasesEnum.nextElement();
System.out.println(alias);
if (ks.isKeyEntry(alias)) {
pkEntry = (KeyStore.PrivateKeyEntry) ks
.getEntry(alias, new KeyStore.PasswordProtection(
"safeweb".toCharArray()));
privateKey = pkEntry.getPrivateKey();
break;
}
}
X509Certificate cert = (X509Certificate) pkEntry.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));
// doc.getDocumentElement().removeAttribute("xmlns:ns2");
// ((Element)
// doc.getDocumentElement().getElementsByTagName("NFe").item(0))
// .setAttribute("xmlns", "http://www.portalfiscal.inf.br/nfe");
// Create a DOM XMLSignatureFactory that will be used to
// generate the enveloped signature.
Reference ref = fac.newReference("#" + id, fac.newDigestMethod(
DigestMethod.SHA1, null), transformList, null, null);
// Create the SignedInfo.
SignedInfo si = fac
.newSignedInfo(fac.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null), fac
.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
// Create the XMLSignature, but don't sign it yet.
XMLSignature signature = fac.newXMLSignature(si, ki);
// Marshal, generate, and sign the enveloped signature.
// Create a DOMSignContext and specify the RSA PrivateKey and
// location of the resulting XMLSignature's parent element.
DOMSignContext dsc = new DOMSignContext(privateKey, doc
.getDocumentElement());
signature.sign(dsc);
// Output the resulting document.
ByteArrayOutputStream os = new ByteArrayOutputStream();
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(os));
return os.toString();
}
uma coisa que temque cuidar muito é o cabeçalho do xml que temque tá desse jeito
<?xml version="1.0" encoding="UTF-8"?>
<cancNFe versao="1.07" xmlns="http://www.portalfiscal.inf.br/nfe">
ou seja, não pode ter o xmlns:ns2=“http://www.w3.org/2000/09/xmldsig#”
o mesmo vale para o enviNFe:
<enviNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.10">
<idLote>1</idLote>
<NFe xmlns="http://www.portalfiscal.inf.br/nfe">
nesse caso tanto o envi como cada nfe devem ter xmlns=“http://www.portalfiscal.inf.br/nfe” e o envi não pode ter o xmlns:ns2=“http://www.w3.org/2000/09/xmldsig#”. Se por acaso o xml estiver do jeito errado, pode usar esses códigos no assinador, ou criar outro método:
esse aqui remove o xmlns:ns2 do elemento raíz:
doc.getDocumentElement().removeAttribute("xmlns:ns2");
esse aqui adiciona o xmlns necessário a tag NFe:
((Element) doc.getDocumentElement().getElementsByTagName("NFe").item(i)).setAttribute("xmlns", "http://www.portalfiscal.inf.br/nfe");
Quem quiser verificar o xml pode usar esse site: http://www.sefaz.rs.gov.br/AAE_ROOT/NFE/SAT-WEB-NFE-VAL_1.asp Acho que ele só valida os certificados do Rio Grande do Sul, mas o bom é que ele verifica a estrutura do xml tb.
É isso por enquanto, qualquer coisa é só perguntar.