Ejemplo n.º 1
0
 /// <summary>
 /// Removes specified files and logs it
 /// </summary>
 /// <param name="path"></param>
 private static void RemoveFileAndLog(AuthenticatedPFX pfx)
 {
     File.Delete(pfx.PfxFullPath);
     File.Delete(pfx.PemCertPath);
     File.Delete(pfx.PemKeyPath);
     _logger.Info($"Removed files from filesystem: {pfx.PfxFullPath}, {pfx.PemCertPath}, {pfx.PemKeyPath}");
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Executes powershell script scriptFile
        /// </summary>
        /// <param name="scriptFile"></param>
        /// <param name="pfx"></param>
        /// <param name="pfxPassword"></param>
        /// <returns></returns>
        public static bool ExecutePowerShell(string scriptFile, AuthenticatedPFX pfx)
        {
            if (scriptFile == null)
            {
                return(false);
            }
            try {
                // First let's create the execution runspace
                RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
                runspace.Open();

                // Now we create the pipeline
                Pipeline pipeline = runspace.CreatePipeline();

                // We create the script to execute with its arguments as a Command
                System.Management.Automation.Runspaces.Command myCommand = new System.Management.Automation.Runspaces.Command(scriptFile);
                CommandParameter pfxParam = new CommandParameter("pfx", pfx.PfxFullPath);
                myCommand.Parameters.Add(pfxParam);
                CommandParameter pfxPassParam = new CommandParameter("pfxPassword", pfx.PfxPassword);
                myCommand.Parameters.Add(pfxPassParam);

                // add the created Command to the pipeline
                pipeline.Commands.Add(myCommand);

                // and we invoke it
                var results = pipeline.Invoke();
                logger.Info($"Executed script {scriptFile}.");
                return(true);
            } catch (Exception e) {
                logger.Error($"Could not execute {scriptFile}: {e.Message}");
                return(false);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Retrieves the certificate from the ACME service. This method also generates the key and the CSR.
        /// </summary>
        /// <param name="commonName">the CN of the certificate to be requested</param>
        /// <param name="pathForPfx">Path where the resulting PFX/PKCS#12 file will be generated</param>
        /// <param name="pfxFriendlyName">Friendly name for the resulting PFX/PKCS#12</param>
        /// <returns>The name of the generated PFX/PKCS#12 file, or null in case of error</returns>
        public async Task <AuthenticatedPFX> RetrieveCertificate(IList <string> domains, string pathForPfx, string pfxFriendlyName)
        {
            try
            {
                if (_orderCtx == null)
                {
                    throw new Exception("Do not call RetrieveCertificate before RegisterNewOrderAndVerify");
                }
                if (!System.IO.Directory.Exists(pathForPfx))
                {
                    throw new Exception("Directory for PFX writing do not exists");
                }

                InitCertes();
                // Let's generate a new key (RSA is good enough IMHO)
                IKey certKey = KeyFactory.FromPem(Utils.GenerateRSAKeyAsPEM(_keySize));
                // Then let's generate the CSR
                var csr = await _orderCtx.CreateCsr(certKey);

                csr.AddName("CN", domains[0]);
                csr.SubjectAlternativeNames = domains;

                // and finalize the ACME order
                var finalOrder = await _orderCtx.Finalize(csr.Generate());

                // Now we can fetch the certificate
                CertificateChain cert = await _orderCtx.Download();

                // We build the PFX/PKCS#12 and the cert/key as PEM
                var pfx = cert.ToPfx(certKey);
                var cer = cert.ToPem();
                var key = certKey.ToPem();
                pfx.AddIssuers(GetCACertChainFromStore());
                var pfxBytes = pfx.Build(pfxFriendlyName, PfxPassword);
                var fileName = pathForPfx + "\\" + Guid.NewGuid().ToString();
                var pfxName  = fileName + ".pfx";
                var cerPath  = fileName + ".cer";
                var keyPath  = fileName + ".key";

                // We write the PFX/PKCS#12 to file
                System.IO.File.WriteAllBytes(pfxName, pfxBytes);
                logger.Info($"Retrieved certificate from the CA. The certificate is in {pfxName}");

                // We write the PEMs to corresponding files
                System.IO.File.WriteAllText(cerPath, cer);
                System.IO.File.WriteAllText(keyPath, key);

                AuthenticatedPFX authPFX = new AuthenticatedPFX(pfxName, PfxPassword, cerPath, keyPath);

                return(authPFX);
            }
            catch (Exception exp)
            {
                logger.Error($"Failed to retrieve certificate from CA: {ProcessCertesException(exp)}");
                return(null);
            }
        }
Ejemplo n.º 4
0
        static int Main(string[] args)
        {
            // Main parameters with their default values
            string taskName = null;

            _winCertesOptions = new WinCertesOptions();

            if (!Utils.IsAdministrator())
            {
                Console.WriteLine("WinCertes.exe must be launched as Administrator"); return(ERROR);
            }
            // Command line options handling and initialization stuff
            if (!HandleOptions(args))
            {
                return(ERROR_INCORRECT_PARAMETER);
            }
            if (_periodic)
            {
                taskName = Utils.DomainsToFriendlyName(_domains);
            }
            InitWinCertesDirectoryPath();
            Utils.ConfigureLogger(_winCertesPath);
            _config = new RegistryConfig(_extra);
            _winCertesOptions.WriteOptionsIntoConfiguration(_config);
            if (_show)
            {
                _winCertesOptions.displayOptions(_config); return(0);
            }

            // Reset is a full reset !
            if (_reset)
            {
                IConfig baseConfig = new RegistryConfig(false);
                baseConfig.DeleteAllParameters();
                Utils.DeleteScheduledTasks();
                return(0);
            }

            // Initialization and renewal/revocation handling
            try
            {
                InitCertesWrapper(_winCertesOptions.ServiceUri, _winCertesOptions.Email);
            }
            catch (Exception e) { _logger.Error(e.Message); return(ERROR); }
            if (_winCertesOptions.Revoke > -1)
            {
                RevokeCert(_domains, _winCertesOptions.Revoke); return(0);
            }
            // default mode: enrollment/renewal. check if there's something to be done
            // note that in any case, we want to be able to set the scheduled task (won't do anything if taskName is null)
            if (!IsThereCertificateAndIsItToBeRenewed(_domains))
            {
                Utils.CreateScheduledTask(taskName, _domains, _extra); return(0);
            }

            // Now the real stuff: we register the order for the domains, and have them validated by the ACME service
            IHTTPChallengeValidator httpChallengeValidator = HTTPChallengeValidatorFactory.GetHTTPChallengeValidator(_winCertesOptions.Standalone, _winCertesOptions.HttpPort, _winCertesOptions.WebRoot);
            IDNSChallengeValidator  dnsChallengeValidator  = DNSChallengeValidatorFactory.GetDNSChallengeValidator(_config);

            if ((httpChallengeValidator == null) && (dnsChallengeValidator == null))
            {
                WriteErrorMessageWithUsage(_options, "Specify either an HTTP or a DNS validation method."); return(ERROR_INCORRECT_PARAMETER);
            }
            if (!(Task.Run(() => _certesWrapper.RegisterNewOrderAndVerify(_domains, httpChallengeValidator, dnsChallengeValidator)).GetAwaiter().GetResult()))
            {
                if (httpChallengeValidator != null)
                {
                    httpChallengeValidator.EndAllChallengeValidations();
                }
                return(ERROR);
            }
            if (httpChallengeValidator != null)
            {
                httpChallengeValidator.EndAllChallengeValidations();
            }

            // We get the certificate from the ACME service
            var pfxName = Task.Run(() => _certesWrapper.RetrieveCertificate(_domains, _winCertesPath, Utils.DomainsToFriendlyName(_domains))).GetAwaiter().GetResult();

            if (pfxName == null)
            {
                return(ERROR);
            }
            AuthenticatedPFX          pfx = new AuthenticatedPFX(_winCertesPath + "\\" + pfxName, _certesWrapper.PfxPassword);
            CertificateStorageManager certificateStorageManager = new CertificateStorageManager(pfx, ((_winCertesOptions.Csp == null) && (!_winCertesOptions.noCsp)));

            // Let's process the PFX into Windows Certificate objet.
            certificateStorageManager.ProcessPFX();
            // and we write its information to the WinCertes configuration
            RegisterCertificateIntoConfiguration(certificateStorageManager.Certificate, _domains);
            // Import the certificate into the Windows store
            if (!_winCertesOptions.noCsp)
            {
                certificateStorageManager.ImportCertificateIntoCSP(_winCertesOptions.Csp);
            }

            // Bind certificate to IIS Site (won't do anything if option is null)
            Utils.BindCertificateForIISSite(certificateStorageManager.Certificate, _winCertesOptions.BindName);
            // Execute PowerShell Script (won't do anything if option is null)
            Utils.ExecutePowerShell(_winCertesOptions.ScriptFile, pfx);
            // Create the AT task that will execute WinCertes periodically (won't do anything if taskName is null)
            Utils.CreateScheduledTask(taskName, _domains, _extra);

            // Let's delete the PFX file
            RemoveFileAndLog(pfx.PfxFullPath);

            return(0);
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Class constructor
 /// </summary>
 /// <param name="authenticatedPFX">the PFX that we will store</param>
 /// <param name="defaultCSP">do we use the default CSP to store the certificate?</param>
 public CertificateStorageManager(AuthenticatedPFX authenticatedPFX, bool defaultCSP)
 {
     AuthenticatedPFX = authenticatedPFX;
     Certificate      = null;
     DefaultCSP       = defaultCSP;
 }