From 43c44056f6e0335097998a0e8cfdb2829ffd1908 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 25 May 2022 15:56:37 -0700 Subject: [PATCH] Allow ToCryptographicException to create serializable exceptions (#69765) --- .../Cryptography/CryptoThrowHelper.Windows.cs | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/CryptoThrowHelper.Windows.cs b/src/libraries/Common/src/System/Security/Cryptography/CryptoThrowHelper.Windows.cs index 2fba282d49f..b41fe846066 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/CryptoThrowHelper.Windows.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/CryptoThrowHelper.Windows.cs @@ -2,9 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Diagnostics; using System.Security.Cryptography; +#if !NETCOREAPP3_1_OR_GREATER +using System.Diagnostics; +using System.Runtime.Serialization; +#endif + namespace Internal.Cryptography { internal static class CryptoThrowHelper @@ -13,19 +17,54 @@ public static CryptographicException ToCryptographicException(this int hr) { string message = Interop.Kernel32.GetMessage(hr); - if ((hr & 0x80000000) != 0x80000000) + // If the incoming value is non-negative, it's a Win32 error instead of an + // HRESULT. We'll convert it to an HRESULT now (subsystem = 0x0007 [win32]). + if (hr >= 0) + { hr = (hr & 0x0000FFFF) | unchecked((int)0x80070000); + } + +#if NETCOREAPP3_1_OR_GREATER + return new CryptographicException(message) + { + HResult = hr + }; +#else + // Prior to .NET Core 3.1, the Exception.HResult property was not publicly + // settable, and CryptographicException did not have a ctor which allowed + // setting both the message and the HRESULT. We use a subclassed helper + // type to allow flowing both pieces of data to receivers. return new WindowsCryptographicException(hr, message); +#endif } +#if !NETCOREAPP3_1_OR_GREATER + [Serializable] private sealed class WindowsCryptographicException : CryptographicException { + private WindowsCryptographicException(SerializationInfo info, StreamingContext context) + { + Debug.Fail("This should never be called; we swap the active type during serialization."); + throw new NotImplementedException(); + } + public WindowsCryptographicException(int hr, string message) : base(message) { HResult = hr; } + + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + // This exception shouldn't be serialized since it's a private implementation + // detail potentially copied across multiple different assemblies. We'll + // instead ask the serializer to pretend that we're a normal CryptographicException. + + info.SetType(typeof(CryptographicException)); + base.GetObjectData(info, context); + } } +#endif } } -- GitLab