public void ImportExistingCertificateShouldNotOverwriteExistingPrivateKeyRights(string sampleCertificateId,
                                                                                        StoreLocation storeLocation, string storeName)
        {
            var sampleCertificate = SampleCertificate.SampleCertificates[sampleCertificateId];

            sampleCertificate.EnsureCertificateNotInStore(storeName, storeLocation);

            WindowsX509CertificateStore.ImportCertificateToStore(
                Convert.FromBase64String(sampleCertificate.Base64Bytes()), sampleCertificate.Password,
                storeLocation, storeName, sampleCertificate.HasPrivateKey);

            WindowsX509CertificateStore.AddPrivateKeyAccessRules(sampleCertificate.Thumbprint, storeLocation, storeName,
                                                                 new List <PrivateKeyAccessRule>
            {
                new PrivateKeyAccessRule("BUILTIN\\Users", PrivateKeyAccess.FullControl)
            });

            WindowsX509CertificateStore.ImportCertificateToStore(
                Convert.FromBase64String(sampleCertificate.Base64Bytes()), sampleCertificate.Password,
                storeLocation, storeName, sampleCertificate.HasPrivateKey);

            var privateKeySecurity = WindowsX509CertificateStore.GetPrivateKeySecurity(sampleCertificate.Thumbprint,
                                                                                       storeLocation, storeName);

            AssertHasPrivateKeyRights(privateKeySecurity, "BUILTIN\\Users", CryptoKeyRights.GenericAll);

            sampleCertificate.EnsureCertificateNotInStore(storeName, storeLocation);
        }
        void ImportCertificate(CalamariVariableDictionary variables)
        {
            var certificateVariable  = GetMandatoryVariable(variables, SpecialVariables.Action.Certificate.CertificateVariable);
            var pfxBytes             = Convert.FromBase64String(GetMandatoryVariable(variables, $"{certificateVariable}.{SpecialVariables.Certificate.Properties.Pfx}"));
            var password             = variables.Get($"{certificateVariable}.{SpecialVariables.Certificate.Properties.Password}");
            var thumbprint           = variables.Get($"{certificateVariable}.{SpecialVariables.Certificate.Properties.Thumbprint}");
            var storeName            = GetMandatoryVariable(variables, SpecialVariables.Action.Certificate.StoreName);
            var privateKeyExportable = variables.GetFlag(SpecialVariables.Action.Certificate.PrivateKeyExportable, false);

            // Either a store-location (LocalMachine or CurrentUser) or a user can be supplied
            StoreLocation storeLocation;
            var           locationSpecified = Enum.TryParse(variables.Get(SpecialVariables.Action.Certificate.StoreLocation), out storeLocation);

            ValidateStore(locationSpecified ? (StoreLocation?)storeLocation : null, storeName);

            try
            {
                if (locationSpecified)
                {
                    Log.Info(
                        $"Importing certificate '{variables.Get($"{certificateVariable}.{SpecialVariables.Certificate.Properties.Subject}")}' with thumbprint '{thumbprint}' into store '{storeLocation}\\{storeName}'");
                    WindowsX509CertificateStore.ImportCertificateToStore(pfxBytes, password, storeLocation, storeName,
                                                                         privateKeyExportable);

                    if (storeLocation == StoreLocation.LocalMachine)
                    {
                        // Set private-key access
                        var privateKeyAccessRules = GetPrivateKeyAccessRules(variables);
                        if (privateKeyAccessRules.Any())
                        {
                            WindowsX509CertificateStore.AddPrivateKeyAccessRules(thumbprint, storeLocation, storeName,
                                                                                 privateKeyAccessRules);
                        }
                    }
                }
                else // Import into a specific user's store
                {
                    var storeUser = variables.Get(SpecialVariables.Action.Certificate.StoreUser);

                    if (string.IsNullOrWhiteSpace(storeUser))
                    {
                        throw new CommandException(
                                  $"Either '{SpecialVariables.Action.Certificate.StoreLocation}' or '{SpecialVariables.Action.Certificate.StoreUser}' must be supplied");
                    }

                    Log.Info(
                        $"Importing certificate '{variables.Get($"{certificateVariable}.{SpecialVariables.Certificate.Properties.Subject}")}' with thumbprint '{thumbprint}' into store '{storeName}' for user '{storeUser}'");
                    WindowsX509CertificateStore.ImportCertificateToStore(pfxBytes, password, storeUser, storeName,
                                                                         privateKeyExportable);
                }
            }
            catch (Exception)
            {
                Log.Error("There was an error importing the certificate into the store");
                throw;
            }
        }
