PkcsUtils.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / ManagedLibraries / Security / System / Security / Cryptography / Pkcs / PkcsUtils.cs / 1305376 / PkcsUtils.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

// 
// PkcsUtils.cs 
//
 
namespace System.Security.Cryptography.Pkcs {
    using System.Collections;
    using System.Diagnostics;
    using System.Globalization; 
    using System.IO;
    using System.Runtime.InteropServices; 
    using System.Security; 
    using System.Security.Cryptography;
    using System.Security.Cryptography.X509Certificates; 
    using System.Security.Cryptography.Xml;
    using System.Text;
    using System.Runtime.Versioning;
 
    internal static class PkcsUtils {
        private static int m_cmsSupported = -1; 
 
        private struct I_CRYPT_ATTRIBUTE {
            internal IntPtr pszObjId; 
            internal uint   cValue;
            internal IntPtr rgValue;    // PCRYPT_ATTR_BLOB
        }
 
        internal static uint AlignedLength (uint length) {
            return ((length + (uint) 7) & ((uint) 0xfffffff8)); 
        } 

        [SecuritySafeCritical] 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal static bool CmsSupported () {
            if (m_cmsSupported == -1) { 
                using(SafeLibraryHandle hModule = CAPI.CAPISafe.LoadLibrary("Crypt32.dll")) {
                    if (!hModule.IsInvalid) { 
                    IntPtr pFunc = CAPI.CAPISafe.GetProcAddress(hModule, "CryptMsgVerifyCountersignatureEncodedEx"); 
                    m_cmsSupported = pFunc == IntPtr.Zero ? 0 : 1;
                    } 
                }
            }

            return m_cmsSupported == 0 ? false : true; 
        }
 
        [SecuritySafeCritical] 
        internal static RecipientInfoType GetRecipientInfoType (X509Certificate2 certificate) {
            RecipientInfoType recipientInfoType = RecipientInfoType.Unknown; 

            if (certificate != null) {
                CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(certificate).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT));
                CAPI.CERT_INFO certInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); 

