Skip to content
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,10 @@
* Remove caching of product ID lookups from DigiCert account

### 2.2.0
* Add support for duplicating certs
* Add support for duplicating certs

### 2.2.1
* Properly mark 'needs_approval' status as Pending rather than Failed

### 2.3.0
* Add configuration flag to support adding KDC/SmartCardLogon EKU to ssl cert requests
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ 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 May 2026.
* **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.
* **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.
Expand Down
59 changes: 49 additions & 10 deletions digicert-certcentral-caplugin/CertCentralCAPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Keyfactor.Extensions.CAPlugin.DigiCert.Client;
using Keyfactor.Extensions.CAPlugin.DigiCert.Models;
using Keyfactor.Logging;
using Keyfactor.PKI;
using Keyfactor.PKI.Enums;
using Keyfactor.PKI.Enums.EJBCA;

Expand Down Expand Up @@ -126,12 +127,15 @@ public async Task<EnrollmentResult> Enroll(string csr, string subject, Dictionar
string commonName = null, organization = null, orgUnit = null;
try
{
subjectParsed = new X509Name(subject);
subjectParsed = new X509Name(true, PKIConstants.X509.OIDLookup, subject);
commonName = subjectParsed.GetValueList(X509Name.CN).Cast<string>().LastOrDefault();
organization = subjectParsed.GetValueList(X509Name.O).Cast<string>().LastOrDefault();
orgUnit = subjectParsed.GetValueList(X509Name.OU).Cast<string>().LastOrDefault();
}
catch (Exception) { }
catch (Exception exc)
{
_logger.LogInformation($"Error while parsing subject. This might be expected. Error message: {exc.Message}");
}

if (commonName == null)
{
Expand Down Expand Up @@ -295,10 +299,23 @@ public async Task<EnrollmentResult> Enroll(string csr, string subject, Dictionar
string priorCertSnString = null;
string priorCertReqID = null;

if (typeOfCert.Equals("ssl") && Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_CLIENT_AUTH]))
if (typeOfCert.Equals("ssl"))
{
orderRequest.Certificate.ProfileOption = "server_client_auth_eku";
_logger.LogWarning($"{CertCentralConstants.Config.INCLUDE_CLIENT_AUTH}: Ability to include client auth EKU in SSL certs is currently planned to cease in May 2026. Make sure any workflows that depend on this feature are updated before then to avoid interruptions.");
bool clientAuth = Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_CLIENT_AUTH]);
bool kdc = Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_KDC]);
if (clientAuth && kdc)
{
throw new Exception($"Cannot enroll for cert with both Client Auth and KDC/SmartCardLogon EKU set to 'true'");
}
if (clientAuth)
{
orderRequest.Certificate.ProfileOption = "server_client_auth_eku";
_logger.LogWarning($"{CertCentralConstants.Config.INCLUDE_CLIENT_AUTH}: Ability to include client auth EKU in SSL certs is currently planned to cease in March 2027. Make sure any workflows that depend on this feature are updated before then to avoid interruptions.");
}
else if (kdc)
{
orderRequest.Certificate.ProfileOption = "kdc_smart_card";
}
}

bool dupe = false;
Expand Down Expand Up @@ -616,7 +633,14 @@ public Dictionary<string, PropertyConfigInfo> 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 May 2026.",
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.",
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.",
Hidden = false,
DefaultValue = false,
Type = "Boolean"
Expand Down Expand Up @@ -1064,9 +1088,9 @@ public async Task ValidateProductInfo(EnrollmentProductInfo productInfo, Diction
CertificateTypeDetailsRequest detailsRequest = new CertificateTypeDetailsRequest(product.NameId);

detailsRequest.ContainerId = null;
if (connectionInfo.ContainsKey(CertCentralConstants.Config.DIVISION_ID))
if (productInfo.ProductParameters.ContainsKey(CertCentralConstants.Config.ENROLL_DIVISION_ID))
{
string div = connectionInfo[CertCentralConstants.Config.DIVISION_ID].ToString();
string div = productInfo.ProductParameters[CertCentralConstants.Config.ENROLL_DIVISION_ID].ToString();
if (!string.IsNullOrWhiteSpace(div))
{
if (int.TryParse($"{div}", out int divId))
Expand All @@ -1088,15 +1112,30 @@ public async Task ValidateProductInfo(EnrollmentProductInfo productInfo, Diction

if (!Constants.ProductTypes.SMIME_CERT.Contains(productInfo.ProductID, StringComparer.OrdinalIgnoreCase))
{
if (connectionInfo.ContainsKey(CertCentralConstants.Config.CERT_TYPE))
if (productInfo.ProductParameters.ContainsKey(CertCentralConstants.Config.CERT_TYPE))
{
var typeOfCert = (string)connectionInfo[CertCentralConstants.Config.CERT_TYPE];
var typeOfCert = (string)productInfo.ProductParameters[CertCentralConstants.Config.CERT_TYPE];
if (!(typeOfCert.Equals("ssl") || typeOfCert.Equals("client")))
{
throw new AnyCAValidationException("Invalid Cert Type specified. Valid options are 'ssl' or 'client'");
}
}
}

bool clientAuth = false, kdc = false;
if (productInfo.ProductParameters.ContainsKey(CertCentralConstants.Config.INCLUDE_CLIENT_AUTH))
{
clientAuth = Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_CLIENT_AUTH]);
}
if (productInfo.ProductParameters.ContainsKey(CertCentralConstants.Config.INCLUDE_KDC))
{
kdc = Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_KDC]);
}
if (clientAuth && kdc)
{
throw new AnyCAValidationException($"Unable to use both {CertCentralConstants.Config.INCLUDE_CLIENT_AUTH} and {CertCentralConstants.Config.INCLUDE_KDC} in the same certificate.");
}

_logger.MethodExit(LogLevel.Trace);
}

Expand Down
1 change: 1 addition & 0 deletions digicert-certcentral-caplugin/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class Config
public const string SYNC_EXPIRATION_DAYS = "SyncExpirationDays";
public const string CERT_TYPE = "CertType";
public const string INCLUDE_CLIENT_AUTH = "IncludeClientAuthEKU";
public const string INCLUDE_KDC = "IncludeKDCSmartCardLogonEKU";
public const string ENROLL_DIVISION_ID = "EnrollDivisionId";
public const string COMMON_NAME_INDICATOR = "CommonNameIndicator";
public const string PROFILE_TYPE = "ProfileType";
Expand Down
6 changes: 5 additions & 1 deletion integration-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@
},
{
"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 May 2026."
"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."
},
{
"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."
},
{
"name": "EnrollDivisionId",
Expand Down
Loading