示例#3
0
        void RemoveChainCertificatesFromStore(X509Store rootAuthorityStore, X509Store intermediateAuthorityStore, string rootAuthorityThumbprint, string intermediateAuthorityThumbprint)
        {
            WindowsX509CertificateStore.RemoveCertificateFromStore(rootAuthorityThumbprint, StoreLocation.LocalMachine, rootAuthorityStore.Name);

            if (!string.IsNullOrEmpty(intermediateAuthorityThumbprint))
            {
                WindowsX509CertificateStore.RemoveCertificateFromStore(intermediateAuthorityThumbprint, StoreLocation.LocalMachine, intermediateAuthorityStore.Name);
            }
        }
示例#4
0
        private void EnsureCertificateNotInStore(X509Store store)
        {
            var certificates = store.Certificates.Find(X509FindType.FindByThumbprint, Thumbprint, false);

            if (certificates.Count == 0)
            {
                return;
            }

            WindowsX509CertificateStore.RemoveCertificateFromStore(Thumbprint, store.Location, store.Name);
        }
        public void CanImportCertificateForUser()
        {
            // This test cheats a little bit, using the current user
            var user              = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
            var storeName         = "My";
            var sampleCertificate = SampleCertificate.CapiWithPrivateKey;

            sampleCertificate.EnsureCertificateNotInStore(storeName, StoreLocation.CurrentUser);

            WindowsX509CertificateStore.ImportCertificateToStore(Convert.FromBase64String(sampleCertificate.Base64Bytes()), sampleCertificate.Password,
                                                                 user, storeName, sampleCertificate.HasPrivateKey);

            sampleCertificate.AssertCertificateIsInStore(storeName, StoreLocation.CurrentUser);

            sampleCertificate.EnsureCertificateNotInStore(storeName, StoreLocation.CurrentUser);
        }
        public void CanImportCertificateChain(string sampleCertificateId, string intermediateAuthorityThumbprint, string rootAuthorityThumbprint, StoreLocation storeLocation, string storeName)
        {
            var sampleCertificate = SampleCertificate.SampleCertificates[sampleCertificateId];

            // intermediate and root authority certificates are always imported to LocalMachine
            var rootAuthorityStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);

            rootAuthorityStore.Open(OpenFlags.ReadWrite);
            var intermediateAuthorityStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine);

            intermediateAuthorityStore.Open(OpenFlags.ReadWrite);

            WindowsX509CertificateStore.RemoveCertificateFromStore(rootAuthorityThumbprint, StoreLocation.LocalMachine, rootAuthorityStore.Name);

            if (!string.IsNullOrEmpty(intermediateAuthorityThumbprint))
            {
                WindowsX509CertificateStore.RemoveCertificateFromStore(intermediateAuthorityThumbprint, StoreLocation.LocalMachine, intermediateAuthorityStore.Name);
            }

            sampleCertificate.EnsureCertificateNotInStore(storeName, storeLocation);

            WindowsX509CertificateStore.ImportCertificateToStore(Convert.FromBase64String(sampleCertificate.Base64Bytes()), sampleCertificate.Password,
                                                                 storeLocation, storeName, sampleCertificate.HasPrivateKey);

            sampleCertificate.AssertCertificateIsInStore(storeName, storeLocation);

            // Assert chain certificates were imported
            if (!string.IsNullOrEmpty(intermediateAuthorityThumbprint))
            {
                AssertCertificateInStore(intermediateAuthorityStore, intermediateAuthorityThumbprint);
            }

            AssertCertificateInStore(rootAuthorityStore, rootAuthorityThumbprint);

            var certificate = sampleCertificate.GetCertificateFromStore(storeName, storeLocation);

            Assert.True(certificate.HasPrivateKey);

            sampleCertificate.EnsureCertificateNotInStore(storeName, storeLocation);

            WindowsX509CertificateStore.RemoveCertificateFromStore(rootAuthorityThumbprint, StoreLocation.LocalMachine, rootAuthorityStore.Name);

            if (!string.IsNullOrEmpty(intermediateAuthorityThumbprint))
            {
                WindowsX509CertificateStore.RemoveCertificateFromStore(intermediateAuthorityThumbprint, StoreLocation.LocalMachine, intermediateAuthorityStore.Name);
            }
        }
        static string FindCertificateInLocalMachineStore(string thumbprint)
        {
            foreach (var storeName in WindowsX509CertificateStore.GetStoreNames(StoreLocation.LocalMachine))
            {
                var store = new X509Store(storeName, StoreLocation.LocalMachine);
                store.Open(OpenFlags.ReadOnly);

                var found = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
                if (found.Count != 0 && found[0].HasPrivateKey)
                {
                    return(storeName);
                }

                store.Close();
            }

            return(null);
        }
