internal static bool TryGetStepOne( X509 currentCerts, X509 targetCerts, CertificateClusterUpgradeStep previousStep, out CertificateClusterUpgradeStep step) { // step 1 adds all newly added certs and issuers (if any) to the white list step = null; List <string> currentThumbprints = CertificateClusterUpgradeFlow.GetThumbprints(currentCerts.ClusterCertificate); List <string> addedThumbprints = CertificateClusterUpgradeFlow.GetAddedThumbprints(currentCerts.ClusterCertificate, targetCerts.ClusterCertificate); Dictionary <string, string> currentCns = CertificateClusterUpgradeFlow.GetCns(currentCerts.ClusterCertificateCommonNames); Dictionary <string, string> addedCnsAndIssuers = CertificateClusterUpgradeFlow.GetAddedCnsAndIssuers(currentCerts.ClusterCertificateCommonNames, targetCerts.ClusterCertificateCommonNames); if (addedThumbprints.Any() || addedCnsAndIssuers.Any()) { step = new CertificateClusterUpgradeStep( thumbprintWhiteList: currentThumbprints.Concat(addedThumbprints).ToList(), thumbprintLoadList: currentCerts.ClusterCertificate, thumbprintFileStoreSvcList: currentCerts.ClusterCertificate, commonNameWhiteList: CertificateClusterUpgradeFlow.MergeCnsAndIssuers(currentCns, addedCnsAndIssuers), commonNameLoadList: currentCerts.ClusterCertificateCommonNames, commonNameFileStoreSvcList: currentCerts.ClusterCertificateCommonNames); } return(true); }
internal void ValidateCertificates() { if (this.clusterProperties.Security == null || this.clusterProperties.Security.CertificateInformation == null) { return; } X509 certInfo = this.clusterProperties.Security.CertificateInformation; List <ClientCertificateThumbprint> clientCertificateThumbprints = certInfo.ClientCertificateThumbprints; List <ClientCertificateCommonName> clientCertificateCommonNames = certInfo.ClientCertificateCommonNames; bool serverCertificatePresent = certInfo.ServerCertificate != null || (certInfo.ServerCertificateCommonNames != null && certInfo.ServerCertificateCommonNames.Any()); bool clientCertificatInfoPresent = (clientCertificateCommonNames != null && clientCertificateCommonNames.Count > 0) || (clientCertificateThumbprints != null && clientCertificateThumbprints.Count > 0); if (clientCertificatInfoPresent && !serverCertificatePresent) { throw new ValidationException(ClusterManagementErrorCode.ClientCertDefinedWithoutServerCert); } SettingsValidator.ValidateThumbprints(certInfo); SettingsValidator.ValidateCommonNames(certInfo); SettingsValidator.ValidateCommonNamesAgainstThumbprints(certInfo); SettingsValidator.ValidateIssuerCertStore(certInfo); }
private static void ValidateIssuerPinningAndIssuerStoresCannotExistTogether(X509 certInfo) { if (certInfo.ClusterCertificateCommonNames != null && certInfo.ClusterCertificateCommonNames.CommonNames != null && certInfo.ClusterCertificateCommonNames.CommonNames.Any(commonName => !string.IsNullOrEmpty(commonName.CertificateIssuerThumbprint)) && certInfo.ClusterCertificateIssuerStores != null && certInfo.ClusterCertificateIssuerStores.Count() != 0) { throw new ValidationException(ClusterManagementErrorCode.IssuerCertStoreAndIssuerPinningCannotBeTogether); } if (certInfo.ServerCertificateCommonNames != null && certInfo.ServerCertificateCommonNames.CommonNames != null && certInfo.ServerCertificateCommonNames.CommonNames.Any(commonName => !string.IsNullOrEmpty(commonName.CertificateIssuerThumbprint)) && certInfo.ServerCertificateIssuerStores != null && certInfo.ServerCertificateIssuerStores.Count() != 0) { throw new ValidationException(ClusterManagementErrorCode.IssuerCertStoreAndIssuerPinningCannotBeTogether); } if (certInfo.ClientCertificateCommonNames != null && certInfo.ClientCertificateCommonNames.Any(clientCert => !string.IsNullOrEmpty(clientCert.CertificateIssuerThumbprint)) && certInfo.ClientCertificateIssuerStores != null && certInfo.ClientCertificateIssuerStores.Count() != 0) { throw new ValidationException(ClusterManagementErrorCode.IssuerCertStoreAndIssuerPinningCannotBeTogether); } }
internal static void ValidateThumbprints(X509 certInfo) { List <ClientCertificateThumbprint> clientCertificateThumbprints = certInfo.ClientCertificateThumbprints; Dictionary <List <string>, ClusterManagementErrorCode> thumbprintListsToValidate = new Dictionary <List <string>, ClusterManagementErrorCode>(); if (clientCertificateThumbprints != null) { thumbprintListsToValidate.Add(clientCertificateThumbprints.Select(ct => ct.CertificateThumbprint).ToList(), ClusterManagementErrorCode.InvalidClientCertificateThumbprint); } if (certInfo.ServerCertificate != null) { thumbprintListsToValidate.Add(certInfo.ServerCertificate.ToThumbprintList(), ClusterManagementErrorCode.InvalidServerCertificateThumbprint); } if (certInfo.ClusterCertificate != null) { thumbprintListsToValidate.Add(certInfo.ClusterCertificate.ToThumbprintList(), ClusterManagementErrorCode.InvalidClusterCertificateThumbprint); } if (certInfo.ReverseProxyCertificate != null) { thumbprintListsToValidate.Add(certInfo.ReverseProxyCertificate.ToThumbprintList(), ClusterManagementErrorCode.InvalidReverseProxyCertificateThumbprint); } foreach (KeyValuePair <List <string>, ClusterManagementErrorCode> entry in thumbprintListsToValidate) { if (!IsValidThumbprintList(entry.Key)) { throw new ValidationException(entry.Value); } } }
internal static IEnumerable <CertificateCommonNameBase> GetAllCommonNames(X509 certInfo) { return(new List <IEnumerable <CertificateCommonNameBase> > { certInfo.ClientCertificateCommonNames, certInfo.ClusterCertificateCommonNames != null ? certInfo.ClusterCertificateCommonNames.CommonNames : null, certInfo.ServerCertificateCommonNames != null ? certInfo.ServerCertificateCommonNames.CommonNames : null, certInfo.ReverseProxyCertificateCommonNames != null ? certInfo.ReverseProxyCertificateCommonNames.CommonNames : null, }.Where(p => p != null).SelectMany(q => q)); }
internal static void ValidateCommonNames(X509 certInfo) { // CNs must not be null IEnumerable <CertificateCommonNameBase> allCns = SettingsValidator.GetAllCommonNames(certInfo); if (allCns.Any(cn => string.IsNullOrWhiteSpace(cn.CertificateCommonName))) { throw new ValidationException(ClusterManagementErrorCode.InvalidCommonName); } IEnumerable <CertificateCommonNameBase> allCnsWithoutItSupport = SettingsValidator.GetAllCommonNames(certInfo, false); if (allCnsWithoutItSupport.Any(cn => !string.IsNullOrWhiteSpace(cn.CertificateIssuerThumbprint))) { throw new ValidationException(ClusterManagementErrorCode.UnsupportedIssuerThumbprintPair); } // Issuer thumbprints must be separated by comma, and should not dupe under the same cn IEnumerable <CertificateCommonNameBase> allCnsWithItSupport = SettingsValidator.GetAllCommonNames(certInfo, true); foreach (CertificateCommonNameBase cn in allCnsWithItSupport) { if (!string.IsNullOrWhiteSpace(cn.CertificateIssuerThumbprint) && !SettingsValidator.AreValidIssuerThumbprints(cn.CertificateIssuerThumbprint)) { throw new ValidationException(ClusterManagementErrorCode.InvalidCertificateIssuerThumbprints, cn.CertificateIssuerThumbprint); } } // Up to 2 CNs are supported, except client CN List <ServerCertificateCommonNames> cnsWithCountCap = new List <ServerCertificateCommonNames>() { certInfo.ClusterCertificateCommonNames, certInfo.ReverseProxyCertificateCommonNames, certInfo.ServerCertificateCommonNames }; if (cnsWithCountCap.Any(cns => cns != null && cns.CommonNames != null && cns.CommonNames.Count > 2)) { throw new ValidationException(ClusterManagementErrorCode.InvalidCommonNameCount); } // no dupe CN is allowed for the same cert type, except client CN foreach (List <CertificateCommonNameBase> cns in cnsWithCountCap .Where(p => p != null && p.CommonNames != null) .Select(p => p.CommonNames)) { if (cns.Any(current => cns.Any(other => current != other && current.CertificateCommonName == other.CertificateCommonName))) { throw new ValidationException(ClusterManagementErrorCode.DupeCommonNameNotAllowedForClusterCert); } } }
internal static void GetFileStoreSvcListForCertTypeChange( X509 currentCerts, X509 targetCerts, out CertificateDescription thumbprintFileStoreSvcCerts, out ServerCertificateCommonNames commonNameFileStoreSvcCerts) { if (targetCerts.ClusterCertificate == null) { thumbprintFileStoreSvcCerts = currentCerts.ClusterCertificate; commonNameFileStoreSvcCerts = targetCerts.ClusterCertificateCommonNames; } else { thumbprintFileStoreSvcCerts = targetCerts.ClusterCertificate; commonNameFileStoreSvcCerts = currentCerts.ClusterCertificateCommonNames; } }
public static List <CertificateClusterUpgradeStep> GetUpgradeFlow(X509 currentCerts, X509 targetCerts) { List <CertificateClusterUpgradeStep> result = new List <CertificateClusterUpgradeStep>(); CertificateClusterUpgradeStep previousStep = null; bool shouldContinue = true; for (int i = 0; i < CertificateClusterUpgradeFlow.upgradeStepDelegateTable.Length && shouldContinue; i++) { CertificateClusterUpgradeStep step; shouldContinue = CertificateClusterUpgradeFlow.upgradeStepDelegateTable[i](currentCerts, targetCerts, previousStep, out step); previousStep = step; if (step != null) { result.Add(step); } } return(result); }
internal static bool TryGetStepThree( X509 currentCerts, X509 targetCerts, CertificateClusterUpgradeStep previousStep, out CertificateClusterUpgradeStep step) { Dictionary <string, string> commonNameWhiteList = targetCerts.ClusterCertificateCommonNames == null || !targetCerts.ClusterCertificateCommonNames.Any() ? null : targetCerts.ClusterCertificateCommonNames.CommonNames.ToDictionary(p => p.CertificateCommonName, p => p.CertificateIssuerThumbprint); step = new CertificateClusterUpgradeStep( thumbprintWhiteList: targetCerts.ClusterCertificate == null ? null : targetCerts.ClusterCertificate.ToThumbprintList(), thumbprintLoadList: targetCerts.ClusterCertificate, thumbprintFileStoreSvcList: targetCerts.ClusterCertificate, commonNameWhiteList: commonNameWhiteList, commonNameLoadList: targetCerts.ClusterCertificateCommonNames, commonNameFileStoreSvcList: targetCerts.ClusterCertificateCommonNames); return(true); }
internal static IEnumerable <CertificateCommonNameBase> GetAllCommonNames(X509 certInfo, bool isIssuerThumbprintSupported) { if (isIssuerThumbprintSupported) { return(new List <IEnumerable <CertificateCommonNameBase> > { certInfo.ClientCertificateCommonNames, certInfo.ClusterCertificateCommonNames != null ? certInfo.ClusterCertificateCommonNames.CommonNames : null, certInfo.ServerCertificateCommonNames != null ? certInfo.ServerCertificateCommonNames.CommonNames : null, }.Where(p => p != null).SelectMany(q => q)); } else { return(new List <IEnumerable <CertificateCommonNameBase> > { certInfo.ReverseProxyCertificateCommonNames != null ? certInfo.ReverseProxyCertificateCommonNames.CommonNames : null, }.Where(p => p != null).SelectMany(q => q)); } }
internal static void ValidateCommonNamesAgainstThumbprints(X509 certInfo) { // for any cert except client cert, CN and thumbprint are not allowed to be configured together KeyValuePair <ServerCertificateCommonNames, CertificateDescription>[] pairs = new KeyValuePair <ServerCertificateCommonNames, CertificateDescription>[] { new KeyValuePair <ServerCertificateCommonNames, CertificateDescription>(certInfo.ClusterCertificateCommonNames, certInfo.ClusterCertificate), new KeyValuePair <ServerCertificateCommonNames, CertificateDescription>(certInfo.ServerCertificateCommonNames, certInfo.ServerCertificate), new KeyValuePair <ServerCertificateCommonNames, CertificateDescription>(certInfo.ReverseProxyCertificateCommonNames, certInfo.ReverseProxyCertificate), }; foreach (var pair in pairs) { ServerCertificateCommonNames cns = pair.Key; CertificateDescription thumbprints = pair.Value; if (cns != null && thumbprints != null) { throw new ValidationException(ClusterManagementErrorCode.InvalidCommonNameThumbprintPair); } } }
internal static void ValidateIssuerCertStore(X509 certInfo) { // Issuercertstore must not exist if corresponding cn does not exist for cert if (certInfo.ClusterCertificateCommonNames == null && certInfo.ClusterCertificateIssuerStores != null && certInfo.ClusterCertificateIssuerStores.Count() != 0) { throw new ValidationException(ClusterManagementErrorCode.IssuerCertStoreSpecifiedWithoutCommonNameCertificate); } if (certInfo.ServerCertificateCommonNames == null && certInfo.ServerCertificateIssuerStores != null && certInfo.ServerCertificateIssuerStores.Count() != 0) { throw new ValidationException(ClusterManagementErrorCode.IssuerCertStoreSpecifiedWithoutCommonNameCertificate); } if (certInfo.ClientCertificateCommonNames == null && certInfo.ClientCertificateIssuerStores != null && certInfo.ClientCertificateIssuerStores.Count() != 0) { throw new ValidationException(ClusterManagementErrorCode.IssuerCertStoreSpecifiedWithoutCommonNameCertificate); } // Issuer thumbprint pinning and issuer store cannot be specified together SettingsValidator.ValidateIssuerPinningAndIssuerStoresCannotExistTogether(certInfo); if (certInfo.ClusterCertificateIssuerStores != null && certInfo.ClusterCertificateIssuerStores.Count != 0) { SettingsValidator.ValidateClusterServerIssuerCertStoreProperties(certInfo.ClusterCertificateIssuerStores); } if (certInfo.ServerCertificateIssuerStores != null && certInfo.ServerCertificateIssuerStores.Count != 0) { SettingsValidator.ValidateClusterServerIssuerCertStoreProperties(certInfo.ServerCertificateIssuerStores); } if (certInfo.ClientCertificateIssuerStores != null && certInfo.ClientCertificateIssuerStores.Count != 0) { SettingsValidator.ValidateClientIssuerCertStoreProperties(certInfo.ClientCertificateIssuerStores); } }
internal static bool TryGetStepTwo( X509 currentCerts, X509 targetCerts, CertificateClusterUpgradeStep previousStep, out CertificateClusterUpgradeStep step) { // step 2: // white list: inherit from the previous step // load list: replace all current certs with target certs // fss list: change if necessary int changedThumbprintCount = CertificateClusterUpgradeFlow.GetChangedThumbprintCount(currentCerts.ClusterCertificate, targetCerts.ClusterCertificate); int changedCnCount = CertificateClusterUpgradeFlow.GetChangedCnCount(currentCerts.ClusterCertificateCommonNames, targetCerts.ClusterCertificateCommonNames); List <string> removedThumbprints = CertificateClusterUpgradeFlow.GetAddedThumbprints(targetCerts.ClusterCertificate, currentCerts.ClusterCertificate); List <string> removedCns = CertificateClusterUpgradeFlow.GetAddedCns(targetCerts.ClusterCertificateCommonNames, currentCerts.ClusterCertificateCommonNames); CertificateDescription thumbprintFileStoreSvcCerts = null; ServerCertificateCommonNames commonNameFileStoreSvcCerts = null; bool shouldContinue = true; switch (changedThumbprintCount + changedCnCount) { case 1: { if (removedThumbprints.Any() || removedCns.Any()) { // cert removal thumbprintFileStoreSvcCerts = currentCerts.ClusterCertificate; commonNameFileStoreSvcCerts = currentCerts.ClusterCertificateCommonNames; } else { // cert add thumbprintFileStoreSvcCerts = targetCerts.ClusterCertificate; commonNameFileStoreSvcCerts = targetCerts.ClusterCertificateCommonNames; shouldContinue = false; } break; } case 2: { if (CertificateClusterUpgradeFlow.IsSwap(currentCerts.ClusterCertificate, targetCerts.ClusterCertificate)) { thumbprintFileStoreSvcCerts = new CertificateDescription() { Thumbprint = currentCerts.ClusterCertificate.Thumbprint, ThumbprintSecondary = currentCerts.ClusterCertificate.Thumbprint, X509StoreName = currentCerts.ClusterCertificate.X509StoreName, }; } else { if (changedThumbprintCount == 2) { // thumbprint replace thumbprintFileStoreSvcCerts = new CertificateDescription() { Thumbprint = currentCerts.ClusterCertificate.Thumbprint, ThumbprintSecondary = targetCerts.ClusterCertificate.Thumbprint, X509StoreName = currentCerts.ClusterCertificate.X509StoreName, }; } else if (changedCnCount == 2) { // cn replace commonNameFileStoreSvcCerts = new ServerCertificateCommonNames() { CommonNames = new List <CertificateCommonNameBase>() { currentCerts.ClusterCertificateCommonNames.CommonNames[0], targetCerts.ClusterCertificateCommonNames.CommonNames[0] }, X509StoreName = currentCerts.ClusterCertificateCommonNames.X509StoreName }; } else { // 1 thumbprint <-> 1 cn CertificateClusterUpgradeFlow.GetFileStoreSvcListForCertTypeChange( currentCerts, targetCerts, out thumbprintFileStoreSvcCerts, out commonNameFileStoreSvcCerts); } } break; } case 3: case 4: { // 1 thumbprints <-> 2 cns, or 2 thumbprints <-> 1 cns, or 2 thumbprints <-> 2 cns CertificateClusterUpgradeFlow.GetFileStoreSvcListForCertTypeChange( currentCerts, targetCerts, out thumbprintFileStoreSvcCerts, out commonNameFileStoreSvcCerts); break; } default: throw new NotSupportedException(string.Format("It's not supported that {0} certificate thumbprints and {1} certificate common names have changed", changedThumbprintCount, changedCnCount)); } step = new CertificateClusterUpgradeStep( thumbprintWhiteList: previousStep != null ? previousStep.ThumbprintWhiteList : CertificateClusterUpgradeFlow.GetThumbprints(currentCerts.ClusterCertificate), thumbprintLoadList: targetCerts.ClusterCertificate, thumbprintFileStoreSvcList: thumbprintFileStoreSvcCerts, commonNameWhiteList: previousStep != null ? previousStep.CommonNameWhiteList : CertificateClusterUpgradeFlow.GetCns(currentCerts.ClusterCertificateCommonNames), commonNameLoadList: targetCerts.ClusterCertificateCommonNames, commonNameFileStoreSvcList: commonNameFileStoreSvcCerts); return(shouldContinue); }