From 0dd4bf0b9fac82e19257e31363ea73b12f0c67a5 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 21 May 2024 09:22:42 -0400 Subject: [PATCH 1/5] Fix for Revoke Issue, get end entity cert only. --- CscGlobalCaProxy/CscGlobalCaProxy.cs | 87 +++++++++++++++++++++------- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/CscGlobalCaProxy/CscGlobalCaProxy.cs b/CscGlobalCaProxy/CscGlobalCaProxy.cs index 96a8535..a595af6 100644 --- a/CscGlobalCaProxy/CscGlobalCaProxy.cs +++ b/CscGlobalCaProxy/CscGlobalCaProxy.cs @@ -96,27 +96,24 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, if (fileContent.Length > 0) { + Logger.Trace($"File Content {fileContent}"); var certData = fileContent.Replace("\r\n", string.Empty); - var splitCerts = - certData.Split(new[] { "-----END CERTIFICATE-----", "-----BEGIN CERTIFICATE-----" }, - StringSplitOptions.RemoveEmptyEntries); - foreach (var cert in splitCerts) - if (!cert.Contains(".crt")) + var certString = GetEndEntityCertificate(certData); + var currentCert = new X509Certificate2(Encoding.ASCII.GetBytes(certString)); + + if (certString.Length > 0) + { + blockingBuffer.Add(new CAConnectorCertificate { - Logger.Trace($"Split Cert Value: {cert}"); - - var currentCert = new X509Certificate2(Encoding.ASCII.GetBytes(cert)); - blockingBuffer.Add(new CAConnectorCertificate - { - CARequestID = $"{currentResponseItem?.Uuid}", - Certificate = cert, - SubmissionDate = currentResponseItem?.OrderDate == null - ? Convert.ToDateTime(currentCert.NotBefore) - : Convert.ToDateTime(currentResponseItem.OrderDate), - Status = certStatus, - ProductID = productId - }, cancelToken); - } + CARequestID = $"{currentResponseItem?.Uuid}", + Certificate = certString, + SubmissionDate = currentResponseItem?.OrderDate == null + ? Convert.ToDateTime(currentCert.NotBefore) + : Convert.ToDateTime(currentResponseItem.OrderDate), + Status = certStatus, + ProductID = productId + }, cancelToken); + } } } } @@ -134,6 +131,41 @@ public override void Synchronize(ICertificateDataReader certificateDataReader, Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); } + private string GetEndEntityCertificate(string certData) + { + var splitCerts = + certData.Split(new[] {"-----END CERTIFICATE-----", "-----BEGIN CERTIFICATE-----"}, + StringSplitOptions.RemoveEmptyEntries); + + X509Certificate2Collection col = new X509Certificate2Collection(); + foreach (var cert in splitCerts) + { + Logger.Trace($"Split Cert Value: {cert}"); + + //skip these headers that came with the split function + if (!cert.Contains(".crt")) + { + col.Import(cert); + } + } + + Logger.Trace("Getting End Entity Certificate"); + var currentCert = CSS.PKI.X509.X509Utilities.GetEndEntityCertificate(col); + Logger.Trace("Converting to Byte Array"); + var byteArray = currentCert?.Export(X509ContentType.Cert); + Logger.Trace("Initializing empty string"); + + var certString = string.Empty; + if (byteArray != null) + { + certString = Convert.ToBase64String(byteArray); + } + + Logger.Trace($"Got certificate {certString}"); + + return certString; + } + [Obsolete] public override EnrollmentResult Enroll(string csr, string subject, Dictionary san, EnrollmentProductInfo productInfo, @@ -247,13 +279,24 @@ public override CAConnectorCertificate GetSingleRecord(string caRequestId) .Result; Logger.Trace($"Single Cert JSON: {JsonConvert.SerializeObject(certificateResponse)}"); + + var fileContent = + Encoding.ASCII.GetString( + Convert.FromBase64String(certificateResponse?.Certificate ?? string.Empty)); + + Logger.Trace($"File Content {fileContent}"); + var certData = fileContent.Replace("\r\n", string.Empty); + var certString = GetEndEntityCertificate(certData); + Logger.Trace($"Cert String Content {certString}"); + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + return new CAConnectorCertificate { CARequestID = keyfactorCaId, - Certificate = certificateResponse.Certificate, - Status = _requestManager.MapReturnStatus(certificateResponse.Status), - SubmissionDate = Convert.ToDateTime(certificateResponse.OrderDate) + Certificate = certString, + Status = _requestManager.MapReturnStatus(certificateResponse?.Status), + SubmissionDate = Convert.ToDateTime(certificateResponse?.OrderDate) }; } From feb53c9079336fa8f6b7fd559c460229179789cf Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Tue, 21 May 2024 13:23:30 +0000 Subject: [PATCH 2/5] Update generated README --- README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6fa11a1..a8f4aef 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,13 @@ + # CSC Global Csc Global operates a PKI as a service platform for customers around the globe. The AnyGateway solution for CscGlobal is designed to allow Keyfactor Command the ability to: - Sync certificates issued from the CA - Request new certificates from the CA - Revoke certificates directly from Keyfactor Command #### 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 CSC Global @@ -16,6 +15,8 @@ CSC Global is supported by Keyfactor for Keyfactor customers. If you have a supp ###### 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. +--- + --- @@ -23,6 +24,16 @@ CSC Global is supported by Keyfactor for Keyfactor customers. If you have a supp +## 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) @@ -464,3 +475,4 @@ Set-KeyfactorGatewayConfig -LogicalName "CSCGlobal" -FilePath [path to json file ### License [Apache](https://apache.org/licenses/LICENSE-2.0) + From 5e491a99b0c7ead88195809cca504afa69133b5b Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 21 May 2024 16:01:40 +0000 Subject: [PATCH 3/5] Fixed Revoke Issues --- CscGlobalCaProxy/CscGlobalCaProxy.cs | 95 +++++++++++++++++----------- CscGlobalCaProxy/RequestManager.cs | 6 ++ 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/CscGlobalCaProxy/CscGlobalCaProxy.cs b/CscGlobalCaProxy/CscGlobalCaProxy.cs index a595af6..3eadd4d 100644 --- a/CscGlobalCaProxy/CscGlobalCaProxy.cs +++ b/CscGlobalCaProxy/CscGlobalCaProxy.cs @@ -34,24 +34,34 @@ public CscGlobalCaProxy() public override int Revoke(string caRequestId, string hexSerialNumber, uint revocationReason) { - Logger.Trace($"Staring Revoke Method"); - var revokeResponse = - Task.Run(async () => - await CscGlobalClient.SubmitRevokeCertificateAsync(caRequestId.Substring(0, 36))) - .Result; //todo fix to use pipe delimiter + try + { + Logger.Trace($"Staring Revoke Method"); + var revokeResponse = + Task.Run(async () => + await CscGlobalClient.SubmitRevokeCertificateAsync(caRequestId.Substring(0, 36))) + .Result; //todo fix to use pipe delimiter - Logger.Trace($"Revoke Response JSON: {JsonConvert.SerializeObject(revokeResponse)}"); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + Logger.Trace($"Revoke Response JSON: {JsonConvert.SerializeObject(revokeResponse)}"); + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - var revokeResult = _requestManager.GetRevokeResult(revokeResponse); + var revokeResult = _requestManager.GetRevokeResult(revokeResponse); - if (revokeResult == Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.FAILED)) + if (revokeResult == Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.FAILED)) + { + if (!string.IsNullOrEmpty(revokeResponse?.RegistrationError?.Description)) + { + throw new UnsuccessfulRequestException($"Revoke Failed with message {revokeResponse?.RegistrationError?.Description}", 30); + } + } + + return revokeResult; + } + catch(Exception e) { - return -1; + throw new Exception($"Revoke Failed with message {e?.Message}"); } - return revokeResult; - } [Obsolete] @@ -145,7 +155,7 @@ private string GetEndEntityCertificate(string certData) //skip these headers that came with the split function if (!cert.Contains(".crt")) { - col.Import(cert); + col.Import(Encoding.UTF8.GetBytes(cert)); } } @@ -271,33 +281,42 @@ public override EnrollmentResult Enroll(ICertificateDataReader certificateDataRe public override CAConnectorCertificate GetSingleRecord(string caRequestId) { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - var keyfactorCaId = caRequestId.Substring(0, 36); //todo fix to use pipe delimiter - Logger.Trace($"Keyfactor Ca Id: {keyfactorCaId}"); - var certificateResponse = - Task.Run(async () => await CscGlobalClient.SubmitGetCertificateAsync(keyfactorCaId)) - .Result; - - Logger.Trace($"Single Cert JSON: {JsonConvert.SerializeObject(certificateResponse)}"); - - var fileContent = - Encoding.ASCII.GetString( - Convert.FromBase64String(certificateResponse?.Certificate ?? string.Empty)); - - Logger.Trace($"File Content {fileContent}"); - var certData = fileContent.Replace("\r\n", string.Empty); - var certString = GetEndEntityCertificate(certData); - Logger.Trace($"Cert String Content {certString}"); - - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + try + { + Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + var keyfactorCaId = caRequestId?.Substring(0, 36); //todo fix to use pipe delimiter + Logger.Trace($"Keyfactor Ca Id: {keyfactorCaId}"); + var certificateResponse = + Task.Run(async () => await CscGlobalClient.SubmitGetCertificateAsync(keyfactorCaId)) + .Result; + + Logger.Trace($"Single Cert JSON: {JsonConvert.SerializeObject(certificateResponse)}"); + + var fileContent = + Encoding.ASCII.GetString( + Convert.FromBase64String(certificateResponse?.Certificate ?? string.Empty)); + + Logger.Trace($"File Content {fileContent}"); + var certData = fileContent?.Replace("\r\n", string.Empty); + var certString = String.Empty; + if (!string.IsNullOrEmpty(certData)) + certString = GetEndEntityCertificate(certData); + Logger.Trace($"Cert String Content {certString}"); - return new CAConnectorCertificate + Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); + + return new CAConnectorCertificate + { + CARequestID = keyfactorCaId, + Certificate = certString, + Status = _requestManager.MapReturnStatus(certificateResponse?.Status), + SubmissionDate = Convert.ToDateTime(certificateResponse?.OrderDate) + }; + } + catch(Exception e) { - CARequestID = keyfactorCaId, - Certificate = certString, - Status = _requestManager.MapReturnStatus(certificateResponse?.Status), - SubmissionDate = Convert.ToDateTime(certificateResponse?.OrderDate) - }; + throw new Exception($"Error Occurred getting single cert {e.Message}"); + } } public override void Initialize(ICAConnectorConfigProvider configProvider) diff --git a/CscGlobalCaProxy/RequestManager.cs b/CscGlobalCaProxy/RequestManager.cs index a86161e..31b0231 100644 --- a/CscGlobalCaProxy/RequestManager.cs +++ b/CscGlobalCaProxy/RequestManager.cs @@ -160,6 +160,12 @@ private string GetCertificateType(string productId) return "2"; case "CSC TrustedSecure Premium Wildcard Certificate": return "1"; + case "CSC Trusted Secure Domain Validated SSL": + return "4"; + case "CSC Trusted Secure Domain Validated Wildcard SSL": + return "5"; + case "CSC Trusted Secure Domain Validated UC Certificate": + return "6"; case "CSC TrustedSecure Domain Validated SSL": return "4"; case "CSC TrustedSecure Domain Validated Wildcard SSL": From 9760471d1c9ec4aed77e7529a28b016197ca0e7d Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Tue, 21 May 2024 12:11:27 -0400 Subject: [PATCH 4/5] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7753ddf..da74ba0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +v1.1.1 +-Fix Revoke Serial Number Mismatch KF 10.1 and 22.1.0 GW combination +-Only Syncing and GetSingleRecord on End Entity Cert to prevent errors. v1.1.0 - Add Support for CNAME Domain Validation From 1eca766089c4ba72702f1c409f5876cdc7ccb783 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Tue, 21 May 2024 12:11:41 -0400 Subject: [PATCH 5/5] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da74ba0..1227ce2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ v1.1.1 --Fix Revoke Serial Number Mismatch KF 10.1 and 22.1.0 GW combination --Only Syncing and GetSingleRecord on End Entity Cert to prevent errors. +- Fix Revoke Serial Number Mismatch KF 10.1 and 22.1.0 GW combination +- Only Syncing and GetSingleRecord on End Entity Cert to prevent errors. v1.1.0 - Add Support for CNAME Domain Validation