santuario-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Roman Podstawa <roman...@gmail.com>
Subject Re: Strange behavior in calculating signature from encrypted xml
Date Mon, 01 Dec 2014 12:25:26 GMT
There are two things:
1. When you write xml to a file (version without ds prefix) then you will
notice that this prefix is added automatically. So KeyInfo class (or
another code related with this) adds this prefix automatically when you
write xml to string. So from my point of view the xml is valid and when you
sign the xml then signature should be calculated for the output xml
content. It looks like writing xml to string does some additional
operations (like adding this ds prefix) and signing xml skip such code.
2. As you see, I use KeyInfo class. So I don't see a reason to add ds
prefix manually. I would understand this if I would create key info element
manually. But in case when I use KeyInfo class then all DOM elements
created for this part of xml should be done automatically.

If you don't understand what I mean (especially in point 1) then please do
a test by writing DOM xml to string in unit test with fail and analyze
Envelope\Body\EncryptedData\KeyInfo
element. You should see ds prefix there.

Thanks,
Romek

2014-12-01 12:56 GMT+01:00 Colm O hEigeartaigh <coheigea@apache.org>:

>
> > From my point of view I shouldn't add this namespace attribute to
> generate a valid signature.
>
> The problem is that without adding the attribute, the XML you are
> producing is not valid as the "ds" prefix used to define KeyInfo can't be
> resolved.
>
> Santuario appears to be adding in the default XML Signature namespace
> associated with the "ds" prefix on the receiving side, hence the signature
> validation failure. I guess this could be considered a bug, but not a very
> important one, as the real problem is that your XML is not valid.
>
> Colm.
>
> On Sun, Nov 30, 2014 at 9:43 AM, Roman Podstawa <romanp81@gmail.com>
> wrote:
>
>> Hello,
>>
>> I’m working on code which should first encrypt Body element content (xml
>> is a soap message) and then sign this encrypted xml. I’ve noticed a strange
>> behavior. I’ve prepared a unit tests to show where the problem is:
>>
>> public class MyTest extends org.junit.Assert
>> {
>>     String
>> mainKey="MIIC+DCCAeSgAwIBAgIQAw19soViIYFA0LfhGDibeTAJBgUrDgMCHQUAMBUxEzARBgNVBAMTClJvb3RDQVRlc3QwHhcNMTQwNDE0MDczMzUyWhcNMzkxMjMxMjM1OTU5WjAXMRUwEwYDVQQDEwxyb2JvY2lrUHJhY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQClHbEhJZiBIjWW0pc2Efpns/xTxXvSl11NlNGqCd6teCVpJd/PAySG/f8oUFyf3LW7wHLhKGbAtg1Lf4pO4KJbWR9BxFyuImwtIqtLU7YAVnPkIpOmn1QFul8KqUl4W5pklh+8HLm7qZHZWOsF0y6gGy4cN2rI/yiSy+65ee7sQUCVWk9AKFoexyf5V3x2WnDZr22BOCrxfMnyhk8Exxj2AsLSt+q94BKzmdh9hVOcvaZivmMrqgRCrF9HZZtF3cek2VFkXIRiOVkiDqKl++k611nKtroeKTRMeJr3seowh6ZfYKdMluf/v3YwDrhEvAzX9wUxWTqxML3Ve0NGPTSJAgMBAAGjSjBIMEYGA1UdAQQ/MD2AEDuq/TTQAqG/IzsZKVWFIF6hFzAVMRMwEQYDVQQDEwpSb290Q0FUZXN0ghAE58iucYM4tULQsZhppop1MAkGBSsOAwIdBQADggEBABy5DeYmLY5L2Zp5JeiwNov1oteej1h01j8fSHjj2JgTiITAHRI4IVcKpa/r4zSYXrtnXsrfmmMZorz6viFBpog4f6BmNIQTzaW1CNEvbaRAEr0U0NRc5gfDL/albdnx8cFu+4QZ9elQd7s7Xf5De0ceC34m1k9gRyzn5axNf7BwSxLeHp1PbFDQPIKDtzNF0/bvoJmDVQi8pGEJIp/LhWeQ7vWNZovGpFmlvuDmOsZp4U+m3/AcRZlKfHn5naWKZUYRMR7VE0UMnirJ3Lfc2r6Ur0AHqQ5PHb7YqgGL3RZSGdh30JUYPlbsyU+iaNRRiQswDZnmgmqHyg/9Q8XJtU0=";
>>     SecretKey secretKey;
>>     PublicKey pk;
>>     String xml="<v:Envelope xmlns:v=\"
>> http://www.w3.org/2003/05/soap-envelope\" xmlns:i=\"
>> http://www.w3.org/2001/XMLSchema-instance\" xmlns:d=\"
>> http://www.w3.org/2001/XMLSchema\" xmlns:c=\"
>> http://www.w3.org/2003/05/soap-encoding\" xmlns:u=\"
>> http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"
>> xmlns:a=\"http://www.w3.org/2005/08/addressing\" xmlns:s=\"
>> http://www.w3.org/2003/05/soap-envelope\"><v:Header><n0:Action
>> xmlns:n0=\"http://www.w3.org/2005/08/addressing\" v:mustUnderstand=\"1\"
>> u:Id=\"uuid-5061ec6e-f05b-4c3f-960d-815ee74ba8ad\">
>> http://tempuri.org/IWS_StarService/HelloWorld</n0:Action><n1:MessageID
>> xmlns:n1=\"http://www.w3.org/2005/08/addressing\"
>> u:Id=\"uuid-a5a15cfa-21cb-4842-b9b3-83ca109cb4ca\">urn:uuid:814a0516-6d5c-4812-86dc-7f3f5d0b2ed2</n1:MessageID><n2:ReplyTo
>> xmlns:n2=\"http://www.w3.org/2005/08/addressing\"
>> u:Id=\"uuid-5f957f93-d071-440c-9278-24b79fd8c611\"><n2:Address>
>> http://www.w3.org/2005/08/addressing/anonymous</n2:Address></n2:ReplyTo><n3:To
>> xmlns:n3=\"http://www.w3.org/2005/08/addressing\" v:mustUnderstand=\"1\"
>> u:Id=\"uuid-01269a2c-cf46-49bf-97ec-bf6bc6e248b6\">
>> http://localhost:4774/API/WS_StarService.svc/Test</n3:To><Security
>> xmlns=\"
>> http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"
>> s:mustUnderstand=\"1\"><u:Timestamp
>> u:Id=\"uuid-3367eb13-35c7-4b60-8ea9-a83e31de989f\"><u:Created>2014-11-29T08:12:50.297Z</u:Created><u:Expires>2014-11-29T14:12:50.297Z</u:Expires></u:Timestamp></Security></v:Header><v:Body
>> u:Id=\"_0\"><n4:HelloWorld xmlns:n4=\"http://tempuri.org/\"><n4:message>my
>> message</n4:message></n4:HelloWorld></v:Body></v:Envelope>";
>>
>>     public MyTest() throws NoSuchAlgorithmException,
>> CertificateException, Base64DecodingException {
>>         InputStream mainKeyStream = new
>> ByteArrayInputStream(Base64.decode(mainKey) );
>>         CertificateFactory cf = CertificateFactory.getInstance("X.509");
>>         X509Certificate cert =
>> (X509Certificate)cf.generateCertificate(mainKeyStream);
>>         pk =cert.getPublicKey();
>>
>>         KeyGenerator keyGen = KeyGenerator.getInstance("AES");
>>         secretKey = keyGen.generateKey();
>>         org.apache.xml.security.Init.init();
>>     }
>>
>>     @org.junit.Test
>>     public void
>> test_sign_document_after_writing_and_reading_from_stream() throws Exception
>> {
>>
>>         Document doc1=signDocument(false);//DIFFERENCE IN THE LAST
>> PARAMETER!
>>
>>         //here we first write xml to stream and read it again. This
>> simulates sending soap message and receiving it on the another side
>>         InputStream outputStream = documentToStream(doc1);
>>         doc1=streamToDocument(outputStream);
>>
>>         boolean isValid1=ensureValidSignature(doc1,secretKey);
>>
>>         assertTrue(isValid1);
>>     }
>>
>>     @org.junit.Test
>>     public void
>> test_sign_document_with_additional_NS_after_writing_and_reading_from_stream()
>> throws Exception {
>>
>>         Document doc1=signDocument(true);//DIFFERENCE IN THE LAST
>> PARAMETER!
>>
>>         //here we first write xml to stream and read it again. This
>> simulates sending soap message and receiving it on the another side
>>         InputStream outputStream = documentToStream(doc1);
>>         doc1=streamToDocument(outputStream);
>>
>>         boolean isValid1=ensureValidSignature(doc1,secretKey);
>>
>>         assertTrue(isValid1);
>>     }
>>
>>     @org.junit.Test
>>     public void test_sign_document() throws Exception {
>>
>>         Document doc1=signDocument(false);//DIFFERENCE IN THE LAST
>> PARAMETER!
>>
>>         boolean isValid1=ensureValidSignature(doc1,secretKey);
>>
>>         assertTrue(isValid1);
>>     }
>>
>>     @org.junit.Test
>>     public void test_sign_document_with_additional_NS() throws Exception {
>>
>>         Document doc1=signDocument(true);//DIFFERENCE IN THE LAST
>> PARAMETER!
>>
>>         boolean isValid1=ensureValidSignature(doc1,secretKey);
>>
>>         assertTrue(isValid1);
>>     }
>>
>>     Document signDocument(boolean addNamespaceAttribute) throws Exception
>> {
>>         InputStream stream = new ByteArrayInputStream(xml.getBytes() );
>>         Document doc=streamToDocument(stream);
>>
>>         NodeList nodes = doc.getElementsByTagNameNS("
>> http://www.w3.org/2003/05/soap-envelope","Body");
>>         Element bodyElement= (Element) nodes.item(0);
>>         bodyElement.setAttributeNS("
>> http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
>> "u:Id", "_0");
>>         bodyElement.setIdAttributeNS("
>> http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
>> "Id", true);
>>
>>         XMLCipher clipper = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);
>>         clipper.init(XMLCipher.WRAP_MODE,pk);
>>         clipper.setKEK(pk);
>>
>>         EncryptedKey encryptedKey=clipper.encryptKey(doc,secretKey);
>>         Element encryptedKeyElement=clipper.martial(encryptedKey);
>>
>>         Element securityElement= (Element) doc.getElementsByTagNameNS("
>> http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd
>> ","Security").item(0);
>>         securityElement.appendChild(encryptedKeyElement);
>>
>>         clipper = XMLCipher.getInstance(XMLCipher.AES_128);
>>         clipper.init(XMLCipher.ENCRYPT_MODE,secretKey);
>>         clipper.setKEK(secretKey);
>>
>>         EncryptedData encryptedBody=clipper.getEncryptedData();
>>         String encryptedBodyId="uuid-"+ UUID.randomUUID().toString();
>>
>>
>>         bodyElement= (Element) doc.getElementsByTagNameNS("
>> http://www.w3.org/2003/05/soap-envelope","Body").item(0);
>>         encryptedBody.setId(encryptedBodyId);
>>
>>         KeyInfo keyInfo = new KeyInfo(doc);
>>         encryptedBody.setKeyInfo(keyInfo);
>>         Element securityTokenReferenceElement=doc.createElementNS("
>> http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd
>> ","SecurityTokenReference");
>>         securityTokenReferenceElement.setAttributeNS("
>> http://www.w3.org/2000/xmlns/","xmlns","
>> http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd
>> ");
>>         securityTokenReferenceElement.setAttributeNS("
>> http://www.w3.org/2000/xmlns/","xmlns:k","
>> http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd");
>>         securityTokenReferenceElement.setAttributeNS("
>> http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd
>> ","k:TokenType","
>> http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey
>> ");
>>         keyInfo.addUnknownElement(securityTokenReferenceElement);
>>
>>         if(addNamespaceAttribute)
>>         {
>>             //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! THIS IS ONLY ONE
>> DIFFERENCE. WE ADD A NAMESPACE ATTRIBUTE EXPLICITLY
>>             Element keyInfoElement=keyInfo.getElement();
>>             keyInfoElement.setAttributeNS("http://www.w3.org/2000/xmlns/
>> ","xmlns:ds","http://www.w3.org/2000/09/xmldsig#");
>>         }
>>
>>         clipper.doFinal(doc,bodyElement,true);
>>
>>         //now sign xml
>>         XMLSignature sig =  new XMLSignature(doc, "",
>> XMLSignature.ALGO_ID_MAC_HMAC_SHA1,
>> Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
>>
>>         org.apache.xml.security.transforms.Transforms transforms = new
>> org.apache.xml.security.transforms.Transforms(doc);
>>
>> transforms.addTransform(org.apache.xml.security.transforms.Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
>>         sig.addDocument("#_0", transforms);
>>
>>         Element elemt=sig.getElement();
>>
>>         securityElement.appendChild(elemt);
>>
>>         sig.sign(secretKey);
>>         return doc;
>>     }
>>
>>     Document streamToDocument(InputStream stream) throws
>> ParserConfigurationException, IOException, SAXException {
>>         DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
>>         f.setNamespaceAware(true);
>>
>>         DocumentBuilder builder = f.newDocumentBuilder();
>>         builder.setErrorHandler(new
>> org.apache.xml.security.utils.IgnoreAllErrorHandler());
>>
>>         Document doc = builder.parse(new BufferedInputStream(stream));
>>         return doc;
>>     }
>>
>>     InputStream documentToStream(Document doc) throws
>> TransformerException {
>>         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
>>         Source xmlSource = new DOMSource(doc);
>>         javax.xml.transform.Result outputTarget = new
>> StreamResult(outputStream);
>>
>> TransformerFactory.newInstance().newTransformer().transform(xmlSource,
>> outputTarget);
>>         InputStream is = new
>> ByteArrayInputStream(outputStream.toByteArray());
>>         return is;
>>     }
>>
>>     boolean ensureValidSignature(Document doc,SecretKey secretKey) throws
>> XPathExpressionException, XMLSecurityException {
>>         NodeList
>> signs1=doc.getElementsByTagNameNS(Constants.SignatureSpecNS, "Signature");
>>         if(signs1.getLength()>0)
>>         {
>>             NodeList nodes = doc.getElementsByTagNameNS("
>> http://www.w3.org/2003/05/soap-envelope", "Body");
>>             Element bodyElement= (Element) nodes.item(0);
>>             bodyElement.setIdAttributeNS("
>> http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
>> "Id", true);
>>
>>             Element signElem= (Element) signs1.item(0);
>>             XMLSignature signature = new XMLSignature(signElem, "test");
>>             boolean isValid=signature.checkSignatureValue(secretKey);
>>             return isValid;
>>         }
>>         return false;
>>     }
>> }
>>
>> Entire code is quite long but the problem is easy to explain. So there
>> are 4 tests. 3 of them pass, 1 fails (at least on my machine). Basically
>> when I create a DOM Document, encrypt and sign it and then verify a
>> signature then everything works great (test: test_sign_document and
>>  test_sign_document_with_additional_NS). But when I first write the signed
>> DOM document to stream and then read it again (and create a DOM Document)
>> and then I verify a signature then results are different. Two additional
>> tests shows this situation and as you can see one test pass and second
>> fails. When you see how xml looks in both tests (after writing them to file
>> or String variable) then you will notice that they are almost the same (I
>> mean the Body part). In both xml (after serialization)
>> Envelope\Body\EncryptedData\KeyInfo there is a namespace attribute (
>> http://www.w3.org/2000/09/xmldsig#). But code to calculate signature
>> create a digest value without this namespace attribute. In other words when
>> you compare testes:
>> test_sign_document_after_writing_and_reading_from_stream and
>> test_sign_document_with_additional_NS_after_writing_and_reading_from_stream
>> you will see that the only difference is that in working tests I add this
>> attribute manually:
>>
>> if(addNamespaceAttribute)
>> {
>>     //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! THIS IS ONLY ONE DIFFERENCE. WE ADD
>> A NAMESPACE ATTRIBUTE EXPLICITLY
>>     Element keyInfoElement=keyInfo.getElement();
>> keyInfoElement.setAttributeNS("http://www.w3.org/2000/xmlns/
>> ","xmlns:ds","http://www.w3.org/2000/09/xmldsig#");
>> }
>> But as I mentioned after writing xml to String this attribute is in both
>> xml content. From my point of view I shouldn't add this namespace attribute
>> to generate a valid signature.
>>
>> Is this a bug?
>>
>> Thanks
>> Romek
>>
>
>
>
> --
> Colm O hEigeartaigh
>
> Talend Community Coder
> http://coders.talend.com
>

Mime
View raw message