2017-03-01 5 views
1

J'ai une requête XML signée, qui est rejetée par la 3ème partie en raison d'une signature non valide. Par conséquent, j'ai écrit mon propre code de validation de signature pour voir ce qui ne va pas. Cependant, j'obtiens NPE en validant la signature XML que je viens de créer. Voici ce que le XML ressemble (je l'ai enlevé les parties non pertinentes):Java NPE lors de la validation de ma propre signature XML

<?xml version="1.0" encoding="UTF-8"?> 
<envelope xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:noNamespaceSchemaLocation="some_third_party.xsd"> 
    <header>...</header> 
    <body>...</body> 
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="MySignature"> 
     <SignedInfo> 
      <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> 
      <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> 
      <Reference URI=""> 
       <Transforms> 
        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> 
       </Transforms> 
       <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
       <DigestValue>AaV+ejxBF8GjJvIZA9Bonw81Z1Y=</DigestValue> 
      </Reference> 
      <Reference Type="http://www.w3.org/2000/09/xmldsig#SignatureProperties" URI="#SignatureProperties"> 
       <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
       <DigestValue>qcofYVnQ/n7sxKJPT5rG0+UYbjg=</DigestValue> 
      </Reference> 
     </SignedInfo> 
     <SignatureValue>XXX</SignatureValue> 
     <KeyInfo> 
      <X509Data> 
       <X509Certificate>XXX</X509Certificate> 
      </X509Data> 
     </KeyInfo> 
     <Object Id="SignatureProperties"> 
      <SignatureProperties xmlns=""> 
       <SignatureProperty Id="TimeStamp" Target="#MySignature"> 
        <TimeStamp> 
         <Date>2017-03-01</Date> 
         <Time>09:06:36.779+01:00</Time> 
        </TimeStamp> 
       </SignatureProperty> 
      </SignatureProperties> 
     </Object> 
    </Signature> 
</envelope> 

Lorsque je tente de valider cette signature, je reçois NPE sur la ligne commentée (il se passe réellement lorsque unmarshalling la signature, avant la réelle validation):

// Omitted: extract the X509 Certificate from the document 
DOMValidateContext valContext = new DOMValidateContext(cert.getPublicKey(), signature); 
XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM"); 
XMLSignature xmlSignature; 
try { 
    // Null pointer exception here! 
    xmlSignature = factory.unmarshalXMLSignature(valContext); 
} catch (MarshalException e) { 
    // Handle exception 
} 

Pour être complet, voici comment je crée la signature:

try { 
    XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM"); 

    Reference ref = xmlSignatureFactory.newReference("", 
      xmlSignatureFactory.newDigestMethod(DigestMethod.SHA1, null), 
      Collections.singletonList(xmlSignatureFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), 
      null, 
      null); 

    Reference signatureRef = xmlSignatureFactory.newReference("#SignatureProperties", 
      xmlSignatureFactory.newDigestMethod(DigestMethod.SHA1, null), 
      null, 
      "http://www.w3.org/2000/09/xmldsig#SignatureProperties", 
      null); 

    SignedInfo signedInfo = xmlSignatureFactory.newSignedInfo(xmlSignatureFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), 
      xmlSignatureFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null), 
      Arrays.asList(ref, signatureRef)); 

    XMLObject xmlObject = xmlSignatureFactory.newXMLObject(Collections.singletonList(new DOMStructure(timestamp)), 
      "SignatureProperties", null, null); 

    KeyInfoFactory keyInfoFactory = xmlSignatureFactory.getKeyInfoFactory(); 
    List<Object> x509Content = new ArrayList<>(); 
    x509Content.add(certificate); 
    X509Data xd = keyInfoFactory.newX509Data(x509Content); 
    KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(xd)); 

    XMLSignature xmlSignature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo, 
      Collections.singletonList(xmlObject), SIGNATURE_ID, null); 
    DOMSignContext signContext = new DOMSignContext(privateKey, document.getDocumentElement()); 
    xmlSignature.sign(signContext); 
} catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException e) { 
    // Handle exception 
} 

Toute idée de ce que je fais mal ici?

Edit: a ajouté le stacktrace pour montrer où NPE est jeté exactement:

java.lang.NullPointerException: null 
    at org.jcp.xml.dsig.internal.dom.DOMXMLObject.<init>(DOMXMLObject.java:120) 
    at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.<init>(DOMXMLSignature.java:171) 
    at org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory.unmarshal(DOMXMLSignatureFactory.java:193) 
    at org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory.unmarshalXMLSignature(DOMXMLSignatureFactory.java:150) 

Edit 2: Je dois aussi mentionner que les deux le contenu SignedValue et X509Certificate ont des espaces blancs après la création de la signature, ce qui fait un peu bizarre de me . Par exemple.

<X509Certificate>MIIG8DCCBdigAwIBAgIUJZSmBORuGuXyx48f04sNGHT+RhwwDQYJKoZIhvcNAQELBQAwWzELMAkG 
    A1UEBhMCQ0gxEzARBgNVBAoTClBvc3QgQ0ggQUcxDTALBgNVBAsTBFBST0QxKDAmBgNVBAMTH1BL 
    SSBTd2lzc1Bvc3QgTWFjaGluZSBBRVAgQ0EgRzMwHhcNMTcwMTI2MTIzMTQ0WhcNMjAwMTI2MTIz 
    MTQ0WjCBsTELMAkGA1UEBhMCQ0gxCzAJBgNVBAgTAkZSMSAwHgYDVQQKExdEaWUgU2Nod2VpemVy 
    ... 
+0

Avez-vous une trace de la pile ? –

+0

Oui, j'ai maintenant ajouté la trace de la pile. – Egemen

+0

Êtes-vous sûr que 'signature' n'est pas nulle? –

Répondre

1

J'ai résolu le problème après un débogage. DOMXMLObject essaie d'obtenir le nom local du nœud SignatureProperties, qui renvoie null. J'ai légèrement modifié la façon dont je crée cet élément et cela fonctionne bien maintenant.

J'ajoute ce morceau de code dans le cas où il est utile pour quelqu'un d'autre plus tard:

private Element createTimestamp(Document doc) { 
    // Use createElementNS instead of createElement, otherwise you will get the aforementioned NPE 
    Element signatureProperties = doc.createElementNS("", "SignatureProperties"); 
    Element signatureProperty = signatureProperties.getOwnerDocument().createElementNS("","SignatureProperty"); 
    signatureProperty.setAttribute("Target", "#" + SIGNATURE_ID); 
    signatureProperty.setAttribute("Id", "TimeStamp"); 
    Element timeStamp = signatureProperty.getOwnerDocument().createElementNS("", "TimeStamp"); 

    ZonedDateTime now = ZonedDateTime.now(ZoneId.systemDefault()); 
    Element date = timeStamp.getOwnerDocument().createElementNS("", "Date"); 
    date.setTextContent(now.toLocalDate().toString()); 
    Element time = timeStamp.getOwnerDocument().createElementNS("", "Time"); 
    time.setTextContent(now.toLocalTime().toString() + now.getOffset().toString()); 

    timeStamp.appendChild(date); 
    timeStamp.appendChild(time); 
    signatureProperty.appendChild(timeStamp); 
    signatureProperties.appendChild(signatureProperty); 
    return signatureProperties; 
} 

Résultat de cette méthode est ensuite utilisée dans cette ligne:

XMLObject xmlObject = xmlSignatureFactory.newXMLObject(Collections.singletonList(new DOMStructure(createTimestamp(doc))), 
       "SignatureProperties", null, null);