locked
How to use kerberos security token to generate derived keys for SOAP requests on CRM 2011 On-premise RRS feed

  • Question

  • Has anybody successfully send SOAP request to CRM 2011 On-premise using JAVA or other non-dotnet client?

    I am able to authenticate with the server via Kerberos with my JAVA client. I got the wrapped secret key in the RequestedProofToken:

    <t<<t:RequestedProofToken><ec:encryptedkey><e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#"></ec:encryptedkey><ec:encryptionmethod Algorithm="http://schemas.xmlsoap.org/2005/02/trust/spnego#GSS_Wrap"><e:EncryptionMethod Algorithm="http://schemas.xmlsoap.org/2005/02/trust/spnego#GSS_Wrap"/></ec:encryptionmethod><ec:cipherdata><e:CipherData><ec:ciphervalue><e:CipherValue>BQQH/wAAABwAA…..keZhPKp9k4u3Yo8PrBZM=</e:CipherValue></ec:ciphervalue></e:CipherData></ec:cipherdata></e:EncryptedKey></t:RequestedProofToken>

    How should I use this secret key to generate the derived keys used for signing and encrypting the message?

    In my environment, I have a c# application sending the following request. I am trying to make the similar request using JAVA.

    <s:Envelope>

    <s:Header>

     <a:Action s:mustUnderstand="1" u:Id="_4">http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Retrieve</a:Action>

     <a:MessageID u:Id="_5">urn:uuid:f40b904c-820c-46a9-8e61-614eed352eb4</a:MessageID>

    <a:ReplyTo u:Id="_6">

     <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>

     </a:ReplyTo>

     <VsDebuggerCausalityData>uIDPo7llQLKfKnVGq2mSkO2JLQ8AAAAAHWP94sr3bUihJt23UjGIbP3GGhdqiVtLjX9XNes24aYACQAA</VsDebuggerCausalityData>

     <a:To s:mustUnderstand="1" u:Id="_7">http://localhost:5555/CRM/XRMServices/2011/Organization.svc</a:To>

    <o:Security s:mustUnderstand="1">

    <u:Timestamp u:Id="uuid-0535f868-7c40-4227-a9aa-9ca6123c6cf2-7">

     <u:Created>2014-03-31T15:08:22.930Z</u:Created>

     <u:Expires>2014-03-31T15:13:22.930Z</u:Expires>

     </u:Timestamp>

    <c:SecurityContextToken u:Id="uuid-ccf610f7-6c6c-49d4-9ac2-92d72e7c48c8-14">

     <c:Identifier>urn:uuid:c66ea628-33b8-47de-9e80-ed38ab3017a8</c:Identifier>

     </c:SecurityContextToken>

    <c:DerivedKeyToken u:Id="_0">

    <o:SecurityTokenReference>

     <o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-ccf610f7-6c6c-49d4-9ac2-92d72e7c48c8-14"/>

     </o:SecurityTokenReference>

     <c:Offset>0</c:Offset>

     <c:Length>24</c:Length>

     <c:Nonce>xzbSHKZCrH8+dQ/njd3xww==</c:Nonce>

     </c:DerivedKeyToken>

    <c:DerivedKeyToken u:Id="_1">

    <o:SecurityTokenReference>

     <o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-ccf610f7-6c6c-49d4-9ac2-92d72e7c48c8-14"/>

     </o:SecurityTokenReference>

     <c:Nonce>56OuI42lQYcSqPw11NiAdA==</c:Nonce>

     </c:DerivedKeyToken>

    <e:ReferenceList>

     <e:DataReference URI="#_3"/>

     <e:DataReference URI="#_8"/>

     </e:ReferenceList>

    <e:EncryptedData Id="_8" Type="http://www.w3.org/2001/04/xmlenc#Element">

     <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>

    <KeyInfo>

    <o:SecurityTokenReference>

     <o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/dk" URI="#_1"/>

     </o:SecurityTokenReference>

     </KeyInfo>

    <e:CipherData>

     <e:CipherValue> …  </e:CipherData>

     </e:EncryptedData>

     </o:Security>

     </s:Header>

    <s:Body u:Id="_2">

    <e:EncryptedData Id="_3" Type="http://www.w3.org/2001/04/xmlenc#Content">

     <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>

    <KeyInfo>

    <o:SecurityTokenReference>

     <o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/dk" URI="#_1"/>

     </o:SecurityTokenReference>

     </KeyInfo>

    <e:CipherData>

     <e:CipherValue> …  </e:CipherData>

     </e:EncryptedData>

     </s:Body>

     </s:Envelope>

    Monday, April 14, 2014 5:46 PM

