none
Algorithm Suite WCF WS Security RRS feed

  • Question

  • I am having an issue with AlgorithmSuite properties when using WCF to communicate with an external (non-WCF) web service. The service is defined using an algorithm suite of "Basic128Sha256Rsa15" which according to the Oasis WS Security specification should use "SHA256" for digests and "RSA-SHA-1" for asymmetric signature generation method. Other tools such as SOAP UI correctly use this configuration.

    However, when using the WsHttpBinding in WCF and changing the AlgorithmSuite to "Basic128Sha256Rsa15" the asymmetric signature method is defined as "RSA-SHA-256" which seems incorrect, and this causes a runtime failure since my certificate cannot use the "RSA-SHA-256" method.

    svcbinding.Security.Message.AlgorithmSuite = _

    Security.SecurityAlgorithmSuite.Basic128Sha256Rsa15

    Is this an error in the WCF specification for this algorithm suite? I cannot see any way to override the asymmetric signature method within this algorithm suite? Has anybody else hit tis problem, as it means the WS Security headers are not compatible with the WS Security specification?

    Tuesday, May 28, 2013 10:03 AM

All replies

  • Hi,

    Thanks for your post.

    I am trying to involve someone familiar with this topic to further look at this issue. There might be some time delay. Appreciate your patience.

    Best Regards.


    Haixia
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, May 30, 2013 8:03 AM
    Moderator
  • I too am interested in this.  Is there a good way to explicitly define the exact signature algorithm to use?  I have a slightly different problem taht I think stems from an unsupported feature, but I was curious about this regardless. 

    My issue is I'm trying to use a certificate with sha256RSA to sign soap messages.  From what I have read so far, this might not be supported at the moment.  However, I noticed that all of my SOAP messages had hmac-sha1 as their signature method.  I was trying to see if I could manually change this somehow.

    Thursday, May 30, 2013 6:05 PM
  • You can change the signature method by using the following code;

    svcbinding.Security.Message.AlgorithmSuite = _

    Security.SecurityAlgorithmSuite.Basic128Sha256Rsa15

    This changes the whole profile so that many things (including the signature method) get updated to new settings. The default is Basic128, and that's why you're seeing the values you get in your code; if you change the algorithm suite then you'll see the value in the SOAP headers change to a different method. I am using the WsHttpBinding binding as I am communicating with a non-.NET web service.

    However, according to the WS Security specification, RSA-SHA-256 should not be used as none of the currently defined profiles conform to it. So if you use this method (as you mention you want to) then the resulting code would likely be incompatible with non-.NET applications since anyone using WS Security compliant code would not be able to use RSA-SHA-256.

    In regard to using RSA-SHA-256, this is possible in .NET. However, you'll need a certificate that supports that method (most are RSA-SHA-1 only, which you can se in cert properties). I have seen that you can use RSA-SHA-1 with a non-supporting cert by creating an RSA-SHA-256 capable cryptographic object and then importing the certificate properties into it, rather than creating the cryptographic object directly from the certificate. I've not tried it myself but there are some examples to be found via Google.

    Hopefully, Microsoft will also soon reply regarding if this is a bug or there is something I am doing wrong in my code!

    Thursday, May 30, 2013 6:54 PM
  • Hi Haixia,

    did you have any luck with this please? Is there any update, as it's been two weeks and I don't see any response?

    Thanks.

    Tuesday, June 11, 2013 10:10 PM
  • Hi rjtmerrett,

    We’ve start contacting some internal support professional for help and haven’t got update so far. We will continue to monitor the status of this case and inform you of any update. Thanks for your patience.

    Best Regards.


    Haixia
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, June 12, 2013 3:43 AM
    Moderator
  • I don't see easy way of solving this, we are checking by using WCF extensibility, we can do anything to solve this, I will send update ASAP on this.

    -Thank you

    Madhu


    Madhu Ponduru(MCSD.NET),Microsoft Dist svcs team,http://blogs.msdn.com/madhuponduru/



    Thursday, June 13, 2013 3:29 AM
  • Hi Madhu, Are you saying it is a bug? I agree there is no easy way to solve this, but my point is that the code seems different to the WS Security specification and therefore the .NET implementation does not conform to the standard and is therefore useless. Effectively, it means WCF WS Security can only be used with other .NET applications, which makes no sense to use WS Security at all in that case? Is this likely to be fixed at any point? It seems silly to have an industry standard and then not adhere to the specification. Thanks.
    Thursday, June 13, 2013 8:45 AM
  • rjtmerrett,

    Take a look at the following link:

    http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/99231ca9-75b8-4254-a8a5-278c73901ec3/

    It helped me figure out which algorithms were being used with which algorithm suite.  I noticed that the asymmetric and symmetric algorithms were not always the same or what I expected.  But knowing which suite I could use to get the proper algorithm was a huge help.  Now I have a Java Spring WS-Security server that can accept my .NET WCF client SOAP requests.  If you're interested, here are the steps I had to do to get it working (it took me two weeks to figure this out).

    1. If you're using a certificate, I had a lot of trouble using one that was created from Java's keytool.  Instead, I had to create it using .NET and copy it to the java keystore.  This step may not be an issue for you, but it was for me.  Here is the command I used.

    makecert -r -pe -n "CN=client.test.com" -b 01/01/2012 -e 01/01/2014 -ss my -sr currentuser -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12

    This creates a certificate using SHA1, which is the only hashing algorithm I could get to work for Java and .NET.  Anything with SHA256 wouldn't work.

    2. I copied the key to the trusted people location on the client server.

    3. I imported the key into my java keystore on the server.

    4. I changed my .NET code to use a custom binding and the Basic128RSA15 algorithm suite and defined my authentication mode as MutualCertificateDuplex.

    5. I set up both my Spring WSS and WCF to sign before encrypt and to include both the timestamp and username token.  Here is what my Spring configuration looks like:

    <xwss:RequireTimestamp maxClockSkew="60"/>
     <xwss:RequireUsernameToken passwordDigestRequired="false" nonceRequired="false"/>

    <!-- Setting xwss:RequireSignature requires that this request in signed -->
        <xwss:RequireSignature requireTimestamp="false">
     <xwss:SymmetricKey keyAlias="misg"/> <!-- the keyAlias must match RSA key alias defined in the keystore -->      
         <xwss:SignatureTarget type= "qname" value="{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}UsernameToken" />
     <xwss:SignatureTarget type= "qname" value="{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp" />
     <xwss:SignatureTarget type="qname" value="{http://schemas.xmlsoap.org/soap/envelope/}Body" />
        </xwss:RequireSignature>

    and my WCF looks like this:

    <bindings>
          <customBinding>
            <binding name="CIMarketingIntegrationServiceSoapBinding">
              <security defaultAlgorithmSuite="Basic128Rsa15" keyEntropyMode="ClientEntropy" enableUnsecuredResponse="true" authenticationMode="MutualCertificateDuplex" requireDerivedKeys="false" includeTimestamp="true" messageProtectionOrder="SignBeforeEncrypt" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11"  requireSecurityContextCancellation="true" requireSignatureConfirmation="false">
                <secureConversationBootstrap/>
              </security>
              <textMessageEncoding messageVersion="Soap11"/>
              <httpTransport/>
              <!--<httpsTransport maxReceivedMessageSize="2000000000" />-->
            </binding>
          </customBinding>
        </bindings>

    In my WCF code, I look up my certificate and I also apply the credentials. To add the usename token to the message (since MutualCertificateDuplex doesn't do that), I added this code:

    // Reference the asymmetric security element and sign the security tokens
    AsymmetricSecurityBindingElement securityBindingElement = bindingCust.Elements.Find<AsymmetricSecurityBindingElement>();
    UserNameSecurityTokenParameters tokenParameters = new UserNameSecurityTokenParameters();
    tokenParameters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
    tokenParameters.RequireDerivedKeys = false;

    //Signs the username token
    securityBindingElement.EndpointSupportingTokenParameters.Signed.Add(tokenParameters);

    So a couple of things to note.  The MutualCertificateDuplex is asymmetric, so it's using the asymmetric algorithm stated in the link I provided above.  I also don't have encryption enabled yet. I'm still working on the proper way to add that so it can be consumed by Spring. Until then we will use SSL.   I have no idea what your configuration requirements are, but I figured I'd put all of the details of what I had to do out there just in case it can help someone else. It took far longer than it should've to get WCF communicating with a non-.NET server. Hope at least some of this helps, let me know if you have questions.

    Thursday, June 13, 2013 4:09 PM
  • Hi gryphon99,

    thanks for the post, it's good to see things do work cross-platform!!

    I think the specific issue in my case is that when using the "Basic128Sha256Rsa15" Algorithm Suite, there is an error in the .NET implementation where the Digital Signature method is specified as RSA-SHA-256 instead of RSA-SHA-1. The problem being that the .NET implementation does not adhere to WS Security protocols and therefore is not cross-platform compatible. I suspect this is also the reason you couldn't get things to work with your Java service when using SHA256.

    In my case, the Java web service I am interacting with is owned by a third party and their service completely adheres to WS Security standards. However, due to the issue with "Basic128Sha256Rsa15" I cannot seem to get WCF to work with the service. I also cannot see any obvious way to override this and make it compatible, hence the query to Microsoft to see if this is a know issue. I cannot believe it is by design that WCF contains an Algorithm Suite specifically listed for use with WS Security that is then incompatible with the WS Security standard itself.

    In your example where you got it to work, you are using "Basic128Rsa15" which doesn't suffer from the same issue because it uses SHA-1 for everything. That's why it works with your Java code. But in my case, I cannot dictate the settings of the server side as the third party already provides this service and (quite rightly) why should they change away from the documented standard.

    I also have another issue with WCF in .NET in that it doesn't seem possible to encrypt individual elements within the <soap:Body>, rather it is only possible to encrypt the entire <soap:Body> or not. One final issue so far (which I have in a separate thread) is that the .NET implementation of C14N canonicalization also seems to be non-standard!! These two issues are completely unrelated to the problem with the Algorithm Suite, but I have only just started to use WCF and so far have found at least 3 items which are incompatible with defined W3C standards, which doesn't bode well for interoperability.

    I suspect once you start to get encryption and signing working fully you may encounter similar issues if you are connecting to Java.

    Hopefully MSFT will be able to shed some light on this issue once one of the engineers has taken a look at this thread.

    Thursday, June 13, 2013 9:33 PM
  • Haixia,

    is there any update from MSFT on this please? Nearly 1 month ago it was stated that Microsoft engineers were getting involved to review, but still we have no update? This clearly sounds like a bug because the WCF specifications for this algorithm suite are not the same as the WS Security specification, which makes it incompatible with the WS Security framework and therefore inoperable with non-.NET frameworks.

    Are you able to confirm if this is a bug on the .NET code, and if it is then when a fix is likely to be released? In the meantime, what is the workaround for generating WS Security compliant web services please?

    Thanks.

    Thursday, July 4, 2013 9:04 PM
  • Hi there.
    This can be done by using a custom Crypto Algorithm:
    http://msdn.microsoft.com/en-us/library/gg617968.aspx/

    I've tested this and it does work.
    Create it using Basic128Sha256Rsa15 as a base but change the DefaultAsymmetricSignatureAlgorithm.

    So it would look something like this:


        public class Basic128Sha256Rsa15Sha1AlgorithmSuite : SecurityAlgorithmSuite
        {
            public override string DefaultAsymmetricKeyWrapAlgorithm
            {
                get { return SecurityAlgorithmSuite.Basic128Sha256Rsa15.DefaultAsymmetricKeyWrapAlgorithm; }
            }

            public override string DefaultAsymmetricSignatureAlgorithm
            {
                get { return SecurityAlgorithms.RsaSha1Signature; }
            }

            public override string DefaultCanonicalizationAlgorithm
            {
                get { return SecurityAlgorithmSuite.Basic128Sha256Rsa15.DefaultCanonicalizationAlgorithm; }
            }
    ....


    Plug it in like this (using a custom binding in this case):

            static IEnumerable<BindingElement> GetBindingElements()
            {
                AsymmetricSecurityBindingElement sec = (AsymmetricSecurityBindingElement)AsymmetricSecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10);
                sec.SetKeyDerivation(false);
                //sec.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic128Sha256Rsa15;
                sec.DefaultAlgorithmSuite = new ScottsAlgorithmSuite.Basic128Sha256Rsa15Sha1AlgorithmSuite();
                OutputSecurityAlgorithms(sec.DefaultAlgorithmSuite);
                sec.MessageProtectionOrder = MessageProtectionOrder.EncryptBeforeSign;
                TextMessageEncodingBindingElement enc = new TextMessageEncodingBindingElement(MessageVersion.Soap12WSAddressing10, Encoding.UTF8);
                HttpTransportBindingElement trans = new HttpTransportBindingElement();

                List<BindingElement> belmnts = new List<BindingElement>();

                belmnts.Add(sec);
                belmnts.Add(enc);
                belmnts.Add(trans);
                return belmnts;
            }


            static void OutputSecurityAlgorithms(SecurityAlgorithmSuite suite)
            {
                Console.WriteLine("DefaultAsymmetricKeyWrapAlgorithm\t" + suite.DefaultAsymmetricKeyWrapAlgorithm);
                Console.WriteLine("DefaultAsymmetricSignatureAlgorithm\t" + suite.DefaultAsymmetricSignatureAlgorithm);
                Console.WriteLine("DefaultCanonicalizationAlgorithm\t" + suite.DefaultCanonicalizationAlgorithm);
                Console.WriteLine("DefaultDigestAlgorithm\t" + suite.DefaultDigestAlgorithm);
                Console.WriteLine("DefaultEncryptionAlgorithm\t" + suite.DefaultEncryptionAlgorithm);
                Console.WriteLine("DefaultEncryptionKeyDerivationLength\t" + suite.DefaultEncryptionKeyDerivationLength);
                Console.WriteLine("DefaultSignatureKeyDerivationLength\t" + suite.DefaultSignatureKeyDerivationLength);
                Console.WriteLine("DefaultSymmetricKeyLength\t" + suite.DefaultSymmetricKeyLength);
                Console.WriteLine("DefaultSymmetricKeyWrapAlgorithm\t" + suite.DefaultSymmetricKeyWrapAlgorithm);
                Console.WriteLine("DefaultSymmetricSignatureAlgorithm\t" + suite.DefaultSymmetricSignatureAlgorithm);
            }


    Looking at my traces when I just use Basic128Sha256Rsa15 it comes out like this:

    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
       <SignedInfo>
          <CanonicalizationMethod Algorithm="</CanonicalizationMethod">http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
          <SignatureMethod Algorithm="</SignatureMethod">http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"></SignatureMethod>
          <Reference URI="#_2">
             <Transforms>
                <Transform Algorithm="</Transform">http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
             </Transforms>
    ....

    When using the custom one it comes out like this:

    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
       <SignedInfo>
          <CanonicalizationMethod Algorithm="</CanonicalizationMethod">http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
          <SignatureMethod Algorithm="</SignatureMethod">http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
          <Reference URI="#_2">
             <Transforms>
                <Transform Algorithm="</Transform">http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
             </Transforms>
    ....

    Hope that helps.
    Thanks,
    Scott


    MS Developer Support

    Thursday, August 8, 2013 1:18 AM
  • Hi scott,

    I've tested with your sample code. i modified the following,

    public override string DefaultAsymmetricKeyWrapAlgorithm
            {
                get { return SecurityAlgorithmSuite.Basic128Sha256Rsa15.DefaultAsymmetricKeyWrapAlgorithm; }
            }

            public override string DefaultAsymmetricSignatureAlgorithm
            {
                get { return SecurityAlgorithms.RsaSha256Signature; }
            }

    ..........

    in my SOAP request (captured from fiddler)

    its show the default algorithm only we overriding sha-1 into sha-256 but we couldn't get.

    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>

    but instead of that i need like this

    Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"

    Thanks in advace

    ------

    Thanks,

    Marudu

    Wednesday, October 30, 2013 3:49 PM