Skip to content

Commit eea0962

Browse files
authored
Merge 1.1.0 to main
2 parents 90c1f06 + 8ba1320 commit eea0962

6 files changed

Lines changed: 45 additions & 83 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ Handle change to Sectigo API Revocation call
1010

1111
1.0.3
1212
Fix for JSON serialization of revocation
13+
14+
1.1.0
15+
Add support for using the cert upload feature to upload auth certs
16+
Switch to .NET 8

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,16 @@ In addition, for the admin account you plan to use, make sure it has the API adm
6363

6464
2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [Sectigo Certificate Manager Gateway AnyCA Gateway REST plugin](https://github.com/Keyfactor/sectigo-scm-caplugin/releases/latest) from GitHub.
6565

66-
3. Copy the unzipped directory (usually called `net6.0`) to the Extensions directory:
66+
3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory:
67+
6768

6869
```shell
70+
Depending on your AnyCA Gateway REST version, copy the unzipped directory to one of the following locations:
6971
Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions
72+
Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions
7073
```
7174

72-
> The directory containing the Sectigo Certificate Manager Gateway AnyCA Gateway REST plugin DLLs (`net6.0`) can be named anything, as long as it is unique within the `Extensions` directory.
75+
> The directory containing the Sectigo Certificate Manager Gateway AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory.
7376

7477
4. Restart the AnyCA Gateway REST service.
7578

sectigo-scm-caplugin/Client/SectigoClient.cs

Lines changed: 16 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Keyfactor.Extensions.CAPlugin.Sectigo.API;
1+
using Keyfactor.AnyGateway.Extensions;
2+
using Keyfactor.Extensions.CAPlugin.Sectigo.API;
23
using Keyfactor.Extensions.CAPlugin.Sectigo.Models;
34
using Keyfactor.Logging;
45

@@ -134,7 +135,7 @@ public async Task CertificateListProducer(BlockingCollection<Certificate> certs,
134135

135136
public async Task<List<Certificate>> PageCertificates(int position = 0, int size = 25, string filter = "")
136137
{
137-
string filterQueryString = String.IsNullOrEmpty(filter) ? string.Empty : $"&{filter}";
138+
string filterQueryString = string.IsNullOrEmpty(filter) ? string.Empty : $"&{filter}";
138139
Logger.LogTrace($"API Request: api/ssl/v1?position={position}&size={size}{filterQueryString}".TrimEnd());
139140
var response = await RestClient.GetAsync($"api/ssl/v1?position={position}&size={size}{filterQueryString}".TrimEnd());
140141
return await ProcessResponse<List<Certificate>>(response);
@@ -305,7 +306,7 @@ private static async Task<T> ProcessResponse<T>(HttpResponseMessage response)
305306
}
306307
}
307308

308-
public static SectigoClient InitializeClient(SectigoConfig config)
309+
public static SectigoClient InitializeClient(SectigoConfig config, ICertificateResolver certResolver)
309310
{
310311
Logger.MethodEntry(LogLevel.Debug);
311312

@@ -314,13 +315,24 @@ public static SectigoClient InitializeClient(SectigoConfig config)
314315
if (config.AuthenticationType.ToLower() == "certificate")
315316
{
316317
clientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
317-
X509Certificate2 authCert = GetClientCertificate(config);
318+
Logger.LogTrace($"Resolving certificate. Source: {config.Certificate.Source}");
319+
X509Certificate2 authCert = null;
320+
if (!string.IsNullOrEmpty(config.Certificate.ImportedCertificate))
321+
{
322+
authCert = new X509Certificate2(Convert.FromBase64String(config.Certificate.ImportedCertificate), config.Certificate.ImportedCertificatePassword);
323+
}
324+
else
325+
{
326+
authCert = certResolver.ResolveCertificate(config.Certificate);
327+
}
318328
if (authCert == null)
319329
{
320330
Logger.MethodExit(LogLevel.Debug);
321331
throw new Exception("AuthType set to Certificate, but no certificate found!");
322332
}
323333

334+
Logger.LogTrace($"Auth cert found. CERT DETAILS: \nSerial Number: {authCert.GetSerialNumberString()}\nHas PK: {authCert.HasPrivateKey.ToString()}\nSubject: {authCert.Subject}");
335+
324336
clientHandler.ClientCertificates.Add(authCert);
325337
}
326338

@@ -348,58 +360,6 @@ public static SectigoClient InitializeClient(SectigoConfig config)
348360
return new SectigoClient(restClient);
349361
}
350362

351-
private static X509Certificate2 GetClientCertificate(SectigoConfig config)
352-
{
353-
Logger.MethodEntry(LogLevel.Debug);
354-
//Dictionary<string, object> caConnectionCertificateDetail = config["ClientCertificate"] as Dictionary<string, object>;
355-
X509Certificate2 clientCert = null;
356-
357-
if (!string.IsNullOrEmpty(config.Certificate.Thumbprint))
358-
{
359-
StoreName sn;
360-
StoreLocation sl;
361-
string thumbprint = config.Certificate.Thumbprint;
362-
363-
if (String.IsNullOrEmpty(thumbprint) ||
364-
!Enum.TryParse(config.Certificate.StoreName, out sn) ||
365-
!Enum.TryParse(config.Certificate.StoreLocation, out sl))
366-
{
367-
throw new Exception("Unable to find client authentication certificate");
368-
}
369-
370-
X509Certificate2Collection foundCerts;
371-
using (X509Store currentStore = new X509Store(sn, sl))
372-
{
373-
Logger.LogTrace($"Search for client auth certificates with Thumprint {thumbprint} in the {sn}{sl} certificate store");
374-
375-
currentStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
376-
foundCerts = currentStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, true);
377-
Logger.LogTrace($"Found {foundCerts.Count} certificates in the {currentStore.Name} store");
378-
currentStore.Close();
379-
}
380-
if (foundCerts.Count > 1)
381-
{
382-
throw new Exception($"Multiple certificates with Thumprint {thumbprint} found in the {sn}{sl} certificate store");
383-
}
384-
if (foundCerts.Count > 0)
385-
clientCert = foundCerts[0];
386-
}
387-
else
388-
{
389-
// Cert is provided via pfx file instead of cert store
390-
try
391-
{
392-
X509Certificate2 cert = new X509Certificate2(config.Certificate.CertificatePath, config.Certificate.CertificatePassword);
393-
clientCert = cert;
394-
}
395-
catch (Exception ex)
396-
{
397-
throw new Exception($"Unable to open the client certificate file with the given password. Error: {ex.Message}");
398-
}
399-
}
400-
Logger.MethodExit(LogLevel.Debug);
401-
return clientCert;
402-
}
403363
#endregion
404364
}
405365
}

