Skip to content

Commit

Permalink
Use SubtleCrypto API on browser DOM scenarios (dotnet#65966)
Browse files Browse the repository at this point in the history
* Use SubtleCrypto API on browser DOM scenarios

* Add sync over async implementation

* Address misc feedback and make fixes

* Address pinvoke errors

* [Attempt] Correct execution of native digest API call at wasm layer

* [Fix up] Correct execution of native digest API call at wasm layer

* Update src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs

* Address feedback and clean up

* Re-implement the crypto worker in ts

* Address feedback

* Revert "Re-implement the crypto worker in ts"

This reverts commit 6a74390.

* * moved stuff around and renamed it
* initialization bit later

* Add code to handle errors in worker (particularly on init)

* Clean up

* Add crypto dll to wasm native project

* Add e2e test

* Adjust test to reflect lack of SharedArrayBuffer for Chrome in test harness

* Enable Chrome test and validate hashed value in tests

* fix merge to track assert being renamed to mono_assert

Co-authored-by: Eric StJohn <ericstj@microsoft.com>
Co-authored-by: pavelsavara <pavel.savara@gmail.com>
Co-authored-by: Ankit Jain <radical@gmail.com>
  • Loading branch information
4 people authored May 24, 2022
1 parent c5f949e commit bfbb783
Show file tree
Hide file tree
Showing 27 changed files with 715 additions and 19 deletions.
2 changes: 1 addition & 1 deletion eng/SignCheckExclusionsFile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
*apphosttemplateapphostexe.exe;;Template, DO-NOT-SIGN, https://github.com/dotnet/core-setup/pull/7549
*comhosttemplatecomhostdll.dll;;Template, DO-NOT-SIGN, https://github.com/dotnet/core-setup/pull/7549
*staticapphosttemplateapphostexe.exe;;Template, DO-NOT-SIGN, https://github.com/dotnet/core-setup/pull/7549
*dotnet.js;;Workaround, https://github.com/dotnet/core-eng/issues/9933
*dotnet.js;;Workaround, https://github.com/dotnet/core-eng/issues/9933
1 change: 1 addition & 0 deletions eng/liveBuilds.targets
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@
<LibrariesRuntimeFiles Condition="'$(TargetOS)' == 'Browser'"
Include="
$(LibrariesNativeArtifactsPath)dotnet.js;
$(LibrariesNativeArtifactsPath)src\dotnet-crypto-worker.js;
$(LibrariesNativeArtifactsPath)dotnet.d.ts;
$(LibrariesNativeArtifactsPath)package.json;
$(LibrariesNativeArtifactsPath)dotnet.wasm;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
<PlatformManifestFileEntry Include="libSystem.Security.Cryptography.Native.Apple.dylib" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Security.Cryptography.Native.Android.a" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Security.Cryptography.Native.Android.so" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Security.Cryptography.Native.Browser.a" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Security.Cryptography.Native.OpenSsl.a" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Security.Cryptography.Native.OpenSsl.dylib" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Security.Cryptography.Native.OpenSsl.so" IsNative="true" />
Expand Down Expand Up @@ -210,6 +211,7 @@
<PlatformManifestFileEntry Include="libmono-wasm-eh-js.a" IsNative="true" />
<PlatformManifestFileEntry Include="libmono-wasm-eh-wasm.a" IsNative="true" />
<PlatformManifestFileEntry Include="System.Private.Runtime.InteropServices.Javascript.dll" />
<PlatformManifestFileEntry Include="dotnet-crypto-worker.js" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.js" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.worker.js" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.js.symbols" IsNative="true" />
Expand Down
12 changes: 12 additions & 0 deletions src/libraries/Common/src/Interop/Browser/Interop.Libraries.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

internal static partial class Interop
{
internal static partial class Libraries
{
// Shims
internal const string SystemNative = "libSystem.Native";
internal const string CryptoNative = "libSystem.Security.Cryptography.Native.Browser";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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.Diagnostics;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class BrowserCrypto
{
// These values are also defined in the pal_crypto_webworker header file, and utilized in the dotnet-crypto-worker in the wasm runtime.
internal enum SimpleDigest
{
Sha1,
Sha256,
Sha384,
Sha512,
};

[LibraryImport(Libraries.CryptoNative, EntryPoint = "SystemCryptoNativeBrowser_CanUseSimpleDigestHash")]
internal static partial int CanUseSimpleDigestHash();

[LibraryImport(Libraries.CryptoNative, EntryPoint = "SystemCryptoNativeBrowser_SimpleDigestHash")]
internal static unsafe partial int SimpleDigestHash(
SimpleDigest hash,
byte* input_buffer,
int input_len,
byte* output_buffer,
int output_len);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>$(DefineConstants);INTERNAL_ASYMMETRIC_IMPLEMENTATIONS</DefineConstants>
Expand Down Expand Up @@ -532,12 +532,15 @@
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'Browser'">
<Compile Include="$(CommonPath)Interop\Unix\Interop.Libraries.cs"
Link="Common\Interop\Unix\Interop.Libraries.cs" />
<!-- GetRandomBytes is identical on Unix and Browser -->
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetRandomBytes.cs"
Link="Common\Interop\Unix\System.Native\Interop.GetRandomBytes.cs" />
<Compile Include="$(CommonPath)Interop\Browser\Interop.Libraries.cs"
Link="Common\Interop\Browser\Interop.Libraries.cs" />
<Compile Include="$(CommonPath)System\Sha1ForNonSecretPurposes.cs"
Link="Common\System\Sha1ForNonSecretPurposes.cs" />
<Compile Include="$(CommonPath)Interop\Browser\System.Security.Cryptography.Native.Browser\Interop.SimpleDigestHash.cs"
Link="Common\Interop\Browser\System.Security.Cryptography.Native.Browser\Interop.SimpleDigestHash.cs" />
<Compile Include="System\Security\Cryptography\AesCcm.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\AesGcm.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\AesImplementation.NotSupported.cs" />
Expand All @@ -563,7 +566,8 @@
<Compile Include="System\Security\Cryptography\RC2Implementation.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\RSACryptoServiceProvider.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\RSA.Create.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\SHAHashProvider.Browser.cs" />
<Compile Include="System\Security\Cryptography\SHAHashProvider.Browser.Managed.cs" />
<Compile Include="System\Security\Cryptography\SHAHashProvider.Browser.Native.cs" />
<Compile Include="System\Security\Cryptography\TripleDESCryptoServiceProvider.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\TripleDesImplementation.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\X509Certificates\CertificatePal.NotSupported.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
// 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.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using Microsoft.Win32.SafeHandles;
using Internal.Cryptography;

namespace System.Security.Cryptography
{
internal static partial class HashProviderDispenser
{
internal static readonly bool CanUseSubtleCryptoImpl = Interop.BrowserCrypto.CanUseSimpleDigestHash() == 1;

public static HashProvider CreateHashProvider(string hashAlgorithmId)
{
switch (hashAlgorithmId)
Expand All @@ -20,7 +17,9 @@ public static HashProvider CreateHashProvider(string hashAlgorithmId)
case HashAlgorithmNames.SHA256:
case HashAlgorithmNames.SHA384:
case HashAlgorithmNames.SHA512:
return new SHAHashProvider(hashAlgorithmId);
return CanUseSubtleCryptoImpl
? new SHANativeHashProvider(hashAlgorithmId)
: new SHAManagedHashProvider(hashAlgorithmId);
}
throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
}
Expand All @@ -38,7 +37,7 @@ public static unsafe int MacData(

public static int HashData(string hashAlgorithmId, ReadOnlySpan<byte> source, Span<byte> destination)
{
HashProvider provider = HashProviderDispenser.CreateHashProvider(hashAlgorithmId);
HashProvider provider = CreateHashProvider(hashAlgorithmId);
provider.AppendHashData(source);
return provider.FinalizeHashAndReset(destination);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
Expand All @@ -9,13 +9,13 @@

namespace System.Security.Cryptography
{
internal sealed class SHAHashProvider : HashProvider
internal sealed class SHAManagedHashProvider : HashProvider
{
private int hashSizeInBytes;
private SHAManagedImplementationBase impl;
private MemoryStream? buffer;

public SHAHashProvider(string hashAlgorithmId)
public SHAManagedHashProvider(string hashAlgorithmId)
{
switch (hashAlgorithmId)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// 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.IO;
using System.Diagnostics;
using System.Security.Cryptography;

using SimpleDigest = Interop.BrowserCrypto.SimpleDigest;

namespace Internal.Cryptography
{
internal sealed class SHANativeHashProvider : HashProvider
{
private readonly int _hashSizeInBytes;
private readonly SimpleDigest _impl;
private MemoryStream? _buffer;

public SHANativeHashProvider(string hashAlgorithmId)
{
Debug.Assert(HashProviderDispenser.CanUseSubtleCryptoImpl);

switch (hashAlgorithmId)
{
case HashAlgorithmNames.SHA1:
_impl = SimpleDigest.Sha1;
_hashSizeInBytes = 20;
break;
case HashAlgorithmNames.SHA256:
_impl = SimpleDigest.Sha256;
_hashSizeInBytes = 32;
break;
case HashAlgorithmNames.SHA384:
_impl = SimpleDigest.Sha384;
_hashSizeInBytes = 48;
break;
case HashAlgorithmNames.SHA512:
_impl = SimpleDigest.Sha512;
_hashSizeInBytes = 64;
break;
default:
throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
}
}

public override void AppendHashData(ReadOnlySpan<byte> data)
{
_buffer ??= new MemoryStream(1000);
_buffer.Write(data);
}

public override int FinalizeHashAndReset(Span<byte> destination)
{
GetCurrentHash(destination);
_buffer = null;

return _hashSizeInBytes;
}

public override int GetCurrentHash(Span<byte> destination)
{
Debug.Assert(destination.Length >= _hashSizeInBytes);

byte[] srcArray = Array.Empty<byte>();
int srcLength = 0;
if (_buffer != null)
{
srcArray = _buffer.GetBuffer();
srcLength = (int)_buffer.Length;
}

unsafe
{
fixed (byte* src = srcArray)
fixed (byte* dest = destination)
{
int res = Interop.BrowserCrypto.SimpleDigestHash(_impl, src, srcLength, dest, destination.Length);
Debug.Assert(res != 0);
}
}

return _hashSizeInBytes;
}

public override int HashSizeInBytes => _hashSizeInBytes;

public override void Dispose(bool disposing)
{
}

public override void Reset()
{
_buffer = null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableLibraryImportGenerator>true</EnableLibraryImportGenerator>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetOS)' == 'Browser'">
<Scenario>WasmTestOnBrowser</Scenario>
<WasmXHarnessArgs>$(WasmXHarnessArgs) --web-server-use-cop</WasmXHarnessArgs>
</PropertyGroup>
<!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
<PropertyGroup>
<TargetPlatformIdentifier>$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))</TargetPlatformIdentifier>
Expand Down
1 change: 1 addition & 0 deletions src/mono/wasm/build/WasmApp.Native.targets
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@
<_WasmPInvokeModules Include="libSystem.Native" />
<_WasmPInvokeModules Include="libSystem.IO.Compression.Native" />
<_WasmPInvokeModules Include="libSystem.Globalization.Native" />
<_WasmPInvokeModules Include="libSystem.Security.Cryptography.Native.Browser" />
</ItemGroup>

<PInvokeTableGenerator
Expand Down
2 changes: 2 additions & 0 deletions src/mono/wasm/build/WasmApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@

<_HasDotnetWasm Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.wasm'">true</_HasDotnetWasm>
<_HasDotnetJsWorker Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.worker.js'">true</_HasDotnetJsWorker>
<_HasDotnetJsCryptoWorker Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet-crypto-worker.js'">true</_HasDotnetJsCryptoWorker>
<_HasDotnetJsSymbols Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.js.symbols'">true</_HasDotnetJsSymbols>
<_HasDotnetJs Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.js'">true</_HasDotnetJs>
</PropertyGroup>
Expand All @@ -270,6 +271,7 @@
<WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.wasm" Condition="'$(_HasDotnetWasm)' != 'true'" />
<WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.js" Condition="'$(_HasDotnetJs)' != 'true'" />
<WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.worker.js" Condition="'$(_HasDotnetJsWorker)' != 'true' and Exists('$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.worker.js')" />
<WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet-crypto-worker.js" Condition="'$(_HasDotnetJsCryptoWorker)' != 'true' and Exists('$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet-crypto-worker.js')" />
<WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.js.symbols"
Condition="'$(WasmEmitSymbolMap)' == 'true' and '$(_HasDotnetJs)' != 'true' and Exists('$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.js.symbols')" />

Expand Down
3 changes: 2 additions & 1 deletion src/mono/wasm/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ target_link_libraries(dotnet
${MONO_ARTIFACTS_DIR}/libmono-wasm-eh-js.a
${MONO_ARTIFACTS_DIR}/libmono-profiler-aot.a
${NATIVE_BIN_DIR}/libSystem.Native.a
${NATIVE_BIN_DIR}/libSystem.IO.Compression.Native.a)
${NATIVE_BIN_DIR}/libSystem.IO.Compression.Native.a
${NATIVE_BIN_DIR}/libSystem.Security.Cryptography.Native.Browser.a)

set_target_properties(dotnet PROPERTIES
LINK_DEPENDS "${NATIVE_BIN_DIR}/src/emcc-default.rsp;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.pre.js;${NATIVE_BIN_DIR}/src/cjs/runtime.cjs.iffe.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.lib.js;${NATIVE_BIN_DIR}/src/pal_random.lib.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.post.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.extpost.js;"
Expand Down
4 changes: 4 additions & 0 deletions src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ const linked_functions = [
// pal_icushim_static.c
"mono_wasm_load_icu_data",
"mono_wasm_get_icudt_name",

// pal_crypto_webworker.c
"dotnet_browser_simple_digest_hash",
"dotnet_browser_can_use_simple_digest_hash",
];

// -- this javascript file is evaluated by emcc during compilation! --
Expand Down
Loading

0 comments on commit bfbb783

Please sign in to comment.