Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect presence of OpenSSL for crypto primitives #52648

Merged
merged 7 commits into from
May 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static class OpenSslNoInit
{
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_OpenSslAvailable")]
vcsjones marked this conversation as resolved.
Show resolved Hide resolved
private static extern int OpenSslAvailable();

private static readonly Lazy<bool> s_openSslAvailable =
new Lazy<bool>(() => OpenSslAvailable() != 0);

internal static bool OpenSslIsAvailable => s_openSslAvailable.Value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ public static string LibcVersion
}
}

public static bool OpenSslPresentOnSystem => !IsBrowser && Interop.OpenSslNoInit.OpenSslIsAvailable;

private static Version s_opensslVersion;
private static Version GetOpenSslVersion()
{
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/Common/tests/TestUtilities/TestUtilities.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
<ItemGroup>
<Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.cs"
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.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)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.OpenSslGetProtocolSupport.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_ObjTxt2Obj)
DllImportEntry(CryptoNative_OcspRequestDestroy)
DllImportEntry(CryptoNative_OcspResponseDestroy)
DllImportEntry(CryptoNative_OpenSslAvailable)
DllImportEntry(CryptoNative_Pbkdf2)
DllImportEntry(CryptoNative_PemReadBioPkcs7)
DllImportEntry(CryptoNative_PemReadBioX509Crl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,17 @@ static int32_t EnsureOpenSsl11Initialized()

#endif

int32_t CryptoNative_OpenSslAvailable()
{
#ifdef FEATURE_DISTRO_AGNOSTIC_SSL
// OpenLibrary will attempt to open libssl. DlOpen will handle
// the case of it already being open and dlclose the duplicate
return OpenLibrary();
vcsjones marked this conversation as resolved.
Show resolved Hide resolved
#else
return 1;
#endif
}

int32_t CryptoNative_EnsureOpenSslInitialized()
{
// If portable then decide which OpenSSL we are, and call the right one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,5 @@ PALEXPORT int32_t CryptoNative_EnsureOpenSslInitialized(void);
PALEXPORT int64_t CryptoNative_OpenSslVersionNumber(void);

PALEXPORT void CryptoNative_RegisterLegacyAlgorithms(void);

PALEXPORT int32_t CryptoNative_OpenSslAvailable(void);
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <assert.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#include "opensslshim.h"
Expand Down Expand Up @@ -51,7 +50,7 @@ static void DlOpen(const char* libraryName)
}
}

static bool OpenLibrary()
int OpenLibrary()
{
// If there is an override of the version specified using the CLR_OPENSSL_VERSION_OVERRIDE
// env variable, try to load that first.
Expand Down Expand Up @@ -124,7 +123,14 @@ static bool OpenLibrary()
DlOpen(MAKELIB("8"));
}

return libssl != NULL;
if (libssl != NULL)
{
return 1;
}
else
{
return 0;
}
}

void InitializeOpenSSLShim(void)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ void ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file,
#define NEED_OPENSSL_1_1 true
#define NEED_OPENSSL_3_0 true

int OpenLibrary(void);
void InitializeOpenSSLShim(void);

