private unsafe static Cryptography.SafeCertStoreHandle FindCertInStore(Cryptography.SafeCertStoreHandle safeSourceStoreHandle, X509FindType findType, Object findValue, bool validOnly) {
            if (findValue == null)
                throw new ArgumentNullException("findValue");

            IntPtr pvFindPara = IntPtr.Zero;
            object pvCallbackData1 = null;
            object pvCallbackData2 = null;
            FindProcDelegate pfnCertCallback1 = null;
            FindProcDelegate pfnCertCallback2 = null;
            uint dwFindType = CAPI.CERT_FIND_ANY;
            string subject, issuer;

            CAPI.CRYPTOAPI_BLOB HashBlob = new CAPI.CRYPTOAPI_BLOB();
            SafeLocalAllocHandle pb = SafeLocalAllocHandle.InvalidHandle;
            _FILETIME ft = new _FILETIME();
            string oidValue = null;

            switch(findType) {
            case X509FindType.FindByThumbprint:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                byte[] hex = X509Utils.DecodeHexString((string) findValue);
                pb = X509Utils.ByteToPtr(hex);
                HashBlob.pbData = pb.DangerousGetHandle(); 
                HashBlob.cbData = (uint) hex.Length;
                dwFindType = CAPI.CERT_FIND_HASH;
                pvFindPara = new IntPtr(&HashBlob);
                break;

            case X509FindType.FindBySubjectName:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                subject = (string) findValue;
                dwFindType = CAPI.CERT_FIND_SUBJECT_STR;
                pb = X509Utils.StringToUniPtr(subject);
                pvFindPara = pb.DangerousGetHandle();
                break;

            case X509FindType.FindBySubjectDistinguishedName:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                subject = (string) findValue;
                pfnCertCallback1 = new FindProcDelegate(FindSubjectDistinguishedNameCallback);
                pvCallbackData1 = subject;
                break;

            case X509FindType.FindByIssuerName:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                issuer = (string) findValue;
                dwFindType = CAPI.CERT_FIND_ISSUER_STR;
                pb = X509Utils.StringToUniPtr(issuer);
                pvFindPara = pb.DangerousGetHandle();
                break;

            case X509FindType.FindByIssuerDistinguishedName:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                issuer = (string) findValue;
                pfnCertCallback1 = new FindProcDelegate(FindIssuerDistinguishedNameCallback);
                pvCallbackData1 = issuer;
                break;

            case X509FindType.FindBySerialNumber:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                pfnCertCallback1 = new FindProcDelegate(FindSerialNumberCallback);
                pfnCertCallback2 = new FindProcDelegate(FindSerialNumberCallback);
                BigInt h = new BigInt();
                h.FromHexadecimal((string) findValue);
                pvCallbackData1 = (byte[]) h.ToByteArray();
                h.FromDecimal((string) findValue);
                pvCallbackData2 = (byte[]) h.ToByteArray();
                break;

            case X509FindType.FindByTimeValid:
                if (findValue.GetType() != typeof(DateTime))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                *((long*) &ft) = ((DateTime) findValue).ToFileTime();
                pfnCertCallback1 = new FindProcDelegate(FindTimeValidCallback);
                pvCallbackData1 = ft; 
                break;

            case X509FindType.FindByTimeNotYetValid:
                if (findValue.GetType() != typeof(DateTime))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                *((long*) &ft) = ((DateTime) findValue).ToFileTime();
                pfnCertCallback1 = new FindProcDelegate(FindTimeNotBeforeCallback);
                pvCallbackData1 = ft; 
                break;

            case X509FindType.FindByTimeExpired:
                if (findValue.GetType() != typeof(DateTime))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                *((long*) &ft) = ((DateTime) findValue).ToFileTime();
                pfnCertCallback1 = new FindProcDelegate(FindTimeNotAfterCallback);
                pvCallbackData1 = ft; 
                break;

            case X509FindType.FindByTemplateName:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                pvCallbackData1 = (string) findValue; 
                pfnCertCallback1 = new FindProcDelegate(FindTemplateNameCallback);
                break;

            case X509FindType.FindByApplicationPolicy:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                // If we were passed the friendly name, retrieve the value string.
                oidValue = X509Utils.FindOidInfoWithFallback(CAPI.CRYPT_OID_INFO_NAME_KEY, (string) findValue, Cryptography.OidGroup.Policy);
                if (oidValue == null) {
                    oidValue = (string) findValue;
                    X509Utils.ValidateOidValue(oidValue);
                }
                pvCallbackData1 = oidValue;
                pfnCertCallback1 = new FindProcDelegate(FindApplicationPolicyCallback);
                break;

            case X509FindType.FindByCertificatePolicy:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                // If we were passed the friendly name, retrieve the value string.
                oidValue = X509Utils.FindOidInfoWithFallback(CAPI.CRYPT_OID_INFO_NAME_KEY, (string)findValue, Cryptography.OidGroup.Policy);
                if (oidValue == null) {
                    oidValue = (string) findValue;
                    X509Utils.ValidateOidValue(oidValue);
                }
                pvCallbackData1 = oidValue;
                pfnCertCallback1 = new FindProcDelegate(FindCertificatePolicyCallback);
                break;

            case X509FindType.FindByExtension:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                // If we were passed the friendly name, retrieve the value string.
                oidValue = X509Utils.FindOidInfoWithFallback(CAPI.CRYPT_OID_INFO_NAME_KEY, (string)findValue, Cryptography.OidGroup.ExtensionOrAttribute);
                if (oidValue == null) {
                    oidValue = (string) findValue;
                    X509Utils.ValidateOidValue(oidValue);
                }
                pvCallbackData1 = oidValue;
                pfnCertCallback1 = new FindProcDelegate(FindExtensionCallback);
                break;

            case X509FindType.FindByKeyUsage:
                // The findValue object can be either a friendly name, a X509KeyUsageFlags enum or an integer.
                if (findValue.GetType() == typeof(string)) {
                    CAPI.KEY_USAGE_STRUCT[] KeyUsages = new CAPI.KEY_USAGE_STRUCT[] { 
                        new CAPI.KEY_USAGE_STRUCT("DigitalSignature", CAPI.CERT_DIGITAL_SIGNATURE_KEY_USAGE),
                        new CAPI.KEY_USAGE_STRUCT("NonRepudiation",   CAPI.CERT_NON_REPUDIATION_KEY_USAGE),
                        new CAPI.KEY_USAGE_STRUCT("KeyEncipherment",  CAPI.CERT_KEY_ENCIPHERMENT_KEY_USAGE),
                        new CAPI.KEY_USAGE_STRUCT("DataEncipherment", CAPI.CERT_DATA_ENCIPHERMENT_KEY_USAGE),
                        new CAPI.KEY_USAGE_STRUCT("KeyAgreement",     CAPI.CERT_KEY_AGREEMENT_KEY_USAGE),
                        new CAPI.KEY_USAGE_STRUCT("KeyCertSign",      CAPI.CERT_KEY_CERT_SIGN_KEY_USAGE),
                        new CAPI.KEY_USAGE_STRUCT("CrlSign",          CAPI.CERT_CRL_SIGN_KEY_USAGE),
                        new CAPI.KEY_USAGE_STRUCT("EncipherOnly",     CAPI.CERT_ENCIPHER_ONLY_KEY_USAGE),
                        new CAPI.KEY_USAGE_STRUCT("DecipherOnly",     CAPI.CERT_DECIPHER_ONLY_KEY_USAGE)
                    };

                    for (uint index = 0; index < KeyUsages.Length; index++) {
                        if (String.Compare(KeyUsages[index].pwszKeyUsage, (string) findValue, StringComparison.OrdinalIgnoreCase) == 0) {
                            pvCallbackData1 = KeyUsages[index].dwKeyUsageBit;
                            break;
                        }
                    }
                    if (pvCallbackData1 == null)
                        throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindType));
                } else if (findValue.GetType() == typeof(X509KeyUsageFlags)) {
                    pvCallbackData1 = findValue;
                } else if (findValue.GetType() == typeof(uint) || findValue.GetType() == typeof(int)) {
                    // We got the actual DWORD
                    pvCallbackData1 = findValue;
                } else 
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindType));

                pfnCertCallback1 = new FindProcDelegate(FindKeyUsageCallback);
                break;

            case X509FindType.FindBySubjectKeyIdentifier:
                if (findValue.GetType() != typeof(string))
                    throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
                pvCallbackData1 = (byte[]) X509Utils.DecodeHexString((string) findValue);
                pfnCertCallback1 = new FindProcDelegate(FindSubjectKeyIdentifierCallback);
                break;

            default:
                throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindType));
            }

            // First, create a memory store
            Cryptography.SafeCertStoreHandle safeTargetStoreHandle = CAPI.CertOpenStore(new IntPtr(CAPI.CERT_STORE_PROV_MEMORY), 
                                                                           CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                                           IntPtr.Zero, 
                                                                           CAPI.CERT_STORE_ENUM_ARCHIVED_FLAG | CAPI.CERT_STORE_CREATE_NEW_FLAG, 
                                                                           null);
            if (safeTargetStoreHandle == null || safeTargetStoreHandle.IsInvalid)
                throw new CryptographicException(Marshal.GetLastWin32Error());

            // FindByCert will throw an exception in case of failures.
            FindByCert(safeSourceStoreHandle, 
                       dwFindType,
                       pvFindPara, 
                       validOnly, 
                       pfnCertCallback1,
                       pfnCertCallback2, 
                       pvCallbackData1,
                       pvCallbackData2, 
                       safeTargetStoreHandle);

            pb.Dispose();
            return safeTargetStoreHandle;
        }
Exemple #2
0
        SafeCertStoreHandle PFXImportCertStore(
            [In]     uint      dwObjectType,
            [In]     object    pvObject,
            [In]     string    szPassword,
            [In]     uint      dwFlags,
            [In]     bool      persistKeyContainers) {

            if (pvObject == null)
                throw new ArgumentNullException("pvObject");

            byte[] pbData = null;
            if (dwObjectType == CERT_QUERY_OBJECT_FILE) {
                pbData = File.ReadAllBytes((string)pvObject);
            } else {
                pbData = (byte[]) pvObject;
            }

#if !FEATURE_CORESYSTEM
            if (persistKeyContainers) {
                //
                // Right now, we always demand KeyContainerPermission regardless of whether the PFX contains a private key or not.
                // We could avoid that by looping through the certs in the store and find out whether there are actually private keys.
                //
                if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
                    KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.Create);
                    kp.Demand();
                }
            }
#endif

            SafeCertStoreHandle safeCertStoreHandle = SafeCertStoreHandle.InvalidHandle;
            GCHandle handle = GCHandle.Alloc(pbData, GCHandleType.Pinned);
            IntPtr ptr = handle.AddrOfPinnedObject();

            try {
                CRYPTOAPI_BLOB certBlob;
                certBlob.cbData = (uint) pbData.Length;
                certBlob.pbData = ptr;

                safeCertStoreHandle = CAPIMethods.PFXImportCertStore(new IntPtr(&certBlob),
                                                                     szPassword,
                                                                     dwFlags);
            }

            finally {
                if (handle.IsAllocated)
                   handle.Free();
            }

            if (!safeCertStoreHandle.IsInvalid) {
                //
                // If the user did not want us to persist private keys, then we should loop through all
                // the certificates in the collection and set our custom CERT_DELETE_KEYSET_PROP_ID property
                // so the key container will be deleted when the cert contexts will go away.
                //

                if (persistKeyContainers == false) {
                    IntPtr pEnumContext = CAPI.CertEnumCertificatesInStore(safeCertStoreHandle, IntPtr.Zero);
                    while (pEnumContext != IntPtr.Zero) {
                        CAPI.CRYPTOAPI_BLOB blob = new CAPI.CRYPTOAPI_BLOB();
                        if (!CAPI.CertSetCertificateContextProperty(pEnumContext,
                                                                    CERT_DELETE_KEYSET_PROP_ID,
                                                                    CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG, // we don't want this property to be persisted.
                                                                    new IntPtr(&blob)))
                            throw new CryptographicException(Marshal.GetLastWin32Error());
                        pEnumContext = CAPI.CertEnumCertificatesInStore(safeCertStoreHandle, pEnumContext);
                    }
                }
            }

            return safeCertStoreHandle;
        }
        private unsafe static byte[] ExportCertificatesToBlob(Cryptography.SafeCertStoreHandle safeCertStoreHandle, X509ContentType contentType, string password) {
            Cryptography.SafeCertContextHandle safeCertContextHandle = Cryptography.SafeCertContextHandle.InvalidHandle;
            uint dwSaveAs = CAPI.CERT_STORE_SAVE_AS_PKCS7;
            byte[] pbBlob = null;
            CAPI.CRYPTOAPI_BLOB DataBlob = new CAPI.CRYPTOAPI_BLOB();
            SafeLocalAllocHandle pbEncoded = SafeLocalAllocHandle.InvalidHandle;

            switch(contentType) {
            case X509ContentType.Cert:
                safeCertContextHandle = CAPI.CertEnumCertificatesInStore(safeCertStoreHandle, safeCertContextHandle);
                if (safeCertContextHandle != null && !safeCertContextHandle.IsInvalid) {
                    CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
                    pbBlob = new byte[pCertContext.cbCertEncoded];
                    Marshal.Copy(pCertContext.pbCertEncoded, pbBlob, 0, pbBlob.Length);
                }
                break;

            case X509ContentType.SerializedCert:
                safeCertContextHandle = CAPI.CertEnumCertificatesInStore(safeCertStoreHandle, safeCertContextHandle);
                uint cbEncoded = 0;
                if (safeCertContextHandle != null && !safeCertContextHandle.IsInvalid) {
                    if (!CAPI.CertSerializeCertificateStoreElement(safeCertContextHandle, 
                                                                   0, 
                                                                   pbEncoded, 
                                                                   new IntPtr(&cbEncoded))) 
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    pbEncoded = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbEncoded));
                    if (!CAPI.CertSerializeCertificateStoreElement(safeCertContextHandle, 
                                                                   0, 
                                                                   pbEncoded, 
                                                                   new IntPtr(&cbEncoded)))
                        throw new CryptographicException(Marshal.GetLastWin32Error());

                    pbBlob = new byte[cbEncoded];
                    Marshal.Copy(pbEncoded.DangerousGetHandle(), pbBlob, 0, pbBlob.Length);
                }
                break;

            case X509ContentType.Pkcs12:
                if (!CAPI.PFXExportCertStore(safeCertStoreHandle, 
                                             new IntPtr(&DataBlob), 
                                             password, 
                                             CAPI.EXPORT_PRIVATE_KEYS | CAPI.REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY))
                    throw new CryptographicException(Marshal.GetLastWin32Error());

                pbEncoded = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(DataBlob.cbData));
                DataBlob.pbData = pbEncoded.DangerousGetHandle();
                if (!CAPI.PFXExportCertStore(safeCertStoreHandle, 
                                             new IntPtr(&DataBlob),
                                             password, 
                                             CAPI.EXPORT_PRIVATE_KEYS | CAPI.REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY))
                    throw new CryptographicException(Marshal.GetLastWin32Error());

                pbBlob = new byte[DataBlob.cbData];
                Marshal.Copy(DataBlob.pbData, pbBlob, 0, pbBlob.Length);
                break;

            case X509ContentType.SerializedStore:
                // falling through
            case X509ContentType.Pkcs7:
                if (contentType == X509ContentType.SerializedStore)
                    dwSaveAs = CAPI.CERT_STORE_SAVE_AS_STORE;

                // determine the required length
                if (!CAPI.CertSaveStore(safeCertStoreHandle, 
                                        CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                        dwSaveAs, 
                                        CAPI.CERT_STORE_SAVE_TO_MEMORY, 
                                        new IntPtr(&DataBlob), 
                                        0)) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());

                pbEncoded = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(DataBlob.cbData));
                DataBlob.pbData = pbEncoded.DangerousGetHandle();
                // now save the store to a memory blob
                if (!CAPI.CertSaveStore(safeCertStoreHandle, 
                                        CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                        dwSaveAs, 
                                        CAPI.CERT_STORE_SAVE_TO_MEMORY, 
                                        new IntPtr(&DataBlob), 
                                        0)) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());

                pbBlob = new byte[DataBlob.cbData];
                Marshal.Copy(DataBlob.pbData, pbBlob, 0, pbBlob.Length);
                break;

            default:
                throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidContentType));
            }

            pbEncoded.Dispose();
            safeCertContextHandle.Dispose();

            return pbBlob;
        }
        private static unsafe void SetFriendlyNameExtendedProperty (SafeCertContextHandle safeCertContextHandle, string name) {
            SafeLocalAllocHandle ptr = X509Utils.StringToUniPtr(name);
            using (ptr) {
                CAPI.CRYPTOAPI_BLOB DataBlob = new CAPI.CRYPTOAPI_BLOB();
                DataBlob.cbData = 2 * ((uint) name.Length + 1);
                DataBlob.pbData = ptr.DangerousGetHandle();

                if (!CAPI.CertSetCertificateContextProperty(safeCertContextHandle,
                                                            CAPI.CERT_FRIENDLY_NAME_PROP_ID,
                                                            0,
                                                            new IntPtr(&DataBlob)))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            }
        }
        private static unsafe byte[] EncodeExtension (byte[] subjectKeyIdentifier) {
            if (subjectKeyIdentifier == null)
                throw new ArgumentNullException("subjectKeyIdentifier");
            if (subjectKeyIdentifier.Length == 0)
                throw new ArgumentException("subjectKeyIdentifier");

            byte[] encodedSubjectKeyIdentifier = null;
            fixed (byte* pb = subjectKeyIdentifier) {
                CAPI.CRYPTOAPI_BLOB pSubjectKeyIdentifier = new CAPI.CRYPTOAPI_BLOB();
                pSubjectKeyIdentifier.pbData = new IntPtr(pb);
                pSubjectKeyIdentifier.cbData = (uint) subjectKeyIdentifier.Length;

                if (!CAPI.EncodeObject(CAPI.szOID_SUBJECT_KEY_IDENTIFIER, new IntPtr(&pSubjectKeyIdentifier), out encodedSubjectKeyIdentifier))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            return encodedSubjectKeyIdentifier;
        }
        public static byte[] Unprotect (byte[] encryptedData,
                                        byte[] optionalEntropy,
                                        DataProtectionScope scope) {
            if (encryptedData == null)
                throw new ArgumentNullException("encryptedData");
            if (Environment.OSVersion.Platform == PlatformID.Win32Windows)
                throw new NotSupportedException(SecurityResources.GetResourceString("NotSupported_PlatformRequiresNT"));

            GCHandle pbDataIn = new GCHandle();
            GCHandle pOptionalEntropy = new GCHandle();
            CAPI.CRYPTOAPI_BLOB userData = new CAPI.CRYPTOAPI_BLOB();

            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                pbDataIn = GCHandle.Alloc(encryptedData, GCHandleType.Pinned);
                CAPI.CRYPTOAPI_BLOB dataIn = new CAPI.CRYPTOAPI_BLOB();
                dataIn.cbData = (uint) encryptedData.Length;
                dataIn.pbData = pbDataIn.AddrOfPinnedObject();
                CAPI.CRYPTOAPI_BLOB entropy = new CAPI.CRYPTOAPI_BLOB();
                if (optionalEntropy != null) {
                    pOptionalEntropy = GCHandle.Alloc(optionalEntropy, GCHandleType.Pinned);
                    entropy.cbData = (uint) optionalEntropy.Length;
                    entropy.pbData = pOptionalEntropy.AddrOfPinnedObject();
                }
                uint dwFlags = CAPI.CRYPTPROTECT_UI_FORBIDDEN;
                if (scope == DataProtectionScope.LocalMachine)
                    dwFlags |= CAPI.CRYPTPROTECT_LOCAL_MACHINE;
                unsafe {
                    if (!CAPI.CryptUnprotectData(new IntPtr(&dataIn),
                                                 IntPtr.Zero,
                                                 new IntPtr(&entropy),
                                                 IntPtr.Zero,
                                                 IntPtr.Zero,
                                                 dwFlags,
                                                 new IntPtr(&userData)))
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                }

                // In some cases, the API would fail due to OOM but simply return a null pointer.
                if (userData.pbData == IntPtr.Zero)
                    throw new OutOfMemoryException();

                byte[] data = new byte[(int) userData.cbData];
                Marshal.Copy(userData.pbData, data, 0, data.Length);

                return data;
            }
            catch (EntryPointNotFoundException) {
                throw new NotSupportedException(SecurityResources.GetResourceString("NotSupported_PlatformRequiresNT"));
            }
            finally {
                if (pbDataIn.IsAllocated)
                   pbDataIn.Free();
                if (pOptionalEntropy.IsAllocated)
                   pOptionalEntropy.Free();
                if (userData.pbData != IntPtr.Zero) {
                    CAPI.CAPISafe.ZeroMemory(userData.pbData, userData.cbData);
                    CAPI.CAPISafe.LocalFree(userData.pbData);
                }
            }
        }
        public static byte[] Protect (byte[] userData,
                                      byte[] optionalEntropy,
                                      DataProtectionScope scope) {
            if (userData == null)
                throw new ArgumentNullException("userData");
            if (Environment.OSVersion.Platform == PlatformID.Win32Windows)
                throw new NotSupportedException(SecurityResources.GetResourceString("NotSupported_PlatformRequiresNT"));

            GCHandle pbDataIn = new GCHandle();
            GCHandle pOptionalEntropy = new GCHandle();
            CAPI.CRYPTOAPI_BLOB blob = new CAPI.CRYPTOAPI_BLOB();

            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                pbDataIn = GCHandle.Alloc(userData, GCHandleType.Pinned);
                CAPI.CRYPTOAPI_BLOB dataIn = new CAPI.CRYPTOAPI_BLOB();
                dataIn.cbData = (uint) userData.Length;
                dataIn.pbData = pbDataIn.AddrOfPinnedObject();
                CAPI.CRYPTOAPI_BLOB entropy = new CAPI.CRYPTOAPI_BLOB();
                if (optionalEntropy != null) {
                    pOptionalEntropy = GCHandle.Alloc(optionalEntropy, GCHandleType.Pinned);
                    entropy.cbData = (uint) optionalEntropy.Length;
                    entropy.pbData = pOptionalEntropy.AddrOfPinnedObject();
                }
                uint dwFlags = CAPI.CRYPTPROTECT_UI_FORBIDDEN;
                if (scope == DataProtectionScope.LocalMachine)
                    dwFlags |= CAPI.CRYPTPROTECT_LOCAL_MACHINE;
                unsafe {
                    if (!CAPI.CryptProtectData(new IntPtr(&dataIn),
                                               String.Empty,
                                               new IntPtr(&entropy),
                                               IntPtr.Zero,
                                               IntPtr.Zero,
                                               dwFlags,
                                               new IntPtr(&blob))) {
                        int lastWin32Error = Marshal.GetLastWin32Error();

                        // One of the most common reasons that DPAPI operations fail is that the user
                        // profile is not loaded (for instance in the case of impersonation or running in a
                        // service.  In those cases, throw an exception that provides more specific details
                        // about what happened.
                        if (CAPI.ErrorMayBeCausedByUnloadedProfile(lastWin32Error)) {
                            throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_DpApi_ProfileMayNotBeLoaded"));
                        }
                        else {
                            throw new CryptographicException(lastWin32Error);
                        }
                    }
                }

                // In some cases, the API would fail due to OOM but simply return a null pointer.
                if (blob.pbData == IntPtr.Zero)
                    throw new OutOfMemoryException();

                byte[] encryptedData = new byte[(int) blob.cbData];
                Marshal.Copy(blob.pbData, encryptedData, 0, encryptedData.Length);

                return encryptedData;
            }
            catch (EntryPointNotFoundException) {
                throw new NotSupportedException(SecurityResources.GetResourceString("NotSupported_PlatformRequiresNT"));
            }
            finally {
                if (pbDataIn.IsAllocated)
                   pbDataIn.Free();
                if (pOptionalEntropy.IsAllocated)
                   pOptionalEntropy.Free();
                if (blob.pbData != IntPtr.Zero) {
                    CAPI.CAPISafe.ZeroMemory(blob.pbData, blob.cbData);
                    CAPI.CAPISafe.LocalFree(blob.pbData);
                }
            }
        }
Exemple #8
0
        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;
        }
Exemple #9
0
        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;
        }
Exemple #10
0
        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;
            }
        }
Exemple #11
0
        private unsafe void EncryptContent (CmsRecipientCollection recipients) {
            CMSG_ENCRYPT_PARAM encryptParam = new CMSG_ENCRYPT_PARAM();

            if (recipients.Count < 1)
                throw new CryptographicException(CAPI.CRYPT_E_RECIPIENT_NOT_FOUND);

            foreach (CmsRecipient recipient in recipients) {
                if (recipient.Certificate == null)
                    throw new ArgumentNullException(SecurityResources.GetResourceString("Cryptography_Cms_RecipientCertificateNotFound"));

                if ((PkcsUtils.GetRecipientInfoType(recipient.Certificate) == RecipientInfoType.KeyAgreement) ||
                    (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier))
                    encryptParam.useCms = true;
            }

            if (!encryptParam.useCms) {
                if (this.Certificates.Count > 0 || this.UnprotectedAttributes.Count > 0) {
                    encryptParam.useCms = true;
                }
            }

            if (encryptParam.useCms && !PkcsUtils.CmsSupported()) {
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Not_Supported"));
            }

            CAPI.CMSG_ENVELOPED_ENCODE_INFO encodeInfo = new CAPI.CMSG_ENVELOPED_ENCODE_INFO(Marshal.SizeOf(typeof(CAPI.CMSG_ENVELOPED_ENCODE_INFO)));
            SafeLocalAllocHandle ceei = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_ENVELOPED_ENCODE_INFO))));

            SetCspParams(this.ContentEncryptionAlgorithm, ref encryptParam);
            encodeInfo.ContentEncryptionAlgorithm.pszObjId = this.ContentEncryptionAlgorithm.Oid.Value;
            //encodeInfo.hCryptProv = encryptParam.safeCryptProvHandle.DangerousGetHandle(); 
            if (encryptParam.pvEncryptionAuxInfo != null && !encryptParam.pvEncryptionAuxInfo.IsInvalid) {
                encodeInfo.pvEncryptionAuxInfo = encryptParam.pvEncryptionAuxInfo.DangerousGetHandle();
            }

            encodeInfo.cRecipients = (uint) recipients.Count;

            List<SafeCertContextHandle> certContexts = null;
            if (encryptParam.useCms) {
                SetCmsRecipientParams(recipients, this.Certificates, this.UnprotectedAttributes, this.ContentEncryptionAlgorithm, ref encryptParam);
                encodeInfo.rgCmsRecipients = encryptParam.rgpRecipients.DangerousGetHandle();
                if (encryptParam.rgCertEncoded != null && !encryptParam.rgCertEncoded.IsInvalid) {
                    encodeInfo.cCertEncoded = (uint) this.Certificates.Count;
                    encodeInfo.rgCertEncoded = encryptParam.rgCertEncoded.DangerousGetHandle();
                }
                if (encryptParam.rgUnprotectedAttr != null && !encryptParam.rgUnprotectedAttr.IsInvalid) {
                    encodeInfo.cUnprotectedAttr = (uint) this.UnprotectedAttributes.Count;
                    encodeInfo.rgUnprotectedAttr = encryptParam.rgUnprotectedAttr.DangerousGetHandle();
                }
            }
            else {
                SetPkcs7RecipientParams(recipients, ref encryptParam, out certContexts);
                encodeInfo.rgpRecipients = encryptParam.rgpRecipients.DangerousGetHandle();
            }

            Marshal.StructureToPtr(encodeInfo, ceei.DangerousGetHandle(), false);

            try {
                SafeCryptMsgHandle safeCryptMsgHandle = CAPI.CryptMsgOpenToEncode(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                                  0,
                                                                                  CAPI.CMSG_ENVELOPED,
                                                                                  ceei.DangerousGetHandle(),
                                                                                  this.ContentInfo.ContentType.Value,
                                                                                  IntPtr.Zero);
                if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid)
                    throw new CryptographicException(Marshal.GetLastWin32Error());

                if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) {
                    m_safeCryptMsgHandle.Dispose();
                }

                m_safeCryptMsgHandle = safeCryptMsgHandle;
            }
            finally {
                Marshal.DestroyStructure(ceei.DangerousGetHandle(), typeof(CAPI.CMSG_ENVELOPED_ENCODE_INFO));
                ceei.Dispose();
            }

            byte[] encodedContent = new byte[0];
            if (String.Compare(this.ContentInfo.ContentType.Value, CAPI.szOID_RSA_data, StringComparison.OrdinalIgnoreCase) == 0) {
                byte[] content = this.ContentInfo.Content;
                fixed (byte * pbContent = content) {
                    CAPI.CRYPTOAPI_BLOB dataBlob = new CAPI.CRYPTOAPI_BLOB();
                    dataBlob.cbData = (uint) content.Length;
                    dataBlob.pbData = new IntPtr(pbContent);
                    if (!CAPI.EncodeObject(new IntPtr(CAPI.X509_OCTET_STRING), new IntPtr(&dataBlob), out encodedContent))
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                }
            }
            else {
                encodedContent = this.ContentInfo.Content;
            }
            if (encodedContent.Length > 0) {
                if (!CAPI.CAPISafe.CryptMsgUpdate(m_safeCryptMsgHandle, encodedContent, (uint) encodedContent.Length, true))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            // Keep alive
            GC.KeepAlive(encryptParam);
            GC.KeepAlive(recipients);
            GC.KeepAlive(certContexts);
        }
        public X509Certificate2Collection Find(X509FindType findType, object findValue, bool validOnly)
        {
            DiagnosticUtility.DebugAssert(!this.certStoreHandle.IsInvalid, "");

            uint dwFindType;
            SafeHGlobalHandle pvFindPara = SafeHGlobalHandle.InvalidHandle;
            SafeCertContextHandle pCertContext = SafeCertContextHandle.InvalidHandle;
            X509Certificate2Collection result = new X509Certificate2Collection();
            SafeHGlobalHandle pvTemp = SafeHGlobalHandle.InvalidHandle;
            string strFindValue;
            byte[] bytes;

            try
            {
                switch (findType)
                {
                    case X509FindType.FindBySubjectName:
                        strFindValue = findValue as string;
                        if (strFindValue == null)
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.X509FindValueMismatch, findType, typeof(string), findValue.GetType())));

                        dwFindType = CAPI.CERT_FIND_SUBJECT_STR;
                        pvFindPara = SafeHGlobalHandle.AllocHGlobal(strFindValue);
                        break;

                    case X509FindType.FindByThumbprint:
                        bytes = findValue as byte[];
                        if (bytes == null)
                        {
                            strFindValue = findValue as string;
                            if (strFindValue == null)
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.X509FindValueMismatchMulti, findType, typeof(string), typeof(byte[]), findValue.GetType())));

                            bytes = SecurityUtils.DecodeHexString(strFindValue);
                        }

                        CAPI.CRYPTOAPI_BLOB blob = new CAPI.CRYPTOAPI_BLOB();
                        pvTemp = SafeHGlobalHandle.AllocHGlobal(bytes);
                        blob.pbData = pvTemp.DangerousGetHandle();
                        blob.cbData = (uint)bytes.Length;
                        dwFindType = CAPI.CERT_FIND_HASH;
                        pvFindPara = SafeHGlobalHandle.AllocHGlobal(CAPI.CRYPTOAPI_BLOB.Size);
                        Marshal.StructureToPtr(blob, pvFindPara.DangerousGetHandle(), false);
                        break;

                    case X509FindType.FindBySubjectDistinguishedName:
                        if (!(findValue is string))
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.X509FindValueMismatch, findType, typeof(string), findValue.GetType())));

                        dwFindType = CAPI.CERT_FIND_ANY;
                        break;

                    case X509FindType.FindByIssuerName:
                        strFindValue = findValue as string;
                        if (strFindValue == null)
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.X509FindValueMismatch, findType, typeof(string), findValue.GetType())));

                        dwFindType = CAPI.CERT_FIND_ISSUER_STR;
                        pvFindPara = SafeHGlobalHandle.AllocHGlobal(strFindValue);
                        break;

                    case X509FindType.FindByIssuerDistinguishedName:
                        if (!(findValue is string))
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.X509FindValueMismatch, findType, typeof(string), findValue.GetType())));

                        dwFindType = CAPI.CERT_FIND_ANY;
                        break;

                    case X509FindType.FindBySerialNumber:
                        bytes = findValue as byte[];
                        if (bytes == null)
                        {
                            strFindValue = findValue as string;
                            if (strFindValue == null)
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.X509FindValueMismatchMulti, findType, typeof(string), typeof(byte[]), findValue.GetType())));

                            bytes = SecurityUtils.DecodeHexString(strFindValue);

                            // reverse bits
                            int len = bytes.Length;
                            for (int i = 0, j = len - 1; i < bytes.Length / 2; ++i, --j)
                            {
                                byte tmp = bytes[i];
                                bytes[i] = bytes[j];
                                bytes[j] = tmp;
                            }
                        }
                        findValue = bytes;
                        dwFindType = CAPI.CERT_FIND_ANY;
                        break;

                    case X509FindType.FindBySubjectKeyIdentifier:
                        bytes = findValue as byte[];
                        if (bytes == null)
                        {
                            strFindValue = findValue as string;
                            if (strFindValue == null)
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.X509FindValueMismatchMulti, findType, typeof(string), typeof(byte[]), findValue.GetType())));

                            bytes = SecurityUtils.DecodeHexString(strFindValue);

                        }
                        findValue = bytes;
                        dwFindType = CAPI.CERT_FIND_ANY;
                        break;

                    default:
                        // Fallback to CLR implementation
                        X509Store store = new X509Store(this.certStoreHandle.DangerousGetHandle());
                        try
                        {
                            return store.Certificates.Find(findType, findValue, validOnly);
                        }
                        finally
                        {
                            store.Close();
                        }
                }

