Bug 13953 - RSACryptoServiceProvider.SignData() doesn't support OID providers
Summary: RSACryptoServiceProvider.SignData() doesn't support OID providers
Status: RESOLVED FIXED
Alias: None
Product: Class Libraries
Classification: Mono
Component: System.Security ()
Version: unspecified
Hardware: PC Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2013-08-13 10:44 UTC by Jonathan Pryor
Modified: 2013-08-13 12:12 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Proposed Patch (1.08 KB, patch)
2013-08-13 10:57 UTC, Jonathan Pryor
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Jonathan Pryor 2013-08-13 10:44:17 UTC
RSACryptoServiceProvider.SignData() doesn't support using OID names for provider names. This is documented at MSDN:

http://msdn.microsoft.com/en-us/library/y2wf1b6k.aspx

> The halg parameter can accept a String, a HashAlgorithm, or a Type.
> The string value can be one of the following:
> * The object identifier (OID) friendly name of the hash algorithm to use,
>   either a name registered in the crypto config file or one in the 
>   Crypto API OID table.
> * The OID value. The OID must be one recognized by the Crypto API.
> For example, you could use SignData(new byte[5], "1.3.14.3.2.26") or 
> SignData(new byte[5], "sha1"), or SignData(new byte[5], "SHA1").

Sample program:

  using System;
  using System.Security.Cryptography;
  using System.Linq;

  class Test {
    public static void Main ()
    {
      string oid = CryptoConfig.MapNameToOID ("SHA256");
      Console.WriteLine ("oid: {0}", oid);
      object provider = CryptoConfig.CreateFromName (oid);
      Console.WriteLine ("provider? {0} [{1}]", provider != null,
          provider == null ? "" : provider.GetType ().FullName);
      using (var rsa = new RSACryptoServiceProvider (2048)) {
        var d = rsa.SignData (new byte[]{1,2,3,4}, oid);
        Console.WriteLine ("d={0}",
            string.Join (" ", d.Select (b => b.ToString ("x2"))));
      }
    }
  }

Actual output:

> $ mono cc.exe 
> oid: 2.16.840.1.101.3.4.2.1
> provider? False []
> 
> Unhandled Exception:
> System.NullReferenceException: Object reference not set to an instance of an object
>   at System.Security.Cryptography.RSACryptoServiceProvider.SignData (System.Byte[] buffer, Int32 offset, Int32 count, System.Object halg) [0x00000] in <filename unknown>:0 
>   at System.Security.Cryptography.RSACryptoServiceProvider.SignData (System.Byte[] buffer, System.Object halg) [0x00000] in <filename unknown>:0 
>   at Test.Main () [0x00000] in <filename unknown>:0 

Expected output (from .NET):

  oid: 2.16.840.1.101.3.4.2.1
  provider? False []
  d=d0 5f c5 5d b3 fc 0c 91 17 47 ad e7 59 a4 09 c2 65 24 8f bd cf 3e 64 e8 d6
    fe 8a b2 89 61 a2 af d5 20 0e 49 67 aa 50 0c dd 90 6c 96 ff c7 ce 4e 0d 29
    81 bd 33 b6 f6 eb 71 79 d5 bb d9 ae 0c 5b 73 01 8b 9d 2e ac 4c a3 ae c5 7f
    4a 8a c1 b5 db 3f d4 80 42 65 2a d9 ce 39 02 1a 62 e6 90 2b d9 d6 70 2b 29
    df 9c 0d 96 b7 c4 6b a0 57 af c7 69 21 6c fe 74 5e a2 36 a7 af e0 c9 b8 65
    d7 3d 28 d6 f3 f2 25 31 cd e8 09 98 0f 27 04 2d fb 01 3e 30 e5 9d 52 b5 4b
    05 33 0f b6 2f ad 1c 34 18 42 37 0e 49 68 7f 35 88 2d 68 d2 19 b1 8c 39 dd
    a6 2e b7 ba 5d 55 1b 29 a2 c8 6f a9 a9 d1 29 08 e9 d3 32 10 34 27 a5 dc fd
    c0 1c 62 f1 4d 4d 76 31 28 d2 26 0c 05 ff eb 93 4c 93 08 e7 b6 28 e6 99 3c
    91 ad ac d6 e0 c5 44 a5 d2 68 fa ed f6 91 30 24 c5 06 29 9b 5e 6a 97 bc 51
    c2 75 9e f6 17 91
Comment 1 Jonathan Pryor 2013-08-13 10:47:39 UTC
Aside: Perhaps RSACryptoServiceProvider.GetHash() should check that it doesn't return null?

https://github.com/mono/mono/blob/01c8c99e/mcs/class/corlib/System.Security.Cryptography/RSACryptoServiceProvider.cs#L231

Perhaps with:

    if (hash == null)
        throw new ArgumentException ("Could not find provider for halg='" + halg + "'.", "halg");
Comment 3 Jonathan Pryor 2013-08-13 10:57:19 UTC
Created attachment 4618 [details]
Proposed Patch
Comment 4 Sebastien Pouliot 2013-08-13 11:06:03 UTC
Looks fine but could you add:

a. a unit test that use an OID (like above);

b. a unit test that use an invalid OID to see if .NET throws an ArgumentException (or another exception, like a CryptographicException) or default to something (like SHA1)
Comment 5 Jonathan Pryor 2013-08-13 12:12:15 UTC
Fixed in mono/bd130f3a.