2008-03-13 Sebastien Pouliot <sebastien@ximian.com>
authorSebastien Pouliot <sebastien@ximian.com>
Fri, 14 Mar 2008 00:40:40 +0000 (00:40 -0000)
committerSebastien Pouliot <sebastien@ximian.com>
Fri, 14 Mar 2008 00:40:40 +0000 (00:40 -0000)
* CryptoConvert.cs: Re-order exception handling to report the most
precise error to caller. Apply RSA extra check to DSA.
* RSAManaged.cs: Test imported parameters to ensure the public and
private parts of the keypair match together.

svn path=/trunk/mcs/; revision=98226

mcs/class/Mono.Security/Mono.Security.Cryptography/ChangeLog
mcs/class/Mono.Security/Mono.Security.Cryptography/CryptoConvert.cs
mcs/class/Mono.Security/Mono.Security.Cryptography/RSAManaged.cs

index 412425fb084e4f84f5df8a51277b32c53e9b2e64..bcdd26d895c0d340a3697fa3fbae2fb0c71f2eea 100644 (file)
@@ -1,3 +1,10 @@
+2008-03-13  Sebastien Pouliot  <sebastien@ximian.com>
+
+       * CryptoConvert.cs: Re-order exception handling to report the most
+       precise error to caller. Apply RSA extra check to DSA.
+       * RSAManaged.cs: Test imported parameters to ensure the public and 
+       private parts of the keypair match together.
+
 2008-03-04  Sebastien Pouliot  <sebastien@ximian.com>
 
        * SymmetricTransform.cs: Sync with corlib. Fix ANSIX923 padding check
index 52377e4b696f4589d76043d79155c7b84250a649..9a3ae26563340a5e5bda4d4d389524779e05ba13 100644 (file)
@@ -92,6 +92,7 @@ namespace Mono.Security.Cryptography {
                        if (offset >= blob.Length)
                                throw new ArgumentException ("blob is too small.");
 
+                       RSAParameters rsap = new RSAParameters ();
                        try {
                                if ((blob [offset]   != 0x07) ||                                // PRIVATEKEYBLOB (0x07)
                                    (blob [offset+1] != 0x02) ||                                // Version (0x02)
@@ -107,7 +108,6 @@ namespace Mono.Security.Cryptography {
                                int bitLen = ToInt32LE (blob, offset+12);
 
                                // DWORD public exponent
-                               RSAParameters rsap = new RSAParameters ();
                                byte[] exp = new byte [4];
                                Buffer.BlockCopy (blob, offset+16, exp, 0, 4);
                                Array.Reverse (exp);
@@ -161,26 +161,32 @@ namespace Mono.Security.Cryptography {
                                        Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen);
                                        Array.Reverse (rsap.D);
                                }
+                       }
+                       catch (Exception e) {
+                               throw new CryptographicException ("Invalid blob.", e);
+                       }
 
-                               RSA rsa = null;
+                       RSA rsa = null;
+                       try {
+                               rsa = RSA.Create ();
+                               rsa.ImportParameters (rsap);
+                       }
+                       catch (CryptographicException ce) {
+                               // this may cause problem when this code is run under
+                               // the SYSTEM identity on Windows (e.g. ASP.NET). See
+                               // http://bugzilla.ximian.com/show_bug.cgi?id=77559
                                try {
-                                       rsa = RSA.Create ();
-                                       rsa.ImportParameters (rsap);
-                               }
-                               catch (CryptographicException) {
-                                       // this may cause problem when this code is run under
-                                       // the SYSTEM identity on Windows (e.g. ASP.NET). See
-                                       // http://bugzilla.ximian.com/show_bug.cgi?id=77559
                                        CspParameters csp = new CspParameters ();
                                        csp.Flags = CspProviderFlags.UseMachineKeyStore;
                                        rsa = new RSACryptoServiceProvider (csp);
                                        rsa.ImportParameters (rsap);
                                }
-                               return rsa;
-                       }
-                       catch (Exception e) {
-                               throw new CryptographicException ("Invalid blob.", e);
+                               catch {
+                                       // rethrow original, not the later, exception if this fails
+                                       throw ce;
+                               }
                        }
+                       return rsa;
                }
 
                static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob)
