• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wmixvideo / nfe / #7323

07 Nov 2025 12:20PM UTC coverage: 52.488% (-0.1%) from 52.617%
#7323

push

web-flow
Merge 372a05676 into f1539e1c0

272 of 387 new or added lines in 14 files covered. (70.28%)

1 existing line in 1 file now uncovered.

14639 of 27890 relevant lines covered (52.49%)

0.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/java/com/fincatto/documentofiscal/utils/DFAssinaturaDigital.java
1
package com.fincatto.documentofiscal.utils;
2

3
import com.fincatto.documentofiscal.DFConfig;
4
import com.fincatto.documentofiscal.DFLog;
5
import org.apache.commons.lang3.StringUtils;
6
import org.apache.commons.lang3.Strings;
7
import org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI;
8
import org.w3c.dom.Document;
9
import org.w3c.dom.Element;
10
import org.w3c.dom.NodeList;
11
import org.xml.sax.InputSource;
12

13
import javax.naming.ldap.LdapName;
14
import javax.xml.crypto.*;
15
import javax.xml.crypto.dsig.*;
16
import javax.xml.crypto.dsig.dom.DOMSignContext;
17
import javax.xml.crypto.dsig.dom.DOMValidateContext;
18
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
19
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
20
import javax.xml.crypto.dsig.keyinfo.X509Data;
21
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
22
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
23
import javax.xml.parsers.DocumentBuilderFactory;
24
import javax.xml.transform.OutputKeys;
25
import javax.xml.transform.Transformer;
26
import javax.xml.transform.TransformerFactory;
27
import javax.xml.transform.dom.DOMSource;
28
import javax.xml.transform.stream.StreamResult;
29
import java.io.*;
30
import java.security.*;
31
import java.security.cert.X509Certificate;
32
import java.util.*;
33

34
public class DFAssinaturaDigital implements DFLog {
35

36
    private static final String C14N_TRANSFORM_METHOD = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
37
    private static final String[] ELEMENTOS_ASSINAVEIS = new String[]{"infEvento", "infCanc", "infNFe", "infInut", "infMDFe", "infCte"};
×
38
    private final DFConfig config;
39

40
    public DFAssinaturaDigital(final DFConfig config) {
×
41
        this.config = config;
×
42
    }
×
43

44
    public static boolean isValida(final InputStream xmlStream) throws Exception {
45
        final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
×
46
        dbf.setNamespaceAware(true);
×
47

48
        final Document document = dbf.newDocumentBuilder().parse(xmlStream);
×
49
        final NodeList nodeList = document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
×
50
        if (nodeList.getLength() == 0) {
×
51
            throw new IllegalStateException("Nao foi encontrada a assinatura do XML.");
×
52
        }
53

54
        final DOMValidateContext validateContext = new DOMValidateContext(new DFKeySelector(), nodeList.item(0));
×
55
        for (final String tag : DFAssinaturaDigital.ELEMENTOS_ASSINAVEIS) {
×
56
            final NodeList elements = document.getElementsByTagName(tag);
×
57
            if (elements.getLength() > 0) {
×
58
                validateContext.setIdAttributeNS((Element) elements.item(0), null, "Id");
×
59
            }
60
        }
61

62
//        final String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
63
//        final XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).getDeclaredConstructor().newInstance());
64

65
        final XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance("DOM", new XMLDSigRI());
×
66
        return signatureFactory.unmarshalXMLSignature(validateContext).validate(validateContext);
×
67
    }
68

69
    public String assinarDocumento(final String conteudoXml) throws Exception {
70
        return this.assinarDocumento(conteudoXml, DFAssinaturaDigital.ELEMENTOS_ASSINAVEIS);
×
71
    }
72

73
    public String assinarDocumento(final String conteudoXml, final String... elementosAssinaveis) throws Exception {
74
        try (StringReader reader = new StringReader(conteudoXml)) {
×
75
            try (StringWriter writer = new StringWriter()) {
×
76
                this.assinarDocumento(reader, writer, elementosAssinaveis);
×
77
                return writer.toString();
×
78
            }
79
        }
80
    }
81

82
    public void assinarDocumento(final Reader xmlReader, final Writer xmlAssinado, final String... elementosAssinaveis) throws Exception {
83
        final KeyStore.PrivateKeyEntry keyEntry = getPrivateKeyEntry();
×
84

85
        final String dn = ((X509Certificate) keyEntry.getCertificate()).getSubjectX500Principal().getName();
×
86
        this.getLogger().debug("DN: {}", dn);
×
87

88
        final String cn = new LdapName(dn).getRdns().stream()
×
NEW
89
                .filter(rdn -> Strings.CI.equals(rdn.getType(), "CN"))
×
90
                .map(val -> String.valueOf(val.getValue()))
×
91
                .findFirst()
×
92
                .orElse("");
×
93
        this.getLogger().debug("CN: {}", cn);
×
94

95

96
        final XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance("DOM");
×
97
        final List<Transform> transforms = new ArrayList<>(2);
×
98
        transforms.add(signatureFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null));
×
99
        transforms.add(signatureFactory.newTransform(DFAssinaturaDigital.C14N_TRANSFORM_METHOD, (TransformParameterSpec) null));
×
100

101
        final KeyInfoFactory keyInfoFactory = signatureFactory.getKeyInfoFactory();
×
102
        final X509Data x509Data = keyInfoFactory.newX509Data(Collections.singletonList((X509Certificate) keyEntry.getCertificate()));
×
103
        final KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(x509Data));
