File: Signing\Cms\NativeMethods.cs
Web Access
Project: src\src\nuget-client\src\NuGet.Core\NuGet.Packaging\NuGet.Packaging.csproj (NuGet.Packaging)
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Runtime.InteropServices;

namespace NuGet.Packaging.Signing
{
    internal static class NativeMethods
    {
        internal const uint PKCS_ATTRIBUTE = 22;
        internal const uint PKCS7_SIGNER_INFO = 500;
        internal const int ERROR_MORE_DATA = 234;
        internal const uint CMSG_SIGNED = 2;
        internal const uint CERT_KEY_IDENTIFIER_PROP_ID = 20;
        internal const uint CERT_ID_KEY_IDENTIFIER = 2;

        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern SafeCryptMsgHandle CryptMsgOpenToEncode(
            CMSG_ENCODING dwMsgEncodingType,
            uint dwFlags,
            uint dwMsgType,
            ref CMSG_SIGNED_ENCODE_INFO pvMsgEncodeInfo,
            string pszInnerContentObjID,
            IntPtr pStreamInfo
        );

        // http://msdn.microsoft.com/en-us/library/windows/desktop/aa380228(v=vs.85).aspx
        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern SafeCryptMsgHandle CryptMsgOpenToDecode(
            CMSG_ENCODING dwMsgEncodingType,
            CMSG_OPENTODECODE_FLAGS dwFlags,
            uint dwMsgType,
            IntPtr hCryptProv,
            IntPtr pRecipientInfo,
            IntPtr pStreamInfo);

        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa380221(v=vs.85).aspx
        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CryptMsgCountersign(
            SafeCryptMsgHandle hCryptMsg,
            uint dwIndex,
            int cCountersigners,
            CMSG_SIGNER_ENCODE_INFO rgCountersigners);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/aa380219(v=vs.85).aspx
        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CryptMsgClose(IntPtr hCryptMsg);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/aa380231(v=vs.85).aspx
        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CryptMsgUpdate(
            SafeCryptMsgHandle hCryptMsg,
            byte[] pbData,
            uint cbData,
            bool fFinal);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/aa380227(v=vs.85).aspx
        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CryptMsgGetParam(
            SafeCryptMsgHandle hCryptMsg,
            CMSG_GETPARAM_TYPE dwParamType,
            uint dwIndex,
            byte[] pvData,
            ref uint pcbData);

        [DllImport("crypt32.dll", SetLastError = true)]
        internal static extern bool CryptMsgGetParam(
            SafeCryptMsgHandle hCryptMsg,
            CMSG_GETPARAM_TYPE dwParamType,
            uint dwIndex,
            IntPtr pvData,
            ref uint pcbData);

        [DllImport("crypt32.dll", SetLastError = true)]
        internal static extern bool CryptDecodeObject(
            CMSG_ENCODING dwCertEncodingType,
            IntPtr lpszStructType,
            IntPtr pbEncoded,
            uint cbEncoded,
            uint dwFlags,
            IntPtr pvStructInfo,
            IntPtr pcbStructInfo);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/aa380220(v=vs.85).aspx
        [DllImport("crypt32.dll", SetLastError = true)]
        internal static extern bool CryptMsgControl(
            SafeCryptMsgHandle hCryptMsg,
            uint dwFlags,
            CMSG_CONTROL_TYPE dwCtrlType,
            IntPtr pvCtrlPara);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/aa379922(v=vs.85).aspx
        [DllImport("crypt32.dll", SetLastError = true)]
        internal static extern bool CryptEncodeObjectEx(
            CMSG_ENCODING dwCertEncodingType,
            IntPtr lpszStructType,
            IntPtr pvStructInfo,
            uint dwFlags,
            IntPtr pEncodePara,
            IntPtr pvEncoded,
            ref uint pcbEncoded);

        [DllImport("advapi32.dll", SetLastError = true)]
        internal static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);

        [DllImport("crypt32.dll", SetLastError = true)]
        internal static extern IntPtr CertDuplicateCertificateContext(IntPtr pCertContext);

        [DllImport("crypt32.dll", SetLastError = true)]
        internal static extern bool CertFreeCertificateContext(IntPtr pCertContext);

        [DllImport("crypt32.dll", SetLastError = true)]
        internal extern static bool CertGetCertificateContextProperty(
            IntPtr pCertContext,
            uint dwPropId,
            IntPtr pvData,
            ref uint pcbData);