#pragma warning suppress 56523 // We are not interested in CRYPT_E_NOT_FOUND error, it return null anyway.
                pCertContext = CAPI.CertFindCertificateInStore(this.certStoreHandle,
                                                               CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                               0,
                                                               dwFindType,
                                                               pvFindPara,
                                                               pCertContext);

                while (pCertContext != null && !pCertContext.IsInvalid)
                {
                    X509Certificate2 cert;
                    if (TryGetMatchingX509Certificate(pCertContext.DangerousGetHandle(), findType,
                            dwFindType, findValue, validOnly, out cert))
                    {
                        result.Add(cert);
                    }

                    // CER
                    RuntimeHelpers.PrepareConstrainedRegions();
                    try { }
                    finally
                    {
                        // Suppress the finalizer
#pragma warning suppress 56508 // CertFindCertificateInStore will release the prev one.
                        GC.SuppressFinalize(pCertContext);
#pragma warning suppress 56523 // We are not interested in CRYPT_E_NOT_FOUND error, it return null anyway.
                        pCertContext = CAPI.CertFindCertificateInStore(this.certStoreHandle,
                                                                       CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                       0,
                                                                       dwFindType,
                                                                       pvFindPara,
                                                                       pCertContext);
                    }
                }
            }
            finally
            {
                if (pCertContext != null)
                {
                    pCertContext.Close();
                }
                pvFindPara.Close();
                pvTemp.Close();
            }
            return result;
        }