Tuesday, April 20, 2010

Interoperability Gotcha: OAEP Parameterization is not supported

@YaronNaveh

WSE2 is already obsolete but I still see people trying to reach interoperability from WSE2 to WCF. Surprisingly there are a number of interesting ws-security scenarios where this is possible. Today I will discuss one scenario where it may be harder.

WSE configuration allows to configure the algorithms we use for encryption:


<microsoft.web.services2>
...
     <keyAlgorithm name="RSA15" />
...
</microsoft.web.services2>


Some scenarios work great with RSA15 but when we change it to RSAOAEP we may see this exception from the WSE party:


OAEP Parameterization is not supported


Let's see what in the message that WCF sent to WSE may cause this:


<e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
  <e:EncryptionMethod   Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
      <DigestMethod       Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"       xmlns="http://www.w3.org/2000/09/xmldsig#" />
  </e:EncryptionMethod>
</EncryptedKey>


We can see that the encryptedKey is indeed encrypted with the RSAOAEP algorithm. Also the RSAOAEP RFC states that:


The RSAES-OAEP-ENCRYPT algorithm... takes three parameters. The two user specified parameters are [MANDATORY]... The message digest function is indicated by the Algorithm attribute of a child ds:DigestMethod element...


Hence the DigestMethod element.

So why WSE throws an exception when a mandatory parameter is specified? Let's look at a WSE generated message to see if it produces anything different:


<e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
  <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
    <ds:DigestMethod     xmlns:ds="http://www.w3.org/2000/09/xmldsig#"     Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
  </e:EncryptionMethod>
</EncryptedKey>


Looks the same to me. So let's drill down into the WSE stack to understand the root cause. The error seems to be thrown from within this method:


public override void set_Parameters(string value)
{
   if (((value != null) && (value.Length != 0)) && (value != this._parameters))
   {
     throw new NotSupportedException("OAEP Parameterization is not supported");
   }
}


Ok so we are comparing the current message parameters (value) to some default value (this._parameters). But what is this default? Let's look in the ctor:


public RSAOAEPKeyExchangeFormatter()
{
   this._parameters = "";
}


Oh boy. WSE2 compares xml fragments as strings! So it sees this:


<DigestMethod xmlns="http://www.w3.org/2000/09/xmldsig#" />


as different from this:


<ds:DigestMethod xmlns:ds="http://www.w3.org/2000/09/xmldsig#" />


While the above fragments have the same xml semantics.

Just in order to convince my self this is the issue, I have manually changed the soap so that it will have the WSE-style digest. This worked like a charm. This kind of gives us the general solution here which is to build a WSE filter that changes the soap format to the one WSe expects. Note that you can only change non-signed soap parts, which is usually the case with the encrypted key. The easier option of course is to revert to the RSA15 algorithm.

And let's not forget the main point which is to never compare xml as a string.

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

Sunday, April 4, 2010

Wcf first connection is slow

@YaronNaveh

You may have experienced the first connection from a Wcf client to a service to be extremely slow. In some cases this is expected as the first connection establishes a session which may require exchange of multiple messages. However in some cases there is no obvious reason for that.

One cause may be a slow http proxy. By default, Wcf uses the default http proxy configured in internet explorer. The proxy may be specified directly or in form of a configuration script:





If this is the cause of the slowness you can reproduce it by surfing to any site using a new IE instance - same slowness should occur.

The possible solutions are:

1. Remove the proxy configuration from IE.
2. Configure your WCF binding with UseDefaultProxy=false.

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

Friday, April 2, 2010

Quiz #2 - The answer (goto in c#)

@YaronNaveh

A few days ago I published the below reflector generated code:


private void NoGoto()
{
     int i = 0;
     if (i == 0)
     {
         switch (i)
         {
             case 0:
             case 1:
             goto Label_002C; //WTF?!
         }
         i--;
     }
    Label_002C:
         i++;
}


And asked what was the original code. Well, here it is:



void NoGoTo()
{
        int i = 0;
        if (i==0)
        {
            switch (i)
            {
                case 0:
                    break;
                case 1:
                    break;
                default:
                    i-- ;
                    break;
            }
        }

        i++;
}


no goto at all.

Liran and an anonymous reader corresponded that goto may not be that bad in all cases. They are right, loop controls such as break and continue are disguised goto's. Liran also mentioned the multi-level breaks in Java which satisfy some of the goto possible use cases. For me all of these are an attempt to capture the 'good' goto use cases and keep our code clean from possible abuse of the generic flavor.

My motivation for the whole inquiry was seeing a lot of goto's in framework code using the reflector. One example is BasicHttpMessageSecurity.CreateMessageSecurity(). I wanted to make sure I am up to the times with the latest coding fashions. When I have downloaded the WCF sources locally to debug them I no no sign of goto.

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

Thursday, April 1, 2010

Remember to compare Url's with System.Uri

@YaronNaveh

When you need to compare two Url's never trust on simple string comparison. Always use a comparison that takes semantics into consideration. In C#, System.Uri can be used. Check the below:


string url1 = "http://www.site.com/dir/index.html";
string url2 = "http://www.site.com/dir/dir1/../index.html";

url1 == url2; //false
new Uri(url1).Equals(url2); //true


And another one:


string url1 = "http://www.site.com/index.html?q=1 2";
string url2 = "http://www.site.com/index.html?q=1%202";

url1 == url2; //false
new Uri(url1).Equals(url2); //true

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!