Last active
January 8, 2024 18:47
-
-
Save rzikm/4f316d358d02406359ee2d1aad05ec4d to your computer and use it in GitHub Desktop.
OCSPStaple
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <Project> | |
| <PropertyGroup> | |
| <SkipConfigureTrimming>true</SkipConfigureTrimming> | |
| <PublishTrimmed>true</PublishTrimmed> | |
| <TrimMode>full</TrimMode> | |
| <TrimmerRemoveSymbols>false</TrimmerRemoveSymbols> | |
| <SelfContained>true</SelfContained> | |
| <!-- <TreatWarningsAsErrors>true</TreatWarningsAsErrors> --> | |
| <!-- Enable NuGet static graph evaluation to optimize incremental restore --> | |
| <RestoreUseStaticGraphEvaluation>true</RestoreUseStaticGraphEvaluation> | |
| <!-- Suppress analyzer and trimming warnings as these are tests --> | |
| <EnableTrimAnalyzer>false</EnableTrimAnalyzer> | |
| <SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings> | |
| <NoWarn>$(NoWarn);IL2121;CA1416</NoWarn> | |
| </PropertyGroup> | |
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <Project> | |
| <Import Project="$(RepositoryEngineeringDir)testing\tests.mobile.targets" Condition="'$(RuntimeIdentifier)' == 'browser-wasm'" /> | |
| <Import Project="$(RepositoryEngineeringDir)targetingpacks.targets" /> | |
| <PropertyGroup> | |
| <BundleDir>$([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(OutputPath)', 'AppBundle'))</BundleDir> | |
| <WasmMainAssemblyFileName>project.dll</WasmMainAssemblyFileName> | |
| </PropertyGroup> | |
| <Target Name="CreateTestWasmAppBundle" | |
| AfterTargets="Publish" | |
| DependsOnTargets="BundleTestWasmApp" | |
| Condition="'$(TargetArchitecture)' == 'wasm' And '$(TargetOS)' == 'browser'" /> | |
| <PropertyGroup Condition="'$(PublishAot)' == 'true'"> | |
| <_IlcReferencedAsPackage>false</_IlcReferencedAsPackage> | |
| <ILCompilerTargetsPath>$(CoreCLRBuildIntegrationDir)Microsoft.DotNet.ILCompiler.SingleEntry.targets</ILCompilerTargetsPath> | |
| </PropertyGroup> | |
| <!-- Overriding these targets as these projects won't need to binplace --> | |
| <Target Name="PublishTestAsSelfContained" /> | |
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Buffers; | |
| using System.Diagnostics; | |
| using System.Net.Sockets; | |
| using System.Runtime.InteropServices; | |
| using System.Security.Cryptography.X509Certificates; | |
| System.Console.WriteLine("Hello World!"); | |
| var serverUrl = Environment.GetCommandLineArgs()[1]; | |
| // var serverUrl = "broker-uswe-01-msit-aks.broker.skype.com"; | |
| // var serverUrl = "digicert.com"; | |
| // var serverUrl = "ep-euwe-01-prod-aks.flightproxy.teams.microsoft.com"; | |
| Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | |
| s.Connect(serverUrl, 443); | |
| X509Certificate2 cert = null; | |
| X509Certificate2 issuer = null; | |
| var sslStream = new System.Net.Security.SslStream(new NetworkStream(s), false, (sender, certificate, chain, errors) => | |
| { | |
| cert = certificate as X509Certificate2; | |
| issuer = new X509Certificate2(chain.ChainElements[1].Certificate); | |
| return true; | |
| }); | |
| sslStream.AuthenticateAsClient(serverUrl); | |
| List<string> ocspUrls = new List<string>(); | |
| foreach (X509Extension ext in cert.Extensions) | |
| { | |
| if (ext is X509AuthorityInformationAccessExtension aia) | |
| { | |
| foreach (string entry in aia.EnumerateOcspUris()) | |
| { | |
| if (Uri.TryCreate(entry, UriKind.Absolute, out Uri? uri)) | |
| { | |
| if (uri.Scheme == "http") | |
| { | |
| ocspUrls.Add(entry); | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| System.Console.WriteLine($"cert: {cert.Subject}"); | |
| File.WriteAllText("cert.pem", cert.ExportCertificatePem()); | |
| System.Console.WriteLine($"issuer: {issuer.Subject}"); | |
| File.WriteAllText("issuer.pem", issuer.ExportCertificatePem()); | |
| using var ocspRequest = Interop.Crypto.X509BuildOcspRequest(cert.Handle, issuer.Handle); | |
| byte[] rentedBytes = ArrayPool<byte>.Shared.Rent(Interop.Crypto.GetOcspRequestDerSize(ocspRequest)); | |
| int encodingSize = Interop.Crypto.EncodeOcspRequest(ocspRequest, rentedBytes); | |
| ArraySegment<byte> encoded = new ArraySegment<byte>(rentedBytes, 0, encodingSize); | |
| ArraySegment<char> rentedChars = UrlBase64Encoding.RentEncode(encoded); | |
| string url = MakeUrl(ocspUrls[0], rentedChars); | |
| // var ocsp = File.ReadAllBytes("/mnt/c/users/radekzikmund/Downloads/ocsp"); | |
| System.Console.WriteLine($"url: {url}"); | |
| var ocsp = await new HttpClient().GetByteArrayAsync(url).ConfigureAwait(false); | |
| System.Console.WriteLine($"ocsp: {ocsp.Length} B"); | |
| File.WriteAllBytes("ocsp-req.der", encoded.ToArray()); | |
| File.WriteAllBytes("ocsp-res.der", ocsp); | |
| // System.Console.WriteLine(Convert.ToHexString(ocsp)); | |
| if (!Interop.Crypto.X509DecodeOcspToExpiration(ocsp, ocspRequest, cert.Handle, issuer.Handle, out DateTimeOffset expiration)) | |
| { | |
| System.Console.WriteLine("Failed to decode OCSP response"); | |
| } | |
| static string MakeUrl(string baseUri, ArraySegment<char> encodedRequest) | |
| { | |
| Debug.Assert(baseUri.Length > 0); | |
| Debug.Assert(encodedRequest.Count > 0); | |
| // From https://datatracker.ietf.org/doc/html/rfc6960: | |
| // | |
| // An OCSP request using the GET method is constructed as follows: | |
| // | |
| // GET {url}/{url-encoding of base-64 encoding of the DER encoding of | |
| // the OCSPRequest} | |
| // | |
| // where {url} may be derived from the value of the authority | |
| // information access extension in the certificate being checked for | |
| // revocation | |
| // Since the certificate isn't expected to have a slash at the end, but might, | |
| // use a custom concat over Uri's built-in combining constructor. | |
| string uriString; | |
| if (baseUri.EndsWith('/')) | |
| { | |
| uriString = string.Concat(baseUri, encodedRequest.AsSpan()); | |
| } | |
| else | |
| { | |
| uriString = string.Concat(baseUri, "/", encodedRequest.AsSpan()); | |
| } | |
| return uriString; | |
| } | |
| internal static class Libraries | |
| { | |
| internal const string CryptoNative = "libSystem.Security.Cryptography.Native.OpenSsl"; | |
| } | |
| internal static partial class Interop | |
| { | |
| internal static partial class Crypto | |
| { | |
| [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_OcspRequestDestroy")] | |
| internal static partial void OcspRequestDestroy(IntPtr ocspReq); | |
| [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetOcspRequestDerSize")] | |
| internal static partial int GetOcspRequestDerSize(SafeOcspRequestHandle req); | |
| [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EncodeOcspRequest")] | |
| internal static partial int EncodeOcspRequest(SafeOcspRequestHandle req, byte[] buf); | |
| [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_X509BuildOcspRequest")] | |
| internal static partial SafeOcspRequestHandle X509BuildOcspRequest(IntPtr subject, IntPtr issuer); | |
| [LibraryImport(Libraries.CryptoNative)] | |
| private static unsafe partial int CryptoNative_X509DecodeOcspToExpiration( | |
| byte* buf, | |
| int len, | |
| SafeOcspRequestHandle req, | |
| IntPtr subject, | |
| IntPtr issuer, | |
| ref long expiration); | |
| internal static unsafe bool X509DecodeOcspToExpiration( | |
| ReadOnlySpan<byte> buf, | |
| SafeOcspRequestHandle request, | |
| IntPtr x509Subject, | |
| IntPtr x509Issuer, | |
| out DateTimeOffset expiration) | |
| { | |
| long timeT = 0; | |
| int ret; | |
| fixed (byte* pBuf = buf) | |
| { | |
| ret = CryptoNative_X509DecodeOcspToExpiration( | |
| pBuf, | |
| buf.Length, | |
| request, | |
| x509Subject, | |
| x509Issuer, | |
| ref timeT); | |
| } | |
| if (ret == 1) | |
| { | |
| if (timeT != 0) | |
| { | |
| expiration = DateTimeOffset.FromUnixTimeSeconds(timeT); | |
| } | |
| else | |
| { | |
| // Something went wrong during the determination of when the response | |
| // should not be used any longer. | |
| // Half an hour sounds fair? | |
| expiration = DateTimeOffset.UtcNow.AddMinutes(30); | |
| } | |
| return true; | |
| } | |
| Debug.Assert(ret == 0, $"Unexpected response from X509DecodeOcspToExpiration: {ret}"); | |
| expiration = DateTimeOffset.MinValue; | |
| return false; | |
| } | |
| [LibraryImport(Libraries.CryptoNative)] | |
| private static partial SafeOcspResponseHandle CryptoNative_DecodeOcspResponse(ref byte buf, int len); | |
| internal static SafeOcspResponseHandle DecodeOcspResponse(ReadOnlySpan<byte> buf) | |
| { | |
| return CryptoNative_DecodeOcspResponse( | |
| ref MemoryMarshal.GetReference(buf), | |
| buf.Length); | |
| } | |
| [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_OcspResponseDestroy")] | |
| internal static partial void OcspResponseDestroy(IntPtr ocspReq); | |
| } | |
| } | |
| internal sealed class SafeOcspRequestHandle : SafeHandleZeroOrMinusOneIsInvalid | |
| { | |
| public SafeOcspRequestHandle() | |
| : base(true) | |
| { | |
| } | |
| protected override bool ReleaseHandle() | |
| { | |
| Interop.Crypto.OcspRequestDestroy(handle); | |
| handle = IntPtr.Zero; | |
| return true; | |
| } | |
| } | |
| internal sealed class SafeOcspResponseHandle : SafeHandleZeroOrMinusOneIsInvalid | |
| { | |
| public SafeOcspResponseHandle() | |
| : base(true) | |
| { | |
| } | |
| protected override bool ReleaseHandle() | |
| { | |
| Interop.Crypto.OcspResponseDestroy(handle); | |
| handle = IntPtr.Zero; | |
| return true; | |
| } | |
| } | |
| // Class of safe handle which uses 0 or -1 as an invalid handle. | |
| public abstract class SafeHandleZeroOrMinusOneIsInvalid : SafeHandle | |
| { | |
| protected SafeHandleZeroOrMinusOneIsInvalid(bool ownsHandle) : base(IntPtr.Zero, ownsHandle) | |
| { | |
| } | |
| public override bool IsInvalid => handle == IntPtr.Zero || handle == new IntPtr(-1); | |
| } | |
| /// <summary> | |
| /// This class provides URL-encoded-Base64, which is distinct from the base64url encoding. | |
| /// </summary> | |
| internal static class UrlBase64Encoding | |
| { | |
| internal static ArraySegment<char> RentEncode(ReadOnlySpan<byte> input) | |
| { | |
| // Every 3 bytes turns into 4 chars for the Base64 operation | |
| int base64Len = ((input.Length + 2) / 3) * 4; | |
| char[] base64 = ArrayPool<char>.Shared.Rent(base64Len); | |
| if (!Convert.TryToBase64Chars(input, base64, out int charsWritten)) | |
| { | |
| Debug.Fail($"Convert.TryToBase64 failed with {input.Length} bytes to a {base64.Length} buffer"); | |
| throw new UnreachableException(); | |
| } | |
| Debug.Assert(charsWritten == base64Len); | |
| // In the degenerate case every char will turn into 3 chars. | |
| int urlEncodedLen = charsWritten * 3; | |
| char[] urlEncoded = ArrayPool<char>.Shared.Rent(urlEncodedLen); | |
| ReadOnlySpan<char> source = base64.AsSpan(0, base64Len); | |
| Span<char> dest = urlEncoded; | |
| int written = 0; | |
| while (!source.IsEmpty) | |
| { | |
| int pos = source.IndexOfAny('+', '/', '='); | |
| if (pos < 0) | |
| { | |
| source.CopyTo(dest); | |
| written += source.Length; | |
| break; | |
| } | |
| source.Slice(0, pos).CopyTo(dest); | |
| source = source.Slice(pos); | |
| dest = dest.Slice(pos); | |
| written += pos; | |
| dest[0] = '%'; | |
| switch (source[0]) | |
| { | |
| case '+': | |
| dest[1] = '2'; | |
| dest[2] = 'B'; | |
| break; | |
| case '/': | |
| dest[1] = '2'; | |
| dest[2] = 'F'; | |
| break; | |
| default: | |
| Debug.Assert(source[0] == '='); | |
| dest[1] = '3'; | |
| dest[2] = 'D'; | |
| break; | |
| } | |
| source = source.Slice(1); | |
| dest = dest.Slice(3); | |
| written += 3; | |
| } | |
| ArrayPool<char>.Shared.Return(base64); | |
| return new ArraySegment<char>(urlEncoded, 0, written); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <Project Sdk="Microsoft.NET.Sdk"> | |
| <PropertyGroup> | |
| <!-- Needed for PublishTrimmed --> | |
| <NetCoreAppToolCurrent>net8.0</NetCoreAppToolCurrent> | |
| <ToolsILLinkDir>/source/dotnet/runtime/artifacts/bin/ILLink.Tasks/Debug/</ToolsILLinkDir> | |
| </PropertyGroup> | |
| <!-- Use live illink bits. It is necessary to both import the package props and override | |
| the tasks assembly, because the live package props in the build output do not use | |
| the same layout as the NuGet package. --> | |
| <!-- This must be done after the usual nuget props imports, to override the implicitly referenced | |
| Microsoft.NET.ILLink.Tasks.props from the SDK. --> | |
| <Import Project="$(ToolsILLinkDir)$(NetCoreAppToolCurrent)/build/Microsoft.NET.ILLink.Tasks.props" /> | |
| <PropertyGroup> | |
| <!-- Don't use SDK's trimming functionality. --> | |
| <_RequiresILLinkPack>false</_RequiresILLinkPack> | |
| <ILLinkTasksAssembly>$(ToolsILLinkDir)$(NetCoreAppToolCurrent)/ILLink.Tasks.dll</ILLinkTasksAssembly> | |
| </PropertyGroup> | |
| <Target Name="ConfigureGenerators" | |
| DependsOnTargets="ConfigureLibraryImportGenerator" | |
| BeforeTargets="CoreCompile" /> | |
| <!-- Microsoft.Interop.LibraryImportGenerator --> | |
| <Target Name="ConfigureLibraryImportGenerator" | |
| DependsOnTargets="ResolveProjectReferences" | |
| BeforeTargets="GenerateMSBuildEditorConfigFileShouldRun"> | |
| <PropertyGroup> | |
| <LibraryImportGenerator_UseMarshalType>true</LibraryImportGenerator_UseMarshalType> | |
| </PropertyGroup> | |
| </Target> | |
| <Import Project="/source/dotnet/runtime/src/libraries/System.Runtime.InteropServices\gen\LibraryImportGenerator\Microsoft.Interop.LibraryImportGenerator.props" /> | |
| <PropertyGroup> | |
| <TargetFramework>net9.0</TargetFramework> | |
| <OutputType>Exe</OutputType> | |
| <NETCoreAppMaximumVersion>9.0</NETCoreAppMaximumVersion> | |
| <UseMonoRuntime></UseMonoRuntime> | |
| <RuntimeIdentifier>linux-x64</RuntimeIdentifier> | |
| <PublishAot></PublishAot> | |
| <AppHostSourcePath>/source/dotnet/runtime/artifacts/bin/linux-x64.Debug/corehost/apphost</AppHostSourcePath> | |
| <SingleFileHostSourcePath>/source/dotnet/runtime/artifacts/bin/coreclr/linux.x64.Debug/corehost/singlefilehost</SingleFileHostSourcePath> | |
| <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |
| <EnablePreviewFeatures>true</EnablePreviewFeatures> | |
| <ImplicitUsings>enable</ImplicitUsings> | |
| <!-- wasm specific --> | |
| <MonoAOTCompilerDir>/source/dotnet/runtime/artifacts/bin/MonoAOTCompiler/Debug/net8.0/</MonoAOTCompilerDir> | |
| <MonoProjectRoot>/source/dotnet/runtime/src/mono/</MonoProjectRoot> | |
| <MonoAOTCompilerTasksAssemblyPath>/source/dotnet/runtime/artifacts/bin/MonoAOTCompiler/Debug/net8.0/MonoAOTCompiler.dll</MonoAOTCompilerTasksAssemblyPath> | |
| <WasmAppBuilderTasksAssemblyPath>/source/dotnet/runtime/artifacts/bin/WasmAppBuilder/Debug/net8.0/WasmAppBuilder.dll</WasmAppBuilderTasksAssemblyPath> | |
| <MonoTargetsTasksAssemblyPath>/source/dotnet/runtime/artifacts/bin/MonoTargetsTasks/Debug/net8.0/MonoTargetsTasks.dll</MonoTargetsTasksAssemblyPath> | |
| <MicrosoftNetCoreAppRuntimePackRidDir>/source/dotnet/runtime/artifacts/bin/microsoft.netcore.app.runtime.linux-x64/Debug/runtimes/linux-x64/</MicrosoftNetCoreAppRuntimePackRidDir> | |
| <!-- Needed for targetingpacks.targets --> | |
| <ProductVersion>9.0.0</ProductVersion> | |
| <NetCoreAppCurrent>net9.0</NetCoreAppCurrent> | |
| <NetCoreAppCurrentVersion>9.0</NetCoreAppCurrentVersion> | |
| <MicrosoftNetCoreAppFrameworkName>Microsoft.NETCore.App</MicrosoftNetCoreAppFrameworkName> | |
| <MicrosoftNetCoreAppRefPackDir>/source/dotnet/runtime/artifacts/bin/microsoft.netcore.app.ref/</MicrosoftNetCoreAppRefPackDir> | |
| <MicrosoftNetCoreAppRuntimePackDir>/source/dotnet/runtime/artifacts/bin/microsoft.netcore.app.runtime.linux-x64/Debug/</MicrosoftNetCoreAppRuntimePackDir> | |
| <RepositoryEngineeringDir>/source/dotnet/runtime/eng/</RepositoryEngineeringDir> | |
| <_ExtraTrimmerArgs> $(_ExtraTrimmerArgs)</_ExtraTrimmerArgs> | |
| <!-- Needed for PublishAot --> | |
| <IlcToolsPath>/source/dotnet/runtime/artifacts/bin/coreclr/linux.x64.Debug/ilc-published/</IlcToolsPath> | |
| <IlcBuildTasksPath>/source/dotnet/runtime/artifacts/bin/coreclr/linux.x64.Debug/ilc-published/netstandard/ILCompiler.Build.Tasks.dll</IlcBuildTasksPath> | |
| <IlcSdkPath>/source/dotnet/runtime/artifacts/bin/coreclr/linux.x64.Debug/aotsdk/</IlcSdkPath> | |
| <IlcFrameworkPath>/source/dotnet/runtime/artifacts/bin/microsoft.netcore.app.runtime.linux-x64/Debug/runtimes/linux-x64/lib/net9.0/</IlcFrameworkPath> | |
| <IlcFrameworkNativePath>/source/dotnet/runtime/artifacts/bin/microsoft.netcore.app.runtime.linux-x64/Debug/runtimes/linux-x64/native/</IlcFrameworkNativePath> | |
| <SysRoot Condition="('$(CrossBuild)' == 'true' or '$(BuildArchitecture)' != '$(TargetArchitecture)') and '$(ROOTFS_DIR)' != ''">$(ROOTFS_DIR)</SysRoot> | |
| <CoreCLRBuildIntegrationDir>/source/dotnet/runtime/artifacts/bin/coreclr/linux.x64.Debug/build/</CoreCLRBuildIntegrationDir> | |
| </PropertyGroup> | |
| <ItemGroup> | |
| <CustomLinkerArg Condition="'$(CrossBuild)' == 'true' and '$(_hostArchitecture)' == '$(_targetArchitecture)' and '$(ROOTFS_DIR)' != ''" Include="--gcc-toolchain=$(ROOTFS_DIR)/usr" /> | |
| </ItemGroup> | |
| <ItemGroup> | |
| </ItemGroup> | |
| <ItemGroup> | |
| </ItemGroup> | |
| <ItemGroup> | |
| <PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" /> | |
| </ItemGroup> | |
| <Target Name="LocateNativeCompiler" Condition="'$(PublishAot)' == 'true' and '$(_hostOS)' != 'win'" BeforeTargets="SetupOSSpecificProps"> | |
| <PropertyGroup> | |
| <CppCompilerAndLinker Condition="'$(CppCompilerAndLinker)' == ''">clang</CppCompilerAndLinker> | |
| </PropertyGroup> | |
| <Exec Command="sh -c 'build_arch="$(TargetArchitecture)" compiler="$(CppCompilerAndLinker)" . "$(RepositoryEngineeringDir)/common/native/init-compiler.sh" && echo "$CC;$LDFLAGS"' 2>/dev/null" EchoOff="true" ConsoleToMsBuild="true" StandardOutputImportance="Low"> | |
| <Output TaskParameter="ConsoleOutput" PropertyName="_CC_LDFLAGS" /> | |
| </Exec> | |
| <PropertyGroup> | |
| <CppLinker>$(_CC_LDFLAGS.SubString(0, $(_CC_LDFLAGS.IndexOf(';'))))</CppLinker> | |
| <_LDFLAGS>$(_CC_LDFLAGS.SubString($([MSBuild]::Add($(_CC_LDFLAGS.IndexOf(';')), 1))))</_LDFLAGS> | |
| <LinkerFlavor Condition="$(_LDFLAGS.Contains('lld'))">lld</LinkerFlavor> | |
| </PropertyGroup> | |
| </Target> | |
| <Import Project="/source/dotnet/runtime/eng/nativeSanitizers.targets" /> | |
| </Project> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment