diff --git a/NuGet.config b/NuGet.config index 74e7c1411d8a..8c974d5ecd32 100644 --- a/NuGet.config +++ b/NuGet.config @@ -9,6 +9,7 @@ + diff --git a/docs/workflow/testing/libraries/testing-android.md b/docs/workflow/testing/libraries/testing-android.md index b4c5179e6be9..abb8c2ec6b80 100644 --- a/docs/workflow/testing/libraries/testing-android.md +++ b/docs/workflow/testing/libraries/testing-android.md @@ -23,9 +23,9 @@ Android SDK and NDK can be automatically installed via the following script: set -e NDK_VER=r23c -SDK_VER=6200805_latest -SDK_API_LEVEL=29 -SDK_BUILD_TOOLS=29.0.3 +SDK_VER=9123335_latest +SDK_API_LEVEL=33 +SDK_BUILD_TOOLS=33.0.1 if [[ "$OSTYPE" == "darwin"* ]]; then HOST_OS=darwin @@ -63,7 +63,7 @@ Android Studio offers a convenient UI: Before running a build you might want to set the Android SDK and NDK environment variables: ``` export ANDROID_SDK_ROOT= -export ANDROID_NDK_ROOT= +export ANDROID_NDK_ROOT= ``` Now we're ready to build everything for Android: diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f3527efef6b9..569c7743ca67 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/icu - d89651b995bbb9565a3674ddf77b187cb6f9f26d + bdaa3a0b2a204574ef4ab63bae2c4b5c6d607849 https://github.com/dotnet/msquic @@ -48,13 +48,13 @@ https://github.com/dotnet/command-line-api 5618b2d243ccdeb5c7e50a298b33b13036b4351b - + https://github.com/dotnet/emsdk - 33b038b591f6e19c32a390333d41292cbd86d93c + ca510604d1667f32b4fa4653e3d3b64be8136bdc - + https://github.com/dotnet/emsdk - 33b038b591f6e19c32a390333d41292cbd86d93c + ca510604d1667f32b4fa4653e3d3b64be8136bdc @@ -130,57 +130,57 @@ https://github.com/dotnet/arcade 02d5538bac1bacfd6fb310d92ab8914de08f3358 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 https://github.com/dotnet/llvm-project @@ -278,13 +278,13 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 5e0b0da43f660de5798186f4fd3bc900fc90576c - + https://github.com/dotnet/hotreload-utils - 6d7ba7d63a9c246a6477bda4d19c3315fd91868f + 74472cc407fe757b9479fd78cdb64d7d6e67935f - + https://github.com/dotnet/runtime-assets - ddb9487d79d1ba17a4fd872ffafe5f1cd7b406d6 + 8a02fa4c0dca32e1402c1926eec810b8e45948a5 https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index 0d9e28a90a17..625e7058506c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -22,8 +22,8 @@ false false $(AssemblyVersion) - 7.0.15 - 7.0.15 + 7.0.16 + 7.0.16 @@ -118,20 +118,20 @@ 4.5.0 7.0.0-rc.1.22414.6 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 - 7.0.0-beta.23566.2 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 + 7.0.0-beta.24060.3 1.0.0-prerelease.22415.6 1.0.0-prerelease.22415.6 @@ -157,7 +157,7 @@ 7.0.0-prerelease.24054.3 7.0.0-prerelease.24054.3 7.0.0-prerelease.24054.3 - 7.0.0-alpha.0.23566.1 + 7.0.0-alpha.0.24060.2 2.4.2 1.0.0 2.4.5 @@ -177,7 +177,7 @@ 7.0.100-1.23401.1 $(MicrosoftNETILLinkTasksVersion) - 7.0.0-rtm.23565.2 + 7.0.0-rtm.24060.3 2.2.3 7.0.0-alpha.1.22459.1 diff --git a/eng/native/ijw/IJW.cmake b/eng/native/ijw/IJW.cmake index 81b69f0d965d..453dfb26b1ac 100644 --- a/eng/native/ijw/IJW.cmake +++ b/eng/native/ijw/IJW.cmake @@ -46,7 +46,7 @@ if (CLR_CMAKE_HOST_WIN32) # 4365 - signed/unsigned mismatch # 4679 - Could not import member. This is an issue with IJW and static abstract methods in interfaces. - add_compile_options(/wd4365 /wd4679) + add_compile_options(/wd4365 /wd4679 /wd5271) # IJW add_compile_options(/clr:netcore) diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index 2ec41d7682c7..0c0969520b0d 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -580,6 +580,29 @@ jobs: helixQueueGroup: ${{ parameters.helixQueueGroup }} ${{ insert }}: ${{ parameters.jobParameters }} +- ${{ if containsValue(parameters.platforms, 'Android_arm64_perf_specific') }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + variables: ${{ parameters.variables }} + osGroup: Android + archType: arm64 + targetRid: android-arm64 + platform: Android_arm64 + shouldContinueOnError: ${{ parameters.shouldContinueOnError }} + container: + image: cbl-mariner-2.0-cross-android-amd64 + registry: mcr + jobParameters: + runtimeFlavor: mono + stagedBuild: ${{ parameters.stagedBuild }} + buildConfig: ${{ parameters.buildConfig }} + ${{ if eq(parameters.passPlatforms, true) }}: + platforms: ${{ parameters.platforms }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + ${{ insert }}: ${{ parameters.jobParameters }} + # Mac Catalyst x64 - ${{ if containsValue(parameters.platforms, 'MacCatalyst_x64') }}: diff --git a/eng/pipelines/common/restore-internal-tools.yml b/eng/pipelines/common/restore-internal-tools.yml index eead4b67c30f..fdec41da53da 100644 --- a/eng/pipelines/common/restore-internal-tools.yml +++ b/eng/pipelines/common/restore-internal-tools.yml @@ -1,5 +1,5 @@ steps: - - task: NuGetAuthenticate@0 + - task: NuGetAuthenticate@1 inputs: nuGetServiceConnections: 'devdiv/dotnet-core-internal-tooling' forceReinstallCredentialProvider: true diff --git a/eng/pipelines/coreclr/ci.yml b/eng/pipelines/coreclr/ci.yml index ae8e4e421804..3b9ad9519b1d 100644 --- a/eng/pipelines/coreclr/ci.yml +++ b/eng/pipelines/coreclr/ci.yml @@ -153,13 +153,3 @@ jobs: crossgen2: true displayNameArgs: R2R_CG2 liveLibrariesBuildConfig: Release - -# -# Formatting -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/coreclr/templates/format-job.yml - platforms: - - Linux_x64 - - windows_x64 diff --git a/eng/pipelines/coreclr/perf-non-wasm-jobs.yml b/eng/pipelines/coreclr/perf-non-wasm-jobs.yml index 9a60000c79d0..cbb49599d956 100644 --- a/eng/pipelines/coreclr/perf-non-wasm-jobs.yml +++ b/eng/pipelines/coreclr/perf-non-wasm-jobs.yml @@ -65,7 +65,7 @@ jobs: buildConfig: release runtimeFlavor: mono platforms: - - Android_arm64 + - Android_arm64_perf_specific jobParameters: buildArgs: -s mono+libs+host+packs -c $(_BuildConfig) nameSuffix: AndroidMono @@ -314,4 +314,4 @@ jobs: projectFile: crossgen_perf.proj runKind: crossgen_scenarios runJobTemplate: /eng/pipelines/coreclr/templates/run-scenarios-job.yml - logicalmachine: 'perftiger_crossgen' \ No newline at end of file + logicalmachine: 'perftiger_crossgen' diff --git a/eng/pipelines/coreclr/templates/helix-queues-setup.yml b/eng/pipelines/coreclr/templates/helix-queues-setup.yml index f61ee6d3efe4..ce7aaf1f9ad3 100644 --- a/eng/pipelines/coreclr/templates/helix-queues-setup.yml +++ b/eng/pipelines/coreclr/templates/helix-queues-setup.yml @@ -31,7 +31,7 @@ jobs: # Android arm64 - ${{ if in(parameters.platform, 'Android_arm64') }}: - - Windows.10.Amd64.Android.Open + - Windows.11.Amd64.Android.Open # Android x64 - ${{ if in(parameters.platform, 'Android_x64') }}: diff --git a/eng/pipelines/installer/jobs/base-job.yml b/eng/pipelines/installer/jobs/base-job.yml index 0155c095669c..b1fa3c3026b5 100644 --- a/eng/pipelines/installer/jobs/base-job.yml +++ b/eng/pipelines/installer/jobs/base-job.yml @@ -345,7 +345,7 @@ jobs: displayName: Clean up old artifacts owned by root - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - task: NuGetAuthenticate@0 + - task: NuGetAuthenticate@1 - ${{ if eq(parameters.osGroup, 'windows') }}: # NuGet's http cache lasts 30 minutes. If we're on a static machine, this may interfere with diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index 554d44135ba3..68597d14960f 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -102,7 +102,7 @@ jobs: - ${{ if in(parameters.platform, 'Android_x86', 'Android_x64', 'Linux_bionic_x64') }}: - Ubuntu.1804.Amd64.Android.29.Open - ${{ if in(parameters.platform, 'Android_arm', 'Android_arm64', 'Linux_bionic_arm64') }}: - - Windows.10.Amd64.Android.Open + - Windows.11.Amd64.Android.Open # iOS Simulator/Mac Catalyst arm64 - ${{ if in(parameters.platform, 'MacCatalyst_arm64', 'iOSSimulator_arm64') }}: diff --git a/eng/pipelines/official/jobs/prepare-signed-artifacts.yml b/eng/pipelines/official/jobs/prepare-signed-artifacts.yml index 016b799e0099..213d56b3cf69 100644 --- a/eng/pipelines/official/jobs/prepare-signed-artifacts.yml +++ b/eng/pipelines/official/jobs/prepare-signed-artifacts.yml @@ -26,7 +26,7 @@ jobs: fetchDepth: 20 - ${{ if eq(parameters.isOfficialBuild, true) }}: - - task: NuGetAuthenticate@0 + - task: NuGetAuthenticate@1 - task: MicroBuildSigningPlugin@2 displayName: Install MicroBuild plugin for Signing diff --git a/eng/testing/performance/performance-setup.ps1 b/eng/testing/performance/performance-setup.ps1 index bd67e15fecdc..693591d73a2d 100644 --- a/eng/testing/performance/performance-setup.ps1 +++ b/eng/testing/performance/performance-setup.ps1 @@ -50,7 +50,7 @@ if ($Internal) { "perftiger_crossgen" { $Queue = "Windows.10.Amd64.19H1.Tiger.Perf" } "perfowl" { $Queue = "Windows.10.Amd64.20H2.Owl.Perf" } "perfsurf" { $Queue = "Windows.10.Arm64.Perf.Surf" } - "perfpixel4a" { $Queue = "Windows.10.Amd64.Pixel.Perf" } + "perfpixel4a" { $Queue = "Windows.11.Amd64.Pixel.Perf" } "perfampere" { $Queue = "Windows.Server.Arm64.Perf" } Default { $Queue = "Windows.10.Amd64.19H1.Tiger.Perf" } } diff --git a/eng/testing/performance/performance-setup.sh b/eng/testing/performance/performance-setup.sh index 09e3a5980eec..a5703929ec15 100755 --- a/eng/testing/performance/performance-setup.sh +++ b/eng/testing/performance/performance-setup.sh @@ -245,7 +245,7 @@ if [[ "$internal" == true ]]; then extra_benchmark_dotnet_arguments= if [[ "$logical_machine" == "perfiphone12mini" ]]; then - queue=OSX.1015.Amd64.Iphone.Perf + queue=OSX.13.Amd64.Iphone.Perf elif [[ "$logical_machine" == "perfampere" ]]; then queue=Ubuntu.2004.Arm64.Perf elif [[ "$architecture" == "arm64" ]]; then diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs index 59736b39f47e..8b07660a3fb6 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs @@ -29,27 +29,30 @@ internal static partial class Crypto int len, SafeOcspRequestHandle req, IntPtr subject, - IntPtr issuer, + IntPtr* issuers, + int issuersLen, ref long expiration); internal static unsafe bool X509DecodeOcspToExpiration( ReadOnlySpan buf, SafeOcspRequestHandle request, IntPtr x509Subject, - IntPtr x509Issuer, + ReadOnlySpan x509Issuers, out DateTimeOffset expiration) { long timeT = 0; int ret; fixed (byte* pBuf = buf) + fixed (IntPtr* pIssuers = x509Issuers) { ret = CryptoNative_X509DecodeOcspToExpiration( pBuf, buf.Length, request, x509Subject, - x509Issuer, + pIssuers, + x509Issuers.Length, ref timeT); } diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs index c8e7dd364902..2e668f6c8463 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs @@ -67,6 +67,7 @@ internal enum ContextAttribute SECPKG_ATTR_ISSUER_LIST_EX = 0x59, // returns SecPkgContext_IssuerListInfoEx SECPKG_ATTR_CLIENT_CERT_POLICY = 0x60, // sets SecPkgCred_ClientCertCtlPolicy SECPKG_ATTR_CONNECTION_INFO = 0x5A, // returns SecPkgContext_ConnectionInfo + SECPKG_ATTR_SESSION_INFO = 0x5D, // sets SecPkgContext_SessionInfo SECPKG_ATTR_CIPHER_INFO = 0x64, // returns SecPkgContext_CipherInfo SECPKG_ATTR_REMOTE_CERT_CHAIN = 0x67, // returns PCCERT_CONTEXT SECPKG_ATTR_UI_INFO = 0x68, // sets SEcPkgContext_UiInfo @@ -249,7 +250,7 @@ public enum Flags SCH_CRED_IGNORE_REVOCATION_OFFLINE = 0x1000, SCH_CRED_CACHE_ONLY_URL_RETRIEVAL_ON_CREATE = 0x2000, SCH_SEND_ROOT_CERT = 0x40000, - SCH_SEND_AUX_RECORD = 0x00200000, + SCH_SEND_AUX_RECORD = 0x00200000, SCH_USE_STRONG_CRYPTO = 0x00400000, SCH_USE_PRESHAREDKEY_ONLY = 0x800000, SCH_ALLOW_NULL_ENCRYPTION = 0x02000000, @@ -334,6 +335,21 @@ internal unsafe struct SecPkgCred_ClientCertPolicy public char* pwszSslCtlIdentifier; } + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct SecPkgContext_SessionInfo + { + public uint dwFlags; + public uint cbSessionId; + public fixed byte rgbSessionId[32]; + + [Flags] + public enum Flags + { + Zero = 0, + SSL_SESSION_RECONNECT = 0x01, + }; + } + [LibraryImport(Interop.Libraries.SspiCli, SetLastError = true)] internal static partial int EncryptMessage( ref CredHandle contextHandle, diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs index 81fdba8901bb..b13e217b7374 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs @@ -298,6 +298,9 @@ private static bool QueryCertContextAttribute(ISSPIInterface secModule, SafeDele public static bool QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(ISSPIInterface secModule, SafeDeleteContext securityContext, out SafeFreeCertContext? certContext) => QueryCertContextAttribute(secModule, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_REMOTE_CERT_CONTEXT, out certContext); + public static bool QueryContextAttributes_SECPKG_ATTR_LOCAL_CERT_CONTEXT(ISSPIInterface secModule, SafeDeleteContext securityContext, out SafeFreeCertContext? certContext) + => QueryCertContextAttribute(secModule, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_LOCAL_CERT_CONTEXT, out certContext); + public static bool QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CHAIN(ISSPIInterface secModule, SafeDeleteContext securityContext, out SafeFreeCertContext? certContext) => QueryCertContextAttribute(secModule, securityContext, Interop.SspiCli.ContextAttribute.SECPKG_ATTR_REMOTE_CERT_CHAIN, out certContext); diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs index 12603f7df6ae..880189a74162 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; using System.Security.Authentication.ExtendedProtection; using Microsoft.Win32.SafeHandles; @@ -310,10 +311,15 @@ public override bool IsInvalid internal sealed class SafeFreeCredential_SECURITY : SafeFreeCredentials { +#pragma warning disable 0649 + // This is used only by SslStream but it is included elsewhere + public X509Certificate? LocalCertificate; +#pragma warning restore 0649 public SafeFreeCredential_SECURITY() : base() { } protected override bool ReleaseHandle() { + LocalCertificate?.Dispose(); return Interop.SspiCli.FreeCredentialsHandle(ref _handle) == 0; } } diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs index 90de3cdee7b9..2962e25c6cd5 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs @@ -148,7 +148,8 @@ public async Task UseCallback_ValidCertificate_ExpectedValuesDuringCallback(Conf { bool callbackCalled = false; handler.CheckCertificateRevocationList = checkRevocation; - handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => { + handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => + { callbackCalled = true; Assert.NotNull(request); @@ -227,6 +228,7 @@ public async Task NoCallback_BadCertificate_ThrowsException(string url) } [OuterLoop("Uses external servers")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/77726")] [ConditionalFact(nameof(ClientSupportsDHECipherSuites))] public async Task NoCallback_RevokedCertificate_NoRevocationChecking_Succeeds() { diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.cs index e72d42e87d21..55a044d62a69 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.cs @@ -338,19 +338,10 @@ private void RsaCryptRoundtrip(RSAEncryptionPadding paddingMode, bool expectSucc Assert.Equal(TestData.HelloBytes, output); } - [ConditionalFact] + [ConditionalFact(nameof(PlatformSupportsEmptyRSAEncryption))] [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] public void RoundtripEmptyArray() { - if (OperatingSystem.IsIOS() && !OperatingSystem.IsIOSVersionAtLeast(13, 6)) - { - throw new SkipTestException("iOS prior to 13.6 does not reliably support RSA encryption of empty data."); - } - if (OperatingSystem.IsTvOS() && !OperatingSystem.IsTvOSVersionAtLeast(14, 0)) - { - throw new SkipTestException("tvOS prior to 14.0 does not reliably support RSA encryption of empty data."); - } - using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params)) { void RoundtripEmpty(RSAEncryptionPadding paddingMode) @@ -701,6 +692,26 @@ public void NotSupportedValueMethods() } } + [ConditionalTheory] + [InlineData(new byte[] { 1, 2, 3, 4 })] + [InlineData(new byte[0])] + public void Decrypt_Pkcs1_ErrorsForInvalidPadding(byte[] data) + { + if (data.Length == 0 && !PlatformSupportsEmptyRSAEncryption) + { + throw new SkipTestException("Platform does not support RSA encryption of empty data."); + } + + using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params)) + { + byte[] encrypted = Encrypt(rsa, data, RSAEncryptionPadding.Pkcs1); + encrypted[1] ^= 0xFF; + + // PKCS#1, the data, and the key are all deterministic so this should always throw an exception. + Assert.ThrowsAny(() => Decrypt(rsa, encrypted, RSAEncryptionPadding.Pkcs1)); + } + } + public static IEnumerable OaepPaddingModes { get @@ -715,5 +726,23 @@ public static IEnumerable OaepPaddingModes } } } + + public static bool PlatformSupportsEmptyRSAEncryption + { + get + { + if (OperatingSystem.IsIOS() && !OperatingSystem.IsIOSVersionAtLeast(13, 6)) + { + return false; + } + + if (OperatingSystem.IsTvOS() && !OperatingSystem.IsTvOSVersionAtLeast(14, 0)) + { + return false; + } + + return true; + } + } } } diff --git a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs index b08655e6f1d1..afed3b929aae 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs @@ -16,6 +16,9 @@ internal sealed class RevocationResponder : IDisposable private static readonly bool s_traceEnabled = Environment.GetEnvironmentVariable("TRACE_REVOCATION_RESPONSE") != null; + private static readonly byte[] s_invalidResponse = + "The server is down for maintenence."u8.ToArray(); + private readonly HttpListener _listener; private readonly Dictionary _aiaPaths = @@ -29,7 +32,7 @@ internal sealed class RevocationResponder : IDisposable public string UriPrefix { get; } - public bool RespondEmpty { get; set; } + public RespondKind RespondKind { get; set; } public AiaResponseKind AiaResponseKind { get; set; } public TimeSpan ResponseDelay { get; set; } @@ -183,7 +186,12 @@ private void HandleRequest(HttpListenerContext context, ref bool responded) Thread.Sleep(ResponseDelay); } - byte[] certData = RespondEmpty ? Array.Empty() : GetCertDataForAiaResponseKind(AiaResponseKind, authority); + byte[] certData = RespondKind switch + { + RespondKind.Empty => Array.Empty(), + RespondKind.Invalid => s_invalidResponse, + _ => GetCertDataForAiaResponseKind(AiaResponseKind, authority), + }; responded = true; context.Response.StatusCode = 200; @@ -201,7 +209,12 @@ private void HandleRequest(HttpListenerContext context, ref bool responded) Thread.Sleep(ResponseDelay); } - byte[] crl = RespondEmpty ? Array.Empty() : authority.GetCrl(); + byte[] crl = RespondKind switch + { + RespondKind.Empty => Array.Empty(), + RespondKind.Invalid => s_invalidResponse, + _ => authority.GetCrl(), + }; responded = true; context.Response.StatusCode = 200; @@ -236,7 +249,12 @@ private void HandleRequest(HttpListenerContext context, ref bool responded) return; } - byte[] ocspResponse = RespondEmpty ? Array.Empty() : authority.BuildOcspResponse(certId, nonce); + byte[] ocspResponse = RespondKind switch + { + RespondKind.Empty => Array.Empty(), + RespondKind.Invalid => s_invalidResponse, + _ => authority.BuildOcspResponse(certId, nonce), + }; if (DelayedActions.HasFlag(DelayedActionsFlag.Ocsp)) { @@ -468,4 +486,11 @@ public enum AiaResponseKind Cert = 0, Pkcs12 = 1, } + + public enum RespondKind + { + Normal = 0, + Empty = 1, + Invalid = 2, + } } diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs index 881a72f78fe4..b6c0ca663a54 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs @@ -301,6 +301,7 @@ public void ProcessStart_UseShellExecute_OnWindows_DoesNotThrow(bool isFolder) [ActiveIssue("https://github.com/dotnet/runtime/issues/34685", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [InlineData(true), InlineData(false)] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "Not supported on iOS and tvOS.")] + [SkipOnPlatform(TestPlatforms.Android, "Android doesn't allow executing custom shell scripts")] public void ProcessStart_UseShellExecute_Executes(bool filenameAsUrl) { string filename = WriteScriptFile(TestDirectory, GetTestFileName(), returnValue: 42); @@ -373,6 +374,7 @@ public void ProcessStart_UseShellExecute_ExecuteOrder() nameof(PlatformDetection.IsNotAppSandbox))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34685", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "Not supported on iOS and tvOS.")] + [SkipOnPlatform(TestPlatforms.Android, "Android doesn't allow executing custom shell scripts")] public void ProcessStart_UseShellExecute_WorkingDirectory() { // Create a directory that will ProcessStartInfo.WorkingDirectory @@ -2621,7 +2623,7 @@ public void NonElevatedUser_QueryProcessNameOfSystemProcess() { // returns the username of the owner of the process or null if the username can't be queried. // for services.exe, this will be null. - string? servicesUser = Helpers.GetProcessUserName(p); + string? servicesUser = Helpers.GetProcessUserName(p); // this isn't really verifying that services.exe is owned by SYSTEM, but we are sure it is not owned by the current user. if (servicesUser != currentProcessUser) diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs index 3cec81f62a50..3c33adeb028c 100644 --- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs @@ -207,6 +207,7 @@ public void PaxNameCollision_DedupInExtendedAttributes() [Theory] [MemberData(nameof(GetExactRootDirMatchCases))] + [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "The temporary directory on Apple mobile platforms exceeds the path length limit.")] public void ExtractToDirectory_ExactRootDirMatch_RegularFile_And_Directory_Throws(TarEntryFormat format, TarEntryType entryType, string fileName) { ExtractToDirectory_ExactRootDirMatch_RegularFile_And_Directory_Throws_Internal(format, entryType, fileName, inverted: false); @@ -214,6 +215,7 @@ public void ExtractToDirectory_ExactRootDirMatch_RegularFile_And_Directory_Throw } [Fact] + [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "The temporary directory on Apple mobile platforms exceeds the path length limit.")] public void ExtractToDirectory_ExactRootDirMatch_Directory_Relative_Throws() { string entryFolderName = "folder"; @@ -240,6 +242,7 @@ public void ExtractToDirectory_ExactRootDirMatch_Directory_Relative_Throws() [InlineData(TarEntryFormat.Ustar)] [InlineData(TarEntryFormat.Pax)] [InlineData(TarEntryFormat.Gnu)] + [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "The temporary directory on Apple mobile platforms exceeds the path length limit.")] public void ExtractToDirectory_ExactRootDirMatch_HardLinks_Throws(TarEntryFormat format) { ExtractToDirectory_ExactRootDirMatch_Links_Throws(format, TarEntryType.HardLink, inverted: false); diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs index a765f4f911eb..2ec99926dcc1 100644 --- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs @@ -272,6 +272,7 @@ await using (TarWriter writer = new(stream, TarEntryFormat.Pax, leaveOpen: true) [Theory] [MemberData(nameof(GetExactRootDirMatchCases))] + [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "The temporary directory on Apple mobile platforms exceeds the path length limit.")] public async Task ExtractToDirectory_ExactRootDirMatch_RegularFile_And_Directory_Throws_Async(TarEntryFormat format, TarEntryType entryType, string fileName) { await ExtractToDirectory_ExactRootDirMatch_RegularFile_And_Directory_Throws_Internal_Async(format, entryType, fileName, inverted: false); @@ -279,6 +280,7 @@ public async Task ExtractToDirectory_ExactRootDirMatch_RegularFile_And_Directory } [Fact] + [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "The temporary directory on Apple mobile platforms exceeds the path length limit.")] public async Task ExtractToDirectory_ExactRootDirMatch_Directory_Relative_Throws_Async() { string entryFolderName = "folder"; @@ -305,6 +307,7 @@ public async Task ExtractToDirectory_ExactRootDirMatch_Directory_Relative_Throws [InlineData(TarEntryFormat.Ustar)] [InlineData(TarEntryFormat.Pax)] [InlineData(TarEntryFormat.Gnu)] + [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "The temporary directory on Apple mobile platforms exceeds the path length limit.")] public async Task ExtractToDirectory_ExactRootDirMatch_HardLinks_Throws_Async(TarEntryFormat format) { await ExtractToDirectory_ExactRootDirMatch_Links_Throws_Async(format, TarEntryType.HardLink, inverted: false); diff --git a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Android.cs b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Android.cs index 43716cd04367..96962f9240be 100644 --- a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Android.cs +++ b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Android.cs @@ -18,7 +18,7 @@ internal static partial class CertificateValidationPal string? hostName) { if (remoteCertificate == null) - return SslPolicyErrors.RemoteCertificateNotAvailable; + return SslPolicyErrors.RemoteCertificateNotAvailable; SslPolicyErrors errors = chain.Build(remoteCertificate) ? SslPolicyErrors.None @@ -91,6 +91,10 @@ internal static partial class CertificateValidationPal return cert; } + // This is only called when we selected local client certificate. + // Currently this is only when Java crypto asked for it. + internal static bool IsLocalCertificateUsed(SafeFreeCredentials? _1, SafeDeleteContext? _2) => true; + // // Used only by client SSL code, never returns null. // diff --git a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.OSX.cs b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.OSX.cs index f9d3afe570af..3bd0c7142c3f 100644 --- a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.OSX.cs +++ b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.OSX.cs @@ -102,6 +102,10 @@ internal static partial class CertificateValidationPal return result; } + // This is only called when we selected local client certificate. + // Currently this is only when Apple crypto asked for it. + internal static bool IsLocalCertificateUsed(SafeFreeCredentials? _1, SafeDeleteContext? _2) => true; + // // Used only by client SSL code, never returns null. // diff --git a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs index 498a09541037..90b9275e9af3 100644 --- a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs +++ b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs @@ -101,6 +101,10 @@ internal static partial class CertificateValidationPal return result; } + // This is only called when we selected local client certificate. + // Currently this is only when OpenSSL needs it because peer asked. + internal static bool IsLocalCertificateUsed(SafeFreeCredentials? _1, SafeDeleteContext? _2) => true; + // // Used only by client SSL code, never returns null. // diff --git a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs index 1ead906ec358..ecdfef024293 100644 --- a/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs @@ -8,6 +8,7 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Principal; +using static Interop.SspiCli; namespace System.Net { @@ -89,6 +90,44 @@ internal static partial class CertificateValidationPal return result; } + // Check that local certificate was used by schannel. + internal static bool IsLocalCertificateUsed(SafeFreeCredentials? credentialsHandle, SafeDeleteContext securityContext) + { + SecPkgContext_SessionInfo info = default; + + // fails on Server 2008 and older. We will fall-back to probing LOCAL_CERT_CONTEXT in that case. + if (SSPIWrapper.QueryBlittableContextAttributes( + GlobalSSPI.SSPISecureChannel, + securityContext, + Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SESSION_INFO, + ref info) && + ((SecPkgContext_SessionInfo.Flags)info.dwFlags).HasFlag(SecPkgContext_SessionInfo.Flags.SSL_SESSION_RECONNECT)) + { + // This is TLS Resumed session. Windows can fail to query the local cert bellow. + // Instead, we will determine the usage form used credentials. + SafeFreeCredential_SECURITY creds = (SafeFreeCredential_SECURITY)credentialsHandle!; + return creds.LocalCertificate != null; + } + + SafeFreeCertContext? localContext = null; + try + { + if (SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_LOCAL_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext, out localContext) && + localContext != null) + { + return !localContext.IsInvalid; + } + } + finally + { + localContext?.Dispose(); + } + + // Some older Windows do not support that. This is only called when client certificate was provided + // so assume it was for a reason. + return true; + } + // // Used only by client SSL code, never returns null. // diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs index 1d4dfa9ac6b0..45f0bbe408f2 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs @@ -30,8 +30,6 @@ public partial class SslStream private int _trailerSize = 16; private int _maxDataSize = 16354; - private bool _refreshCredentialNeeded = true; - private static readonly Oid s_serverAuthOid = new Oid("1.3.6.1.5.5.7.3.1", "1.3.6.1.5.5.7.3.1"); private static readonly Oid s_clientAuthOid = new Oid("1.3.6.1.5.5.7.3.2", "1.3.6.1.5.5.7.3.2"); @@ -56,7 +54,12 @@ public partial class SslStream { get { - return _selectedClientCertificate; + if (_selectedClientCertificate != null && CertificateValidationPal.IsLocalCertificateUsed(_credentialsHandle, _securityContext!)) + { + return _selectedClientCertificate; + } + + return null; } } @@ -104,11 +107,6 @@ internal bool RemoteCertRequired } } - internal void SetRefreshCredentialNeeded() - { - _refreshCredentialNeeded = true; - } - internal void CloseContext() { if (!_remoteCertificateExposed) @@ -510,7 +508,7 @@ private string[] GetRequestCertificateAuthorities() --*/ - private bool AcquireClientCredentials(ref byte[]? thumbPrint) + private bool AcquireClientCredentials(ref byte[]? thumbPrint, bool newCredentialsRequested = false) { // Acquire possible Client Certificate information and set it on the handle. @@ -518,7 +516,6 @@ private bool AcquireClientCredentials(ref byte[]? thumbPrint) bool cachedCred = false; // this is a return result from this method. X509Certificate2? selectedCert = SelectClientCertificate(out sessionRestartAttempt); - try { // Try to locate cached creds first. @@ -576,7 +573,7 @@ private bool AcquireClientCredentials(ref byte[]? thumbPrint) _sslAuthenticationOptions.CertificateContext = SslStreamCertificateContext.Create(selectedCert!); } - _credentialsHandle = AcquireCredentialsHandle(_sslAuthenticationOptions); + _credentialsHandle = AcquireCredentialsHandle(_sslAuthenticationOptions, newCredentialsRequested); thumbPrint = guessedThumbPrint; // Delay until here in case something above threw. } } @@ -687,9 +684,9 @@ private bool AcquireServerCredentials(ref byte[]? thumbPrint) return cachedCred; } - private static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) + private static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions, bool newCredentialsRequested = false) { - SafeFreeCredentials? cred = SslStreamPal.AcquireCredentialsHandle(sslAuthenticationOptions); + SafeFreeCredentials? cred = SslStreamPal.AcquireCredentialsHandle(sslAuthenticationOptions, newCredentialsRequested); if (sslAuthenticationOptions.CertificateContext != null && cred != null) { @@ -749,7 +746,6 @@ internal ProtocolToken NextMessage(ReadOnlySpan incomingBuffer) if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "NextMessage() returned SecurityStatusPal.CredentialsNeeded"); - SetRefreshCredentialNeeded(); status = GenerateToken(incomingBuffer, ref nextmsg); } @@ -788,6 +784,11 @@ private SecurityStatusPal GenerateToken(ReadOnlySpan inputBuffer, ref byte bool sendTrustList = false; byte[]? thumbPrint = null; + // We need to try get credentials at the beginning. + // _credentialsHandle may be always null on some platforms but + // _securityContext will be allocated on first call. + bool refreshCredentialNeeded = _securityContext == null; + // // Looping through ASC or ISC with potentially cached credential that could have been // already disposed from a different thread before ISC or ASC dir increment a cred ref count. @@ -797,7 +798,7 @@ private SecurityStatusPal GenerateToken(ReadOnlySpan inputBuffer, ref byte do { thumbPrint = null; - if (_refreshCredentialNeeded) + if (refreshCredentialNeeded) { cachedCreds = _sslAuthenticationOptions.IsServer ? AcquireServerCredentials(ref thumbPrint) @@ -826,15 +827,31 @@ private SecurityStatusPal GenerateToken(ReadOnlySpan inputBuffer, ref byte _sslAuthenticationOptions, SelectClientCertificate ); + + if (status.ErrorCode == SecurityStatusPalErrorCode.CredentialsNeeded) + { + refreshCredentialNeeded = true; + cachedCreds = AcquireClientCredentials(ref thumbPrint, newCredentialsRequested: true); + + if (NetEventSource.Log.IsEnabled()) + NetEventSource.Info(this, "InitializeSecurityContext() returned 'CredentialsNeeded'."); + + status = SslStreamPal.InitializeSecurityContext( + ref _credentialsHandle!, + ref _securityContext, + _sslAuthenticationOptions.TargetHost, + inputBuffer, + ref result, + _sslAuthenticationOptions, + SelectClientCertificate); + } } } while (cachedCreds && _credentialsHandle == null); } finally { - if (_refreshCredentialNeeded) + if (refreshCredentialNeeded) { - _refreshCredentialNeeded = false; - // // Assuming the ISC or ASC has referenced the credential, // we want to call dispose so to decrement the effective ref count. @@ -974,7 +991,6 @@ internal bool VerifyRemoteCertificate(RemoteCertificateValidationCallback? remot } _remoteCertificate = certificate; - if (_remoteCertificate == null) { if (NetEventSource.Log.IsEnabled() && RemoteCertRequired) NetEventSource.Error(this, $"Remote certificate required, but no remote certificate received"); diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs index 20574597af70..f47f9b597618 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Linux.cs @@ -25,14 +25,31 @@ public partial class SslStreamCertificateContext private byte[]? _ocspResponse; private DateTimeOffset _ocspExpiration; private DateTimeOffset _nextDownload; + // Private copy of the intermediate certificates, in case the user decides to dispose the + // instances reachable through IntermediateCertificates property. + private X509Certificate2[] _privateIntermediateCertificates; + private X509Certificate2? _rootCertificate; private Task? _pendingDownload; private List? _ocspUrls; - private X509Certificate2? _ca; private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] intermediates, SslCertificateTrust? trust) { Certificate = target; IntermediateCertificates = intermediates; + if (intermediates.Length > 0) + { + _privateIntermediateCertificates = new X509Certificate2[intermediates.Length]; + + for (int i = 0; i < intermediates.Length; i++) + { + _privateIntermediateCertificates[i] = new X509Certificate2(intermediates[i]); + } + } + else + { + _privateIntermediateCertificates = Array.Empty(); + } + Trust = trust; SslContexts = new ConcurrentDictionary(); @@ -54,7 +71,7 @@ private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] } } - if (KeyHandle== null) + if (KeyHandle == null) { throw new NotSupportedException(SR.net_ssl_io_no_server_cert); } @@ -75,15 +92,8 @@ private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] partial void AddRootCertificate(X509Certificate2? rootCertificate, ref bool transferredOwnership) { - if (IntermediateCertificates.Length == 0) - { - _ca = rootCertificate; - transferredOwnership = true; - } - else - { - _ca = IntermediateCertificates[0]; - } + _rootCertificate = rootCertificate; + transferredOwnership = rootCertificate != null; if (!_staplingForbidden) { @@ -148,7 +158,7 @@ private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] return new ValueTask(pending); } - if (_ocspUrls is null && _ca is not null) + if (_ocspUrls is null && _rootCertificate is not null) { foreach (X509Extension ext in Certificate.Extensions) { @@ -191,7 +201,9 @@ private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] private async Task FetchOcspAsync() { - X509Certificate2? caCert = _ca; + Debug.Assert(_rootCertificate != null); + X509Certificate2? caCert = _privateIntermediateCertificates.Length > 0 ? _privateIntermediateCertificates[0] : _rootCertificate; + Debug.Assert(_ocspUrls is not null); Debug.Assert(_ocspUrls.Count > 0); Debug.Assert(caCert is not null); @@ -210,6 +222,13 @@ private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] return null; } + IntPtr[] issuerHandles = ArrayPool.Shared.Rent(_privateIntermediateCertificates.Length + 1); + for (int i = 0; i < _privateIntermediateCertificates.Length; i++) + { + issuerHandles[i] = _privateIntermediateCertificates[i].Handle; + } + issuerHandles[_privateIntermediateCertificates.Length] = _rootCertificate.Handle; + using (SafeOcspRequestHandle ocspRequest = Interop.Crypto.X509BuildOcspRequest(subject, issuer)) { byte[] rentedBytes = ArrayPool.Shared.Rent(Interop.Crypto.GetOcspRequestDerSize(ocspRequest)); @@ -226,8 +245,9 @@ private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] if (ret is not null) { - if (!Interop.Crypto.X509DecodeOcspToExpiration(ret, ocspRequest, subject, issuer, out DateTimeOffset expiration)) + if (!Interop.Crypto.X509DecodeOcspToExpiration(ret, ocspRequest, subject, issuerHandles.AsSpan(0, _privateIntermediateCertificates.Length + 1), out DateTimeOffset expiration)) { + ret = null; continue; } @@ -245,15 +265,27 @@ private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] _ocspResponse = ret; _ocspExpiration = expiration; _nextDownload = nextCheckA < nextCheckB ? nextCheckA : nextCheckB; - _pendingDownload = null; break; } } + issuerHandles.AsSpan().Clear(); + ArrayPool.Shared.Return(issuerHandles); ArrayPool.Shared.Return(rentedBytes); ArrayPool.Shared.Return(rentedChars.Array!); GC.KeepAlive(Certificate); + GC.KeepAlive(_privateIntermediateCertificates); + GC.KeepAlive(_rootCertificate); GC.KeepAlive(caCert); + + _pendingDownload = null; + if (ret == null) + { + // All download attempts failed, don't try again for 5 seconds. + // This backoff will be applied only if the OCSP staple is not expired. + // If it is expired, we will force-refresh it during next GetOcspResponseAsync call. + _nextDownload = DateTimeOffset.UtcNow.AddSeconds(5); + } return ret; } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs index f01dd68e294b..184cbd2a8177 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs @@ -55,7 +55,7 @@ public static void VerifyPackageInfo() throw new PlatformNotSupportedException(); } - public static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) + public static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions _1, bool _2) { return null; } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs index 255b30d7f2c2..d8fc15ca7a54 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs @@ -62,7 +62,7 @@ public static void VerifyPackageInfo() throw new PlatformNotSupportedException(); } - public static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) + public static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions _1, bool _2) { return null; } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs index 1e1a0df55889..e4188015d416 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs @@ -46,7 +46,7 @@ public static void VerifyPackageInfo() return HandshakeInternal(ref context, inputBuffer, ref outputBuffer, sslAuthenticationOptions, clientCertificateSelectionCallback); } - public static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) + public static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions _1, bool _2) { return null; } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs index 1321cc0754ed..2c6929314580 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs @@ -136,7 +136,7 @@ public static byte[] ConvertAlpnProtocolListToByteArray(List)fetchOcspAsyncMethod.Invoke(context, Array.Empty()); + Assert.Null(ocspFetch); + + byte[] ocspResponseValue = (byte[])ocspResponseField.GetValue(context); + Assert.Null(ocspResponseValue); + } + } + } +} diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamMutualAuthenticationTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamMutualAuthenticationTest.cs index fc34a29fdc7b..90c0a6cb0490 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamMutualAuthenticationTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamMutualAuthenticationTest.cs @@ -8,6 +8,7 @@ using System.Security.Cryptography.X509Certificates; using Xunit; +using System.Runtime.InteropServices; namespace System.Net.Security.Tests { @@ -32,6 +33,38 @@ public void Dispose() _clientCertificate.Dispose(); } + public enum ClientCertSource + { + ClientCertificate, + SelectionCallback, + } + + public static TheoryData CertSourceData() + { + TheoryData data = new(); + + foreach (var source in Enum.GetValues()) + { + data.Add(source); + } + + return data; + } + + + public static TheoryData BoolAndCertSourceData() + { + TheoryData data = new(); + + foreach (var source in Enum.GetValues()) + { + data.Add(true, source); + data.Add(false, source); + } + + return data; + } + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] [InlineData(false, false)] [InlineData(false, true)] @@ -83,9 +116,112 @@ public async Task SslStream_RequireClientCert_IsMutuallyAuthenticated_ReturnsTru } } + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [ClassData(typeof(SslProtocolSupport.SupportedSslProtocolsTestData))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/65563", TestPlatforms.Android)] + public async Task SslStream_CachedCredentials_IsMutuallyAuthenticatedCorrect( + SslProtocols protocol) + { + var clientOptions = new SslClientAuthenticationOptions + { + ClientCertificates = new X509CertificateCollection() { _clientCertificate }, + EnabledSslProtocols = protocol, + RemoteCertificateValidationCallback = delegate { return true; }, + TargetHost = Guid.NewGuid().ToString("N") + }; + + for (int i = 0; i < 5; i++) + { + (SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams(); + using (client) + using (server) + { + bool expectMutualAuthentication = (i % 2) == 0; + + var serverOptions = new SslServerAuthenticationOptions + { + ClientCertificateRequired = expectMutualAuthentication, + ServerCertificate = expectMutualAuthentication ? _serverCertificate : _selfSignedCertificate, + RemoteCertificateValidationCallback = delegate { return true; }, + EnabledSslProtocols = protocol + }; + + await TestConfiguration.WhenAllOrAnyFailedWithTimeout( + client.AuthenticateAsClientAsync(clientOptions), + server.AuthenticateAsServerAsync(serverOptions)); + + // mutual authentication should only be set if server required client cert + Assert.Equal(expectMutualAuthentication, server.IsMutuallyAuthenticated); + Assert.Equal(expectMutualAuthentication, client.IsMutuallyAuthenticated); + }; + } + } + + [ConditionalTheory(typeof(TestConfiguration), nameof(TestConfiguration.SupportsRenegotiation))] + [MemberData(nameof(CertSourceData))] + [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)] + public async Task SslStream_NegotiateClientCertificate_IsMutuallyAuthenticatedCorrect(ClientCertSource certSource) + { + SslStreamCertificateContext context = SslStreamCertificateContext.Create(_serverCertificate, null); + var clientOptions = new SslClientAuthenticationOptions + { + TargetHost = Guid.NewGuid().ToString("N") + }; + + for (int round = 0; round < 3; round++) + { + (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); + using (var client = new SslStream(stream1, false, AllowAnyCertificate)) + using (var server = new SslStream(stream2, false, AllowAnyCertificate)) + { + + switch (certSource) + { + case ClientCertSource.ClientCertificate: + clientOptions.ClientCertificates = new X509CertificateCollection() { _clientCertificate }; + break; + case ClientCertSource.SelectionCallback: + clientOptions.LocalCertificateSelectionCallback = ClientCertSelectionCallback; + break; + } + + Task t2 = client.AuthenticateAsClientAsync(clientOptions); + Task t1 = server.AuthenticateAsServerAsync(new SslServerAuthenticationOptions + { + ServerCertificateContext = context, + ClientCertificateRequired = false, + EnabledSslProtocols = SslProtocols.Tls12, + + }); + + await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); + + if (round >= 0 && server.RemoteCertificate != null) + { + // TLS resumed + Assert.True(client.IsMutuallyAuthenticated, "client.IsMutuallyAuthenticated"); + Assert.True(server.IsMutuallyAuthenticated, "server.IsMutuallyAuthenticated"); + continue; + } + + Assert.False(client.IsMutuallyAuthenticated, "client.IsMutuallyAuthenticated"); + Assert.False(server.IsMutuallyAuthenticated, "server.IsMutuallyAuthenticated"); + + var t = client.ReadAsync(new byte[1]); + await server.NegotiateClientCertificateAsync(); + Assert.NotNull(server.RemoteCertificate); + await server.WriteAsync(new byte[1]); + await t; + + Assert.NotNull(server.RemoteCertificate); + Assert.True(client.IsMutuallyAuthenticated, "client.IsMutuallyAuthenticated"); + Assert.True(server.IsMutuallyAuthenticated, "server.IsMutuallyAuthenticated"); + } + } + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] [ClassData(typeof(SslProtocolSupport.SupportedSslProtocolsTestData))] - [PlatformSpecific(TestPlatforms.Linux)] // https://github.com/dotnet/runtime/issues/65563 - [Theory] public async Task SslStream_ResumedSessionsClientCollection_IsMutuallyAuthenticatedCorrect( SslProtocols protocol) { @@ -128,7 +264,7 @@ public async Task SslStream_RequireClientCert_IsMutuallyAuthenticated_ReturnsTru } else { - Assert.Null(server.RemoteCertificate); + Assert.Null(server.RemoteCertificate); } }; } @@ -183,7 +319,7 @@ public async Task SslStream_RequireClientCert_IsMutuallyAuthenticated_ReturnsTru } else { - Assert.Null(server.RemoteCertificate); + Assert.Null(server.RemoteCertificate); } }; } @@ -221,7 +357,7 @@ public async Task SslStream_RequireClientCert_IsMutuallyAuthenticated_ReturnsTru if (expectMutualAuthentication) { - clientOptions.LocalCertificateSelectionCallback = (s, t, l, r, a) => _clientCertificate; + clientOptions.LocalCertificateSelectionCallback = (s, t, l, r, a) => _clientCertificate; } else { @@ -242,7 +378,7 @@ public async Task SslStream_RequireClientCert_IsMutuallyAuthenticated_ReturnsTru } else { - Assert.Null(server.RemoteCertificate); + Assert.Null(server.RemoteCertificate); } }; } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index 7c3d432f34cb..b31313499753 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -31,6 +31,7 @@ + diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/AiaTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/AiaTests.cs index c2e70c7f150a..1a339b57c65a 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/AiaTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/AiaTests.cs @@ -33,7 +33,7 @@ public static void EmptyAiaResponseIsIgnored() using (endEntity) using (X509Certificate2 intermediate2Cert = intermediate2.CloneIssuerCert()) { - responder.RespondEmpty = true; + responder.RespondKind = RespondKind.Empty; RetryHelper.Execute(() => { using (ChainHolder holder = new ChainHolder()) diff --git a/src/native/libs/System.Security.Cryptography.Native/opensslshim.h b/src/native/libs/System.Security.Cryptography.Native/opensslshim.h index efc0d4706027..7d5ec84cc7d5 100644 --- a/src/native/libs/System.Security.Cryptography.Native/opensslshim.h +++ b/src/native/libs/System.Security.Cryptography.Native/opensslshim.h @@ -276,8 +276,10 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); REQUIRED_FUNCTION(ERR_peek_error) \ REQUIRED_FUNCTION(ERR_peek_error_line) \ REQUIRED_FUNCTION(ERR_peek_last_error) \ + REQUIRED_FUNCTION(ERR_pop_to_mark) \ FALLBACK_FUNCTION(ERR_put_error) \ REQUIRED_FUNCTION(ERR_reason_error_string) \ + REQUIRED_FUNCTION(ERR_set_mark) \ LIGHTUP_FUNCTION(ERR_set_debug) \ LIGHTUP_FUNCTION(ERR_set_error) \ REQUIRED_FUNCTION(EVP_aes_128_cbc) \ @@ -332,6 +334,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); REQUIRED_FUNCTION(EVP_PKCS82PKEY) \ REQUIRED_FUNCTION(EVP_PKEY2PKCS8) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_ctrl) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_ctrl_str) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_free) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_get0_pkey) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_new) \ @@ -758,8 +761,10 @@ FOR_ALL_OPENSSL_FUNCTIONS #define ERR_peek_error_line ERR_peek_error_line_ptr #define ERR_peek_last_error ERR_peek_last_error_ptr #define ERR_put_error ERR_put_error_ptr +#define ERR_pop_to_mark ERR_pop_to_mark_ptr #define ERR_reason_error_string ERR_reason_error_string_ptr #define ERR_set_debug ERR_set_debug_ptr +#define ERR_set_mark ERR_set_mark_ptr #define ERR_set_error ERR_set_error_ptr #define EVP_aes_128_cbc EVP_aes_128_cbc_ptr #define EVP_aes_128_cfb8 EVP_aes_128_cfb8_ptr @@ -813,6 +818,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_PKCS82PKEY EVP_PKCS82PKEY_ptr #define EVP_PKEY2PKCS8 EVP_PKEY2PKCS8_ptr #define EVP_PKEY_CTX_ctrl EVP_PKEY_CTX_ctrl_ptr +#define EVP_PKEY_CTX_ctrl_str EVP_PKEY_CTX_ctrl_str_ptr #define EVP_PKEY_CTX_free EVP_PKEY_CTX_free_ptr #define EVP_PKEY_CTX_get0_pkey EVP_PKEY_CTX_get0_pkey_ptr #define EVP_PKEY_CTX_new EVP_PKEY_CTX_new_ptr diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c index c9ccdf33e3af..043bf9f9d1ed 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c @@ -67,6 +67,19 @@ static bool ConfigureEncryption(EVP_PKEY_CTX* ctx, RsaPaddingMode padding, const { return false; } + + // OpenSSL 3.2 introduced a change where PKCS#1 RSA decryption does not fail for invalid padding. + // If the padding is invalid, the decryption operation returns random data. + // See https://github.com/openssl/openssl/pull/13817 for background. + // Some Linux distributions backported this change to previous versions of OpenSSL. + // Here we do a best-effort to set a flag to revert the behavior to failing if the padding is invalid. + ERR_set_mark(); + + EVP_PKEY_CTX_ctrl_str(ctx, "rsa_pkcs1_implicit_rejection", "0"); + + // Undo any changes to the error queue that may have occured while configuring implicit rejection if the + // current version does not support implicit rejection. + ERR_pop_to_mark(); } else { diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c index 431c2b8ec067..6372802c2c18 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_ssl.c @@ -577,7 +577,7 @@ X509* CryptoNative_SslGetPeerCertificate(SSL* ssl) long len = SSL_get_tlsext_status_ocsp_resp(ssl, &data); X509* cert = SSL_get1_peer_certificate(ssl); - if (len > 0 && cert != NULL) + if (len > 0 && cert != NULL && !X509_get_ex_data(cert, g_x509_ocsp_index)) { OCSP_RESPONSE* ocspResp = d2i_OCSP_RESPONSE(NULL, &data, len); diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_x509.c b/src/native/libs/System.Security.Cryptography.Native/pal_x509.c index 3681d1f3cb30..11e3910a98e1 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_x509.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_x509.c @@ -1280,11 +1280,11 @@ CryptoNative_X509ChainVerifyOcsp(X509_STORE_CTX* storeCtx, OCSP_REQUEST* req, OC return X509ChainVerifyOcsp(storeCtx, subject, issuer, req, resp, cachePath); } -int32_t CryptoNative_X509DecodeOcspToExpiration(const uint8_t* buf, int32_t len, OCSP_REQUEST* req, X509* subject, X509* issuer, int64_t* expiration) +int32_t CryptoNative_X509DecodeOcspToExpiration(const uint8_t* buf, int32_t len, OCSP_REQUEST* req, X509* subject, X509** issuers, int issuersLen, int64_t* expiration) { ERR_clear_error(); - if (buf == NULL || len == 0) + if (buf == NULL || len == 0 || issuersLen == 0) { return 0; } @@ -1307,7 +1307,16 @@ int32_t CryptoNative_X509DecodeOcspToExpiration(const uint8_t* buf, int32_t len, if (bag != NULL) { - if (X509_STORE_add_cert(store, issuer) && sk_X509_push(bag, issuer)) + int i; + for (i = 0; i < issuersLen; i++) + { + if (!X509_STORE_add_cert(store, issuers[i]) || !sk_X509_push(bag, issuers[i])) + { + break; + } + } + + if (i == issuersLen) { ctx = X509_STORE_CTX_new(); } @@ -1321,7 +1330,7 @@ int32_t CryptoNative_X509DecodeOcspToExpiration(const uint8_t* buf, int32_t len, { int canCache = 0; time_t expiration_t = 0; - X509VerifyStatusCode code = CheckOcspGetExpiry(req, resp, subject, issuer, ctx, &canCache, &expiration_t); + X509VerifyStatusCode code = CheckOcspGetExpiry(req, resp, subject, issuers[0], ctx, &canCache, &expiration_t); if (sizeof(time_t) == sizeof(int64_t)) { diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_x509.h b/src/native/libs/System.Security.Cryptography.Native/pal_x509.h index bcee51f069df..c51d5ee4b02d 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_x509.h +++ b/src/native/libs/System.Security.Cryptography.Native/pal_x509.h @@ -407,4 +407,4 @@ PALEXPORT int32_t CryptoNative_X509ChainVerifyOcsp(X509_STORE_CTX* storeCtx, Decode len bytes of buf into an OCSP response, process it against the OCSP request, and return if the bytes were valid. If the bytes were valid, and the OCSP response had a nextUpdate value, assign it to expiration. */ -PALEXPORT int32_t CryptoNative_X509DecodeOcspToExpiration(const uint8_t* buf, int32_t len, OCSP_REQUEST* req, X509* subject, X509* issuer, int64_t* expiration); +PALEXPORT int32_t CryptoNative_X509DecodeOcspToExpiration(const uint8_t* buf, int32_t len, OCSP_REQUEST* req, X509* subject, X509** issuers, int issuersLen, int64_t* expiration); diff --git a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs index 0f409c1745f7..dfcb4e3948cf 100644 --- a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs +++ b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs @@ -73,6 +73,8 @@ public class AndroidAppBuilderTask : Task public string? MinApiLevel { get; set; } + public string? TargetApiLevel { get; set; } + public string? BuildApiLevel { get; set; } public string? BuildToolsVersion { get; set; } @@ -108,6 +110,7 @@ public override bool Execute() apkBuilder.AndroidSdk = AndroidSdk; apkBuilder.AndroidNdk = AndroidNdk; apkBuilder.MinApiLevel = MinApiLevel; + apkBuilder.TargetApiLevel = TargetApiLevel; apkBuilder.BuildApiLevel = BuildApiLevel; apkBuilder.BuildToolsVersion = BuildToolsVersion; apkBuilder.StripDebugSymbols = StripDebugSymbols; diff --git a/src/tasks/AndroidAppBuilder/ApkBuilder.cs b/src/tasks/AndroidAppBuilder/ApkBuilder.cs index 4cfc8d0d1cac..6c022ad9d972 100644 --- a/src/tasks/AndroidAppBuilder/ApkBuilder.cs +++ b/src/tasks/AndroidAppBuilder/ApkBuilder.cs @@ -13,12 +13,14 @@ public class ApkBuilder { private const string DefaultMinApiLevel = "21"; + private const string DefaultTargetApiLevel = "31"; public string? ProjectName { get; set; } public string? AppDir { get; set; } public string? AndroidNdk { get; set; } public string? AndroidSdk { get; set; } public string? MinApiLevel { get; set; } + public string? TargetApiLevel { get; set; } public string? BuildApiLevel { get; set; } public string? BuildToolsVersion { get; set; } public string OutputDir { get; set; } = ""!; @@ -125,14 +127,24 @@ public ApkBuilder(TaskLoggingHelper logger) if (string.IsNullOrEmpty(MinApiLevel)) MinApiLevel = DefaultMinApiLevel; - // make sure BuildApiLevel >= MinApiLevel + if (string.IsNullOrEmpty(TargetApiLevel)) + TargetApiLevel = DefaultTargetApiLevel; + + // make sure BuildApiLevel >= MinApiLevel and BuildApiLevel >= TargetApiLevel // only if these api levels are not "preview" (not integers) - if (int.TryParse(BuildApiLevel, out int intApi) && - int.TryParse(MinApiLevel, out int intMinApi) && - intApi < intMinApi) + if (int.TryParse(BuildApiLevel, out int intApi)) { - throw new ArgumentException($"BuildApiLevel={BuildApiLevel} <= MinApiLevel={MinApiLevel}. " + - "Make sure you've downloaded some recent build-tools in Android SDK"); + if (int.TryParse(MinApiLevel, out int intMinApi) && intApi < intMinApi) + { + throw new ArgumentException($"BuildApiLevel={BuildApiLevel} < MinApiLevel={MinApiLevel}. " + + "Make sure you've downloaded some recent build-tools in Android SDK"); + } + + if (int.TryParse(TargetApiLevel, out int intTargetApi) && intApi < intTargetApi) + { + throw new ArgumentException($"BuildApiLevel={BuildApiLevel} < TargetApiLevel={TargetApiLevel}. " + + "Make sure you've downloaded some recent build-tools in Android SDK"); + } } string buildToolsFolder = Path.Combine(AndroidSdk, "build-tools", BuildToolsVersion); @@ -422,7 +434,8 @@ public ApkBuilder(TaskLoggingHelper logger) Utils.GetEmbeddedResource("AndroidManifest.xml") .Replace("%PackageName%", packageId) .Replace("%NetworkSecurityConfig%", networkSecurityConfigAttribute) - .Replace("%MinSdkLevel%", MinApiLevel)); + .Replace("%MinSdkLevel%", MinApiLevel) + .Replace("%TargetSdkVersion%", TargetApiLevel)); string javaCompilerArgs = $"-d obj -classpath src -bootclasspath {androidJar} -source 1.8 -target 1.8 "; Utils.RunProcess(logger, javac, javaCompilerArgs + javaActivityPath, workingDir: OutputDir); diff --git a/src/tasks/AndroidAppBuilder/Templates/AndroidManifest.xml b/src/tasks/AndroidAppBuilder/Templates/AndroidManifest.xml index befd2e446a65..e820327e6d25 100644 --- a/src/tasks/AndroidAppBuilder/Templates/AndroidManifest.xml +++ b/src/tasks/AndroidAppBuilder/Templates/AndroidManifest.xml @@ -3,7 +3,7 @@ package="%PackageName%" a:versionCode="1" a:versionName="1.0"> - +