From abea92ddcf9c3164922214490a99b4dae262a3a7 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Wed, 24 Jan 2024 00:34:00 +0000 Subject: [PATCH 1/4] Fixed Multi domain Issue --- DigiCertSymCaProxy/Client/Models/San.cs | 2 +- DigiCertSymCaProxy/RequestManager.cs | 172 +++++++++++++----------- 2 files changed, 95 insertions(+), 79 deletions(-) diff --git a/DigiCertSymCaProxy/Client/Models/San.cs b/DigiCertSymCaProxy/Client/Models/San.cs index 55575d8..37b014c 100644 --- a/DigiCertSymCaProxy/Client/Models/San.cs +++ b/DigiCertSymCaProxy/Client/Models/San.cs @@ -22,6 +22,6 @@ public class San : ISan [JsonProperty("other_name", NullValueHandling = NullValueHandling.Ignore)] public List OtherName { get; set; } [JsonProperty("registered_id", NullValueHandling = NullValueHandling.Ignore)] public List RegisteredId { get; set; } [JsonProperty("rfc822_name", NullValueHandling = NullValueHandling.Ignore)] public List Rfc822Name { get; set; } - [JsonProperty("user_principal_name", NullValueHandling = NullValueHandling.Ignore)] public List UserPrincipalName { get; set; } + [JsonProperty("user_principal_name", NullValueHandling = NullValueHandling.Ignore)] public List UserPrincipalName { get; set; } } } diff --git a/DigiCertSymCaProxy/RequestManager.cs b/DigiCertSymCaProxy/RequestManager.cs index c8db8a4..dd16d2b 100644 --- a/DigiCertSymCaProxy/RequestManager.cs +++ b/DigiCertSymCaProxy/RequestManager.cs @@ -1,13 +1,13 @@ -// Copyright 2023 Keyfactor -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a -// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless -// required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES -// OR CONDITIONS OF ANY KIND, either express or implied. See the License for -// thespecific language governing permissions and limitations under the -// License. -using System; +// Copyright 2023 Keyfactor +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +// required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +// OR CONDITIONS OF ANY KIND, either express or implied. See the License for +// thespecific language governing permissions and limitations under the +// License. +using System; using System.Collections.Generic; using System.IO; using System.Reflection; @@ -23,6 +23,7 @@ using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Pkcs; +using System.Linq; namespace Keyfactor.AnyGateway.DigiCertSym { @@ -232,6 +233,49 @@ public SearchCertificateRequestType GetSearchCertificatesRequest(int pageCounter } } + private (Dictionary DNSOut, Dictionary MultiOut) ProcessSansArray( + string[] sanArray, string commonName) + { + Dictionary dnsOut = new Dictionary(); + Dictionary multiOut = new Dictionary(); + + if (sanArray.Length == 1) + { + var singleItem = sanArray.First(); + if (singleItem == commonName || string.IsNullOrWhiteSpace(commonName)) + { + dnsOut.Add(singleItem, singleItem); + } + else + { + throw new InvalidOperationException("Error: Single item does not match CommonName."); + } + } + else if (sanArray.Length > 1) + { + if (!string.IsNullOrWhiteSpace(commonName)) + { + if (!sanArray.Contains(commonName)) + { + throw new InvalidOperationException("Error: Multiple items, none of them match CommonName."); + } + else + { + dnsOut.Add(commonName, commonName); + multiOut = sanArray.Where(item => item != commonName) + .ToDictionary(item => item, item => item); + } + } + else + { + dnsOut.Add(sanArray.First(), sanArray.First()); + multiOut = sanArray.Skip(1).ToDictionary(item => item, item => item); + } + } + + return (dnsOut, multiOut); + } + public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, string csr, Dictionary san) { @@ -303,38 +347,46 @@ public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, Logger.Trace($"Enrollment Serialized JSON before DNS and OU, result: {JsonConvert.SerializeObject(enrollmentRequest)}"); - //5. Loop through DNS Entries, if coming from Cert bot, then need to get common name from here as well + Dictionary MultiOut=null; + + List dnsList = new List(); + + //5. If it contains the dns and it is not multi domain get the DNS if (san.ContainsKey("dns")) { - var dnsList = new List(); var dnsKp = san["dns"]; Logger.Trace($"dnsKP: {dnsKp}"); - var commonNameList = new List(); - var j = 1; - foreach (var item in dnsKp) + (Dictionary DNSOut, Dictionary MultiOut) result; + + if (!getCommonNameFromSubject) { - commonNameList.Add(item); - if (j < 2) - { - DnsName dns = new DnsName { Id = DnsConstantName, Value = item }; - dnsList.Add(dns); - } - else - { - DnsName dns = new DnsName { Id = DnsConstantName + j, Value = item }; - dnsList.Add(dns); - } - j++; + //Cert Bot flow, Cert Bot has no common name and the dns comes from the SAN blank for common name returns first DNS + result = ProcessSansArray(dnsKp, ""); } - string commonName = string.Join(",", commonNameList); + else + { + result = ProcessSansArray(dnsKp, enrollmentRequest?.Attributes?.CommonName); + } + + DnsName up = new DnsName { Id = DnsConstantName, Value = result.DNSOut.FirstOrDefault().Value }; + MultiOut = result.MultiOut; var jsonResultDns = JsonConvert.SerializeObject(enrollmentRequest); if (!getCommonNameFromSubject) - jsonResultDns = ReplaceCsrEntry(new[] { "CN", commonName }, jsonResult); + jsonResultDns = ReplaceCsrEntry(new[] { "CN", result.DNSOut.FirstOrDefault().Value }, jsonResult); enrollmentRequest = JsonConvert.DeserializeObject(jsonResultDns); + dnsList.Add(up); + + //5. Handle the multiple domain scenario domains go in a different attribute + if (MultiOut?.Count > 0) + { + DnsName mdns = new DnsName { Id = "custom_encode_dnsName_multi", Value = string.Join(",", MultiOut.Values) }; + dnsList.Add(mdns); + } + sn.DnsName = dnsList; } @@ -346,47 +398,23 @@ public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, Logger.Trace($"upn: {upKp}"); - var k = 1; - foreach (var item in upKp) - { - if (k < 2) - { - UserPrincipalName up = new UserPrincipalName { Id = UpnConstantName, Value = item }; - upList.Add(up); - } - else - { - UserPrincipalName up = new UserPrincipalName { Id = UpnConstantName + k, Value = item }; - upList.Add(up); - } - k++; - } + //Multiple UPNs not supported by Digicert so take the first one in the list + UserPrincipalName up = new UserPrincipalName { Id = UpnConstantName, Value = upKp.FirstOrDefault() }; + upList.Add(up); sn.UserPrincipalName = upList; } //7. Loop through IP Entries - if (san.ContainsKey("ip4") || san.ContainsKey("ip6")) + if (san.ContainsKey("ipaddress")) { var ipList = new List(); - var ipKp = san.ContainsKey("ip4") ? san["ip4"] : san["ip6"]; + var ipKp = san["ipaddress"]; Logger.Trace($"ip: {ipKp}"); - var k = 1; - foreach (var item in ipKp) - { - if (k < 2) - { - IpAddress ip = new IpAddress { Id = IpConstantName, Value = item }; - ipList.Add(ip); - } - else - { - IpAddress ip = new IpAddress { Id = IpConstantName + k, Value = item }; - ipList.Add(ip); - } - k++; - } + //Multiple IP Addresses not supported by Digicert so take the first one in the list + IpAddress ip = new IpAddress { Id = IpConstantName, Value = ipKp.FirstOrDefault() }; + ipList.Add(ip); sn.IpAddress = ipList; } @@ -398,21 +426,9 @@ public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, Logger.Trace($"mail: {mailKp}"); - var k = 1; - foreach (var item in mailKp) - { - if (k < 2) - { - Rfc822Name mail = new Rfc822Name { Id = EmailConstantName, Value = item }; - mailList.Add(mail); - } - else - { - Rfc822Name mail = new Rfc822Name { Id = EmailConstantName + k, Value = item }; - mailList.Add(mail); - } - k++; - } + //Multiple IP Addresses not supported by Digicert so take the first one in the list + Rfc822Name mail = new Rfc822Name { Id = EmailConstantName, Value = mailKp.FirstOrDefault() }; + mailList.Add(mail); sn.Rfc822Name = mailList; } @@ -425,11 +441,11 @@ public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, var i = OuStartPoint; foreach (var ou in organizationalUnits) { - var organizationUnit = new OrganizationUnit { Id = OuStartPoint==0?"cert_org_unit":"cert_org_unit" + i, Value = ou }; + var organizationUnit = new OrganizationUnit { Id = OuStartPoint == 0 ? "cert_org_unit" : "cert_org_unit" + i, Value = ou }; orgUnits.Add(organizationUnit); i++; } - + var attributes = enrollmentRequest.Attributes; attributes.OrganizationUnit = orgUnits; attributes.San = sn; From f7df018b8fa49e74097ed653972334a26e47c6f5 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Wed, 24 Jan 2024 00:34:36 +0000 Subject: [PATCH 2/4] Update generated README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3864bdb..fe2bf77 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,11 @@ This gateway integration supports the Digicert MPKI platform. It handles Enrollm This repository contains an AnyGateway CA Connector, which is a plugin to the Keyfactor AnyGateway. AnyGateway CA Connectors allow Keyfactor Command to be used for inventory, issuance, and revocation of certificates from a third-party certificate authority. +## Support for DigiCert mPKI AnyGateway +DigiCert mPKI AnyGateway + +###### To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. --- From 7c0267b1b079fdda2c7adada82ca85c95a266ae9 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Thu, 25 Jan 2024 14:28:53 +0000 Subject: [PATCH 3/4] Cleand up error conditions --- DigiCertSymCaProxy/DigiCertSymProxy.cs | 3 +++ DigiCertSymCaProxy/RequestManager.cs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/DigiCertSymCaProxy/DigiCertSymProxy.cs b/DigiCertSymCaProxy/DigiCertSymProxy.cs index 672df4f..0a09ce9 100644 --- a/DigiCertSymCaProxy/DigiCertSymProxy.cs +++ b/DigiCertSymCaProxy/DigiCertSymProxy.cs @@ -283,6 +283,9 @@ public override CAConnectorCertificate GetSingleRecord(string caRequestId) try { Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + if (string.IsNullOrEmpty(caRequestId)) + return null; + var keyfactorCaId = caRequestId; Logger.Trace($"Keyfactor Ca Id: {keyfactorCaId}"); var certificateResponse = diff --git a/DigiCertSymCaProxy/RequestManager.cs b/DigiCertSymCaProxy/RequestManager.cs index dd16d2b..4941b21 100644 --- a/DigiCertSymCaProxy/RequestManager.cs +++ b/DigiCertSymCaProxy/RequestManager.cs @@ -479,8 +479,8 @@ public EnrollmentResult return new EnrollmentResult { Status = (int)PKIConstants.Microsoft.RequestDisposition.ISSUED, //success - CARequestID = enrollmentResponse.Result.SerialNumber, - Certificate = cert.Certificate, + CARequestID = enrollmentResponse?.Result?.SerialNumber, + Certificate = cert?.Certificate, StatusMessage = $"Order Successfully Created With Order Number {enrollmentResponse.Result.SerialNumber}" }; From a5aef3b3e232d392541da737f01ec30ef05d0cdb Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Thu, 25 Jan 2024 16:47:20 +0000 Subject: [PATCH 4/4] Fixed Email Enrollment --- DigiCertSymCaProxy/RequestManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DigiCertSymCaProxy/RequestManager.cs b/DigiCertSymCaProxy/RequestManager.cs index 4941b21..a414aeb 100644 --- a/DigiCertSymCaProxy/RequestManager.cs +++ b/DigiCertSymCaProxy/RequestManager.cs @@ -419,10 +419,10 @@ public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, } //8. Loop through mail Entries - if (san.ContainsKey("mail")) + if (san.ContainsKey("email")) { var mailList = new List(); - var mailKp = san["mail"]; + var mailKp = san["email"]; Logger.Trace($"mail: {mailKp}");