Skip to content

Commit edbb1ea

Browse files
authored
Merge e7871c3 into 9187539
2 parents 9187539 + e7871c3 commit edbb1ea

11 files changed

Lines changed: 384 additions & 37 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,4 +360,4 @@ MigrationBackup/
360360
.ionide/
361361

362362
# Fody - auto-generated XML schema
363-
FodyWeavers.xsd
363+
FodyWeavers.xsd

CHANGELOG.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
v.1.0.2
2-
- Warning: enrollment field/template parameter with the name "CN DCV Email (admin@boingy.com)" has been renamed to "CN DCV Email" to make it compatible with the REST gateway. "Aplicant Pgone (+nn.nnnnnnnn)" has also been renamed to "Applicant Phone".
3-
- Updated dependencies.
4-
- Added support for default values via enrollment parameters configured in the AnyGateway REST certificate template.
5-
- Fixed issue with non-ASCII characters breaking the gateway.
6-
7-
v1.0.1
8-
- Fixed issue with SANs not being read correctly.
9-
101
v1.0
11-
- Initial Release.
2+
3+
- Initial Release.

README.md

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ This integration is tested and confirmed as working for Anygateway REST 24.4 and
7676

7777
* **Gateway Registration**
7878

79-
TODO Gateway Registration is a required section
79+
Download the **PCA root certificate** from AWS and have it ready to import into the Gateway **in `.pem` format**.
8080

8181
* **CA Connection**
8282

@@ -98,6 +98,7 @@ This integration is tested and confirmed as working for Anygateway REST 24.4 and
9898
* **IAMUserAccessKey** - IAM user access key (secret).
9999
* **IAMUserAccessSecret** - IAM user access secret (secret).
100100
* **ExternalId** - Optional sts:ExternalId to supply on AssumeRole calls.
101+
* **Enabled** - Flag to Enable or Disable gateway functionality. Disabling is primarily used to allow creation of the CA prior to configuration information being available.
101102

102103
2. Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. The AWSPCA CA Gateway plugin supports the following product IDs:
103104
@@ -107,6 +108,11 @@ This integration is tested and confirmed as working for Anygateway REST 24.4 and
107108
108109
3. Follow the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Keyfactor.htm) to add each defined Certificate Authority to Keyfactor Command and import the newly defined Certificate Templates.
109110
111+
4. In Keyfactor Command (v12.3+), for each imported Certificate Template, follow the [official documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Configuring%20Template%20Options.htm) to define enrollment fields for each of the following parameters:
112+
113+
* **LifetimeDays** - OPTIONAL: The number of days of validity to use when requesting certs. If not provided, default is 365
114+
* **SigningAlgorithm** - Required: AWS ACM PCA certificate signature algorithm to use when issuing certificates. Value is an AWS PCA SigningAlgorithm enum name (case-insensitive), e.g. SHA256WITHRSA, SHA384WITHRSA, SHA256WITHECDSA. If omitted, the plugin selects a default compatible with the CA key algorithm.
115+
110116
111117
## Authentication (Access Key + Secret)
112118
@@ -121,7 +127,7 @@ Before configuring the CAPlugin, have the following prepared:
121127
- **Access Key ID** (example format: `AKIAIOSFODNN7EXAMPLE`)
122128
- **Secret Access Key** (example format: `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`)
123129
124-
#### 2) A target IAM Role the connector will run as (recommended)
130+
#### 2) A target IAM Role the Gateway will run as (recommended)
125131
Example:
126132
- `arn:aws:iam::123456789012:role/Keyfactor-AnyGateway-AcmPcaRole`
127133
@@ -292,6 +298,52 @@ The following examples are intended as **copy/adapt templates**.
292298
}
293299
```
294300
301+
---
302+
303+
## Signing algorithm selection (ACM PCA)
304+
305+
The connector supports an optional **template / product parameter** named `SigningAlgorithm` that controls the **certificate signature algorithm**
306+
passed to AWS ACM PCA `IssueCertificate`.
307+
308+
- If **not set**, the plugin will **auto-select** a compatible default based on the CA `KeyAlgorithm` returned by
309+
`DescribeCertificateAuthority`.
310+
- If **set**, the plugin validates the value and **rejects incompatible combinations** before calling AWS.
311+
312+
### Where to configure
313+
314+
Set `SigningAlgorithm` on the **AnyGateway template** (product parameters), alongside `LifetimeDays`.
315+
316+
### Valid `SigningAlgorithm` values (AWS PCA)
317+
318+
- RSA family: `SHA256WITHRSA`, `SHA384WITHRSA`, `SHA512WITHRSA`
319+
- ECDSA family: `SHA256WITHECDSA`, `SHA384WITHECDSA`, `SHA512WITHECDSA`
320+
- SM2: `SM3WITHSM2`
321+
- ML-DSA (post-quantum): `ML_DSA_44`, `ML_DSA_65`, `ML_DSA_87`
322+
323+
### Allowed CA key algorithm <-> signing algorithm combinations
324+
325+
The CA key algorithm is the PCA CA **KeyAlgorithm** (not the subject key in the CSR). The signing algorithm must match the CA key family.
326+
327+
| CA KeyAlgorithm | Allowed SigningAlgorithm values |
328+
|---|---|
329+
| `RSA_2048`, `RSA_3072`, `RSA_4096` | `SHA256WITHRSA`, `SHA384WITHRSA`, `SHA512WITHRSA` |
330+
| `EC_prime256v1`, `EC_secp384r1`, `EC_secp521r1` | `SHA256WITHECDSA`, `SHA384WITHECDSA`, `SHA512WITHECDSA` |
331+
| `SM2` | `SM3WITHSM2` |
332+
| `ML_DSA_44` | `ML_DSA_44` |
333+
| `ML_DSA_65` | `ML_DSA_65` |
334+
| `ML_DSA_87` | `ML_DSA_87` |
335+
336+
### Auto-selection defaults
337+
338+
When `SigningAlgorithm` is omitted, the plugin selects:
339+
340+
- RSA CAs -> `SHA256WITHRSA`
341+
- EC P-256 -> `SHA256WITHECDSA`
342+
- EC P-384 -> `SHA384WITHECDSA`
343+
- EC P-521 -> `SHA512WITHECDSA`
344+
- SM2 -> `SM3WITHSM2`
345+
- ML-DSA -> exact-match (`ML_DSA_44/65/87`)
346+
295347
296348
## License
297349

aws-pca-caplugin/AWSPCACAPlugin.cs

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
66
// and limitations under the License.
77

8-
using System.Collections.Concurrent;
9-
using System.Security.Cryptography;
10-
using System.Security.Cryptography.X509Certificates;
11-
using System.Text;
12-
using System.Text.RegularExpressions;
138
using Amazon.ACMPCA;
149
using Keyfactor.AnyGateway.Extensions;
1510
using Keyfactor.Extensions.CAPlugin.AWS.Client;
@@ -19,6 +14,12 @@
1914
using Keyfactor.PKI.Enums.EJBCA;
2015
using Keyfactor.PKI.PEM;
2116
using Microsoft.Extensions.Logging;
17+
using System.Collections.Concurrent;
18+
using System.Security.Cryptography;
19+
using System.Security.Cryptography.X509Certificates;
20+
using System.Text;
21+
using System.Text.RegularExpressions;
22+
using static Org.BouncyCastle.Math.EC.ECCurve;
2223

2324
namespace Keyfactor.Extensions.CAPlugin.AWS;
2425

@@ -33,15 +34,23 @@ public AWSPCACAPlugin()
3334
}
3435

3536
private IAwsPcaClient AwsClient { get; set; }
36-
37+
private bool _enabled = false;
3738

3839
//done
3940
public void Initialize(IAnyCAPluginConfigProvider configProvider, ICertificateDataReader certificateDataReader)
4041
{
4142
Logger.MethodEntry(LogLevel.Debug);
4243
_certificateDataReader = certificateDataReader;
44+
var _enabled = bool.Parse(GetRequiredString(configProvider, "Enabled"));
45+
if (!_enabled)
46+
{
47+
Logger.LogWarning($"The CA is currently in the Disabled state. It must be Enabled to perform operations. Skipping config validation and AWS PCA Client creation...");
48+
Logger.MethodExit();
49+
return;
50+
}
4351
AwsClient = new AwsPcaClient(configProvider);
4452
Logger.MethodExit(LogLevel.Debug);
53+
4554
}
4655

4756
//done
@@ -358,6 +367,15 @@ public async Task<EnrollmentResult> Enroll(
358367
parsed > 0)
359368
days = parsed;
360369

370+
371+
// Optional signing algorithm override (template parameter)
372+
string? signingAlgorithm = null;
373+
if (productInfo.ProductParameters != null &&
374+
productInfo.ProductParameters.TryGetValue(EnrollmentConfigConstants.SigningAlgorithm,
375+
out var algoStr) &&
376+
!string.IsNullOrWhiteSpace(algoStr))
377+
signingAlgorithm = algoStr.Trim();
378+
361379
// Normalize CSR to PEM (keeps your existing behavior)
362380
csr = PemUtilities.DERToPEM(PemUtilities.PEMToDER(csr), PemUtilities.PemObjectType.CertRequest);
363381

@@ -369,6 +387,7 @@ public async Task<EnrollmentResult> Enroll(
369387
csr,
370388
productInfo.ProductID,
371389
days,
390+
signingAlgorithm,
372391
"Certificate Issued")
373392
.ConfigureAwait(false);
374393
}
@@ -445,6 +464,12 @@ public async Task<EnrollmentResult> Enroll(
445464
public async Task Ping()
446465
{
447466
Logger.MethodEntry();
467+
if (!_enabled)
468+
{
469+
Logger.LogWarning($"The CA is currently in the Disabled state. It must be Enabled to perform operations. Skipping config validation and AWS PCA Client creation...");
470+
Logger.MethodExit();
471+
return;
472+
}
448473
try
449474
{
450475
Logger.LogInformation("Ping request received");
@@ -460,12 +485,27 @@ public async Task Ping()
460485
}
461486

462487
//do
463-
public async Task ValidateCAConnectionInfo(Dictionary<string, object> connectionInfo)
488+
public Task ValidateCAConnectionInfo(Dictionary<string, object> connectionInfo)
464489
{
490+
try
491+
{
492+
if (!(bool)connectionInfo["Enabled"])
493+
{
494+
Logger.LogWarning($"The CA is currently in the Disabled state. It must be Enabled to perform operations. Skipping validation...");
495+
Logger.MethodExit(LogLevel.Trace);
496+
return Task.CompletedTask;
497+
}
498+
}
499+
catch (Exception ex)
500+
{
501+
Logger.LogError($"Exception: {LogHandler.FlattenException(ex)}");
502+
}
503+
504+
return Task.CompletedTask;
465505
}
466506

467507
//do
468-
public async Task ValidateProductInfo(EnrollmentProductInfo productInfo,
508+
public Task ValidateProductInfo(EnrollmentProductInfo productInfo,
469509
Dictionary<string, object> connectionInfo)
470510
{
471511
var certType = Constants.GetTemplateTypes().Find(x =>
@@ -474,6 +514,7 @@ public async Task ValidateProductInfo(EnrollmentProductInfo productInfo,
474514
if (certType == null) throw new ArgumentException($"Cannot find {productInfo.ProductID}", "ProductId");
475515

476516
Logger.LogInformation($"Validated {certType} ({certType})configured for AnyGateway");
517+
return Task.CompletedTask;
477518
}
478519

479520
//done
@@ -610,6 +651,13 @@ public Dictionary<string, PropertyConfigInfo> GetCAConnectorAnnotations()
610651
Hidden = false,
611652
DefaultValue = "",
612653
Type = "String"
654+
},
655+
[Constants.Enabled] = new ()
656+
{
657+
Comments = "Flag to Enable or Disable gateway functionality. Disabling is primarily used to allow creation of the CA prior to configuration information being available.",
658+
Hidden = false,
659+
DefaultValue = true,
660+
Type = "Boolean"
613661
}
614662
};
615663
}
@@ -627,6 +675,15 @@ public Dictionary<string, PropertyConfigInfo> GetTemplateParameterAnnotations()
627675
Hidden = false,
628676
DefaultValue = 365,
629677
Type = "Number"
678+
},
679+
// this is used to passdown csr details/prefill. will be overridden by commmand if not present.
680+
[EnrollmentConfigConstants.SigningAlgorithm] = new()
681+
{
682+
Comments =
683+
"Required: AWS ACM PCA certificate signature algorithm to use when issuing certificates. Value is an AWS PCA SigningAlgorithm enum name (case-insensitive), e.g. SHA256WITHRSA, SHA384WITHRSA, SHA256WITHECDSA. If omitted, the plugin selects a default compatible with the CA key algorithm.",
684+
Hidden = false,
685+
DefaultValue = "SHA256WITHRSA",
686+
Type = "String"
630687
}
631688
};
632689
}
@@ -641,6 +698,7 @@ private async Task<EnrollmentResult> IssueAndFetchAsync(
641698
string csrPem,
642699
string productId,
643700
int validityDays,
701+
string? signingAlgorithm,
644702
string statusMessageOnSuccess,
645703
string? idempotencyToken = null)
646704
{
@@ -650,6 +708,7 @@ private async Task<EnrollmentResult> IssueAndFetchAsync(
650708
CsrPem = csrPem,
651709
ProductId = productId,
652710
ValidityDays = validityDays,
711+
SigningAlgorithm = signingAlgorithm,
653712
IdempotencyToken = idempotencyToken ?? Guid.NewGuid().ToString("N")
654713
};
655714

@@ -1069,6 +1128,17 @@ private string PreparePemTextFromApi(string? base64)
10691128

10701129
return text;
10711130
}
1131+
private static string GetRequiredString(IAnyCAPluginConfigProvider provider, string key)
1132+
{
1133+
if (!provider.CAConnectionData.TryGetValue(key, out var obj) || obj == null)
1134+
throw new InvalidOperationException($"Missing required configuration value '{key}'.");
1135+
1136+
var str = obj.ToString();
1137+
if (string.IsNullOrWhiteSpace(str))
1138+
throw new InvalidOperationException($"Configuration value '{key}' is empty.");
1139+
1140+
return str!;
1141+
}
10721142

10731143
#endregion
10741144
}

aws-pca-caplugin/AWSPCACAPlugin.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313

1414

1515
<Target Name="CustomPostBuild" AfterTargets="PostBuildEvent">
16-
<Exec Condition="'$(Configuration)'=='DebugAndPush'" Command="PowerShell -ExecutionPolicy Bypass -File &quot;C:\Users\mkachkaev\source\repos\scripts\SyncScriptAWS_GT.ps1&quot;&#xA;" />
16+
<Exec Condition="'$(Configuration)'=='DebugAndPush'"
17+
Command="PowerShell -ExecutionPolicy Bypass -File &quot;C:\Users\mkachkaev\source\repos\scripts\SyncScriptAWS_GT.ps1&quot;&#xA;" />
1718
</Target>
1819

1920

aws-pca-caplugin/CHANGELOG.md

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)