0

私は証明書を扱うプロジェクトを行っており、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
        {

        }
    }
}

他の同様の状況で使用しており、正常に機能しているため、ここで問題が発生しているとは思いません。これを正しく機能させる方法はありますか?

4

1 に答える 1