File: System\ServiceModel\Channels\PeerUnsafeNativeCryptMethods.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Channels
{
    using System;
    using System.Runtime;
    using System.Runtime.ConstrainedExecution;
    using System.Runtime.InteropServices;
    using System.Runtime.Versioning;
    using System.Security;
    using System.Text;
 
    [StructLayout(LayoutKind.Sequential)]
    struct SystemTime
    {
        public short wYear;
        public short wMonth;
        public short wDayOfWeek;
        public short wDay;
        public short wHour;
        public short wMinute;
        public short wSecond;
        public short wMilliseconds;
 
        public SystemTime(DateTime date)
        {
            wYear = (short)date.Year;
            wMonth = (short)date.Month;
            wDayOfWeek = (short)date.DayOfWeek;
            wDay = (short)date.Day;
            wHour = (short)date.Hour;
            wMinute = (short)date.Minute;
            wSecond = (short)date.Second;
            wMilliseconds = (short)date.Millisecond;
        }
    }
 
    [SuppressUnmanagedCodeSecurity]
    class CertificateHandle : SafeHandle
    {
        #region PInvoke declarations
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [DllImport("Crypt32.dll", CallingConvention = CallingConvention.StdCall)]
        [ResourceExposure(ResourceScope.None)]
        extern static bool CertFreeCertificateContext(IntPtr pCertContext);
 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [DllImport("Crypt32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [ResourceExposure(ResourceScope.None)]
        extern static bool CertDeleteCertificateFromStore(IntPtr pCertContext);
 
        #endregion
        protected bool delete = false;
        protected CertificateHandle()
            : base(IntPtr.Zero, true)
        {
            return;
        }
 
        public override bool IsInvalid
        {
            get { return handle == IntPtr.Zero; }
        }
 
        protected override bool ReleaseHandle()
        {
            if (delete)
                return CertDeleteCertificateFromStore(handle);
            else
                return CertFreeCertificateContext(handle);
        }
    }
 
    [SuppressUnmanagedCodeSecurity]
    sealed class StoreCertificateHandle : CertificateHandle
    {
        StoreCertificateHandle() : base() { base.delete = true; }
    }
 
    [SuppressUnmanagedCodeSecurity]
    sealed class CertificateStoreHandle : SafeHandle
    {
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [DllImport("Crypt32.dll", CallingConvention = CallingConvention.StdCall)]
        [ResourceExposure(ResourceScope.None)]
        static extern bool CertCloseStore(IntPtr hCertStore, int dwFlags);
 
        CertificateStoreHandle()
            : base(IntPtr.Zero, true)
        {
            return;
        }
 
        public override bool IsInvalid
        {
            get { return handle == IntPtr.Zero; }
        }
 
        protected override bool ReleaseHandle()
        {
            return CertCloseStore(handle, 0);
        }
    }
 
    [SuppressUnmanagedCodeSecurity]
    sealed class KeyContainerHandle : SafeHandle
    {
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [DllImport("Advapi32.dll", CallingConvention = CallingConvention.StdCall)]
        [ResourceExposure(ResourceScope.None)]
        static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);
 
        KeyContainerHandle()
            : base(IntPtr.Zero, true)
        {
            return;
        }
 
        public override bool IsInvalid
        {
            get { return handle == IntPtr.Zero; }
        }
 
        protected override bool ReleaseHandle()
        {
            return CryptReleaseContext(handle, 0);
        }
    }
 
    sealed class KeyHandle : SafeHandle
    {
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [DllImport("Advapi32.dll", CallingConvention = CallingConvention.StdCall)]
        [ResourceExposure(ResourceScope.None)]
        static extern bool CryptDestroyKey(IntPtr hKey);
 
        KeyHandle()
            : base(IntPtr.Zero, true)
        {
            return;
        }
 
        public override bool IsInvalid
        {
            get { return handle == IntPtr.Zero; }
        }
 
        protected override bool ReleaseHandle()
        {
            return CryptDestroyKey(handle);
        }
    }
 
    sealed class CryptoApiBlob : IDisposable
    {
        int cbData;
        CriticalAllocHandle data;
 
        public CryptoApiBlob()
        {
        }
 
        public CryptoApiBlob(byte[] bytes)
        {
            Fx.Assert(bytes != null, "Cannot set null data");
            AllocateBlob(bytes.Length);
            Marshal.Copy(bytes, 0, (IntPtr)data, bytes.Length);
            cbData = bytes.Length;
            return;
        }
 
        public int DataSize
        {
            get
            {
                Fx.Assert(cbData >= 0, "Size must be greater than or equal to zero");
                return cbData;
            }
        }
 
        public void AllocateBlob(int size)
        {
            data = CriticalAllocHandle.FromSize(size);
            cbData = size;
        }
 
        [StructLayout(LayoutKind.Sequential)]
        public class InteropHelper
        {
            public int size;
            public IntPtr data;
            public InteropHelper(int size, IntPtr data)
            {
                this.size = size;
                this.data = data;
            }
        }
        public InteropHelper GetMemoryForPinning()
        {
            return new InteropHelper(cbData, (IntPtr)data);
        }
 
        public byte[] GetBytes()
        {
            if (cbData == 0)
                return null;
 
            byte[] bytes = DiagnosticUtility.Utility.AllocateByteArray(cbData);
            Marshal.Copy((IntPtr)data, bytes, 0, cbData);
            return bytes;
        }
 
        void Dispose(bool disposing)
        {
            if (disposing)
            {
                GC.SuppressFinalize(this);
            }
        }
 
        public void Dispose()
        {
            Dispose(true);
            return;
        }
    }
 
    sealed class CertificateName
    {
        #region PInvoke Declarations
        [DllImport("Crypt32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto, SetLastError = true)]
        [ResourceExposure(ResourceScope.None)]
        extern static bool CertStrToName(CertEncodingType dwCertEncodingType,
                                                    [MarshalAs(UnmanagedType.LPTStr)]string pszX500,
                                                    StringType dwStrType,
                                                    IntPtr pvReserved,
                                                    [In, Out]byte[] pbEncoded,
                                                    [In, Out]ref int pcbEncoded,
                                                    [MarshalAs(UnmanagedType.LPTStr)]ref StringBuilder ppszError);
 
 
        [Flags]
        enum CertEncodingType : int
        {
            X509AsnEncoding = 0x00000001,
            PKCS7AsnEncoding = 0x00010000
        }
 
        [Flags]
        enum StringType : int
        {
            SimpleNameString = 1,
            OIDNameString = 2,
            X500NameString = 3,
 
            CommaFlag = 0x04000000,
            SemicolonFlag = 0x40000000,
            CRLFFlag = 0x08000000,
            NoPlusFlag = 0x20000000,
            NoQuotingFlag = 0x10000000,
            ReverseFlag = 0x02000000,
            DisableIE4UTF8Flag = 0x00010000,
            EnableT61UnicodeFlag = 0x00020000,
            EnableUTF8UnicodeFlag = 0x00040000
        }
        #endregion
 
        string dn;
 
        public CertificateName(string dn)
        {
            Fx.Assert(!String.IsNullOrEmpty(dn), "Empty subject name for certificate!");
            this.dn = dn;
        }
 
        public string DistinguishedName
        {
            get { return dn; }
        }
 
        public CryptoApiBlob GetCryptoApiBlob()
        {
            byte[] encodedName = GetEncodedName();
            return new CryptoApiBlob(encodedName);
        }
 
        byte[] GetEncodedName()
        {
            int encodingSize = 0;
            StringBuilder errorString = null;
 
            CertStrToName(CertEncodingType.X509AsnEncoding | CertEncodingType.PKCS7AsnEncoding,
                            DistinguishedName,
                            StringType.OIDNameString | StringType.ReverseFlag,
                            IntPtr.Zero,
                            null,
                            ref encodingSize,
                            ref errorString);
 
            byte[] encodedBytes = new byte[encodingSize];
            bool ok = CertStrToName(CertEncodingType.X509AsnEncoding | CertEncodingType.PKCS7AsnEncoding,
                                        DistinguishedName,
                                        StringType.OIDNameString | StringType.ReverseFlag,
                                        IntPtr.Zero,
                                        encodedBytes,
                                        ref encodingSize,
                                        ref errorString);
 
            if (!ok)
            {
                PeerExceptionHelper.ThrowInvalidOperation_PeerCertGenFailure(PeerExceptionHelper.GetLastException());
            }
 
            return encodedBytes;
        }
    }
 
 
    sealed partial class SelfSignedCertificate : IDisposable
    {
        #region PInvoke declarations
        [DllImport("Crypt32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [ResourceExposure(ResourceScope.None)]
        extern static CertificateHandle CertCreateSelfSignCertificate(
                                                    KeyContainerHandle hProv,
                                                    CryptoApiBlob.InteropHelper pSubjectIssuerBlob,
                                                    SelfSignFlags dwFlags,
                                                    IntPtr pKeyProvInfo,
                                                    IntPtr pSignatureAlgorithm,
                                                    [In] ref SystemTime pStartTime,
                                                    [In] ref SystemTime pEndTime,
                                                    IntPtr pExtensions);
 
        [DllImport("Crypt32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [ResourceExposure(ResourceScope.None)]
        extern static CertificateStoreHandle CertOpenStore(
                                                    IntPtr lpszStoreProvider,
                                                    int dwMsgAndCertEncodingType,
                                                    IntPtr hCryptProv,
                                                    int dwFlags,
                                                    IntPtr pvPara);
 
        [DllImport("Crypt32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [ResourceExposure(ResourceScope.None)]
        extern static bool CertAddCertificateContextToStore(
                                                    CertificateStoreHandle hCertStore,
                                                    CertificateHandle pCertContext,
                                                    AddDisposition dwAddDisposition,
                                                    [Out]out StoreCertificateHandle ppStoreContext);
 
        [DllImport("Advapi32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [ResourceExposure(ResourceScope.None)]
        extern static bool CryptAcquireContext(
                                                    [Out]out KeyContainerHandle phProv,
                                                    string pszContainer,
                                                    string pszProvider,
                                                    ProviderType dwProvType,
                                                    ContextFlags dwFlags);
 
        [DllImport("Advapi32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [ResourceExposure(ResourceScope.None)]
        extern static bool CryptGenKey(
                                                    KeyContainerHandle hProv,
                                                    AlgorithmType algId,
                                                    KeyFlags dwFlags,
                                                    [Out]out KeyHandle phKey);
 
        [DllImport("Crypt32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true, CharSet = CharSet.Unicode)]
        [ResourceExposure(ResourceScope.None)]
        extern static bool PFXExportCertStoreEx(
                                                    CertificateStoreHandle hStore,
                                                    IntPtr pPFX,
            //IntPtr szPassword,
                                                    string password,
                                                    IntPtr pvReserved,
                                                    PfxExportFlags dwFlags);
 
        [DllImport("Crypt32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [ResourceExposure(ResourceScope.None)]
        extern static bool CertSetCertificateContextProperty(
                                                    CertificateHandle context,
                                                    int propId,
                                                    int flags,
                                                    KeyHandle pv);
 
        [Flags]
        enum SelfSignFlags : int
        {
            None = 0,
            NoSign = 1,
            NoKeyInfo = 2,
        }
 
        enum AddDisposition : int
        {
            New = 1,
            UseExisting = 2,
            ReplaceExisting = 3,
            Always = 4,
            ReplaceExistingInheritProperties = 5
        }
 
        [Flags]
        enum PfxExportFlags : int
        {
            ReportNoPrivateKey = 0x00000001,
            ReportNotAbleToExportPrivateKey = 0x00000002,
            ExportPrivateKeys = 0x00000004
        }
 
        enum ProviderType : int
        {
            RsaFull = 1,
            RsaSignature = 2,
            Dss = 3,
            Fortezza = 4,
            MsExchange = 5,
            Ssl = 6,
            RsaSecureChannel = 12,
            DssDiffieHellman = 13,
            EcDsaSignature = 14,
            EcNraSignature = 15,
            EcDsaFull = 16,
            EcNraFull = 17,
            DiffieHellmanSecureChannel = 18,
            SpyrusLynks = 20,
            RandomNumberGenerator = 21,
            IntelSec = 22,
            ReplaceOwf = 23,
            RsaAes = 24
        }
 
        [Flags]
        enum ContextFlags : uint
        {
            VerifyContext = 0xF0000000,
            NewKeySet = 0x00000008,
            DeleteKeySet = 0x00000010,
            MachineKeySet = 0x00000020,
            Silent = 0x00000040
        }
 
        enum AlgorithmType : int
        {
            KeyExchange = 1,
            Signature = 2
        }
 
        enum KeyFlags : int
        {
            Exportable = 0x00000001,
            UserProtected = 0x00000002,
            CreateSalt = 0x00000004,
            UpdateKey = 0x00000008,
            NoSalt = 0x00000010,
            PreGenerate = 0x00000040,
            Online = 0x00000080,
            Sf = 0x00000100,
            CreateIv = 0x00000200,
            KeyExchangeKey = 0x00000400,
            DataKey = 0x00000800,
            Volatile = 0x00001000,
            SgcKey = 0x00002000,
            Archivable = 0x00004000,
            Exportable2k = 0x08000001,
        }
 
        const int CERT_KEY_SPEC_PROP_ID = 1;
        const int CERT_KEY_PROV_INFO_PROP_ID = 2;
 
        #endregion
 
        [Serializable]
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public class CRYPT_KEY_PROV_INFO
        {
            public string container;
            public string provName;
            public int providerType;
            public int flags;
            public int paramsCount;
            public IntPtr param;
            public int keySpec;
        }
 
        [Serializable]
        [StructLayout(LayoutKind.Sequential)]
        public struct CRYPT_OBJID_BLOB
        {
            public int count;
            public IntPtr parameters;
        }
 
        [Serializable]
        [StructLayout(LayoutKind.Sequential)]
        public class CRYPT_ALGORITHM_IDENTIFIER
        {
            public CRYPT_ALGORITHM_IDENTIFIER(string id)
            {
                this.pszObjId = id;
            }
            public string pszObjId;
            public CRYPT_OBJID_BLOB Parameters;
        }
 
        [Serializable]
        [StructLayout(LayoutKind.Sequential)]
        public class Sha1AlgorithmId : CRYPT_ALGORITHM_IDENTIFIER
        {
            const string AlgId = "1.2.840.113549.1.1.5";
            public Sha1AlgorithmId() : base(AlgId) { }
        }
 
        CriticalAllocHandle GetProviderInfo()
        {
            CRYPT_KEY_PROV_INFO provInfo = new CRYPT_KEY_PROV_INFO();
            provInfo.container = this.keyContainerName;
            provInfo.providerType = (int)ProviderType.RsaSecureChannel;
            provInfo.paramsCount = 0;
            provInfo.keySpec = (int)AlgorithmType.KeyExchange;
            return CriticalAllocHandleBlob.FromBlob<CRYPT_KEY_PROV_INFO>(provInfo);
        }
 
        static CriticalAllocHandle GetSha1AlgorithmId()
        {
            Sha1AlgorithmId sha1Id = new Sha1AlgorithmId();
            return CriticalAllocHandleBlob.FromBlob<CRYPT_ALGORITHM_IDENTIFIER>(sha1Id);
        }
    }
}