                uint algId = X509Utils.OidToAlgId(certInfo.SubjectPublicKeyInfo.Algorithm.pszObjId); 
                if (algId == CAPI.CALG_RSA_KEYX) 
                    recipientInfoType = RecipientInfoType.KeyTransport;
                else if (algId == CAPI.CALG_DH_SF || algId == CAPI.CALG_DH_EPHEM) 
                    recipientInfoType = RecipientInfoType.KeyAgreement;
                else
                    recipientInfoType = RecipientInfoType.Unknown;
            } 

            return recipientInfoType; 
        } 

        [SecurityCritical] 
        internal static unsafe int GetMaxKeyLength (SafeCryptProvHandle safeCryptProvHandle, uint algId) {
            uint enumFlag = CAPI.CRYPT_FIRST;
            uint cbPeex = (uint) Marshal.SizeOf(typeof(CAPI.PROV_ENUMALGS_EX));
            SafeLocalAllocHandle pPeex = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.PROV_ENUMALGS_EX)))); 

            using (pPeex) { 
                while (CAPI.CAPISafe.CryptGetProvParam(safeCryptProvHandle, CAPI.PP_ENUMALGS_EX, pPeex.DangerousGetHandle(), new IntPtr(&cbPeex), enumFlag)) { 
                    CAPI.PROV_ENUMALGS_EX peex = (CAPI.PROV_ENUMALGS_EX) Marshal.PtrToStructure(pPeex.DangerousGetHandle(), typeof(CAPI.PROV_ENUMALGS_EX));
 
                    if (peex.aiAlgid == algId)
                        return (int) peex.dwMaxLen;

                    enumFlag = 0; 
                }
            } 
 
            throw new CryptographicException(CAPI.CRYPT_E_UNKNOWN_ALGO);
        } 

        [SecurityCritical]
        internal static unsafe uint GetVersion (SafeCryptMsgHandle safeCryptMsgHandle) {
            uint dwVersion = 0; 
            uint cbCount = (uint) Marshal.SizeOf(typeof(uint));
            if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle, 
                                                CAPI.CMSG_VERSION_PARAM, 
                                                0,
                                                new IntPtr(&dwVersion), 
                                                new IntPtr(&cbCount)))
                checkErr(Marshal.GetLastWin32Error());

            return dwVersion; 
        }
 
        [SecurityCritical] 
        internal static unsafe uint GetMessageType (SafeCryptMsgHandle safeCryptMsgHandle) {
            uint dwMsgType = 0; 
            uint cbMsgType = (uint) Marshal.SizeOf(typeof(uint));
            if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle,
                                                CAPI.CMSG_TYPE_PARAM,
                                                0, 
                                                new IntPtr(&dwMsgType),
                                                new IntPtr(&cbMsgType))) 
                checkErr(Marshal.GetLastWin32Error()); 

            return dwMsgType; 
        }

        [SecurityCritical]
        internal static unsafe AlgorithmIdentifier GetAlgorithmIdentifier (SafeCryptMsgHandle safeCryptMsgHandle) { 
            AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier();
 
            uint cbAlgorithm = 0; 
            if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle,
                                                CAPI.CMSG_ENVELOPE_ALGORITHM_PARAM, 
                                                0,
                                                IntPtr.Zero,
                                                new IntPtr(&cbAlgorithm)))
                checkErr(Marshal.GetLastWin32Error()); 

            if (cbAlgorithm > 0) { 
                SafeLocalAllocHandle pbAlgorithm = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbAlgorithm)); 
                if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle,
                                                    CAPI.CMSG_ENVELOPE_ALGORITHM_PARAM, 
                                                    0,
                                                    pbAlgorithm,
                                                    new IntPtr(&cbAlgorithm)))
                    checkErr(Marshal.GetLastWin32Error()); 

                CAPI.CRYPT_ALGORITHM_IDENTIFIER cryptAlgorithmIdentifier = (CAPI.CRYPT_ALGORITHM_IDENTIFIER) Marshal.PtrToStructure(pbAlgorithm.DangerousGetHandle(), typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER)); 
                algorithmIdentifier = new AlgorithmIdentifier(cryptAlgorithmIdentifier); 
                pbAlgorithm.Dispose();
            } 

            return algorithmIdentifier;
        }
 
        [SecurityCritical]
        internal static unsafe void GetParam (SafeCryptMsgHandle safeCryptMsgHandle, 
                                              uint paramType, 
                                              uint index,
                                              out SafeLocalAllocHandle pvData, 
                                              out uint cbData) {
            cbData = 0;
            pvData = SafeLocalAllocHandle.InvalidHandle;
 
            fixed (uint * pcbData = &cbData) {
                if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle, 
                                                    paramType, 
                                                    index,
                                                    pvData, 
                                                    new IntPtr(pcbData)))
                    checkErr(Marshal.GetLastWin32Error());

                if (cbData > 0) { 
                    pvData = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbData));
 
                    if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle, 
                                                        paramType,
                                                        index, 
                                                        pvData,
                                                        new IntPtr(pcbData)))
                        checkErr(Marshal.GetLastWin32Error());
                } 
            }
        } 
 
        [SecurityCritical]
        internal static unsafe void GetParam (SafeCryptMsgHandle safeCryptMsgHandle, 
                                              uint paramType,
                                              uint index,
                                              out byte[] pvData,
                                              out uint cbData) { 
            cbData = 0;
            pvData = new byte[0]; 
 
            fixed (uint * pcbData = &cbData) {
                if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle, 
                                                    paramType,
                                                    index,
                                                    IntPtr.Zero,
                                                    new IntPtr(pcbData))) 
                    checkErr(Marshal.GetLastWin32Error());
 
                if (cbData > 0) { 
                    pvData = new byte[cbData];
 
                    fixed (byte * ppvData = &pvData[0]) {
                        if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle,
                                                            paramType,
                                                            index, 
                                                            new IntPtr(ppvData),
                                                            new IntPtr(pcbData))) 
                            checkErr(Marshal.GetLastWin32Error()); 
                    }
                } 
            }
        }

        [SecurityCritical] 
        internal static unsafe X509Certificate2Collection GetCertificates (SafeCryptMsgHandle safeCryptMsgHandle) {
            uint dwCount = 0; 
            uint cbCount = (uint) Marshal.SizeOf(typeof(uint)); 
            X509Certificate2Collection certificates = new X509Certificate2Collection();
 
            if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle,
                                                CAPI.CMSG_CERT_COUNT_PARAM,
                                                0,
                                                new IntPtr(&dwCount), 
                                                new IntPtr(&cbCount)))
                checkErr(Marshal.GetLastWin32Error()); 
 
            for (uint index = 0; index < dwCount; index++) {
                uint cbEncoded = 0; 
                SafeLocalAllocHandle pbEncoded = SafeLocalAllocHandle.InvalidHandle;

                GetParam(safeCryptMsgHandle, CAPI.CMSG_CERT_PARAM, index, out pbEncoded, out cbEncoded);
                if (cbEncoded > 0) { 
                    SafeCertContextHandle safeCertContextHandle = CAPI.CAPISafe.CertCreateCertificateContext(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                                                             pbEncoded, 
                                                                                                             cbEncoded); 
                    if (safeCertContextHandle == null || safeCertContextHandle.IsInvalid)
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 

                    certificates.Add(new X509Certificate2(safeCertContextHandle.DangerousGetHandle()));
                    safeCertContextHandle.Dispose();
                } 
            }
 
            return certificates; 
        }
 
        [SecurityCritical]
        internal static byte[] GetContent (SafeCryptMsgHandle safeCryptMsgHandle) {
            uint cbContent = 0;
            byte[] content = new byte[0]; 

            GetParam(safeCryptMsgHandle, CAPI.CMSG_CONTENT_PARAM, 0, out content, out cbContent); 
 
            return content;
        } 

        [SecurityCritical]
        internal static Oid GetContentType (SafeCryptMsgHandle safeCryptMsgHandle) {
            uint cbContentType = 0; 
            byte[] contentType = new byte[0];
 
            GetParam(safeCryptMsgHandle, CAPI.CMSG_INNER_CONTENT_TYPE_PARAM, 0, out contentType, out cbContentType); 
            if (contentType.Length > 0 && contentType[contentType.Length - 1] == 0) {
                byte[] temp = new byte[contentType.Length - 1]; 
                Array.Copy(contentType, 0, temp, 0, temp.Length);
                contentType = temp;
            }
            return new Oid(Encoding.ASCII.GetString(contentType)); 
        }
 
        [SecurityCritical] 
        internal static byte[] GetMessage (SafeCryptMsgHandle safeCryptMsgHandle) {
            uint cbMessage = 0; 
            byte[] message = new byte[0];

            GetParam(safeCryptMsgHandle, CAPI.CMSG_ENCODED_MESSAGE, 0, out message, out cbMessage);
            return message; 
        }
 
        [SecurityCritical] 
        internal static unsafe int GetSignerIndex (SafeCryptMsgHandle safeCrytpMsgHandle, SignerInfo signerInfo, int startIndex) {
            uint dwSigners = 0; 
            uint cbCount = (uint) Marshal.SizeOf(typeof(uint));

            if (!CAPI.CAPISafe.CryptMsgGetParam(safeCrytpMsgHandle,
                                                CAPI.CMSG_SIGNER_COUNT_PARAM, 
                                                0,
                                                new IntPtr(&dwSigners), 
                                                new IntPtr(&cbCount))) 
                checkErr(Marshal.GetLastWin32Error());
 
            for (int index = startIndex; index < (int) dwSigners; index++) {
                uint cbCmsgSignerInfo = 0;

                if (!CAPI.CAPISafe.CryptMsgGetParam(safeCrytpMsgHandle, 
                                                    CAPI.CMSG_SIGNER_INFO_PARAM,
                                                    (uint)index, 
                                                    IntPtr.Zero, 
                                                    new IntPtr(&cbCmsgSignerInfo)))
                    checkErr(Marshal.GetLastWin32Error()); 

                if (cbCmsgSignerInfo > 0) {
                    SafeLocalAllocHandle pbCmsgSignerInfo = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbCmsgSignerInfo));
 
                    if (!CAPI.CAPISafe.CryptMsgGetParam(safeCrytpMsgHandle,
                                                        CAPI.CMSG_SIGNER_INFO_PARAM, 
                                                        (uint)index, 
                                                        pbCmsgSignerInfo,
                                                        new IntPtr(&cbCmsgSignerInfo))) 
                        checkErr(Marshal.GetLastWin32Error());

                    CAPI.CMSG_SIGNER_INFO cmsgSignerInfo1 = signerInfo.GetCmsgSignerInfo();
                    CAPI.CMSG_SIGNER_INFO cmsgSignerInfo2 = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO)); 

                    if (X509Utils.MemEqual((byte *) cmsgSignerInfo1.Issuer.pbData, 
                                  cmsgSignerInfo1.Issuer.cbData, 
                                  (byte *) cmsgSignerInfo2.Issuer.pbData,
                                  cmsgSignerInfo2.Issuer.cbData) && 
                        X509Utils.MemEqual((byte *) cmsgSignerInfo1.SerialNumber.pbData,
                                  cmsgSignerInfo1.SerialNumber.cbData,
                                  (byte *) cmsgSignerInfo2.SerialNumber.pbData,
                                  cmsgSignerInfo2.SerialNumber.cbData)) { 
                        return index; // Signer's index is found.
                    } 
 
                    // Keep alive.
                    pbCmsgSignerInfo.Dispose(); 
                }
            }

            throw new CryptographicException(CAPI.CRYPT_E_SIGNER_NOT_FOUND); 
        }
 
        [SecurityCritical] 
        internal static unsafe CryptographicAttributeObjectCollection GetUnprotectedAttributes (SafeCryptMsgHandle safeCryptMsgHandle) {
            uint cbUnprotectedAttr = 0; 
            CryptographicAttributeObjectCollection attributes = new CryptographicAttributeObjectCollection();
            SafeLocalAllocHandle pbUnprotectedAttr = SafeLocalAllocHandle.InvalidHandle;
            if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle,
                                                CAPI.CMSG_UNPROTECTED_ATTR_PARAM, 
                                                0,
                                                pbUnprotectedAttr, 
                                                new IntPtr(&cbUnprotectedAttr))) { 
                int lastWin32Error = Marshal.GetLastWin32Error();
                if (lastWin32Error != CAPI.CRYPT_E_ATTRIBUTES_MISSING) 
                    checkErr(Marshal.GetLastWin32Error());
            }

            if (cbUnprotectedAttr > 0) { 
                using (pbUnprotectedAttr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbUnprotectedAttr))) {
                    if (!CAPI.CAPISafe.CryptMsgGetParam(safeCryptMsgHandle, 
                                                        CAPI.CMSG_UNPROTECTED_ATTR_PARAM, 
                                                        0,
                                                        pbUnprotectedAttr, 
                                                        new IntPtr(&cbUnprotectedAttr)))
                        checkErr(Marshal.GetLastWin32Error());

                    attributes = new CryptographicAttributeObjectCollection(pbUnprotectedAttr); 
                }
            } 
            return attributes; 
        }
 
        [SecurityCritical]
        internal unsafe static X509IssuerSerial DecodeIssuerSerial (CAPI.CERT_ISSUER_SERIAL_NUMBER pIssuerAndSerial) {
            SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle;
            uint cbSize = CAPI.CAPISafe.CertNameToStrW(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                       new IntPtr(&pIssuerAndSerial.Issuer),
                                                       CAPI.CERT_X500_NAME_STR | CAPI.CERT_NAME_STR_REVERSE_FLAG, 
                                                       ptr, 
                                                       0);
            if (cbSize <= 1) // The API actually return 1 when It fails; which is not what the documentation says. 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(2 * cbSize));
            cbSize = CAPI.CAPISafe.CertNameToStrW(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                  new IntPtr(&pIssuerAndSerial.Issuer),
                                                  CAPI.CERT_X500_NAME_STR | CAPI.CERT_NAME_STR_REVERSE_FLAG, 
                                                  ptr, 
                                                  cbSize);
            if (cbSize <= 1) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            X509IssuerSerial issuerSerial = new X509IssuerSerial();
            issuerSerial.IssuerName = Marshal.PtrToStringUni(ptr.DangerousGetHandle()); 
            byte[] serial = new byte[pIssuerAndSerial.SerialNumber.cbData];
            Marshal.Copy(pIssuerAndSerial.SerialNumber.pbData, serial, 0, serial.Length); 
            issuerSerial.SerialNumber = X509Utils.EncodeHexStringFromInt(serial); 

            ptr.Dispose(); 
            return issuerSerial;
        }

        [SecuritySafeCritical] 
        internal static string DecodeOctetString (byte[] encodedOctetString) {
            uint cbDecoded = 0; 
            SafeLocalAllocHandle pbDecoded = null; 

            if (!CAPI.DecodeObject(new IntPtr(CAPI.X509_OCTET_STRING), 
                                   encodedOctetString,
                                   out pbDecoded,
                                   out cbDecoded))
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            if (cbDecoded == 0) 
                return String.Empty; 

            CAPI.CRYPTOAPI_BLOB decodedBlob = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(pbDecoded.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB)); 
            if (decodedBlob.cbData == 0)
                return String.Empty;
            string octetString = Marshal.PtrToStringUni(decodedBlob.pbData);
            pbDecoded.Dispose(); 

            return octetString; 
        } 

        [SecuritySafeCritical] 
        internal static byte[] DecodeOctetBytes (byte[] encodedOctetString) {
            uint cbDecoded = 0;

            SafeLocalAllocHandle pbDecoded = null; 
            if (!CAPI.DecodeObject(new IntPtr(CAPI.X509_OCTET_STRING),
                                   encodedOctetString, 
                                   out pbDecoded, 
                                   out cbDecoded))
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            if (cbDecoded == 0)
                return new byte[0];
 
            using (pbDecoded) {
                return CAPI.BlobToByteArray(pbDecoded.DangerousGetHandle()); 
            } 
        }
 
        internal static byte[] EncodeOctetString (string octetString) {
            // Marshal data to be encoded to unmanaged memory.
            byte[] octets = new byte[2 * (octetString.Length + 1)];
            Encoding.Unicode.GetBytes(octetString, 0, octetString.Length, octets, 0); 
            return EncodeOctetString(octets);
        } 
 
        [SecuritySafeCritical]
        internal static unsafe byte[] EncodeOctetString (byte[] octets) { 
            fixed (byte * pbOctets = octets) {
                CAPI.CRYPTOAPI_BLOB octetsBlob = new CAPI.CRYPTOAPI_BLOB();
                octetsBlob.cbData = (uint) octets.Length;
                octetsBlob.pbData = new IntPtr(pbOctets); 

                // Encode data. 
                byte[] encodedOctets = new byte[0]; 
                if (!CAPI.EncodeObject(new IntPtr((long) CAPI.X509_OCTET_STRING),
                                       new IntPtr((long) &octetsBlob), 
                                       out encodedOctets)) {
                    throw new CryptographicException(Marshal.GetLastWin32Error());
                }
                return encodedOctets; 
            }
        } 
 
        internal static string DecodeObjectIdentifier (byte[] encodedObjId, int offset) {
            StringBuilder objId = new StringBuilder(""); 
            if (0 < (encodedObjId.Length - offset)) {
                byte b = encodedObjId[offset];
                byte c = (byte) ((uint) b / 40);
                objId.Append(c.ToString(null, null)); 
                objId.Append(".");
                c = (byte) ((uint) b % 40); 
                objId.Append(c.ToString(null, null)); 

                ulong s = 0; 
                for (int index = offset + 1; index < encodedObjId.Length; index++) {
                    c = encodedObjId[index];
                    s = (s << 7) + (ulong) (c & 0x7f);
                    if (0 == (c & 0x80)) { 
                        objId.Append(".");
                        objId.Append(s.ToString(null, null)); 
                        s = 0; 
                    }
                } 

                // s should be 0 at this point, otherwise we have a bad ASN.
                if (0 != s) {
                    throw new CryptographicException(CAPI.CRYPT_E_BAD_ENCODE); 
                }
            } 
 
            return objId.ToString();
        } 

        internal static CmsRecipientCollection SelectRecipients (SubjectIdentifierType recipientIdentifierType) {
            X509Store store = new X509Store("AddressBook");
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); 

            X509Certificate2Collection certificates = new X509Certificate2Collection(store.Certificates); 
 
            foreach (X509Certificate2 certificate in store.Certificates) {
                if (certificate.NotBefore <= DateTime.Now && certificate.NotAfter >= DateTime.Now) { 
                    bool validUsages = true;
                    foreach (X509Extension extension in certificate.Extensions) {
                        if (String.Compare(extension.Oid.Value, CAPI.szOID_KEY_USAGE, StringComparison.OrdinalIgnoreCase) == 0) {
                            X509KeyUsageExtension keyUsage = new X509KeyUsageExtension(); 
                            keyUsage.CopyFrom(extension);
                            if ((keyUsage.KeyUsages & X509KeyUsageFlags.KeyEncipherment) == 0 && 
                                (keyUsage.KeyUsages & X509KeyUsageFlags.KeyAgreement) == 0) { 
                                validUsages = false;
                            } 
                            break;
                        }
                    }
 
                    if (validUsages) {
                        certificates.Add(certificate); 
                    } 
                }
            } 

            if (certificates.Count < 1)
                throw new CryptographicException(CAPI.CRYPT_E_RECIPIENT_NOT_FOUND);
 
            X509Certificate2Collection recipients = X509Certificate2UI.SelectFromCollection(certificates, null, null, X509SelectionFlag.MultiSelection);
            if (recipients.Count < 1) 
                throw new CryptographicException(CAPI.ERROR_CANCELLED); 

            return new CmsRecipientCollection(recipientIdentifierType, recipients); 
        }

        internal static X509Certificate2 SelectSignerCertificate () {
            X509Store store = new X509Store(); 
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly | OpenFlags.IncludeArchived);
 
            X509Certificate2Collection certificates = new X509Certificate2Collection(); 

            foreach (X509Certificate2 certificate in store.Certificates) { 
                if (certificate.HasPrivateKey && certificate.NotBefore <= DateTime.Now && certificate.NotAfter >= DateTime.Now) {
                    bool validUsages = true;
                    foreach (X509Extension extension in certificate.Extensions) {
                        if (String.Compare(extension.Oid.Value, CAPI.szOID_KEY_USAGE, StringComparison.OrdinalIgnoreCase) == 0) { 
                            X509KeyUsageExtension keyUsage = new X509KeyUsageExtension();
                            keyUsage.CopyFrom(extension); 
                            if ((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == 0 && 
                                (keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == 0) {
                                validUsages = false; 
                            }
                            break;
                        }
                    } 

                    if (validUsages) { 
                        certificates.Add(certificate); 
                    }
                } 
            }

            if (certificates.Count < 1)
                throw new CryptographicException(CAPI.CRYPT_E_SIGNER_NOT_FOUND); 

            certificates = X509Certificate2UI.SelectFromCollection(certificates, null, null, X509SelectionFlag.SingleSelection); 
            if (certificates.Count < 1) 
                throw new CryptographicException(CAPI.ERROR_CANCELLED);
 
            Debug.Assert(certificates.Count == 1);

            return certificates[0];
        } 

        [SecuritySafeCritical] 
        internal static AsnEncodedDataCollection GetAsnEncodedDataCollection (CAPI.CRYPT_ATTRIBUTE cryptAttribute) { 
            AsnEncodedDataCollection list = new AsnEncodedDataCollection();
            Oid oid = new Oid(cryptAttribute.pszObjId); 
            string szOid = oid.Value;

            for (uint index = 0; index < cryptAttribute.cValue; index++) {
                IntPtr pAttributeBlob = new IntPtr((long)cryptAttribute.rgValue + (index * Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB)))); 
                Pkcs9AttributeObject attribute = new Pkcs9AttributeObject(oid, CAPI.BlobToByteArray(pAttributeBlob));
                Pkcs9AttributeObject customAttribute = CryptoConfig.CreateFromName(szOid) as Pkcs9AttributeObject; 
                if (customAttribute != null) { 
                    customAttribute.CopyFrom(attribute);
                    attribute = customAttribute; 
                }
                list.Add(attribute);
            }
            return list; 
        }
 
        [SecurityCritical] 
        internal static AsnEncodedDataCollection GetAsnEncodedDataCollection (CAPI.CRYPT_ATTRIBUTE_TYPE_VALUE cryptAttribute) {
            AsnEncodedDataCollection list = new AsnEncodedDataCollection(); 
            list.Add(new Pkcs9AttributeObject(new Oid(cryptAttribute.pszObjId), CAPI.BlobToByteArray(cryptAttribute.Value)));
            return list;
        }
 
        [SecurityCritical]
        internal static unsafe IntPtr CreateCryptAttributes (CryptographicAttributeObjectCollection attributes) { 
            // NULL if no attribute. 
            if (attributes.Count == 0)
                return IntPtr.Zero; 

            //
            // The goal here is to compute the size needed for the attributes we are passing to CMSG_SIGNER_ENCODE_INFO
            // The unmanaged memory structure we are creating here has the following layout: 
            //
            // Let cAttr = number of attributes. 
            // 
            // This to create the array of CRYPT_ATTRIBUTE
            // for i = 0 to cAttr { 
            //     CRYPT_ATTRRIBUTE[i]                           // pszObjId | cValue | rgValue
            // }
            //
            // This is to fill in the data for each entry of CRYPT_ATTRIBUTE array above. 
            // for i = 0 to cAttr {
            //     objId[i]                                      // Value of the Oid, i.e "1.2.3.4" 
            //     for j = 0 to CRYPT_ATTRIBUTE[i].cValue - 1 {  // Array of CRYPTOAPI_BLOB 
            //        CRYPT_ATTRIBUTE[i].rgValue[j].cbData       // Data size
            //        CRYPT_ATTRIBUTE[i].rgValue[j].pbData       // Pointer to data 
            //     }
            //     for j = 0 to CRYPT_ATTRIBUTE[i].cValue - 1 {  // Data for each entry of the CRYPTOAPI_BLOB array above.
            //        *CRYPT_ATTRIBUTE[i].rgValue[j].pbData      // The actual data
            //    } 
            // }
 
            uint totalLength = 0; 
            uint cryptAttrSize = AlignedLength((uint) Marshal.SizeOf(typeof(I_CRYPT_ATTRIBUTE)));
            uint cryptBlobSize = AlignedLength((uint) Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB))); 

            // First compute the total serialized unmanaged memory size needed.
            // For each attribute, we add the CRYPT_ATTRIBUTE size, the size
            // needed for the ObjId, and the size needed for all the values 
            // inside each attribute which is computed in inner loop.
            foreach (CryptographicAttributeObject attribute in attributes) { 
                totalLength += cryptAttrSize;  // sizeof(CRYPT_ATTRIBUTE) 
                totalLength += AlignedLength((uint) (attribute.Oid.Value.Length + 1));  // strlen(pszObjId) + 1
 
                // For each value within the attribute, we add the CRYPT_ATTR_BLOB size and
                // the actual size needed for the data.
                foreach (AsnEncodedData attributeValue in attribute.Values) {
                    totalLength += cryptBlobSize;   // Add CRYPT_ATTR_BLOB size 
                    totalLength += AlignedLength((uint) attributeValue.RawData.Length); // Data size
                } 
            } 

            // Allocate the unmanaged memory blob to hold the entire serialized CRYPT_ATTRIBUTE array. 
            SafeLocalAllocHandle pCryptAttributes = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(totalLength));

            // Now fill up unmanaged memory with data from the managed side.
            I_CRYPT_ATTRIBUTE * pCryptAttribute = (I_CRYPT_ATTRIBUTE *) pCryptAttributes.DangerousGetHandle(); 
            IntPtr pAttrData = new IntPtr((long) pCryptAttributes.DangerousGetHandle() + (cryptAttrSize * attributes.Count));
 
            foreach (CryptographicAttributeObject attribute in attributes) { 
                byte * pszObjId = (byte *) pAttrData;
                byte[] objId = new byte[attribute.Oid.Value.Length + 1]; 
                CAPI.CRYPTOAPI_BLOB * pDataBlob = (CAPI.CRYPTOAPI_BLOB *) (pszObjId + AlignedLength((uint) objId.Length));

                // CRYPT_ATTRIBUTE.pszObjId
                pCryptAttribute->pszObjId = (IntPtr) pszObjId; 

                // CRYPT_ATTRIBUTE.cValue 
                pCryptAttribute->cValue = (uint) attribute.Values.Count; 

                // CRYPT_ATTRIBUTE.rgValue 
                pCryptAttribute->rgValue = (IntPtr) pDataBlob;

                // ObjId - The actual dotted value of the OID.
                Encoding.ASCII.GetBytes(attribute.Oid.Value, 0, attribute.Oid.Value.Length, objId, 0); 
                Marshal.Copy(objId, 0, pCryptAttribute->pszObjId, objId.Length);
 
                // cValue of CRYPT_ATTR_BLOBs followed by cValue of actual data. 
                IntPtr pbEncodedData = new IntPtr((long) pDataBlob + (attribute.Values.Count * cryptBlobSize));
                foreach (AsnEncodedData value in attribute.Values) { 
                    // Retrieve encoded data.
                    byte[] encodedData = value.RawData;

                    // Write data 
                    if (encodedData.Length > 0) {
                        // CRYPT_ATTR_BLOB.cbData 
                        pDataBlob->cbData = (uint) encodedData.Length; 

                        // CRYPT_ATTR_BLOB.pbData 
                        pDataBlob->pbData = pbEncodedData;

                        Marshal.Copy(encodedData, 0, pbEncodedData, encodedData.Length);
                        pbEncodedData = new IntPtr((long) pbEncodedData + AlignedLength((uint) encodedData.Length)); 
                    }
 
                    // Advance pointer. 
                    pDataBlob++;
                } 

                // Advance pointers.
                pCryptAttribute++;
                pAttrData = pbEncodedData; 
            }
 
            // Since we are returning IntPtr, we MUST supress finalizer, otherwise 
            // the GC can collect the memory underneath us!!!
            GC.SuppressFinalize(pCryptAttributes); 

            return pCryptAttributes.DangerousGetHandle();
        }
 
        internal static CAPI.CMSG_SIGNER_ENCODE_INFO CreateSignerEncodeInfo (CmsSigner signer) {
            return CreateSignerEncodeInfo(signer, false); 
        } 

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [SecuritySafeCritical]
        internal static unsafe CAPI.CMSG_SIGNER_ENCODE_INFO CreateSignerEncodeInfo (CmsSigner signer, bool silent) {
            CAPI.CMSG_SIGNER_ENCODE_INFO cmsSignerEncodeInfo = new CAPI.CMSG_SIGNER_ENCODE_INFO(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNER_ENCODE_INFO))); 

            SafeCryptProvHandle safeCryptProvHandle = SafeCryptProvHandle.InvalidHandle; 
            uint keySpec = 0; 
            bool freeCsp = false;
 
            cmsSignerEncodeInfo.HashAlgorithm.pszObjId = signer.DigestAlgorithm.Value;

            if (0 == String.Compare(
                signer.Certificate.PublicKey.Oid.Value, 
                CAPI.szOID_X957_DSA,
                StringComparison.Ordinal)) 
            { 
                cmsSignerEncodeInfo.HashEncryptionAlgorithm.pszObjId = CAPI.szOID_X957_sha1DSA;
            } 

            cmsSignerEncodeInfo.cAuthAttr = (uint) signer.SignedAttributes.Count;
            cmsSignerEncodeInfo.rgAuthAttr = CreateCryptAttributes(signer.SignedAttributes);
 
            cmsSignerEncodeInfo.cUnauthAttr = (uint) signer.UnsignedAttributes.Count;
            cmsSignerEncodeInfo.rgUnauthAttr = CreateCryptAttributes(signer.UnsignedAttributes); 
 
            if (signer.SignerIdentifierType == SubjectIdentifierType.NoSignature) {
                cmsSignerEncodeInfo.HashEncryptionAlgorithm.pszObjId = CAPI.szOID_PKIX_NO_SIGNATURE; 
                cmsSignerEncodeInfo.pCertInfo  = IntPtr.Zero;
                cmsSignerEncodeInfo.dwKeySpec  = keySpec;

                //  If the HashEncryptionAlgorithm is set to szOID_PKIX_NO_SIGNATURE, then, 
                //  the signature value only contains the hash octets. hCryptProv must still
                //  be specified. However, since a private key isn't used the hCryptProv can be 
                //  acquired using CRYPT_VERIFYCONTEXT. 
                if (!CAPI.CryptAcquireContext(ref safeCryptProvHandle,
                                              null, 
                                              null,
                                              CAPI.PROV_RSA_FULL,
                                                CAPI.CRYPT_VERIFYCONTEXT)) {
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 
                }
 
                cmsSignerEncodeInfo.hCryptProv = safeCryptProvHandle.DangerousGetHandle(); 
                GC.SuppressFinalize(safeCryptProvHandle);
 
                // Fake up the SignerId so our server can recognize it
                // dwIdChoice
                cmsSignerEncodeInfo.SignerId.dwIdChoice = CAPI.CERT_ID_ISSUER_SERIAL_NUMBER;
 
                // Issuer
                X500DistinguishedName dummyName = new X500DistinguishedName(CAPI.DummySignerCommonName); 
                dummyName.Oid = new Oid(CAPI.szOID_RDN_DUMMY_SIGNER); 
                cmsSignerEncodeInfo.SignerId.Value.IssuerSerialNumber.Issuer.cbData = (uint)dummyName.RawData.Length;
                SafeLocalAllocHandle pbDataIssuer = 
                    CAPI.LocalAlloc(CAPI.LPTR,
                                    new IntPtr(cmsSignerEncodeInfo.SignerId.Value.IssuerSerialNumber.Issuer.cbData));
                Marshal.Copy(dummyName.RawData, 0, pbDataIssuer.DangerousGetHandle(), dummyName.RawData.Length);
                cmsSignerEncodeInfo.SignerId.Value.IssuerSerialNumber.Issuer.pbData = pbDataIssuer.DangerousGetHandle(); 
                GC.SuppressFinalize(pbDataIssuer);
 
                // SerialNumber 
                cmsSignerEncodeInfo.SignerId.Value.IssuerSerialNumber.SerialNumber.cbData = (uint)1;
                SafeLocalAllocHandle pbDataSerialNumber = 
                        CAPI.LocalAlloc(CAPI.LPTR,
                                        new IntPtr(cmsSignerEncodeInfo.SignerId.Value.IssuerSerialNumber.SerialNumber.cbData));
                byte * pSerialNumber = (byte *)pbDataSerialNumber.DangerousGetHandle();
                *pSerialNumber = 0x00; 
                cmsSignerEncodeInfo.SignerId.Value.IssuerSerialNumber.SerialNumber.pbData =
                    pbDataSerialNumber.DangerousGetHandle(); 
                GC.SuppressFinalize(pbDataSerialNumber); 

                return cmsSignerEncodeInfo; 
            }

            SafeCertContextHandle safeCertContextHandle = X509Utils.GetCertContext(signer.Certificate);
 
            if (!CAPI.CAPISafe.CryptAcquireCertificatePrivateKey(safeCertContextHandle,
                    (silent? 
                    CAPI.CRYPT_SILENT | CAPI.CRYPT_ACQUIRE_USE_PROV_INFO_FLAG | CAPI.CRYPT_ACQUIRE_COMPARE_KEY_FLAG: 
                    CAPI.CRYPT_ACQUIRE_USE_PROV_INFO_FLAG | CAPI.CRYPT_ACQUIRE_COMPARE_KEY_FLAG),
                                                        IntPtr.Zero, 
                                                        ref safeCryptProvHandle,
                                                        ref keySpec,
                                                        ref freeCsp))
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            cmsSignerEncodeInfo.dwKeySpec = keySpec; 
            cmsSignerEncodeInfo.hCryptProv = safeCryptProvHandle.DangerousGetHandle(); 

            // Since we are storing only IntPtr in CMSG_SIGNER_ENCODE_INFO.hCryptProv, we MUST then 
            // supress the finalizer, otherwise the GC can collect the resource underneath us!!!
            GC.SuppressFinalize(safeCryptProvHandle);

            CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle()); 
            cmsSignerEncodeInfo.pCertInfo  = pCertContext.pCertInfo;
 
            // If CMS, then fill in the Subject Key Identifier (SKI) or SignerId. 
            if (signer.SignerIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier) {
                uint cbData = 0; 
                SafeLocalAllocHandle pbData = SafeLocalAllocHandle.InvalidHandle;
                if (!CAPI.CAPISafe.CertGetCertificateContextProperty(safeCertContextHandle,
                                                                     CAPI.CERT_KEY_IDENTIFIER_PROP_ID,
                                                                     pbData, 
                                                                     ref cbData))
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
                if (cbData > 0) {
                    pbData = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbData)); 

                    if (!CAPI.CAPISafe.CertGetCertificateContextProperty(safeCertContextHandle,
                                                                         CAPI.CERT_KEY_IDENTIFIER_PROP_ID,
                                                                         pbData, 
                                                                         ref cbData))
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
                    cmsSignerEncodeInfo.SignerId.dwIdChoice = CAPI.CERT_ID_KEY_IDENTIFIER;
                    cmsSignerEncodeInfo.SignerId.Value.KeyId.cbData = cbData; 
                    cmsSignerEncodeInfo.SignerId.Value.KeyId.pbData = pbData.DangerousGetHandle();

                    // Since we are storing only IntPtr in CMSG_SIGNER_ENCODE_INFO.SignerId.KeyId.pbData,
                    // we MUST supress finalizer, otherwise the GC can collect the resource underneath us!!! 
                    GC.SuppressFinalize(pbData);
                } 
            } 

            return cmsSignerEncodeInfo; 
        }

        [SecuritySafeCritical]
        internal static X509Certificate2Collection CreateBagOfCertificates (CmsSigner signer) { 
            X509Certificate2Collection certificates = new X509Certificate2Collection();
 
            // 
            // First add extra bag of certs.
            // 

            certificates.AddRange(signer.Certificates);

            // 
            // Then include chain option.
            // 
 
            if (signer.IncludeOption != X509IncludeOption.None) {
                if (signer.IncludeOption == X509IncludeOption.EndCertOnly) { 
                    certificates.Add(signer.Certificate);
                }
                else {
                    int cCerts = 1; 
                    X509Chain chain = new X509Chain();
                    chain.Build(signer.Certificate); 
 
                    // Can't honor the option if we only have a partial chain.
                    if ((chain.ChainStatus.Length > 0) && 
                        ((chain.ChainStatus[0].Status & X509ChainStatusFlags.PartialChain) == X509ChainStatusFlags.PartialChain))
                        throw new CryptographicException(CAPI.CERT_E_CHAINING);

                    if (signer.IncludeOption == X509IncludeOption.WholeChain) { 
                        cCerts = chain.ChainElements.Count;
                    } 
                    else { 
                        // Default to ExcludeRoot.
                        if (chain.ChainElements.Count > 1) { 
                            cCerts = chain.ChainElements.Count - 1;
                        }
                    }
 
                    for (int i = 0; i < cCerts; i++) {
                        certificates.Add(chain.ChainElements[i].Certificate); 
                    } 
                }
            } 

            return certificates;
        }
 
        [SecurityCritical]
        internal static unsafe SafeLocalAllocHandle CreateEncodedCertBlob (X509Certificate2Collection certificates) { 
            SafeLocalAllocHandle certBlob = SafeLocalAllocHandle.InvalidHandle; 

            if (certificates.Count > 0) { 
                certBlob = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(certificates.Count * Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB))));
                CAPI.CRYPTOAPI_BLOB * pCertBlob = (CAPI.CRYPTOAPI_BLOB * ) certBlob.DangerousGetHandle();

                foreach (X509Certificate2 certificate in certificates) { 
                    SafeCertContextHandle safeCertContextHandle = X509Utils.GetCertContext(certificate);
                    CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle()); 
 
                    pCertBlob->cbData = pCertContext.cbCertEncoded;
                    pCertBlob->pbData = pCertContext.pbCertEncoded; 
                    pCertBlob++;
                }
            }
 
            return certBlob;
        } 
 
        [SecuritySafeCritical]
        internal static unsafe uint AddCertsToMessage (SafeCryptMsgHandle safeCryptMsgHandle, X509Certificate2Collection bagOfCerts, X509Certificate2Collection chainOfCerts) { 
            uint certsAdded = 0;

            foreach (X509Certificate2 certificate in chainOfCerts) {
                // Skip it if already in the bag of certs. 
                X509Certificate2Collection foundCerts = bagOfCerts.Find(X509FindType.FindByThumbprint, certificate.Thumbprint, false);
                if (foundCerts.Count == 0) { 
                    SafeCertContextHandle safeCertContextHandle = X509Utils.GetCertContext(certificate); 
                    CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
 
                    CAPI.CRYPTOAPI_BLOB certBlob = new CAPI.CRYPTOAPI_BLOB();
                    certBlob.cbData = pCertContext.cbCertEncoded;
                    certBlob.pbData = pCertContext.pbCertEncoded;
 
                    if (!CAPI.CryptMsgControl(safeCryptMsgHandle,
                                              0, 
                                              CAPI.CMSG_CTRL_ADD_CERT, 
                                              new IntPtr((long) &certBlob)))
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 
                    certsAdded++;
                }
            }
 
            return certsAdded;
        } 
 
        internal static X509Certificate2 FindCertificate (SubjectIdentifier identifier, X509Certificate2Collection certificates) {
            X509Certificate2 certificate = null; 

            if (certificates != null && certificates.Count > 0) {
                X509Certificate2Collection filters;
                switch (identifier.Type) { 
                case SubjectIdentifierType.IssuerAndSerialNumber:
                    filters = certificates.Find(X509FindType.FindByIssuerDistinguishedName, ((X509IssuerSerial) identifier.Value).IssuerName, false); 
                    if (filters.Count > 0) { 
                        filters = filters.Find(X509FindType.FindBySerialNumber, ((X509IssuerSerial) identifier.Value).SerialNumber, false);
                        if (filters.Count > 0) 
                            certificate = filters[0];
                    }
                    break;
                case SubjectIdentifierType.SubjectKeyIdentifier: 
                    filters = certificates.Find(X509FindType.FindBySubjectKeyIdentifier, identifier.Value, false);
                    if (filters.Count > 0) 
                        certificate = filters[0]; 

                    break; 
                }
            }

            return certificate; 
        }
 
        private static void checkErr (int err) { 
            if (CAPI.CRYPT_E_INVALID_MSG_TYPE != err)
                throw new CryptographicException(err); 
        }

        // for Key ID signing only
        [SecuritySafeCritical] 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        internal static unsafe X509Certificate2 CreateDummyCertificate (CspParameters parameters) { 
            SafeCertContextHandle handle = SafeCertContextHandle.InvalidHandle;
 
            // hProv
            SafeCryptProvHandle hProv = SafeCryptProvHandle.InvalidHandle;
            UInt32 dwFlags = 0;
            if (0 != (parameters.Flags & CspProviderFlags.UseMachineKeyStore)) 
            {
                dwFlags |= CAPI.CRYPT_MACHINE_KEYSET; 
            } 
            if (0 != (parameters.Flags & CspProviderFlags.UseDefaultKeyContainer))
            { 
                dwFlags |= CAPI.CRYPT_VERIFYCONTEXT;
            }
            if (0 != (parameters.Flags & CspProviderFlags.NoPrompt))
            { 
                dwFlags |= CAPI.CRYPT_SILENT;
            } 
            bool rc = CAPI.CryptAcquireContext(ref hProv, 
                                               parameters.KeyContainerName,
                                               parameters.ProviderName, 
                                               (uint)parameters.ProviderType,
                                               dwFlags);
            if (!rc)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            // pKeyProvInfo 
            CAPI.CRYPT_KEY_PROV_INFO KeyProvInfo = new CAPI.CRYPT_KEY_PROV_INFO(); 
            KeyProvInfo.pwszProvName       = parameters.ProviderName;
            KeyProvInfo.pwszContainerName  = parameters.KeyContainerName; 
            KeyProvInfo.dwProvType         = (uint)parameters.ProviderType;
            KeyProvInfo.dwKeySpec          = (uint)parameters.KeyNumber ;
            KeyProvInfo.dwFlags            = (uint)((parameters.Flags & CspProviderFlags.UseMachineKeyStore) == CspProviderFlags.UseMachineKeyStore ? CAPI.CRYPT_MACHINE_KEYSET : 0);
 
            SafeLocalAllocHandle pKeyProvInfo = CAPI.LocalAlloc(CAPI.LPTR,
                                                                new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPT_KEY_PROV_INFO)))); 
            Marshal.StructureToPtr(KeyProvInfo, pKeyProvInfo.DangerousGetHandle(), false); 

            // Signature 
            CAPI.CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm = new CAPI.CRYPT_ALGORITHM_IDENTIFIER();
            SignatureAlgorithm.pszObjId = CAPI.szOID_OIWSEC_sha1RSASign;

            SafeLocalAllocHandle pSignatureAlgorithm = CAPI.LocalAlloc(CAPI.LPTR, 
                                                                new IntPtr( Marshal.SizeOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER))));
            Marshal.StructureToPtr(SignatureAlgorithm, pSignatureAlgorithm.DangerousGetHandle(), false); 
 
            // pSubjectIssuerBlob
            X500DistinguishedName subjectName = new X500DistinguishedName("cn=CMS Signer Dummy Certificate"); 
            fixed (byte * pbOctets = subjectName.RawData) {
                CAPI.CRYPTOAPI_BLOB SubjectIssuerBlob = new CAPI.CRYPTOAPI_BLOB();
                SubjectIssuerBlob.cbData = (uint)subjectName.RawData.Length;
                SubjectIssuerBlob.pbData = new IntPtr(pbOctets); 

                handle = CAPI.CAPIUnsafe.CertCreateSelfSignCertificate(hProv, 
                                                                       new IntPtr(&SubjectIssuerBlob), 
                                                                       1,
                                                                       pKeyProvInfo.DangerousGetHandle(), 
                                                                       pSignatureAlgorithm.DangerousGetHandle(),
                                                                       IntPtr.Zero,  //StartTime
                                                                       IntPtr.Zero,  //EndTime
                                                                       IntPtr.Zero); //Extensions 
            }
 
            Marshal.DestroyStructure(pKeyProvInfo.DangerousGetHandle(), typeof(CAPI.CRYPT_KEY_PROV_INFO)); 
            pKeyProvInfo.Dispose();
            Marshal.DestroyStructure(pSignatureAlgorithm.DangerousGetHandle(), typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER)); 
            pSignatureAlgorithm.Dispose();

            if (handle == null || handle.IsInvalid)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            X509Certificate2 certificate = new X509Certificate2(handle.DangerousGetHandle()); 
            handle.Dispose(); 
            return certificate;
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK