Use invalid password hresult in managed p12 reader
authorKevin Jones <kevin@vcsjones.com>
Wed, 11 Dec 2019 14:42:32 +0000 (09:42 -0500)
committerKevin Jones <kevin@vcsjones.com>
Wed, 11 Dec 2019 14:42:32 +0000 (09:42 -0500)
The managed PKCS12 reader was not setting the HResult on exceptions
when the MAC of the PKCS12 failed (typically the result of a bad password).
This made the CryptographicException indistinguishable from other
PKCS12 CryptographicExceptions without relying on the exception message.

Some other applications used the HResult to determine if the PKCS12
could not be read due to an invalid password.

src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/UnixPkcs12Reader.cs
src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests.cs
src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests_Collection.cs
src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests_SingleCert.cs

index 12a6826c99f5a21f3d1f2e765b44468b5ba74f3f..1ef51eb6f0b4ff4b3d7a82a66cd47b9131563455 100644 (file)
@@ -19,6 +19,7 @@ namespace Internal.Cryptography.Pal
     internal abstract class UnixPkcs12Reader : IDisposable
     {
         private const string DecryptedSentinel = nameof(UnixPkcs12Reader);
+        private const int ErrorInvalidPasswordHResult = unchecked((int)0x80070056);
 
         private PfxAsn _pfxAsn;
         private ContentInfoAsn[] _safeContentsValues;
@@ -190,7 +191,10 @@ namespace Internal.Cryptography.Pal
             }
             catch (Exception e)
             {
-                throw new CryptographicException(SR.Cryptography_Pfx_BadPassword, e);
+                throw new CryptographicException(SR.Cryptography_Pfx_BadPassword, e)
+                {
+                    HResult = ErrorInvalidPasswordHResult
+                };
             }
             finally
             {
@@ -225,7 +229,10 @@ namespace Internal.Cryptography.Pal
                 return;
             }
 
-            throw new CryptographicException(SR.Cryptography_Pfx_BadPassword);
+            throw new CryptographicException(SR.Cryptography_Pfx_BadPassword)
+            {
+                HResult = ErrorInvalidPasswordHResult
+            };
         }
 
         private void Decrypt(ReadOnlySpan<char> password, ReadOnlyMemory<byte> authSafeContents)
index 246fb637ec1b677515a8c7affd743b2a3824acfb..612083176e7a7f2b83fa0fdec91183157293a65e 100644 (file)
@@ -15,6 +15,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
         // Use a MAC count of 1 because we're not persisting things, and the password
         // is with the test... just save some CPU cycles.
         private const int MacCount = 1;
+        protected const int ErrorInvalidPasswordHResult = unchecked((int)0x80070056);
 
         // Use SHA-1 for Windows 7-8.1 support.
         private static readonly HashAlgorithmName s_digestAlgorithm = HashAlgorithmName.SHA1;
@@ -764,7 +765,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
                 cert2.Attributes.Add(id2);
                 key1.Attributes.Add(id3);
                 key2.Attributes.Add(id4);
-                
+
                 AddContents(keyContents, builder, pw, encrypt: false);
                 AddContents(certContents, builder, pw, encrypt: true);
                 builder.SealWithMac(pw, s_digestAlgorithm, MacCount);
@@ -815,7 +816,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
                     -2146893819);
             }
         }
-        
+
         [Theory]
         [InlineData(false, false)]
         [InlineData(false, true)]
index 8cf7f45734e810afa2a4247e731e15083f1ce9da..b4f205c146f3082b341a724e9858c83bff18d953 100644 (file)
@@ -84,6 +84,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
                 () => coll.Import(pfxBytes, wrongPassword, s_importFlags));
 
             AssertMessageContains("password", ex);
+            Assert.Equal(ErrorInvalidPasswordHResult, ex.HResult);
         }
 
         protected override void ReadUnreadablePfx(
index 17e60e7bd3bded167c65306d6752a31aaa970c17..046623564fc00184b01dda8464385f19a9aae1ff 100644 (file)
@@ -58,6 +58,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
                 () => new X509Certificate2(pfxBytes, wrongPassword, s_importFlags));
 
             AssertMessageContains("password", ex);
+            Assert.Equal(ErrorInvalidPasswordHResult, ex.HResult);
         }
 
         protected override void ReadUnreadablePfx(