sectigo-scm-caplugin/SectigoCAPlugin.cs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ public class SectigoCAPlugin : IAnyCAPlugin
3333
private SectigoConfig _config;
3434
private readonly ILogger _logger;
3535
private ICertificateDataReader _certificateDataReader;
36+
private ICertificateResolver _certificateResolver;
3637

37-
public SectigoCAPlugin()
38+
public SectigoCAPlugin(ICertificateResolver certResolver = null)
3839
{
3940
_logger = LogHandler.GetClassLogger<SectigoCAPlugin>();
41+
_certificateResolver = certResolver;
4042
}
4143

4244
public void Initialize(IAnyCAPluginConfigProvider configProvider, ICertificateDataReader certificateDataReader)
@@ -88,7 +90,7 @@ public async Task<EnrollmentResult> Enroll(string csr, string subject, Dictionar
8890
department = productInfo.ProductParameters["Department"];
8991
_logger.LogTrace($"Department: {department}");
9092
}
91-
var client = SectigoClient.InitializeClient(_config);
93+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
9294
var fieldList = Task.Run(async () => await client.ListCustomFields()).Result;
9395
var allFields = fieldList.CustomFields?.Select(f => f);
9496

@@ -370,7 +372,7 @@ public async Task<AnyCAPluginCertificate> GetSingleRecord(string caRequestID)
370372
_logger.LogTrace($"Get Single Certificate Detail from Sectigo (sslId: {caRequestID})");
371373
int sslId = int.Parse(caRequestID.Split('-')[0]);
372374

373-
var client = SectigoClient.InitializeClient(_config);
375+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
374376
var singleCert = Task.Run(async () => await client.GetCertificate(sslId)).Result;
375377
_logger.LogTrace($"{singleCert.CommonName} ({singleCert.status}) retrieved from Sectigo.");
376378