All replies

  • Hi,

    I wouldn't try to construct the WS-security token yourself - there are lots of libraries that will do this for you. You need to find a SOAP library that supports WS-security.

    See http://blogs.msdn.com/b/dynamics-coe/archive/2013/09/21/integrating-microsoft-dynamics-crm-2011-online-with-java-and-other-non-net-clients.aspx

    Hope this helps,

    Scott


    Scott Durow
    Blog www.develop1.net    Follow Me
    Rockstar365
    If this post answers your question, please click "Mark As Answer" on the post and "Mark as Helpful"

    Monday, April 14, 2014 7:13 PM
    Answerer
  • http://social.microsoft.com/Forums/en-US/c485d98b-6e0b-49e7-ab34-8ecf8d694d31/signing-soap-message-request-via-adfs?forum=crmdevelopment#b677372d-49d4-40da-ad4d-fdb9a1fb7fed may help.

    It has a sample walkthrough expanding on the basic process of:

    1. Digest value - canonicalize the timestamp xml, do a simple SHA1 hash on it.

    2. Place the digestvalue in the 'signedInfo' and canonicalize the SignedInfo XML.

    3. Calculate a derived PSHA1 key based on the trust:BinarySecret of the original token request ('main' key) and the trust:BinarySecret (seed/nonce/secondary key) of the token response.

    4. Hash the binary version of the base64 of your canonicalized signedxml as HMACSHA1, with the derived key as the secret, and turn the result hash back into Base64, that's your SignatureValue

    Your process may actually be simpler if you are using a prooftoken, my prooftoken was specified to be 'derived' so I had to deal with step 3 above. You may actually just be able to use your prooftoken as the secret for step 4.

    Scott's right, if you can find a library that works, it would be waaaay better, but I didn't have that kind of luck at the time.

    Tuesday, April 15, 2014 4:36 PM
  • Thank you for the replies!

    In my case, I feel like I need to have two derived keys. The following is the keys  that the C# application sent to the server.

    <c:DerivedKeyToken u:Id="_0" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-ccf610f7-6c6c-49d4-9ac2-92d72e7c48c8-14" /></o:SecurityTokenReference><c:Offset>0</c:Offset><c:Length>24</c:Length><c:Nonce>0jjV+sdQRdHkQ9d/5p7RHA==</c:Nonce></c:DerivedKeyToken>

    <c:DerivedKeyToken u:Id="_1" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-ccf610f7-6c6c-49d4-9ac2-92d72e7c48c8-14" /></o:SecurityTokenReference><c:Nonce>pzS13XmeVlTvYrfzpAs3rA==</c:Nonce></c:DerivedKeyToken>

    Each of them has different Nonce. I computed the derived keys with PSHA1 using the prooftoken according to WS-SecureConversation:

    P_SHA1 (secret, label + seed)

    However, I am not sure if I used the correct label + seed. I am also not sure if I used the correct length for the keys, especially for the second derived key since there is no Length specified for it.

    I am using the Kerberos authentication via Active Directory. I first used GSSContext.unwrap() to unwrap the prooftoken. And then call PSHA1 to create the keys.

    Do you have any suggestion?

    I was starting with the JAVA Walkthrough from the MSDN. I got it working with my CRM 2011 Online. But I could not get it work with CRM 2011 On-premise. I also tried to use CXF but I had no success.

    Tuesday, April 15, 2014 6:17 PM
  • I went through the blog that Scott pointed:

    http://blogs.msdn.com/b/dynamics-coe/archive/2013/09/21/integrating-microsoft-dynamics-crm-2011-online-with-java-and-other-non-net-clients.aspx

    I am seeing it did similarly to the JAVA walkthrough http://msdn.microsoft.com/en-us/library/jj602979.aspx

    The Java client need to make up the Security header using the information coming back from the server:

    // Generate security header

    securityHeader = String.format(

    MSDC_SECURITY_HEADER_TEMPLATE,

    keyIdentifier,

    securityToken0,

    securityToken1);

    The good thing using Office 365 online account is, there is no need to manipulate the security information. But it is not the case for CRM 2011 On-premise.

    Based on my understanding, after retrieving the security token from the CRM server authentication response, there are the following major steps needed for generating the request for my environment:

    --Unwrap the security token, generate a secret key.

    --Generate derived keys using the same secret key – Hash algorithm (P_SHA1). The client need generate 2 derived keys for each request. One is used to sign the message, the other is used to encrypt the signature and the body.

    --Signing message

    • Canonicalization – xml-exc-c14n algorithm. Normalize the xml message.
    • Digest message – SHA1 algorithm. Hash the canonical  XML document to generate a fix-length digest value (usually 160-bit).
    • Sign the digest value. This should be a symmetric signature (using the same derived key to sign and validate) – HMAC_SHA1 algorithm.

    --Encrypt signature and body. This should be a symmetric encryption (using the same derived key to encrypt and decrypt) – aes256-cbc algorithm for my case.

    Is my understanding correct?

    How should I generate the derived keys? I also don’t know what are exactly inside the Signature since it was encrypted. What are the references that are required to be in the SingInfo. Can someone provide a Signature sample?

    Thanks!

    Tuesday, April 15, 2014 7:52 PM
  • I have figured out the correct implementation for signature and encryption. I have been able to authenticate and send SOAP requests to the 2011/2013 On-Premise server through my Java application. Thanks!

    Tuesday, May 6, 2014 12:53 PM
  • Are you able to decrypt EncryptedKey value from the RequestedProofToken? I'm fighting with this task for few days and I cannot determine what encryption algorithm to use. For now I establish that first 16 bytes from CipherValue are somekind of header and the rest is an encrypted key bytes. But cant correctly decrypt it. Do you know how to do this?

    Thanks!

    Wednesday, February 25, 2015 7:31 PM