Ejemplo n.º 1
0
        public DetailedEnsureCertificateResult EnsureValidCertificateExists(
            DateTimeOffset notBefore,
            DateTimeOffset notAfter,
            CertificatePurpose purpose,
            string path,
            bool trust,
            bool includePrivateKey,
            string password,
            string subject)
        {
            if (purpose == CertificatePurpose.All)
            {
                throw new ArgumentException("The certificate must have a specific purpose.");
            }

            var result = new DetailedEnsureCertificateResult();

            var certificates = ListCertificates(purpose, StoreName.My, StoreLocation.CurrentUser, isValid: true, requireExportable: true, result.Diagnostics).Concat(
                ListCertificates(purpose, StoreName.My, StoreLocation.LocalMachine, isValid: true, requireExportable: true, result.Diagnostics));

            var filteredCertificates = subject == null ? certificates : certificates.Where(c => c.Subject == subject);

            if (subject != null)
            {
                var excludedCertificates = certificates.Except(filteredCertificates);

                result.Diagnostics.Debug($"Filtering found certificates to those with a subject equal to '{subject}'");
                result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(filteredCertificates));
                result.Diagnostics.Debug($"Listing certificates excluded from consideration.");
                result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(excludedCertificates));
            }
            else
            {
                result.Diagnostics.Debug("Skipped filtering certificates by subject.");
            }

            certificates = filteredCertificates;

            result.ResultCode = EnsureCertificateResult.Succeeded;

            X509Certificate2 certificate = null;

            if (certificates.Count() > 0)
            {
                result.Diagnostics.Debug("Found valid certificates present on the machine.");
                result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(certificates));
                certificate = certificates.First();
                result.Diagnostics.Debug("Selected certificate");
                result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(certificate));
                result.ResultCode = EnsureCertificateResult.ValidCertificatePresent;
            }
            else
            {
                result.Diagnostics.Debug("No valid certificates present on this machine. Trying to create one.");
                try {
                    switch (purpose)
                    {
                    case CertificatePurpose.All:
                        throw new InvalidOperationException("The certificate must have a specific purpose.");

                    case CertificatePurpose.HTTPS:
                        certificate = CreateAspNetCoreHttpsDevelopmentCertificate(notBefore, notAfter, subject, result.Diagnostics);
                        break;

                    default:
                        throw new InvalidOperationException("The certificate must have a purpose.");
                    }
                } catch (Exception e) {
                    result.Diagnostics.Error("Error creating the certificate.", e);
                    result.ResultCode = EnsureCertificateResult.ErrorCreatingTheCertificate;
                    return(result);
                }

                try {
                    certificate = SaveCertificateInStore(certificate, StoreName.My, StoreLocation.CurrentUser, result.Diagnostics);
                } catch (Exception e) {
                    result.Diagnostics.Error($"Error saving the certificate in the certificate store '{StoreLocation.CurrentUser}\\{StoreName.My}'.", e);
                    result.ResultCode = EnsureCertificateResult.ErrorSavingTheCertificateIntoTheCurrentUserPersonalStore;
                    return(result);
                }
            }
            if (path != null)
            {
                result.Diagnostics.Debug("Trying to export the certificate.");
                result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(certificate));
                try {
                    ExportCertificate(certificate, path, includePrivateKey, password, result.Diagnostics);
                } catch (Exception e) {
                    result.Diagnostics.Error("An error ocurred exporting the certificate.", e);
                    result.ResultCode = EnsureCertificateResult.ErrorExportingTheCertificate;
                    return(result);
                }
            }

            if ((RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) && trust)
            {
                try {
                    result.Diagnostics.Debug("Trying to export the certificate.");
                    TrustCertificate(certificate, result.Diagnostics);
                } catch (UserCancelledTrustException) {
                    result.Diagnostics.Error("The user cancelled trusting the certificate.", null);
                    result.ResultCode = EnsureCertificateResult.UserCancelledTrustStep;
                    return(result);
                } catch (Exception e) {
                    result.Diagnostics.Error("There was an error trusting the certificate.", e);
                    result.ResultCode = EnsureCertificateResult.FailedToTrustTheCertificate;
                    return(result);
                }
            }

            return(result);
        }