        internal static int GetHRForWin32Error(int err)
        {
            if ((err & 0x80000000) == 0x80000000)
            {
                return err;
            }

            return (err & 0x0000FFFF) | unchecked((int)0x80070000);
        }
    }

    internal sealed class SafeCryptMsgHandle : SafeHandle
    {
        internal static SafeCryptMsgHandle InvalidHandle => new SafeCryptMsgHandle(IntPtr.Zero);

        public override bool IsInvalid => handle == IntPtr.Zero;

        private SafeCryptMsgHandle()
            : base(IntPtr.Zero, ownsHandle: true)
        {
        }

        internal SafeCryptMsgHandle(IntPtr handle)
            : base(handle, ownsHandle: true)
        {
        }

        internal SafeCryptMsgHandle(IntPtr handle, bool ownsHandle)
            : base(handle, ownsHandle)
        {
        }

        protected override bool ReleaseHandle()
        {
            return NativeMethods.CryptMsgClose(handle);
        }
    }

    internal sealed class SafeLocalAllocHandle : SafeHandle
    {
        public override bool IsInvalid { get { return handle == IntPtr.Zero; } }

        internal SafeLocalAllocHandle(IntPtr handle) : base(handle, ownsHandle: true)
        {
        }

        protected override bool ReleaseHandle()
        {
            if (!IsInvalid)
            {
                Marshal.FreeHGlobal(handle);

                handle = IntPtr.Zero;
            }

            return true;
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct CRYPT_INTEGER_BLOB
    {
        internal uint cbData;
        internal IntPtr pbData;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal struct CRYPT_ATTRIBUTES
    {
        internal uint cAttr;
        internal /*CRYPT_ATTRIBUTE*/ IntPtr rgAttr;
    }

    // http://msdn.microsoft.com/en-us/library/windows/desktop/aa381139(v=vs.85).aspx
    [StructLayout(LayoutKind.Sequential)]
    internal unsafe struct CRYPT_ATTRIBUTE
    {
        internal IntPtr pszObjId;
        internal uint cValue;
        internal IntPtr rgValue;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal unsafe struct CRYPT_ATTRIBUTE_STRING
    {
        [MarshalAs(UnmanagedType.LPStr)]
        internal string pszObjId;
        internal uint cValue;
        internal IntPtr rgValue;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA
    {
        internal uint cbSize;
        internal uint dwSignerIndex;
        internal CRYPT_INTEGER_BLOB BLOB;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA
    {
        internal uint cbSize;
        internal uint dwSignerIndex;
        internal uint dwUnauthAttrIndex;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal struct CMSG_SIGNER_INFO
    {
        internal uint dwVersion;
        internal Rfc3161TimestampWin32.CRYPTOAPI_BLOB Issuer;
        internal Rfc3161TimestampWin32.CRYPTOAPI_BLOB SerialNumber;
        internal Rfc3161TimestampWin32.CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
        internal Rfc3161TimestampWin32.CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
        internal Rfc3161TimestampWin32.CRYPTOAPI_BLOB EncryptedHash;
        internal CRYPT_ATTRIBUTES AuthAttrs;
        internal CRYPT_ATTRIBUTES UnauthAttrs;
    }

    [Flags]
    internal enum CMSG_OPENTODECODE_FLAGS : uint
    {
        // Source: wincrypt.h
        None = 0,
        CMSG_DETACHED_FLAG = 0x00000004,
        CMSG_CRYPT_RELEASE_CONTEXT_FLAG = 0x00008000
    }

    [Flags]
    internal enum CMSG_ENCODING : uint
    {
        // Source: wincrypt.h
        X509_ASN_ENCODING = 0x00000001,
        PKCS_7_ASN_ENCODING = 0x00010000,
        Any = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
    }

    internal enum CMSG_CONTROL_TYPE : uint
    {
        CMSG_CTRL_VERIFY_SIGNATURE = 1,
        CMSG_CTRL_DECRYPT = 2,
        CMSG_CTRL_VERIFY_HASH = 5,
        CMSG_CTRL_ADD_SIGNER = 6,
        CMSG_CTRL_DEL_SIGNER = 7,
        CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR = 8,
        CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR = 9,
        CMSG_CTRL_ADD_CERT = 10,
        CMSG_CTRL_DEL_CERT = 11,
        CMSG_CTRL_ADD_CRL = 12,
        CMSG_CTRL_DEL_CRL = 13,
        CMSG_CTRL_ADD_ATTR_CERT = 14,
        CMSG_CTRL_DEL_ATTR_CERT = 15,
        CMSG_CTRL_KEY_TRANS_DECRYPT = 16,
        CMSG_CTRL_KEY_AGREE_DECRYPT = 17,
        CMSG_CTRL_MAIL_LIST_DECRYPT = 18,
        CMSG_CTRL_VERIFY_SIGNATURE_EX = 19,
        CMSG_CTRL_ADD_CMS_SIGNER_INFO = 20,
        CMSG_CTRL_ENABLE_STRONG_SIGNATURE = 21
    }

    internal enum CMSG_GETPARAM_TYPE : uint
    {
        // Source: wincrypt.h
        CMSG_TYPE_PARAM = 1,
        CMSG_CONTENT_PARAM = 2,
        CMSG_BARE_CONTENT_PARAM = 3,
        CMSG_INNER_CONTENT_TYPE_PARAM = 4,
        CMSG_SIGNER_COUNT_PARAM = 5,
        CMSG_SIGNER_INFO_PARAM = 6,
        CMSG_SIGNER_CERT_INFO_PARAM = 7,
        CMSG_SIGNER_HASH_ALGORITHM_PARAM = 8,
        CMSG_SIGNER_AUTH_ATTR_PARAM = 9,
        CMSG_SIGNER_UNAUTH_ATTR_PARAM = 10,
        CMSG_CERT_COUNT_PARAM = 11,
        CMSG_CERT_PARAM = 12,
        CMSG_CRL_COUNT_PARAM = 13,
        CMSG_CRL_PARAM = 14,
        CMSG_ENVELOPE_ALGORITHM_PARAM = 15,
        CMSG_RECIPIENT_COUNT_PARAM = 17,
        CMSG_RECIPIENT_INDEX_PARAM = 18,
        CMSG_RECIPIENT_INFO_PARAM = 19,
        CMSG_HASH_ALGORITHM_PARAM = 20,
        CMSG_HASH_DATA_PARAM = 21,
        CMSG_COMPUTED_HASH_PARAM = 22,
        CMSG_ENCRYPT_PARAM = 26,
        CMSG_ENCRYPTED_DIGEST = 27,
        CMSG_ENCODED_SIGNER = 28,
        CMSG_ENCODED_MESSAGE = 29,
        CMSG_VERSION_PARAM = 30,
        CMSG_ATTR_CERT_COUNT_PARAM = 31,
        CMSG_ATTR_CERT_PARAM = 32,
        CMSG_CMS_RECIPIENT_COUNT_PARAM = 33,
        CMSG_CMS_RECIPIENT_INDEX_PARAM = 34,
        CMSG_CMS_RECIPIENT_ENCRYPTED_KEY_INDEX_PARAM = 35,
        CMSG_CMS_RECIPIENT_INFO_PARAM = 36,
        CMSG_UNPROTECTED_ATTR_PARAM = 37,
        CMSG_SIGNER_CERT_ID_PARAM = 38,
        CMSG_CMS_SIGNER_INFO_PARAM = 39
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct CMSG_SIGNER_ENCODE_INFO
    {
        internal uint cbSize;
        internal IntPtr pCertInfo;
        internal IntPtr hCryptProvOrhNCryptKey;
        internal int dwKeySpec;
        internal CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
        internal IntPtr pvHashAuxInfo;
        internal int cAuthAttr;
        internal IntPtr rgAuthAttr;
        internal int cUnauthAttr;
        internal IntPtr rgUnauthAttr;
        internal CERT_ID SignerId;
        internal CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
        internal IntPtr pvHashEncryptionAuxInfo;

        public void Dispose()
        {
            if (!hCryptProvOrhNCryptKey.Equals(IntPtr.Zero)) { NativeMethods.CryptReleaseContext(hCryptProvOrhNCryptKey, 0); }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct CRYPT_ALGORITHM_IDENTIFIER
    {
        public string pszObjId;
        public CRYPT_INTEGER_BLOB Parameters;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct BLOB
    {
        public uint cbData;
        public IntPtr pbData;

        public void Dispose()
        {
            NativeUtility.SafeFree(pbData);
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct CERT_ID
    {
        internal uint dwIdChoice;
        internal BLOB KeyId;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct CMSG_SIGNED_ENCODE_INFO
    {
        internal int cbSize;
        internal int cSigners;
        internal IntPtr rgSigners;
        internal int cCertEncoded;
        internal IntPtr rgCertEncoded;
        internal int cCrlEncoded;
        internal IntPtr rgCrlEncoded;
        internal int cAttrCertEncoded;
        internal IntPtr rgAttrCertEncoded;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct CERT_CONTEXT
    {
        public uint dwCertEncodingType;
        public IntPtr pbCertEncoded;
        public uint cbCertEncoded;
        public IntPtr pCertInfo;
        public IntPtr hCertStore;
    }
}