Skip to content

Commit

Permalink
Merge pull request #27 from Keyfactor/dev-1.2
Browse files Browse the repository at this point in the history
Fixes ab#48215,ab#54658,ab#51327
ab#47288
  • Loading branch information
fiddlermikey authored Apr 15, 2024
2 parents 26810c5 + 8166f07 commit f65a6c6
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 63 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/keyfactor-bootstrap-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Keyfactor Bootstrap Workflow

on:
workflow_dispatch:
pull_request:
types: [opened, closed, synchronize, edited, reopened]
push:
create:
branches:
- 'release-*.*'

jobs:
call-starter-workflow:
uses: keyfactor/actions/.github/workflows/starter.yml@v2
secrets:
token: ${{ secrets.V2BUILDTOKEN}}
APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}}
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }}
42 changes: 0 additions & 42 deletions .github/workflows/keyfactor-starter-workflow.yml

This file was deleted.

5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@
# 1.0.10
* Handle change to Sectigo API for organization/department lookups
# 1.1.0
* Allow organization name to be provided in the template section of the config
* Allow organization name to be provided in the template section of the config
# 1.2.0
* Allow for blank CN to be provided
* Fixes for Certificate Authentication
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@

# Sectigo Certificate Manager

Sectigo Certificate Manager is a private certificate authority designed for enterprise use. The Sectigo Gateway enables the following certificate authority management functions via Keyfactor Command: Enrollment of new certificates, Revocation of existing certificates, and Synchronization of previously issued certificates.

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

## About the Keyfactor AnyCA Gateway DCOM Connector

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

This repository contains an AnyCA Gateway Connector, which is a plugin to the Keyfactor AnyGateway. AnyCA Gateway Connectors allow Keyfactor Command to be used for inventory, issuance, and revocation of certificates from a third-party certificate authority.

## Support for Sectigo Certificate Manager

Sectigo Certificate Manager
Sectigo Certificate Manager 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.

---


---





## Keyfactor AnyCA Gateway Framework Supported
The Keyfactor gateway framework implements common logic shared across various gateway implementations and handles communication with Keyfactor Command. The gateway framework hosts gateway implementations or plugins that understand how to communicate with specific CAs. This allows you to integrate your third-party CAs with Keyfactor Command such that they behave in a manner similar to the CAs natively supported by Keyfactor Command.




This gateway extension was compiled against version of the AnyCA Gateway DCOM Framework. You will need at least this version of the 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)



Expand Down Expand Up @@ -52,14 +63,18 @@ Additional information about [Sectigo Certificate Manager](https://sectigo.com/k
* Code Signing

## Compatibility
This AnyGateway is designed to be used with version 21.3.2 of the Keyfactor AnyGateway Framework
This AnyGateway is designed to be used with version 21.3.2 or newer of the Keyfactor AnyGateway DCOM Framework

## Prerequisites

### Certificate Chain

In order to enroll for certificates the Keyfactor Command server must trust the trust chain. Once you create your Root and/or Subordinate CA, make sure to import the certificate chain into the Command Server certificate store

### Sectigo Settings
For each Organization/Department you plan on using through the gateway, in your Sectigo portal, go to that Organization, select Certificate Settings -> SSL Certificates, and check the "Enable Web/REST API" checkbox.
In addition, for the admin account you plan to use, make sure it has the API admin type selected in the portal.

### Migration
In the event that a system is being upgraded from the Legacy Sectigo CA Gateway (19.4 or older), a migration from the legacy database format to the AnyGateway format will be required.

Expand Down
3 changes: 3 additions & 0 deletions integration-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"integration_type": "ca-gateway",
"name": "Sectigo Certificate Manager",
"status": "production",
"update_catalog": true,
"link_github": true,
"release_dir": "src/SectigoCAProxy/bin/Release",
"support_level": "kf-supported",
"description": "Sectigo Certificate Manager is a private certificate authority designed for enterprise use. The Sectigo Gateway enables the following certificate authority management functions via Keyfactor Command: Enrollment of new certificates, Revocation of existing certificates, and Synchronization of previously issued certificates."
}
6 changes: 5 additions & 1 deletion readme_source.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,18 @@ Additional information about [Sectigo Certificate Manager](https://sectigo.com/k
* Code Signing

## Compatibility
This AnyGateway is designed to be used with version 21.3.2 of the Keyfactor AnyGateway Framework
This AnyGateway is designed to be used with version 21.3.2 or newer of the Keyfactor AnyGateway DCOM Framework

## Prerequisites

### Certificate Chain

In order to enroll for certificates the Keyfactor Command server must trust the trust chain. Once you create your Root and/or Subordinate CA, make sure to import the certificate chain into the Command Server certificate store

### Sectigo Settings
For each Organization/Department you plan on using through the gateway, in your Sectigo portal, go to that Organization, select Certificate Settings -> SSL Certificates, and check the "Enable Web/REST API" checkbox.
In addition, for the admin account you plan to use, make sure it has the API admin type selected in the portal.

### Migration
In the event that a system is being upgraded from the Legacy Sectigo CA Gateway (19.4 or older), a migration from the legacy database format to the AnyGateway format will be required.

Expand Down
14 changes: 7 additions & 7 deletions src/SectigoCAProxy/Client/SectigoApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public SectigoApiClient(HttpClient httpClient)

public async Task<Certificate> GetCertificate(int sslId)
{
var response = await RestClient.GetAsync($"/api/ssl/v1/{sslId}");
var response = await RestClient.GetAsync($"api/ssl/v1/{sslId}");
return await ProcessResponse<Certificate>(response);
}

Expand Down Expand Up @@ -197,7 +197,7 @@ public async Task<ListPersonsResponse> ListPersons(int orgId)

public async Task<ListCustomFieldsResponse> ListCustomFields()
{
var response = await RestClient.GetAsync("/api/ssl/v1/customFields");
var response = await RestClient.GetAsync("api/ssl/v1/customFields");
return new ListCustomFieldsResponse { CustomFields = await ProcessResponse<List<CustomField>>(response) };
}

Expand All @@ -209,7 +209,7 @@ public async Task<ListSslProfilesResponse> ListSslProfiles(int? orgId = null)
urlSuffix = $"?organizationId={orgId}";
}

