Skip to content

Commit

Permalink
Merge pull request #15 from Keyfactor/release1.0_dev
Browse files Browse the repository at this point in the history
Release1.0.10
  • Loading branch information
fiddlermikey committed Feb 2, 2024
2 parents 46b4c0e + 3fc187b commit 418af78
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 133 deletions.
54 changes: 16 additions & 38 deletions .github/workflows/keyfactor-starter-workflow.yml
Original file line number Diff line number Diff line change
@@ -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 }}
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion DigiCertSymCaProxy/Client/Models/San.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ public class San : ISan
[JsonProperty("other_name", NullValueHandling = NullValueHandling.Ignore)] public List<OtherName> OtherName { get; set; }
[JsonProperty("registered_id", NullValueHandling = NullValueHandling.Ignore)] public List<RegisteredId> RegisteredId { get; set; }
[JsonProperty("rfc822_name", NullValueHandling = NullValueHandling.Ignore)] public List<Rfc822Name> Rfc822Name { get; set; }
[JsonProperty("user_principal_name", NullValueHandling = NullValueHandling.Ignore)] public List<UserPrincipalName> UserPrincipalName { get; set; }
[JsonProperty("user_principal_name", NullValueHandling = NullValueHandling.Ignore)] public List<UserPrincipalName> UserPrincipalName { get; set; }
}
}
3 changes: 3 additions & 0 deletions DigiCertSymCaProxy/DigiCertSymProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
180 changes: 98 additions & 82 deletions DigiCertSymCaProxy/RequestManager.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -23,6 +23,7 @@
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using System.Linq;

namespace Keyfactor.AnyGateway.DigiCertSym
{
Expand Down Expand Up @@ -232,6 +233,49 @@ public SearchCertificateRequestType GetSearchCertificatesRequest(int pageCounter
}
}

private (Dictionary<string, string> DNSOut, Dictionary<string, string> MultiOut) ProcessSansArray(
string[] sanArray, string commonName)
{
Dictionary<string, string> dnsOut = new Dictionary<string, string>();
Dictionary<string, string> multiOut = new Dictionary<string, string>();

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<string, string[]> san)
{
Expand Down Expand Up @@ -303,38 +347,46 @@ public SearchCertificateRequestType GetSearchCertificatesRequest(int pageCounter

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<string, string> MultiOut=null;

List<DnsName> dnsList = new List<DnsName>();

//5. If it contains the dns and it is not multi domain get the DNS
if (san.ContainsKey("dns"))
{
var dnsList = new List<DnsName>();
var dnsKp = san["dns"];
Logger.Trace($"dnsKP: {dnsKp}");
var commonNameList = new List<string>();

var j = 1;
foreach (var item in dnsKp)
(Dictionary<string, string> DNSOut, Dictionary<string, string> 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<EnrollmentRequest>(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;
}

Expand All @@ -346,73 +398,37 @@ public SearchCertificateRequestType GetSearchCertificatesRequest(int pageCounter

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<IpAddress>();

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;
}

//8. Loop through mail Entries
if (san.ContainsKey("mail"))
if (san.ContainsKey("email"))
{
var mailList = new List<Rfc822Name>();
var mailKp = san["mail"];
var mailKp = san["email"];

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;
}

Expand All @@ -425,11 +441,11 @@ public SearchCertificateRequestType GetSearchCertificatesRequest(int pageCounter
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;
Expand Down Expand Up @@ -463,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}"
};
Expand Down
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@

# DigiCert mPKI AnyGateway

This gateway integration supports the Digicert MPKI platform. It handles Enrollment, Renewal, Revoke and inventory by multiple seat Ids.

#### Integration status: Production - Ready for use in production environments.


## About the Keyfactor AnyGateway CA Connector

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 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.

---


---




Expand All @@ -24,14 +28,16 @@ This repository contains an AnyGateway CA Connector, which is a plugin to the Ke

This gateway was compiled against version 22.1.1 of the AnyGateway Framework. You will need at least this version of the AnyGateway Framework Installed. If you have a later AnyGateway Framework Installed you will probably need to add binding redirects in the CAProxyServer.exe.config file to make things work properly.

[Keyfactor CAGateway Install Guide](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Introduction.htm)



---


# 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.
Expand Down
Loading

0 comments on commit 418af78

Please sign in to comment.