Monday, November 12, 2012

Signing with OpenSAML

When exchanging information with SAML it is highly recomended to sign and verify signatures on all messages. This to ensure the the sender really is how he seas he is and that the information sent has not been manipulated during transport.

Every SAML object that implements the SignableXMLObject interface can be signed.

The signing of a SAML message is done in three steps. First all the properties for the signature is put in a Signature object. Properties that can be set include singing credentials, algorithm and optionally a key info object that can bu used during verification.
signature.setSigningCredential(credential);
signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
The Signature object is then added to the SAML object using the setSignature method.
entityDescriptor.setSignature(signature); The second step is to marchal the object. This must be done before signing or else you will get a message like this.

SEVERE: Unable to compute signature, Signature XMLObject does not have the XMLSignature created during marshalling.


Element element = Configuration.getMarshallerFactory().getMarshaller(entityDescriptor).marshall(entityDescriptor);
The third step is to perform the actual signing to produce a cryptographic signature, this is done with the Signer class.
Signer.signObject(signature);
Here is how the signed object might look after signing and marshalling.


   
      
         
            
               
                  
                     
                        
                        
                     
                  
                  
                     a3HbFE7e2n/x2yqDTKyXrQNaDHs=
                  
               
            
         
      
 b8cPqphGwZIvBy1DuEWoS/lhreiMp7WtcukC2TkXl2nRwuJ5i1TN+ifefxvsjs9ocQ4XAL6EVrXXaJvyRMkepuDYAFqYYGle4iPkl5XZpCDeMjTEt/T45f3etOdn5EGmNgA5MwUQxFTnERYkdNiN//r8BYuNfEKFNd+BqyVRjRWBbgywWRfSBBz8u1m4aysyeYcz9M72pI9YhC4QqRtXG7cght78Lt3JLUMDHKZMg9itvs1rPwItLFCzaJr57Q/V+nQ8uIb0bCUUrXZw9hGl5b3SYIuJLdHI0IDPt8YGpNa/yzVqnKOk5FvhASmMQur3/CbdCvRKr8yTpalW3zDgfw==



Further reading

This is not a book specifically on OpenSAML but I do recommend it as i does have some chapters on how XML signatures work. This is the same standard as the one used by SAML and OpenSAML.

This is a very good book for those that want get an intro to cryptography. Helped me alot in understanding public key cryptography.

4 comments:

  1. After putting Signer.signObject(signature);
    I am getting

    Signature object is not initialized properly.

    ReplyDelete
  2. Hi Stefan ...

    How are you outputting the Response XML? I can create an Assertion without issue, and output its XML, but when I try to get a Response output, the Signature is being destroyed.

    I have the following code snippets.

    ------

    void signObject(SignableXMLObject object) throws Exception
    {
    SecurityConfiguration secConfig = Configuration.getGlobalSecurityConfiguration();
    Signature signature = createSAMLObject(Signature.class);
    SecurityHelper.prepareSignatureParams(signature, signingCredential, secConfig, null); //Is this even necessary?
    signature.setSigningCredential(signingCredential);
    signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
    signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);

    object.setSignature(signature);

    Configuration.getMarshallerFactory().getMarshaller(object).marshall(object);
    Signer.signObject(signature);
    }

    Document asDOMObject(XMLObject object) throws Exception
    {
    Document document = builder.newDocument ();
    Marshaller out = Configuration.getMarshallerFactory().getMarshaller(object);
    out.marshall(object, document);
    return document;
    }


    {
    // code to create an assertion
    signObject(assertion);

    // code to create a response with the assertion
    signObject(response);

    //At this point, both objects have valid XMLSignatures ... I can see this using a debugger.

    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    TransformerFactory.newInstance().newTransformer().transform(
    new DOMSource(asDOMObject(assertion)), new StreamResult(buffer));
    byte[] rawResult = buffer.toByteArray();
    buffer.close();

    String xmlResult = new String(rawResult);
    log.info("Assertion:");
    log.info(xmlResult);

    //The Assertion gets output without an issue ... the signature values are all in tact.

    buffer = new ByteArrayOutputStream();
    TransformerFactory.newInstance().newTransformer().transform(
    new DOMSource(asDOMObject(response)), new StreamResult(buffer));

    //Immediately after the above line is executed, the XMLSignature is changed and the original values are lost. Why?

    rawResult = buffer.toByteArray ();
    buffer.close();

    xmlResult = new String(rawResult);
    log.info("Response:");
    log.info(xmlResult);
    }

    I've tried a slightly different approach, but I think it's basically the same thing ...

    ResponseMarshaller responseMarshaller = new ResponseMarshaller();
    Element plain = responseMarshaller.marshall(response);
    xmlResult = XMLHelper.nodeToString(plain);

    This code also results in the Response's XMLSignature to be destroyed when it is marshalled.

    Any assistance you can provide would be very much appreciated. Thanks so much for looking at this.

    ReplyDelete