From a1b7589d8003b277138d18d830793edece22a876 Mon Sep 17 00:00:00 2001 From: David Galey Date: Tue, 30 Jun 2026 13:47:20 -0400 Subject: [PATCH 1/8] add product ID filter to sync --- .../API/ListCertificateOrders.cs | 11 +++- .../CertCentralCAPlugin.cs | 61 +++++++++---------- .../CertCentralConfig.cs | 15 +++++ .../Client/CertCentralClient.cs | 5 +- digicert-certcentral-caplugin/Constants.cs | 1 + 5 files changed, 57 insertions(+), 36 deletions(-) diff --git a/digicert-certcentral-caplugin/API/ListCertificateOrders.cs b/digicert-certcentral-caplugin/API/ListCertificateOrders.cs index 7a62f6d..73714c8 100644 --- a/digicert-certcentral-caplugin/API/ListCertificateOrders.cs +++ b/digicert-certcentral-caplugin/API/ListCertificateOrders.cs @@ -29,7 +29,8 @@ public ListCertificateOrdersRequest(bool ignoreExpired = false) public bool ignoreExpired { get; set; } public int expiredWindow { get; set; } = 0; - public string divID { get; set; } = string.Empty; + public List divIDs { get; set; } = new List(); + public List productIDs { get; set; } = new List(); public new string BuildParameters() { @@ -38,9 +39,13 @@ public ListCertificateOrdersRequest(bool ignoreExpired = false) sbParamters.Append("limit=").Append(this.limit.ToString()); sbParamters.Append("&offset=").Append(HttpUtility.UrlEncode(this.offset.ToString())); - if (!string.IsNullOrEmpty(divID)) + foreach (string divID in this.divIDs) { - sbParamters.Append("&filters[container_id]=").Append(this.divID); + sbParamters.Append("&filters[container_id]=").Append(divID); + } + foreach (string productID in productIDs) + { + sbParamters.Append("&filters[product_name_id]=").Append(productID); } if (ignoreExpired) { diff --git a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs index c71a6a2..0830e09 100644 --- a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs +++ b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs @@ -476,6 +476,13 @@ public Dictionary GetCAConnectorAnnotations() DefaultValue = "", Type = "String" }, + [CertCentralConstants.Config.SYNC_PROD_FILTER] = new PropertyConfigInfo() + { + Comments = "If you list one or more Product IDs here (comma-separated), the sync process will filter records to only return orders of those product types. Leave empty to sync all products.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, [CertCentralConstants.Config.FILTER_EXPIRED] = new PropertyConfigInfo() { Comments = "If set to 'true', syncing will apply a filter to not return orders that are expired for longer than specified in SyncExpirationDays.", @@ -834,12 +841,17 @@ public async Task Synchronize(BlockingCollection blockin caList.ForEach(c => c.ToUpper()); - List divFilters = null; + List divFilters = new List(); if (!string.IsNullOrEmpty(_config.SyncDivisionFilter)) { - divFilters = new List(); divFilters.AddRange(_config.SyncDivisionFilter.Split(',')); } + List productFilters = new List(); + if (!string.IsNullOrEmpty(_config.SyncProductFilter)) + { + _logger.LogTrace($"Sync Products: {_config.SyncProductFilter}"); + productFilters = _config.SyncProducts; + } if (fullSync) { @@ -857,37 +869,20 @@ public async Task Synchronize(BlockingCollection blockin long starttime = time; _logger.LogDebug($"SYNC: Starting sync at time {time}"); List allOrders = new List(); - if (divFilters != null) + + ListCertificateOrdersResponse ordersResponse = client.ListAllCertificateOrders(ignoreExpired, expiredWindow, divFilters, productFilters); + if (ordersResponse.Status == CertCentralBaseResponse.StatusType.ERROR) { - foreach (string div in divFilters) - { - ListCertificateOrdersResponse ordersResponse = client.ListAllCertificateOrders(ignoreExpired, expiredWindow, div); - if (ordersResponse.Status == CertCentralBaseResponse.StatusType.ERROR) - { - Error error = ordersResponse.Errors[0]; - _logger.LogError("Error in listing all certificate orders"); - throw new Exception($"DigiCert CertCentral web service returned {error.code} - {error.message} when retrieving all rows"); - } - else - { - allOrders.AddRange(ordersResponse.orders); - } - } + Error error = ordersResponse.Errors[0]; + _logger.LogError("Error in listing all certificate orders"); + throw new Exception($"DigiCert CertCentral web service returned {error.code} - {error.message} when retrieving all rows"); } else { - ListCertificateOrdersResponse ordersResponse = client.ListAllCertificateOrders(ignoreExpired, expiredWindow, null); - if (ordersResponse.Status == CertCentralBaseResponse.StatusType.ERROR) - { - Error error = ordersResponse.Errors[0]; - _logger.LogError("Error in listing all certificate orders"); - throw new Exception($"DigiCert CertCentral web service returned {error.code} - {error.message} when retrieving all rows"); - } - else - { - allOrders.AddRange(ordersResponse.orders); - } + allOrders.AddRange(ordersResponse.orders); } + + _logger.LogDebug($"SYNC: Found {allOrders.Count} records"); foreach (var orderDetails in allOrders) { @@ -897,7 +892,7 @@ public async Task Synchronize(BlockingCollection blockin cancelToken.ThrowIfCancellationRequested(); string caReqId = orderDetails.id + "-" + orderDetails.certificate.id; _logger.LogDebug($"SYNC: Retrieving certs for order id {orderDetails.id}"); - orderCerts = GetAllConnectorCertsForOrder(caReqId, caList, divFilters); + orderCerts = GetAllConnectorCertsForOrder(caReqId, caList, divFilters, productFilters); if (orderCerts == null || orderCerts.Count == 0) { continue; @@ -939,7 +934,7 @@ public async Task Synchronize(BlockingCollection blockin { cancelToken.ThrowIfCancellationRequested(); string caReqId = order.order_id + "-" + order.certificate_id; - orderCerts = GetAllConnectorCertsForOrder(caReqId, caList, divFilters); + orderCerts = GetAllConnectorCertsForOrder(caReqId, caList, divFilters, productFilters); if (orderCerts == null || orderCerts.Count > 0) { continue; @@ -1639,7 +1634,7 @@ string FormatSyncDate(DateTime? syncTime) /// /// /// - private List GetAllConnectorCertsForOrder(string caRequestID, List caFilterIds, List divIds) + private List GetAllConnectorCertsForOrder(string caRequestID, List caFilterIds, List divIds, List productIds) { _logger.MethodEntry(LogLevel.Trace); // Split ca request id into order and cert id @@ -1662,6 +1657,10 @@ private List GetAllConnectorCertsForOrder(string caReque _logger.LogTrace($"Found order ID {orderId} that does not match Division filter. Division ID: {orderResponse.container.Id.ToString()} Skipping..."); return null; } + if (productIds != null && productIds.Count > 0 && !productIds.Contains(orderResponse.product.name_id.ToString())) + { + _logger.LogTrace($"Found order ID {orderId} that does not match Product filter. Product ID: {orderResponse.product.name_id.ToString()} Skipping..."); + } var orderCerts = GetAllCertsForOrder(orderId); diff --git a/digicert-certcentral-caplugin/CertCentralConfig.cs b/digicert-certcentral-caplugin/CertCentralConfig.cs index fa3b354..6909c2e 100644 --- a/digicert-certcentral-caplugin/CertCentralConfig.cs +++ b/digicert-certcentral-caplugin/CertCentralConfig.cs @@ -33,6 +33,21 @@ public List SyncCAs } } } + public string SyncProductFilter { get; set; } + public List SyncProducts + { + get + { + if (!string.IsNullOrEmpty(SyncProductFilter)) + { + return SyncProductFilter.Split(",").ToList(); + } + else + { + return new List(); + } + } + } public bool? FilterExpiredOrders { get; set; } public int? SyncExpirationDays { get; set; } diff --git a/digicert-certcentral-caplugin/Client/CertCentralClient.cs b/digicert-certcentral-caplugin/Client/CertCentralClient.cs index fd9af77..753f54f 100644 --- a/digicert-certcentral-caplugin/Client/CertCentralClient.cs +++ b/digicert-certcentral-caplugin/Client/CertCentralClient.cs @@ -523,7 +523,7 @@ public DownloadCertificateByFormatResponse DownloadCertificateByFormat(DownloadC return dlCertificateRequestResponse; } - public ListCertificateOrdersResponse ListAllCertificateOrders(bool ignoreExpired = false, int expiredWindow = 0, string divId = "") + public ListCertificateOrdersResponse ListAllCertificateOrders(bool ignoreExpired, int expiredWindow, List divIds, List productIds) { int batch = 1000; ListCertificateOrdersResponse totalResponse = new ListCertificateOrdersResponse(); @@ -536,7 +536,8 @@ public ListCertificateOrdersResponse ListAllCertificateOrders(bool ignoreExpired offset = totalResponse.orders.Count, ignoreExpired = ignoreExpired, expiredWindow = expiredWindow, - divID = divId + divIDs = divIds, + productIDs = productIds }; CertCentralResponse response = Request(request, request.BuildParameters()); diff --git a/digicert-certcentral-caplugin/Constants.cs b/digicert-certcentral-caplugin/Constants.cs index 183a7cd..19fe860 100644 --- a/digicert-certcentral-caplugin/Constants.cs +++ b/digicert-certcentral-caplugin/Constants.cs @@ -30,6 +30,7 @@ public class Config public const string ENABLED = "Enabled"; public const string SYNC_CA_FILTER = "SyncCAFilter"; public const string SYNC_DIV_FILTER = "SyncDivisionFilter"; + public const string SYNC_PROD_FILTER = "SyncProductFilter"; public const string FILTER_EXPIRED = "FilterExpiredOrders"; public const string SYNC_EXPIRATION_DAYS = "SyncExpirationDays"; public const string CERT_TYPE = "CertType"; From babebc35eeb27e2d87ae561aae2b0056c23af018 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Tue, 30 Jun 2026 17:48:47 +0000 Subject: [PATCH 2/8] Update generated docs --- README.md | 1 + integration-manifest.json | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 6929905..4918513 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ An API Key within your Digicert account that has the necessary permissions to en * **RevokeCertificateOnly** - Default DigiCert behavior on revocation requests is to revoke the entire order. If this value is changed to 'true', revocation requests will instead just revoke the individual certificate. * **SyncCAFilter** - If you list one or more CA IDs here (comma-separated), the sync process will only sync records from those CAs. If you want to sync all CA IDs, leave this field empty. * **SyncDivisionFilter** - If you list one or more Divison IDs (also known as Container IDs) here (comma-separated), the sync process will filter records to only return orders from those divisions. If you want to sync all divisions, leave this field empty. Note that this has no relationship to the value of the DivisionId config field. + * **SyncProductFilter** - If you list one or more Product IDs here (comma-separated), the sync process will filter records to only return orders of those product types. Leave empty to sync all products. * **FilterExpiredOrders** - If set to 'true', syncing will apply a filter to not return orders that are expired for longer than specified in SyncExpirationDays. * **SyncExpirationDays** - If FilterExpiredOrders is set to true, this setting determines how many days in the past to still return expired orders. For example, a value of 30 means the sync will return any certs that expired within the past 30 days. A value of 0 means the sync will not return any certs that expired before the current day. This value is ignored if FilterExpiredOrders is false. * **Enabled** - Flag to Enable or Disable gateway functionality. Disabling is primarily used to allow creation of the CA prior to configuration information being available. diff --git a/integration-manifest.json b/integration-manifest.json index a854d2f..8cad8e9 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -38,6 +38,10 @@ "name": "SyncDivisionFilter", "description": "If you list one or more Divison IDs (also known as Container IDs) here (comma-separated), the sync process will filter records to only return orders from those divisions. If you want to sync all divisions, leave this field empty. Note that this has no relationship to the value of the DivisionId config field." }, + { + "name": "SyncProductFilter", + "description": "If you list one or more Product IDs here (comma-separated), the sync process will filter records to only return orders of those product types. Leave empty to sync all products." + }, { "name": "FilterExpiredOrders", "description": "If set to 'true', syncing will apply a filter to not return orders that are expired for longer than specified in SyncExpirationDays." From 9eaa6ea3a0617fc53aa3bdea04372ff9b0f4f42a Mon Sep 17 00:00:00 2001 From: David Galey Date: Wed, 1 Jul 2026 13:36:57 -0400 Subject: [PATCH 3/8] add Intel vPro EKU support --- .../CertCentralCAPlugin.cs | 20 +++++++++++++++---- digicert-certcentral-caplugin/Constants.cs | 1 + 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs index 0830e09..4b3b8b6 100644 --- a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs +++ b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs @@ -303,9 +303,10 @@ public async Task Enroll(string csr, string subject, Dictionar { bool clientAuth = Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_CLIENT_AUTH]); bool kdc = Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_KDC]); - if (clientAuth && kdc) + bool intel = Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_INTEL]); + if ((clientAuth ? 1 : 0) + (kdc ? 1 : 0) + (intel ? 1 : 0) >= 2) //If more than one EKU option is selected { - throw new Exception($"Cannot enroll for cert with both Client Auth and KDC/SmartCardLogon EKU set to 'true'"); + throw new Exception($"Cannot enroll for cert with more than one EKU option selected"); } if (clientAuth) { @@ -316,6 +317,10 @@ public async Task Enroll(string csr, string subject, Dictionar { orderRequest.Certificate.ProfileOption = "kdc_smart_card"; } + else if (intel) + { + orderRequest.Certificate.ProfileOption = "intel_vpro_eku"; + } } bool dupe = false; @@ -640,14 +645,21 @@ public Dictionary GetTemplateParameterAnnotations() }, [CertCentralConstants.Config.INCLUDE_CLIENT_AUTH] = new PropertyConfigInfo() { - Comments = "OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the Client Authentication EKU added to the request. NOTE: This feature is currently planned to be removed by DigiCert in March 2027.", + Comments = "OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the Client Authentication EKU added to the request. NOTE: Only one EKU option can be set for any given enrollment. NOTE: This feature is currently planned to be removed by DigiCert in March 2027.", Hidden = false, DefaultValue = false, Type = "Boolean" }, [CertCentralConstants.Config.INCLUDE_KDC] = new PropertyConfigInfo() { - Comments = "OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the KDC/SmartCardLogon EKU added to the request.", + Comments = "OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the KDC/SmartCardLogon EKU added to the request. NOTE: Only one EKU option can be set for any given enrollment.", + Hidden = false, + DefaultValue = false, + Type = "Boolean" + }, + [CertCentralConstants.Config.INCLUDE_INTEL] = new PropertyConfigInfo() + { + Comments = "OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the Intel vPro EKU added to the request. NOTE: Only one EKU option can be set for any given enrollment.", Hidden = false, DefaultValue = false, Type = "Boolean" diff --git a/digicert-certcentral-caplugin/Constants.cs b/digicert-certcentral-caplugin/Constants.cs index 19fe860..a01d8ca 100644 --- a/digicert-certcentral-caplugin/Constants.cs +++ b/digicert-certcentral-caplugin/Constants.cs @@ -36,6 +36,7 @@ public class Config public const string CERT_TYPE = "CertType"; public const string INCLUDE_CLIENT_AUTH = "IncludeClientAuthEKU"; public const string INCLUDE_KDC = "IncludeKDCSmartCardLogonEKU"; + public const string INCLUDE_INTEL = "IncludeIntelvProEKU"; public const string ENROLL_DIVISION_ID = "EnrollDivisionId"; public const string COMMON_NAME_INDICATOR = "CommonNameIndicator"; public const string PROFILE_TYPE = "ProfileType"; From 1df8750b561095481b7904c3e2956c6e4a798df6 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Wed, 1 Jul 2026 17:38:52 +0000 Subject: [PATCH 4/8] Update generated docs --- README.md | 5 +++-- integration-manifest.json | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4918513..6f735fc 100644 --- a/README.md +++ b/README.md @@ -107,8 +107,9 @@ An API Key within your Digicert account that has the necessary permissions to en * **Organization-Name** - OPTIONAL: For requests that will not have a subject (such as ACME) you can use this field to provide the organization name. Value supplied here will override any CSR values, so do not include this field if you want the organization from the CSR to be used. * **RenewalWindowDays** - OPTIONAL: The number of days from certificate expiration that the gateway should do a renewal rather than a reissue. If not provided, default is 90. * **CertType** - OPTIONAL: The type of cert to enroll for. Valid values are 'ssl' and 'client'. The value provided here must be consistant with the ProductID. If not provided, default is 'ssl'. Ignored for secure_email_* product types. - * **IncludeClientAuthEKU** - OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the Client Authentication EKU added to the request. NOTE: This feature is currently planned to be removed by DigiCert in March 2027. - * **IncludeKDCSmartCardLogonEKU** - OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the KDC/SmartCardLogon EKU added to the request. + * **IncludeClientAuthEKU** - OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the Client Authentication EKU added to the request. NOTE: Only one EKU option can be set for any given enrollment. NOTE: This feature is currently planned to be removed by DigiCert in March 2027. + * **IncludeKDCSmartCardLogonEKU** - OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the KDC/SmartCardLogon EKU added to the request. NOTE: Only one EKU option can be set for any given enrollment. + * **IncludeIntelvProEKU** - OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the Intel vPro EKU added to the request. NOTE: Only one EKU option can be set for any given enrollment. * **EnrollDivisionId** - OPTIONAL: The division (container) ID to use for enrollments against this template. * **CommonNameIndicator** - Required for secure_email_sponsor and secure_email_organization products, ignored otherwise. Defines the source of the common name. Valid values are: email_address, given_name_surname, pseudonym, organization_name * **ProfileType** - Optional for secure_email_* types, ignored otherwise. Valid values are: strict, multipurpose. Use 'multipurpose' if your cert includes any additional EKUs such as client auth. Default if not provided is dependent on product configuration within Digicert portal. diff --git a/integration-manifest.json b/integration-manifest.json index 8cad8e9..a30cc75 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -78,11 +78,15 @@ }, { "name": "IncludeClientAuthEKU", - "description": "OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the Client Authentication EKU added to the request. NOTE: This feature is currently planned to be removed by DigiCert in March 2027." + "description": "OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the Client Authentication EKU added to the request. NOTE: Only one EKU option can be set for any given enrollment. NOTE: This feature is currently planned to be removed by DigiCert in March 2027." }, { "name": "IncludeKDCSmartCardLogonEKU", - "description": "OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the KDC/SmartCardLogon EKU added to the request." + "description": "OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the KDC/SmartCardLogon EKU added to the request. NOTE: Only one EKU option can be set for any given enrollment." + }, + { + "name": "IncludeIntelvProEKU", + "description": "OPTIONAL for SSL certs, ignored otherwise. If set to 'true', SSL certs enrolled under this template will have the Intel vPro EKU added to the request. NOTE: Only one EKU option can be set for any given enrollment." }, { "name": "EnrollDivisionId", From c543fcbf74fcd97c0b7d9deb43018f10eeeb6d09 Mon Sep 17 00:00:00 2001 From: David Galey Date: Wed, 1 Jul 2026 13:53:40 -0400 Subject: [PATCH 5/8] fix for renewal of smime certs --- digicert-certcentral-caplugin/CertCentralCAPlugin.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs index 4b3b8b6..f40480f 100644 --- a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs +++ b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs @@ -2074,6 +2074,7 @@ private EnrollmentResult EnrollForSmimeCert(string csr, string subject, Dictiona if (enrollmentType == EnrollmentType.Renew) { + priorCertSnString = productInfo.ProductParameters["PriorCertSN"]; priorCertReqID = _certificateDataReader.GetRequestIDBySerialNumber(priorCertSnString).Result; if (string.IsNullOrEmpty(priorCertReqID)) { From c453bddfb0ab1067561acccd1a6961b1a56a1541 Mon Sep 17 00:00:00 2001 From: David Galey Date: Wed, 1 Jul 2026 14:10:31 -0400 Subject: [PATCH 6/8] validation for intel vpro eku --- digicert-certcentral-caplugin/CertCentralCAPlugin.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs index f40480f..caf6f1a 100644 --- a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs +++ b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs @@ -1129,7 +1129,7 @@ public async Task ValidateProductInfo(EnrollmentProductInfo productInfo, Diction } } - bool clientAuth = false, kdc = false; + bool clientAuth = false, kdc = false, intel = false; if (productInfo.ProductParameters.ContainsKey(CertCentralConstants.Config.INCLUDE_CLIENT_AUTH)) { clientAuth = Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_CLIENT_AUTH]); @@ -1138,9 +1138,13 @@ public async Task ValidateProductInfo(EnrollmentProductInfo productInfo, Diction { kdc = Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_KDC]); } - if (clientAuth && kdc) + if (productInfo.ProductParameters.ContainsKey(CertCentralConstants.Config.INCLUDE_INTEL)) { - throw new AnyCAValidationException($"Unable to use both {CertCentralConstants.Config.INCLUDE_CLIENT_AUTH} and {CertCentralConstants.Config.INCLUDE_KDC} in the same certificate."); + intel = Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_INTEL]); + } + if ((clientAuth ? 1 : 0) + (kdc ? 1 : 0) + (intel ? 1 : 0) >= 2) // If more than one EKU option is selected + { + throw new AnyCAValidationException($"Unable to use more than one of: {CertCentralConstants.Config.INCLUDE_CLIENT_AUTH}, {CertCentralConstants.Config.INCLUDE_KDC}, or {CertCentralConstants.Config.INCLUDE_INTEL} in the same certificate."); } _logger.MethodExit(LogLevel.Trace); From 126fd30f1e7c62a86d3ef28d6d1d5889720b3883 Mon Sep 17 00:00:00 2001 From: David Galey Date: Wed, 1 Jul 2026 14:36:49 -0400 Subject: [PATCH 7/8] fix for template validation --- digicert-certcentral-caplugin/CertCentralCAPlugin.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs index caf6f1a..cb1a503 100644 --- a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs +++ b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs @@ -1094,10 +1094,11 @@ public async Task ValidateProductInfo(EnrollmentProductInfo productInfo, Diction // Get product ID details. CertificateTypeDetailsRequest detailsRequest = new CertificateTypeDetailsRequest(product.NameId); + // For pulling product ID details, we use the Connection-level Division ID rather than the enrollment-level one. detailsRequest.ContainerId = null; - if (productInfo.ProductParameters.ContainsKey(CertCentralConstants.Config.ENROLL_DIVISION_ID)) + if (connectionInfo.ContainsKey(CertCentralConstants.Config.DIVISION_ID)) { - string div = productInfo.ProductParameters[CertCentralConstants.Config.ENROLL_DIVISION_ID].ToString(); + string div = connectionInfo[CertCentralConstants.Config.DIVISION_ID].ToString(); if (!string.IsNullOrWhiteSpace(div)) { if (int.TryParse($"{div}", out int divId)) From a8e6c5e99d2b210da097afda663e727ee357e265 Mon Sep 17 00:00:00 2001 From: David Galey Date: Thu, 2 Jul 2026 10:44:05 -0400 Subject: [PATCH 8/8] changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6df6ad5..4f81506 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,3 +30,9 @@ ### 2.3.0 * Add configuration flag to support adding KDC/SmartCardLogon EKU to ssl cert requests + +### 2.4.0 +* Add configuration flag to support Intel vPro EKU on ssl cert requests +* Add ability to filter sync by product ID +* Bug fix for SMIME cert renewal +* Bug fix for template validation