Creating and Validating Java Digital Signature

Asked

Viewed 7,861 times

15

I’m trying to sign a test NFE with a self-signed digital certificate through the code below. The code at first works, the signature is generated in the file and the validation done through the Keystore works, but when I use another code to validate the signature by the signature key itself it does not validate. If it’s a problem with the signed-up certificate, could you tell me how to generate a test that works without having to buy.

String C14N_TRANSFORM_METHOD = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
String PROVIDER_CLASS_NAME = "org.jcp.xml.dsig.internal.dom.XMLDSigRI";
String PROVIDER_NAME = "jsr105Provider";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

    factory.setNamespaceAware(false);

    try {
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse( new File("nota.xml") );
        NodeList elements = doc.getElementsByTagName( "infNFe" );
        Element el = (Element) elements.item(0);
        String idNota = el.getAttribute("Id");
        el.setIdAttribute("Id", true);


        System.out.println("ID: "+idNota);

        String providerName = System.getProperty( PROVIDER_NAME , PROVIDER_CLASS_NAME );

        XMLSignatureFactory factorySignature = XMLSignatureFactory.getInstance("DOM" , (Provider) Class.forName(providerName).newInstance()  );

        ArrayList transformList = new ArrayList();
        TransformParameterSpec  transParamSpec  = null;

        Transform envelopedTransform = factorySignature.newTransform(Transform.ENVELOPED, transParamSpec );
        Transform c14NTransform = factorySignature.newTransform(C14N_TRANSFORM_METHOD, transParamSpec );

        transformList.add( envelopedTransform );
        transformList.add( c14NTransform );

        Reference ref = factorySignature.newReference("#"+idNota ,  factorySignature.newDigestMethod(DigestMethod.SHA1, null) , transformList , null , null );

        SignedInfo signedInfo = factorySignature.newSignedInfo( factorySignature.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null),
                                                                factorySignature.newSignatureMethod(SignatureMethod.RSA_SHA1, null), 
                                                                Collections.singletonList( ref ) );

        KeyStore  ks = KeyStore.getInstance("PKCS12");
        ks.load(new FileInputStream("boteco_assinado.pfx"), "rd1234".toCharArray() );

        Enumeration aliasesEnum = ks.aliases();
        String alias = "";
        while( aliasesEnum.hasMoreElements() ){
            alias = (String) aliasesEnum.nextElement();
            System.out.println(alias);
            break;//encontrou um certificado
        }

        KeyStore.PrivateKeyEntry  keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry( alias , new KeyStore.PasswordProtection("rd1234".toCharArray() )  );

        X509Certificate cert = (X509Certificate) keyEntry.getCertificate();

        KeyInfoFactory factoryKeyInfo = factorySignature.getKeyInfoFactory();
        List x509Content = new ArrayList();

        x509Content.add(cert);

        X509Data x509Data = factoryKeyInfo.newX509Data(x509Content);

        KeyInfo keyInfo = factoryKeyInfo.newKeyInfo( Collections.singletonList(x509Data) );

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        dbf.setNamespaceAware(true);

        //Document doc = dbf.newDocumentBuilder().parse(new FileInputStream("nota.xml") );

        DOMSignContext domSignContext = new DOMSignContext(keyEntry.getPrivateKey() , doc.getDocumentElement() );



        XMLSignature signature = factorySignature.newXMLSignature(signedInfo, keyInfo );

        signature.sign( domSignContext );

        ///gera arquivo assinado
        OutputStream out = new FileOutputStream(new File("nota_assinada.xml") );
        TransformerFactory transformFactory = TransformerFactory.newInstance();
        Transformer trans = transformFactory.newTransformer();
        trans.transform(new DOMSource(doc) , new StreamResult(out) );


        /*======================================================================*/
        // Encontra o elemente Signature
        NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");

        if (nl.getLength() == 0) {
            throw new Exception("Não foi possível encontrar o elemente Signature");
        }

        // Cria um DOMValidateContext
        DOMValidateContext valContext = new DOMValidateContext( new X509KeySelector(ks), nl.item(0));

        // Dsempacota (unmarshal) a XMLSignature
        XMLSignature signatures = factorySignature.unmarshalXMLSignature(valContext);

        // Valida a XMLSignature.
        boolean coreValidity = signatures.validate(valContext);

        // Checa o status da validação
        if (coreValidity == false) {
            System.err.println("Falha na Assinatura!");
        } else {
            System.out.println("Assinatura Correta!");
        }
    } catch ( Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Follow code I use to validate by signature

String C14N_TRANSFORM_METHOD = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
    String PROVIDER_CLASS_NAME = "org.jcp.xml.dsig.internal.dom.XMLDSigRI";
    String PROVIDER_NAME = "jsr105Provider";


    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

    factory.setNamespaceAware(true);

    DocumentBuilder builder = factory.newDocumentBuilder();
    Document doc = builder.parse( new File("nota_assinada.xml") );
    NodeList elements = doc.getElementsByTagName( "infNFe" );
    Element el = (Element) elements.item(0);
    String idNota = el.getAttribute("Id");
    el.setIdAttribute("Id", true);

    String providerName = System.getProperty( PROVIDER_NAME , PROVIDER_CLASS_NAME );

    XMLSignatureFactory factorySignature = XMLSignatureFactory.getInstance("DOM" , (Provider) Class.forName(providerName).newInstance()  );



    NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");

    if (nl.getLength() == 0) {
        throw new Exception("Não foi possível encontrar o elemente Signature");
    }

    // Cria um DOMValidateContext
    DOMValidateContext valContext = new DOMValidateContext( new KeyValueKeySelector(), nl.item(0));

    // Dsempacota (unmarshal) a XMLSignature
    XMLSignature signatures = factorySignature.unmarshalXMLSignature(valContext);

    // Valida a XMLSignature.
    boolean coreValidity = signatures.validate(valContext);

    // Checa o status da validação
    if (coreValidity == false) {
        System.err.println("Falha na Assinatura!");
    } else {
        System.out.println("Assinatura Correta!");
    }
    boolean sv = signatures.getSignatureValue().validate(valContext);
    System.out.println("signature validation status: " + sv); 

and the keySelect

public class KeyValueKeySelector extends KeySelector {

  public KeySelectorResult select(KeyInfo keyInfo,  KeySelector.Purpose purpose, AlgorithmMethod method,  XMLCryptoContext context) throws KeySelectorException {

    if (keyInfo == null) {
      throw new KeySelectorException("Null KeyInfo object!");
    }

    SignatureMethod sm = (SignatureMethod) method;
    List list = keyInfo.getContent();

    for (int i = 0; i < list.size(); i++) {

        XMLStructure xmlStructure = (XMLStructure) list.get(i);

        PublicKey pk = null;

        if(xmlStructure instanceof X509Data){                   
              for (Object data : ((X509Data) xmlStructure).getContent()) {
                  if (data instanceof X509Certificate) {
                      System.out.println("x509Certificate");
                      pk = ((X509Certificate)data).getPublicKey();
                      System.out.println( ((X509Certificate) data).getSubjectDN().getName() );
                      // make sure algorithm is compatible with method
                      if (algEquals(sm.getAlgorithm(),pk.getAlgorithm())) {
                          return new SimpleKeySelectorResult(pk);
                      }
                  }
              }

        }
    }
    throw new KeySelectorException("No KeyValue element     found!");
  }

  public boolean algEquals(String algURI, String algName) {
    if (algName.equalsIgnoreCase("DSA") &&
        algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) {
      return true;
    } else if (algName.equalsIgnoreCase("RSA") &&
        algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) {
      return true;
    } else {
      return false;
    }
  }


  public class SimpleKeySelectorResult implements KeySelectorResult {
        private PublicKey pk;

        SimpleKeySelectorResult(PublicKey pk) {
                this.pk = pk;
        }

        @Override
        public Key getKey() {
                return this.pk;
        }
}

} 
  • Have you tried creating your own certification authority ? by the Openssl standard, here is a link to how to make one: https://securityinformacao.wordpress.com/2008/12/22/criando-autoridade-certificadora-e-certificaos-digital/

2 answers

0

Note that if you need to create this Permission, the name is case sensitive (Xi with i tiny). It has to be exactly XiSecurityRuntimePermission and kind Runtime.

0

Steps executed to verify file integrity (the steps my java program needs to perform):

  • Submit the received file to the MD5 unidirectional function and store the result (a 16 byte hash).
  • Decrypt the hash received from the sender using the RSA algorithm and the sender’s public key.
  • Compare item 1 hash with decrypted hash in item 2.
  • If they are different it will mean that the file was changed after its generation.

Source:http://www.guj.com.br/java/275221-como-validar-assinatura-digital#1447644.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.