×
104
        final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
×
105
        documentBuilderFactory.setNamespaceAware(true);
×
106

107
        final Document document = documentBuilderFactory.newDocumentBuilder().parse(new InputSource(xmlReader));
×
108
        for (final String elementoAssinavel : elementosAssinaveis) {
×
109
            final NodeList elements = document.getElementsByTagName(elementoAssinavel);
×
110
            for (int i = 0; i < elements.getLength(); i++) {
×
111
                final Element element = (Element) elements.item(i);
×
112
                final String id = element.getAttribute("Id");
×
113
                element.setIdAttribute("Id", true);
×
114

115
                final Reference reference = signatureFactory.newReference("#" + id, signatureFactory.newDigestMethod(DigestMethod.SHA1, null), transforms, null, null);
×
116
                final SignedInfo signedInfo = signatureFactory.newSignedInfo(signatureFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), signatureFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(reference));
×
117
                final XMLSignature signature = signatureFactory.newXMLSignature(signedInfo, keyInfo);
×
118
                signature.sign(new DOMSignContext(keyEntry.getPrivateKey(), element.getParentNode()));
×
119
            }
120
        }
121

122
        final Transformer transformer = TransformerFactory.newInstance().newTransformer();
×
123
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
×
124
        transformer.transform(new DOMSource(document), new StreamResult(xmlAssinado));
×
125
    }
×
126

127
    private KeyStore.PrivateKeyEntry getPrivateKeyEntry() throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException {
128
        final KeyStore.PasswordProtection passwordProtection = new KeyStore.PasswordProtection(this.config.getCertificadoSenha().toCharArray());
×
129
        if (StringUtils.isNotBlank(config.getCertificadoAlias())) {
×
130
            this.getLogger().debug("Usando alias informado: '{}'", config.getCertificadoAlias());
×
131
            return (KeyStore.PrivateKeyEntry) config.getCertificadoKeyStore().getEntry(config.getCertificadoAlias(), passwordProtection);
×
132
        } else {
133
            final KeyStore ks = config.getCertificadoKeyStore();
×
134
            for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) {
×
135
                final String alias = e.nextElement();
×
136
                if (ks.isKeyEntry(alias)) {
×
137
                    this.getLogger().debug("Usando alias descoberto: '{}'", alias);
×
138
                    return (KeyStore.PrivateKeyEntry) ks.getEntry(alias, passwordProtection);
×
139
                }
140
            }
×
141
            throw new KeyStoreException("N\u00E3o foi poss\u00EDvel encontrar a chave privada do certificado!");
×
142
        }
143
    }
144

145
    public String assinarString(final String string) throws Exception {
146
        final byte[] buffer = string.getBytes();
×
147
        final Signature signatureProvider = Signature.getInstance("SHA1withRSA");
×
148
        signatureProvider.initSign(getPrivateKeyEntry().getPrivateKey());
×
149
        signatureProvider.update(buffer, 0, buffer.length);
×
150
        return Base64.getEncoder().encodeToString(signatureProvider.sign());
×
151
    }
152

153
    static class DFKeySelector extends KeySelector {
×
154
        @Override
155
        public KeySelectorResult select(final KeyInfo keyInfo, final KeySelector.Purpose purpose, final AlgorithmMethod method, final XMLCryptoContext context) throws KeySelectorException {
156
            for (final Object object : keyInfo.getContent()) {
×
157
                final XMLStructure info = (XMLStructure) object;
×
158
                if (info instanceof X509Data) {
×
159
                    final X509Data x509Data = (X509Data) info;
×
160
                    for (final Object certificado : x509Data.getContent()) {
×
161
                        if (certificado instanceof X509Certificate) {
×
162
                            final X509Certificate x509Certificate = (X509Certificate) certificado;
×
163
                            if (this.algEquals(method.getAlgorithm(), x509Certificate.getPublicKey().getAlgorithm())) {
×
164
                                return x509Certificate::getPublicKey;
×
165
                            }
166
                        }
167
                    }
×
168
                }
169
            }
×
170
            throw new KeySelectorException("Nao foi localizada a chave do certificado.");
×
171
        }
172

173
        private boolean algEquals(final String algURI, final String algName) {
174
            return ((algName.equalsIgnoreCase("DSA") && algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) || (algName.equalsIgnoreCase("RSA") && algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)));
×
175
        }
176
    }
177
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc