私は証明書を扱うプロジェクトを行っており、CTL_USAGE 構造を C# に変換する必要があります。元の構造は次のとおりです。
typedef struct _CTL_USAGE {
DWORD cUsageIdentifier;
LPSTR *rgpszUsageIdentifier;
} CTL_USAGE, *PCTL_USAGE, CERT_ENHKEY_USAGE, *PCERT_ENHKEY_USAGE;
P/Invoke Web サイトによると、C# の構造は次のようになります。
[StructLayout(LayoutKind.Sequential)]
public struct CTL_USAGE
{
public int cUsageIdentifier;
public IntPtr rgpszUsageIdentifier;
}
このコードを使用するには、Encoding.ASCII.GetBytes() を使用して、構造体に追加する各文字列をバイト配列に変換します。次に、GCHandle.Alloc(byteArray, GCHandleType.Pinned) を使用して、そのバイト配列を GCHandle に変換します。その値を IntPtrs の配列に追加してから、GCHandle を IntPtr 配列に作成し、それを rgpszUsageIdentifier に割り当てます。CryptEncodeObjectEx の呼び出しはエラーをスローしませんが、結果のデータはガベージであり、CryptDecodeObject を使用して暗号化を解除することはできません。私のエンコーディングは次のとおりです。
//EnhancedUsage is a List<String> containing the Enhanced Usage OIDs
CTL_USAGE usage = new CTL_USAGE()
{
cUsageIdentifier = EnhancedUsage.Count,
};
List<IntPtr> usageList = new List<IntPtr>();
foreach (string s in EnhancedUsage)
usageList.Add(new PinnedHandle(Encoding.ASCII.GetBytes(s)));
usage.rgpszUsageIdentifier = new PinnedHandle(usageList.ToArray());
IntPtr data = Marshal.AllocHGlobal(Marshal.SizeOf(usage));
Marshal.StructureToPtr(usage, data, false);
int encodedSize = 0;
if (!Crypt32.CryptEncodeObjectEx((int)CertEncoding.X509Asn, CertOid.szOID_ENHANCED_KEY_USAGE, data, 0, IntPtr.Zero, null, ref encodedSize))
throw new Win32Exception();
byte[] buffer = new byte[encodedSize];
if (!Crypt32.CryptEncodeObjectEx((int)CertEncoding.X509Asn, CertOid.szOID_ENHANCED_KEY_USAGE, data, 0, IntPtr.Zero, buffer, ref encodedSize))
throw new Win32Exception();
PinnedHandle クラスは、GCHandle のラッパーです。次のようになります。
public class PinnedHandle : IDisposable
{
private GCHandle handle;
public PinnedHandle(object value)
{
handle = GCHandle.Alloc(value, GCHandleType.Pinned);
}
public static implicit operator IntPtr(PinnedHandle value)
{
return value.handle.AddrOfPinnedObject();
}
public void Dispose()
{
try
{
handle.Free();
}
catch
{
}
}
}
他の同様の状況で使用しており、正常に機能しているため、ここで問題が発生しているとは思いません。これを正しく機能させる方法はありますか?