Check for OpenSSL availability for OpenSsl asymmetric primitives
authorKevin Jones <kevin@vcsjones.com>
Mon, 16 Aug 2021 23:52:08 +0000 (19:52 -0400)
committerGitHub <noreply@github.com>
Mon, 16 Aug 2021 23:52:08 +0000 (16:52 -0700)
If you attempt to use any of the *OpenSsl primitives on macOS, this will currently abort the whole process.
This changes them to check for OpenSSL's presence and throw an appropriate exception instead of aborting.

When used as an internal implementation, the aborting behavior remains.

src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs
src/libraries/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.cs
src/libraries/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs
src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs
src/libraries/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx
src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj
src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/DSAOpenSsl.cs
src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.cs
src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDsaOpenSsl.cs
src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/RSAOpenSsl.cs

index 7c75208..d51e1a3 100644 (file)
@@ -41,6 +41,7 @@ namespace System.Security.Cryptography
 
             public DSAOpenSsl(int keySize)
             {
+                ThrowIfNotSupported();
                 LegalKeySizesValue = s_legalKeySizes;
                 base.KeySize = keySize;
                 _key = new Lazy<SafeDsaHandle>(GenerateKey);
@@ -416,6 +417,8 @@ namespace System.Security.Cryptography
                 _key = new Lazy<SafeDsaHandle>(newKey);
             }
 
+            static partial void ThrowIfNotSupported();
+
             private static readonly KeySizes[] s_legalKeySizes = new KeySizes[] { new KeySizes(minSize: 512, maxSize: 3072, skipSize: 64) };
         }
 #if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
index 61e4678..d1fa05f 100644 (file)
@@ -15,6 +15,7 @@ namespace System.Security.Cryptography
 
             public ECDiffieHellmanOpenSsl(ECCurve curve)
             {
+                ThrowIfNotSupported();
                 _key = new ECOpenSsl(curve);
                 KeySizeValue = _key.KeySize;
             }
@@ -26,6 +27,7 @@ namespace System.Security.Cryptography
 
             public ECDiffieHellmanOpenSsl(int keySize)
             {
+                ThrowIfNotSupported();
                 base.KeySize = keySize;
                 _key = new ECOpenSsl(this);
             }
@@ -133,6 +135,8 @@ namespace System.Security.Cryptography
                 ThrowIfDisposed();
                 return _key.Value;
             }
+
+            static partial void ThrowIfNotSupported();
         }
 #if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
     }
index 7c9d0cc..c56d3f4 100644 (file)
@@ -26,6 +26,7 @@ namespace System.Security.Cryptography
             /// <exception cref="ArgumentNullException">if <paramref name="curve" /> is null.</exception>
             public ECDsaOpenSsl(ECCurve curve)
             {
+                ThrowIfNotSupported();
                 _key = new ECOpenSsl(curve);
                 ForceSetKeySize(_key.KeySize);
             }
@@ -44,6 +45,7 @@ namespace System.Security.Cryptography
             /// <param name="keySize">Size of the key to generate, in bits.</param>
             public ECDsaOpenSsl(int keySize)
             {
+                ThrowIfNotSupported();
                 // Use the base setter to get the validation and field assignment without the
                 // side effect of dereferencing _key.
                 base.KeySize = keySize;
@@ -360,6 +362,8 @@ namespace System.Security.Cryptography
                     );
                 }
             }
+
+            static partial void ThrowIfNotSupported();
         }
 #if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
     }
index 718059a..aab2a5a 100644 (file)
@@ -33,6 +33,7 @@ namespace System.Security.Cryptography
 
         public RSAOpenSsl(int keySize)
         {
+            ThrowIfNotSupported();
             base.KeySize = keySize;
             _key = new Lazy<SafeEvpPKeyHandle>(GenerateKey);
         }
@@ -946,6 +947,8 @@ namespace System.Security.Cryptography
             }
         }
 
+        static partial void ThrowIfNotSupported();
+
         private static Exception PaddingModeNotSupported() =>
             new CryptographicException(SR.Cryptography_InvalidPaddingMode);
 
index 40e6dcd..d27bec3 100644 (file)
@@ -1,16 +1,16 @@
 <root>
-  <!-- 
-    Microsoft ResX Schema 
-    
+  <!--
+    Microsoft ResX Schema
+
     Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
     associated with the data types.
-    
+
     Example:
-    
+
     ... ado.net/XML headers & schema ...
     <resheader name="resmimetype">text/microsoft-resx</resheader>
     <resheader name="version">2.0</resheader>
         <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
         <comment>This is a comment</comment>
     </data>
-                
-    There are any number of "resheader" rows that contain simple 
+
+    There are any number of "resheader" rows that contain simple
     name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
     mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
     extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
     read any of the formats listed below.
-    
+
     mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
+    value   : The object must be serialized with
             : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
             : and then encoded with base64 encoding.
-    
+
     mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
+    value   : The object must be serialized with
             : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
             : and then encoded with base64 encoding.
 
     mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
+    value   : The object must be serialized into a byte array
             : using a System.ComponentModel.TypeConverter
             : and then encoded with base64 encoding.
     -->
   <data name="Cryptography_NotValidPublicOrPrivateKey" xml:space="preserve">
     <value>Key is not a valid public or private key.</value>
   </data>
+  <data name="Cryptography_AlgorithmNotSupported" xml:space="preserve">
+    <value>Algorithm '{0}' is not supported on this platform.</value>
+  </data>
   <data name="PlatformNotSupported_CryptographyOpenSSL" xml:space="preserve">
     <value>OpenSSL is not supported on this platform.</value>
   </data>
index f28aa95..89fdccd 100644 (file)
@@ -55,6 +55,8 @@
              Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.cs" />
     <Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs"
              Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs" />
