diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d223a9..7f09020 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,4 +23,7 @@ * Remove caching of product ID lookups from DigiCert account ### 2.2.0 -* Add support for duplicating certs \ No newline at end of file +* Add support for duplicating certs + +### 2.2.1 +* Properly mark 'needs_approval' status as Pending rather than Failed diff --git a/README.md b/README.md index 612f944..6929905 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs index 3c337eb..c71a6a2 100644 --- a/digicert-certcentral-caplugin/CertCentralCAPlugin.cs +++ b/digicert-certcentral-caplugin/CertCentralCAPlugin.cs @@ -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; @@ -126,12 +127,15 @@ public async Task 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().LastOrDefault(); organization = subjectParsed.GetValueList(X509Name.O).Cast().LastOrDefault(); orgUnit = subjectParsed.GetValueList(X509Name.OU).Cast().LastOrDefault(); } - catch (Exception) { } + catch (Exception exc) + { + _logger.LogInformation($"Error while parsing subject. This might be expected. Error message: {exc.Message}"); + } if (commonName == null) { @@ -295,10 +299,23 @@ public async Task 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; @@ -616,7 +633,14 @@ 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 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" @@ -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)) @@ -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); } diff --git a/digicert-certcentral-caplugin/Constants.cs b/digicert-certcentral-caplugin/Constants.cs index 2379499..183a7cd 100644 --- a/digicert-certcentral-caplugin/Constants.cs +++ b/digicert-certcentral-caplugin/Constants.cs @@ -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"; diff --git a/integration-manifest.json b/integration-manifest.json index e211f33..a854d2f 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -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",