示例#8
0
        static string AddCertificateToStore(VariableDictionary variables, string certificateVariable, StoreLocation storeLocation, string storeName)
        {
            var pfxBytes = Convert.FromBase64String(variables.Get($"{certificateVariable}.{SpecialVariables.Certificate.Properties.Pfx}"));
            var password = variables.Get($"{certificateVariable}.{SpecialVariables.Certificate.Properties.Password}");
            var subject  = variables.Get($"{certificateVariable}.{SpecialVariables.Certificate.Properties.Subject}");

            Log.Info($"Adding certificate '{subject}' into Cert:\\{storeLocation}\\{storeName}");
            try
            {
                WindowsX509CertificateStore.ImportCertificateToStore(pfxBytes, password, storeLocation, storeName, true);
                return(storeName);
            }
            catch (Exception)
            {
                Log.Error("Exception while attempting to add certificate to store");
                throw;
            }
        }
        static string AddCertificateToLocalMachineStore(IVariables variables, string certificateVariable)
        {
            var pfxBytes = Convert.FromBase64String(variables.Get($"{certificateVariable}.{CertificateVariables.Properties.Pfx}"));
            var password = variables.Get($"{certificateVariable}.{CertificateVariables.Properties.Password}");
            var subject  = variables.Get($"{certificateVariable}.{CertificateVariables.Properties.Subject}");

            Log.Info($"Adding certificate '{subject}' into Cert:\\LocalMachine\\My");

            try
            {
                WindowsX509CertificateStore.ImportCertificateToStore(pfxBytes, password, StoreLocation.LocalMachine, "My", true);
                return("My");
            }
            catch (Exception)
            {
                Log.Error("Exception while attempting to add certificate to store");
                throw;
            }
        }
        public void CanImportCertificate(string sampleCertificateId, StoreLocation storeLocation, string storeName)
        {
            var sampleCertificate = SampleCertificate.SampleCertificates[sampleCertificateId];

            sampleCertificate.EnsureCertificateNotInStore(storeName, storeLocation);

            WindowsX509CertificateStore.ImportCertificateToStore(Convert.FromBase64String(sampleCertificate.Base64Bytes()), sampleCertificate.Password,
                                                                 storeLocation, storeName, sampleCertificate.HasPrivateKey);

            sampleCertificate.AssertCertificateIsInStore(storeName, storeLocation);

            if (sampleCertificate.HasPrivateKey)
            {
                var certificate = sampleCertificate.GetCertificateFromStore(storeName, storeLocation);
                Assert.True(certificate.HasPrivateKey);
            }

            sampleCertificate.EnsureCertificateNotInStore(storeName, storeLocation);
        }
示例#11
0
        static void EnsureApplicationPoolHasCertificatePrivateKeyAccess(VariableDictionary variables)
        {
            foreach (var binding in GetEnabledBindings(variables))
            {
                string certificateVariable = binding.certificateVariable;

                if (string.IsNullOrWhiteSpace(certificateVariable))
                {
                    continue;
                }

                var thumbprint       = variables.Get($"{certificateVariable}.{SpecialVariables.Certificate.Properties.Thumbprint}");
                var privateKeyAccess = CreatePrivateKeyAccessForApplicationPoolAccount(variables);

                // The store-name variable was set by IisWebSiteBeforePostDeploy
                var storeName = variables.Get(SpecialVariables.Action.IisWebSite.Output.CertificateStoreName);
                WindowsX509CertificateStore.AddPrivateKeyAccessRules(thumbprint, StoreLocation.LocalMachine, storeName,
                                                                     new List <PrivateKeyAccessRule> {
                    privateKeyAccess
                });
            }
        }
示例#12
0
        /// <summary>
        /// SF allows you to provide an override location for the storeLocation and storeName, so this method can optionally
        /// check for the certificate thumbprint in the given storeLocation/storeName.
        /// </summary>
        /// <param name="thumbprint"></param>
        /// <param name="storeLocation"></param>
        /// <param name="storeNameOverride"></param>
        /// <returns></returns>
        static string FindCertificateInStore(string thumbprint, StoreLocation storeLocation, string storeNameOverride)
        {
            foreach (var storeName in WindowsX509CertificateStore.GetStoreNames(storeLocation))
            {
                if (!string.IsNullOrEmpty(storeNameOverride) && storeName.Equals(storeNameOverride, StringComparison.InvariantCultureIgnoreCase))
                {
                    continue;
                }

                //Log.Verbose($"Trying to find certificate with thumbprint '{thumbprint}' in Cert:\\{storeLocation}\\{storeName}");
                var store = new X509Store(storeName, storeLocation);
                store.Open(OpenFlags.ReadOnly);

                var found = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
                if (found.Count != 0 && found[0].HasPrivateKey)
                {
                    return(storeName);
                }

                store.Close();
            }

            return(null);
        }