+    <Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslAvailable.cs"
+             Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslAvailable.cs" />
     <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs"
              Link="Common\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs" />
     <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeBignumHandle.Unix.cs"
index f0bef49..3a2adb6 100644 (file)
@@ -9,6 +9,7 @@ namespace System.Security.Cryptography
     {
         public DSAOpenSsl(DSAParameters parameters)
         {
+            ThrowIfNotSupported();
             // Make _key be non-null before calling ImportParameters
             _key = new Lazy<SafeDsaHandle>();
             ImportParameters(parameters);
@@ -31,6 +32,7 @@ namespace System.Security.Cryptography
             if (pkeyHandle.IsInvalid)
                 throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle));
 
+            ThrowIfNotSupported();
             // If dsa is valid it has already been up-ref'd, so we can just use this handle as-is.
             SafeDsaHandle key = Interop.Crypto.EvpPkeyGetDsa(pkeyHandle);
             if (key.IsInvalid)
@@ -57,6 +59,7 @@ namespace System.Security.Cryptography
             if (handle == IntPtr.Zero)
                 throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(handle));
 
+            ThrowIfNotSupported();
             SafeDsaHandle ecKeyHandle = SafeDsaHandle.DuplicateHandle(handle);
             SetKey(ecKeyHandle);
         }
@@ -89,5 +92,13 @@ namespace System.Security.Cryptography
                 throw;
             }
         }
+
+        static partial void ThrowIfNotSupported()
+        {
+            if (!Interop.OpenSslNoInit.OpenSslIsAvailable)
+            {
+                throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(DSAOpenSsl)));
+            }
+        }
     }
 }
index 09d0809..86e29e6 100644 (file)
@@ -23,6 +23,7 @@ namespace System.Security.Cryptography
             if (pkeyHandle.IsInvalid)
                 throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle));
 
+            ThrowIfNotSupported();
             // If ecKey is valid it has already been up-ref'd, so we can just use this handle as-is.
             SafeEcKeyHandle key = Interop.Crypto.EvpPkeyGetEcKey(pkeyHandle);
             if (key.IsInvalid)
@@ -50,6 +51,7 @@ namespace System.Security.Cryptography
             if (handle == IntPtr.Zero)
                 throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(handle));
 
+            ThrowIfNotSupported();
             SafeEcKeyHandle ecKeyHandle = SafeEcKeyHandle.DuplicateHandle(handle);
             _key = new ECOpenSsl(ecKeyHandle);
             KeySizeValue = _key.KeySize;
@@ -83,5 +85,13 @@ namespace System.Security.Cryptography
                 throw;
             }
         }
+
+        static partial void ThrowIfNotSupported()
+        {
+            if (!Interop.OpenSslNoInit.OpenSslIsAvailable)
+            {
+                throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(ECDiffieHellmanOpenSsl)));
+            }
+        }
     }
 }
index 2bf99c2..27c08d7 100644 (file)
@@ -23,6 +23,7 @@ namespace System.Security.Cryptography
             if (pkeyHandle.IsInvalid)
                 throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle));
 
+            ThrowIfNotSupported();
             // If ecKey is valid it has already been up-ref'd, so we can just use this handle as-is.
             SafeEcKeyHandle key = Interop.Crypto.EvpPkeyGetEcKey(pkeyHandle);
             if (key.IsInvalid)
@@ -50,6 +51,7 @@ namespace System.Security.Cryptography
             if (handle == IntPtr.Zero)
                 throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(handle));
 
+            ThrowIfNotSupported();
             SafeEcKeyHandle ecKeyHandle = SafeEcKeyHandle.DuplicateHandle(handle);
             _key = new ECOpenSsl(ecKeyHandle);
             KeySizeValue = _key.KeySize;
@@ -83,5 +85,13 @@ namespace System.Security.Cryptography
                 throw;
             }
         }
+
+        static partial void ThrowIfNotSupported()
+        {
+            if (!Interop.OpenSslNoInit.OpenSslIsAvailable)
+            {
+                throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(ECDsaOpenSsl)));
+            }
+        }
     }
 }
index c6f8efb..151dfba 100644 (file)
@@ -10,6 +10,8 @@ namespace System.Security.Cryptography
     {
         public RSAOpenSsl(RSAParameters parameters)
         {
+            ThrowIfNotSupported();
+
             // Make _key be non-null before calling ImportParameters
             _key = new Lazy<SafeEvpPKeyHandle>();
             ImportParameters(parameters);
@@ -30,6 +32,7 @@ namespace System.Security.Cryptography
             if (handle == IntPtr.Zero)
                 throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(handle));
 
+            ThrowIfNotSupported();
             SafeEvpPKeyHandle pkey = Interop.Crypto.EvpPKeyCreateRsa(handle);
             Debug.Assert(!pkey.IsInvalid);
 
@@ -53,6 +56,7 @@ namespace System.Security.Cryptography
             if (pkeyHandle.IsInvalid)
                 throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle));
 
+            ThrowIfNotSupported();
             SafeEvpPKeyHandle newKey = Interop.Crypto.EvpPKeyDuplicate(
                 pkeyHandle,
                 Interop.Crypto.EvpAlgorithmId.RSA);
@@ -69,5 +73,13 @@ namespace System.Security.Cryptography
         {
             return Interop.Crypto.EvpPKeyDuplicate(GetKey(), Interop.Crypto.EvpAlgorithmId.RSA);
         }
+
+        static partial void ThrowIfNotSupported()
+        {
+            if (!Interop.OpenSslNoInit.OpenSslIsAvailable)
+            {
+                throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(RSAOpenSsl)));
+            }
+        }
     }
 }