@@ -446,7 +448,7 @@ public async Task Ping()
446448
try
447449
{
448450
_logger.LogDebug("Attempting to ping Sectigo API");
449-
var client = SectigoClient.InitializeClient(_config);
451+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
450452
_ = Task.Run(async () => await client.ListOrganizations()).Result;
451453
}
452454
catch (Exception ex)
@@ -462,7 +464,7 @@ public async Task<int> Revoke(string caRequestID, string hexSerialNumber, uint r
462464

463465
try
464466
{
465-
var client = SectigoClient.InitializeClient(_config);
467+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
466468
var response = Task.Run(async () => await client.RevokeSslCertificateById(int.Parse(caRequestID), (int)revocationReason, RevokeReasonToString(revocationReason))).Result;
467469

468470
_logger.MethodExit(LogLevel.Debug);
@@ -501,7 +503,7 @@ public async Task Synchronize(BlockingCollection<AnyCAPluginCertificate> blockin
501503
string[] filterProfileIds = _config.SyncFilterProfileId.Split(',');
502504
filter.Add("sslTypeId", filterProfileIds);
503505
}
504-
var client = SectigoClient.InitializeClient(_config);
506+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
505507
producerTask = client.CertificateListProducer(certsToAdd, newCancelToken.Token, _config.PageSize, filter);
506508

507509
foreach (Certificate certToAdd in certsToAdd.GetConsumingEnumerable())
@@ -654,7 +656,7 @@ public async Task ValidateProductInfo(EnrollmentProductInfo productInfo, Diction
654656
_logger.MethodEntry(LogLevel.Debug);
655657
string rawConfig = JsonConvert.SerializeObject(connectionInfo);
656658
var parsedConfig = JsonConvert.DeserializeObject<SectigoConfig>(rawConfig);
657-
SectigoClient localClient = SectigoClient.InitializeClient(parsedConfig);
659+
SectigoClient localClient = SectigoClient.InitializeClient(parsedConfig, _certificateResolver);
658660

659661
var profileList = Task.Run(async () => await localClient.ListSslProfiles()).Result;
660662
if (profileList.SslProfiles.Where(p => p.id == int.Parse(productInfo.ProductID)).Count() == 0)
@@ -667,28 +669,28 @@ public async Task ValidateProductInfo(EnrollmentProductInfo productInfo, Diction
667669

668670
private async Task<Organization> GetOrganizationAsync(string orgName)
669671
{
670-
var client = SectigoClient.InitializeClient(_config);
672+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
671673
var orgList = await client.ListOrganizations();
672674
return orgList.Organizations.Where(x => x.name.ToLower().Equals(orgName.ToLower())).FirstOrDefault();
673675
}
674676

675677
private async Task<int> GetProfileTerm(int profileId)
676678
{
677-
var client = SectigoClient.InitializeClient(_config);
679+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
678680
var profileList = await client.ListSslProfiles();
679681
return profileList.SslProfiles.Where(x => x.id == profileId).FirstOrDefault().terms[0];
680682
}
681683

682684
private async Task<Profile> GetProfile(int profileId)
683685
{
684-
var client = SectigoClient.InitializeClient(_config);
686+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
685687
var profileList = await client.ListSslProfiles();
686688
return profileList.SslProfiles.Where(x => x.id == profileId).FirstOrDefault();
687689
}
688690

689691
private async Task<List<int>> GetProfileIds()
690692
{
691-
var client = SectigoClient.InitializeClient(_config);
693+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
692694
var profileList = await client.ListSslProfiles();
693695
return profileList.SslProfiles.Select(x => x.id).ToList();
694696
}
@@ -730,7 +732,7 @@ private async Task<EnrollmentResult> PickUpEnrolledCertificate(int sslId, string
730732
while (retryCounter < _config.PickupRetries)
731733
{
732734
_logger.LogDebug($"Try number {retryCounter + 1} to pickup enrolled certificate");
733-
var client = SectigoClient.InitializeClient(_config);
735+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
734736
var certificate = Task.Run(async () => await client.PickupCertificate(sslId, subject)).Result;
735737
if (certificate != null && !String.IsNullOrEmpty(certificate.Subject))
736738
{
@@ -765,7 +767,7 @@ public X509Certificate2 PickupSingleCert(int sslId, string subject)
765767
while (retryCounter < _config.PickupRetries)
766768
{
767769
_logger.LogDebug($"Try number {retryCounter + 1} to pickup single certificate");
768-
var client = SectigoClient.InitializeClient(_config);
770+
var client = SectigoClient.InitializeClient(_config, _certificateResolver);
769771
var certificate = Task.Run(async () => await client.PickupCertificate(sslId, subject)).Result;
770772
if (certificate != null && !String.IsNullOrEmpty(certificate.Subject))
771773
{

sectigo-scm-caplugin/SectigoConfig.cs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using Newtonsoft.Json;
1+
using Keyfactor.AnyGateway.Extensions;
2+
3+
using Newtonsoft.Json;
24

35
using System;
46
using System.Collections.Generic;
@@ -54,13 +56,4 @@ public SectigoConfig()
5456
[JsonProperty("ClientCertificate")]
5557
public ClientCertificate Certificate { get; set; }
5658
}
57-
58-
public class ClientCertificate
59-
{
60-
public string StoreName { get; set; }
61-
public string StoreLocation { get; set; }
62-
public string Thumbprint { get; set; }
63-
public string CertificatePath { get; set; }
64-
public string CertificatePassword { get; set; }
65-
}
6659
}

sectigo-scm-caplugin/sectigo-scm-caplugin.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
55
<RootNamespace>Keyfactor.Extensions.CAPlugin.Sectigo</RootNamespace>
66
<ImplicitUsings>disable</ImplicitUsings>
77
<Nullable>disable</Nullable>
@@ -10,7 +10,7 @@
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13-
<PackageReference Include="Keyfactor.AnyGateway.IAnyCAPlugin" Version="3.0.0" />
13+
<PackageReference Include="Keyfactor.AnyGateway.IAnyCAPlugin" Version="3.1.0" />
1414
<PackageReference Include="Keyfactor.Common" Version="2.5.0" />
1515
<PackageReference Include="Keyfactor.Logging" Version="1.1.1" />
1616
<PackageReference Include="Keyfactor.PKI" Version="5.5.0" />

0 commit comments

Comments
 (0)