From abea92ddcf9c3164922214490a99b4dae262a3a7 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Wed, 24 Jan 2024 00:34:00 +0000 Subject: [PATCH 1/8] 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/8] 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/8] 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/8] 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}"); From 36a2b9bb67872b6f6b472eab7bc19be60fbfc6b3 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Fri, 26 Jan 2024 09:26:51 -0500 Subject: [PATCH 5/8] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48b408d..5322b1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,5 @@ +1.0.10 +* Fixed bug with multiple DNS entries and fixed IP Sans issue + 1.0.9 * Initial Public Release Version From 6cdf908043bb5639c624abb544e10f3e43fdc942 Mon Sep 17 00:00:00 2001 From: Michael Henderson Date: Fri, 26 Jan 2024 07:09:45 -0800 Subject: [PATCH 6/8] Update workflow --- .../workflows/keyfactor-starter-workflow.yml | 54 ++++++------------- integration-manifest.json | 18 ++++--- 2 files changed, 26 insertions(+), 46 deletions(-) diff --git a/.github/workflows/keyfactor-starter-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml index ce3cfbe..6d8de53 100644 --- a/.github/workflows/keyfactor-starter-workflow.yml +++ b/.github/workflows/keyfactor-starter-workflow.yml @@ -1,41 +1,19 @@ -name: Starter Workflow -on: [workflow_dispatch, push, pull_request] +name: Keyfactor Bootstrap Workflow -jobs: - call-create-github-release-workflow: - uses: Keyfactor/actions/.github/workflows/github-release.yml@main - get-manifest-properties: - runs-on: windows-latest - outputs: - update_catalog: ${{ steps.read-json.outputs.prop }} - steps: - - uses: actions/checkout@v3 - - name: Read json - id: read-json - shell: pwsh - run: | - $json = Get-Content integration-manifest.json | ConvertFrom-Json - echo "::set-output name=prop::$(echo $json.update_catalog)" - - call-dotnet-build-and-release-workflow: - needs: [call-create-github-release-workflow] - uses: Keyfactor/actions/.github/workflows/dotnet-build-and-release.yml@main - with: - release_version: ${{ needs.call-create-github-release-workflow.outputs.release_version }} - release_url: ${{ needs.call-create-github-release-workflow.outputs.release_url }} - release_dir: DigiCertSymCaProxy\bin\Release - secrets: - token: ${{ secrets.PRIVATE_PACKAGE_ACCESS }} +on: + workflow_dispatch: + pull_request: + types: [opened, closed, synchronize, edited, reopened] + push: + create: + branches: + - 'release-*.*' - call-generate-readme-workflow: - if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' - uses: Keyfactor/actions/.github/workflows/generate-readme.yml@main +jobs: + call-starter-workflow: + uses: keyfactor/actions/.github/workflows/starter.yml@v2 secrets: - token: ${{ secrets.APPROVE_README_PUSH }} - - call-update-catalog-workflow: - needs: get-manifest-properties - if: needs.get-manifest-properties.outputs.update_catalog == 'True' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') - uses: Keyfactor/actions/.github/workflows/update-catalog.yml@main - secrets: - token: ${{ secrets.SDK_SYNC_PAT }} + token: ${{ secrets.V2BUILDTOKEN}} + APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} + gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} + gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} diff --git a/integration-manifest.json b/integration-manifest.json index 5a2a623..efef0ab 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -1,10 +1,12 @@ { - "$schema": "https://keyfactor.github.io/integration-manifest-schema.json", - "integration_type": "ca-gateway", - "name": "DigiCert mPKI AnyGateway", - "status": "production", - "update_catalog": false, - "link_github": false, - "gateway_framework": "22.1.1", - "description": "This gateway integration supports the Digicert MPKI platform. It handles Enrollment, Renewal, Revoke and inventory by multiple seat Ids." + "$schema": "https://keyfactor.github.io/integration-manifest-schema.json", + "integration_type": "ca-gateway", + "name": "DigiCert mPKI AnyGateway", + "status": "production", + "update_catalog": false, + "link_github": false, + "support_level": "kf-supported", + "gateway_framework": "22.1.1", + "release_dir": "DigiCertSymCaProxy/bin/Release", + "description": "This gateway integration supports the Digicert MPKI platform. It handles Enrollment, Renewal, Revoke and inventory by multiple seat Ids." } From cd270496fa436f44f16fe873cf141423e86d38ff Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Fri, 26 Jan 2024 15:10:20 +0000 Subject: [PATCH 7/8] Update generated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe2bf77..69e780c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This repository contains an AnyGateway CA Connector, which is a plugin to the Ke ## Support for DigiCert mPKI AnyGateway -DigiCert mPKI AnyGateway +DigiCert mPKI AnyGateway is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com ###### 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 5e88260e6a11f86cf551b4667b99487fceb3de0a Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Wed, 31 Jan 2024 14:42:05 -0500 Subject: [PATCH 8/8] removed version --- readme_source.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme_source.md b/readme_source.md index 8ade144..f6da702 100644 --- a/readme_source.md +++ b/readme_source.md @@ -1,6 +1,6 @@ # Getting Started ## Standard Gateway Installation -To begin, you must have the CA Gateway Service 21.3.2 installed and operational before attempting to configure the DigiCertSym mPKI plugin. This integration was tested with Keyfactor 9.1.0.0. +To begin, you must have the CA Gateway Service installed and operational before attempting to configure the DigiCertSym mPKI plugin. This integration was tested with Keyfactor 9.1.0.0. To install the gateway follow these instructions. 1) **Gateway Server** - Get the latest gateway .msi installer from Keyfactor and run the installation on the gateway server.