var response = await RestClient.GetAsync($"/api/ssl/v1/types{urlSuffix}");
var response = await RestClient.GetAsync($"api/ssl/v1/types{urlSuffix}");
return new ListSslProfilesResponse { SslProfiles = await ProcessResponse<List<Profile>>(response) };
}

Expand All @@ -223,7 +223,7 @@ public async Task<int> Enroll(EnrollRequest request)
{
try
{
var response = await RestClient.PostAsJsonAsync("/api/ssl/v1/enroll", request);
var response = await RestClient.PostAsJsonAsync("api/ssl/v1/enroll", request);
var enrollResponse = await ProcessResponse<EnrollResponse>(response);

return enrollResponse.sslId;
Expand All @@ -246,7 +246,7 @@ public async Task<int> Renew(int sslId)
{
try
{
var response = await RestClient.PostAsJsonAsync($"/api/ssl/v1/renewById/{sslId}", "");
var response = await RestClient.PostAsJsonAsync($"api/ssl/v1/renewById/{sslId}", "");
var renewResponse = await ProcessResponse<EnrollResponse>(response);

return renewResponse.sslId;
Expand All @@ -267,7 +267,7 @@ public async Task<int> Renew(int sslId)

public async Task<X509Certificate2> PickupCertificate(int sslId, string subject)
{
var response = await RestClient.GetAsync($"/api/ssl/v1/collect/{sslId}/x509CO");
var response = await RestClient.GetAsync($"api/ssl/v1/collect/{sslId}/x509CO");

if (response.IsSuccessStatusCode && response.Content.Headers.ContentLength > 0)
{
Expand All @@ -283,7 +283,7 @@ public async Task<X509Certificate2> PickupCertificate(int sslId, string subject)

public async Task Reissue(ReissueRequest request, int sslId)
{
var response = await RestClient.PostAsJsonAsync($"/api/ssl/v1/replace/{sslId}", request);
var response = await RestClient.PostAsJsonAsync($"api/ssl/v1/replace/{sslId}", request);
response.EnsureSuccessStatusCode();
}

Expand Down
26 changes: 20 additions & 6 deletions src/SectigoCAProxy/SectigoCAProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,11 @@ public override EnrollmentResult Enroll(ICertificateDataReader certificateDataRe
{
Logger.Debug("Parse Subject for Common Name, Organization, and Org Unit");

string commonName = ParseSubject(subject, "CN=");
Logger.Trace($"Common Name: {commonName}");
string commonName = ParseSubject(subject, "CN=", false);
if (!string.IsNullOrEmpty(commonName))
{
Logger.Trace($"Common Name: {commonName}");
}

string orgStr = null;
if (productInfo.ProductParameters.ContainsKey("Organization"))
Expand Down Expand Up @@ -390,7 +393,7 @@ public override EnrollmentResult Enroll(ICertificateDataReader certificateDataRe
comments = $"CERTIFICATE_REQUESTOR: {productInfo.ProductParameters["Keyfactor-Requester"]}"//this is how the current gateway passes this data
};

Logger.Debug($"Submit {enrollmentType} request for {subject}");
Logger.Debug($"Submit {enrollmentType} request");
sslId = Task.Run(async () => await Client.Enroll(request)).Result;
newCert = Task.Run(async () => await Client.GetCertificate(sslId)).Result;
Logger.Debug($"Enrolled for Certificate {newCert.CommonName} (ID: {newCert.Id}) | Status: {newCert.status}. Attempt to Pickup Certificate.");
Expand Down Expand Up @@ -635,16 +638,21 @@ private static string ParseSanList(Dictionary<string, string[]> san, bool multiD

if (!multiDomain)
{
if (allSans.Contains(commonName) && allSans.Count() > 1)
if (!string.IsNullOrEmpty(commonName) && allSans.Contains(commonName) && allSans.Count() > 1)
{
List<string> sans = allSans.ToList();
sans.Remove(commonName);
sanList = string.Join(",", sans.ToArray());
}
else
{
List<string> sans = allSans.ToList();
sanList = string.Join(",", sans.ToArray());
}
}
else
{
if (allSans.Contains(commonName))
if (!string.IsNullOrEmpty(commonName) && allSans.Contains(commonName))
{
List<string> sans = allSans.ToList();
sans.Remove(commonName);
Expand Down Expand Up @@ -792,9 +800,15 @@ private static SectigoApiClient InitializeRestClient(Dictionary<string, object>
webRequestHandler.ClientCertificates.Add(authCert);
}

string apiEndpoint = localConfig.ApiEndpoint;
if (!apiEndpoint.EndsWith("/"))
{
apiEndpoint += "/";
}

HttpClient restClient = new HttpClient(webRequestHandler)
{
BaseAddress = new Uri(localConfig.ApiEndpoint)
BaseAddress = new Uri(apiEndpoint)
};

restClient.DefaultRequestHeaders.Add(Constants.CUSTOMER_URI_KEY, localConfig.CustomerUri);
Expand Down

0 comments on commit f65a6c6

Please sign in to comment.