mirror of
https://github.com/Yamato-Security/WELA.git
synced 2026-10-02 12:34:42 +02:00
50 lines
4.1 KiB
C#
50 lines
4.1 KiB
C#
// Fixed offline chain build. No certificate/key store or policy writes.
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Cryptography;
|
|
namespace Wela.Capi2Probe {
|
|
public sealed class ChainResult { public uint Flags, ErrorStatus, InfoStatus, Chains, Elements; }
|
|
public static class Native {
|
|
public static CngKey CreateEphemeralRsa() {
|
|
CngKeyCreationParameters parameters=new CngKeyCreationParameters();
|
|
parameters.Provider=CngProvider.MicrosoftSoftwareKeyStorageProvider;
|
|
parameters.Parameters.Add(new CngProperty("Length",BitConverter.GetBytes(2048),CngPropertyOptions.None));
|
|
// Literal null is essential: PowerShell converts a null string argument to empty.
|
|
return CngKey.Create(CngAlgorithm.Rsa,null,parameters);
|
|
}
|
|
public const uint OfflineFlags=0x80002104; // cache-only URL/revocation, no AIA, no auth-root auto-update
|
|
[StructLayout(LayoutKind.Sequential)] struct Usage { public uint Count; public IntPtr Oids; }
|
|
[StructLayout(LayoutKind.Sequential)] struct Match { public uint Type; public Usage Usage; }
|
|
[StructLayout(LayoutKind.Sequential)] struct Parameters {
|
|
public uint Size; public Match RequestedUsage,RequestedIssuancePolicy;
|
|
public uint UrlTimeout; public int CheckFreshness; public uint Freshness;
|
|
public IntPtr CacheResync,StrongSign; public uint StrongFlags;
|
|
}
|
|
// Both CERT_CHAIN_CONTEXT and CERT_SIMPLE_CHAIN have this documented prefix.
|
|
[StructLayout(LayoutKind.Sequential)] struct ChainPrefix { public uint Size,Error,Info,Count; public IntPtr Entries; }
|
|
[DllImport("crypt32.dll",ExactSpelling=true,SetLastError=true)] static extern IntPtr CertCreateCertificateContext(uint encoding,byte[] encoded,uint length);
|
|
[DllImport("crypt32.dll",ExactSpelling=true,SetLastError=true)] [return:MarshalAs(UnmanagedType.Bool)] static extern bool CertGetCertificateChain(IntPtr engine,IntPtr certificate,IntPtr time,IntPtr additionalStore,ref Parameters parameters,uint flags,IntPtr reserved,out IntPtr chain);
|
|
[DllImport("crypt32.dll",ExactSpelling=true)] static extern void CertFreeCertificateChain(IntPtr chain);
|
|
[DllImport("crypt32.dll",ExactSpelling=true)] [return:MarshalAs(UnmanagedType.Bool)] static extern bool CertFreeCertificateContext(IntPtr certificate);
|
|
public static ChainResult Build(byte[] der) {
|
|
if(IntPtr.Size!=8 || Marshal.SizeOf(typeof(Parameters))!=96 || Marshal.SizeOf(typeof(ChainPrefix))!=24)throw new InvalidOperationException("Unsupported native chain structure layout.");
|
|
if(der==null || der.Length<128 || der.Length>8192)throw new ArgumentException("Certificate DER exceeds the fixed bound.");
|
|
IntPtr certificate=CertCreateCertificateContext(1,der,(uint)der.Length),chain=IntPtr.Zero;
|
|
if(certificate==IntPtr.Zero)throw new Win32Exception(Marshal.GetLastWin32Error());
|
|
try {
|
|
Parameters p=new Parameters();p.Size=(uint)Marshal.SizeOf(typeof(Parameters));p.UrlTimeout=1000;
|
|
// No revocation-check request, additional store, custom trust engine, or caching of the end certificate.
|
|
if(!CertGetCertificateChain(IntPtr.Zero,certificate,IntPtr.Zero,IntPtr.Zero,ref p,OfflineFlags,IntPtr.Zero,out chain))throw new Win32Exception(Marshal.GetLastWin32Error());
|
|
if(chain==IntPtr.Zero)throw new InvalidOperationException("Native chain context is absent.");
|
|
ChainPrefix c=(ChainPrefix)Marshal.PtrToStructure(chain,typeof(ChainPrefix));
|
|
if(c.Size<24 || c.Count!=1 || c.Entries==IntPtr.Zero)throw new InvalidOperationException("Unexpected native chain shape.");
|
|
IntPtr simple=Marshal.ReadIntPtr(c.Entries);if(simple==IntPtr.Zero)throw new InvalidOperationException("Native simple chain is absent.");
|
|
ChainPrefix s=(ChainPrefix)Marshal.PtrToStructure(simple,typeof(ChainPrefix));
|
|
if(s.Size<24 || s.Count!=1 || s.Entries==IntPtr.Zero || s.Error!=c.Error)throw new InvalidOperationException("Unexpected native simple chain shape.");
|
|
return new ChainResult {Flags=OfflineFlags,ErrorStatus=c.Error,InfoStatus=c.Info,Chains=c.Count,Elements=s.Count};
|
|
} finally {if(chain!=IntPtr.Zero)CertFreeCertificateChain(chain);CertFreeCertificateContext(certificate);}
|
|
}
|
|
}
|
|
}
|