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);
        }
Пример #2
0
        // 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;
        }
Пример #3
0
        // 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);
        }
Пример #5
0
        // 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);
 }
Пример #10
0
        // 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);
            }
        }
Пример #11
0
        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;
        }
Пример #12
0
        internal static string EnsureNonDefaultCertificateInstalled(BridgeConfiguration configuration, CertificateCreationSettings certificateCreationSettings, string resourceAddress)
        {
            X509Certificate2 cert = CertificateManager.CreateAndInstallNonDefaultMachineCertificates(GetCertificateGeneratorInstance(configuration), certificateCreationSettings, resourceAddress);

            return cert.Thumbprint;
        }
Пример #13
0
        // 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);
        }
Пример #14
0
 private static void CreateAndInstallMachineCertificate(CertificateGenerator certificateGenerate, CertificateCreationSettings certificateCreationSettings)
 {
     X509Certificate2 certificate = certificateGenerate.CreateMachineCertificate(certificateCreationSettings).Certificate;
     CertificateManager.AddToStoreIfNeeded(StoreName.My, StoreLocation.LocalMachine, certificate);
 }
Пример #15
0
 public X509CertificateContainer CreateUserCertificate(CertificateCreationSettings creationSettings)
 {
     EnsureInitialized();
     return(CreateCertificate(false, false, _authorityCertificate.InternalCertificate, creationSettings));
 }
Пример #16
0
        // 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;
        }
Пример #17
0
 public X509CertificateContainer CreateUserCertificate(CertificateCreationSettings creationSettings)
 {
     EnsureInitialized();
     return CreateCertificate(false, false, _authorityCertificate.InternalCertificate, creationSettings);
 }
Пример #18
0
        // 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;
        }
Пример #19
0
        // 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;
            }
        }