SignedXml.CheckSignature very slow!

Discussion in 'Microsoft Dot NET Framework' started by Ulrich Proeller, Feb 23, 2008.

  1. When trying to verify the signature of a SignedXml object, the call to
    SignedXml.CheckSignature(rsaKey) takes up to 20 seconds. Obviously this
    happens only, if the machine on which the code is running is member of a
    windows domain.
    I tried to debug into the .NET Framework code and found, that the delay
    happens in X509Utils._GetOidFromFriendlyName(name).
    There is an issue reported in KB948080 which describes the reported
    behavior. In the article, it is recommended to use
    RSACryptoProvider.VerifyHash() instead of RSACryptoProvider.VerifyData().
    How can I accomplish that when using a SignedXml object?

    Thanks in advance for any idea!
     
    Ulrich Proeller, Feb 23, 2008
    #1
    1. Advertisements

  2. Ulrich Proeller wrote:
    > When trying to verify the signature of a SignedXml object, the call to
    > SignedXml.CheckSignature(rsaKey) takes up to 20 seconds. Obviously this
    > happens only, if the machine on which the code is running is member of a
    > windows domain.
    > I tried to debug into the .NET Framework code and found, that the delay
    > happens in X509Utils._GetOidFromFriendlyName(name).
    > There is an issue reported in KB948080 which describes the reported
    > behavior. In the article, it is recommended to use
    > RSACryptoProvider.VerifyHash() instead of RSACryptoProvider.VerifyData().
    > How can I accomplish that when using a SignedXml object?
    >

    Well, obviously you can't modify the implementation of SignedXml, but it
    should be possible to avoid the call to X509Utils._GetOidFromFriendlyName().
    This call is coming from CryptoConfig.MapNameToOID(), which, I'm guessing
    (but if you could provide a stack trace, please be so kind), is called from
    X509Utils.OidToAlgId(), which in turn is called from
    RSAPKCS1SignatureDeformatter.VerifySignature() <-
    SignedXml.CheckSignedInfo() <- SignedXml.CheckSignature().

    There's a bug in how X509Utils.OidToAlgId() and CryptoConfig.MapNameToOID()
    interact. CryptoConfig.MapNameToOID() uses two lookup tables, the default
    lookup table and the machine lookup table, to match friendly names to OIDs.
    The machine table is normally empty, and the default lookup table contains
    mappings from all standard .NET algorithm names to OIDs. If both lookups
    fail, .MapNameToOID() issues a domain query to resolve the name.

    Now, X509Utils.OidToAlgId() calls CryptoConfig.MapNameToOID() with an *OID*
    rather than a name, but the latter doesn't know how to handle OIDs. The
    default lookup table doesn't contain any OIDs, it contains names. You don't
    need a lookup call to match an OID to an OID, after all! Therefore, *any*
    call to X509Utils.OidToAlgId() using an OID will invoke a domain query,
    hence the slowdown.

    That's the long and boring explanation, now on to the solution. The machine
    lookup table is editable. If you add "mappings" from OIDs to OIDs, the
    slowdown should disappear. The relevant section is in the machine.config of
    the framework directory.

    The following should do the trick for all framework-implemented hash
    algorithms (it does not include third-party ones):

    <configuration>
    <mscorlib>
    <cryptographySettings>
    <oidMap>
    <!-- Brought to you by the department of redundancy department -->
    <oidEntry OID="1.2.840.113549.2.5" name="1.2.840.113549.2.5"/>
    <!-- MD5 -->
    <oidEntry OID="1.3.36.3.2.1" name="1.3.36.3.2.1"/> <!--
    RIPEMD160 -->

    <oidEntry OID="1.3.14.3.2.26" name="1.3.14.3.2.26"/> <!-- SHA1 -->
    <oidEntry OID="2.16.840.1.101.3.4.2.1"
    name="2.16.840.1.101.3.4.2.1"/> <!-- SHA256 -->
    <oidEntry OID="2.16.840.1.101.3.4.2.2"
    name="2.16.840.1.101.3.4.2.2"/> <!-- SHA384 -->
    <oidEntry OID="2.16.840.1.101.3.4.2.3"
    name="2.16.840.1.101.3.4.2.3"/> <!-- SHA512 -->
    </oidMap>
    </cryptographySettings>
    </mscorlib>
    </configuration>

    If this turns out to be of any help to you, please let us know; I'd be
    interested in the results -- in particular if I'm right, because I haven't
    tested any of this, but also if this just set you on the right track.

    --
    J.
     
    Jeroen Mostert, Feb 24, 2008
    #2
    1. Advertisements

  3. Hello Jeroen,

    your guess concerning the callstack is right and the proposed entries in the
    machine.config fixed the problem on my machine.
    Thank you very much!
    This code is running when our application is trying to validate its license
    file. Naturally, no one who bought the product want to be punished with a 20
    seconds extra wait time. So is it harmless that the installer of the
    application enters this entries in the machine.config file of all of our
    customers?

    Kind regards

    Ulrich
     
    Ulrich Proeller, Feb 24, 2008
    #3
  4. Ulrich Proeller wrote:
    > your guess concerning the callstack is right and the proposed entries in the
    > machine.config fixed the problem on my machine.
    > Thank you very much!


    Great! You can thank Lutz Roeder and his Reflector for this too. And the
    fact that I'm too lazy to use a debugger. :)

    > This code is running when our application is trying to validate its license
    > file. Naturally, no one who bought the product want to be punished with a 20
    > seconds extra wait time. So is it harmless that the installer of the
    > application enters this entries in the machine.config file of all of our
    > customers?
    >

    I would say yes. Although these entries will obviously affect every
    application using the crypto functions, literally the worst thing that can
    happen is that none of them suffer slowdowns while looking up OIDs. There is
    no legitimate reason for applications to add alternate OID mappings that
    don't match yours, so application compatibility shouldn't be affected either.

    You *do* have to take care not to add these entries more than once, since
    this could have unexpected side-effects (I haven't checked whether it does
    nothing or causes a runtime error, but it's best not to count on this
    behavior anyway). Make sure to have your installer check that you do not add
    a mapping whose name already exists.

    Finally, it's possible that Microsoft will one day bring out a patch for
    this problem itself that will not cooperate nicely with these extra entries,
    and if that happens your application might break. I suggest reporting this
    problem (and your fix) to Microsoft Support as well, to lessen the chances
    of this.

    --
    J.
     
    Jeroen Mostert, Feb 24, 2008
    #4
  5. Thank you very much! This anwered all my questions.

    Ulrich
     
    Ulrich Proeller, Mar 6, 2008
    #5
  6. Ulrich Proeller

    mratwork

    Joined:
    Jan 21, 2009
    Messages:
    1
    Likes Received:
    0
    Hi, allthough almost a year later, the problem still exists and it brought me trouble. So i decided to give this a chance.

    Yes, altering machine.config does work, but the problem is that I think it's too unreliable altering machine.config from within some setup package. In my case, I use SignedXml in a Winforms application, which is distributed to customers.

    So, I found another solution which will work in case there is ReflectionPermission and SecurityPermission available. This solution makes use of reflection to duplicate the Hashtable defaultOidHT in CryptoConfig.
    basically, it does the same as altering machine.config, but it does so for all Name / Oids pairs (well, i found out that for some Oids, there are more Names which map to it, hence the guard before adding to the Hashtable).

    Enjoy!!!

    class SignedXmlUser
    {
    static SignedXmlUser
    {
    try
    {

    Type cryptoConfigType = typeof(CryptoConfig);
    BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;

    // First retrieve the value of the property CryptoConfig.DefaultOidHT. This will initialize
    // the Hashtable defaultOidHT (the static field)
    PropertyInfo propertyInfo = cryptoConfigType.GetProperty("DefaultOidHT", flags);
    propertyInfo.GetValue(null, null);

    // Second, retrieve the value of the field defaultOidHT (the Hashtable)
    FieldInfo fieldInfo = cryptoConfigType.GetField("defaultOidHT", flags);
    Hashtable defaultOidHT = fieldInfo.GetValue(null) as Hashtable;

    if (defaultOidHT != null)
    {
    Hashtable copy = new Hashtable(defaultOidHT);
    foreach (DictionaryEntry entry in copy)
    {
    if (!defaultOidHT.ContainsKey(entry.Value))
    defaultOidHT.Add(entry.Value, entry.Value);
    }
    }
    }
    catch (Exception ex)
    {

    }
    }

    private void CheckSignedXml
    {
    ...
    signedXml.CheckSignature(...)
    ...
    }

    }
     
    mratwork, Jan 21, 2009
    #6
  7. Ulrich Proeller

    philsoft

    Joined:
    Jan 7, 2011
    Messages:
    1
    Likes Received:
    0
    mratwork
    Dude, u rock!!!!!! u really saved my butt!!!
     
    philsoft, Jan 7, 2011
    #7
    1. Advertisements

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Robert Hooker
    Replies:
    2
    Views:
    869
    Yan-Hong Huang[MSFT]
    Sep 29, 2003
  2. Guest

    checksignature always returning false

    Guest, Apr 10, 2006, in forum: Microsoft Dot NET Framework
    Replies:
    3
    Views:
    1,172
    Kevin Yu [MSFT]
    Apr 12, 2006
  3. Guest

    SignedXml class incompatibility?

    Guest, May 23, 2006, in forum: Microsoft Dot NET Framework
    Replies:
    0
    Views:
    242
    Guest
    May 23, 2006
  4. Guest

    SignedXml CheckSignature()

    Guest, Jul 10, 2006, in forum: Microsoft Dot NET Framework
    Replies:
    2
    Views:
    618
    Guest
    Jul 10, 2006
  5. --- .NET Em ---

    SignedXml not found in .net 2.0 ?

    --- .NET Em ---, Oct 5, 2006, in forum: Microsoft Dot NET Framework
    Replies:
    1
    Views:
    811
    --- .NET Em ---
    Oct 5, 2006
Loading...

Share This Page