From 1dd7d9fe50918b308595811b896cf6d1ce7f0e55 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Wed, 11 Dec 2019 09:42:32 -0500 Subject: [PATCH] Use invalid password hresult in managed p12 reader 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/Internal/Cryptography/Pal.Unix/UnixPkcs12Reader.cs | 11 +++++++++-- .../tests/PfxFormatTests.cs | 5 +++-- .../tests/PfxFormatTests_Collection.cs | 1 + .../tests/PfxFormatTests_SingleCert.cs | 1 + 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/UnixPkcs12Reader.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/UnixPkcs12Reader.cs index 12a6826..1ef51eb 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/UnixPkcs12Reader.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/UnixPkcs12Reader.cs @@ -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 password, ReadOnlyMemory authSafeContents) diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests.cs index 246fb63..6120831 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests.cs @@ -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)] diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests_Collection.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests_Collection.cs index 8cf7f45..b4f205c 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests_Collection.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests_Collection.cs @@ -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( diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests_SingleCert.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests_SingleCert.cs index 17e60e7..0466235 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests_SingleCert.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/PfxFormatTests_SingleCert.cs @@ -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( -- 2.7.4