示例#13
0
        public void SafeForConcurrentOperations()
        {
            var maxTimeAllowedForTest = TimeSpan.FromSeconds(20);
            var sw = Stopwatch.StartNew();

            try
            {
                using (var cts = new CancellationTokenSource(maxTimeAllowedForTest))
                {
                    var cancellationToken = cts.Token;
                    var sampleCertificate = SampleCertificate.SampleCertificates[SampleCertificate.CngPrivateKeyId];

                    var numThreads             = 20;
                    var numIterationsPerThread = 1;
                    var exceptions             = new BlockingCollection <Exception>();
                    void Log(string message) => Console.WriteLine($"{sw.Elapsed} {Thread.CurrentThread.Name}: {message}");

                    WindowsX509CertificateStore.ImportCertificateToStore(
                        Convert.FromBase64String(sampleCertificate.Base64Bytes()), sampleCertificate.Password,
                        StoreLocation.LocalMachine, "My", sampleCertificate.HasPrivateKey);

                    CountdownEvent       allThreadsReady    = null;
                    CountdownEvent       allThreadsFinished = null;
                    ManualResetEventSlim goForIt            = new ManualResetEventSlim(false);

                    Thread[] CreateThreads(int number, string name, Action action) => Enumerable.Range(0, number)
                    .Select(i => new Thread(() =>
                    {
                        allThreadsReady.Signal();
                        goForIt.Wait(cancellationToken);
                        for (int j = 0; j < numIterationsPerThread; j++)
                        {
                            try
                            {
                                Log($"{name} {j}");
                                action();
                            }
                            catch (Exception e)
                            {
                                Log(e.ToString());
                                exceptions.Add(e);
                            }
                        }
                        allThreadsFinished.Signal();
                    })
                    {
                        Name = $"{name}#{i}"
                    }).ToArray();

                    var threads =
                        CreateThreads(numThreads, "ImportCertificateToStore", () =>
                    {
                        WindowsX509CertificateStore.ImportCertificateToStore(
                            Convert.FromBase64String(sampleCertificate.Base64Bytes()),
                            sampleCertificate.Password,
                            StoreLocation.LocalMachine, "My", sampleCertificate.HasPrivateKey);
                    })
                        .Concat(CreateThreads(numThreads, "AddPrivateKeyAccessRules", () =>
                    {
                        WindowsX509CertificateStore.AddPrivateKeyAccessRules(
                            sampleCertificate.Thumbprint, StoreLocation.LocalMachine, "My",
                            new List <PrivateKeyAccessRule>
                        {
                            new PrivateKeyAccessRule("BUILTIN\\Users", PrivateKeyAccess.FullControl)
                        });
                    }))
                        .Concat(CreateThreads(numThreads, "GetPrivateKeySecurity", () =>
                    {
                        var unused = WindowsX509CertificateStore.GetPrivateKeySecurity(
                            sampleCertificate.Thumbprint, StoreLocation.LocalMachine, "My");
                    })).ToArray();

                    allThreadsReady    = new CountdownEvent(threads.Length);
                    allThreadsFinished = new CountdownEvent(threads.Length);

                    foreach (var thread in threads)
                    {
                        thread.Start();
                    }

                    allThreadsReady.Wait(cancellationToken);
                    goForIt.Set();
                    allThreadsFinished.Wait(cancellationToken);

                    foreach (var thread in threads)
                    {
                        Log($"Waiting for {thread.Name} to join...");
                        if (!thread.Join(TimeSpan.FromSeconds(1)))
                        {
                            Log($"Aborting {thread.Name}");
                            thread.Abort();
                        }
                    }

                    sw.Stop();

                    sampleCertificate.EnsureCertificateNotInStore("My", StoreLocation.LocalMachine);

                    if (exceptions.Any())
                    {
                        throw new AssertionException(
                                  $"The following exceptions were thrown during the test causing it to fail:{Environment.NewLine}{string.Join($"{Environment.NewLine}{new string('=', 80)}", exceptions.GroupBy(ex => ex.Message).Select(g => g.First().ToString()))}");
                    }

                    if (sw.Elapsed > maxTimeAllowedForTest)
                    {
                        throw new TimeoutException(
                                  $"This test exceeded the {maxTimeAllowedForTest} allowed for this test to complete.");
                    }
                }
            }
            catch (OperationCanceledException)
            {
                throw new TimeoutException($"This test took longer than {maxTimeAllowedForTest} to run");
            }
        }