@@ -195,6 +201,7 @@ namespace Mono.Security.Cryptography {
                        if (offset >= blob.Length)
                                throw new ArgumentException ("blob is too small.");
 
+                       DSAParameters dsap = new DSAParameters ();
                        try {
                                if ((blob [offset] != 0x07) ||                          // PRIVATEKEYBLOB (0x07)
                                    (blob [offset + 1] != 0x02) ||                      // Version (0x02)
@@ -204,7 +211,6 @@ namespace Mono.Security.Cryptography {
                                        throw new CryptographicException ("Invalid blob header");
 
                                int bitlen = ToInt32LE (blob, offset + 12);
-                               DSAParameters dsap = new DSAParameters ();
                                int bytelen = bitlen >> 3;
                                int pos = offset + 16;
 
@@ -235,14 +241,32 @@ namespace Mono.Security.Cryptography {
                                Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
                                Array.Reverse (dsap.Seed);
                                pos += 20;
-
-                               DSA dsa = (DSA)DSA.Create ();
-                               dsa.ImportParameters (dsap);
-                               return dsa;
                        }
                        catch (Exception e) {
                                throw new CryptographicException ("Invalid blob.", e);
                        }
+
+                       DSA dsa = null;
+                       try {
+                               dsa = (DSA)DSA.Create ();
+                               dsa.ImportParameters (dsap);
+                       }
+                       catch (CryptographicException ce) {
+                               // this may cause problem when this code is run under
+                               // the SYSTEM identity on Windows (e.g. ASP.NET). See
+                               // http://bugzilla.ximian.com/show_bug.cgi?id=77559
+                               try {
+                                       CspParameters csp = new CspParameters ();
+                                       csp.Flags = CspProviderFlags.UseMachineKeyStore;
+                                       dsa = new DSACryptoServiceProvider (csp);
+                                       dsa.ImportParameters (dsap);
+                               }
+                               catch {
+                                       // rethrow original, not the later, exception if this fails
+                                       throw ce;
+                               }
+                       }
+                       return dsa;
                }
 
                static public byte[] ToCapiPrivateKeyBlob (RSA rsa) 
index 15b27b5e8d975164b037181bf22af89719eed30c..29ee75a21ced7c9ee8d28fe8ce1b0a1fd1271057 100644 (file)
@@ -297,9 +297,9 @@ namespace Mono.Security.Cryptography {
 
                        // if missing "mandatory" parameters
                        if (parameters.Exponent == null) 
-                               throw new CryptographicException ("Missing Exponent");
+                               throw new CryptographicException (Locale.GetText ("Missing Exponent"));
                        if (parameters.Modulus == null)
-                               throw new CryptographicException ("Missing Modulus");
+                               throw new CryptographicException (Locale.GetText ("Missing Modulus"));
        
                        e = new BigInteger (parameters.Exponent);
                        n = new BigInteger (parameters.Modulus);
@@ -316,10 +316,44 @@ namespace Mono.Security.Cryptography {
                                p = new BigInteger (parameters.P);
                        if (parameters.Q != null)
                                q = new BigInteger (parameters.Q);
-                       
+
                        // we now have a keypair
                        keypairGenerated = true;
-                       isCRTpossible = ((p != null) && (q != null) && (dp != null) && (dq != null) && (qInv != null));
+                       bool privateKey = ((p != null) && (q != null) && (dp != null));
+                       isCRTpossible = (privateKey && (dq != null) && (qInv != null));
+
+                       // check if the public/private keys match
+                       // the way the check is made allows a bad D to work if CRT is available (like MS does, see unit tests)
+                       if (!privateKey)
+                               return;
+
+                       // always check n == p * q
+                       bool ok = (n == (p * q));
+                       if (ok) {
+                               // we now know that p and q are correct, so (p - 1), (q - 1) and phi will be ok too
+                               BigInteger pSub1 = (p - 1);
+                               BigInteger qSub1 = (q - 1);
+                               BigInteger phi = pSub1 * qSub1;
+                               // e is fairly static but anyway we can ensure it makes sense by recomputing d
+                               BigInteger dcheck = e.ModInverse (phi);
+
+                               // now if our new d(check) is different than the d we're provided then we cannot
+                               // be sure if 'd' or 'e' is invalid... (note that, from experience, 'd' is more 
+                               // likely to be invalid since it's twice as large as DP (or DQ) and sits at the
+                               // end of the structure (e.g. truncation).
+                               ok = (d == dcheck);
+
+                               // ... unless we have the pre-computed CRT parameters
+                               if (!ok && isCRTpossible) {
+                                       // we can override the previous decision since Mono always prefer, for 
+                                       // performance reasons, using the CRT algorithm
+                                       ok = (dp == (dcheck % pSub1)) && (dq == (dcheck % qSub1)) && 
+                                               (qInv == q.ModInverse (p));
+                               }
+                       }
+
+                       if (!ok)
+                               throw new CryptographicException (Locale.GetText ("Private/public key mismatch"));
                }
 
                protected override void Dispose (bool disposing)