Ejemplo n.º 2
0
        public DetailedEnsureCertificateResult EnsureValidCertificateExists(
            DateTimeOffset notBefore,
            DateTimeOffset notAfter,
            CertificatePurpose purpose,
            string path            = null,
            bool trust             = false,
            bool includePrivateKey = false,
            string password        = null,
            string subjectOverride = null,
            bool isInteractive     = true)
        {
            if (purpose == CertificatePurpose.All)
            {
                throw new ArgumentException("The certificate must have a specific purpose.");
            }

            var result = new DetailedEnsureCertificateResult();

            var certificates = ListCertificates(purpose, StoreName.My, StoreLocation.CurrentUser, isValid: true, requireExportable: true, result.Diagnostics).Concat(
                ListCertificates(purpose, StoreName.My, StoreLocation.LocalMachine, isValid: true, requireExportable: true, result.Diagnostics));

            var filteredCertificates = subjectOverride == null ? certificates : certificates.Where(c => c.Subject == subjectOverride);

            if (subjectOverride != null)
            {
                var excludedCertificates = certificates.Except(filteredCertificates);

                result.Diagnostics.Debug($"Filtering found certificates to those with a subject equal to '{subjectOverride}'");
                result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(filteredCertificates));
                result.Diagnostics.Debug($"Listing certificates excluded from consideration.");
                result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(excludedCertificates));
            }
            else
            {
                result.Diagnostics.Debug("Skipped filtering certificates by subject.");
            }

            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                foreach (var cert in filteredCertificates)
                {
                    if (!CanAccessCertificateKeyAcrossPartitions(cert))
                    {
                        if (!isInteractive)
                        {
                            // If the process is not interactive (first run experience) bail out. We will simply create a certificate
                            // in case there is none or report success during the first run experience.
                            break;
                        }
                        try
                        {
                            // The command we run handles making keys for all localhost certificates accessible across partitions. If it can not run the
                            // command safely (because there are other localhost certificates that were not created by asp.net core, it will throw.
                            MakeCertificateKeyAccessibleAcrossPartitions(cert);
                            break;
                        }
                        catch (Exception ex)
                        {
                            result.Diagnostics.Error("Failed to make certificate key accessible", ex);
                            result.ResultCode = EnsureCertificateResult.FailedToMakeKeyAccessible;
                            return(result);
                        }
                    }
                }
            }

            certificates = filteredCertificates;

            result.ResultCode = EnsureCertificateResult.Succeeded;

            X509Certificate2 certificate = null;

            if (certificates.Count() > 0)
            {
                result.Diagnostics.Debug("Found valid certificates present on the machine.");
                result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(certificates));
                certificate = certificates.First();
                result.Diagnostics.Debug("Selected certificate");
                result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(certificate));
                result.ResultCode = EnsureCertificateResult.ValidCertificatePresent;
            }
            else
            {
                result.Diagnostics.Debug("No valid certificates present on this machine. Trying to create one.");
                try
                {
                    switch (purpose)
                    {
                    case CertificatePurpose.All:
                        throw new InvalidOperationException("The certificate must have a specific purpose.");

                    case CertificatePurpose.HTTPS:
                        certificate = CreateAspNetCoreHttpsDevelopmentCertificate(notBefore, notAfter, subjectOverride, result.Diagnostics);
                        break;

                    default:
                        throw new InvalidOperationException("The certificate must have a purpose.");
                    }
                }
                catch (Exception e)
                {
                    result.Diagnostics.Error("Error creating the certificate.", e);
                    result.ResultCode = EnsureCertificateResult.ErrorCreatingTheCertificate;
                    return(result);
                }

                try
                {
                    certificate = SaveCertificateInStore(certificate, StoreName.My, StoreLocation.CurrentUser, result.Diagnostics);
                }
                catch (Exception e)
                {
                    result.Diagnostics.Error($"Error saving the certificate in the certificate store '{StoreLocation.CurrentUser}\\{StoreName.My}'.", e);
                    result.ResultCode = EnsureCertificateResult.ErrorSavingTheCertificateIntoTheCurrentUserPersonalStore;
                    return(result);
                }

                if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && isInteractive)
                {
                    MakeCertificateKeyAccessibleAcrossPartitions(certificate);
                }

                if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && isInteractive)
                {
                    MakeCertificateKeyAccessibleAcrossPartitions(certificate);
                }
            }
            if (path != null)
            {
                result.Diagnostics.Debug("Trying to export the certificate.");
                result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(certificate));
                try
                {
                    ExportCertificate(certificate, path, includePrivateKey, password, result.Diagnostics);
                }
                catch (Exception e)
                {
                    result.Diagnostics.Error("An error ocurred exporting the certificate.", e);
                    result.ResultCode = EnsureCertificateResult.ErrorExportingTheCertificate;
                    return(result);
                }
            }

            if ((RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) && trust)
            {
                try
                {
                    result.Diagnostics.Debug("Trying to export the certificate.");
                    TrustCertificate(certificate, result.Diagnostics);
                }
                catch (UserCancelledTrustException)
                {
                    result.Diagnostics.Error("The user cancelled trusting the certificate.", null);
                    result.ResultCode = EnsureCertificateResult.UserCancelledTrustStep;
                    return(result);
                }
                catch (Exception e)
                {
                    result.Diagnostics.Error("There was an error trusting the certificate.", e);
                    result.ResultCode = EnsureCertificateResult.FailedToTrustTheCertificate;
                    return(result);
                }
            }

            return(result);
        }