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); }
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); }