#if !HAVE_OPENSSL_EC2M
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,8 @@
Link="Common\System\Security\Cryptography\ECDiffieHellmanDerivation.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)' == 'true' and '$(UseAndroidCrypto)' != 'true'">
<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)Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.Cipher.cs"
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.Cipher.cs" />
<Compile Include="System\Security\Cryptography\AesCcm.Unix.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public sealed partial class AesCcm
{
private byte[] _key;

public static bool IsSupported => true;

[MemberNotNull(nameof(_key))]
private void ImportKey(ReadOnlySpan<byte> key)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public sealed partial class AesCcm
{
private byte[] _key;

public static bool IsSupported { get; } = Interop.OpenSslNoInit.OpenSslIsAvailable;
vcsjones marked this conversation as resolved.
Show resolved Hide resolved

[MemberNotNull(nameof(_key))]
private void ImportKey(ReadOnlySpan<byte> key)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public sealed partial class AesCcm
{
private SafeKeyHandle _keyHandle;

public static bool IsSupported => true;

[MemberNotNull(nameof(_keyHandle))]
private void ImportKey(ReadOnlySpan<byte> key)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,23 @@ public sealed partial class AesCcm : IDisposable

public AesCcm(ReadOnlySpan<byte> key)
{
ThrowIfNotSupported();

AesAEAD.CheckKeySize(key.Length);
ImportKey(key);
}

public AesCcm(byte[] key)
{
ThrowIfNotSupported();

if (key == null)
throw new ArgumentNullException(nameof(key));

AesAEAD.CheckKeySize(key.Length);
ImportKey(key);
}

public static bool IsSupported => true;

public void Encrypt(byte[] nonce, byte[] plaintext, byte[] ciphertext, byte[] tag, byte[]? associatedData = null)
{
AeadCommon.CheckArgumentsForNull(nonce, plaintext, ciphertext, tag);
Expand Down Expand Up @@ -78,5 +80,13 @@ private static void CheckParameters(
if (!tag.Length.IsLegalSize(TagByteSizes))
throw new ArgumentException(SR.Cryptography_InvalidTagLength, nameof(tag));
}

private static void ThrowIfNotSupported()
{
if (!IsSupported)
{
throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(AesCcm)));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public sealed partial class AesGcm
{
private SafeEvpCipherCtxHandle _ctxHandle;

public static bool IsSupported => true;

[MemberNotNull(nameof(_ctxHandle))]
private void ImportKey(ReadOnlySpan<byte> key)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public sealed partial class AesGcm
{
private SafeEvpCipherCtxHandle _ctxHandle;

public static bool IsSupported { get; } = Interop.OpenSslNoInit.OpenSslIsAvailable;

[MemberNotNull(nameof(_ctxHandle))]
private void ImportKey(ReadOnlySpan<byte> key)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public partial class AesGcm
{
private SafeKeyHandle _keyHandle;

public static bool IsSupported => true;

[MemberNotNull(nameof(_keyHandle))]
private void ImportKey(ReadOnlySpan<byte> key)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,23 @@ public sealed partial class AesGcm : IDisposable

public AesGcm(ReadOnlySpan<byte> key)
{
ThrowIfNotSupported();

AesAEAD.CheckKeySize(key.Length);
ImportKey(key);
}

public AesGcm(byte[] key)
{
ThrowIfNotSupported();

if (key == null)
throw new ArgumentNullException(nameof(key));

AesAEAD.CheckKeySize(key.Length);
ImportKey(key);
}

public static bool IsSupported => true;

public void Encrypt(byte[] nonce, byte[] plaintext, byte[] ciphertext, byte[] tag, byte[]? associatedData = null)
{
AeadCommon.CheckArgumentsForNull(nonce, plaintext, ciphertext, tag);
Expand Down Expand Up @@ -79,5 +81,13 @@ private static void CheckParameters(
if (!tag.Length.IsLegalSize(TagByteSizes))
throw new ArgumentException(SR.Cryptography_InvalidTagLength, nameof(tag));
}

private static void ThrowIfNotSupported()
{
if (!IsSupported)
{
throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(AesGcm)));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ namespace System.Security.Cryptography
{
public sealed partial class ChaCha20Poly1305
{
public static bool IsSupported { get; } = Interop.Crypto.EvpChaCha20Poly1305() != IntPtr.Zero;
public static bool IsSupported { get; } = Interop.OpenSslNoInit.OpenSslIsAvailable &&
Interop.Crypto.EvpChaCha20Poly1305() != IntPtr.Zero;

private SafeEvpCipherCtxHandle _ctxHandle;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -687,15 +687,28 @@ public static IEnumerable<object[]> GetNistCcmTestCasesWithNonEmptyPT()

public class AesCcmIsSupportedTests
{
public class AesGcmIsSupportedTests
public static bool RuntimeSaysIsNotSupported => !AesCcm.IsSupported;

[ConditionalFact(nameof(RuntimeSaysIsNotSupported))]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if these tests will get exercised during CI or not, but I confirmed they work locally without openssl.

public static void CtorThrowsPNSEIfNotSupported()
{
[Fact]
public static void CheckIsSupported()
{
bool expectedIsSupported = !PlatformDetection.IsBrowser;
byte[] key = RandomNumberGenerator.GetBytes(256 / 8);

Assert.Equal(expectedIsSupported, AesCcm.IsSupported);
Assert.Throws<PlatformNotSupportedException>(() => new AesCcm(key));
Assert.Throws<PlatformNotSupportedException>(() => new AesCcm(key.AsSpan()));
}

[Fact]
public static void CheckIsSupported()
{
bool expectedIsSupported = !PlatformDetection.IsBrowser;

if (PlatformDetection.IsOSX)
{
expectedIsSupported = PlatformDetection.OpenSslPresentOnSystem;
}

Assert.Equal(expectedIsSupported, AesCcm.IsSupported);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -855,11 +855,27 @@ private static IEnumerable<AEADTest> GetNistTests()

public class AesGcmIsSupportedTests
{
public static bool RuntimeSaysIsNotSupported => !AesGcm.IsSupported;

[ConditionalFact(nameof(RuntimeSaysIsNotSupported))]
public static void CtorThrowsPNSEIfNotSupported()
{
byte[] key = RandomNumberGenerator.GetBytes(256 / 8);

Assert.Throws<PlatformNotSupportedException>(() => new AesGcm(key));
Assert.Throws<PlatformNotSupportedException>(() => new AesGcm(key.AsSpan()));
}

[Fact]
public static void CheckIsSupported()
{
bool expectedIsSupported = !PlatformDetection.IsBrowser;

if (PlatformDetection.IsOSX)
{
expectedIsSupported = PlatformDetection.OpenSslPresentOnSystem;
}

Assert.Equal(expectedIsSupported, AesGcm.IsSupported);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -447,9 +447,10 @@ public static void CheckIsSupported()
// The test queries the OS directly to ensure our version check is correct.
expectedIsSupported = CngUtility.IsAlgorithmSupported("CHACHA20_POLY1305");
}
else if (PlatformDetection.IsOSX || PlatformDetection.IsOpenSslSupported)
else if (PlatformDetection.OpenSslPresentOnSystem &&
(PlatformDetection.IsOSX || PlatformDetection.IsOpenSslSupported))
{
const int OpenSslChaChaMinimumVersion = 0x1010000F;
const int OpenSslChaChaMinimumVersion = 0x1_01_00_00_F; //major_minor_fix_patch_status
expectedIsSupported = SafeEvpPKeyHandle.OpenSslVersion >= OpenSslChaChaMinimumVersion;
}

Expand Down