protected override void ModifyHost(ServiceHost serviceHost, ResourceRequestContext context) { // Ensure the service certificate is installed before this endpoint resource is used //Create an expired certificate CertificateCreationSettings certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - TcpExpiredServerCertResource", ValidityType = CertificateValidityType.Expired, ValidityNotBefore = DateTime.UtcNow - TimeSpan.FromDays(4), ValidityNotAfter = DateTime.UtcNow - TimeSpan.FromDays(2), //If you specify multiple subjects, the first one becomes the subject, and all of them become Subject Alt Names. //In this case, the certificate subject is CN=fqdn, OU=..., O=... , and SANs will be fqdn, hostname, localhost //We do this so that a single bridge setup can deal with all the possible addresses that a client might use. //If we don't put "localhost' here, a long-running bridge will not be able to receive requests from both fqdn and localhost //because the certs won't match. Subject = s_fqdn, SubjectAlternativeNames = new string[] { s_fqdn, s_hostname, "localhost" } }; X509Certificate2 cert = CertificateResourceHelpers.EnsureCustomCertificateInstalled(context.BridgeConfiguration, certificateCreationSettings, Address); serviceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, cert.Thumbprint); }
// Requests a certificate to be generated by the Bridge // If the certificate requested is for the local machine, for example if // server hostname is: foo.bar.com // local address is considered to be: 127.0.0.1, localhost, foo, foo.bar.com // Then we also install the certificate to the local machine, because it means we are about to run an HTTPS/SSL test against // this machine. // Otherwise, don't bother installing as the cert is for a remote machine. public override ResourceResponse Put(ResourceRequestContext context) { X509Certificate2 certificate; string subject; if (!context.Properties.TryGetValue(subjectKeyName, out subject) || string.IsNullOrWhiteSpace(subject)) { throw new ArgumentException("When PUTting to this resource, specify an non-empty 'subject'", "context.Properties"); } // There can be multiple subjects, separated by , string[] subjects = subject.Split(','); bool isLocal = IsLocalMachineResource(subjects[0]); lock (s_certificateResourceLock) { if (!s_createdCertsBySubject.TryGetValue(subjects[0], out certificate)) { CertificateGenerator generator = CertificateResourceHelpers.GetCertificateGeneratorInstance(context.BridgeConfiguration); if (isLocal) { // If we're PUTting a cert that refers to a hostname local to the bridge, // return the Local Machine cert that CertificateManager caches and add it to the collection // // If we are receiving a PUT to the same endpoint address as the bridge server, it means that // a test is going to be run on this box // // In keeping with the semantic of these classes, we must PUT before we can GET a cert certificate = CertificateManager.CreateAndInstallLocalMachineCertificates(generator); } else { CertificateCreationSettings certificateCreationSettings = new CertificateCreationSettings() { Subjects = subjects, }; certificate = generator.CreateMachineCertificate(certificateCreationSettings).Certificate; } X509Certificate2 dummy; if (!isLocal || !s_createdCertsByThumbprint.TryGetValue(certificate.Thumbprint, out dummy)) { // when isLocal, it's possible for there to be > 1 subject sharing the same thumbprint // in this case, we only cache the first isLocal subject, the rest we don't cache s_createdCertsBySubject.Add(subjects[0], certificate); s_createdCertsByThumbprint.Add(certificate.Thumbprint, certificate); } } } ResourceResponse response = new ResourceResponse(); response.Properties.Add(thumbprintKeyName, certificate.Thumbprint); response.Properties.Add(isLocalKeyName, isLocal.ToString()); return response; }
// When called, generates the a cert for the machine DNS name with SAN localhost, and installs both certs // returns thumbprint of the machine certs public static X509Certificate2 CreateAndInstallLocalMachineCertificates(CertificateGenerator certificateGenerator) { if (certificateGenerator == null) { throw new ArgumentNullException("certificateGenerator"); } lock (s_certificateLock) { if (s_localCertificate != null) { return(s_localCertificate); } Trace.WriteLine("[CertificateManager] Installing Root and Machine certificates to machine store."); // At this point, we know we haven't generated the certs yet, or the operation is completing on another thread // Certificate generation is time-consuming, so we want to make sure that we don't unnecessarily generate a cert var rootCertificate = certificateGenerator.AuthorityCertificate.Certificate; var fqdn = Dns.GetHostEntry("127.0.0.1").HostName; var hostname = fqdn.Split('.')[0]; // always create a certificate locally for the current machine's fully qualified domain name, // hostname, and "localhost". CertificateCreationSettings certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - Machine certificate generated by the CertificateManager", Subject = fqdn, SubjectAlternativeNames = new string[] { fqdn, hostname, "localhost" } }; var hostCert = certificateGenerator.CreateMachineCertificate(certificateCreationSettings).Certificate; // Since s_myCertificates keys by subject name, we won't install a cert for the same subject twice // only the first-created cert will win InstallCertificateToRootStore(rootCertificate); InstallCertificateToMyStore(hostCert, certificateCreationSettings.ValidityType == CertificateValidityType.Valid); s_localCertificate = hostCert; // Create the PeerTrust cert certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - UserPeerTrustCertificateResource", Subject = fqdn, SubjectAlternativeNames = new string[] { fqdn, hostname, "localhost" } }; var peerCert = certificateGenerator.CreateMachineCertificate(certificateCreationSettings).Certificate; InstallCertificateToTrustedPeopleStore(peerCert, certificateCreationSettings.ValidityType == CertificateValidityType.Valid); } return(s_localCertificate); }
protected override void ModifyHost(ServiceHost serviceHost, ResourceRequestContext context) { // Ensure the service certificate is installed before this endpoint resource is used //Create a certificate and add to the revocation list CertificateCreationSettings certificateCreationSettings = new CertificateCreationSettings() { IsValidCert = false, Subjects = new string[] { s_fqdn, s_hostname, "localhost" } }; X509Certificate2 cert = CertificateResourceHelpers.EnsureRevokedCertificateInstalled(context.BridgeConfiguration, certificateCreationSettings, Address); CertificateManager.RevokeCertificate(CertificateResourceHelpers.GetCertificateGeneratorInstance(context.BridgeConfiguration), cert.SerialNumber); serviceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, cert.Thumbprint); }
// Requests a certificate to be generated by the Bridge based on a user name and not machine name public override ResourceResponse Put(ResourceRequestContext context) { X509Certificate2 certificate; string subject; if (!context.Properties.TryGetValue(subjectKeyName, out subject) || string.IsNullOrWhiteSpace(subject)) { throw new ArgumentException("When PUTting to this resource, specify an non-empty 'subject'", "context.Properties"); } // There can be multiple subjects, separated by , string[] subjects = subject.Split(','); lock (s_certificateResourceLock) { if (!s_createdCertsBySubject.TryGetValue(subjects[0], out certificate)) { CertificateGenerator generator = CertificateResourceHelpers.GetCertificateGeneratorInstance(context.BridgeConfiguration); CertificateCreationSettings certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - UserCertificateResource", Subject = subjects[0], SubjectAlternativeNames = subjects }; certificate = generator.CreateUserCertificate(certificateCreationSettings).Certificate; // Cache the certificates s_createdCertsBySubject.Add(subjects[0], certificate); s_createdCertsByThumbprint.Add(certificate.Thumbprint, certificate); // Created certs get put onto the local machine // We ideally don't want this to happen, but until we find a way to have BridgeClient not need elevation for cert installs // we need this to happen so that running locally doesn't require elevation as it messes up our CI and developer builds CertificateManager.InstallCertificateToMyStore(certificate); } } ResourceResponse response = new ResourceResponse(); response.Properties.Add(thumbprintKeyName, certificate.Thumbprint); return response; }
protected override void ModifyHost(ServiceHost serviceHost, ResourceRequestContext context) { // Ensure the service certificate is installed before this endpoint resource is used //Create a certificate and add to the revocation list CertificateCreationSettings certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - TcpRevokedServerCertResource", ValidityType = CertificateValidityType.Revoked, Subject = s_fqdn, SubjectAlternativeNames = new string[] { s_fqdn, s_hostname, "localhost" } }; X509Certificate2 cert = CertificateResourceHelpers.EnsureCustomCertificateInstalled(context.BridgeConfiguration, certificateCreationSettings, Address); serviceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, cert.Thumbprint); }
protected override void ModifyHost(ServiceHost serviceHost, ResourceRequestContext context) { // Ensure the service certificate is installed before this endpoint resource is used // Exactly one subject name, which is going to be the CN CertificateCreationSettings certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - TcpCertificateWithSubjectCanonicalNameLocalhostResource", Subject = "localhost", SubjectAlternativeNames = new string[0], ValidityType = CertificateValidityType.NonAuthoritativeForMachine }; X509Certificate2 cert = CertificateResourceHelpers.EnsureCustomCertificateInstalled(context.BridgeConfiguration, certificateCreationSettings, Address); serviceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, cert.Thumbprint); }
protected override void ModifyHost(ServiceHost serviceHost, ResourceRequestContext context) { // Ensure the service certificate is installed before this endpoint resource is used // CN=not-real-subject-name means that a cert for "not-real-subject-name" will be installed // Per #422 this shouldn't matter as we now check with SAN CertificateCreationSettings certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - TcpCertificateWithServerAltNameResource", Subject = "not-real-subject-name", SubjectAlternativeNames = new string[] { "not-real-subject-name", "not-real-subject-name.example.com", s_fqdn, s_hostname, "localhost" } }; X509Certificate2 cert = CertificateResourceHelpers.EnsureCustomCertificateInstalled(context.BridgeConfiguration, certificateCreationSettings, Address); serviceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, cert.Thumbprint); }
internal static X509Certificate2 EnsureRevokedCertificateInstalled(BridgeConfiguration configuration, CertificateCreationSettings certificateCreationSettings, string resourceAddress) { return CertificateManager.CreateAndInstallNonDefaultMachineCertificates(GetCertificateGeneratorInstance(configuration), certificateCreationSettings, resourceAddress); }
// We generate a local machine certificate for common usage. This method is usded to generate certs for non common usage, such as an expired cert. public static X509Certificate2 CreateAndInstallNonDefaultMachineCertificates(CertificateGenerator certificateGenerator, CertificateCreationSettings certificateCreationSettings, string resourceAddress) { if (certificateCreationSettings == null) { throw new ArgumentException("certificateCreationSettings cannot be null as we are creating a non default certificate"); } if (certificateGenerator == null) { throw new ArgumentNullException("certificateGenerator"); } lock (s_certificateLock) { Trace.WriteLine("[CertificateManager] Installing Non default Machine certificates to machine store."); var rootCertificate = certificateGenerator.AuthorityCertificate.Certificate; var hostCert = certificateGenerator.CreateMachineCertificate(certificateCreationSettings).Certificate; InstallCertificateToRootStore(rootCertificate); InstallCertificateToMyStore(hostCert, certificateCreationSettings.ValidityType == CertificateValidityType.Valid, resourceAddress); return(hostCert); } }
private static int Main(string[] args) { ApplyAppSettings(); if (args.Length > 0) { if (string.Compare(args[0], "-Uninstall", true) == 0) { UninstallAllCerts(); return 0; } else if (string.Compare(args[0], "-help", true) == 0) { Usage(); return 0; } else { Usage(); return 1; } } UninstallAllCerts(); CertificateGenerator certificateGenerate = new CertificateGenerator(); certificateGenerate.CertificatePassword = "******"; certificateGenerate.CrlUriBridgeHost = s_fqdn; certificateGenerate.ValidityPeriod = s_ValidatePeriod; if (!string.IsNullOrEmpty(s_testserverbase)) { certificateGenerate.CrlUriRelativePath += "/" + s_testserverbase; } certificateGenerate.CrlUriRelativePath += "/CrlService.svc/GetCrl"; //Create and install root and server cert CertificateManager.CreateAndInstallLocalMachineCertificates(certificateGenerate); //Create and Install expired cert CertificateCreationSettings certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - TcpExpiredServerCertResource", ValidityType = CertificateValidityType.Expired, ValidityNotBefore = DateTime.UtcNow - TimeSpan.FromDays(4), ValidityNotAfter = DateTime.UtcNow - TimeSpan.FromDays(2), //If you specify multiple subjects, the first one becomes the subject, and all of them become Subject Alt Names. //In this case, the certificate subject is CN=fqdn, OU=..., O=... , and SANs will be fqdn, hostname, localhost //We do this so that a single bridge setup can deal with all the possible addresses that a client might use. //If we don't put "localhost' here, a long-running bridge will not be able to receive requests from both fqdn and localhost //because the certs won't match. Subject = s_fqdn, SubjectAlternativeNames = new string[] { s_fqdn, s_hostname, "localhost" } }; CreateAndInstallMachineCertificate(certificateGenerate, certificateCreationSettings); //Create and Install TcpCertificateWithServerAltNameResource certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - TcpCertificateWithServerAltNameResource", Subject = "not-real-subject-name", SubjectAlternativeNames = new string[] { "not-real-subject-name", "not-real-subject-name.example.com", s_fqdn, s_hostname, "localhost" } }; CreateAndInstallMachineCertificate(certificateGenerate, certificateCreationSettings); //TcpCertificateWithSubjectCanonicalNameDomainNameResource certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - TcpCertificateWithSubjectCanonicalNameDomainNameResource", Subject = s_hostname, SubjectAlternativeNames = new string[0], ValidityType = CertificateValidityType.NonAuthoritativeForMachine }; CreateAndInstallMachineCertificate(certificateGenerate, certificateCreationSettings); //WCF Bridge - TcpCertificateWithSubjectCanonicalNameFqdnResource certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - TcpCertificateWithSubjectCanonicalNameFqdnResource", Subject = s_fqdn, SubjectAlternativeNames = new string[0], ValidityType = CertificateValidityType.NonAuthoritativeForMachine }; CreateAndInstallMachineCertificate(certificateGenerate, certificateCreationSettings); //TcpCertificateWithSubjectCanonicalNameLocalhostResource certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - TcpCertificateWithSubjectCanonicalNameLocalhostResource", Subject = "localhost", SubjectAlternativeNames = new string[0], ValidityType = CertificateValidityType.NonAuthoritativeForMachine }; CreateAndInstallMachineCertificate(certificateGenerate, certificateCreationSettings); //TcpRevokedServerCertResource certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - TcpRevokedServerCertResource", ValidityType = CertificateValidityType.Revoked, Subject = s_fqdn, SubjectAlternativeNames = new string[] { s_fqdn, s_hostname, "localhost" } }; CreateAndInstallMachineCertificate(certificateGenerate, certificateCreationSettings); //Create and install client cert certificateCreationSettings = new CertificateCreationSettings() { FriendlyName = "WCF Bridge - UserCertificateResource", Subject = "WCF Client Certificate", }; X509Certificate2 certificate = certificateGenerate.CreateUserCertificate(certificateCreationSettings).Certificate; CertificateManager.AddToStoreIfNeeded(StoreName.TrustedPeople, StoreLocation.LocalMachine, certificate); CertificateManager.AddToStoreIfNeeded(StoreName.My, StoreLocation.LocalMachine, certificate); //Create CRL and save it File.WriteAllBytes(s_CrlFileLocation, certificateGenerate.CrlEncoded); return 0; }
internal static string EnsureNonDefaultCertificateInstalled(BridgeConfiguration configuration, CertificateCreationSettings certificateCreationSettings, string resourceAddress) { X509Certificate2 cert = CertificateManager.CreateAndInstallNonDefaultMachineCertificates(GetCertificateGeneratorInstance(configuration), certificateCreationSettings, resourceAddress); return cert.Thumbprint; }
// Only the ctor should be calling with isAuthority = true // if isAuthority, value for isMachineCert doesn't matter private X509CertificateContainer CreateCertificate(bool isAuthority, bool isMachineCert, X509Certificate signingCertificate, CertificateCreationSettings certificateCreationSettings) { if (certificateCreationSettings == null) { if (isAuthority) { certificateCreationSettings = new CertificateCreationSettings(); } else { throw new Exception("Parameter certificateCreationSettings cannot be null when isAuthority is false"); } } // Set to default cert creation settings if not set if (certificateCreationSettings.ValidityNotBefore == default(DateTime)) { certificateCreationSettings.ValidityNotBefore = _defaultValidityNotBefore; } if (certificateCreationSettings.ValidityNotAfter == default(DateTime)) { certificateCreationSettings.ValidityNotAfter = _defaultValidityNotAfter; } if (!isAuthority ^ (signingCertificate != null)) { throw new ArgumentException("Either isAuthority == true or signingCertificate is not null"); } string subject = certificateCreationSettings.Subject; // If certificateCreationSettings.SubjectAlternativeNames == null, then we should add exactly one SubjectAlternativeName == Subject // so that the default certificate generated is compatible with mainline scenarios // However, if certificateCreationSettings.SubjectAlternativeNames == string[0], then allow this as this is a legit scenario we want to test out if (certificateCreationSettings.SubjectAlternativeNames == null) { certificateCreationSettings.SubjectAlternativeNames = new string[1] { subject }; } string[] subjectAlternativeNames = certificateCreationSettings.SubjectAlternativeNames; if (!isAuthority && string.IsNullOrWhiteSpace(subject)) { throw new ArgumentException("Certificate Subject must not be an empty string or only whitespace", "creationSettings.Subject"); } EnsureInitialized(); s_certGenerator.Reset(); s_certGenerator.SetSignatureAlgorithm(_signatureAlthorithm); X509Name authorityX509Name = CreateX509Name(_authorityCanonicalName); var serialNum = new BigInteger(64 /*sizeInBits*/, _random).Abs(); var keyPair = isAuthority ? _authorityKeyPair : _keyPairGenerator.GenerateKeyPair(); if (isAuthority) { s_certGenerator.SetIssuerDN(authorityX509Name); s_certGenerator.SetSubjectDN(authorityX509Name); var authorityKeyIdentifier = new AuthorityKeyIdentifier( SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(_authorityKeyPair.Public), new GeneralNames(new GeneralName(authorityX509Name)), serialNum); s_certGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, authorityKeyIdentifier); s_certGenerator.AddExtension(X509Extensions.KeyUsage, false, new KeyUsage(X509KeyUsage.DigitalSignature | X509KeyUsage.KeyAgreement | X509KeyUsage.KeyCertSign | X509KeyUsage.KeyEncipherment | X509KeyUsage.CrlSign)); } else { X509Name subjectName = CreateX509Name(subject); s_certGenerator.SetIssuerDN(PrincipalUtilities.GetSubjectX509Principal(signingCertificate)); s_certGenerator.SetSubjectDN(subjectName); s_certGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(_authorityKeyPair.Public)); s_certGenerator.AddExtension(X509Extensions.KeyUsage, false, new KeyUsage(X509KeyUsage.DigitalSignature | X509KeyUsage.KeyAgreement | X509KeyUsage.KeyEncipherment)); } s_certGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(keyPair.Public)); s_certGenerator.SetSerialNumber(serialNum); s_certGenerator.SetNotBefore(certificateCreationSettings.ValidityNotBefore); s_certGenerator.SetNotAfter(certificateCreationSettings.ValidityNotAfter); s_certGenerator.SetPublicKey(keyPair.Public); s_certGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(isAuthority)); s_certGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, false, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPClientAuth)); if (!isAuthority) { if (isMachineCert) { List <Asn1Encodable> subjectAlternativeNamesAsAsn1EncodableList = new List <Asn1Encodable>(); // All endpoints should also be in the Subject Alt Names for (int i = 0; i < subjectAlternativeNames.Length; i++) { if (!string.IsNullOrWhiteSpace(subjectAlternativeNames[i])) { // Machine certs can have additional DNS names subjectAlternativeNamesAsAsn1EncodableList.Add(new GeneralName(GeneralName.DnsName, subjectAlternativeNames[i])); } } s_certGenerator.AddExtension(X509Extensions.SubjectAlternativeName, true, new DerSequence(subjectAlternativeNamesAsAsn1EncodableList.ToArray())); } else { if (subjectAlternativeNames.Length > 1) { var subjectAlternativeNamesAsAsn1EncodableList = new Asn1EncodableVector(); // Only add a SAN for the user if there are any for (int i = 1; i < subjectAlternativeNames.Length; i++) { if (!string.IsNullOrWhiteSpace(subjectAlternativeNames[i])) { Asn1EncodableVector otherNames = new Asn1EncodableVector(); otherNames.Add(new DerObjectIdentifier(_upnObjectId)); otherNames.Add(new DerTaggedObject(true, 0, new DerUtf8String(subjectAlternativeNames[i]))); Asn1Object genName = new DerTaggedObject(false, 0, new DerSequence(otherNames)); subjectAlternativeNamesAsAsn1EncodableList.Add(genName); } } s_certGenerator.AddExtension(X509Extensions.SubjectAlternativeName, true, new DerSequence(subjectAlternativeNamesAsAsn1EncodableList)); } } } // Our CRL Distribution Point has the serial number in the query string to fool Windows into doing a fresh query // rather than using a cached copy of the CRL in the case where the CRL has been previously accessed before var crlDistributionPoints = new DistributionPoint[2] { new DistributionPoint(new DistributionPointName( new GeneralNames(new GeneralName( GeneralName.UniformResourceIdentifier, string.Format("{0}?serialNum={1}", _crlUri, serialNum.ToString(radix: 16))))), null, null), new DistributionPoint(new DistributionPointName( new GeneralNames(new GeneralName( GeneralName.UniformResourceIdentifier, string.Format("{0}?serialNum={1}", _crlUri, serialNum.ToString(radix: 16))))), null, new GeneralNames(new GeneralName(authorityX509Name))) }; var revocationListExtension = new CrlDistPoint(crlDistributionPoints); s_certGenerator.AddExtension(X509Extensions.CrlDistributionPoints, false, revocationListExtension); X509Certificate cert = s_certGenerator.Generate(_authorityKeyPair.Private, _random); switch (certificateCreationSettings.ValidityType) { case CertificateValidityType.Revoked: RevokeCertificateBySerialNumber(serialNum.ToString(radix: 16)); break; case CertificateValidityType.Expired: break; default: EnsureCertificateIsValid(cert); break; } // For now, given that we don't know what format to return it in, preserve the formats so we have // the flexibility to do what we need to X509CertificateContainer container = new X509CertificateContainer(); X509CertificateEntry[] chain = new X509CertificateEntry[1]; chain[0] = new X509CertificateEntry(cert); Pkcs12Store store = new Pkcs12StoreBuilder().Build(); store.SetKeyEntry( certificateCreationSettings.FriendlyName != null ? certificateCreationSettings.FriendlyName : string.Empty, new AsymmetricKeyEntry(keyPair.Private), chain); using (MemoryStream stream = new MemoryStream()) { store.Save(stream, _password.ToCharArray(), _random); container.Pfx = stream.ToArray(); } X509Certificate2 outputCert; if (isAuthority) { // don't hand out the private key for the cert when it's the authority outputCert = new X509Certificate2(cert.GetEncoded()); } else { // Otherwise, allow encode with the private key. note that X509Certificate2.RawData will not provide the private key // you will have to re-export this cert if needed outputCert = new X509Certificate2(container.Pfx, _password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); } container.Subject = subject; container.InternalCertificate = cert; container.Certificate = outputCert; container.Thumbprint = outputCert.Thumbprint; Trace.WriteLine("[CertificateGenerator] generated a certificate:"); Trace.WriteLine(string.Format(" {0} = {1}", "isAuthority", isAuthority)); if (!isAuthority) { Trace.WriteLine(string.Format(" {0} = {1}", "Signed by", signingCertificate.SubjectDN)); Trace.WriteLine(string.Format(" {0} = {1}", "Subject (CN) ", subject)); Trace.WriteLine(string.Format(" {0} = {1}", "Subject Alt names ", string.Join(", ", subjectAlternativeNames))); Trace.WriteLine(string.Format(" {0} = {1}", "Friendly Name ", certificateCreationSettings.FriendlyName)); } Trace.WriteLine(string.Format(" {0} = {1}", "HasPrivateKey:", outputCert.HasPrivateKey)); Trace.WriteLine(string.Format(" {0} = {1}", "Thumbprint", outputCert.Thumbprint)); Trace.WriteLine(string.Format(" {0} = {1}", "CertificateValidityType", certificateCreationSettings.ValidityType)); return(container); }
private static void CreateAndInstallMachineCertificate(CertificateGenerator certificateGenerate, CertificateCreationSettings certificateCreationSettings) { X509Certificate2 certificate = certificateGenerate.CreateMachineCertificate(certificateCreationSettings).Certificate; CertificateManager.AddToStoreIfNeeded(StoreName.My, StoreLocation.LocalMachine, certificate); }
public X509CertificateContainer CreateUserCertificate(CertificateCreationSettings creationSettings) { EnsureInitialized(); return(CreateCertificate(false, false, _authorityCertificate.InternalCertificate, creationSettings)); }
// Only the ctor should be calling with isAuthority = true // if isAuthority, value for isMachineCert doesn't matter private X509CertificateContainer CreateCertificate(bool isAuthority, bool isMachineCert, X509Certificate signingCertificate, CertificateCreationSettings certificateCreationSettings) { if (certificateCreationSettings == null) { if (isAuthority) { certificateCreationSettings = new CertificateCreationSettings(); } else { throw new Exception("Parameter certificateCreationSettings cannot be null when isAuthority is false"); } } // Set to default cert creation settings if not set if (certificateCreationSettings.ValidityNotBefore == default(DateTime)) { certificateCreationSettings.ValidityNotBefore = _defaultValidityNotBefore; } if (certificateCreationSettings.ValidityNotAfter == default(DateTime)) { certificateCreationSettings.ValidityNotAfter = _defaultValidityNotAfter; } string[] subjects = certificateCreationSettings.Subjects; if (!isAuthority ^ (signingCertificate != null)) { throw new ArgumentException("Either isAuthority == true or signingCertificate is not null"); } if (!isAuthority && (subjects == null || subjects.Length == 0)) { throw new ArgumentException("If not creating an authority, must specify at least one Subject", "subjects"); } if (!isAuthority && string.IsNullOrWhiteSpace(subjects[0])) { throw new ArgumentException("Certificate Subject must not be an empty string or only whitespace", "creationSettings.Subjects"); } EnsureInitialized(); _certGenerator.Reset(); _certGenerator.SetSignatureAlgorithm(_signatureAlthorithm); X509Name authorityX509Name = CreateX509Name(_authorityCanonicalName); var keyPair = isAuthority ? _authorityKeyPair : _keyPairGenerator.GenerateKeyPair(); if (isAuthority) { _certGenerator.SetIssuerDN(authorityX509Name); _certGenerator.SetSubjectDN(authorityX509Name); var authorityKeyIdentifier = new AuthorityKeyIdentifier( SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(_authorityKeyPair.Public), new GeneralNames(new GeneralName(authorityX509Name)), new BigInteger(7, _random).Abs()); _certGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, true, authorityKeyIdentifier); _certGenerator.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(X509KeyUsage.DigitalSignature | X509KeyUsage.KeyAgreement | X509KeyUsage.KeyCertSign | X509KeyUsage.KeyEncipherment | X509KeyUsage.CrlSign)); } else { X509Name subjectName = CreateX509Name(subjects[0]); _certGenerator.SetIssuerDN(PrincipalUtilities.GetSubjectX509Principal(signingCertificate)); _certGenerator.SetSubjectDN(subjectName); _certGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, true, new AuthorityKeyIdentifierStructure(_authorityKeyPair.Public)); _certGenerator.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(X509KeyUsage.DigitalSignature | X509KeyUsage.KeyAgreement | X509KeyUsage.KeyEncipherment)); } _certGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(keyPair.Public)); _certGenerator.SetSerialNumber(new BigInteger(64 /*sizeInBits*/, _random).Abs()); _certGenerator.SetNotBefore(certificateCreationSettings.ValidityNotBefore); _certGenerator.SetNotAfter(certificateCreationSettings.ValidityNotAfter); _certGenerator.SetPublicKey(keyPair.Public); _certGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(isAuthority)); _certGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPClientAuth)); if (!isAuthority) { if (isMachineCert) { List<Asn1Encodable> subjectAlternativeNames = new List<Asn1Encodable>(); // All endpoints should also be in the Subject Alt Names for (int i = 0; i < subjects.Length; i++) { if (!string.IsNullOrWhiteSpace(subjects[i])) { // Machine certs can have additional DNS names subjectAlternativeNames.Add(new GeneralName(GeneralName.DnsName, subjects[i])); } } _certGenerator.AddExtension(X509Extensions.SubjectAlternativeName, true, new DerSequence(subjectAlternativeNames.ToArray())); } else { if (subjects.Length > 1) { var subjectAlternativeNames = new Asn1EncodableVector(); // Only add a SAN for the user if there are any for (int i = 1; i < subjects.Length; i++) { if (!string.IsNullOrWhiteSpace(subjects[i])) { Asn1EncodableVector otherNames = new Asn1EncodableVector(); otherNames.Add(new DerObjectIdentifier(_upnObjectId)); otherNames.Add(new DerTaggedObject(true, 0, new DerUtf8String(subjects[i]))); Asn1Object genName = new DerTaggedObject(false, 0, new DerSequence(otherNames)); subjectAlternativeNames.Add(genName); } } _certGenerator.AddExtension(X509Extensions.SubjectAlternativeName, true, new DerSequence(subjectAlternativeNames)); } } } var crlDistributionPoints = new DistributionPoint[1] { new DistributionPoint(new DistributionPointName( new GeneralNames(new GeneralName(GeneralName.UniformResourceIdentifier, _crlUri))), null, new GeneralNames(new GeneralName(authorityX509Name))) }; var revocationListExtension = new CrlDistPoint(crlDistributionPoints); _certGenerator.AddExtension(X509Extensions.CrlDistributionPoints, false, revocationListExtension); X509Certificate cert = _certGenerator.Generate(_authorityKeyPair.Private, _random); if (certificateCreationSettings.IsValidCert) { EnsureCertificateValidity(cert); } // For now, given that we don't know what format to return it in, preserve the formats so we have // the flexibility to do what we need to X509CertificateContainer container = new X509CertificateContainer(); X509CertificateEntry[] chain = new X509CertificateEntry[1]; chain[0] = new X509CertificateEntry(cert); Pkcs12Store store = new Pkcs12StoreBuilder().Build(); store.SetKeyEntry("", new AsymmetricKeyEntry(keyPair.Private), chain); using (MemoryStream stream = new MemoryStream()) { store.Save(stream, _password.ToCharArray(), _random); container.Pfx = stream.ToArray(); } X509Certificate2 outputCert; if (isAuthority) { // don't hand out the private key for the cert when it's the authority outputCert = new X509Certificate2(cert.GetEncoded()); } else { // Otherwise, allow encode with the private key. note that X509Certificate2.RawData will not provide the private key // you will have to re-export this cert if needed outputCert = new X509Certificate2(container.Pfx, _password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); } container.Subject = subjects[0]; container.InternalCertificate = cert; container.Certificate = outputCert; container.Thumbprint = outputCert.Thumbprint; Trace.WriteLine("[CertificateGenerator] generated a certificate:"); Trace.WriteLine(string.Format(" {0} = {1}", "isAuthority", isAuthority)); if (!isAuthority) { Trace.WriteLine(string.Format(" {0} = {1}", "Signed by", signingCertificate.SubjectDN)); Trace.WriteLine(string.Format(" {0} = {1}", "Subject (CN) ", subjects[0])); Trace.WriteLine(string.Format(" {0} = {1}", "Alt names ", string.Join(", ", subjects))); } Trace.WriteLine(string.Format(" {0} = {1}", "HasPrivateKey:", outputCert.HasPrivateKey)); Trace.WriteLine(string.Format(" {0} = {1}", "Thumbprint", outputCert.Thumbprint)); return container; }
public X509CertificateContainer CreateUserCertificate(CertificateCreationSettings creationSettings) { EnsureInitialized(); return CreateCertificate(false, false, _authorityCertificate.InternalCertificate, creationSettings); }
// When called, generates the a cert for the machine DNS name with SAN localhost, and installs both certs // returns thumbprint of the machine certs public static X509Certificate2 CreateAndInstallLocalMachineCertificates(CertificateGenerator certificateGenerator) { if (certificateGenerator == null) { throw new ArgumentNullException("certificateGenerator"); } lock (s_certificateLock) { if (s_localCertificate != null) { return s_localCertificate; } Trace.WriteLine("[CertificateManager] Installing Root and Machine certificates to machine store."); // At this point, we know we haven't generated the certs yet, or the operation is completing on another thread // Certificate generation is time-consuming, so we want to make sure that we don't unnecessarily generate a cert var rootCertificate = certificateGenerator.AuthorityCertificate.Certificate; var fqdn = Dns.GetHostEntry("127.0.0.1").HostName; var hostname = fqdn.Split('.')[0]; // always create a certificate locally for the current machine's fully qualified domain name, // hostname, and "localhost". CertificateCreationSettings certificateCreationSettings = new CertificateCreationSettings() { Subjects = new string[] { fqdn, hostname, "localhost" } }; var hostCert = certificateGenerator.CreateMachineCertificate(certificateCreationSettings).Certificate; // Since s_myCertificates keys by subject name, we won't install a cert for the same subject twice // only the first-created cert will win InstallCertificateToRootStore(rootCertificate); InstallCertificateToMyStore(hostCert, certificateCreationSettings.IsValidCert); s_localCertificate = hostCert; } return s_localCertificate; }
// We generate a local machine certificate for common usage. This method is usded to generate certs for non common usage, such as an expired cert. public static X509Certificate2 CreateAndInstallNonDefaultMachineCertificates(CertificateGenerator certificateGenerator, CertificateCreationSettings certificateCreationSettings, string resourceAddress) { if (certificateCreationSettings == null) { throw new ArgumentException("certificateCreationSettings cannot be null as we are creating a non default certificate"); } if (certificateGenerator == null) { throw new ArgumentNullException("certificateGenerator"); } lock (s_certificateLock) { Trace.WriteLine("[CertificateManager] Installing Non default Machine certificates to machine store."); var rootCertificate = certificateGenerator.AuthorityCertificate.Certificate; var hostCert = certificateGenerator.CreateMachineCertificate(certificateCreationSettings).Certificate; InstallCertificateToRootStore(rootCertificate); InstallCertificateToMyStore(hostCert, certificateCreationSettings.IsValidCert, resourceAddress); return hostCert; } }