From b0f4f97c3f846d285d03e28403d72fc94c27b182 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 16 Mar 2026 17:15:43 -0400 Subject: [PATCH 01/42] inital commit --- .claude/settings.local.json | 19 + .../keyfactor-bootstrap-workflow.yml | 19 + .vscode/settings.json | 3 + CHANGELOG.md | 8 + README.md | 1274 ++++++++++++++++ SampleConfig.json | 1084 ++++++++++++++ SslStoreCaProxy.slnx | 3 + SslStoreCaProxy/Client/Models/AddSan.cs | 10 + SslStoreCaProxy/Client/Models/AdminContact.cs | 23 + SslStoreCaProxy/Client/Models/AuthRequest.cs | 22 + SslStoreCaProxy/Client/Models/AuthResponse.cs | 16 + .../Client/Models/AuthenticationStatus.cs | 11 + SslStoreCaProxy/Client/Models/Certificate.cs | 8 + SslStoreCaProxy/Client/Models/DeleteSan.cs | 8 + .../Client/Models/DomainAuthVettingStatus.cs | 27 + .../Models/DownloadCertificateRequest.cs | 11 + .../Models/DownloadCertificateResponse.cs | 27 + SslStoreCaProxy/Client/Models/EditSan.cs | 8 + .../Client/Models/EmailApproverRequest.cs | 16 + .../Client/Models/EmailApproverResponse.cs | 18 + .../Client/Models/EnrollmentField.cs | 17 + .../Client/Models/NewOrderRequest.cs | 96 ++ .../Client/Models/NewOrderResponse.cs | 75 + SslStoreCaProxy/Client/Models/OrderNote.cs | 10 + SslStoreCaProxy/Client/Models/OrderStatus.cs | 20 + .../Client/Models/OrderStatusRequest.cs | 11 + .../Client/Models/OrderStatusResponse.cs | 68 + SslStoreCaProxy/Client/Models/Organization.cs | 25 + .../Client/Models/OrganizationAddress.cs | 18 + .../Client/Models/OrganizationContact.cs | 18 + .../Client/Models/OrganizationInfo.cs | 21 + .../Client/Models/OrganizationListRequest.cs | 15 + .../Client/Models/OrganizationResponse.cs | 15 + .../Client/Models/QueryOrderRequest.cs | 41 + .../Client/Models/ReIssueRequest.cs | 33 + .../Client/Models/RevokeOrderRequest.cs | 12 + .../Client/Models/RevokeOrderResponse.cs | 18 + .../Client/Models/TechnicalContact.cs | 23 + SslStoreCaProxy/Client/Models/Template.cs | 30 + .../Client/Models/TemplateNewOrderRequest.cs | 270 ++++ .../Client/Models/TemplateRegex.cs | 17 + SslStoreCaProxy/Client/SslStoreClient.cs | 226 +++ SslStoreCaProxy/Constants.cs | 11 + .../Exceptions/RetryCountExceededException.cs | 11 + SslStoreCaProxy/Interfaces/IAddSan.cs | 8 + SslStoreCaProxy/Interfaces/IAdminContact.cs | 21 + SslStoreCaProxy/Interfaces/IAuthRequest.cs | 15 + SslStoreCaProxy/Interfaces/IAuthResponse.cs | 13 + .../Interfaces/IAuthenticationStatus.cs | 9 + .../Interfaces/IDomainAuthVettingStatus.cs | 17 + .../Interfaces/IDownloadCertificateRequest.cs | 10 + .../IDownloadCertificateResponse.cs | 20 + .../Interfaces/IEmailApproverRequest.cs | 11 + .../Interfaces/IEmailApproverResponse.cs | 12 + .../Interfaces/IEnrollmentField.cs | 12 + .../Interfaces/INewOrderRequest.cs | 44 + .../Interfaces/INewOrderResponse.cs | 68 + SslStoreCaProxy/Interfaces/IOrderNote.cs | 8 + SslStoreCaProxy/Interfaces/IOrderStatus.cs | 17 + .../Interfaces/IOrderStatusRequest.cs | 10 + .../Interfaces/IOrderStatusResponse.cs | 62 + SslStoreCaProxy/Interfaces/IOrganization.cs | 22 + .../Interfaces/IOrganizationAddress.cs | 16 + .../Interfaces/IOrganizationContact.cs | 13 + .../Interfaces/IOrganizationInfo.cs | 18 + .../Interfaces/IOrganizationListRequest.cs | 8 + .../Interfaces/IOrganizationResponse.cs | 11 + .../Interfaces/IQueryOrderRequest.cs | 20 + SslStoreCaProxy/Interfaces/IReIssueRequest.cs | 29 + SslStoreCaProxy/Interfaces/IRequestManager.cs | 22 + .../Interfaces/IRevokeOrderRequest.cs | 11 + .../Interfaces/IRevokeOrderResponse.cs | 13 + SslStoreCaProxy/Interfaces/ISslStoreClient.cs | 30 + .../Interfaces/ITechnicalContact.cs | 21 + SslStoreCaProxy/Interfaces/ITemplate.cs | 26 + .../Interfaces/ITemplateNewOrderRequest.cs | 27 + SslStoreCaProxy/Interfaces/ITemplateRegex.cs | 10 + SslStoreCaProxy/ProductDefinitions.cs | 476 ++++++ SslStoreCaProxy/RequestManager.cs | 412 +++++ SslStoreCaProxy/SslStoreCAPluginConfig.cs | 77 + SslStoreCaProxy/SslStoreCaProxy.cs | 404 +++++ SslStoreCaProxy/SslStoreCaProxy.csproj | 21 + SslStoreCaProxy/manifest.json | 10 + docs/ssl-validity-timeline.html | 1323 +++++++++++++++++ integration-manifest.json | 11 + readme_source.md | 1242 ++++++++++++++++ 86 files changed, 8346 insertions(+) create mode 100644 .claude/settings.local.json create mode 100644 .github/workflows/keyfactor-bootstrap-workflow.yml create mode 100644 .vscode/settings.json create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 SampleConfig.json create mode 100644 SslStoreCaProxy.slnx create mode 100644 SslStoreCaProxy/Client/Models/AddSan.cs create mode 100644 SslStoreCaProxy/Client/Models/AdminContact.cs create mode 100644 SslStoreCaProxy/Client/Models/AuthRequest.cs create mode 100644 SslStoreCaProxy/Client/Models/AuthResponse.cs create mode 100644 SslStoreCaProxy/Client/Models/AuthenticationStatus.cs create mode 100644 SslStoreCaProxy/Client/Models/Certificate.cs create mode 100644 SslStoreCaProxy/Client/Models/DeleteSan.cs create mode 100644 SslStoreCaProxy/Client/Models/DomainAuthVettingStatus.cs create mode 100644 SslStoreCaProxy/Client/Models/DownloadCertificateRequest.cs create mode 100644 SslStoreCaProxy/Client/Models/DownloadCertificateResponse.cs create mode 100644 SslStoreCaProxy/Client/Models/EditSan.cs create mode 100644 SslStoreCaProxy/Client/Models/EmailApproverRequest.cs create mode 100644 SslStoreCaProxy/Client/Models/EmailApproverResponse.cs create mode 100644 SslStoreCaProxy/Client/Models/EnrollmentField.cs create mode 100644 SslStoreCaProxy/Client/Models/NewOrderRequest.cs create mode 100644 SslStoreCaProxy/Client/Models/NewOrderResponse.cs create mode 100644 SslStoreCaProxy/Client/Models/OrderNote.cs create mode 100644 SslStoreCaProxy/Client/Models/OrderStatus.cs create mode 100644 SslStoreCaProxy/Client/Models/OrderStatusRequest.cs create mode 100644 SslStoreCaProxy/Client/Models/OrderStatusResponse.cs create mode 100644 SslStoreCaProxy/Client/Models/Organization.cs create mode 100644 SslStoreCaProxy/Client/Models/OrganizationAddress.cs create mode 100644 SslStoreCaProxy/Client/Models/OrganizationContact.cs create mode 100644 SslStoreCaProxy/Client/Models/OrganizationInfo.cs create mode 100644 SslStoreCaProxy/Client/Models/OrganizationListRequest.cs create mode 100644 SslStoreCaProxy/Client/Models/OrganizationResponse.cs create mode 100644 SslStoreCaProxy/Client/Models/QueryOrderRequest.cs create mode 100644 SslStoreCaProxy/Client/Models/ReIssueRequest.cs create mode 100644 SslStoreCaProxy/Client/Models/RevokeOrderRequest.cs create mode 100644 SslStoreCaProxy/Client/Models/RevokeOrderResponse.cs create mode 100644 SslStoreCaProxy/Client/Models/TechnicalContact.cs create mode 100644 SslStoreCaProxy/Client/Models/Template.cs create mode 100644 SslStoreCaProxy/Client/Models/TemplateNewOrderRequest.cs create mode 100644 SslStoreCaProxy/Client/Models/TemplateRegex.cs create mode 100644 SslStoreCaProxy/Client/SslStoreClient.cs create mode 100644 SslStoreCaProxy/Constants.cs create mode 100644 SslStoreCaProxy/Exceptions/RetryCountExceededException.cs create mode 100644 SslStoreCaProxy/Interfaces/IAddSan.cs create mode 100644 SslStoreCaProxy/Interfaces/IAdminContact.cs create mode 100644 SslStoreCaProxy/Interfaces/IAuthRequest.cs create mode 100644 SslStoreCaProxy/Interfaces/IAuthResponse.cs create mode 100644 SslStoreCaProxy/Interfaces/IAuthenticationStatus.cs create mode 100644 SslStoreCaProxy/Interfaces/IDomainAuthVettingStatus.cs create mode 100644 SslStoreCaProxy/Interfaces/IDownloadCertificateRequest.cs create mode 100644 SslStoreCaProxy/Interfaces/IDownloadCertificateResponse.cs create mode 100644 SslStoreCaProxy/Interfaces/IEmailApproverRequest.cs create mode 100644 SslStoreCaProxy/Interfaces/IEmailApproverResponse.cs create mode 100644 SslStoreCaProxy/Interfaces/IEnrollmentField.cs create mode 100644 SslStoreCaProxy/Interfaces/INewOrderRequest.cs create mode 100644 SslStoreCaProxy/Interfaces/INewOrderResponse.cs create mode 100644 SslStoreCaProxy/Interfaces/IOrderNote.cs create mode 100644 SslStoreCaProxy/Interfaces/IOrderStatus.cs create mode 100644 SslStoreCaProxy/Interfaces/IOrderStatusRequest.cs create mode 100644 SslStoreCaProxy/Interfaces/IOrderStatusResponse.cs create mode 100644 SslStoreCaProxy/Interfaces/IOrganization.cs create mode 100644 SslStoreCaProxy/Interfaces/IOrganizationAddress.cs create mode 100644 SslStoreCaProxy/Interfaces/IOrganizationContact.cs create mode 100644 SslStoreCaProxy/Interfaces/IOrganizationInfo.cs create mode 100644 SslStoreCaProxy/Interfaces/IOrganizationListRequest.cs create mode 100644 SslStoreCaProxy/Interfaces/IOrganizationResponse.cs create mode 100644 SslStoreCaProxy/Interfaces/IQueryOrderRequest.cs create mode 100644 SslStoreCaProxy/Interfaces/IReIssueRequest.cs create mode 100644 SslStoreCaProxy/Interfaces/IRequestManager.cs create mode 100644 SslStoreCaProxy/Interfaces/IRevokeOrderRequest.cs create mode 100644 SslStoreCaProxy/Interfaces/IRevokeOrderResponse.cs create mode 100644 SslStoreCaProxy/Interfaces/ISslStoreClient.cs create mode 100644 SslStoreCaProxy/Interfaces/ITechnicalContact.cs create mode 100644 SslStoreCaProxy/Interfaces/ITemplate.cs create mode 100644 SslStoreCaProxy/Interfaces/ITemplateNewOrderRequest.cs create mode 100644 SslStoreCaProxy/Interfaces/ITemplateRegex.cs create mode 100644 SslStoreCaProxy/ProductDefinitions.cs create mode 100644 SslStoreCaProxy/RequestManager.cs create mode 100644 SslStoreCaProxy/SslStoreCAPluginConfig.cs create mode 100644 SslStoreCaProxy/SslStoreCaProxy.cs create mode 100644 SslStoreCaProxy/SslStoreCaProxy.csproj create mode 100644 SslStoreCaProxy/manifest.json create mode 100644 docs/ssl-validity-timeline.html create mode 100644 integration-manifest.json create mode 100644 readme_source.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..73a0c9f --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,19 @@ +{ + "permissions": { + "allow": [ + "WebFetch(domain:www.thesslstore.com)", + "Bash(grep -r \"365\\\\|730\\\\|825\\\\|397\\\\|200\\\\|199\" /c/Users/bhill/source/repos/sslstore-cagateway/Setup/Templates/*.json)", + "Bash(start \"\" \"c:\\\\Users\\\\bhill\\\\source\\\\repos\\\\sslstore-cagateway\\\\docs\\\\ssl-validity-timeline.html\")", + "Bash(rm -f SslStoreCaProxy.sln)", + "Bash(dotnet new:*)", + "Bash(dotnet sln:*)", + "Bash(ls \"c:\\\\Users\\\\bhill\\\\source\\\\repos\\\\sslstore-cagateway\"/*.sln)", + "Bash(find c:Usersbhillsourcerepossslstore-cagateway -maxdepth 1 -name *.sln -type f)", + "Bash(dotnet restore:*)", + "Bash(dotnet build:*)", + "Bash(ls c:/Users/bhill/source/repos/sslstore-cagateway/*.json)", + "Bash(node -e \":*)", + "Bash(xargs grep:*)" + ] + } +} diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-bootstrap-workflow.yml new file mode 100644 index 0000000..aa54b9c --- /dev/null +++ b/.github/workflows/keyfactor-bootstrap-workflow.yml @@ -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 }} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..013007b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dotnet.preferCSharpExtension": true +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e82d4d6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +v1.1.1 +- SSL Store Api Changed Encoding Rules, needed to fix integration to match + +v1.1.0 +- Added new AutoWWW field for single domain SSL Store products + +v1.0.4: +- Original Release Version diff --git a/README.md b/README.md new file mode 100644 index 0000000..5914eda --- /dev/null +++ b/README.md @@ -0,0 +1,1274 @@ +# SSLStore + +SSLStore is a certificate reseller with access to over 80 certificate products. Vendors include Digicert and Sectigo and all their acquired companies such as RapidSSL, Geotrust and Comodo. There is one API for all these products so a single integration to the SSLStore can get you instant access to over 80 Certificate products. + +#### 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 SSLStore + +SSLStore 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. + + +--- + + + + + + + + +--- + + +*** + +# Compatibility +This AnyGateway is designed to be used with version 21.3.2 of the Keyfactor AnyGateway Framework. + +# Getting Started + +## Integration Overview + +### Supported Functionality +- Certificate Sync - Full +- Certificate Enrollment for Domain Validated product suite (Regular, with SANs, and Wildcard) +- Certificate Enrollment for Organization Validated product suite (Regular, with SANs, and Wildcard) +- Certificate Enrollment for Extended Validation product suite (Regular and with SANs) +- Certificate Renewal/Reissue +- Certificate Revocation + + +### Unsupported Functionality +- Certificate Sync - Partial (not possible through the SSL Store API library) +- Approval/Denial of Enrollment Requests (not possible through the SSL Store API library) + +### Documentation +**General Documentation** +[SSLStore API Documentation](https://www.thesslstore.com/api/) + + +## Standard Gateway Installation +To begin, you must have the CA Gateway Service 21.3.2 installed and operational before attempting to configure the SSLStore Any Gateway plugin. This integration was tested with Keyfactor 8.7.0.0. +To install the gateway follow these instructions. + +1) Gateway Server - run the installation .msi obtained from Keyfactor + +2) Gateway Server - If you have the rights to install the database (usually in a Non SQL PAAS Environment) Using Powershell, run the following command to create the gateway database. + + **SQL Server Windows Auth** + ``` + %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] + ``` + Note if you are using SQL Authentication, then you need to run + + **SQL Server SQL Authentication** + + ``` + %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] -u [sql user] -p [sql password] + ``` + + If you do **not** have rights to created the database then have the database created ahead of time by the support team and just populate the database + + ## Populate commands below + + **Windows Authentication** + + ``` + %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] + ``` + + **SQL Server SQL Authentication** + + ``` + %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] -u [sql user] -p [sql password] + ``` + +3) Gateway Server - run the following Powershell to import the Cmdlets + + C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll (must be imported into Powershell) + ```ps + Import-Module C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll + ``` + +4) Gateway Server - Run the Following Powershell script to set the gateway encryption cert + + ### Set-KeyfactorGatewayEncryptionCert + This cmdlet will generate a self-signed certificate used to encrypt the database connection string. It populates a registry value with the serial number of the certificate to be used. The certificate is stored in the LocalMachine Personal Store and the registry key populated is: + + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvcProxy\Parameters\EncryptSerialNumber + No parameters are required to run this cmdlet. + +5) Gateway Server - Run the following Powershell Script to Set the Database Connection + + ### Set-KeyfactorGatewayDatabaseConnection + This cmdlet will set and encrypt the database connection string used by the AnyGateway service. + + **Windows Authentication** + ```ps + Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] + ``` + + **SQL Authentication** + ```ps + $KeyfactorCredentials = Get-Credentials + Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] -Account [$KeyfactorCredentials] + ``` +## Standard Gateway Configuration Finished +--- + + +## SSLStore AnyGateway Specific Configuration +It is important to note that importing the SSLStore configuration into the CA Gateway prior to installing the binaries must be completed. Additionally, the CA Gateway service +must be running in order to succesfully import the configuation. When the CA Gateway service starts it will attempt to validate the connection information to +the CA. Without the imported configuration, the service will fail to start. + +### Binary Installation + +1) Get the Latest Zip File from [Here](https://github.com/Keyfactor/quovadis-cagateway/releases) +2) Gateway Server - Copy the SSLStoreCaProxy.dll to the location where the Gateway Framework was installed (usually C:\Program Files\Keyfactor\Keyfactor AnyGateway) + +### Configuration Changes +1) Gateway Server - Edit the CAProxyServer.exe.config file and replace the line that says "NoOp" with the line below: + ``` + + ``` +2) Gateway Server - Install the Intermediate Comodo Certificate that was received from SSLStore + +3) Gateway Server - Take the sample Config.json located [Here](https://github.com/Keyfactor/quovadis-cagateway/raw/main/SampleConfig.json) and make the following modifications + +- *Security Settings Modifications* (Swap this out for the typical Gateway Security Settings for Test or Prod) + +``` + "Security": { + "KEYFACTOR\\administrator": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + }, + "KEYFACTOR\\SVC_AppPool": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + }, + "KEYFACTOR\\SVC_TimerService": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + } +``` +- *SSLStore Environment Settings* (Modify these with the keys and Urls obtained from SSLStore) +``` + "CAConnection": { + "SSLStoreURL": "https://sandbox-wbapi.thesslstore.com", + "PartnerCode": "SomePartnerCodeFromSSLStore", + "AuthToken": "SomeAuthTokenFromSSLStore", + "KeyfactorApiUrl": "https://kftrain.keyfactor.lab/KeyfactorAPI", + "KeyfactorApiUserId": "SomeKeyfactorAPIUser", + "KeyfactorApiPassword": "SomeKeyfactorAPIPassword", + "PageSize": "25", + "SampleRequest": { + "AuthRequest": { + "PartnerCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + }, + "AuthToken": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + } + }, + "ProductCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + }, + "TSSOrganizationId": { + "FieldData": { + "RequiredForProducts": [ + "None" + ], + "EnrollmentFieldMapping": "Organization ID" + } + }, + "OrganizationInfo": { + "OrganizationName": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization Name" + } + }, + "RegistrationNumber": { + "FieldData": { + "RequiredForProducts": [ + "certum" + ], + "EnrollmentFieldMapping": "Organization Registration Number" + } + }, + "JurisdictionCountry": { + "FieldData": { + "RequiredForProducts": [ + "comodoevssl", + "comodoevcsc", + "comodoevmdc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "positiveevssl" + ], + "EnrollmentFieldMapping": "Organization Jurisdiction Country" + } + }, + "OrganizationAddress": { + "AddressLine1": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization Address" + } + }, + "Region": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization State/Province" + } + }, + "PostalCode": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization Postal Code" + } + }, + "LocalityName": { + "FieldData": { + "RequiredForProducts": [ + "comodocsc", + "comodoevssl", + "comodoevcsc", + "comodoevmdc", + "comodomdc", + "comodomdcwildcard", + "comodouccwildcard", + "comodoucc", + "pacenterprise" + ], + "EnrollmentFieldMapping": "Organization Locality Name" + } + }, + "Country": { + "FieldData": { + "RequiredForProducts": [ + "truebizidmd", + "digi_ev_md_ssl", + "digi_md_ssl", + "digi_plus_ev_ssl", + "digi_plus_ssl", + "digi_securesite", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_ssl_basic", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev_flex", + "digi_securesite_flex", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex" + ], + "EnrollmentFieldMapping": "Organization Country" + } + }, + "Phone": { + "FieldData": { + "RequiredForProducts": [ + "truebizidmd", + "digi_ev_md_ssl", + "digi_md_ssl", + "digi_plus_ev_ssl", + "digi_plus_ssl", + "digi_securesite", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_ssl_basic", + "digi_sslwebserver_ev_flex", + "digi_truebizid_ev_flex", + "digi_securesite_flex", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex" + ], + "EnrollmentFieldMapping": "Organization Phone" + } + } + } + }, + "ValidityPeriod": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Validity Period (In Months)" + } + }, + "ServerCount": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Server Count" + } + }, + "CSR": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + }, + "DomainName": { + "FieldData": { + "RequiredForProducts": [ + "Certum" + ], + "EnrollmentFieldMapping": "Domain Name" + } + }, + "WebServerType": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Web Server Type" + } + }, + "DNSNames": { + "FieldData": { + "RequiredForProducts": [ + "digi_ssl_ev_basic", + "digi_ssl_ev_basic-EO", + "digi_securesite_ev_flex", + "digi_securesite_ev_flex-EO", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_ev_flex-EO", + "digi_securesite_pro_flex", + "digi_securesite_pro_flex-EO", + "digi_ssl_basic", + "digi_ssl_basic-EO", + "digi_securesite_flex", + "digi_securesite_flex-EO", + "digi_truebizid_flex", + "digi_truebizid_flex-EO", + "digi_truebizid_ev_flex", + "digi_truebizid_ev_flex-EO", + "digi_ssl_dv_geotrust_flex", + "digi_rapidssl", + "digi_rapidssl_wc", + "digi_ssl123_flex", + "digi_sslwebserver_flex", + "digi_sslwebserver_flex-EO", + "digi_sslwebserver_ev_flex", + "digi_sslwebserver_ev_flex-EO", + "positivemdcssl", + "positivemdcwildcard", + "sectigodvucc", + "sectigouccwildcard", + "sectigoevmdc", + "sectigomdcwildcard", + "sectigomdc" + ], + "EnrollmentFieldMapping": "DNS Names Comma Separated", + "Array": true + } + }, + "isCUOrder": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Is CU Order?" + } + }, + "isRenewalOrder": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Is Renewal Order?" + } + }, + "isTrialOrder": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Is Trial Order?" + } + }, + "AdminContact": { + "FirstName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - First Name" + } + }, + "LastName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Last Name" + } + }, + "Phone": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Phone" + } + }, + "Email": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Email" + } + }, + "Title": { + "FieldData": { + "RequiredForProducts": [ + "symantec", + "digi_ssl_ev_basic", + "digi_sslwebserver_ev_flex", + "digi_truebizid_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_ev_flex" + ], + "EnrollmentFieldMapping": "Admin Contact - Title" + } + }, + "OrganizationName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Organization Name" + } + }, + "AddressLine1": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Address" + } + }, + "City": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - City" + } + }, + "Region": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Region" + } + }, + "PostalCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Postal Code" + } + }, + "Country": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Country" + } + } + }, + "TechnicalContact": { + "FirstName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - First Name" + } + }, + "LastName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Last Name" + } + }, + "SubjectFirstName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Subject First Name" + } + }, + "SubjectLastName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Subject Last Name" + } + }, + "Phone": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Phone" + } + }, + "Email": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Email" + } + }, + "Title": { + "FieldData": { + "RequiredForProducts": [ + "symantec", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev_flex" + ], + "EnrollmentFieldMapping": "Technical Contact - Title" + } + }, + "AddressLine1": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Address" + } + }, + "City": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - City" + } + }, + "Region": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Region" + } + }, + "PostalCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Postal Code" + } + }, + "Country": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Country" + } + } + }, + "AutoWWW": { + "FieldData": { + "RequiredForProducts": [ + "positivessl" + ], + "EnrollmentFieldMapping": "AutoWWW" + } + }, + "ApproverEmail": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Approver Email" + } + }, + "FileAuthDVIndicator": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "File Auth Domain Validation" + } + }, + "CNAMEAuthDVIndicator": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "CName Auth Domain Validation" + } + }, + "SignatureHashAlgorithm": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Signature Hash Algorithm" + } + } + } + } +``` + +- *Template Settings - See Configuration Instructional Video on how these work* +``` + "Templates": { + "positivessl": { + "ProductID": "positivessl", + "Parameters": { + "AutoWWW": "True" + } + }, + "positiveevssl": { + "ProductID": "positiveevssl", + "Parameters": {} + }, + "enterpriseproev": { + "ProductID": "enterpriseproev", + "Parameters": {} + }, + "enterpriseproevmdc": { + "ProductID": "enterpriseproevmdc", + "Parameters": {} + }, + "positivesslwildcard": { + "ProductID": "positivesslwildcard", + "Parameters": {} + }, + "positivemdcssl": { + "ProductID": "positivemdcssl", + "Parameters": {} + }, + "positivemdcwildcard": { + "ProductID": "positivemdcwildcard", + "Parameters": {} + }, + "positiveevmdc": { + "ProductID": "positiveevmdc", + "Parameters": {} + }, + "instantssl": { + "ProductID": "instantssl", + "Parameters": {} + }, + "instantsslpro": { + "ProductID": "instantsslpro", + "Parameters": {} + }, + "comodopremiumssl": { + "ProductID": "comodopremiumssl", + "Parameters": {} + }, + "comodopremiumwildcard": { + "ProductID": "comodopremiumwildcard", + "Parameters": {} + }, + "enterprisepro": { + "ProductID": "enterprisepro", + "Parameters": {} + }, + "enterpriseprowc": { + "ProductID": "enterpriseprowc", + "Parameters": {} + }, + "sectigossl": { + "ProductID": "sectigossl", + "Parameters": {} + }, + "sectigodvucc": { + "ProductID": "sectigodvucc", + "Parameters": {} + }, + "sectigoevssl": { + "ProductID": "sectigoevssl", + "Parameters": {} + }, + "sectigoevmdc": { + "ProductID": "sectigoevmdc", + "Parameters": {} + }, + "sectigoovssl": { + "ProductID": "sectigoovssl", + "Parameters": {} + }, + "sectigomdc": { + "ProductID": "sectigomdc", + "Parameters": {} + }, + "sectigomdcwildcard": { + "ProductID": "sectigomdcwildcard", + "Parameters": {} + }, + "sectigoovwildcard": { + "ProductID": "sectigoovwildcard", + "Parameters": {} + }, + "sectigowildcard": { + "ProductID": "sectigowildcard", + "Parameters": {} + }, + "sectigouccwildcard": { + "ProductID": "sectigouccwildcard", + "Parameters": {} + }, + "digi_ssl_ev_basic": { + "ProductID": "digi_ssl_ev_basic", + "Parameters": {} + }, + "digi_ssl_ev_basic-EO": { + "ProductID": "digi_ssl_ev_basic-EO", + "Parameters": {} + }, + "digi_securesite_ev_flex": { + "ProductID": "digi_securesite_ev_flex", + "Parameters": {} + }, + "digi_securesite_ev_flex-EO": { + "ProductID": "digi_securesite_ev_flex-EO", + "Parameters": {} + }, + "digi_securesite_pro_ev_flex": { + "ProductID": "digi_securesite_pro_ev_flex", + "Parameters": {} + }, + "digi_securesite_pro_ev_flex-EO": { + "ProductID": "digi_securesite_pro_ev_flex-EO", + "Parameters": {} + }, + "digi_securesite_pro_flex": { + "ProductID": "digi_securesite_pro_flex", + "Parameters": {} + }, + "digi_securesite_pro_flex-EO": { + "ProductID": "digi_securesite_pro_flex-EO", + "Parameters": {} + }, + "digi_ssl_basic": { + "ProductID": "digi_ssl_basic", + "Parameters": {} + }, + "digi_ssl_basic-EO": { + "ProductID": "digi_ssl_basic-EO", + "Parameters": {} + }, + "digi_securesite_flex": { + "ProductID": "digi_securesite_flex", + "Parameters": {} + }, + "digi_securesite_flex-EO": { + "ProductID": "digi_securesite_flex-EO", + "Parameters": {} + }, + "digi_truebizid_flex": { + "ProductID": "digi_truebizid_flex", + "Parameters": {} + }, + "digi_truebizid_flex-EO": { + "ProductID": "digi_truebizid_flex-EO", + "Parameters": {} + }, + "digi_truebizid_ev_flex": { + "ProductID": "digi_truebizid_ev_flex", + "Parameters": {} + }, + "digi_truebizid_ev_flex-EO": { + "ProductID": "digi_truebizid_ev_flex-EO", + "Parameters": {} + }, + "digi_ssl_dv_geotrust_flex": { + "ProductID": "digi_ssl_dv_geotrust_flex", + "Parameters": {} + }, + "digi_rapidssl": { + "ProductID": "digi_rapidssl", + "Parameters": {} + }, + "digi_rapidssl_wc": { + "ProductID": "digi_rapidssl_wc", + "Parameters": {} + }, + "digi_ssl123_flex": { + "ProductID": "digi_ssl123_flex", + "Parameters": {} + }, + "digi_sslwebserver_flex": { + "ProductID": "digi_sslwebserver_flex", + "Parameters": {} + }, + "digi_sslwebserver_flex-EO": { + "ProductID": "digi_sslwebserver_flex-EO", + "Parameters": {} + }, + "digi_sslwebserver_ev_flex": { + "ProductID": "digi_sslwebserver_ev_flex", + "Parameters": {} + }, + "digi_sslwebserver_ev_flex-EO": { + "ProductID": "digi_sslwebserver_ev_flex-EO", + "Parameters": {} + } + } +``` + +- *Gateway Settings* +``` + "CertificateManagers": null, + "GatewayRegistration": { + "LogicalName": "SSLStore", + "GatewayCertificate": { + "StoreName": "CA", + "StoreLocation": "LocalMachine", + "Thumbprint": "339cdd57cfd5b141169b615ff31428782d1da639" + } + } +``` + +- *Service Settings* (Modify these to be in accordance with Keyfactor Standard Gateway Production Settings) +``` + "ServiceSettings": { + "ViewIdleMinutes": 1, + "FullScanPeriodHours": 1, + "PartialScanPeriodMinutes": 1 + } +``` + +5) Gateway Server - Save the newly modified config.json to the following location "C:\Program Files\Keyfactor\Keyfactor AnyGateway" + +### Template Installation + +1) Command Server - Copy and Unzip the Template Setup Files located [Here](https://github.com/Keyfactor/sslstore-cagateway/raw/main/TemplateSetup.zip) +2) Command Server - Change the Security Settings in the CaTemplateUserSecurity.csv file to the appropriate settings for Test or Production +3) Command Server - Run the CreateTemplate.ps1 file and choose option 1 to create the templates in active directory. + *Note if you get errors the security is likely wrong and you will have to add the security manually according to Keyfactor standards* +4) Command Server - Use the Keyfactor Portal to Import the Templates created in Active Directory in step #3 above +5) Command Server - Run the CreateTemplate.ps1 file and choose option 3 to create all the enrollment fields. + *Note You will have to override the default API Questions to the appropriate information.* + +### Certificate Authority Installation +1) Gateway Server - Start the Keyfactor Gateway Service +2) Run the set Gateway command similar to below +```ps +Set-KeyfactorGatewayConfig -LogicalName "SSLStore" -FilePath [path to json file] -PublishAd +``` +3) Command Server - Import the certificate authority in Keyfactor Portal + +### Release 1.1 Notes +Look over the AutoWWW field in both the Sample Config and readme. If you want to include it for a template see the positivessl sample in the readme. It is also needed as a new field in the SampleRequest Section of the file as shown in the readme. + +*** + +### License +[Apache](https://apache.org/licenses/LICENSE-2.0) + diff --git a/SampleConfig.json b/SampleConfig.json new file mode 100644 index 0000000..dcb3f97 --- /dev/null +++ b/SampleConfig.json @@ -0,0 +1,1084 @@ +{ + "Security": { + "KEYFACTOR\\administrator": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + }, + "KEYFACTOR\\SVC_AppPool": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + }, + "KEYFACTOR\\SVC_TimerService": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + } + }, + "CAConnection": { + "SSLStoreURL": "https://sandbox-wbapi.thesslstore.com", + "PartnerCode": "SomePartnerCodeFromSSLStore", + "AuthToken": "SomeAuthTokenFromSSLStore", + "KeyfactorApiUrl": "https://kftrain.keyfactor.lab/KeyfactorAPI", + "KeyfactorApiUserId": "SomeKeyfactorAPIUser", + "KeyfactorApiPassword": "SomeKeyfactorAPIPassword", + "PageSize": "25", + "SampleRequest": { + "AuthRequest": { + "PartnerCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + }, + "AuthToken": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + } + }, + "ProductCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + }, + "TSSOrganizationId": { + "FieldData": { + "RequiredForProducts": [ + "None" + ], + "EnrollmentFieldMapping": "Organization ID" + } + }, + "OrganizationInfo": { + "OrganizationName": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization Name" + } + }, + "RegistrationNumber": { + "FieldData": { + "RequiredForProducts": [ + "certum" + ], + "EnrollmentFieldMapping": "Organization Registration Number" + } + }, + "JurisdictionCountry": { + "FieldData": { + "RequiredForProducts": [ + "comodoevssl", + "comodoevcsc", + "comodoevmdc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "positiveevssl" + ], + "EnrollmentFieldMapping": "Organization Jurisdiction Country" + } + }, + "OrganizationAddress": { + "AddressLine1": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization Address" + } + }, + "Region": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization State/Province" + } + }, + "PostalCode": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization Postal Code" + } + }, + "LocalityName": { + "FieldData": { + "RequiredForProducts": [ + "comodocsc", + "comodoevssl", + "comodoevcsc", + "comodoevmdc", + "comodomdc", + "comodomdcwildcard", + "comodouccwildcard", + "comodoucc", + "pacenterprise" + ], + "EnrollmentFieldMapping": "Organization Locality Name" + } + }, + "Country": { + "FieldData": { + "RequiredForProducts": [ + "truebizidmd", + "digi_ev_md_ssl", + "digi_md_ssl", + "digi_plus_ev_ssl", + "digi_plus_ssl", + "digi_securesite", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_ssl_basic", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev_flex", + "digi_securesite_flex", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex" + ], + "EnrollmentFieldMapping": "Organization Country" + } + }, + "Phone": { + "FieldData": { + "RequiredForProducts": [ + "truebizidmd", + "digi_ev_md_ssl", + "digi_md_ssl", + "digi_plus_ev_ssl", + "digi_plus_ssl", + "digi_securesite", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_ssl_basic", + "digi_sslwebserver_ev_flex", + "digi_truebizid_ev_flex", + "digi_securesite_flex", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex" + ], + "EnrollmentFieldMapping": "Organization Phone" + } + } + } + }, + "ValidityPeriod": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Validity Period (In Months)" + } + }, + "ServerCount": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Server Count" + } + }, + "CSR": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + }, + "DomainName": { + "FieldData": { + "RequiredForProducts": [ + "Certum" + ], + "EnrollmentFieldMapping": "Domain Name" + } + }, + "WebServerType": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Web Server Type" + } + }, + "DNSNames": { + "FieldData": { + "RequiredForProducts": [ + "digi_ssl_ev_basic", + "digi_ssl_ev_basic-EO", + "digi_securesite_ev_flex", + "digi_securesite_ev_flex-EO", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_ev_flex-EO", + "digi_securesite_pro_flex", + "digi_securesite_pro_flex-EO", + "digi_ssl_basic", + "digi_ssl_basic-EO", + "digi_securesite_flex", + "digi_securesite_flex-EO", + "digi_truebizid_flex", + "digi_truebizid_flex-EO", + "digi_truebizid_ev_flex", + "digi_truebizid_ev_flex-EO", + "digi_ssl_dv_geotrust_flex", + "digi_rapidssl", + "digi_rapidssl_wc", + "digi_ssl123_flex", + "digi_sslwebserver_flex", + "digi_sslwebserver_flex-EO", + "digi_sslwebserver_ev_flex", + "digi_sslwebserver_ev_flex-EO", + "positivemdcssl", + "positivemdcwildcard", + "sectigodvucc", + "sectigouccwildcard", + "sectigoevmdc", + "sectigomdcwildcard", + "sectigomdc" + ], + "EnrollmentFieldMapping": "DNS Names Comma Separated", + "Array": true + } + }, + "isCUOrder": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Is CU Order?" + } + }, + "isRenewalOrder": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Is Renewal Order?" + } + }, + "isTrialOrder": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Is Trial Order?" + } + }, + "AdminContact": { + "FirstName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - First Name" + } + }, + "LastName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Last Name" + } + }, + "Phone": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Phone" + } + }, + "Email": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Email" + } + }, + "Title": { + "FieldData": { + "RequiredForProducts": [ + "symantec", + "digi_ssl_ev_basic", + "digi_sslwebserver_ev_flex", + "digi_truebizid_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_ev_flex" + ], + "EnrollmentFieldMapping": "Admin Contact - Title" + } + }, + "OrganizationName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Organization Name" + } + }, + "AddressLine1": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Address" + } + }, + "City": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - City" + } + }, + "Region": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Region" + } + }, + "PostalCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Postal Code" + } + }, + "Country": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Country" + } + } + }, + "TechnicalContact": { + "FirstName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - First Name" + } + }, + "LastName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Last Name" + } + }, + "SubjectFirstName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Subject First Name" + } + }, + "SubjectLastName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Subject Last Name" + } + }, + "Phone": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Phone" + } + }, + "Email": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Email" + } + }, + "Title": { + "FieldData": { + "RequiredForProducts": [ + "symantec", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev_flex" + ], + "EnrollmentFieldMapping": "Technical Contact - Title" + } + }, + "AddressLine1": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Address" + } + }, + "City": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - City" + } + }, + "Region": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Region" + } + }, + "PostalCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Postal Code" + } + }, + "Country": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Country" + } + } + }, + "ApproverEmail": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Approver Email" + } + }, + "AutoWWW": { + "FieldData": { + "RequiredForProducts": [ + "positivessl" + ], + "EnrollmentFieldMapping": "AutoWWW" + } + }, + "FileAuthDVIndicator": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "File Auth Domain Validation" + } + }, + "CNAMEAuthDVIndicator": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "CName Auth Domain Validation" + } + }, + "SignatureHashAlgorithm": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Signature Hash Algorithm" + } + } + } + }, + "Templates": { + "positivessl": { + "ProductID": "positivessl", + "Parameters": { + "Parameters": { + "AutoWWW": "True" + } + } + }, + "positiveevssl": { + "ProductID": "positiveevssl", + "Parameters": {} + }, + "enterpriseproev": { + "ProductID": "enterpriseproev", + "Parameters": {} + }, + "enterpriseproevmdc": { + "ProductID": "enterpriseproevmdc", + "Parameters": {} + }, + "positivesslwildcard": { + "ProductID": "positivesslwildcard", + "Parameters": {} + }, + "positivemdcssl": { + "ProductID": "positivemdcssl", + "Parameters": {} + }, + "positivemdcwildcard": { + "ProductID": "positivemdcwildcard", + "Parameters": {} + }, + "positiveevmdc": { + "ProductID": "positiveevmdc", + "Parameters": {} + }, + "instantssl": { + "ProductID": "instantssl", + "Parameters": {} + }, + "instantsslpro": { + "ProductID": "instantsslpro", + "Parameters": {} + }, + "comodopremiumssl": { + "ProductID": "comodopremiumssl", + "Parameters": {} + }, + "comodopremiumwildcard": { + "ProductID": "comodopremiumwildcard", + "Parameters": {} + }, + "enterprisepro": { + "ProductID": "enterprisepro", + "Parameters": {} + }, + "enterpriseprowc": { + "ProductID": "enterpriseprowc", + "Parameters": {} + }, + "sectigossl": { + "ProductID": "sectigossl", + "Parameters": {} + }, + "sectigodvucc": { + "ProductID": "sectigodvucc", + "Parameters": {} + }, + "sectigoevssl": { + "ProductID": "sectigoevssl", + "Parameters": {} + }, + "sectigoevmdc": { + "ProductID": "sectigoevmdc", + "Parameters": {} + }, + "sectigoovssl": { + "ProductID": "sectigoovssl", + "Parameters": {} + }, + "sectigomdc": { + "ProductID": "sectigomdc", + "Parameters": {} + }, + "sectigomdcwildcard": { + "ProductID": "sectigomdcwildcard", + "Parameters": {} + }, + "sectigoovwildcard": { + "ProductID": "sectigoovwildcard", + "Parameters": {} + }, + "sectigowildcard": { + "ProductID": "sectigowildcard", + "Parameters": {} + }, + "sectigouccwildcard": { + "ProductID": "sectigouccwildcard", + "Parameters": {} + }, + "digi_ssl_ev_basic": { + "ProductID": "digi_ssl_ev_basic", + "Parameters": {} + }, + "digi_ssl_ev_basic-EO": { + "ProductID": "digi_ssl_ev_basic-EO", + "Parameters": {} + }, + "digi_securesite_ev_flex": { + "ProductID": "digi_securesite_ev_flex", + "Parameters": {} + }, + "digi_securesite_ev_flex-EO": { + "ProductID": "digi_securesite_ev_flex-EO", + "Parameters": {} + }, + "digi_securesite_pro_ev_flex": { + "ProductID": "digi_securesite_pro_ev_flex", + "Parameters": {} + }, + "digi_securesite_pro_ev_flex-EO": { + "ProductID": "digi_securesite_pro_ev_flex-EO", + "Parameters": {} + }, + "digi_securesite_pro_flex": { + "ProductID": "digi_securesite_pro_flex", + "Parameters": {} + }, + "digi_securesite_pro_flex-EO": { + "ProductID": "digi_securesite_pro_flex-EO", + "Parameters": {} + }, + "digi_ssl_basic": { + "ProductID": "digi_ssl_basic", + "Parameters": {} + }, + "digi_ssl_basic-EO": { + "ProductID": "digi_ssl_basic-EO", + "Parameters": {} + }, + "digi_securesite_flex": { + "ProductID": "digi_securesite_flex", + "Parameters": {} + }, + "digi_securesite_flex-EO": { + "ProductID": "digi_securesite_flex-EO", + "Parameters": {} + }, + "digi_truebizid_flex": { + "ProductID": "digi_truebizid_flex", + "Parameters": {} + }, + "digi_truebizid_flex-EO": { + "ProductID": "digi_truebizid_flex-EO", + "Parameters": {} + }, + "digi_truebizid_ev_flex": { + "ProductID": "digi_truebizid_ev_flex", + "Parameters": {} + }, + "digi_truebizid_ev_flex-EO": { + "ProductID": "digi_truebizid_ev_flex-EO", + "Parameters": {} + }, + "digi_ssl_dv_geotrust_flex": { + "ProductID": "digi_ssl_dv_geotrust_flex", + "Parameters": {} + }, + "digi_rapidssl": { + "ProductID": "digi_rapidssl", + "Parameters": {} + }, + "digi_rapidssl_wc": { + "ProductID": "digi_rapidssl_wc", + "Parameters": {} + }, + "digi_ssl123_flex": { + "ProductID": "digi_ssl123_flex", + "Parameters": {} + }, + "digi_sslwebserver_flex": { + "ProductID": "digi_sslwebserver_flex", + "Parameters": {} + }, + "digi_sslwebserver_flex-EO": { + "ProductID": "digi_sslwebserver_flex-EO", + "Parameters": {} + }, + "digi_sslwebserver_ev_flex": { + "ProductID": "digi_sslwebserver_ev_flex", + "Parameters": {} + }, + "digi_sslwebserver_ev_flex-EO": { + "ProductID": "digi_sslwebserver_ev_flex-EO", + "Parameters": {} + } + }, + "CertificateManagers": null, + "GatewayRegistration": { + "LogicalName": "SSLStore", + "GatewayCertificate": { + "StoreName": "CA", + "StoreLocation": "LocalMachine", + "Thumbprint": "339cdd57cfd5b141169b615ff31428782d1da639" + } + }, + "ServiceSettings": { + "ViewIdleMinutes": 1, + "FullScanPeriodHours": 1, + "PartialScanPeriodMinutes": 1 + } +} \ No newline at end of file diff --git a/SslStoreCaProxy.slnx b/SslStoreCaProxy.slnx new file mode 100644 index 0000000..ba17d13 --- /dev/null +++ b/SslStoreCaProxy.slnx @@ -0,0 +1,3 @@ + + + diff --git a/SslStoreCaProxy/Client/Models/AddSan.cs b/SslStoreCaProxy/Client/Models/AddSan.cs new file mode 100644 index 0000000..733d3ed --- /dev/null +++ b/SslStoreCaProxy/Client/Models/AddSan.cs @@ -0,0 +1,10 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class AddSan : IAddSan + { + public string OldValue { get; set; } + public string NewValue { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/AdminContact.cs b/SslStoreCaProxy/Client/Models/AdminContact.cs new file mode 100644 index 0000000..c0d6fa9 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/AdminContact.cs @@ -0,0 +1,23 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class AdminContact : IAdminContact + { + public string FirstName { get; set; } + public string LastName { get; set; } + public string SubjectFirstName { get; set; } + public string SubjectLastName { get; set; } + public string Phone { get; set; } + public string Fax { get; set; } + public string Email { get; set; } + public string Title { get; set; } + public string OrganizationName { get; set; } + public string AddressLine1 { get; set; } + public string AddressLine2 { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/AuthRequest.cs b/SslStoreCaProxy/Client/Models/AuthRequest.cs new file mode 100644 index 0000000..2405499 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/AuthRequest.cs @@ -0,0 +1,22 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class AuthRequest : IAuthRequest + { + public string PartnerCode { get; set; } + public string AuthToken { get; set; } + public string ReplayToken { get; set; } + public string UserAgent { get; set; } + + [JsonProperty("TokenID")] public string TokenId { get; set; } + + public string TokenCode { get; set; } + + [JsonProperty("IPAddress")] public string IpAddress { get; set; } + + public bool IsUsedForTokenSystem { get; set; } + public string Token { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/AuthResponse.cs b/SslStoreCaProxy/Client/Models/AuthResponse.cs new file mode 100644 index 0000000..77a95be --- /dev/null +++ b/SslStoreCaProxy/Client/Models/AuthResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class AuthResponse : IAuthResponse + { + [JsonProperty("isError")] public bool IsError { get; set; } + + public List Message { get; set; } + public string Timestamp { get; set; } + public string ReplayToken { get; set; } + public string InvokingPartnerCode { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/AuthenticationStatus.cs b/SslStoreCaProxy/Client/Models/AuthenticationStatus.cs new file mode 100644 index 0000000..8f4651c --- /dev/null +++ b/SslStoreCaProxy/Client/Models/AuthenticationStatus.cs @@ -0,0 +1,11 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class AuthenticationStatus : IAuthenticationStatus + { + public string AuthenticationStep { get; set; } + public string Status { get; set; } + public string LastUpdated { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/Certificate.cs b/SslStoreCaProxy/Client/Models/Certificate.cs new file mode 100644 index 0000000..1a99e81 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/Certificate.cs @@ -0,0 +1,8 @@ +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class Certificate + { + public string FileContent { get; set; } + public string FileName { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/DeleteSan.cs b/SslStoreCaProxy/Client/Models/DeleteSan.cs new file mode 100644 index 0000000..4bc6ff4 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/DeleteSan.cs @@ -0,0 +1,8 @@ +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class DeleteSan + { + public string OldValue { get; set; } + public string NewValue { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/DomainAuthVettingStatus.cs b/SslStoreCaProxy/Client/Models/DomainAuthVettingStatus.cs new file mode 100644 index 0000000..8bb0335 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/DomainAuthVettingStatus.cs @@ -0,0 +1,27 @@ +using System; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class DomainAuthVettingStatus : IDomainAuthVettingStatus + { + [JsonProperty("domain")] public string Domain { get; set; } + + [JsonProperty("dcvMethod")] public string DcvMethod { get; set; } + + [JsonProperty("dcvStatus")] public string DcvStatus { get; set; } + + public string FileName { get; set; } + public string FileContents { get; set; } + + [JsonProperty("DNSName")] public string DnsName { get; set; } + + [JsonProperty("DNSEntry")] public string DnsEntry { get; set; } + + public string PollStatus { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public DateTime LastPollDate { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/DownloadCertificateRequest.cs b/SslStoreCaProxy/Client/Models/DownloadCertificateRequest.cs new file mode 100644 index 0000000..23de171 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/DownloadCertificateRequest.cs @@ -0,0 +1,11 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class DownloadCertificateRequest : IDownloadCertificateRequest + { + public AuthRequest AuthRequest { get; set; } + [JsonProperty("TheSSLStoreOrderID")] public string TheSslStoreOrderId { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/DownloadCertificateResponse.cs b/SslStoreCaProxy/Client/Models/DownloadCertificateResponse.cs new file mode 100644 index 0000000..de4093b --- /dev/null +++ b/SslStoreCaProxy/Client/Models/DownloadCertificateResponse.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class DownloadCertificateResponse : IDownloadCertificateResponse + { + public AuthResponse AuthResponse { get; set; } + public string CertificateEndDate { get; set; } + + [JsonProperty("CertificateEndDateInUTC")] + public string CertificateEndDateInUtc { get; set; } + + public string CertificateStartDate { get; set; } + + [JsonProperty("CertificateStartDateInUTC")] + public string CertificateStartDateInUtc { get; set; } + + public string CertificateStatus { get; set; } + public List Certificates { get; set; } + [JsonProperty("PartnerOrderID")] public string PartnerOrderId { get; set; } + [JsonProperty("TheSSLStoreOrderID")] public object TheSslStoreOrderId { get; set; } + public string ValidationStatus { get; set; } + [JsonProperty("VendorOrderID")] public object VendorOrderId { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/EditSan.cs b/SslStoreCaProxy/Client/Models/EditSan.cs new file mode 100644 index 0000000..184c01c --- /dev/null +++ b/SslStoreCaProxy/Client/Models/EditSan.cs @@ -0,0 +1,8 @@ +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class EditSan + { + public string OldValue { get; set; } + public string NewValue { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/EmailApproverRequest.cs b/SslStoreCaProxy/Client/Models/EmailApproverRequest.cs new file mode 100644 index 0000000..98eeeae --- /dev/null +++ b/SslStoreCaProxy/Client/Models/EmailApproverRequest.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class EmailApproverRequest : IEmailApproverRequest + { + public AuthRequest AuthRequest { get; set; } + public string ProductCode { get; set; } + public string DomainName { get; set; } + } +} diff --git a/SslStoreCaProxy/Client/Models/EmailApproverResponse.cs b/SslStoreCaProxy/Client/Models/EmailApproverResponse.cs new file mode 100644 index 0000000..4c48104 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/EmailApproverResponse.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class EmailApproverResponse : IEmailApproverResponse + { + public List ApproverEmailList { get; set; } + public AuthResponse AuthResponse { get; set; } + [JsonProperty("baseDomainName", NullValueHandling = NullValueHandling.Ignore)] + public string BaseDomainName { get; set; } + } +} diff --git a/SslStoreCaProxy/Client/Models/EnrollmentField.cs b/SslStoreCaProxy/Client/Models/EnrollmentField.cs new file mode 100644 index 0000000..580b8a8 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/EnrollmentField.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class EnrollmentField : IEnrollmentField + { + public int Id { get; set; } + public string Name { get; set; } + public List Options { get; set; } = new List(); + public int DataType { get; set; } + } +} diff --git a/SslStoreCaProxy/Client/Models/NewOrderRequest.cs b/SslStoreCaProxy/Client/Models/NewOrderRequest.cs new file mode 100644 index 0000000..7877e6d --- /dev/null +++ b/SslStoreCaProxy/Client/Models/NewOrderRequest.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class NewOrderRequest : INewOrderRequest + { + public AuthRequest AuthRequest { get; set; } + + [JsonProperty("CustomOrderID", NullValueHandling = NullValueHandling.Ignore)] + public string CustomOrderId { get; set; } + + public string ProductCode { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string ExtraProductCodes { get; set; } + + public OrganizationInfo OrganizationInfo { get; set; } + + [JsonProperty("TSSOrganizationId", NullValueHandling = NullValueHandling.Ignore)] + public long TssOrganizationId { get; set; } + + public long ValidityPeriod { get; set; } + + public long ServerCount { get; set; } + + [JsonProperty("CSR")] public string Csr { get; set; } + + public string DomainName { get; set; } + + public string WebServerType { get; set; } + + [JsonProperty("DNSNames", NullValueHandling = NullValueHandling.Ignore)] + public List DnsNames { get; set; } + + [JsonProperty("isCUOrder")] public bool IsCuOrder { get; set; } + + [JsonProperty("AutoWWW", NullValueHandling = NullValueHandling.Ignore,DefaultValueHandling =DefaultValueHandling.Ignore)] + public bool? AutoWWW { get; set; } + + [JsonProperty("isRenewalOrder")] public bool IsRenewalOrder { get; set; } + + public string SpecialInstructions { get; set; } + + [JsonProperty("RelatedTheSSLStoreOrderID", NullValueHandling = NullValueHandling.Ignore)] + public string RelatedTheSslStoreOrderId { get; set; } + + [JsonProperty("isTrialOrder")] public bool IsTrialOrder { get; set; } + + public AdminContact AdminContact { get; set; } + + public TechnicalContact TechnicalContact { get; set; } + + public string ApproverEmail { get; set; } + + [JsonProperty("ReserveSANCount", NullValueHandling = NullValueHandling.Ignore)] + public long ReserveSanCount { get; set; } + + public bool AddInstallationSupport { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string EmailLanguageCode { get; set; } + + [JsonProperty("FileAuthDVIndicator")] public bool? FileAuthDvIndicator { get; set; } + + [JsonProperty("CNAMEAuthDVIndicator", NullValueHandling = NullValueHandling.Ignore)] + public bool? CnameAuthDvIndicator { get; set; } + + [JsonProperty("HTTPSFileAuthDVIndicator", NullValueHandling = NullValueHandling.Ignore)] + public bool HttpsFileAuthDvIndicator { get; set; } + + public string SignatureHashAlgorithm { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public bool CertTransparencyIndicator { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public long RenewalDays { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string DateTimeCulture { get; set; } + + [JsonProperty("CSRUniqueValue", NullValueHandling = NullValueHandling.Ignore)] + public string CsrUniqueValue { get; set; } + + [JsonProperty("isPKCS10", NullValueHandling = NullValueHandling.Ignore)] + public bool IsPkcs10 { get; set; } + + [JsonProperty("WildcardReserveSANCount", NullValueHandling = NullValueHandling.Ignore)] + public long WildcardReserveSanCount { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string ProvisioningMethod { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/NewOrderResponse.cs b/SslStoreCaProxy/Client/Models/NewOrderResponse.cs new file mode 100644 index 0000000..b664105 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/NewOrderResponse.cs @@ -0,0 +1,75 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class NewOrderResponse : INewOrderResponse + { + public AdminContact AdminContact { get; set; } + public string ApproverEmail { get; set; } + public string AuthFileContent { get; set; } + public string AuthFileName { get; set; } + public AuthResponse AuthResponse { get; set; } + [JsonProperty("CNAMEAuthName")] public string CnameAuthName { get; set; } + [JsonProperty("CNAMEAuthValue")] public string CnameAuthValue { get; set; } + public string CertificateEndDate { get; set; } + + [JsonProperty("CertificateEndDateInUTC")] + public string CertificateEndDateInUtc { get; set; } + + public string CertificateStartDate { get; set; } + + [JsonProperty("CertificateStartDateInUTC")] + public string CertificateStartDateInUtc { get; set; } + + public string CommonName { get; set; } + public string Country { get; set; } + [JsonProperty("CustomOrderID")] public string CustomOrderId { get; set; } + [JsonProperty("CustomerID")] public int CustomerId { get; set; } + public string CustomerLoginName { get; set; } + public string CustomerPassword { get; set; } + [JsonProperty("DNSNames")] public string DnsNames { get; set; } + [JsonProperty("DUNS")] public string Duns { get; set; } + public string Locality { get; set; } + public string OrderAmount { get; set; } + public string OrderExpiryDate { get; set; } + [JsonProperty("OrderExpiryDateInUTC")] public string OrderExpiryDateInUtc { get; set; } + public OrderStatus OrderStatus { get; set; } + public string Organization { get; set; } + public string OrganizationAddress { get; set; } + public string OrganizationPhone { get; set; } + public string OrganizationPostalcode { get; set; } + public string OrganizationalUnit { get; set; } + [JsonProperty("PartnerOrderID")] public string PartnerOrderId { get; set; } + public string PollDate { get; set; } + [JsonProperty("PollDateInUTC")] public string PollDateInUtc { get; set; } + public string PollStatus { get; set; } + public string ProductCode { get; set; } + public string ProductName { get; set; } + public string PurchaseDate { get; set; } + [JsonProperty("PurchaseDateInUTC")] public string PurchaseDateInUtc { get; set; } + [JsonProperty("RefundRequestID")] public string RefundRequestId { get; set; } + public string ReissueSuccessCode { get; set; } + [JsonProperty("SANCount")] public int SanCount { get; set; } + public string SerialNumber { get; set; } + public int ServerCount { get; set; } + public string SignatureEncryptionAlgorithm { get; set; } + public string SignatureHashAlgorithm { get; set; } + public string SiteSealurl { get; set; } + public string State { get; set; } + public string SubVendorName { get; set; } + [JsonProperty("TSSOrganizationId")] public int TssOrganizationId { get; set; } + public TechnicalContact TechnicalContact { get; set; } + [JsonProperty("TheSSLStoreOrderID")] public string TheSslStoreOrderId { get; set; } + public string TinyOrderLink { get; set; } + public string Token { get; set; } + public string TokenCode { get; set; } + [JsonProperty("TokenID")] public string TokenId { get; set; } + public int Validity { get; set; } + public string VendorName { get; set; } + [JsonProperty("VendorOrderID")] public string VendorOrderId { get; set; } + public string WebServerType { get; set; } + [JsonProperty("isRefundApproved")] public bool IsRefundApproved { get; set; } + [JsonProperty("wildcardSANCount")] public int WildcardSanCount { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/OrderNote.cs b/SslStoreCaProxy/Client/Models/OrderNote.cs new file mode 100644 index 0000000..1ae23f6 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/OrderNote.cs @@ -0,0 +1,10 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class OrderNote : IOrderNote + { + public string Comments { get; set; } + public string DateAdded { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/OrderStatus.cs b/SslStoreCaProxy/Client/Models/OrderStatus.cs new file mode 100644 index 0000000..068f970 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/OrderStatus.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class OrderStatus : IOrderStatus + { + [JsonProperty("isTinyOrder")] public bool IsTinyOrder { get; set; } + + [JsonProperty("isTinyOrderClaimed")] public bool IsTinyOrderClaimed { get; set; } + + public string MajorStatus { get; set; } + public string MinorStatus { get; set; } + public List AuthenticationStatuses { get; set; } + public string AuthenticationComments { get; set; } + public List OrderNotes { get; set; } + public List DomainAuthVettingStatus { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/OrderStatusRequest.cs b/SslStoreCaProxy/Client/Models/OrderStatusRequest.cs new file mode 100644 index 0000000..81ac958 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/OrderStatusRequest.cs @@ -0,0 +1,11 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class OrderStatusRequest : IOrderStatusRequest + { + public AuthRequest AuthRequest { get; set; } + [JsonProperty("TheSSLStoreOrderID")] public string TheSslStoreOrderId { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/OrderStatusResponse.cs b/SslStoreCaProxy/Client/Models/OrderStatusResponse.cs new file mode 100644 index 0000000..7a23f52 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/OrderStatusResponse.cs @@ -0,0 +1,68 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class OrderStatusResponse : IOrderStatusResponse + { + public AuthResponse AuthResponse { get; set; } + [JsonProperty("PartnerOrderID")] public string PartnerOrderId { get; set; } + [JsonProperty("CustomOrderID")] public string CustomOrderId { get; set; } + [JsonProperty("TheSSLStoreOrderID")] public string TheSslStoreOrderId { get; set; } + [JsonProperty("VendorOrderID")] public string VendorOrderId { get; set; } + [JsonProperty("RefundRequestID")] public string RefundRequestId { get; set; } + [JsonProperty("isRefundApproved")] public bool IsRefundApproved { get; set; } + public string TinyOrderLink { get; set; } + public OrderStatus OrderStatus { get; set; } + public string OrderAmount { get; set; } + public string PurchaseDate { get; set; } + public string CertificateStartDate { get; set; } + public string CertificateEndDate { get; set; } + public string CommonName { get; set; } + [JsonProperty("DNSNames")] public string DnsNames { get; set; } + [JsonProperty("SANCount")] public long SanCount { get; set; } + public long ServerCount { get; set; } + public long Validity { get; set; } + public string Organization { get; set; } + public string OrganizationalUnit { get; set; } + public string State { get; set; } + public string Country { get; set; } + public string Locality { get; set; } + public string OrganizationPhone { get; set; } + public string OrganizationAddress { get; set; } + public string OrganizationPostalcode { get; set; } + [JsonProperty("DUNS")] public string Duns { get; set; } + public string WebServerType { get; set; } + public string ApproverEmail { get; set; } + public string ProductName { get; set; } + public AdminContact AdminContact { get; set; } + public TechnicalContact TechnicalContact { get; set; } + public string ReissueSuccessCode { get; set; } + public string AuthFileName { get; set; } + public string AuthFileContent { get; set; } + public string PollStatus { get; set; } + public string PollDate { get; set; } + public string CustomerLoginName { get; set; } + public string CustomerPassword { get; set; } + [JsonProperty("CustomerID")] public long CustomerId { get; set; } + [JsonProperty("TokenID")] public string TokenId { get; set; } + public string TokenCode { get; set; } + public string SiteSealurl { get; set; } + [JsonProperty("CNAMEAuthName")] public string CnameAuthName { get; set; } + [JsonProperty("CNAMEAuthValue")] public string CnameAuthValue { get; set; } + public string SignatureEncryptionAlgorithm { get; set; } + public string SignatureHashAlgorithm { get; set; } + public string VendorName { get; set; } + public string SubVendorName { get; set; } + public string Token { get; set; } + + [JsonProperty("CertificateStartDateInUTC")] + public string CertificateStartDateInUtc { get; set; } + + [JsonProperty("CertificateEndDateInUTC")] + public string CertificateEndDateInUtc { get; set; } + + [JsonProperty("PurchaseDateInUTC")] public string PurchaseDateInUtc { get; set; } + [JsonProperty("PollDateInUTC")] public string PollDateInUtc { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/Organization.cs b/SslStoreCaProxy/Client/Models/Organization.cs new file mode 100644 index 0000000..7b6410d --- /dev/null +++ b/SslStoreCaProxy/Client/Models/Organization.cs @@ -0,0 +1,25 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class Organization : IOrganization + { + public string Address { get; set; } + public string Address2 { get; set; } + public object ApproversContact { get; set; } + public string AssumedName { get; set; } + public string City { get; set; } + public string Country { get; set; } + public string Name { get; set; } + public OrganizationContact OrganizationContact { get; set; } + [JsonProperty("Organization_Phone", NullValueHandling = NullValueHandling.Ignore)] + public string OrganizationPhone { get; set; } + public string State { get; set; } + public string Zip { get; set; } + public string Status { get; set; } + [JsonProperty("TSSOrganizationId", NullValueHandling = NullValueHandling.Ignore)] + public int TssOrganizationId { get; set; } + public int VendorOrganizationId { get; set; } + } +} diff --git a/SslStoreCaProxy/Client/Models/OrganizationAddress.cs b/SslStoreCaProxy/Client/Models/OrganizationAddress.cs new file mode 100644 index 0000000..d2d6b95 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/OrganizationAddress.cs @@ -0,0 +1,18 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class OrganizationAddress : IOrganizationAddress + { + public string AddressLine1 { get; set; } + public string AddressLine2 { get; set; } + public string AddressLine3 { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + public string Phone { get; set; } + public string Fax { get; set; } + public string LocalityName { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/OrganizationContact.cs b/SslStoreCaProxy/Client/Models/OrganizationContact.cs new file mode 100644 index 0000000..61e953c --- /dev/null +++ b/SslStoreCaProxy/Client/Models/OrganizationContact.cs @@ -0,0 +1,18 @@ + +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class OrganizationContact : IOrganizationContact + { + public string Email { get; set; } + public string Firstname { get; set; } + public string JobTitle { get; set; } + public string Lastname { get; set; } + public string Phone { get; set; } + [JsonProperty("Phone_Extension", NullValueHandling = NullValueHandling.Ignore)] + public string PhoneExtension { get; set; } + public string Username { get; set; } + } +} diff --git a/SslStoreCaProxy/Client/Models/OrganizationInfo.cs b/SslStoreCaProxy/Client/Models/OrganizationInfo.cs new file mode 100644 index 0000000..ef76148 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/OrganizationInfo.cs @@ -0,0 +1,21 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class OrganizationInfo : IOrganizationInfo + { + public string OrganizationName { get; set; } + + [JsonProperty("DUNS")] public string Duns { get; set; } + + public string Division { get; set; } + public string IncorporatingAgency { get; set; } + public string RegistrationNumber { get; set; } + public string JurisdictionCity { get; set; } + public string JurisdictionRegion { get; set; } + public string JurisdictionCountry { get; set; } + public string AssumedName { get; set; } + public OrganizationAddress OrganizationAddress { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/OrganizationListRequest.cs b/SslStoreCaProxy/Client/Models/OrganizationListRequest.cs new file mode 100644 index 0000000..16dffb3 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/OrganizationListRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class OrganizationListRequest : IOrganizationListRequest + { + public string PartnerCode { get; set; } + public string AuthToken { get; set; } + } +} diff --git a/SslStoreCaProxy/Client/Models/OrganizationResponse.cs b/SslStoreCaProxy/Client/Models/OrganizationResponse.cs new file mode 100644 index 0000000..6ef3038 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/OrganizationResponse.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class OrganizationResponse : IOrganizationResponse + { + public AuthResponse AuthResponse { get; set; } + public List OrganizationList { get; set; } + } +} diff --git a/SslStoreCaProxy/Client/Models/QueryOrderRequest.cs b/SslStoreCaProxy/Client/Models/QueryOrderRequest.cs new file mode 100644 index 0000000..dd90de4 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/QueryOrderRequest.cs @@ -0,0 +1,41 @@ +using System; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class QueryOrderRequest : IQueryOrderRequest + { + public AuthRequest AuthRequest { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public DateTime? StartDate { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public DateTime? EndDate { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public DateTime? CertificateExpireToDate { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public DateTime? CertificateExpireFromDate { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string DomainName { get; set; } + + [JsonProperty("SubUserID", NullValueHandling = NullValueHandling.Ignore)] + public string SubUserId { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string ProductCode { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string DateTimeCulture { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public long PageNumber { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public long PageSize { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/ReIssueRequest.cs b/SslStoreCaProxy/Client/Models/ReIssueRequest.cs new file mode 100644 index 0000000..17c55b3 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/ReIssueRequest.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class ReIssueRequest : IReIssueRequest + { + public AuthRequest AuthRequest { get; set; } + [JsonProperty("TheSSLStoreOrderID")] public string TheSslStoreOrderId { get; set; } + [JsonProperty("CSR")] public string Csr { get; set; } + public string WebServerType { get; set; } + [JsonProperty("DNSNames")] public List DnsNames { get; set; } + [JsonProperty("isRenewalOrder")] public bool IsRenewalOrder { get; set; } + public string SpecialInstructions { get; set; } + [JsonProperty("EditSAN")] public List EditSan { get; set; } + [JsonProperty("DeleteSAN")] public List DeleteSan { get; set; } + [JsonProperty("AddSAN")] public List AddSan { get; set; } + [JsonProperty("isWildCard")] public bool IsWildCard { get; set; } + public string ReissueEmail { get; set; } + public bool PreferEnrollmentLink { get; set; } + public string SignatureHashAlgorithm { get; set; } + [JsonProperty("FileAuthDVIndicator")] public bool FileAuthDvIndicator { get; set; } + + [JsonProperty("HTTPSFileAuthDVIndicator")] + public bool HttpsFileAuthDvIndicator { get; set; } + + [JsonProperty("CNAMEAuthDVIndicator")] public bool CNameAuthDvIndicator { get; set; } + public string ApproverEmails { get; set; } + public string DateTimeCulture { get; set; } + [JsonProperty("CSRUniqueValue")] public string CsrUniqueValue { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/RevokeOrderRequest.cs b/SslStoreCaProxy/Client/Models/RevokeOrderRequest.cs new file mode 100644 index 0000000..2e71652 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/RevokeOrderRequest.cs @@ -0,0 +1,12 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class RevokeOrderRequest : IRevokeOrderRequest + { + public AuthRequest AuthRequest { get; set; } + [JsonProperty("TheSSLStoreOrderID")] public string TheSslStoreOrderId { get; set; } + public string SerialNumber { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/RevokeOrderResponse.cs b/SslStoreCaProxy/Client/Models/RevokeOrderResponse.cs new file mode 100644 index 0000000..95abb0b --- /dev/null +++ b/SslStoreCaProxy/Client/Models/RevokeOrderResponse.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class RevokeOrderResponse : IRevokeOrderResponse + { + public string InvokingPartnerCode { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public List Message { get; set; } + + public object ReplayToken { get; set; } + public string Timestamp { get; set; } + [JsonProperty("isError")] public bool IsError { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/TechnicalContact.cs b/SslStoreCaProxy/Client/Models/TechnicalContact.cs new file mode 100644 index 0000000..53c96f4 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/TechnicalContact.cs @@ -0,0 +1,23 @@ +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class TechnicalContact : ITechnicalContact + { + public string FirstName { get; set; } + public string LastName { get; set; } + public string SubjectFirstName { get; set; } + public string SubjectLastName { get; set; } + public string Phone { get; set; } + public string Fax { get; set; } + public string Email { get; set; } + public string Title { get; set; } + public string OrganizationName { get; set; } + public string AddressLine1 { get; set; } + public string AddressLine2 { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/Template.cs b/SslStoreCaProxy/Client/Models/Template.cs new file mode 100644 index 0000000..b89e361 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/Template.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class Template : ITemplate + { + public int Id { get; set; } + public string CommonName { get; set; } + public string TemplateName { get; set; } + public string Oid { get; set; } + public string KeySize { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string KeyType { get; set; } + public string ForestRoot { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string FriendlyName { get; set; } + public string KeyRetention { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? KeyRetentionDays { get; set; } + public bool KeyArchival { get; set; } + public List EnrollmentFields { get; set; } + public int AllowedEnrollmentTypes { get; set; } + public List TemplateRegexes { get; set; } + public bool UseAllowedRequesters { get; set; } + public List AllowedRequesters { get; set; } + public string DisplayName { get; set; } + } +} diff --git a/SslStoreCaProxy/Client/Models/TemplateNewOrderRequest.cs b/SslStoreCaProxy/Client/Models/TemplateNewOrderRequest.cs new file mode 100644 index 0000000..5e03d61 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/TemplateNewOrderRequest.cs @@ -0,0 +1,270 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class TemplateNewOrderRequest : ITemplateNewOrderRequest + { + public TemplateAuthRequest AuthRequest { get; set; } + public ProductCode ProductCode { get; set; } + public TemplateOrganizationInfo OrganizationInfo { get; set; } + public ValidityPeriod ValidityPeriod { get; set; } + public ServerCount ServerCount { get; set; } + [JsonProperty("CSR")] public Csr Csr { get; set; } + public DomainName DomainName { get; set; } + public WebServerType WebServerType { get; set; } + [JsonProperty("DNSNames")] public DnsNames DnsNames { get; set; } + [JsonProperty("isCUOrder")] public IsCuOrder IsCuOrder { get; set; } + [JsonProperty("AutoWWW", NullValueHandling = NullValueHandling.Ignore)] public AutoWWW AutoWWW { get; set; } + [JsonProperty("isRenewalOrder")] public IsRenewalOrder IsRenewalOrder { get; set; } + [JsonProperty("isTrialOrder")] public IsTrialOrder IsTrialOrder { get; set; } + public TemplateAdminContact AdminContact { get; set; } + public TemplateTechnicalContact TechnicalContact { get; set; } + public ApproverEmail ApproverEmail { get; set; } + [JsonProperty("FileAuthDVIndicator")] public FileAuthDvIndicator FileAuthDvIndicator { get; set; } + [JsonProperty("CNAMEAuthDVIndicator")] public CNameAuthDvIndicator CNameAuthDvIndicator { get; set; } + public SignatureHashAlgorithm SignatureHashAlgorithm { get; set; } + } + + public class FieldData + { + public List RequiredForProducts { get; set; } + public string EnrollmentFieldMapping { get; set; } + public bool Array { get; set; } + } + + public class PartnerCode + { + public FieldData FieldData { get; set; } + } + + public class AuthToken + { + public FieldData FieldData { get; set; } + } + + [JsonObject("AuthRequest")] + public class TemplateAuthRequest + { + public PartnerCode PartnerCode { get; set; } + public AuthToken AuthToken { get; set; } + } + + public class ProductCode + { + public FieldData FieldData { get; set; } + } + + public class OrganizationName + { + public FieldData FieldData { get; set; } + } + + public class RegistrationNumber + { + public FieldData FieldData { get; set; } + } + + public class JurisdictionCountry + { + public FieldData FieldData { get; set; } + } + + public class AddressLine1 + { + public FieldData FieldData { get; set; } + } + + public class Region + { + public FieldData FieldData { get; set; } + } + + public class PostalCode + { + public FieldData FieldData { get; set; } + } + + public class LocalityName + { + public FieldData FieldData { get; set; } + } + + [JsonObject("OrganizationAddress")] + public class TemplateOrganizationAddress + { + public AddressLine1 AddressLine1 { get; set; } + public Region Region { get; set; } + public PostalCode PostalCode { get; set; } + public LocalityName LocalityName { get; set; } + public Country Country { get; set; } + public Phone Phone { get; set; } + + } + + [JsonObject("OrganizationInfo")] + public class TemplateOrganizationInfo + { + public OrganizationName OrganizationName { get; set; } + public RegistrationNumber RegistrationNumber { get; set; } + public JurisdictionCountry JurisdictionCountry { get; set; } + public TemplateOrganizationAddress OrganizationAddress { get; set; } + } + + public class ValidityPeriod + { + public FieldData FieldData { get; set; } + } + + public class ServerCount + { + public FieldData FieldData { get; set; } + } + + [JsonObject("CSR")] + public class Csr + { + public FieldData FieldData { get; set; } + } + + public class DomainName + { + public FieldData FieldData { get; set; } + } + + public class WebServerType + { + public FieldData FieldData { get; set; } + } + + [JsonObject("DNSNames")] + public class DnsNames + { + public FieldData FieldData { get; set; } + } + + [JsonObject("isCUOrder")] + public class IsCuOrder + { + public FieldData FieldData { get; set; } + } + + [JsonObject("AutoWWW",ItemNullValueHandling =NullValueHandling.Ignore)] + public class AutoWWW + { + public FieldData FieldData { get; set; } + } + + [JsonObject("isRenewalOrder")] + public class IsRenewalOrder + { + public FieldData FieldData { get; set; } + } + + [JsonObject("isTrialOrder")] + public class IsTrialOrder + { + public FieldData FieldData { get; set; } + } + + public class FirstName + { + public FieldData FieldData { get; set; } + } + + public class LastName + { + public FieldData FieldData { get; set; } + } + + public class Phone + { + public FieldData FieldData { get; set; } + } + + public class Email + { + public FieldData FieldData { get; set; } + } + + public class Title + { + public FieldData FieldData { get; set; } + } + + public class City + { + public FieldData FieldData { get; set; } + } + + public class Country + { + public FieldData FieldData { get; set; } + } + + [JsonObject("AdminContact")] + public class TemplateAdminContact + { + public FirstName FirstName { get; set; } + public LastName LastName { get; set; } + public Phone Phone { get; set; } + public Email Email { get; set; } + public Title Title { get; set; } + public OrganizationName OrganizationName { get; set; } + public AddressLine1 AddressLine1 { get; set; } + public City City { get; set; } + public Region Region { get; set; } + public PostalCode PostalCode { get; set; } + public Country Country { get; set; } + } + + public class SubjectFirstName + { + public FieldData FieldData { get; set; } + } + + public class SubjectLastName + { + public FieldData FieldData { get; set; } + } + + [JsonObject("TechnicalContact")] + public class TemplateTechnicalContact + { + public FirstName FirstName { get; set; } + public LastName LastName { get; set; } + public SubjectFirstName SubjectFirstName { get; set; } + public SubjectLastName SubjectLastName { get; set; } + public Phone Phone { get; set; } + public Email Email { get; set; } + public Title Title { get; set; } + public AddressLine1 AddressLine1 { get; set; } + public City City { get; set; } + public Region Region { get; set; } + public PostalCode PostalCode { get; set; } + public Country Country { get; set; } + } + + public class ApproverEmail + { + public FieldData FieldData { get; set; } + } + + [JsonObject("FileAuthDVIndicator")] + public class FileAuthDvIndicator + { + public FieldData FieldData { get; set; } + } + + [JsonObject("CNAMEAuthDVIndicator")] + public class CNameAuthDvIndicator + { + public FieldData FieldData { get; set; } + } + + public class SignatureHashAlgorithm + { + public FieldData FieldData { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Client/Models/TemplateRegex.cs b/SslStoreCaProxy/Client/Models/TemplateRegex.cs new file mode 100644 index 0000000..27eaab6 --- /dev/null +++ b/SslStoreCaProxy/Client/Models/TemplateRegex.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Keyfactor.AnyGateway.SslStore.Interfaces; + +namespace Keyfactor.AnyGateway.SslStore.Client.Models +{ + public class TemplateRegex : ITemplateRegex + { + public int TemplateId { get; set; } + public string SubjectPart { get; set; } + public string Regex { get; set; } + public string Error { get; set; } + } +} diff --git a/SslStoreCaProxy/Client/SslStoreClient.cs b/SslStoreCaProxy/Client/SslStoreClient.cs new file mode 100644 index 0000000..a2169fe --- /dev/null +++ b/SslStoreCaProxy/Client/SslStoreClient.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Keyfactor.AnyGateway.Extensions; +using Keyfactor.AnyGateway.SslStore.Client.Models; +using Keyfactor.AnyGateway.SslStore.Exceptions; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Keyfactor.Logging; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace Keyfactor.AnyGateway.SslStore.Client +{ + public sealed class SslStoreClient : ISslStoreClient + { + private static readonly ILogger _logger = LogHandler.GetClassLogger(); + + public SslStoreClient(IAnyCAPluginConfigProvider config) + { + if (config.CAConnectionData.ContainsKey(Constants.SslStoreUrl)) + { + BaseUrl = new Uri(config.CAConnectionData[Constants.SslStoreUrl].ToString()); + RestClient = ConfigureRestClient(); + } + } + + private Uri BaseUrl { get; } + private HttpClient RestClient { get; } + private int PageSize { get; } = 100; + + public async Task SubmitNewOrderRequestAsync(NewOrderRequest newOrderRequest) + { + using (var resp = await RestClient.PostAsync("/rest/order/neworder", new StringContent( + JsonConvert.SerializeObject(newOrderRequest), Encoding.UTF8, "application/json"))) + { + _logger.LogTrace(JsonConvert.SerializeObject(newOrderRequest)); + resp.EnsureSuccessStatusCode(); + var enrollmentResponse = + JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); + return enrollmentResponse; + } + } + + public async Task SubmitEmailApproverRequestAsync(EmailApproverRequest newApproverRequest) + { + using (var resp = await RestClient.PostAsync("/rest/order/approverlist", new StringContent( + JsonConvert.SerializeObject(newApproverRequest), Encoding.UTF8, "application/json"))) + { + _logger.LogTrace(JsonConvert.SerializeObject(newApproverRequest)); + resp.EnsureSuccessStatusCode(); + var enrollmentResponse = + JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); + return enrollmentResponse; + } + } + + public async Task SubmitReIssueRequestAsync(ReIssueRequest reIssueOrderRequest) + { + using (var resp = await RestClient.PostAsync("/rest/order/reissue", new StringContent( + JsonConvert.SerializeObject(reIssueOrderRequest), Encoding.UTF8, "application/json"))) + { + var orderStatusResponse = + JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); + return orderStatusResponse; + } + } + + public async Task SubmitRenewRequestAsync(NewOrderRequest renewOrderRequest) + { + using (var resp = await RestClient.PostAsync("/rest/order/neworder", new StringContent( + JsonConvert.SerializeObject(renewOrderRequest), Encoding.UTF8, "application/json"))) + { + _logger.LogTrace(JsonConvert.SerializeObject(renewOrderRequest)); + resp.EnsureSuccessStatusCode(); + var enrollmentResponse = + JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); + return enrollmentResponse; + } + } + + public async Task SubmitDownloadCertificateAsync( + DownloadCertificateRequest downloadOrderRequest) + { + using (var resp = await RestClient.PostAsync("/rest/order/download", new StringContent( + JsonConvert.SerializeObject(downloadOrderRequest), Encoding.UTF8, "application/json"))) + { + _logger.LogTrace(JsonConvert.SerializeObject(downloadOrderRequest)); + resp.EnsureSuccessStatusCode(); + var downloadOrderResponse = + JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); + return downloadOrderResponse; + } + } + + public async Task SubmitQueryOrderRequestAsync(BlockingCollection bc, CancellationToken ct, + RequestManager requestManager) + { + _logger.MethodEntry(); + try + { + var itemsProcessed = 0; + var pageCounter = 0; + var isComplete = false; + var retryCount = 0; + do + { + pageCounter++; + var queryOrderRequest = requestManager.GetQueryOrderRequest(PageSize, pageCounter); + var batchItemsProcessed = 0; + using (var resp = await RestClient.PostAsync("/rest/order/query", new StringContent( + JsonConvert.SerializeObject(queryOrderRequest), Encoding.UTF8, "application/json"))) + { + if (!resp.IsSuccessStatusCode) + { + var responseMessage = resp.Content.ReadAsStringAsync().Result; + _logger.LogError( + $"Failed Request to SslStore. Retrying request. Status Code {resp.StatusCode} | Message: {responseMessage}"); + retryCount++; + if (retryCount > 5) + throw new RetryCountExceededException( + $"5 consecutive failures to {resp.RequestMessage.RequestUri}"); + + continue; + } + + var batchResponse = + JsonConvert.DeserializeObject>( + await resp.Content.ReadAsStringAsync()); + + _logger.LogTrace($"Order List JSON {JsonConvert.SerializeObject(batchResponse)}"); + + var batchCount = batchResponse.Count; + + _logger.LogTrace($"Processing {batchCount} items in batch"); + do + { + var r = batchResponse[batchItemsProcessed]; + if (bc.TryAdd(r, 10, ct)) + { + _logger.LogTrace($"Added Certificate ID {r.TheSslStoreOrderId} to Queue for processing"); + batchItemsProcessed++; + itemsProcessed++; + _logger.LogTrace($"Processed {batchItemsProcessed} of {batchCount}"); + _logger.LogTrace($"Total Items Processed: {itemsProcessed}"); + } + else + { + _logger.LogTrace($"Adding {r} blocked. Retry"); + } + } while (batchItemsProcessed < batchCount); + } + + if (batchItemsProcessed < PageSize) + isComplete = true; + } while (!isComplete); + + bc.CompleteAdding(); + } + catch (OperationCanceledException cancelEx) + { + _logger.LogWarning($"Synchronize method was cancelled. Message: {cancelEx.Message}"); + bc.CompleteAdding(); + _logger.MethodExit(); + throw; + } + catch (RetryCountExceededException retryEx) + { + _logger.LogError($"Retries Failed: {retryEx.Message}"); + _logger.MethodExit(); + } + catch (HttpRequestException ex) + { + _logger.LogError($"HttpRequest Failed: {ex.Message}"); + _logger.MethodExit(); + } + + _logger.MethodExit(); + } + + public async Task SubmitRevokeCertificateAsync(RevokeOrderRequest revokeOrderRequest) + { + using (var resp = await RestClient.PostAsync("/rest/order/refundrequest", new StringContent( + JsonConvert.SerializeObject(revokeOrderRequest), Encoding.UTF8, "application/json"))) + { + var revocationResponse = + JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); + return revocationResponse; + } + } + + public async Task SubmitOrderStatusRequestAsync(OrderStatusRequest orderStatusRequest) + { + using (var resp = await RestClient.PostAsync("/rest/order/status", new StringContent( + JsonConvert.SerializeObject(orderStatusRequest), Encoding.UTF8, "application/json"))) + { + var orderStatusResponse = + JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); + return orderStatusResponse; + } + } + + public async Task SubmitOrganizationListAsync(OrganizationListRequest organizationListRequest) + { + using (var resp = await RestClient.PostAsync("/rest/digicert/organizationlist", new StringContent( + JsonConvert.SerializeObject(organizationListRequest), Encoding.UTF8, "application/json"))) + { + var organizationListResponse = + JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); + return organizationListResponse; + } + } + + private HttpClient ConfigureRestClient() + { + var clientHandler = new HttpClientHandler(); + var returnClient = new HttpClient(clientHandler, true) { BaseAddress = BaseUrl }; + returnClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + return returnClient; + } + } +} diff --git a/SslStoreCaProxy/Constants.cs b/SslStoreCaProxy/Constants.cs new file mode 100644 index 0000000..36caa82 --- /dev/null +++ b/SslStoreCaProxy/Constants.cs @@ -0,0 +1,11 @@ +namespace Keyfactor.AnyGateway.SslStore +{ + internal class Constants + { + public static string SslStoreUrl = "SSLStoreURL"; + public static string PartnerCode = "PartnerCode"; + public static string AuthToken = "AuthToken"; + public static string PageSize = "PageSize"; + public static int DefaultPageSize = 100; + } +} diff --git a/SslStoreCaProxy/Exceptions/RetryCountExceededException.cs b/SslStoreCaProxy/Exceptions/RetryCountExceededException.cs new file mode 100644 index 0000000..125c666 --- /dev/null +++ b/SslStoreCaProxy/Exceptions/RetryCountExceededException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Keyfactor.AnyGateway.SslStore.Exceptions +{ + public class RetryCountExceededException : Exception + { + public RetryCountExceededException(string message) : base(message) + { + } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IAddSan.cs b/SslStoreCaProxy/Interfaces/IAddSan.cs new file mode 100644 index 0000000..6bf7277 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IAddSan.cs @@ -0,0 +1,8 @@ +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IAddSan + { + string OldValue { get; set; } + string NewValue { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IAdminContact.cs b/SslStoreCaProxy/Interfaces/IAdminContact.cs new file mode 100644 index 0000000..deb6573 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IAdminContact.cs @@ -0,0 +1,21 @@ +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IAdminContact + { + string FirstName { get; set; } + string LastName { get; set; } + string SubjectFirstName { get; set; } + string SubjectLastName { get; set; } + string Phone { get; set; } + string Fax { get; set; } + string Email { get; set; } + string Title { get; set; } + string OrganizationName { get; set; } + string AddressLine1 { get; set; } + string AddressLine2 { get; set; } + string City { get; set; } + string Region { get; set; } + string PostalCode { get; set; } + string Country { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IAuthRequest.cs b/SslStoreCaProxy/Interfaces/IAuthRequest.cs new file mode 100644 index 0000000..17d4526 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IAuthRequest.cs @@ -0,0 +1,15 @@ +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IAuthRequest + { + string PartnerCode { get; set; } + string AuthToken { get; set; } + string ReplayToken { get; set; } + string UserAgent { get; set; } + string TokenId { get; set; } + string TokenCode { get; set; } + string IpAddress { get; set; } + bool IsUsedForTokenSystem { get; set; } + string Token { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IAuthResponse.cs b/SslStoreCaProxy/Interfaces/IAuthResponse.cs new file mode 100644 index 0000000..161a3ee --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IAuthResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IAuthResponse + { + bool IsError { get; set; } + List Message { get; set; } + string Timestamp { get; set; } + string ReplayToken { get; set; } + string InvokingPartnerCode { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IAuthenticationStatus.cs b/SslStoreCaProxy/Interfaces/IAuthenticationStatus.cs new file mode 100644 index 0000000..d4c66f9 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IAuthenticationStatus.cs @@ -0,0 +1,9 @@ +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IAuthenticationStatus + { + string AuthenticationStep { get; set; } + string Status { get; set; } + string LastUpdated { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IDomainAuthVettingStatus.cs b/SslStoreCaProxy/Interfaces/IDomainAuthVettingStatus.cs new file mode 100644 index 0000000..a6dcdfc --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IDomainAuthVettingStatus.cs @@ -0,0 +1,17 @@ +using System; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IDomainAuthVettingStatus + { + string Domain { get; set; } + string DcvMethod { get; set; } + string DcvStatus { get; set; } + string FileName { get; set; } + string FileContents { get; set; } + string DnsName { get; set; } + string DnsEntry { get; set; } + string PollStatus { get; set; } + DateTime LastPollDate { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IDownloadCertificateRequest.cs b/SslStoreCaProxy/Interfaces/IDownloadCertificateRequest.cs new file mode 100644 index 0000000..af9f698 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IDownloadCertificateRequest.cs @@ -0,0 +1,10 @@ +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IDownloadCertificateRequest + { + AuthRequest AuthRequest { get; set; } + string TheSslStoreOrderId { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IDownloadCertificateResponse.cs b/SslStoreCaProxy/Interfaces/IDownloadCertificateResponse.cs new file mode 100644 index 0000000..88e8872 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IDownloadCertificateResponse.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IDownloadCertificateResponse + { + AuthResponse AuthResponse { get; set; } + string CertificateEndDate { get; set; } + string CertificateEndDateInUtc { get; set; } + string CertificateStartDate { get; set; } + string CertificateStartDateInUtc { get; set; } + string CertificateStatus { get; set; } + List Certificates { get; set; } + string PartnerOrderId { get; set; } + object TheSslStoreOrderId { get; set; } + string ValidationStatus { get; set; } + object VendorOrderId { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IEmailApproverRequest.cs b/SslStoreCaProxy/Interfaces/IEmailApproverRequest.cs new file mode 100644 index 0000000..722f83e --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IEmailApproverRequest.cs @@ -0,0 +1,11 @@ +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IEmailApproverRequest + { + AuthRequest AuthRequest { get; set; } + string ProductCode { get; set; } + string DomainName { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IEmailApproverResponse.cs b/SslStoreCaProxy/Interfaces/IEmailApproverResponse.cs new file mode 100644 index 0000000..a0d353a --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IEmailApproverResponse.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IEmailApproverResponse + { + List ApproverEmailList { get; set; } + AuthResponse AuthResponse { get; set; } + string BaseDomainName { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IEnrollmentField.cs b/SslStoreCaProxy/Interfaces/IEnrollmentField.cs new file mode 100644 index 0000000..ff377d7 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IEnrollmentField.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IEnrollmentField + { + int Id { get; set; } + string Name { get; set; } + List Options { get; set; } + int DataType { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/INewOrderRequest.cs b/SslStoreCaProxy/Interfaces/INewOrderRequest.cs new file mode 100644 index 0000000..59e87fb --- /dev/null +++ b/SslStoreCaProxy/Interfaces/INewOrderRequest.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface INewOrderRequest + { + AuthRequest AuthRequest { get; set; } + string CustomOrderId { get; set; } + string ProductCode { get; set; } + string ExtraProductCodes { get; set; } + OrganizationInfo OrganizationInfo { get; set; } + long TssOrganizationId { get; set; } + long ValidityPeriod { get; set; } + long ServerCount { get; set; } + string Csr { get; set; } + string DomainName { get; set; } + string WebServerType { get; set; } + List DnsNames { get; set; } + bool IsCuOrder { get; set; } + bool? AutoWWW { get; set; } + bool IsRenewalOrder { get; set; } + string SpecialInstructions { get; set; } + string RelatedTheSslStoreOrderId { get; set; } + bool IsTrialOrder { get; set; } + AdminContact AdminContact { get; set; } + TechnicalContact TechnicalContact { get; set; } + string ApproverEmail { get; set; } + long ReserveSanCount { get; set; } + bool AddInstallationSupport { get; set; } + string EmailLanguageCode { get; set; } + bool? FileAuthDvIndicator { get; set; } + bool? CnameAuthDvIndicator { get; set; } + bool HttpsFileAuthDvIndicator { get; set; } + string SignatureHashAlgorithm { get; set; } + bool CertTransparencyIndicator { get; set; } + long RenewalDays { get; set; } + string DateTimeCulture { get; set; } + string CsrUniqueValue { get; set; } + bool IsPkcs10 { get; set; } + long WildcardReserveSanCount { get; set; } + string ProvisioningMethod { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/INewOrderResponse.cs b/SslStoreCaProxy/Interfaces/INewOrderResponse.cs new file mode 100644 index 0000000..ec1f3aa --- /dev/null +++ b/SslStoreCaProxy/Interfaces/INewOrderResponse.cs @@ -0,0 +1,68 @@ +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface INewOrderResponse + { + AdminContact AdminContact { get; set; } + string ApproverEmail { get; set; } + string AuthFileContent { get; set; } + string AuthFileName { get; set; } + AuthResponse AuthResponse { get; set; } + string CnameAuthName { get; set; } + string CnameAuthValue { get; set; } + string CertificateEndDate { get; set; } + string CertificateEndDateInUtc { get; set; } + string CertificateStartDate { get; set; } + string CertificateStartDateInUtc { get; set; } + string CommonName { get; set; } + string Country { get; set; } + string CustomOrderId { get; set; } + int CustomerId { get; set; } + string CustomerLoginName { get; set; } + string CustomerPassword { get; set; } + string DnsNames { get; set; } + string Duns { get; set; } + string Locality { get; set; } + string OrderAmount { get; set; } + string OrderExpiryDate { get; set; } + string OrderExpiryDateInUtc { get; set; } + OrderStatus OrderStatus { get; set; } + string Organization { get; set; } + string OrganizationAddress { get; set; } + string OrganizationPhone { get; set; } + string OrganizationPostalcode { get; set; } + string OrganizationalUnit { get; set; } + string PartnerOrderId { get; set; } + string PollDate { get; set; } + string PollDateInUtc { get; set; } + string PollStatus { get; set; } + string ProductCode { get; set; } + string ProductName { get; set; } + string PurchaseDate { get; set; } + string PurchaseDateInUtc { get; set; } + string RefundRequestId { get; set; } + string ReissueSuccessCode { get; set; } + int SanCount { get; set; } + string SerialNumber { get; set; } + int ServerCount { get; set; } + string SignatureEncryptionAlgorithm { get; set; } + string SignatureHashAlgorithm { get; set; } + string SiteSealurl { get; set; } + string State { get; set; } + string SubVendorName { get; set; } + int TssOrganizationId { get; set; } + TechnicalContact TechnicalContact { get; set; } + string TheSslStoreOrderId { get; set; } + string TinyOrderLink { get; set; } + string Token { get; set; } + string TokenCode { get; set; } + string TokenId { get; set; } + int Validity { get; set; } + string VendorName { get; set; } + string VendorOrderId { get; set; } + string WebServerType { get; set; } + bool IsRefundApproved { get; set; } + int WildcardSanCount { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IOrderNote.cs b/SslStoreCaProxy/Interfaces/IOrderNote.cs new file mode 100644 index 0000000..2d7c65b --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IOrderNote.cs @@ -0,0 +1,8 @@ +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IOrderNote + { + string Comments { get; set; } + string DateAdded { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IOrderStatus.cs b/SslStoreCaProxy/Interfaces/IOrderStatus.cs new file mode 100644 index 0000000..e4d55df --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IOrderStatus.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IOrderStatus + { + bool IsTinyOrder { get; set; } + bool IsTinyOrderClaimed { get; set; } + string MajorStatus { get; set; } + string MinorStatus { get; set; } + List AuthenticationStatuses { get; set; } + string AuthenticationComments { get; set; } + List OrderNotes { get; set; } + List DomainAuthVettingStatus { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IOrderStatusRequest.cs b/SslStoreCaProxy/Interfaces/IOrderStatusRequest.cs new file mode 100644 index 0000000..fcd8e43 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IOrderStatusRequest.cs @@ -0,0 +1,10 @@ +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IOrderStatusRequest + { + AuthRequest AuthRequest { get; set; } + string TheSslStoreOrderId { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IOrderStatusResponse.cs b/SslStoreCaProxy/Interfaces/IOrderStatusResponse.cs new file mode 100644 index 0000000..883455e --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IOrderStatusResponse.cs @@ -0,0 +1,62 @@ +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IOrderStatusResponse + { + AuthResponse AuthResponse { get; set; } + string PartnerOrderId { get; set; } + string CustomOrderId { get; set; } + string TheSslStoreOrderId { get; set; } + string VendorOrderId { get; set; } + string RefundRequestId { get; set; } + bool IsRefundApproved { get; set; } + string TinyOrderLink { get; set; } + OrderStatus OrderStatus { get; set; } + string OrderAmount { get; set; } + string PurchaseDate { get; set; } + string CertificateStartDate { get; set; } + string CertificateEndDate { get; set; } + string CommonName { get; set; } + string DnsNames { get; set; } + long SanCount { get; set; } + long ServerCount { get; set; } + long Validity { get; set; } + string Organization { get; set; } + string OrganizationalUnit { get; set; } + string State { get; set; } + string Country { get; set; } + string Locality { get; set; } + string OrganizationPhone { get; set; } + string OrganizationAddress { get; set; } + string OrganizationPostalcode { get; set; } + string Duns { get; set; } + string WebServerType { get; set; } + string ApproverEmail { get; set; } + string ProductName { get; set; } + AdminContact AdminContact { get; set; } + TechnicalContact TechnicalContact { get; set; } + string ReissueSuccessCode { get; set; } + string AuthFileName { get; set; } + string AuthFileContent { get; set; } + string PollStatus { get; set; } + string PollDate { get; set; } + string CustomerLoginName { get; set; } + string CustomerPassword { get; set; } + long CustomerId { get; set; } + string TokenId { get; set; } + string TokenCode { get; set; } + string SiteSealurl { get; set; } + string CnameAuthName { get; set; } + string CnameAuthValue { get; set; } + string SignatureEncryptionAlgorithm { get; set; } + string SignatureHashAlgorithm { get; set; } + string VendorName { get; set; } + string SubVendorName { get; set; } + string Token { get; set; } + string CertificateStartDateInUtc { get; set; } + string CertificateEndDateInUtc { get; set; } + string PurchaseDateInUtc { get; set; } + string PollDateInUtc { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IOrganization.cs b/SslStoreCaProxy/Interfaces/IOrganization.cs new file mode 100644 index 0000000..6f369d2 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IOrganization.cs @@ -0,0 +1,22 @@ +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IOrganization + { + string Address { get; set; } + string Address2 { get; set; } + object ApproversContact { get; set; } + string AssumedName { get; set; } + string City { get; set; } + string Country { get; set; } + string Name { get; set; } + OrganizationContact OrganizationContact { get; set; } + string OrganizationPhone { get; set; } + string State { get; set; } + string Zip { get; set; } + string Status { get; set; } + int TssOrganizationId { get; set; } + int VendorOrganizationId { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IOrganizationAddress.cs b/SslStoreCaProxy/Interfaces/IOrganizationAddress.cs new file mode 100644 index 0000000..e1831a9 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IOrganizationAddress.cs @@ -0,0 +1,16 @@ +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IOrganizationAddress + { + string AddressLine1 { get; set; } + string AddressLine2 { get; set; } + string AddressLine3 { get; set; } + string City { get; set; } + string Region { get; set; } + string PostalCode { get; set; } + string Country { get; set; } + string Phone { get; set; } + string Fax { get; set; } + string LocalityName { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IOrganizationContact.cs b/SslStoreCaProxy/Interfaces/IOrganizationContact.cs new file mode 100644 index 0000000..b283d21 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IOrganizationContact.cs @@ -0,0 +1,13 @@ +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IOrganizationContact + { + string Email { get; set; } + string Firstname { get; set; } + string JobTitle { get; set; } + string Lastname { get; set; } + string Phone { get; set; } + string PhoneExtension { get; set; } + string Username { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IOrganizationInfo.cs b/SslStoreCaProxy/Interfaces/IOrganizationInfo.cs new file mode 100644 index 0000000..1ffe4d3 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IOrganizationInfo.cs @@ -0,0 +1,18 @@ +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IOrganizationInfo + { + string OrganizationName { get; set; } + string Duns { get; set; } + string Division { get; set; } + string IncorporatingAgency { get; set; } + string RegistrationNumber { get; set; } + string JurisdictionCity { get; set; } + string JurisdictionRegion { get; set; } + string JurisdictionCountry { get; set; } + string AssumedName { get; set; } + OrganizationAddress OrganizationAddress { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IOrganizationListRequest.cs b/SslStoreCaProxy/Interfaces/IOrganizationListRequest.cs new file mode 100644 index 0000000..1e98104 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IOrganizationListRequest.cs @@ -0,0 +1,8 @@ +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IOrganizationListRequest + { + string PartnerCode { get; set; } + string AuthToken { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IOrganizationResponse.cs b/SslStoreCaProxy/Interfaces/IOrganizationResponse.cs new file mode 100644 index 0000000..489a96a --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IOrganizationResponse.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IOrganizationResponse + { + AuthResponse AuthResponse { get; set; } + List OrganizationList { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IQueryOrderRequest.cs b/SslStoreCaProxy/Interfaces/IQueryOrderRequest.cs new file mode 100644 index 0000000..5042278 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IQueryOrderRequest.cs @@ -0,0 +1,20 @@ +using System; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IQueryOrderRequest + { + AuthRequest AuthRequest { get; set; } + DateTime? StartDate { get; set; } + DateTime? EndDate { get; set; } + DateTime? CertificateExpireToDate { get; set; } + DateTime? CertificateExpireFromDate { get; set; } + string DomainName { get; set; } + string SubUserId { get; set; } + string ProductCode { get; set; } + string DateTimeCulture { get; set; } + long PageNumber { get; set; } + long PageSize { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IReIssueRequest.cs b/SslStoreCaProxy/Interfaces/IReIssueRequest.cs new file mode 100644 index 0000000..72fde8b --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IReIssueRequest.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IReIssueRequest + { + AuthRequest AuthRequest { get; set; } + string TheSslStoreOrderId { get; set; } + string Csr { get; set; } + string WebServerType { get; set; } + List DnsNames { get; set; } + bool IsRenewalOrder { get; set; } + string SpecialInstructions { get; set; } + List EditSan { get; set; } + List DeleteSan { get; set; } + List AddSan { get; set; } + bool IsWildCard { get; set; } + string ReissueEmail { get; set; } + bool PreferEnrollmentLink { get; set; } + string SignatureHashAlgorithm { get; set; } + bool FileAuthDvIndicator { get; set; } + bool HttpsFileAuthDvIndicator { get; set; } + bool CNameAuthDvIndicator { get; set; } + string ApproverEmails { get; set; } + string DateTimeCulture { get; set; } + string CsrUniqueValue { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IRequestManager.cs b/SslStoreCaProxy/Interfaces/IRequestManager.cs new file mode 100644 index 0000000..5ca1fb4 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IRequestManager.cs @@ -0,0 +1,22 @@ +using Keyfactor.AnyGateway.Extensions; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IRequestManager + { + NewOrderRequest GetEnrollmentRequest(string csr, EnrollmentProductInfo productInfo, + IAnyCAPluginConfigProvider configProvider, bool isRenewalOrder); + + AuthRequest GetAuthRequest(); + ReIssueRequest GetReIssueRequest(INewOrderResponse orderData, string csr, bool isRenewal); + AdminContact GetAdminContact(EnrollmentProductInfo productInfo); + TechnicalContact GetTechnicalContact(EnrollmentProductInfo productInfo); + DownloadCertificateRequest GetCertificateRequest(string theSslStoreOrderId); + RevokeOrderRequest GetRevokeOrderRequest(string theSslStoreOrderId); + int GetClientPageSize(IAnyCAPluginConfigProvider config); + QueryOrderRequest GetQueryOrderRequest(int pageSize, int pageNumber); + OrderStatusRequest GetOrderStatusRequest(string theSslStoreId); + int MapReturnStatus(string sslStoreStatus); + } +} diff --git a/SslStoreCaProxy/Interfaces/IRevokeOrderRequest.cs b/SslStoreCaProxy/Interfaces/IRevokeOrderRequest.cs new file mode 100644 index 0000000..58ed409 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IRevokeOrderRequest.cs @@ -0,0 +1,11 @@ +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IRevokeOrderRequest + { + AuthRequest AuthRequest { get; set; } + string TheSslStoreOrderId { get; set; } + string SerialNumber { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/IRevokeOrderResponse.cs b/SslStoreCaProxy/Interfaces/IRevokeOrderResponse.cs new file mode 100644 index 0000000..3a9b422 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/IRevokeOrderResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface IRevokeOrderResponse + { + string InvokingPartnerCode { get; set; } + List Message { get; set; } + object ReplayToken { get; set; } + string Timestamp { get; set; } + bool IsError { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/ISslStoreClient.cs b/SslStoreCaProxy/Interfaces/ISslStoreClient.cs new file mode 100644 index 0000000..fd5cf0a --- /dev/null +++ b/SslStoreCaProxy/Interfaces/ISslStoreClient.cs @@ -0,0 +1,30 @@ +using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface ISslStoreClient + { + Task SubmitNewOrderRequestAsync(NewOrderRequest newOrderRequest); + + Task SubmitReIssueRequestAsync(ReIssueRequest reIssueOrderRequest); + + Task SubmitRenewRequestAsync(NewOrderRequest renewOrderRequest); + + Task SubmitDownloadCertificateAsync( + DownloadCertificateRequest downloadOrderRequest); + + Task SubmitQueryOrderRequestAsync(BlockingCollection bc, CancellationToken ct, + RequestManager requestManager); + + Task SubmitRevokeCertificateAsync(RevokeOrderRequest revokeOrderRequest); + + Task SubmitOrganizationListAsync(OrganizationListRequest organizationListRequest); + + Task SubmitOrderStatusRequestAsync(OrderStatusRequest orderStatusRequest); + + Task SubmitEmailApproverRequestAsync(EmailApproverRequest newApproverRequest); + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/ITechnicalContact.cs b/SslStoreCaProxy/Interfaces/ITechnicalContact.cs new file mode 100644 index 0000000..0c8a4f5 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/ITechnicalContact.cs @@ -0,0 +1,21 @@ +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface ITechnicalContact + { + string FirstName { get; set; } + string LastName { get; set; } + string SubjectFirstName { get; set; } + string SubjectLastName { get; set; } + string Phone { get; set; } + string Fax { get; set; } + string Email { get; set; } + string Title { get; set; } + string OrganizationName { get; set; } + string AddressLine1 { get; set; } + string AddressLine2 { get; set; } + string City { get; set; } + string Region { get; set; } + string PostalCode { get; set; } + string Country { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/ITemplate.cs b/SslStoreCaProxy/Interfaces/ITemplate.cs new file mode 100644 index 0000000..1fbbeb5 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/ITemplate.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface ITemplate + { + int Id { get; set; } + string CommonName { get; set; } + string TemplateName { get; set; } + string Oid { get; set; } + string KeySize { get; set; } + string KeyType { get; set; } + string ForestRoot { get; set; } + string FriendlyName { get; set; } + string KeyRetention { get; set; } + int? KeyRetentionDays { get; set; } + bool KeyArchival { get; set; } + List EnrollmentFields { get; set; } + int AllowedEnrollmentTypes { get; set; } + List TemplateRegexes { get; set; } + bool UseAllowedRequesters { get; set; } + List AllowedRequesters { get; set; } + string DisplayName { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/ITemplateNewOrderRequest.cs b/SslStoreCaProxy/Interfaces/ITemplateNewOrderRequest.cs new file mode 100644 index 0000000..bc46601 --- /dev/null +++ b/SslStoreCaProxy/Interfaces/ITemplateNewOrderRequest.cs @@ -0,0 +1,27 @@ +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface ITemplateNewOrderRequest + { + TemplateAuthRequest AuthRequest { get; set; } + ProductCode ProductCode { get; set; } + TemplateOrganizationInfo OrganizationInfo { get; set; } + ValidityPeriod ValidityPeriod { get; set; } + ServerCount ServerCount { get; set; } + Csr Csr { get; set; } + DomainName DomainName { get; set; } + WebServerType WebServerType { get; set; } + DnsNames DnsNames { get; set; } + AutoWWW AutoWWW { get; set; } + IsCuOrder IsCuOrder { get; set; } + IsRenewalOrder IsRenewalOrder { get; set; } + IsTrialOrder IsTrialOrder { get; set; } + TemplateAdminContact AdminContact { get; set; } + TemplateTechnicalContact TechnicalContact { get; set; } + ApproverEmail ApproverEmail { get; set; } + FileAuthDvIndicator FileAuthDvIndicator { get; set; } + CNameAuthDvIndicator CNameAuthDvIndicator { get; set; } + SignatureHashAlgorithm SignatureHashAlgorithm { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/Interfaces/ITemplateRegex.cs b/SslStoreCaProxy/Interfaces/ITemplateRegex.cs new file mode 100644 index 0000000..66f2dbe --- /dev/null +++ b/SslStoreCaProxy/Interfaces/ITemplateRegex.cs @@ -0,0 +1,10 @@ +namespace Keyfactor.AnyGateway.SslStore.Interfaces +{ + public interface ITemplateRegex + { + int TemplateId { get; set; } + string SubjectPart { get; set; } + string Regex { get; set; } + string Error { get; set; } + } +} \ No newline at end of file diff --git a/SslStoreCaProxy/ProductDefinitions.cs b/SslStoreCaProxy/ProductDefinitions.cs new file mode 100644 index 0000000..f4152b5 --- /dev/null +++ b/SslStoreCaProxy/ProductDefinitions.cs @@ -0,0 +1,476 @@ +using System.Collections.Generic; +using System.Linq; +using Keyfactor.AnyGateway.SslStore.Client.Models; + +namespace Keyfactor.AnyGateway.SslStore +{ + /// + /// Static registry of all SSL Store products and their enrollment fields. + /// Template-level properties (Id, OID, KeySize, etc.) are configured in Keyfactor Command. + /// + public static class ProductDefinitions + { + private static int _nextFieldId = 1; + + #region Shared Option Lists + + private static readonly List ValidityStandard = new List { "12", "24", "36", "48", "60" }; + private static readonly List ValidityExtended = new List { "6", "12", "24", "36", "48", "60" }; + private static readonly List ValidityDigicert = new List { "12", "24", "36", "48", "60", "72" }; + + private static readonly List BoolOptions = new List { "False", "True" }; + + private static readonly List CountryCodes = new List + { + "US","AF","AX","AL","DZ","AS","AD","AO","AI","AQ","AG","AR","AM","AW","AU","AT","AZ", + "BS","BH","BD","BB","BY","BE","BZ","BJ","BM","BT","BO","BQ","BA","BW","BV","BR","IO", + "BN","BG","BF","BI","CV","KH","CM","CA","KY","CF","TD","CL","CN","CX","CC","CO","KM", + "CG","CD","CK","CR","CI","HR","CU","CW","CY","CZ","DK","DJ","DM","DO","EC","EG","SV", + "GQ","ER","EE","SZ","ET","FK","FO","FJ","FI","FR","GF","PF","TF","GA","GM","GE","DE", + "GH","GI","GR","GL","GD","GP","GU","GT","GG","GN","GW","GY","HT","HM","VA","HN","HK", + "HU","IS","IN","ID","IR","IQ","IE","IM","IL","IT","JM","JP","JE","JO","KZ","KE","KI", + "KP","KR","KW","KG","LA","LV","LB","LS","LR","LY","LI","LT","LU","MO","MG","MW","MY", + "MV","ML","MT","MH","MQ","MR","MU","YT","MX","FM","MD","MC","MN","ME","MS","MA","MZ", + "MM","NA","NR","NP","NL","NC","NZ","NI","NE","NG","NU","NF","MK","MP","NO","OM","PK", + "PW","PS","PA","PG","PY","PE","PH","PN","PL","PT","PR","QA","RE","RO","RU","RW","BL", + "SH","KN","LC","MF","PM","VC","WS","SM","ST","SA","SN","RS","SC","SL","SG","SX","SK", + "SI","SB","SO","ZA","GS","SS","ES","LK","SD","SR","SJ","SE","CH","SY","TW","TJ","TZ", + "TH","TL","TG","TK","TO","TT","TN","TR","TM","TC","TV","UG","UA","AE","GB","UM","UY", + "UZ","VU","VE","VN","VG","VI","WF","EH","YE","ZM","ZW" + }; + + private static readonly List SignatureHashAlgorithms = new List + { + "PREFER_SHA2", "REQUIRE_SHA2", "PREFER_SHA1", "" + }; + + private static readonly List WebServerTypes = new List + { + "aol","apachessl","apacheraven","apachessleay","iis","iis4","iis5","c2net","Ibmhttp", + "Ibminternet","Iplanet","Dominogo4625","Dominogo4626","Domino","Netscape", + "NetscapeFastTrack","zeusv3","Other","apacheopenssl","apache2","apacheapachessl", + "cobaltseries","covalentserver","cpanel","ensim","hsphere","ipswitch","plesk","tomcat", + "WebLogic","website","webstar","sapwebserver","webten","redhat","reven","r3ssl","quid", + "oracle","javawebserver","cisco3000","citrix" + }; + + #endregion + + #region Enrollment Field Builders + + private static EnrollmentField TextField(string name) + { + return new EnrollmentField { Id = _nextFieldId++, Name = name, Options = new List { "" }, DataType = 1 }; + } + + private static EnrollmentField DropdownField(string name, List options) + { + return new EnrollmentField { Id = _nextFieldId++, Name = name, Options = new List(options), DataType = 2 }; + } + + // Group 1: Legacy Full (36 fields) - comodossl, comodoevssl, etc. + private static List LegacyFullFields(List validity) + { + return new List + { + DropdownField("Is CU Order?", BoolOptions), + DropdownField("Is Renewal Order?", BoolOptions), + DropdownField("Is Trial Order?", BoolOptions), + TextField("Admin Contact - First Name"), + TextField("Admin Contact - Last Name"), + TextField("Admin Contact - Phone"), + TextField("Admin Contact - Email"), + TextField("Admin Contact - Organization Name"), + TextField("Admin Contact - Address"), + TextField("Admin Contact - City"), + TextField("Admin Contact - Region"), + TextField("Admin Contact - Postal Code"), + DropdownField("Admin Contact - Country", CountryCodes), + TextField("Technical Contact - First Name"), + TextField("Technical Contact - Last Name"), + TextField("Technical Contact - Phone"), + TextField("Technical Contact - Email"), + TextField("Technical Contact - Organization Name"), + TextField("Technical Contact - Address"), + TextField("Technical Contact - City"), + TextField("Technical Contact - Region"), + TextField("Technical Contact - Postal Code"), + DropdownField("Technical Contact - Country", CountryCodes), + TextField("Approver Email"), + DropdownField("File Auth Domain Validation", BoolOptions), + DropdownField("CName Auth Domain Validation", BoolOptions), + DropdownField("Signature Hash Algorithm", SignatureHashAlgorithms), + DropdownField("Web Server Type", WebServerTypes), + TextField("Server Count"), + DropdownField("Validity Period (In Months)", validity), + TextField("Organization Name"), + TextField("Organization Address"), + TextField("Organization Region"), + TextField("Organization Postal Code"), + TextField("Organization Country"), + TextField("Organization Phone") + }; + } + + // Group 1b: Legacy Full + DNS Names + Jurisdiction (38 fields) - digi_quickssl_md + private static List LegacyFullDnsJurisdictionFields(List validity) + { + var fields = new List { TextField("DNS Names Comma Separated") }; + fields.AddRange(LegacyFullFields(validity)); + // Insert Jurisdiction Country before Organization Phone (at the end) + fields.Insert(fields.Count - 1, DropdownField("Organization Jurisdiction Country", CountryCodes)); + return fields; + } + + // Group 2: EO Minimal (3 fields) - digi_*-EO products, digi_securesite_pro_flex + private static List EoMinimalFields() + { + return new List + { + TextField("DNS Names Comma Separated"), + DropdownField("Validity Period (In Months)", ValidityDigicert), + DropdownField("Organization ID", new List()) + }; + } + + // Group 3: Sectigo/Comodo OV (9 fields) - instantssl, comodopremiumssl, etc. + private static List SectigoOvFields() + { + return new List + { + TextField("Admin Contact - Email"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Organization Name"), + TextField("Organization Address"), + TextField("Organization State/Province"), + TextField("Organization Postal Code"), + DropdownField("Organization Country", CountryCodes), + TextField("Organization Phone") + }; + } + + // Group 4: DigiCert OV Flex (14 fields) - digi_securesite_flex, digi_sslwebserver_flex, etc. + private static List DigiCertOvFlexFields() + { + return new List + { + TextField("DNS Names Comma Separated"), + TextField("Admin Contact - First Name"), + TextField("Admin Contact - Last Name"), + TextField("Admin Contact - Phone"), + TextField("Admin Contact - Email"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityDigicert), + TextField("Organization Name"), + TextField("Organization Address"), + TextField("Organization City"), + TextField("Organization State/Province"), + TextField("Organization Postal Code"), + DropdownField("Organization Country", CountryCodes), + TextField("Organization Phone") + }; + } + + // Group 5: DV Minimal (3 fields) - positivessl, sectigossl, etc. + private static List DvMinimalFields() + { + return new List + { + TextField("Admin Contact - Email"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityStandard) + }; + } + + // Group 6: DigiCert EV Flex (15 fields) - digi_securesite_ev_flex, digi_ssl_ev_basic, etc. + private static List DigiCertEvFlexFields(string regionFieldName = "Organization State/Province") + { + return new List + { + TextField("DNS Names Comma Separated"), + TextField("Admin Contact - First Name"), + TextField("Admin Contact - Last Name"), + TextField("Admin Contact - Phone"), + TextField("Admin Contact - Email"), + TextField("Admin Contact - Title"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityDigicert), + TextField("Organization Name"), + TextField("Organization Address"), + TextField("Organization City"), + TextField(regionFieldName), + TextField("Organization Postal Code"), + DropdownField("Organization Country", CountryCodes), + TextField("Organization Phone") + }; + } + + // Group 7: DV MDC (4 fields) - positivemdcssl, sectigodvucc, etc. + private static List DvMdcFields() + { + return new List + { + TextField("DNS Names Comma Separated"), + TextField("Admin Contact - Email"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityStandard) + }; + } + + // Group 8: DigiCert DV RapidSSL (3 fields) - digi_rapidssl, digi_rapidssl_wc + private static List DigiCertDvRapidSslFields() + { + return new List + { + TextField("Technical Contact - Email"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityDigicert) + }; + } + + // Group 9: DigiCert DV GeoTrust/SSL123 (4 fields) - digi_ssl_dv_geotrust_flex, digi_ssl123_flex + private static List DigiCertDvGeoTrustFields() + { + return new List + { + TextField("DNS Names Comma Separated"), + TextField("Technical Contact - Email"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityDigicert) + }; + } + + // Group 10: EV with Jurisdiction (10 fields) - enterpriseproev, positiveevssl + private static List EvJurisdictionFields() + { + return new List + { + TextField("Admin Contact - Email"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Organization Name"), + TextField("Organization Address"), + TextField("Organization State/Province"), + TextField("Organization Postal Code"), + DropdownField("Organization Country", CountryCodes), + DropdownField("Organization Jurisdiction Country", CountryCodes), + TextField("Organization Phone") + }; + } + + // Group 11: EV MDC with Jurisdiction (11 fields) - positiveevmdc, sectigoevmdc + private static List EvMdcJurisdictionFields() + { + return new List + { + TextField("DNS Names Comma Separated"), + TextField("Admin Contact - Email"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Organization Name"), + TextField("Organization Address"), + TextField("Organization State/Province"), + TextField("Organization Postal Code"), + DropdownField("Organization Country", CountryCodes), + DropdownField("Organization Jurisdiction Country", CountryCodes), + TextField("Organization Phone") + }; + } + + // Group 11b: EV MDC with Jurisdiction (Country before Jurisdiction) - enterpriseproevmdc + private static List EvMdcJurisdictionAltFields() + { + return new List + { + TextField("DNS Names Comma Separated"), + TextField("Admin Contact - Email"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Organization Name"), + TextField("Organization Address"), + TextField("Organization State/Province"), + TextField("Organization Postal Code"), + DropdownField("Organization Jurisdiction Country", CountryCodes), + DropdownField("Organization Country", CountryCodes), + TextField("Organization Phone") + }; + } + + // Group 12: OV MDC (10 fields) - sectigomdc, sectigomdcwildcard + private static List OvMdcFields() + { + return new List + { + TextField("DNS Names Comma Separated"), + TextField("Admin Contact - Email"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Organization Name"), + TextField("Organization Address"), + TextField("Organization State/Province"), + TextField("Organization Postal Code"), + DropdownField("Organization Country", CountryCodes), + TextField("Organization Phone") + }; + } + + // Group 15: Enterprise Pro OV (9 fields) - enterprisepro (Admin First Name instead of Email) + private static List EnterpriseProOvFields() + { + return new List + { + TextField("Admin Contact - First Name"), + TextField("Approver Email"), + DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Organization Name"), + TextField("Organization Address"), + TextField("Organization State/Province"), + TextField("Organization Postal Code"), + DropdownField("Organization Country", CountryCodes), + TextField("Organization Phone") + }; + } + + #endregion + + #region Product Registry + + private static readonly Dictionary> _products = BuildRegistry(); + + private static Dictionary> BuildRegistry() + { + var registry = new Dictionary>(); + + // --- Group 1: Legacy Full (validity: 6,12,24,36,48,60) --- + foreach (var code in new[] + { + "comododvucc", "comodoevcsc", "comodoevmdc", "comodoevssl", "comodomdc", + "comodomdcwildcard", "comodopciscan", "comodossl", "comodoucc", + "comodouccwildcard", "comodowildcard", "digi_client_premium", "digi_csc", + "digi_csc_ev", "digi_doc_signing_ind_2000", "digi_doc_signing_ind_500", + "digi_doc_signing_org_2000", "digi_doc_signing_org_5000", + "elitessl", "enterprisessl", "essentialssl", "essentialwildcard", + "hackerprooftm", "hgpcicontrolscan", "pacbasic", "pacpro", "pacenterprise" + }) + { + registry[code] = LegacyFullFields(ValidityExtended); + } + + // comodocsc: Legacy Full but with standard validity (12,24,36,48,60) + registry["comodocsc"] = LegacyFullFields(ValidityStandard); + + // --- Group 1b: Legacy Full + DNS + Jurisdiction --- + registry["digi_quickssl_md"] = LegacyFullDnsJurisdictionFields(ValidityExtended); + + // --- Group 2: EO Minimal --- + foreach (var code in new[] + { + "digi_securesite_ev_flex-EO", "digi_securesite_flex-EO", + "digi_securesite_pro_ev_flex-EO", "digi_securesite_pro_flex", + "digi_securesite_pro_flex-EO", "digi_ssl_basic-EO", "digi_ssl_ev_basic-EO", + "digi_sslwebserver_ev_flex-EO", "digi_sslwebserver_flex-EO", + "digi_truebizid_ev_flex-EO", "digi_truebizid_flex-EO" + }) + { + registry[code] = EoMinimalFields(); + } + + // --- Group 3: Sectigo/Comodo OV --- + foreach (var code in new[] + { + "comodopremiumssl", "comodopremiumwildcard", "enterpriseprowc", + "instantssl", "instantsslpro", "sectigoovssl", "sectigoovwildcard" + }) + { + registry[code] = SectigoOvFields(); + } + + // --- Group 4: DigiCert OV Flex --- + foreach (var code in new[] + { + "digi_securesite_flex", "digi_ssl_basic", + "digi_sslwebserver_flex", "digi_truebizid_flex" + }) + { + registry[code] = DigiCertOvFlexFields(); + } + + // --- Group 5: DV Minimal --- + foreach (var code in new[] + { + "positivessl", "positivesslwildcard", "sectigoevssl", + "sectigossl", "sectigowildcard" + }) + { + registry[code] = DvMinimalFields(); + } + + // --- Group 6: DigiCert EV Flex (State/Province) --- + foreach (var code in new[] + { + "digi_securesite_ev_flex", "digi_ssl_ev_basic", + "digi_sslwebserver_ev_flex", "digi_truebizid_ev_flex" + }) + { + registry[code] = DigiCertEvFlexFields(); + } + + // Group 6b: DigiCert EV Flex with "Organization Region" instead of "State/Province" + registry["digi_securesite_pro_ev_flex"] = DigiCertEvFlexFields("Organization Region"); + + // --- Group 7: DV MDC --- + foreach (var code in new[] + { + "positivemdcssl", "positivemdcwildcard", "sectigodvucc", "sectigouccwildcard" + }) + { + registry[code] = DvMdcFields(); + } + + // --- Group 8: DigiCert DV RapidSSL --- + registry["digi_rapidssl"] = DigiCertDvRapidSslFields(); + registry["digi_rapidssl_wc"] = DigiCertDvRapidSslFields(); + + // --- Group 9: DigiCert DV GeoTrust/SSL123 --- + registry["digi_ssl_dv_geotrust_flex"] = DigiCertDvGeoTrustFields(); + registry["digi_ssl123_flex"] = DigiCertDvGeoTrustFields(); + + // --- Group 10: EV with Jurisdiction --- + registry["enterpriseproev"] = EvJurisdictionFields(); + registry["positiveevssl"] = EvJurisdictionFields(); + + // --- Group 11: EV MDC with Jurisdiction --- + registry["positiveevmdc"] = EvMdcJurisdictionFields(); + registry["sectigoevmdc"] = EvMdcJurisdictionFields(); + + // --- Group 11b: EV MDC Jurisdiction (alt field order) --- + registry["enterpriseproevmdc"] = EvMdcJurisdictionAltFields(); + + // --- Group 12: OV MDC --- + registry["sectigomdc"] = OvMdcFields(); + registry["sectigomdcwildcard"] = OvMdcFields(); + + // --- Group 15: Enterprise Pro OV --- + registry["enterprisepro"] = EnterpriseProOvFields(); + + return registry; + } + + #endregion + + #region Public API + + public static List GetProductIds() + { + return _products.Keys.ToList(); + } + + public static List GetEnrollmentFields(string productCode) + { + return _products.TryGetValue(productCode, out var fields) ? fields : null; + } + + #endregion + } +} diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs new file mode 100644 index 0000000..b81b013 --- /dev/null +++ b/SslStoreCaProxy/RequestManager.cs @@ -0,0 +1,412 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Text.RegularExpressions; +using Keyfactor.AnyGateway.Extensions; +using Keyfactor.AnyGateway.SslStore.Client.Models; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Keyfactor.Logging; +using Keyfactor.PKI.Enums.EJBCA; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Keyfactor.AnyGateway.SslStore +{ + public class RequestManager : IRequestManager + { + private static readonly ILogger _logger = LogHandler.GetClassLogger(); + private readonly SslStoreCaProxy _sslStoreCaProxy; + + public RequestManager(SslStoreCaProxy sslStoreCaProxy) + { + _sslStoreCaProxy = sslStoreCaProxy; + } + + public NewOrderRequest GetEnrollmentRequest(string csr, EnrollmentProductInfo productInfo, + IAnyCAPluginConfigProvider configProvider, bool isRenewalOrder) + { + var pemCsr = ConvertCsrToPem(csr); + + var sampleRequest = JsonConvert.SerializeObject(configProvider.CAConnectionData["SampleRequest"]); + + var settings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + MissingMemberHandling = MissingMemberHandling.Ignore + }; + var request = BuildNewOrderRequest(productInfo, + JsonConvert.DeserializeObject(sampleRequest, settings), pemCsr, isRenewalOrder); + + return request; + } + + private string ConvertCsrToPem(string csr) + { + try + { + var csrBytes = Convert.FromBase64String(csr); + var base64 = Convert.ToBase64String(csrBytes); + var sb = new StringBuilder(); + sb.AppendLine("-----BEGIN CERTIFICATE REQUEST-----"); + for (int i = 0; i < base64.Length; i += 64) + { + sb.AppendLine(base64.Substring(i, Math.Min(64, base64.Length - i))); + } + sb.AppendLine("-----END CERTIFICATE REQUEST-----"); + return sb.ToString(); + } + catch + { + return csr; + } + } + + public EmailApproverRequest GetEmailApproverListRequest(string productId, string productName) + { + return new EmailApproverRequest() + { + AuthRequest = GetAuthRequest(), + ProductCode = productId, + DomainName = productName + }; + } + + public OrganizationListRequest GetOrganizationListRequest() + { + return new OrganizationListRequest() + { + PartnerCode = _sslStoreCaProxy.PartnerCode, + AuthToken = _sslStoreCaProxy.AuthenticationToken + }; + } + + public AuthRequest GetAuthRequest() + { + return new AuthRequest + { + PartnerCode = _sslStoreCaProxy.PartnerCode, + AuthToken = _sslStoreCaProxy.AuthenticationToken + }; + } + + public ReIssueRequest GetReIssueRequest(INewOrderResponse orderData, string csr, bool isRenewal) + { + return new ReIssueRequest + { + AuthRequest = GetAuthRequest(), + TheSslStoreOrderId = orderData.TheSslStoreOrderId, + Csr = csr, + IsRenewalOrder = isRenewal, + IsWildCard = orderData.ProductCode.Contains("wc") || orderData.ProductCode.Contains("wildcard"), + ReissueEmail = orderData.AdminContact.Email, + ApproverEmails = orderData.ApproverEmail, + PreferEnrollmentLink = false, + FileAuthDvIndicator = orderData.OrderStatus.DomainAuthVettingStatus == null ? false : orderData.OrderStatus.DomainAuthVettingStatus.Exists(x => x.FileName != null), + CNameAuthDvIndicator = orderData.OrderStatus.DomainAuthVettingStatus == null ? false : orderData.OrderStatus.DomainAuthVettingStatus.Exists(x => x.DnsName != null), + WebServerType = orderData.WebServerType + }; + } + + public AdminContact GetAdminContact(EnrollmentProductInfo productInfo) + { + return new AdminContact + { + FirstName = productInfo.ProductParameters["Admin Contact - First Name"], + LastName = productInfo.ProductParameters["Admin Contact - Last Name"], + Phone = productInfo.ProductParameters["Admin Contact - Phone"], + Email = productInfo.ProductParameters["Admin Contact - Email"], + OrganizationName = productInfo.ProductParameters["Admin Contact - Organization Name"], + AddressLine1 = productInfo.ProductParameters["Admin Contact - Address"], + City = productInfo.ProductParameters["Admin Contact - City"], + Region = productInfo.ProductParameters["Admin Contact - Region"], + PostalCode = productInfo.ProductParameters["Admin Contact - Postal Code"], + Country = productInfo.ProductParameters["Admin Contact - Country"] + }; + } + + public TechnicalContact GetTechnicalContact(EnrollmentProductInfo productInfo) + { + return new TechnicalContact + { + FirstName = productInfo.ProductParameters["Technical Contact - First Name"], + LastName = productInfo.ProductParameters["Technical Contact - Last Name"], + Phone = productInfo.ProductParameters["Technical Contact - Phone"], + Email = productInfo.ProductParameters["Technical Contact - Email"], + OrganizationName = productInfo.ProductParameters["Technical Contact - Organization Name"], + AddressLine1 = productInfo.ProductParameters["Technical Contact - Address"], + City = productInfo.ProductParameters["Technical Contact - City"], + Region = productInfo.ProductParameters["Technical Contact - Region"], + PostalCode = productInfo.ProductParameters["Technical Contact - Postal Code"], + Country = productInfo.ProductParameters["Technical Contact - Country"] + }; + } + + public DownloadCertificateRequest GetCertificateRequest(string theSslStoreOrderId) + { + return new DownloadCertificateRequest + { + AuthRequest = GetAuthRequest(), + TheSslStoreOrderId = theSslStoreOrderId + }; + } + + public RevokeOrderRequest GetRevokeOrderRequest(string theSslStoreOrderId) + { + return new RevokeOrderRequest + { + AuthRequest = GetAuthRequest(), + TheSslStoreOrderId = theSslStoreOrderId + }; + } + + public int GetClientPageSize(IAnyCAPluginConfigProvider config) + { + if (config.CAConnectionData.ContainsKey(Constants.PageSize)) + return int.Parse(config.CAConnectionData[Constants.PageSize].ToString()); + return Constants.DefaultPageSize; + } + + public QueryOrderRequest GetQueryOrderRequest(int pageSize, int pageNumber) + { + return new QueryOrderRequest + { + AuthRequest = GetAuthRequest(), + PageSize = pageSize, + PageNumber = pageNumber + }; + } + + public OrderStatusRequest GetOrderStatusRequest(string theSslStoreId) + { + return new OrderStatusRequest + { + AuthRequest = GetAuthRequest(), + TheSslStoreOrderId = theSslStoreId + }; + } + + public int MapReturnStatus(string sslStoreStatus) + { + switch (sslStoreStatus) + { + case "Active": + return (int)EndEntityStatus.GENERATED; + case "Initial": + case "Pending": + return (int)EndEntityStatus.INPROCESS; + case "Cancelled": + return (int)EndEntityStatus.REVOKED; + default: + return (int)EndEntityStatus.FAILED; + } + } + + public NewOrderRequest GetRenewalRequest(INewOrderResponse orderData, string csr) + { + return new NewOrderRequest + { + AuthRequest = GetAuthRequest(), + RelatedTheSslStoreOrderId = orderData.TheSslStoreOrderId, + ProductCode = orderData.ProductCode, + AdminContact = GetAdminContact(orderData), + TechnicalContact = GetTechnicalContact(orderData), + ApproverEmail = orderData.ApproverEmail, + SignatureHashAlgorithm = orderData.SignatureHashAlgorithm, + WebServerType = orderData.WebServerType, + ValidityPeriod = orderData.Validity, + ServerCount = orderData.ServerCount, + IsRenewalOrder = true, + FileAuthDvIndicator = orderData.OrderStatus?.DomainAuthVettingStatus?.Exists(x => x.FileName != null), + CnameAuthDvIndicator = orderData.OrderStatus?.DomainAuthVettingStatus?.Exists(x => x.DnsName != null), + Csr = csr + }; + } + + public AdminContact GetAdminContact(INewOrderResponse productInfo) + { + return new AdminContact + { + FirstName = productInfo.AdminContact.FirstName, + LastName = productInfo.AdminContact.LastName, + Phone = productInfo.AdminContact.Phone, + Email = productInfo.AdminContact.Email + }; + } + + public TechnicalContact GetTechnicalContact(INewOrderResponse productInfo) + { + return new TechnicalContact + { + FirstName = productInfo.AdminContact.FirstName, + LastName = productInfo.AdminContact.LastName, + Phone = productInfo.AdminContact.Phone, + Email = productInfo.AdminContact.Email + }; + } + + private NewOrderRequest BuildNewOrderRequest(EnrollmentProductInfo productInfo, + TemplateNewOrderRequest newOrderRequest, string csr, bool isRenewal) + { + var customOrderId = Guid.NewGuid().ToString(); + productInfo.ProductParameters.Add("CustomOrderId", customOrderId); + + var request = + new JObject( + new JObject( + new JProperty("AuthRequest", + new JObject(new JProperty("PartnerCode", _sslStoreCaProxy.PartnerCode), + new JProperty("AuthToken", _sslStoreCaProxy.AuthenticationToken))), + new JProperty("ProductCode", productInfo.ProductID.Replace("-EO", "")), + new JProperty("CustomOrderId", customOrderId), + new JProperty("TSSOrganizationId", productInfo.ProductParameters.ContainsKey("Organization ID") ? ExtractOrgId(productInfo.ProductParameters["Organization ID"]) : null), + new JProperty("OrganizationInfo", + new JObject( + CreatePropertyFromTemplate("$.OrganizationInfo.OrganizationName", productInfo, + newOrderRequest), + CreatePropertyFromTemplate("$.OrganizationInfo.RegistrationNumber", productInfo, + newOrderRequest), + CreatePropertyFromTemplate("$.OrganizationInfo.JurisdictionCountry", productInfo, + newOrderRequest), + new JProperty("OrganizationAddress", + new JObject( + CreatePropertyFromTemplate( + "$.OrganizationInfo.OrganizationAddress.AddressLine1", productInfo, + newOrderRequest), + CreatePropertyFromTemplate("$.OrganizationInfo.OrganizationAddress.Region", + productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.OrganizationInfo.OrganizationAddress.PostalCode", + productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.OrganizationInfo.OrganizationAddress.Country", + productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.OrganizationInfo.OrganizationAddress.Phone", + productInfo, newOrderRequest), + CreatePropertyFromTemplate( + "$.OrganizationInfo.OrganizationAddress.LocalityName", productInfo, + newOrderRequest))))), + CreatePropertyFromTemplate("$.ValidityPeriod", productInfo, newOrderRequest), + new JProperty("ServerCount", 1), + new JProperty("CSR", csr), + CreatePropertyFromTemplate("$.DomainName", productInfo, newOrderRequest), + new JProperty("WebServerType", "Other"), + CreatePropertyFromTemplate("$.DNSNames", productInfo, newOrderRequest, true), + new JProperty("isCUOrder", false), + CreatePropertyFromTemplate("$.AutoWWW", productInfo, newOrderRequest), + new JProperty("IsRenewalOrder", isRenewal), + new JProperty("isTrialOrder", false), + new JProperty("AdminContact", + new JObject( + CreatePropertyFromTemplate("$.AdminContact.FirstName", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.AdminContact.LastName", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.AdminContact.Phone", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.AdminContact.Email", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.AdminContact.Title", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.AdminContact.OrganizationName", productInfo, + newOrderRequest), + CreatePropertyFromTemplate("$.AdminContact.AddressLine1", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.AdminContact.City", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.AdminContact.Region", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.AdminContact.PostalCode", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.AdminContact.Country", productInfo, newOrderRequest) + )), + new JProperty("TechnicalContact", + new JObject( + CreatePropertyFromTemplate("$.TechnicalContact.FirstName", productInfo, + newOrderRequest), + CreatePropertyFromTemplate("$.TechnicalContact.LastName", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.TechnicalContact.Phone", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.TechnicalContact.Email", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.TechnicalContact.Title", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.TechnicalContact.OrganizationName", productInfo, + newOrderRequest), + CreatePropertyFromTemplate("$.TechnicalContact.AddressLine1", productInfo, + newOrderRequest), + CreatePropertyFromTemplate("$.TechnicalContact.City", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.TechnicalContact.Region", productInfo, newOrderRequest), + CreatePropertyFromTemplate("$.TechnicalContact.PostalCode", productInfo, + newOrderRequest), + CreatePropertyFromTemplate("$.TechnicalContact.Country", productInfo, newOrderRequest) + )), + CreatePropertyFromTemplate("$.ApproverEmail", productInfo, newOrderRequest), + new JProperty("FileAuthDVIndicator", false), + new JProperty("CNAMEAuthDVIndicator", false), + new JProperty("SignatureHashAlgorithm", "PREFER_SHA2"))); + + return request.ToObject(); + } + + public string GetCertificateContent(List certificates, string commonName) + { + foreach (var c in certificates) + { + var cert = new X509Certificate2(Encoding.UTF8.GetBytes(c.FileContent)); + if (cert.SubjectName.Name != null && cert.SubjectName.Name.Contains(commonName)) return c.FileContent; + } + + return ""; + } + + private JArray CreateJArrayFromCommaSeparatedList(string csList) + { + var ja = new JArray(); + foreach (var i in csList.Split(',')) ja.Add(i); + return ja; + } + + private JProperty CreatePropertyFromTemplate(string propertyPath, EnrollmentProductInfo productInfo, + TemplateNewOrderRequest newOrderRequest, bool isArray = false) + { + var template = (JObject)JToken.FromObject(newOrderRequest); + var requiredForProducts = + new JArray(template.SelectTokens(propertyPath + ".FieldData.RequiredForProducts")); + var enrollmentFieldName = template.SelectToken(propertyPath + ".FieldData.EnrollmentFieldMapping"); + + if (requiredForProducts.Count > 0) + { + if (requiredForProducts[0].Any(i => i.Value() == "All") || + requiredForProducts[0].Any(i => i.Value() == productInfo.ProductID)) + if (enrollmentFieldName != null && enrollmentFieldName.Value() != "None") + { + if (productInfo.ProductParameters.ContainsKey(enrollmentFieldName.Value())) + { + var enrollmentFieldValue = + productInfo.ProductParameters[enrollmentFieldName.Value()]; + if (isArray == false) + return new JProperty(propertyPath.Substring(propertyPath.LastIndexOf('.') + 1), + enrollmentFieldValue); + return new JProperty(propertyPath.Substring(propertyPath.LastIndexOf('.') + 1), + CreateJArrayFromCommaSeparatedList(enrollmentFieldValue)); + } + + _logger.LogError( + $"Enrollment Field is required in the config settings but missing from the request or names do not match.: {enrollmentFieldName.Value()}"); + } + } + else + { + _logger.LogError($"Enrollment Field is in the request but missing from config settings: {propertyPath}"); + } + + return new JProperty(propertyPath.Substring(propertyPath.LastIndexOf('.') + 1), null); + } + + private string ExtractOrgId(string organization) + { + if (organization != null) + { + Regex pattern = new Regex(@"(\([^0-9]*\d+[^0-9]*\))"); + Match match = pattern.Match(organization); + return match.Value.Replace("(", "").Replace(")", ""); + } + else + { + return null; + } + } + } +} diff --git a/SslStoreCaProxy/SslStoreCAPluginConfig.cs b/SslStoreCaProxy/SslStoreCAPluginConfig.cs new file mode 100644 index 0000000..091f78b --- /dev/null +++ b/SslStoreCaProxy/SslStoreCAPluginConfig.cs @@ -0,0 +1,77 @@ +using Keyfactor.AnyGateway.Extensions; +using System.Collections.Generic; + +namespace Keyfactor.AnyGateway.SslStore +{ + public class SslStoreCAPluginConfig + { + public const int DefaultPageSize = 100; + + public class ConfigConstants + { + public static string SSLStoreURL = "SSLStoreURL"; + public static string PartnerCode = "PartnerCode"; + public static string AuthToken = "AuthToken"; + public static string PageSize = "PageSize"; + public static string Enabled = "Enabled"; + } + + public class Config + { + public string SSLStoreURL { get; set; } + public string PartnerCode { get; set; } + public string AuthToken { get; set; } + public int PageSize { get; set; } = DefaultPageSize; + public bool Enabled { get; set; } + } + + public static Dictionary GetPluginAnnotations() + { + return new Dictionary() + { + [ConfigConstants.SSLStoreURL] = new PropertyConfigInfo() + { + Comments = "The Base URL for the SSL Store API endpoint (e.g. https://sandbox-wbapi.thesslstore.com).", + Hidden = false, + DefaultValue = "https://sandbox-wbapi.thesslstore.com", + Type = "String" + }, + [ConfigConstants.PartnerCode] = new PropertyConfigInfo() + { + Comments = "The Partner Code obtained from SSL Store.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + [ConfigConstants.AuthToken] = new PropertyConfigInfo() + { + Comments = "The Authentication Token obtained from SSL Store.", + Hidden = true, + DefaultValue = "", + Type = "Secret" + }, + [ConfigConstants.PageSize] = new PropertyConfigInfo() + { + Comments = "The number of records to return per page during synchronization.", + Hidden = false, + DefaultValue = DefaultPageSize, + Type = "Number" + }, + [ConfigConstants.Enabled] = new PropertyConfigInfo() + { + Comments = "Flag to Enable or Disable the CA connector.", + Hidden = false, + DefaultValue = true, + Type = "Bool" + } + }; + } + + public static Dictionary GetTemplateParameterAnnotations() + { + return new Dictionary() + { + }; + } + } +} diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs new file mode 100644 index 0000000..10fdb32 --- /dev/null +++ b/SslStoreCaProxy/SslStoreCaProxy.cs @@ -0,0 +1,404 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Keyfactor.AnyGateway.Extensions; +using Keyfactor.AnyGateway.SslStore.Client; +using Keyfactor.AnyGateway.SslStore.Client.Models; +using Keyfactor.AnyGateway.SslStore.Interfaces; +using Keyfactor.Logging; +using Keyfactor.PKI.Enums.EJBCA; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System.Linq; + +namespace Keyfactor.AnyGateway.SslStore +{ + public class SslStoreCaProxy : IAnyCAPlugin + { + private static readonly ILogger _logger = LogHandler.GetClassLogger(); + private RequestManager _requestManager; + private IAnyCAPluginConfigProvider Config { get; set; } + private ICertificateDataReader _certDataReader; + private SslStoreCAPluginConfig.Config _config; + + public string PartnerCode { get; set; } + public string AuthenticationToken { get; set; } + public int PageSize { get; set; } + + public void Initialize(IAnyCAPluginConfigProvider configProvider, ICertificateDataReader certificateDataReader) + { + _logger.MethodEntry(); + try + { + _certDataReader = certificateDataReader; + Config = configProvider; + var rawData = JsonConvert.SerializeObject(configProvider.CAConnectionData); + _config = JsonConvert.DeserializeObject(rawData); + + PartnerCode = _config.PartnerCode; + AuthenticationToken = _config.AuthToken; + PageSize = _config.PageSize > 0 ? _config.PageSize : SslStoreCAPluginConfig.DefaultPageSize; + + _requestManager = new RequestManager(this); + + _logger.LogTrace($"Initialize - Enabled: {_config.Enabled}"); + } + catch (Exception ex) + { + _logger.LogError($"Failed to initialize SslStore CAPlugin: {ex}"); + throw; + } + } + + public async Task Ping() + { + _logger.MethodEntry(); + if (!_config.Enabled) + { + _logger.LogWarning("The CA is currently in the Disabled state. Skipping connectivity test..."); + _logger.MethodExit(); + return; + } + _logger.LogDebug("Pinging SslStore to validate connection"); + _logger.MethodExit(); + } + + public Task ValidateCAConnectionInfo(Dictionary connectionInfo) + { + _logger.MethodEntry(); + _logger.LogDebug("Validating SslStore CA Connection properties"); + var rawData = JsonConvert.SerializeObject(connectionInfo); + var config = JsonConvert.DeserializeObject(rawData); + + if (!config.Enabled) + { + _logger.LogWarning("The CA is currently in the Disabled state. Skipping config validation..."); + _logger.MethodExit(); + return Task.CompletedTask; + } + + List missingFields = new List(); + if (string.IsNullOrEmpty(config.SSLStoreURL)) missingFields.Add(nameof(config.SSLStoreURL)); + if (string.IsNullOrEmpty(config.PartnerCode)) missingFields.Add(nameof(config.PartnerCode)); + if (string.IsNullOrEmpty(config.AuthToken)) missingFields.Add(nameof(config.AuthToken)); + + if (missingFields.Count > 0) + { + throw new ArgumentException($"The following required fields are missing or empty: {string.Join(", ", missingFields)}"); + } + + _logger.MethodExit(); + return Ping(); + } + + public Task ValidateProductInfo(EnrollmentProductInfo productInfo, Dictionary connectionInfo) + { + _logger.MethodEntry(); + _logger.MethodExit(); + return Task.CompletedTask; + } + + public List GetProductIds() + { + return ProductDefinitions.GetProductIds(); + } + + public Dictionary GetCAConnectorAnnotations() + { + _logger.MethodEntry(); + _logger.MethodExit(); + return SslStoreCAPluginConfig.GetPluginAnnotations(); + } + + public Dictionary GetTemplateParameterAnnotations() + { + _logger.MethodEntry(); + _logger.MethodExit(); + return SslStoreCAPluginConfig.GetTemplateParameterAnnotations(); + } + + public async Task Revoke(string caRequestId, string hexSerialNumber, uint revocationReason) + { + _logger.MethodEntry(); + var revokeOrderRequest = _requestManager.GetRevokeOrderRequest(caRequestId.Split('-')[0]); + _logger.LogTrace($"Revoke Request JSON {JsonConvert.SerializeObject(revokeOrderRequest)}"); + try + { + var client = new SslStoreClient(Config); + var requestResponse = await client.SubmitRevokeCertificateAsync(revokeOrderRequest); + + _logger.LogTrace($"Revoke Response JSON {JsonConvert.SerializeObject(requestResponse)}"); + + if (requestResponse.AuthResponse.IsError) + { + _logger.LogError("Revoke Error Occurred"); + _logger.MethodExit(); + return (int)EndEntityStatus.FAILED; + } + + _logger.MethodExit(); + return (int)EndEntityStatus.REVOKED; + } + catch (Exception e) + { + _logger.LogError($"An Error has occurred during the revoke process {e.Message}"); + return (int)EndEntityStatus.FAILED; + } + } + + public async Task Enroll(string csr, string subject, Dictionary san, + EnrollmentProductInfo productInfo, RequestFormat requestFormat, EnrollmentType enrollmentType) + { + _logger.MethodEntry(); + var client = new SslStoreClient(Config); + + try + { + INewOrderResponse enrollmentResponse = null; + + if (enrollmentType == EnrollmentType.New) + { + _logger.LogTrace("Entering New Enrollment"); + + if (!productInfo.ProductParameters.ContainsKey("PriorCertSN")) + { + string[] arrayProducts = Array.Empty(); + string[] arrayApproverEmails = Array.Empty(); + + if (productInfo.ProductParameters.ContainsKey("DNS Names Comma Separated")) + { + _logger.LogTrace($"DNS Comma Separated {productInfo.ProductParameters["DNS Names Comma Separated"]}"); + arrayProducts = productInfo.ProductParameters["DNS Names Comma Separated"].Split(new char[] { ',' }); + } + if (productInfo.ProductParameters.ContainsKey("Approver Email")) + { + _logger.LogTrace($"Approver Email {productInfo.ProductParameters["Approver Email"]}"); + arrayApproverEmails = productInfo.ProductParameters["Approver Email"].Split(new char[] { ',' }); + } + + var count = 1; + foreach (var product in arrayProducts) + { + var emailApproverRequest = _requestManager.GetEmailApproverListRequest(productInfo.ProductID, product); + _logger.LogTrace($"Email Approver Request JSON {JsonConvert.SerializeObject(emailApproverRequest)}"); + + var emailApproverResponse = client.SubmitEmailApproverRequestAsync(emailApproverRequest); + _logger.LogTrace($"Email Approver Response JSON {JsonConvert.SerializeObject(emailApproverResponse)}"); + + var emailValidation = ValidateEmails(emailApproverResponse, arrayApproverEmails, productInfo, count); + _logger.LogTrace($"Email Validation Result {emailValidation}"); + + if (emailValidation.Length > 0) + { + return new EnrollmentResult + { + Status = (int)EndEntityStatus.FAILED, + StatusMessage = emailValidation + }; + } + count++; + } + + var enrollmentRequest = _requestManager.GetEnrollmentRequest(csr, productInfo, Config, false); + _logger.LogTrace($"enrollmentRequest JSON {JsonConvert.SerializeObject(enrollmentRequest)}"); + + enrollmentResponse = await client.SubmitNewOrderRequestAsync(enrollmentRequest); + _logger.LogTrace($"enrollmentResponse JSON {JsonConvert.SerializeObject(enrollmentResponse)}"); + } + else + { + return new EnrollmentResult + { + Status = (int)EndEntityStatus.FAILED, + StatusMessage = "You cannot renew an expired cert please perform a new enrollment." + }; + } + } + else if (enrollmentType == EnrollmentType.RenewOrReissue) + { + _logger.LogTrace("Entering Renew/Reissue Logic..."); + + var sn = productInfo.ProductParameters["PriorCertSN"]; + _logger.LogTrace($"Prior Cert Serial Number: {sn}"); + + var caRequestId = await _certDataReader.GetRequestIDBySerialNumber(sn); + _logger.LogTrace($"Prior CA Request ID: {caRequestId}"); + + var orderId = caRequestId.Split('-')[0]; + var orderStatusRequest = _requestManager.GetOrderStatusRequest(orderId); + _logger.LogTrace($"orderStatusRequest JSON {JsonConvert.SerializeObject(orderStatusRequest)}"); + + var orderStatusResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); + _logger.LogTrace($"orderStatusResponse JSON {JsonConvert.SerializeObject(orderStatusResponse)}"); + + // Try renewal first, fall back to reissue + var renewRequest = _requestManager.GetRenewalRequest(orderStatusResponse, csr); + _logger.LogTrace($"renewRequest JSON {JsonConvert.SerializeObject(renewRequest)}"); + + enrollmentResponse = await client.SubmitRenewRequestAsync(renewRequest); + _logger.LogTrace($"enrollmentResponse JSON {JsonConvert.SerializeObject(enrollmentResponse)}"); + + if (enrollmentResponse != null && enrollmentResponse.AuthResponse != null && enrollmentResponse.AuthResponse.IsError) + { + _logger.LogTrace("Renewal failed, attempting reissue..."); + var reIssueRequest = _requestManager.GetReIssueRequest(orderStatusResponse, csr, false); + _logger.LogTrace($"reIssueRequest JSON {JsonConvert.SerializeObject(reIssueRequest)}"); + + enrollmentResponse = await client.SubmitReIssueRequestAsync(reIssueRequest); + _logger.LogTrace($"reissue enrollmentResponse JSON {JsonConvert.SerializeObject(enrollmentResponse)}"); + } + } + + return GetEnrollmentResult(enrollmentResponse); + } + finally + { + _logger.MethodExit(); + } + } + + private EnrollmentResult GetEnrollmentResult(INewOrderResponse newOrderResponse) + { + if (newOrderResponse != null && newOrderResponse.AuthResponse.IsError) + { + _logger.MethodExit(); + return new EnrollmentResult + { + Status = (int)EndEntityStatus.FAILED, + StatusMessage = newOrderResponse.AuthResponse.Message[0] + }; + } + + _logger.MethodExit(); + return new EnrollmentResult + { + Status = (int)EndEntityStatus.GENERATED, + StatusMessage = $"Order Successfully Created With Order Number {newOrderResponse?.TheSslStoreOrderId}" + }; + } + + public async Task GetSingleRecord(string caRequestId) + { + _logger.MethodEntry(); + + var client = new SslStoreClient(Config); + var orderStatusRequest = _requestManager.GetOrderStatusRequest(caRequestId); + _logger.LogTrace($"orderStatusRequest JSON {JsonConvert.SerializeObject(orderStatusRequest)}"); + + var certResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); + _logger.LogTrace($"certResponse JSON {JsonConvert.SerializeObject(certResponse)}"); + + _logger.MethodExit(); + return new AnyCAPluginCertificate + { + CARequestID = caRequestId, + Certificate = string.Empty, + Status = _requestManager.MapReturnStatus(certResponse?.OrderStatus.MajorStatus) + }; + } + + public async Task Synchronize(BlockingCollection blockingBuffer, + DateTime? lastSync, bool fullSync, CancellationToken cancelToken) + { + _logger.MethodEntry(); + + try + { + var client = new SslStoreClient(Config); + var certs = new BlockingCollection(100); + _ = client.SubmitQueryOrderRequestAsync(certs, cancelToken, _requestManager); + + foreach (var currentResponseItem in certs.GetConsumingEnumerable(cancelToken)) + { + if (cancelToken.IsCancellationRequested) + { + _logger.LogError("Synchronize was canceled."); + break; + } + + try + { + _logger.LogTrace($"Took Certificate ID {currentResponseItem?.TheSslStoreOrderId} from Queue"); + + var orderStatusRequest = _requestManager.GetOrderStatusRequest(currentResponseItem?.TheSslStoreOrderId); + var orderStatusResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); + + var fileContent = ""; + var certStatus = _requestManager.MapReturnStatus(orderStatusResponse.OrderStatus.MajorStatus); + + if (certStatus == (int)EndEntityStatus.GENERATED) + { + var downloadCertificateRequest = _requestManager.GetCertificateRequest(orderStatusResponse.TheSslStoreOrderId); + var certResponse = await client.SubmitDownloadCertificateAsync(downloadCertificateRequest); + if (!certResponse.AuthResponse.IsError) + { + fileContent = _requestManager.GetCertificateContent(certResponse.Certificates, orderStatusResponse.CommonName); + } + } + + if ((certStatus == (int)EndEntityStatus.GENERATED && fileContent.Length > 0) || + certStatus == (int)EndEntityStatus.REVOKED) + { + string serialNumber = ""; + if (fileContent.Length > 0) + { + var cert = new X509Certificate2(Encoding.UTF8.GetBytes(fileContent)); + serialNumber = cert.SerialNumber; + } + + blockingBuffer.Add(new AnyCAPluginCertificate + { + CARequestID = $"{orderStatusResponse.TheSslStoreOrderId}-{serialNumber}", + Certificate = fileContent, + Status = certStatus, + ProductID = $"{orderStatusResponse.ProductCode}" + }, cancelToken); + } + } + catch (OperationCanceledException) + { + _logger.LogError("Synchronize was canceled."); + break; + } + } + } + catch (AggregateException) + { + _logger.LogError("SslStore Synchronize Task failed!"); + throw; + } + + _logger.MethodExit(); + } + + private string ValidateEmails(Task validEmails, string[] arrayApproverEmails, EnrollmentProductInfo productInfo, int count) + { + if (arrayApproverEmails.Length > 1 && productInfo.ProductID.Contains("digi")) + { + return "There should only be one approval email for Digicert products."; + } + + if (count == 1 && productInfo.ProductID.Contains("digi") && arrayApproverEmails.Length > 0) + { + if (!validEmails.Result.ApproverEmailList.Contains(arrayApproverEmails[0])) + { + return $"Digicert Approver Email must be one of the following {string.Join(",", validEmails.Result.ApproverEmailList)}"; + } + } + + if (!productInfo.ProductID.Contains("digi")) + { + if (!validEmails.Result.ApproverEmailList.Intersect(arrayApproverEmails).Any()) + { + return $"Sectigo Approver Email must be one of the following {string.Join(",", validEmails.Result.ApproverEmailList)}"; + } + } + + return ""; + } + } +} diff --git a/SslStoreCaProxy/SslStoreCaProxy.csproj b/SslStoreCaProxy/SslStoreCaProxy.csproj new file mode 100644 index 0000000..38fbab3 --- /dev/null +++ b/SslStoreCaProxy/SslStoreCaProxy.csproj @@ -0,0 +1,21 @@ + + + net6.0;net8.0 + disable + true + false + Keyfactor.AnyGateway.SslStore + SslStoreCaProxy + + + + + + + + + + Always + + + diff --git a/SslStoreCaProxy/manifest.json b/SslStoreCaProxy/manifest.json new file mode 100644 index 0000000..047caab --- /dev/null +++ b/SslStoreCaProxy/manifest.json @@ -0,0 +1,10 @@ +{ + "extensions": { + "Keyfactor.AnyGateway.Extensions.IAnyCAPlugin": { + "SslStoreCaPlugin": { + "assemblypath": "SslStoreCaProxy.dll", + "TypeFullName": "Keyfactor.AnyGateway.SslStore.SslStoreCaProxy" + } + } + } +} diff --git a/docs/ssl-validity-timeline.html b/docs/ssl-validity-timeline.html new file mode 100644 index 0000000..942e453 --- /dev/null +++ b/docs/ssl-validity-timeline.html @@ -0,0 +1,1323 @@ + + + + + +SSL Certificate Validity Timeline - Keyfactor CA Gateway Impact + + + + +

SSL/TLS Certificate Validity Reduction Timeline

+

Impact on Keyfactor AnyGateway ↔ TheSSLStore API Integration  |  CA/Browser Forum Ballot SC-081v3

+ + + + +

Regulatory Phase Timeline

+

CA/Browser Forum Ballot SC-081v3 — phased reduction of public TLS certificate max validity

+ +
+ + +
+
+
+
Before March 15, 2026
+

Current State — 398 Days Max

+

Templates offer 12-60 month validity. Renewals copy prior order validity. DCV reuse up to 398 days. Multi-year plans reissue once per year.

+ CURRENT +
+
+ + +
+
+
+
March 15, 2026 — 200 Days Max
+

Phase 1: Half the Validity

+

Max cert lifetime drops to 200 days (~6.5 months). DCV reuse drops to 200 days. Multi-year plans still valid — but certs must be reissued every ~6 months instead of every year. No extra cost, just more frequent reissues.

+ IMMINENT — 13 DAYS AWAY +
+
+ + +
+
+
+
March 15, 2027 — 100 Days Max
+

Phase 2: Quarterly Reissues

+

Max validity drops to 100 days. DCV reuse drops to 100 days. Multi-year plan = ~4 free reissues per year. AD template renewal windows need tightening.

+ 1 YEAR AWAY +
+
+ + +
+
+
+
March 15, 2029 — 47 Days Max
+

Phase 3: Full Automation Required

+

Max validity drops to 47 days. DCV reuse drops to 10 days. Multi-year plan = ~8 reissues/year. Manual workflows impossible. DCV re-validation on nearly every reissue.

+ 3 YEARS AWAY +
+
+ +
+ + +

The SSLStore Multi-Year Subscription Model

+

SSLStore sells multi-year plans (2-3 years). You pay once. The actual certificate is only valid for the current max. When it expires, you reissue for free under the same order. You do NOT buy a new certificate.

+ +
+

Key Concept: Order Expiry vs Certificate Expiry

+

The SSLStore API returns two different dates that the gateway must distinguish:

+
    +
  • OrderExpiryDate (NewOrderResponse.cs:35) — when the paid subscription plan expires (e.g., 2-3 years)
  • +
  • CertificateEndDate (NewOrderResponse.cs:15) — when the actual issued certificate expires (200 days after Phase 1)
  • +
+

When the cert expires but the order is still valid, the correct action is a free reissue (/rest/order/reissue), NOT a paid renewal (/rest/order/neworder).

+
+ + +
+
+
Today: 2-Year Plan with 365-Day Certs (730 ÷ 2)
+
+
Order (paid)
+
+
2-year subscription plan (730 days)
+
+
+
+
Cert #1
+
+
365 days — included with plan
+
+
+
+
Cert #2 (reissue)
+
+
365 days — FREE reissue
+
+
+
+ +
+
Phase 1: Same 2-Year Plan with ~183-Day Certs (730 ÷ 4)
+
+
Order (paid)
+
+
2-year subscription plan (730 days) — same price
+
+
+
+
Cert #1
+
+
183d
+
+
+
+
Cert #2 (reissue)
+
+
183d — FREE
+
+
+
+
Cert #3 (reissue)
+
+
183d — FREE
+
+
+
+
Cert #4 (reissue)
+
+
183d — FREE
+
+
+
+ +
+
Phase 3: Same 2-Year Plan with 47-Day Certs
+
+
Order (paid)
+
+
2-year plan (730 days) — same price, ~16 reissues
+
+
+
+
Certs (reissues)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
~16 × 47-day certs — all FREE reissues under same order
+
+
+
+
+ + +

The Renew vs Reissue Problem

+

The Keyfactor framework decides Renew vs Reissue based on the AD certificate template settings — but it doesn't know whether the SSLStore order is still active. This causes the wrong API call.

+ +
+

Critical Bug: Keyfactor Sends "Renew" When It Should Send "Reissue"

+

The Keyfactor AnyGateway framework controls the enrollment type sent to the gateway. When a cert enters the AD template's renewal period, the framework sends EnrollmentType.Renew. The gateway then blindly calls /rest/order/neworder with IsRenewalOrder=true — creating a new paid order.

+

But if the customer has a multi-year plan, the order is still valid. The correct action is /rest/order/reissue (free). The good news: OrderExpiryDate is already returned by /rest/order/status (confirmed via Postman), already mapped in NewOrderResponse.cs:35, and already on the INewOrderResponse interface. The orderStatusResponse object in the Renew handler already has this value — no model or API changes required.

+
+ +
+

Important: "Order Still Open" Is Not Enough — Remaining Time Must Fit the New Cert

+

Simply checking OrderExpiryDate > today is insufficient. Consider this scenario:

+
    +
  • Current cert expires in 30 days (inside renewal window — trigger fires)
  • +
  • Order expiry is 45 days away (order is technically still "open")
  • +
  • Desired new cert validity: 200 days (Phase 1 max)
  • +
+

The order is open, but there's only 45 days left — not enough room for a 200-day cert. Attempting a reissue here would either be rejected by the SSLStore API or result in a truncated cert. The gateway must compare remaining order time vs desired cert validity and fall back to a paid renewal when there isn't enough room.

+
+ +
+
+
+

Current Behavior (WRONG)

+ CAUSES UNNECESSARY CHARGES +
+
+
+
+
AD Template
+

Cert enters renewal window (6 weeks before expiry)

+

Framework sends EnrollmentType.Renew

+
+
+
+
CA Gateway
+

GetRenewalRequest() called

+

Copies old validity, sets IsRenewalOrder=true

+ NO ORDER CHECK +
+
+
+
SSLStore API
+

/rest/order/neworder

+

Creates NEW paid order even though the existing order is still valid

+ CUSTOMER CHARGED +
+
+
+
+ +
+
+

Correct Behavior (NEEDED)

+ FREE REISSUE UNDER EXISTING ORDER +
+
+
+
+
AD Template
+

Cert enters renewal window (framework sends Renew)

+

Framework behavior unchanged

+
+
+
+
CA Gateway (FIXED)
+

Check two conditions:
+ 1. OrderExpiryDate > now
+ 2. (OrderExpiryDate - now) ≥ desiredValidity

+

BOTH trueGetReIssueRequest() (free)
Either falseGetRenewalRequest() (new purchase)

+ SMART ROUTING +
+
+
+
SSLStore API
+

If order valid: /rest/order/reissueFREE

+

If order expired: /rest/order/neworder → new purchase

+ CORRECT API CALL +
+
+
+
+
+ + +

AD Certificate Template Settings

+

The AD template's Validity Period and Renewal Period control when Keyfactor triggers renewals. These must be updated to match actual cert lifetimes, or the renewal window becomes miscalibrated.

+ + +
+
+
Today: Validity = 1 Year, Renewal Window = 6 Weeks
+
+
Certificate
+
+
Active (319 days)
+
Renew (42d)
+
+
+
+ +
+
Phase 1 Recommended: Validity = 6 Months, Renewal Window = 4 Weeks
+
+
Certificate
+
+
Active (~172 days)
+
Renew (28d)
+
+
+
+ +
+
Phase 2 Recommended: Validity = 3 Months, Renewal Window = 3 Weeks
+
+
Certificate
+
+
Active (~79 days)
+
Renew (21d)
+
+
+
+ +
+
Phase 3 Recommended: Validity = 2 Months, Renewal Window = 2 Weeks
+
+
Certificate
+
+
Active (~33 days)
+
Renew (14d)
+
+
+
+ +
+
Phase 3 BROKEN: If you keep Validity = 1 Year, Renewal Window = 6 Weeks
+
+
Certificate
+
+
Cert is only 47 days — but KF thinks it has 365 days. Renewal never triggers!
+
+
+
+
+ +
+

Important: Keyfactor Uses the Actual Cert Expiration Date

+

Keyfactor Command reads the NotAfter date from the synced certificate, not the AD template validity period, to determine when the cert actually expires. So the renewal window will fire based on real cert expiry. However:

+
    +
  • The AD template validity should still match actual cert validity to avoid confusion and audit issues
  • +
  • The renewal window duration (6 weeks) is what really matters — it must not exceed the cert lifetime
  • +
  • At 47 days (Phase 3), a 6-week renewal window means renewal triggers on day 5 — essentially immediately
  • +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PhaseMax Cert ValidityAD Template ValidityAD Renewal PeriodEffective Active TimeReissues per Year
(2-yr plan)
Today398 days1 year6 weeks~319 days1
Phase 1 (Mar 2026)200 days6 months4 weeks~172 days~4
Phase 2 (Mar 2027)100 days3 months3 weeks~79 days~8
Phase 3 (Mar 2029)47 days2 months2 weeks~33 days~16
+ + +

Template Validity Options: What Breaks When

+

Current enrollment field options (in months) from Setup/Templates/*.json mapped against each phase's maximum

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Template OptionDaysToday (398d max)Phase 1 (200d max)Phase 2 (100d max)Phase 3 (47d max)
60 months (5 yr)~1825Already invalid since 2020REJECTEDREJECTEDREJECTED
48 months (4 yr)~1460Already invalid since 2020REJECTEDREJECTEDREJECTED
36 months (3 yr)~1095Already invalid since 2020REJECTEDREJECTEDREJECTED
24 months (2 yr)~730Already invalid since 2020REJECTEDREJECTEDREJECTED
12 months (1 yr)~365VALIDREJECTEDREJECTEDREJECTED
6 months (new)~180VALIDVALIDREJECTEDREJECTED
3 months (new)~90VALIDVALIDVALIDREJECTED
1 month (new)~30VALIDVALIDVALIDVALID
+ + +

Order Flow: Keyfactor GW ↔ SSLStore API

+

How new enrollment, renewal/reissue, and sync flows change across each phase

+ +
+
Breaking Change
+
Warning / Needs Update
+
No Change Needed
+
Code Change Required
+
+ +
+ + +
+
+

Phase 1: March 15, 2026 — 200 Day Maximum

+ MAX 200 DAYS +
+
+ + +

New Enrollment Flow

+
+
+
1. Keyfactor Command
+

User selects template & picks validity from enrollment field dropdown

+ BREAKS: 12-60 month options invalid +
+
+
+
2. CA Gateway
+

BuildNewOrderRequest() maps template validity to ValidityPeriod field

+ UPDATE: Templates need 6-month option +
+
+
+
3. SSLStore API
+

/rest/order/neworder — API rejects if cert validity > 200 days

+ API ENFORCES NEW LIMIT +
+
+ + +

Cert Expiry on Multi-Year Plan (Renew vs Reissue)

+
+
+
1. Keyfactor Command
+

200-day cert enters renewal window. Framework sends EnrollmentType.Renew regardless of order status.

+ ALWAYS SENDS RENEW +
+
+
+
2. CA Gateway (TODAY)
+

GetRenewalRequest() copies old validity, creates new paid order. Does NOT check if existing order is still valid.

+ WRONG: CREATES NEW PAID ORDER +
+
+
+
3. SSLStore API
+

/rest/order/neworder — charges customer for a new order when a free reissue would have worked

+ CUSTOMER OVERCHARGED +
+
+ +
+
+
1. Keyfactor Command
+

Same trigger — no change to framework

+ NO CHANGE +
+
+
+
2. CA Gateway (FIXED)
+

On Renew: query order status, check OrderExpiryDate. If order still valid → /rest/order/reissue (free). If expired → /rest/order/neworder.

+ NEW: Smart renew/reissue routing +
+
+
+
3. SSLStore API
+

/rest/order/reissue → free cert under existing plan

+ CORRECT: FREE REISSUE +
+
+ + +

Sync / Inventory Flow

+
+
+
1. SSLStore API
+

/rest/order/query & /rest/order/status return shorter-lived certs

+ NO CHANGE +
+
+
+
2. CA Gateway
+

Synchronize() downloads certs, maps status, stores in Keyfactor

+ NO CHANGE +
+
+
+
3. Keyfactor Command
+

Inventory updated. Expiration alerts trigger sooner — 2x more renewals

+ REVIEW: Alert thresholds & AD template renewal period +
+
+
+
+ + +
+
+

Phase 2: March 15, 2027 — 100 Day Maximum

+ MAX 100 DAYS +
+
+ +

New Enrollment Flow

+
+
+
1. Keyfactor Command
+

Template dropdown now needs 3-month option (or less). AD template validity & renewal period updated.

+ UPDATE: Templates & AD settings +
+
+
+
2. CA Gateway
+

ValidityPeriod must be ≤3 months. 6-month option now invalid. Smart reissue logic handles multi-year plans.

+ UPDATE: Remove 6-month option +
+
+
+
3. SSLStore API
+

API enforces 100-day max. DCV reuse also 100 days. ~4 reissues/year on 2-yr plan.

+ API ENFORCES +
+
+ +

DCV Reuse Impact

+
+
+
CA Gateway
+

FileAuthDvIndicator / CNameAuthDvIndicator still reuse prior DCV

+ DCV expires every 100 days +
+
+
+
SSLStore API
+

Prior DCV may be expired. Re-validation triggered more often.

+ MORE DCV CHALLENGES +
+
+
+
Operations
+

DNS/File validation challenges ~4x/year per domain instead of 1x

+ PROCESS IMPACT +
+
+
+
+ + +
+
+

Phase 3: March 15, 2029 — 47 Day Maximum

+ MAX 47 DAYS +
+
+ +

Full Automation Required

+
+
+
Keyfactor Command
+

Must auto-trigger reissues ~14 days before expiry. ~16 reissues/year on 2-yr plan. Manual approval workflows become unsustainable.

+ REQUIRES AUTO-RENEWAL +
+
+
+
CA Gateway
+

Smart reissue routing critical at this volume. Must handle 10-day DCV reuse — nearly every reissue needs fresh DCV.

+ MAJOR: DCV REARCHITECT +
+
+
+
SSLStore API
+

47-day certs, 10-day DCV reuse. API will require automated DCV completion for every reissue.

+ API CHANGES EXPECTED +
+
+ +

Scale Impact

+
+
+
Volume
+

100 certs today = 800 reissue operations/year. Sync must handle increased order volume. API rate limits become a concern.

+
+
+
+
DCV
+

10-day reuse = DCV validation with almost every reissue. DNS automation (RFC 2136 / cloud API) becomes mandatory.

+
+
+
+
Operations
+

Zero-touch pipeline required end-to-end. Any manual step becomes a bottleneck at this reissue frequency.

+
+
+
+
+ +
+ + +

Specific Code Impacts

+

Files and methods in this gateway that require changes

+ +
+ +
+

1. Renew Handler — Needs Smart Reissue Routing

+ SslStoreCaProxy/SslStoreCaProxy.cs:160-186 +

When Keyfactor sends EnrollmentType.Renew, the gateway must check if the SSLStore order is still valid. If so, perform a free reissue instead of creating a new paid order.

+
// Current: always creates new paid order
+case RequestUtilities.EnrollmentType.Renew:
+  var renewRequest = _requestManager
+    .GetRenewalRequest(orderStatusResponse, csr);
+  // calls /rest/order/neworder ← WRONG for multi-year plans
+
+// Needed: two-condition check
+var orderExpiry = DateTime.Parse(
+    orderStatusResponse.OrderExpiryDateInUtc);
+var desiredValidityDays = orderStatusResponse.Validity;
+var remainingDays =
+    (orderExpiry - DateTime.UtcNow).TotalDays;
+
+if (remainingDays >= desiredValidityDays) {
+  // Enough room in order → FREE reissue
+  reIssueRequest = _requestManager
+    .GetReIssueRequest(orderStatusResponse, csr, true);
+  // calls /rest/order/reissue ← FREE
+} else {
+  // Order expired OR not enough room for new cert
+  // → new purchase
+  var renewRequest = _requestManager
+    .GetRenewalRequest(orderStatusResponse, csr);
+  // calls /rest/order/neworder
+}
+
+// Examples:
+// Order has 400d left, want 200d cert → 400 >= 200 → REISSUE (free)
+// Order has 45d left,  want 200d cert → 45  <  200 → RENEW  (paid)
+// Order expired,       want 200d cert →  0  <  200 → RENEW  (paid)
+
+ +
+

2. OrderExpiryDate — Already Available (No Model Changes)

+ SslStoreCaProxy/Client/Models/NewOrderResponse.cs:35 & Interfaces/INewOrderResponse.cs:28 +

Confirmed via Postman: /rest/order/status already returns OrderExpiryDate. The model already maps it. The interface already exposes it. The orderStatusResponse in the Renew handler is already an INewOrderResponse — the data is there right now, just never checked.

+
// /rest/order/status response (confirmed):
+"OrderExpiryDate": "2/19/2022 12:00:00 AM",
+"OrderExpiryDateInUTC": "2/19/2022 5:00:00 AM"
+
+// NewOrderResponse.cs:35 - already mapped:
+public string OrderExpiryDate { get; set; }
+[JsonProperty("OrderExpiryDateInUTC")]
+public string OrderExpiryDateInUtc { get; set; }
+
+// INewOrderResponse.cs:28 - already on interface:
+string OrderExpiryDate { get; set; }
+string OrderExpiryDateInUtc { get; set; }
+
+// Fix is ONE if-check in SslStoreCaProxy.cs:
+// orderStatusResponse.OrderExpiryDate is
+// already populated. Just use it.
+
+ +
+

3. Renewal Copies Old Validity

+ SslStoreCaProxy/RequestManager.cs:211 +

GetRenewalRequest() blindly copies orderData.Validity from the prior order. Old 12-month orders will produce 12-month renewal requests that fail.

+
// Current code (line 211):
+ValidityPeriod = orderData.Validity,
+
+// Needs to cap to current max:
+ValidityPeriod = Math.Min(orderData.Validity, MAX_VALIDITY),
+
+ +
+

4. Template Files — Validity Options

+ Setup/Templates/*.json (80+ files) +

All templates list 12, 24, 36, 48, 60 month options. After Phase 1, only ≤6 months is valid.

+
"Name": "Validity Period (In Months)",
+"Options": [
+  "12",   ← REJECTED (365 days > 200)
+  "24",   ← REJECTED
+  "36",   ← REJECTED
+  "48",   ← REJECTED
+  "60"    ← REJECTED
+]
+// Replace with:
+"Options": [ "6" ]
+
+ +
+

5. New Enrollment — No Validation

+ SslStoreCaProxy/RequestManager.cs:281 +

BuildNewOrderRequest() passes validity straight through from the template with no bounds checking. The API will reject, but errors surface late.

+
// Line 281 - passed through unchecked:
+CreatePropertyFromTemplate(
+  "$.ValidityPeriod", productInfo,
+  newOrderRequest)
+
+// Consider: pre-validate before API call
+// to give users a clear error message
+
+ +
+

6. Expired Cert Handling

+ SslStoreCaProxy/SslStoreCaProxy.cs:152-157 +

If a cert expires before Keyfactor triggers renewal, the gateway rejects with a hard error. With shorter lifetimes this will happen more often. Consider auto-falling back to new enrollment.

+
return new EnrollmentResult {
+  Status = 30, //failure
+  StatusMessage = "You cannot renew an expired
+    cert please perform an new enrollment."
+};
+
+// Consider: auto-fallback to new enrollment
+// instead of hard failure
+
+ +
+ + +

Gameplan & Implementation Timeline

+

Prioritized action items across all three phases

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
WhenPriorityTypeActionFiles / Config
NOW
(before Mar 15)
P0CodeSmart Renew/Reissue routing — When gateway receives EnrollmentType.Renew, compare (OrderExpiryDate - today) against the desired cert validity. If remaining order time ≥ desired validity → free reissue. Otherwise → new paid renewal. OrderExpiryDate already populated on orderStatusResponse, no model changes needed.SslStoreCaProxy.cs:160-186
NOW
(before Mar 15)
P0CodeCap renewal validity — Fix GetRenewalRequest() to not blindly copy orderData.Validity. Cap to 6 months max.RequestManager.cs:211
NOW
(before Mar 15)
P0ConfigUpdate template validity options — Replace 12-60 month options with 6-month across all 80+ template filesSetup/Templates/*.json
NOW
(before Mar 15)
P0ConfigUpdate AD certificate templates — Set Validity Period to 6 months, Renewal Period to 4 weeksAD Certificate Templates (certtmpl.msc)
Q2 2026P1CodeAdd validity pre-validation in BuildNewOrderRequest() with clear error messages before hitting the APIRequestManager.cs:281
Q2 2026P1CodeImprove expired cert handling — auto-fallback to new enrollment instead of hard failure messageSslStoreCaProxy.cs:152-157
Q2 2026P1ConfigReview Keyfactor Command expiration alert thresholds for 200-day cert lifecycleKeyfactor Command config
Q4 2026P1ConfigPrepare for Phase 2: update templates to 3-month max, AD template validity to 3 months, renewal period to 3 weeksTemplates/*.json, AD templates
2028P2ArchArchitect automated DCV pipeline for 10-day reuse window. Evaluate DNS-01 automation (RFC 2136 / cloud provider APIs)RequestManager.cs, new DCV module
2028-2029P2ArchZero-touch pipeline: auto-DCV, auto-reissue, auto-deployment. AD templates at 2 months / 2 week renewal. 16 reissues/year on 2-yr plans.Full gateway + Keyfactor orchestrator
+
+ +
+ Generated for sslstore-cagateway (branch: sslapifixes)  |  Based on CA/Browser Forum Ballot SC-081v3  |  March 2, 2026
+ Sources: thesslstore.com, digicert.com, sectigo.com, appviewx.com +
+ + + diff --git a/integration-manifest.json b/integration-manifest.json new file mode 100644 index 0000000..1a4403e --- /dev/null +++ b/integration-manifest.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://keyfactor.github.io/integration-manifest-schema.json", + "integration_type": "ca-gateway", + "name": "SSLStore", + "status": "production", + "release_dir": "SslStoreCaProxy/bin/Release", + "support_level": "kf-supported", + "update_catalog": true, + "link_github": true, + "description": "SSLStore is a certificate reseller with access to over 80 certificate products. Vendors include Digicert and Sectigo and all their acquired companies such as RapidSSL, Geotrust and Comodo. There is one API for all these products so a single integration to the SSLStore can get you instant access to over 80 Certificate products." +} diff --git a/readme_source.md b/readme_source.md new file mode 100644 index 0000000..d30820f --- /dev/null +++ b/readme_source.md @@ -0,0 +1,1242 @@ +*** + +# Compatibility +This AnyGateway is designed to be used with version 21.3.2 of the Keyfactor AnyGateway Framework. + +# Getting Started + +## Integration Overview + +### Supported Functionality +- Certificate Sync - Full +- Certificate Enrollment for Domain Validated product suite (Regular, with SANs, and Wildcard) +- Certificate Enrollment for Organization Validated product suite (Regular, with SANs, and Wildcard) +- Certificate Enrollment for Extended Validation product suite (Regular and with SANs) +- Certificate Renewal/Reissue +- Certificate Revocation + + +### Unsupported Functionality +- Certificate Sync - Partial (not possible through the SSL Store API library) +- Approval/Denial of Enrollment Requests (not possible through the SSL Store API library) + +### Documentation +**General Documentation** +[SSLStore API Documentation](https://www.thesslstore.com/api/) + + +## Standard Gateway Installation +To begin, you must have the CA Gateway Service 21.3.2 installed and operational before attempting to configure the SSLStore Any Gateway plugin. This integration was tested with Keyfactor 8.7.0.0. +To install the gateway follow these instructions. + +1) Gateway Server - run the installation .msi obtained from Keyfactor + +2) Gateway Server - If you have the rights to install the database (usually in a Non SQL PAAS Environment) Using Powershell, run the following command to create the gateway database. + + **SQL Server Windows Auth** + ``` + %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] + ``` + Note if you are using SQL Authentication, then you need to run + + **SQL Server SQL Authentication** + + ``` + %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] -u [sql user] -p [sql password] + ``` + + If you do **not** have rights to created the database then have the database created ahead of time by the support team and just populate the database + + ## Populate commands below + + **Windows Authentication** + + ``` + %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] + ``` + + **SQL Server SQL Authentication** + + ``` + %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] -u [sql user] -p [sql password] + ``` + +3) Gateway Server - run the following Powershell to import the Cmdlets + + C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll (must be imported into Powershell) + ```ps + Import-Module C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll + ``` + +4) Gateway Server - Run the Following Powershell script to set the gateway encryption cert + + ### Set-KeyfactorGatewayEncryptionCert + This cmdlet will generate a self-signed certificate used to encrypt the database connection string. It populates a registry value with the serial number of the certificate to be used. The certificate is stored in the LocalMachine Personal Store and the registry key populated is: + + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvcProxy\Parameters\EncryptSerialNumber + No parameters are required to run this cmdlet. + +5) Gateway Server - Run the following Powershell Script to Set the Database Connection + + ### Set-KeyfactorGatewayDatabaseConnection + This cmdlet will set and encrypt the database connection string used by the AnyGateway service. + + **Windows Authentication** + ```ps + Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] + ``` + + **SQL Authentication** + ```ps + $KeyfactorCredentials = Get-Credentials + Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] -Account [$KeyfactorCredentials] + ``` +## Standard Gateway Configuration Finished +--- + + +## SSLStore AnyGateway Specific Configuration +It is important to note that importing the SSLStore configuration into the CA Gateway prior to installing the binaries must be completed. Additionally, the CA Gateway service +must be running in order to succesfully import the configuation. When the CA Gateway service starts it will attempt to validate the connection information to +the CA. Without the imported configuration, the service will fail to start. + +### Binary Installation + +1) Get the Latest Zip File from [Here](https://github.com/Keyfactor/quovadis-cagateway/releases) +2) Gateway Server - Copy the SSLStoreCaProxy.dll to the location where the Gateway Framework was installed (usually C:\Program Files\Keyfactor\Keyfactor AnyGateway) + +### Configuration Changes +1) Gateway Server - Edit the CAProxyServer.exe.config file and replace the line that says "NoOp" with the line below: + ``` + + ``` +2) Gateway Server - Install the Intermediate Comodo Certificate that was received from SSLStore + +3) Gateway Server - Take the sample Config.json located [Here](https://github.com/Keyfactor/quovadis-cagateway/raw/main/SampleConfig.json) and make the following modifications + +- *Security Settings Modifications* (Swap this out for the typical Gateway Security Settings for Test or Prod) + +``` + "Security": { + "KEYFACTOR\\administrator": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + }, + "KEYFACTOR\\SVC_AppPool": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + }, + "KEYFACTOR\\SVC_TimerService": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + } +``` +- *SSLStore Environment Settings* (Modify these with the keys and Urls obtained from SSLStore) +``` + "CAConnection": { + "SSLStoreURL": "https://sandbox-wbapi.thesslstore.com", + "PartnerCode": "SomePartnerCodeFromSSLStore", + "AuthToken": "SomeAuthTokenFromSSLStore", + "KeyfactorApiUrl": "https://kftrain.keyfactor.lab/KeyfactorAPI", + "KeyfactorApiUserId": "SomeKeyfactorAPIUser", + "KeyfactorApiPassword": "SomeKeyfactorAPIPassword", + "PageSize": "25", + "SampleRequest": { + "AuthRequest": { + "PartnerCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + }, + "AuthToken": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + } + }, + "ProductCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + }, + "TSSOrganizationId": { + "FieldData": { + "RequiredForProducts": [ + "None" + ], + "EnrollmentFieldMapping": "Organization ID" + } + }, + "OrganizationInfo": { + "OrganizationName": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization Name" + } + }, + "RegistrationNumber": { + "FieldData": { + "RequiredForProducts": [ + "certum" + ], + "EnrollmentFieldMapping": "Organization Registration Number" + } + }, + "JurisdictionCountry": { + "FieldData": { + "RequiredForProducts": [ + "comodoevssl", + "comodoevcsc", + "comodoevmdc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "positiveevssl" + ], + "EnrollmentFieldMapping": "Organization Jurisdiction Country" + } + }, + "OrganizationAddress": { + "AddressLine1": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization Address" + } + }, + "Region": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization State/Province" + } + }, + "PostalCode": { + "FieldData": { + "RequiredForProducts": [ + "digi_plus_ssl", + "digi_wc_ssl", + "digi_md_ssl", + "digi_securesite_md", + "digi_csc", + "digi_securesite", + "digi_securesite_pro", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_csc_ev", + "digi_ev_md_ssl", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_securesite_pro_ev_flex", + "digi_ssl_basic", + "digi_securesite_flex", + "digi_plus_ev_ssl", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_truebizid_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex", + "digi_sslwebserver_ev_flex", + "truebizid", + "truebusinessidev", + "truebusinessidevmd", + "truebusinessidwildcard", + "truebizidmdwc", + "truebizidmd", + "malwarescan", + "sslwebserverwildcard", + "thawtecsc", + "sslwebserver", + "sslwebserverev", + "sectigocsc", + "sectigoevssl", + "sectigoevcsc", + "sectigoevmdc", + "sectigoovssl", + "sectigomdc", + "sectigomdcwildcard", + "sectigoovwildcard", + "comodocsc", + "positiveevssl", + "comodoevssl", + "comodoevcsc", + "enterpriseproev", + "enterpriseproevmdc", + "positiveevmdc", + "comodoevmdc", + "comodomdc", + "instantssl", + "instantsslpro", + "comodopremiumssl", + "comodomdcwildcard", + "comodopremiumwildcard", + "comodouccwildcard", + "comodoucc", + "elitessl", + "comodopciscan", + "enterprisessl", + "enterprisepro", + "enterpriseprowc", + "pacenterprise", + "hackerprooftm", + "hgpcicontrolscan" + ], + "EnrollmentFieldMapping": "Organization Postal Code" + } + }, + "LocalityName": { + "FieldData": { + "RequiredForProducts": [ + "comodocsc", + "comodoevssl", + "comodoevcsc", + "comodoevmdc", + "comodomdc", + "comodomdcwildcard", + "comodouccwildcard", + "comodoucc", + "pacenterprise" + ], + "EnrollmentFieldMapping": "Organization Locality Name" + } + }, + "Country": { + "FieldData": { + "RequiredForProducts": [ + "truebizidmd", + "digi_ev_md_ssl", + "digi_md_ssl", + "digi_plus_ev_ssl", + "digi_plus_ssl", + "digi_securesite", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_ssl_basic", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev_flex", + "digi_securesite_flex", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex" + ], + "EnrollmentFieldMapping": "Organization Country" + } + }, + "Phone": { + "FieldData": { + "RequiredForProducts": [ + "truebizidmd", + "digi_ev_md_ssl", + "digi_md_ssl", + "digi_plus_ev_ssl", + "digi_plus_ssl", + "digi_securesite", + "digi_securesite_wc", + "digi_securesite_pro_ev", + "digi_securesite_ev_md", + "digi_securesite_ev", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_flex", + "digi_ssl_basic", + "digi_sslwebserver_ev_flex", + "digi_truebizid_ev_flex", + "digi_securesite_flex", + "digi_truebizid_ev", + "digi_truebizid", + "digi_truebizid_ev_md", + "digi_truebizid_wc", + "digi_truebizid_md", + "digi_truebizid_md_wc", + "digi_sslwebserver_ev", + "digi_sslwebserver", + "digi_sslwebserver_wc", + "digi_sslwebserver_md_wc", + "digi_sslwebserver_flex" + ], + "EnrollmentFieldMapping": "Organization Phone" + } + } + } + }, + "ValidityPeriod": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Validity Period (In Months)" + } + }, + "ServerCount": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Server Count" + } + }, + "CSR": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "None" + } + }, + "DomainName": { + "FieldData": { + "RequiredForProducts": [ + "Certum" + ], + "EnrollmentFieldMapping": "Domain Name" + } + }, + "WebServerType": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Web Server Type" + } + }, + "DNSNames": { + "FieldData": { + "RequiredForProducts": [ + "digi_ssl_ev_basic", + "digi_ssl_ev_basic-EO", + "digi_securesite_ev_flex", + "digi_securesite_ev_flex-EO", + "digi_securesite_pro_ev_flex", + "digi_securesite_pro_ev_flex-EO", + "digi_securesite_pro_flex", + "digi_securesite_pro_flex-EO", + "digi_ssl_basic", + "digi_ssl_basic-EO", + "digi_securesite_flex", + "digi_securesite_flex-EO", + "digi_truebizid_flex", + "digi_truebizid_flex-EO", + "digi_truebizid_ev_flex", + "digi_truebizid_ev_flex-EO", + "digi_ssl_dv_geotrust_flex", + "digi_rapidssl", + "digi_rapidssl_wc", + "digi_ssl123_flex", + "digi_sslwebserver_flex", + "digi_sslwebserver_flex-EO", + "digi_sslwebserver_ev_flex", + "digi_sslwebserver_ev_flex-EO", + "positivemdcssl", + "positivemdcwildcard", + "sectigodvucc", + "sectigouccwildcard", + "sectigoevmdc", + "sectigomdcwildcard", + "sectigomdc" + ], + "EnrollmentFieldMapping": "DNS Names Comma Separated", + "Array": true + } + }, + "isCUOrder": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Is CU Order?" + } + }, + "isRenewalOrder": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Is Renewal Order?" + } + }, + "isTrialOrder": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Is Trial Order?" + } + }, + "AdminContact": { + "FirstName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - First Name" + } + }, + "LastName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Last Name" + } + }, + "Phone": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Phone" + } + }, + "Email": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Email" + } + }, + "Title": { + "FieldData": { + "RequiredForProducts": [ + "symantec", + "digi_ssl_ev_basic", + "digi_sslwebserver_ev_flex", + "digi_truebizid_ev_flex", + "digi_securesite_pro_ev_flex", + "digi_securesite_ev_flex" + ], + "EnrollmentFieldMapping": "Admin Contact - Title" + } + }, + "OrganizationName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Organization Name" + } + }, + "AddressLine1": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Address" + } + }, + "City": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - City" + } + }, + "Region": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Region" + } + }, + "PostalCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Postal Code" + } + }, + "Country": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Admin Contact - Country" + } + } + }, + "TechnicalContact": { + "FirstName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - First Name" + } + }, + "LastName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Last Name" + } + }, + "SubjectFirstName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Subject First Name" + } + }, + "SubjectLastName": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Subject Last Name" + } + }, + "Phone": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Phone" + } + }, + "Email": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Email" + } + }, + "Title": { + "FieldData": { + "RequiredForProducts": [ + "symantec", + "digi_ssl_ev_basic", + "digi_securesite_ev_flex", + "digi_truebizid_ev_flex", + "digi_sslwebserver_ev_flex" + ], + "EnrollmentFieldMapping": "Technical Contact - Title" + } + }, + "AddressLine1": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Address" + } + }, + "City": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - City" + } + }, + "Region": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Region" + } + }, + "PostalCode": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Postal Code" + } + }, + "Country": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Technical Contact - Country" + } + } + }, + "AutoWWW": { + "FieldData": { + "RequiredForProducts": [ + "positivessl" + ], + "EnrollmentFieldMapping": "AutoWWW" + } + }, + "ApproverEmail": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Approver Email" + } + }, + "FileAuthDVIndicator": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "File Auth Domain Validation" + } + }, + "CNAMEAuthDVIndicator": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "CName Auth Domain Validation" + } + }, + "SignatureHashAlgorithm": { + "FieldData": { + "RequiredForProducts": [ + "All" + ], + "EnrollmentFieldMapping": "Signature Hash Algorithm" + } + } + } + } +``` + +- *Template Settings - See Configuration Instructional Video on how these work* +``` + "Templates": { + "positivessl": { + "ProductID": "positivessl", + "Parameters": { + "AutoWWW": "True" + } + }, + "positiveevssl": { + "ProductID": "positiveevssl", + "Parameters": {} + }, + "enterpriseproev": { + "ProductID": "enterpriseproev", + "Parameters": {} + }, + "enterpriseproevmdc": { + "ProductID": "enterpriseproevmdc", + "Parameters": {} + }, + "positivesslwildcard": { + "ProductID": "positivesslwildcard", + "Parameters": {} + }, + "positivemdcssl": { + "ProductID": "positivemdcssl", + "Parameters": {} + }, + "positivemdcwildcard": { + "ProductID": "positivemdcwildcard", + "Parameters": {} + }, + "positiveevmdc": { + "ProductID": "positiveevmdc", + "Parameters": {} + }, + "instantssl": { + "ProductID": "instantssl", + "Parameters": {} + }, + "instantsslpro": { + "ProductID": "instantsslpro", + "Parameters": {} + }, + "comodopremiumssl": { + "ProductID": "comodopremiumssl", + "Parameters": {} + }, + "comodopremiumwildcard": { + "ProductID": "comodopremiumwildcard", + "Parameters": {} + }, + "enterprisepro": { + "ProductID": "enterprisepro", + "Parameters": {} + }, + "enterpriseprowc": { + "ProductID": "enterpriseprowc", + "Parameters": {} + }, + "sectigossl": { + "ProductID": "sectigossl", + "Parameters": {} + }, + "sectigodvucc": { + "ProductID": "sectigodvucc", + "Parameters": {} + }, + "sectigoevssl": { + "ProductID": "sectigoevssl", + "Parameters": {} + }, + "sectigoevmdc": { + "ProductID": "sectigoevmdc", + "Parameters": {} + }, + "sectigoovssl": { + "ProductID": "sectigoovssl", + "Parameters": {} + }, + "sectigomdc": { + "ProductID": "sectigomdc", + "Parameters": {} + }, + "sectigomdcwildcard": { + "ProductID": "sectigomdcwildcard", + "Parameters": {} + }, + "sectigoovwildcard": { + "ProductID": "sectigoovwildcard", + "Parameters": {} + }, + "sectigowildcard": { + "ProductID": "sectigowildcard", + "Parameters": {} + }, + "sectigouccwildcard": { + "ProductID": "sectigouccwildcard", + "Parameters": {} + }, + "digi_ssl_ev_basic": { + "ProductID": "digi_ssl_ev_basic", + "Parameters": {} + }, + "digi_ssl_ev_basic-EO": { + "ProductID": "digi_ssl_ev_basic-EO", + "Parameters": {} + }, + "digi_securesite_ev_flex": { + "ProductID": "digi_securesite_ev_flex", + "Parameters": {} + }, + "digi_securesite_ev_flex-EO": { + "ProductID": "digi_securesite_ev_flex-EO", + "Parameters": {} + }, + "digi_securesite_pro_ev_flex": { + "ProductID": "digi_securesite_pro_ev_flex", + "Parameters": {} + }, + "digi_securesite_pro_ev_flex-EO": { + "ProductID": "digi_securesite_pro_ev_flex-EO", + "Parameters": {} + }, + "digi_securesite_pro_flex": { + "ProductID": "digi_securesite_pro_flex", + "Parameters": {} + }, + "digi_securesite_pro_flex-EO": { + "ProductID": "digi_securesite_pro_flex-EO", + "Parameters": {} + }, + "digi_ssl_basic": { + "ProductID": "digi_ssl_basic", + "Parameters": {} + }, + "digi_ssl_basic-EO": { + "ProductID": "digi_ssl_basic-EO", + "Parameters": {} + }, + "digi_securesite_flex": { + "ProductID": "digi_securesite_flex", + "Parameters": {} + }, + "digi_securesite_flex-EO": { + "ProductID": "digi_securesite_flex-EO", + "Parameters": {} + }, + "digi_truebizid_flex": { + "ProductID": "digi_truebizid_flex", + "Parameters": {} + }, + "digi_truebizid_flex-EO": { + "ProductID": "digi_truebizid_flex-EO", + "Parameters": {} + }, + "digi_truebizid_ev_flex": { + "ProductID": "digi_truebizid_ev_flex", + "Parameters": {} + }, + "digi_truebizid_ev_flex-EO": { + "ProductID": "digi_truebizid_ev_flex-EO", + "Parameters": {} + }, + "digi_ssl_dv_geotrust_flex": { + "ProductID": "digi_ssl_dv_geotrust_flex", + "Parameters": {} + }, + "digi_rapidssl": { + "ProductID": "digi_rapidssl", + "Parameters": {} + }, + "digi_rapidssl_wc": { + "ProductID": "digi_rapidssl_wc", + "Parameters": {} + }, + "digi_ssl123_flex": { + "ProductID": "digi_ssl123_flex", + "Parameters": {} + }, + "digi_sslwebserver_flex": { + "ProductID": "digi_sslwebserver_flex", + "Parameters": {} + }, + "digi_sslwebserver_flex-EO": { + "ProductID": "digi_sslwebserver_flex-EO", + "Parameters": {} + }, + "digi_sslwebserver_ev_flex": { + "ProductID": "digi_sslwebserver_ev_flex", + "Parameters": {} + }, + "digi_sslwebserver_ev_flex-EO": { + "ProductID": "digi_sslwebserver_ev_flex-EO", + "Parameters": {} + } + } +``` + +- *Gateway Settings* +``` + "CertificateManagers": null, + "GatewayRegistration": { + "LogicalName": "SSLStore", + "GatewayCertificate": { + "StoreName": "CA", + "StoreLocation": "LocalMachine", + "Thumbprint": "339cdd57cfd5b141169b615ff31428782d1da639" + } + } +``` + +- *Service Settings* (Modify these to be in accordance with Keyfactor Standard Gateway Production Settings) +``` + "ServiceSettings": { + "ViewIdleMinutes": 1, + "FullScanPeriodHours": 1, + "PartialScanPeriodMinutes": 1 + } +``` + +5) Gateway Server - Save the newly modified config.json to the following location "C:\Program Files\Keyfactor\Keyfactor AnyGateway" + +### Template Installation + +1) Command Server - Copy and Unzip the Template Setup Files located [Here](https://github.com/Keyfactor/sslstore-cagateway/raw/main/TemplateSetup.zip) +2) Command Server - Change the Security Settings in the CaTemplateUserSecurity.csv file to the appropriate settings for Test or Production +3) Command Server - Run the CreateTemplate.ps1 file and choose option 1 to create the templates in active directory. + *Note if you get errors the security is likely wrong and you will have to add the security manually according to Keyfactor standards* +4) Command Server - Use the Keyfactor Portal to Import the Templates created in Active Directory in step #3 above +5) Command Server - Run the CreateTemplate.ps1 file and choose option 3 to create all the enrollment fields. + *Note You will have to override the default API Questions to the appropriate information.* + +### Certificate Authority Installation +1) Gateway Server - Start the Keyfactor Gateway Service +2) Run the set Gateway command similar to below +```ps +Set-KeyfactorGatewayConfig -LogicalName "SSLStore" -FilePath [path to json file] -PublishAd +``` +3) Command Server - Import the certificate authority in Keyfactor Portal + +### Release 1.1 Notes +Look over the AutoWWW field in both the Sample Config and readme. If you want to include it for a template see the positivessl sample in the readme. It is also needed as a new field in the SampleRequest Section of the file as shown in the readme. + +*** + +### License +[Apache](https://apache.org/licenses/LICENSE-2.0) From 61f111ae6e925a961040fe296bba89b26e2a5f56 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 17 Mar 2026 11:41:59 -0400 Subject: [PATCH 02/42] added in Template Params --- SslStoreCaProxy/SslStoreCAPluginConfig.cs | 294 ++++++++++++++++++++++ 1 file changed, 294 insertions(+) diff --git a/SslStoreCaProxy/SslStoreCAPluginConfig.cs b/SslStoreCaProxy/SslStoreCAPluginConfig.cs index 091f78b..faeffb8 100644 --- a/SslStoreCaProxy/SslStoreCAPluginConfig.cs +++ b/SslStoreCaProxy/SslStoreCAPluginConfig.cs @@ -71,6 +71,300 @@ public static Dictionary GetTemplateParameterAnnotat { return new Dictionary() { + ["DNS Names Comma Separated"] = new PropertyConfigInfo() + { + Comments = "Comma-separated list of DNS names (SANs) for the certificate.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Approver Email"] = new PropertyConfigInfo() + { + Comments = "Comma-separated approver email address(es) for domain validation.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Validity Period (In Months)"] = new PropertyConfigInfo() + { + Comments = "Certificate validity period in months (e.g. 12, 24, 36, 48, 60, 72).", + Hidden = false, + DefaultValue = "12", + Type = "String" + }, + ["Admin Contact - First Name"] = new PropertyConfigInfo() + { + Comments = "Administrative contact first name.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Admin Contact - Last Name"] = new PropertyConfigInfo() + { + Comments = "Administrative contact last name.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Admin Contact - Phone"] = new PropertyConfigInfo() + { + Comments = "Administrative contact phone number.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Admin Contact - Email"] = new PropertyConfigInfo() + { + Comments = "Administrative contact email address.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Admin Contact - Title"] = new PropertyConfigInfo() + { + Comments = "Administrative contact job title.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Admin Contact - Organization Name"] = new PropertyConfigInfo() + { + Comments = "Administrative contact organization name.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Admin Contact - Address"] = new PropertyConfigInfo() + { + Comments = "Administrative contact street address.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Admin Contact - City"] = new PropertyConfigInfo() + { + Comments = "Administrative contact city.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Admin Contact - Region"] = new PropertyConfigInfo() + { + Comments = "Administrative contact state/province/region.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Admin Contact - Postal Code"] = new PropertyConfigInfo() + { + Comments = "Administrative contact postal/zip code.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Admin Contact - Country"] = new PropertyConfigInfo() + { + Comments = "Administrative contact two-letter country code (e.g. US).", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Technical Contact - First Name"] = new PropertyConfigInfo() + { + Comments = "Technical contact first name.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Technical Contact - Last Name"] = new PropertyConfigInfo() + { + Comments = "Technical contact last name.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Technical Contact - Phone"] = new PropertyConfigInfo() + { + Comments = "Technical contact phone number.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Technical Contact - Email"] = new PropertyConfigInfo() + { + Comments = "Technical contact email address.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Technical Contact - Organization Name"] = new PropertyConfigInfo() + { + Comments = "Technical contact organization name.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Technical Contact - Address"] = new PropertyConfigInfo() + { + Comments = "Technical contact street address.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Technical Contact - City"] = new PropertyConfigInfo() + { + Comments = "Technical contact city.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Technical Contact - Region"] = new PropertyConfigInfo() + { + Comments = "Technical contact state/province/region.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Technical Contact - Postal Code"] = new PropertyConfigInfo() + { + Comments = "Technical contact postal/zip code.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Technical Contact - Country"] = new PropertyConfigInfo() + { + Comments = "Technical contact two-letter country code (e.g. US).", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Organization Name"] = new PropertyConfigInfo() + { + Comments = "Organization name for the certificate.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Organization Address"] = new PropertyConfigInfo() + { + Comments = "Organization street address.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Organization City"] = new PropertyConfigInfo() + { + Comments = "Organization city.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Organization Region"] = new PropertyConfigInfo() + { + Comments = "Organization state/province/region.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Organization State/Province"] = new PropertyConfigInfo() + { + Comments = "Organization state or province.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Organization Postal Code"] = new PropertyConfigInfo() + { + Comments = "Organization postal/zip code.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Organization Country"] = new PropertyConfigInfo() + { + Comments = "Organization two-letter country code (e.g. US).", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Organization Phone"] = new PropertyConfigInfo() + { + Comments = "Organization phone number.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Organization Jurisdiction Country"] = new PropertyConfigInfo() + { + Comments = "Jurisdiction country code for EV certificates.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Organization ID"] = new PropertyConfigInfo() + { + Comments = "DigiCert organization ID for EO (Enterprise Organization) products.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + ["Server Count"] = new PropertyConfigInfo() + { + Comments = "Number of server licenses for the certificate.", + Hidden = false, + DefaultValue = "1", + Type = "String" + }, + ["Web Server Type"] = new PropertyConfigInfo() + { + Comments = "Web server type (e.g. apacheopenssl, iis, tomcat, Other).", + Hidden = false, + DefaultValue = "Other", + Type = "String" + }, + ["Signature Hash Algorithm"] = new PropertyConfigInfo() + { + Comments = "Signature hash algorithm (PREFER_SHA2, REQUIRE_SHA2, PREFER_SHA1).", + Hidden = false, + DefaultValue = "PREFER_SHA2", + Type = "String" + }, + ["File Auth Domain Validation"] = new PropertyConfigInfo() + { + Comments = "Use file-based domain validation (True/False).", + Hidden = false, + DefaultValue = "False", + Type = "String" + }, + ["CName Auth Domain Validation"] = new PropertyConfigInfo() + { + Comments = "Use CNAME-based domain validation (True/False).", + Hidden = false, + DefaultValue = "False", + Type = "String" + }, + ["Is CU Order?"] = new PropertyConfigInfo() + { + Comments = "Is this a CU (Customer) order (True/False).", + Hidden = false, + DefaultValue = "False", + Type = "String" + }, + ["Is Renewal Order?"] = new PropertyConfigInfo() + { + Comments = "Is this a renewal order (True/False).", + Hidden = false, + DefaultValue = "False", + Type = "String" + }, + ["Is Trial Order?"] = new PropertyConfigInfo() + { + Comments = "Is this a trial order (True/False).", + Hidden = false, + DefaultValue = "False", + Type = "String" + } }; } } From 7dd14d8d7689de1312dbdc6a9741c2051708bfb6 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 17 Mar 2026 12:32:02 -0400 Subject: [PATCH 03/42] added config changes --- .claude/settings.local.json | 11 ++++++++++- .gitignore | 1 + SslStoreCaProxy/SslStoreCaProxy.cs | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 73a0c9f..591f74f 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -13,7 +13,16 @@ "Bash(dotnet build:*)", "Bash(ls c:/Users/bhill/source/repos/sslstore-cagateway/*.json)", "Bash(node -e \":*)", - "Bash(xargs grep:*)" + "Bash(xargs grep:*)", + "Bash(dotnet tool:*)", + "Bash(powershell -Command \"[System.Reflection.Assembly]::LoadFrom\\(''C:\\\\Users\\\\bhill\\\\.nuget\\\\packages\\\\keyfactor.anygateway.ianycaplugin\\\\3.0.0\\\\lib\\\\net6.0\\\\Keyfactor.AnyGateway.IAnyCAPlugin.dll''\\).GetTypes\\(\\) | ForEach-Object { Write-Host $_.FullName; $_.GetMethods\\(\\) | ForEach-Object { Write-Host '' '' $_.Name ''\\('' \\($_.GetParameters\\(\\) | ForEach-Object { $_.ParameterType.Name + '' '' + $_.Name }\\) ''\\)'' } }\")", + "Bash(powershell -Command \"try { $asm = [System.Reflection.Assembly]::LoadFrom\\(''C:\\\\Users\\\\bhill\\\\.nuget\\\\packages\\\\keyfactor.anygateway.ianycaplugin\\\\3.0.0\\\\lib\\\\net6.0\\\\Keyfactor.AnyGateway.IAnyCAPlugin.dll''\\); $asm.GetTypes\\(\\) } catch [System.Reflection.ReflectionTypeLoadException] { $_.Exception.Types | Where-Object { $_ -ne $null } | ForEach-Object { Write-Host $_.FullName; $_.GetMethods\\(\\) | ForEach-Object { Write-Host '' '' $_.Name ''\\('' \\($_.GetParameters\\(\\) | ForEach-Object { $_.ParameterType.ToString\\(\\) + '' '' + $_.Name }\\) ''\\)'' } } }\")", + "Bash(powershell -Command \"try { $asm = [System.Reflection.Assembly]::LoadFrom\\(''C:\\\\Users\\\\bhill\\\\.nuget\\\\packages\\\\keyfactor.anygateway.ianycaplugin\\\\3.0.0\\\\lib\\\\net6.0\\\\Keyfactor.AnyGateway.IAnyCAPlugin.dll''\\); $asm.GetTypes\\(\\) } catch [System.Reflection.ReflectionTypeLoadException] { $_.Exception.Types | Where-Object { $_ -ne $null } | ForEach-Object { Write-Host $_.FullName; try { $_.GetMethods\\(\\) | ForEach-Object { Write-Host \\('' '' + $_.Name\\) } } catch { Write-Host '' \\(methods not loadable\\)'' } } }\")", + "Bash(xxd /c/Users/bhill/.nuget/packages/keyfactor.anygateway.ianycaplugin/3.0.0/lib/net6.0/Keyfactor.AnyGateway.IAnyCAPlugin.dll)", + "Bash(dotnet ildasm:*)", + "Bash(dotnet-ildasm /c/Users/bhill/.nuget/packages/keyfactor.anygateway.ianycaplugin/3.0.0/lib/net6.0/Keyfactor.AnyGateway.IAnyCAPlugin.dll)", + "Bash(python -c \":*)", + "Bash(powershell -Command \"$bytes = [System.IO.File]::ReadAllBytes\\(''C:\\\\Users\\\\bhill\\\\.nuget\\\\packages\\\\keyfactor.anygateway.ianycaplugin\\\\3.0.0\\\\lib\\\\net6.0\\\\Keyfactor.AnyGateway.IAnyCAPlugin.dll''\\); $text = [System.Text.Encoding]::ASCII.GetString\\($bytes\\); $matches = [regex]::Matches\\($text, ''[A-Za-z_][A-Za-z0-9_]{5,}''\\); $matches.Value | Sort-Object -Unique | Where-Object { $_ -match ''emplate|nroll|roduct|nnot|onfig|lugin|arameter|ingle|ync|evoke|ing$|alidat|nitializ|GetCA|IAny'' }\")" ] } } diff --git a/.gitignore b/.gitignore index ce89292..adbb137 100644 --- a/.gitignore +++ b/.gitignore @@ -416,3 +416,4 @@ FodyWeavers.xsd *.msix *.msm *.msp +.claude/settings.local.json diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs index 10fdb32..2bf69a8 100644 --- a/SslStoreCaProxy/SslStoreCaProxy.cs +++ b/SslStoreCaProxy/SslStoreCaProxy.cs @@ -91,6 +91,7 @@ public Task ValidateCAConnectionInfo(Dictionary connectionInfo) throw new ArgumentException($"The following required fields are missing or empty: {string.Join(", ", missingFields)}"); } + _config = config; _logger.MethodExit(); return Ping(); } From 73e845646f236eb5d878b29ad516a069776be7be Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 17 Mar 2026 13:44:27 -0400 Subject: [PATCH 04/42] fixed await --- SslStoreCaProxy/SslStoreCaProxy.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs index 2bf69a8..901d750 100644 --- a/SslStoreCaProxy/SslStoreCaProxy.cs +++ b/SslStoreCaProxy/SslStoreCaProxy.cs @@ -187,7 +187,7 @@ public async Task Enroll(string csr, string subject, Dictionar var emailApproverRequest = _requestManager.GetEmailApproverListRequest(productInfo.ProductID, product); _logger.LogTrace($"Email Approver Request JSON {JsonConvert.SerializeObject(emailApproverRequest)}"); - var emailApproverResponse = client.SubmitEmailApproverRequestAsync(emailApproverRequest); + var emailApproverResponse = await client.SubmitEmailApproverRequestAsync(emailApproverRequest); _logger.LogTrace($"Email Approver Response JSON {JsonConvert.SerializeObject(emailApproverResponse)}"); var emailValidation = ValidateEmails(emailApproverResponse, arrayApproverEmails, productInfo, count); @@ -376,7 +376,7 @@ public async Task Synchronize(BlockingCollection blockin _logger.MethodExit(); } - private string ValidateEmails(Task validEmails, string[] arrayApproverEmails, EnrollmentProductInfo productInfo, int count) + private string ValidateEmails(EmailApproverResponse validEmails, string[] arrayApproverEmails, EnrollmentProductInfo productInfo, int count) { if (arrayApproverEmails.Length > 1 && productInfo.ProductID.Contains("digi")) { @@ -385,17 +385,17 @@ private string ValidateEmails(Task validEmails, string[] if (count == 1 && productInfo.ProductID.Contains("digi") && arrayApproverEmails.Length > 0) { - if (!validEmails.Result.ApproverEmailList.Contains(arrayApproverEmails[0])) + if (!validEmails.ApproverEmailList.Contains(arrayApproverEmails[0])) { - return $"Digicert Approver Email must be one of the following {string.Join(",", validEmails.Result.ApproverEmailList)}"; + return $"Digicert Approver Email must be one of the following {string.Join(",", validEmails.ApproverEmailList)}"; } } if (!productInfo.ProductID.Contains("digi")) { - if (!validEmails.Result.ApproverEmailList.Intersect(arrayApproverEmails).Any()) + if (!validEmails.ApproverEmailList.Intersect(arrayApproverEmails).Any()) { - return $"Sectigo Approver Email must be one of the following {string.Join(",", validEmails.Result.ApproverEmailList)}"; + return $"Sectigo Approver Email must be one of the following {string.Join(",", validEmails.ApproverEmailList)}"; } } From f55be6f3ecf67f35785af36b75d7b82d0ff57a7b Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 17 Mar 2026 14:10:53 -0400 Subject: [PATCH 05/42] fixed field issues --- SslStoreCaProxy/Interfaces/IRequestManager.cs | 5 +- SslStoreCaProxy/ProductDefinitions.cs | 46 +++++++++---------- SslStoreCaProxy/RequestManager.cs | 39 +++++++++++++--- SslStoreCaProxy/SslStoreCAPluginConfig.cs | 13 ++---- SslStoreCaProxy/SslStoreCaProxy.cs | 29 ++++++++---- 5 files changed, 80 insertions(+), 52 deletions(-) diff --git a/SslStoreCaProxy/Interfaces/IRequestManager.cs b/SslStoreCaProxy/Interfaces/IRequestManager.cs index 5ca1fb4..a4bb581 100644 --- a/SslStoreCaProxy/Interfaces/IRequestManager.cs +++ b/SslStoreCaProxy/Interfaces/IRequestManager.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Keyfactor.AnyGateway.Extensions; using Keyfactor.AnyGateway.SslStore.Client.Models; @@ -5,8 +6,8 @@ namespace Keyfactor.AnyGateway.SslStore.Interfaces { public interface IRequestManager { - NewOrderRequest GetEnrollmentRequest(string csr, EnrollmentProductInfo productInfo, - IAnyCAPluginConfigProvider configProvider, bool isRenewalOrder); + NewOrderRequest GetEnrollmentRequest(string csr, string subject, Dictionary san, + EnrollmentProductInfo productInfo, IAnyCAPluginConfigProvider configProvider, bool isRenewalOrder); AuthRequest GetAuthRequest(); ReIssueRequest GetReIssueRequest(INewOrderResponse orderData, string csr, bool isRenewal); diff --git a/SslStoreCaProxy/ProductDefinitions.cs b/SslStoreCaProxy/ProductDefinitions.cs index f4152b5..331fbd3 100644 --- a/SslStoreCaProxy/ProductDefinitions.cs +++ b/SslStoreCaProxy/ProductDefinitions.cs @@ -102,7 +102,7 @@ private static List LegacyFullFields(List validity) DropdownField("Signature Hash Algorithm", SignatureHashAlgorithms), DropdownField("Web Server Type", WebServerTypes), TextField("Server Count"), - DropdownField("Validity Period (In Months)", validity), + TextField("Validity Period (In Days)"), TextField("Organization Name"), TextField("Organization Address"), TextField("Organization Region"), @@ -115,7 +115,7 @@ private static List LegacyFullFields(List validity) // Group 1b: Legacy Full + DNS Names + Jurisdiction (38 fields) - digi_quickssl_md private static List LegacyFullDnsJurisdictionFields(List validity) { - var fields = new List { TextField("DNS Names Comma Separated") }; + var fields = new List(); fields.AddRange(LegacyFullFields(validity)); // Insert Jurisdiction Country before Organization Phone (at the end) fields.Insert(fields.Count - 1, DropdownField("Organization Jurisdiction Country", CountryCodes)); @@ -127,8 +127,8 @@ private static List EoMinimalFields() { return new List { - TextField("DNS Names Comma Separated"), - DropdownField("Validity Period (In Months)", ValidityDigicert), + + TextField("Validity Period (In Days)"), DropdownField("Organization ID", new List()) }; } @@ -140,7 +140,7 @@ private static List SectigoOvFields() { TextField("Admin Contact - Email"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Validity Period (In Days)"), TextField("Organization Name"), TextField("Organization Address"), TextField("Organization State/Province"), @@ -155,13 +155,13 @@ private static List DigiCertOvFlexFields() { return new List { - TextField("DNS Names Comma Separated"), + TextField("Admin Contact - First Name"), TextField("Admin Contact - Last Name"), TextField("Admin Contact - Phone"), TextField("Admin Contact - Email"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityDigicert), + TextField("Validity Period (In Days)"), TextField("Organization Name"), TextField("Organization Address"), TextField("Organization City"), @@ -179,7 +179,7 @@ private static List DvMinimalFields() { TextField("Admin Contact - Email"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityStandard) + TextField("Validity Period (In Days)") }; } @@ -188,14 +188,14 @@ private static List DigiCertEvFlexFields(string regionFieldName { return new List { - TextField("DNS Names Comma Separated"), + TextField("Admin Contact - First Name"), TextField("Admin Contact - Last Name"), TextField("Admin Contact - Phone"), TextField("Admin Contact - Email"), TextField("Admin Contact - Title"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityDigicert), + TextField("Validity Period (In Days)"), TextField("Organization Name"), TextField("Organization Address"), TextField("Organization City"), @@ -211,10 +211,10 @@ private static List DvMdcFields() { return new List { - TextField("DNS Names Comma Separated"), + TextField("Admin Contact - Email"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityStandard) + TextField("Validity Period (In Days)") }; } @@ -225,7 +225,7 @@ private static List DigiCertDvRapidSslFields() { TextField("Technical Contact - Email"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityDigicert) + TextField("Validity Period (In Days)") }; } @@ -234,10 +234,10 @@ private static List DigiCertDvGeoTrustFields() { return new List { - TextField("DNS Names Comma Separated"), + TextField("Technical Contact - Email"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityDigicert) + TextField("Validity Period (In Days)") }; } @@ -248,7 +248,7 @@ private static List EvJurisdictionFields() { TextField("Admin Contact - Email"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Validity Period (In Days)"), TextField("Organization Name"), TextField("Organization Address"), TextField("Organization State/Province"), @@ -264,10 +264,10 @@ private static List EvMdcJurisdictionFields() { return new List { - TextField("DNS Names Comma Separated"), + TextField("Admin Contact - Email"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Validity Period (In Days)"), TextField("Organization Name"), TextField("Organization Address"), TextField("Organization State/Province"), @@ -283,10 +283,10 @@ private static List EvMdcJurisdictionAltFields() { return new List { - TextField("DNS Names Comma Separated"), + TextField("Admin Contact - Email"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Validity Period (In Days)"), TextField("Organization Name"), TextField("Organization Address"), TextField("Organization State/Province"), @@ -302,10 +302,10 @@ private static List OvMdcFields() { return new List { - TextField("DNS Names Comma Separated"), + TextField("Admin Contact - Email"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Validity Period (In Days)"), TextField("Organization Name"), TextField("Organization Address"), TextField("Organization State/Province"), @@ -322,7 +322,7 @@ private static List EnterpriseProOvFields() { TextField("Admin Contact - First Name"), TextField("Approver Email"), - DropdownField("Validity Period (In Months)", ValidityStandard), + TextField("Validity Period (In Days)"), TextField("Organization Name"), TextField("Organization Address"), TextField("Organization State/Province"), diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index b81b013..be51f6d 100644 --- a/SslStoreCaProxy/RequestManager.cs +++ b/SslStoreCaProxy/RequestManager.cs @@ -28,8 +28,8 @@ public RequestManager(SslStoreCaProxy sslStoreCaProxy) _sslStoreCaProxy = sslStoreCaProxy; } - public NewOrderRequest GetEnrollmentRequest(string csr, EnrollmentProductInfo productInfo, - IAnyCAPluginConfigProvider configProvider, bool isRenewalOrder) + public NewOrderRequest GetEnrollmentRequest(string csr, string subject, Dictionary san, + EnrollmentProductInfo productInfo, IAnyCAPluginConfigProvider configProvider, bool isRenewalOrder) { var pemCsr = ConvertCsrToPem(csr); @@ -41,7 +41,7 @@ public NewOrderRequest GetEnrollmentRequest(string csr, EnrollmentProductInfo pr MissingMemberHandling = MissingMemberHandling.Ignore }; var request = BuildNewOrderRequest(productInfo, - JsonConvert.DeserializeObject(sampleRequest, settings), pemCsr, isRenewalOrder); + JsonConvert.DeserializeObject(sampleRequest, settings), pemCsr, subject, san, isRenewalOrder); return request; } @@ -251,11 +251,21 @@ public TechnicalContact GetTechnicalContact(INewOrderResponse productInfo) } private NewOrderRequest BuildNewOrderRequest(EnrollmentProductInfo productInfo, - TemplateNewOrderRequest newOrderRequest, string csr, bool isRenewal) + TemplateNewOrderRequest newOrderRequest, string csr, string subject, Dictionary san, bool isRenewal) { var customOrderId = Guid.NewGuid().ToString(); productInfo.ProductParameters.Add("CustomOrderId", customOrderId); + // Extract domain name from CSR subject CN + var domainName = subject?.Split(',') + .Select(p => p.Trim()) + .Where(p => p.StartsWith("CN=", StringComparison.OrdinalIgnoreCase)) + .Select(p => p.Substring(3)) + .FirstOrDefault() ?? ""; + + // Extract DNS SANs from Keyfactor san parameter + var dnsNames = san != null && san.ContainsKey("dns") ? san["dns"] : Array.Empty(); + var request = new JObject( new JObject( @@ -289,12 +299,12 @@ private NewOrderRequest BuildNewOrderRequest(EnrollmentProductInfo productInfo, CreatePropertyFromTemplate( "$.OrganizationInfo.OrganizationAddress.LocalityName", productInfo, newOrderRequest))))), - CreatePropertyFromTemplate("$.ValidityPeriod", productInfo, newOrderRequest), + new JProperty("ValidityPeriod", ConvertDaysToMonths(productInfo)), new JProperty("ServerCount", 1), new JProperty("CSR", csr), - CreatePropertyFromTemplate("$.DomainName", productInfo, newOrderRequest), + new JProperty("DomainName", domainName), new JProperty("WebServerType", "Other"), - CreatePropertyFromTemplate("$.DNSNames", productInfo, newOrderRequest, true), + new JProperty("DNSNames", new JArray(dnsNames)), new JProperty("isCUOrder", false), CreatePropertyFromTemplate("$.AutoWWW", productInfo, newOrderRequest), new JProperty("IsRenewalOrder", isRenewal), @@ -395,6 +405,21 @@ private JProperty CreatePropertyFromTemplate(string propertyPath, EnrollmentProd return new JProperty(propertyPath.Substring(propertyPath.LastIndexOf('.') + 1), null); } + private long ConvertDaysToMonths(EnrollmentProductInfo productInfo) + { + if (productInfo.ProductParameters.ContainsKey("Validity Period (In Days)") && + long.TryParse(productInfo.ProductParameters["Validity Period (In Days)"], out var days)) + { + // Convert days to months, rounding up so short-lived certs (e.g. 90 days) get at least 1 month + var months = (long)Math.Ceiling(days / 30.0); + _logger.LogTrace($"Validity conversion: {days} days -> {months} months"); + return months; + } + + _logger.LogWarning("Validity Period (In Days) not found or invalid, defaulting to 12 months"); + return 12; + } + private string ExtractOrgId(string organization) { if (organization != null) diff --git a/SslStoreCaProxy/SslStoreCAPluginConfig.cs b/SslStoreCaProxy/SslStoreCAPluginConfig.cs index faeffb8..c520a10 100644 --- a/SslStoreCaProxy/SslStoreCAPluginConfig.cs +++ b/SslStoreCaProxy/SslStoreCAPluginConfig.cs @@ -71,13 +71,6 @@ public static Dictionary GetTemplateParameterAnnotat { return new Dictionary() { - ["DNS Names Comma Separated"] = new PropertyConfigInfo() - { - Comments = "Comma-separated list of DNS names (SANs) for the certificate.", - Hidden = false, - DefaultValue = "", - Type = "String" - }, ["Approver Email"] = new PropertyConfigInfo() { Comments = "Comma-separated approver email address(es) for domain validation.", @@ -85,11 +78,11 @@ public static Dictionary GetTemplateParameterAnnotat DefaultValue = "", Type = "String" }, - ["Validity Period (In Months)"] = new PropertyConfigInfo() + ["Validity Period (In Days)"] = new PropertyConfigInfo() { - Comments = "Certificate validity period in months (e.g. 12, 24, 36, 48, 60, 72).", + Comments = "Certificate validity period in days (e.g. 90, 365, 730).", Hidden = false, - DefaultValue = "12", + DefaultValue = "365", Type = "String" }, ["Admin Contact - First Name"] = new PropertyConfigInfo() diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs index 901d750..5fdd4c3 100644 --- a/SslStoreCaProxy/SslStoreCaProxy.cs +++ b/SslStoreCaProxy/SslStoreCaProxy.cs @@ -167,24 +167,33 @@ public async Task Enroll(string csr, string subject, Dictionar if (!productInfo.ProductParameters.ContainsKey("PriorCertSN")) { - string[] arrayProducts = Array.Empty(); - string[] arrayApproverEmails = Array.Empty(); + // Extract domain name from CSR subject and SANs from the Keyfactor san parameter + var domainName = subject?.Split(',') + .Select(p => p.Trim()) + .Where(p => p.StartsWith("CN=", StringComparison.OrdinalIgnoreCase)) + .Select(p => p.Substring(3)) + .FirstOrDefault() ?? ""; + _logger.LogTrace($"Domain Name from subject: {domainName}"); - if (productInfo.ProductParameters.ContainsKey("DNS Names Comma Separated")) - { - _logger.LogTrace($"DNS Comma Separated {productInfo.ProductParameters["DNS Names Comma Separated"]}"); - arrayProducts = productInfo.ProductParameters["DNS Names Comma Separated"].Split(new char[] { ',' }); - } + var dnsNames = san != null && san.ContainsKey("dns") ? san["dns"] : Array.Empty(); + _logger.LogTrace($"DNS Names from SAN: {string.Join(",", dnsNames)}"); + + string[] arrayApproverEmails = Array.Empty(); if (productInfo.ProductParameters.ContainsKey("Approver Email")) { _logger.LogTrace($"Approver Email {productInfo.ProductParameters["Approver Email"]}"); arrayApproverEmails = productInfo.ProductParameters["Approver Email"].Split(new char[] { ',' }); } + // Validate approver emails against all domains (CN + SANs) + var allDomains = new List(); + if (!string.IsNullOrEmpty(domainName)) allDomains.Add(domainName); + allDomains.AddRange(dnsNames.Where(d => !string.Equals(d, domainName, StringComparison.OrdinalIgnoreCase))); + var count = 1; - foreach (var product in arrayProducts) + foreach (var domain in allDomains) { - var emailApproverRequest = _requestManager.GetEmailApproverListRequest(productInfo.ProductID, product); + var emailApproverRequest = _requestManager.GetEmailApproverListRequest(productInfo.ProductID, domain); _logger.LogTrace($"Email Approver Request JSON {JsonConvert.SerializeObject(emailApproverRequest)}"); var emailApproverResponse = await client.SubmitEmailApproverRequestAsync(emailApproverRequest); @@ -204,7 +213,7 @@ public async Task Enroll(string csr, string subject, Dictionar count++; } - var enrollmentRequest = _requestManager.GetEnrollmentRequest(csr, productInfo, Config, false); + var enrollmentRequest = _requestManager.GetEnrollmentRequest(csr, subject, san, productInfo, Config, false); _logger.LogTrace($"enrollmentRequest JSON {JsonConvert.SerializeObject(enrollmentRequest)}"); enrollmentResponse = await client.SubmitNewOrderRequestAsync(enrollmentRequest); From 64dd60ffd07130f07576184436b0f5bf2e537f15 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 17 Mar 2026 14:54:04 -0400 Subject: [PATCH 06/42] Removed outdated request --- SslStoreCaProxy/RequestManager.cs | 221 ++++++++++-------------------- 1 file changed, 73 insertions(+), 148 deletions(-) diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index be51f6d..42fb2d3 100644 --- a/SslStoreCaProxy/RequestManager.cs +++ b/SslStoreCaProxy/RequestManager.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Net; -using System.Reflection; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.RegularExpressions; @@ -14,7 +11,6 @@ using Keyfactor.PKI.Enums.EJBCA; using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Keyfactor.AnyGateway.SslStore { @@ -32,18 +28,7 @@ public NewOrderRequest GetEnrollmentRequest(string csr, string subject, Dictiona EnrollmentProductInfo productInfo, IAnyCAPluginConfigProvider configProvider, bool isRenewalOrder) { var pemCsr = ConvertCsrToPem(csr); - - var sampleRequest = JsonConvert.SerializeObject(configProvider.CAConnectionData["SampleRequest"]); - - var settings = new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore, - MissingMemberHandling = MissingMemberHandling.Ignore - }; - var request = BuildNewOrderRequest(productInfo, - JsonConvert.DeserializeObject(sampleRequest, settings), pemCsr, subject, san, isRenewalOrder); - - return request; + return BuildNewOrderRequest(productInfo, pemCsr, subject, san, isRenewalOrder); } private string ConvertCsrToPem(string csr) @@ -251,103 +236,87 @@ public TechnicalContact GetTechnicalContact(INewOrderResponse productInfo) } private NewOrderRequest BuildNewOrderRequest(EnrollmentProductInfo productInfo, - TemplateNewOrderRequest newOrderRequest, string csr, string subject, Dictionary san, bool isRenewal) + string csr, string subject, Dictionary san, bool isRenewal) { - var customOrderId = Guid.NewGuid().ToString(); - productInfo.ProductParameters.Add("CustomOrderId", customOrderId); + var p = productInfo.ProductParameters; // Extract domain name from CSR subject CN var domainName = subject?.Split(',') - .Select(p => p.Trim()) - .Where(p => p.StartsWith("CN=", StringComparison.OrdinalIgnoreCase)) - .Select(p => p.Substring(3)) + .Select(part => part.Trim()) + .Where(part => part.StartsWith("CN=", StringComparison.OrdinalIgnoreCase)) + .Select(part => part.Substring(3)) .FirstOrDefault() ?? ""; // Extract DNS SANs from Keyfactor san parameter - var dnsNames = san != null && san.ContainsKey("dns") ? san["dns"] : Array.Empty(); + var dnsNames = san != null && san.ContainsKey("dns") ? san["dns"].ToList() : new List(); - var request = - new JObject( - new JObject( - new JProperty("AuthRequest", - new JObject(new JProperty("PartnerCode", _sslStoreCaProxy.PartnerCode), - new JProperty("AuthToken", _sslStoreCaProxy.AuthenticationToken))), - new JProperty("ProductCode", productInfo.ProductID.Replace("-EO", "")), - new JProperty("CustomOrderId", customOrderId), - new JProperty("TSSOrganizationId", productInfo.ProductParameters.ContainsKey("Organization ID") ? ExtractOrgId(productInfo.ProductParameters["Organization ID"]) : null), - new JProperty("OrganizationInfo", - new JObject( - CreatePropertyFromTemplate("$.OrganizationInfo.OrganizationName", productInfo, - newOrderRequest), - CreatePropertyFromTemplate("$.OrganizationInfo.RegistrationNumber", productInfo, - newOrderRequest), - CreatePropertyFromTemplate("$.OrganizationInfo.JurisdictionCountry", productInfo, - newOrderRequest), - new JProperty("OrganizationAddress", - new JObject( - CreatePropertyFromTemplate( - "$.OrganizationInfo.OrganizationAddress.AddressLine1", productInfo, - newOrderRequest), - CreatePropertyFromTemplate("$.OrganizationInfo.OrganizationAddress.Region", - productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.OrganizationInfo.OrganizationAddress.PostalCode", - productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.OrganizationInfo.OrganizationAddress.Country", - productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.OrganizationInfo.OrganizationAddress.Phone", - productInfo, newOrderRequest), - CreatePropertyFromTemplate( - "$.OrganizationInfo.OrganizationAddress.LocalityName", productInfo, - newOrderRequest))))), - new JProperty("ValidityPeriod", ConvertDaysToMonths(productInfo)), - new JProperty("ServerCount", 1), - new JProperty("CSR", csr), - new JProperty("DomainName", domainName), - new JProperty("WebServerType", "Other"), - new JProperty("DNSNames", new JArray(dnsNames)), - new JProperty("isCUOrder", false), - CreatePropertyFromTemplate("$.AutoWWW", productInfo, newOrderRequest), - new JProperty("IsRenewalOrder", isRenewal), - new JProperty("isTrialOrder", false), - new JProperty("AdminContact", - new JObject( - CreatePropertyFromTemplate("$.AdminContact.FirstName", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.AdminContact.LastName", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.AdminContact.Phone", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.AdminContact.Email", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.AdminContact.Title", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.AdminContact.OrganizationName", productInfo, - newOrderRequest), - CreatePropertyFromTemplate("$.AdminContact.AddressLine1", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.AdminContact.City", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.AdminContact.Region", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.AdminContact.PostalCode", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.AdminContact.Country", productInfo, newOrderRequest) - )), - new JProperty("TechnicalContact", - new JObject( - CreatePropertyFromTemplate("$.TechnicalContact.FirstName", productInfo, - newOrderRequest), - CreatePropertyFromTemplate("$.TechnicalContact.LastName", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.TechnicalContact.Phone", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.TechnicalContact.Email", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.TechnicalContact.Title", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.TechnicalContact.OrganizationName", productInfo, - newOrderRequest), - CreatePropertyFromTemplate("$.TechnicalContact.AddressLine1", productInfo, - newOrderRequest), - CreatePropertyFromTemplate("$.TechnicalContact.City", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.TechnicalContact.Region", productInfo, newOrderRequest), - CreatePropertyFromTemplate("$.TechnicalContact.PostalCode", productInfo, - newOrderRequest), - CreatePropertyFromTemplate("$.TechnicalContact.Country", productInfo, newOrderRequest) - )), - CreatePropertyFromTemplate("$.ApproverEmail", productInfo, newOrderRequest), - new JProperty("FileAuthDVIndicator", false), - new JProperty("CNAMEAuthDVIndicator", false), - new JProperty("SignatureHashAlgorithm", "PREFER_SHA2"))); + return new NewOrderRequest + { + AuthRequest = GetAuthRequest(), + ProductCode = productInfo.ProductID.Replace("-EO", ""), + CustomOrderId = Guid.NewGuid().ToString(), + TssOrganizationId = p.ContainsKey("Organization ID") ? long.TryParse(ExtractOrgId(p["Organization ID"]), out var orgId) ? orgId : 0 : 0, + OrganizationInfo = new OrganizationInfo + { + OrganizationName = GetParam(p, "Organization Name"), + JurisdictionCountry = GetParam(p, "Organization Jurisdiction Country"), + OrganizationAddress = new OrganizationAddress + { + AddressLine1 = GetParam(p, "Organization Address"), + Region = GetParam(p, "Organization Region") ?? GetParam(p, "Organization State/Province"), + PostalCode = GetParam(p, "Organization Postal Code"), + Country = GetParam(p, "Organization Country"), + Phone = GetParam(p, "Organization Phone"), + LocalityName = GetParam(p, "Organization City") + } + }, + ValidityPeriod = ConvertDaysToMonths(productInfo), + ServerCount = 1, + Csr = csr, + DomainName = domainName, + WebServerType = GetParam(p, "Web Server Type") ?? "Other", + DnsNames = dnsNames, + IsCuOrder = false, + IsRenewalOrder = isRenewal, + IsTrialOrder = false, + AdminContact = new AdminContact + { + FirstName = GetParam(p, "Admin Contact - First Name"), + LastName = GetParam(p, "Admin Contact - Last Name"), + Phone = GetParam(p, "Admin Contact - Phone"), + Email = GetParam(p, "Admin Contact - Email"), + Title = GetParam(p, "Admin Contact - Title"), + OrganizationName = GetParam(p, "Admin Contact - Organization Name"), + AddressLine1 = GetParam(p, "Admin Contact - Address"), + City = GetParam(p, "Admin Contact - City"), + Region = GetParam(p, "Admin Contact - Region"), + PostalCode = GetParam(p, "Admin Contact - Postal Code"), + Country = GetParam(p, "Admin Contact - Country") + }, + TechnicalContact = new TechnicalContact + { + FirstName = GetParam(p, "Technical Contact - First Name"), + LastName = GetParam(p, "Technical Contact - Last Name"), + Phone = GetParam(p, "Technical Contact - Phone"), + Email = GetParam(p, "Technical Contact - Email"), + Title = GetParam(p, "Technical Contact - Title"), + OrganizationName = GetParam(p, "Technical Contact - Organization Name"), + AddressLine1 = GetParam(p, "Technical Contact - Address"), + City = GetParam(p, "Technical Contact - City"), + Region = GetParam(p, "Technical Contact - Region"), + PostalCode = GetParam(p, "Technical Contact - Postal Code"), + Country = GetParam(p, "Technical Contact - Country") + }, + ApproverEmail = GetParam(p, "Approver Email"), + FileAuthDvIndicator = false, + CnameAuthDvIndicator = false, + SignatureHashAlgorithm = GetParam(p, "Signature Hash Algorithm") ?? "PREFER_SHA2" + }; + } - return request.ToObject(); + private static string GetParam(Dictionary parameters, string key) + { + return parameters.ContainsKey(key) ? parameters[key] : null; } public string GetCertificateContent(List certificates, string commonName) @@ -361,50 +330,6 @@ public string GetCertificateContent(List certificates, string commo return ""; } - private JArray CreateJArrayFromCommaSeparatedList(string csList) - { - var ja = new JArray(); - foreach (var i in csList.Split(',')) ja.Add(i); - return ja; - } - - private JProperty CreatePropertyFromTemplate(string propertyPath, EnrollmentProductInfo productInfo, - TemplateNewOrderRequest newOrderRequest, bool isArray = false) - { - var template = (JObject)JToken.FromObject(newOrderRequest); - var requiredForProducts = - new JArray(template.SelectTokens(propertyPath + ".FieldData.RequiredForProducts")); - var enrollmentFieldName = template.SelectToken(propertyPath + ".FieldData.EnrollmentFieldMapping"); - - if (requiredForProducts.Count > 0) - { - if (requiredForProducts[0].Any(i => i.Value() == "All") || - requiredForProducts[0].Any(i => i.Value() == productInfo.ProductID)) - if (enrollmentFieldName != null && enrollmentFieldName.Value() != "None") - { - if (productInfo.ProductParameters.ContainsKey(enrollmentFieldName.Value())) - { - var enrollmentFieldValue = - productInfo.ProductParameters[enrollmentFieldName.Value()]; - if (isArray == false) - return new JProperty(propertyPath.Substring(propertyPath.LastIndexOf('.') + 1), - enrollmentFieldValue); - return new JProperty(propertyPath.Substring(propertyPath.LastIndexOf('.') + 1), - CreateJArrayFromCommaSeparatedList(enrollmentFieldValue)); - } - - _logger.LogError( - $"Enrollment Field is required in the config settings but missing from the request or names do not match.: {enrollmentFieldName.Value()}"); - } - } - else - { - _logger.LogError($"Enrollment Field is in the request but missing from config settings: {propertyPath}"); - } - - return new JProperty(propertyPath.Substring(propertyPath.LastIndexOf('.') + 1), null); - } - private long ConvertDaysToMonths(EnrollmentProductInfo productInfo) { if (productInfo.ProductParameters.ContainsKey("Validity Period (In Days)") && From 680fd415c5326b47ea37293c6364c09000dbe40a Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 17 Mar 2026 15:18:13 -0400 Subject: [PATCH 07/42] fixed serialization --- SslStoreCaProxy/Client/SslStoreClient.cs | 37 +++++++++++++++--------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/SslStoreCaProxy/Client/SslStoreClient.cs b/SslStoreCaProxy/Client/SslStoreClient.cs index a2169fe..ca48d67 100644 --- a/SslStoreCaProxy/Client/SslStoreClient.cs +++ b/SslStoreCaProxy/Client/SslStoreClient.cs @@ -13,6 +13,7 @@ using Keyfactor.Logging; using Microsoft.Extensions.Logging; using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; namespace Keyfactor.AnyGateway.SslStore.Client { @@ -20,6 +21,14 @@ public sealed class SslStoreClient : ISslStoreClient { private static readonly ILogger _logger = LogHandler.GetClassLogger(); + // Use DefaultContractResolver to ensure [JsonProperty] attributes are respected, + // regardless of the host application's global JsonConvert settings. + private static readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings + { + ContractResolver = new DefaultContractResolver(), + NullValueHandling = NullValueHandling.Ignore + }; + public SslStoreClient(IAnyCAPluginConfigProvider config) { if (config.CAConnectionData.ContainsKey(Constants.SslStoreUrl)) @@ -36,9 +45,9 @@ public SslStoreClient(IAnyCAPluginConfigProvider config) public async Task SubmitNewOrderRequestAsync(NewOrderRequest newOrderRequest) { using (var resp = await RestClient.PostAsync("/rest/order/neworder", new StringContent( - JsonConvert.SerializeObject(newOrderRequest), Encoding.UTF8, "application/json"))) + JsonConvert.SerializeObject(newOrderRequest, _serializerSettings), Encoding.UTF8, "application/json"))) { - _logger.LogTrace(JsonConvert.SerializeObject(newOrderRequest)); + _logger.LogTrace(JsonConvert.SerializeObject(newOrderRequest, _serializerSettings)); resp.EnsureSuccessStatusCode(); var enrollmentResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -49,9 +58,9 @@ public async Task SubmitNewOrderRequestAsync(NewOrderRequest n public async Task SubmitEmailApproverRequestAsync(EmailApproverRequest newApproverRequest) { using (var resp = await RestClient.PostAsync("/rest/order/approverlist", new StringContent( - JsonConvert.SerializeObject(newApproverRequest), Encoding.UTF8, "application/json"))) + JsonConvert.SerializeObject(newApproverRequest, _serializerSettings), Encoding.UTF8, "application/json"))) { - _logger.LogTrace(JsonConvert.SerializeObject(newApproverRequest)); + _logger.LogTrace(JsonConvert.SerializeObject(newApproverRequest, _serializerSettings)); resp.EnsureSuccessStatusCode(); var enrollmentResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -62,7 +71,7 @@ public async Task SubmitEmailApproverRequestAsync(EmailAp public async Task SubmitReIssueRequestAsync(ReIssueRequest reIssueOrderRequest) { using (var resp = await RestClient.PostAsync("/rest/order/reissue", new StringContent( - JsonConvert.SerializeObject(reIssueOrderRequest), Encoding.UTF8, "application/json"))) + JsonConvert.SerializeObject(reIssueOrderRequest, _serializerSettings), Encoding.UTF8, "application/json"))) { var orderStatusResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -73,9 +82,9 @@ public async Task SubmitReIssueRequestAsync(ReIssueRequest reI public async Task SubmitRenewRequestAsync(NewOrderRequest renewOrderRequest) { using (var resp = await RestClient.PostAsync("/rest/order/neworder", new StringContent( - JsonConvert.SerializeObject(renewOrderRequest), Encoding.UTF8, "application/json"))) + JsonConvert.SerializeObject(renewOrderRequest, _serializerSettings), Encoding.UTF8, "application/json"))) { - _logger.LogTrace(JsonConvert.SerializeObject(renewOrderRequest)); + _logger.LogTrace(JsonConvert.SerializeObject(renewOrderRequest, _serializerSettings)); resp.EnsureSuccessStatusCode(); var enrollmentResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -87,9 +96,9 @@ public async Task SubmitDownloadCertificateAsync( DownloadCertificateRequest downloadOrderRequest) { using (var resp = await RestClient.PostAsync("/rest/order/download", new StringContent( - JsonConvert.SerializeObject(downloadOrderRequest), Encoding.UTF8, "application/json"))) + JsonConvert.SerializeObject(downloadOrderRequest, _serializerSettings), Encoding.UTF8, "application/json"))) { - _logger.LogTrace(JsonConvert.SerializeObject(downloadOrderRequest)); + _logger.LogTrace(JsonConvert.SerializeObject(downloadOrderRequest, _serializerSettings)); resp.EnsureSuccessStatusCode(); var downloadOrderResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -113,7 +122,7 @@ public async Task SubmitQueryOrderRequestAsync(BlockingCollection>( await resp.Content.ReadAsStringAsync()); - _logger.LogTrace($"Order List JSON {JsonConvert.SerializeObject(batchResponse)}"); + _logger.LogTrace($"Order List JSON {JsonConvert.SerializeObject(batchResponse, _serializerSettings)}"); var batchCount = batchResponse.Count; @@ -185,7 +194,7 @@ public async Task SubmitQueryOrderRequestAsync(BlockingCollection SubmitRevokeCertificateAsync(RevokeOrderRequest revokeOrderRequest) { using (var resp = await RestClient.PostAsync("/rest/order/refundrequest", new StringContent( - JsonConvert.SerializeObject(revokeOrderRequest), Encoding.UTF8, "application/json"))) + JsonConvert.SerializeObject(revokeOrderRequest, _serializerSettings), Encoding.UTF8, "application/json"))) { var revocationResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -196,7 +205,7 @@ public async Task SubmitRevokeCertificateAsync(RevokeOrder public async Task SubmitOrderStatusRequestAsync(OrderStatusRequest orderStatusRequest) { using (var resp = await RestClient.PostAsync("/rest/order/status", new StringContent( - JsonConvert.SerializeObject(orderStatusRequest), Encoding.UTF8, "application/json"))) + JsonConvert.SerializeObject(orderStatusRequest, _serializerSettings), Encoding.UTF8, "application/json"))) { var orderStatusResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -207,7 +216,7 @@ public async Task SubmitOrderStatusRequestAsync(OrderStatusRe public async Task SubmitOrganizationListAsync(OrganizationListRequest organizationListRequest) { using (var resp = await RestClient.PostAsync("/rest/digicert/organizationlist", new StringContent( - JsonConvert.SerializeObject(organizationListRequest), Encoding.UTF8, "application/json"))) + JsonConvert.SerializeObject(organizationListRequest, _serializerSettings), Encoding.UTF8, "application/json"))) { var organizationListResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); From 04cda51974177af1398b241910280d7dcac918e3 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 17 Mar 2026 15:32:30 -0400 Subject: [PATCH 08/42] fixed serialize issue --- SslStoreCaProxy/Client/SslStoreClient.cs | 45 +++++++++++++++--------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/SslStoreCaProxy/Client/SslStoreClient.cs b/SslStoreCaProxy/Client/SslStoreClient.cs index ca48d67..3d8b721 100644 --- a/SslStoreCaProxy/Client/SslStoreClient.cs +++ b/SslStoreCaProxy/Client/SslStoreClient.cs @@ -21,14 +21,25 @@ public sealed class SslStoreClient : ISslStoreClient { private static readonly ILogger _logger = LogHandler.GetClassLogger(); - // Use DefaultContractResolver to ensure [JsonProperty] attributes are respected, - // regardless of the host application's global JsonConvert settings. - private static readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings + // Use an explicit JsonSerializer to ensure [JsonProperty] attributes are respected, + // regardless of the host application's global JsonConvert.DefaultSettings. + private static readonly JsonSerializer _serializer = new JsonSerializer { ContractResolver = new DefaultContractResolver(), NullValueHandling = NullValueHandling.Ignore }; + private static string Serialize(object obj) + { + var sb = new StringBuilder(); + using (var sw = new System.IO.StringWriter(sb)) + using (var jw = new JsonTextWriter(sw)) + { + _serializer.Serialize(jw, obj); + } + return sb.ToString(); + } + public SslStoreClient(IAnyCAPluginConfigProvider config) { if (config.CAConnectionData.ContainsKey(Constants.SslStoreUrl)) @@ -45,9 +56,9 @@ public SslStoreClient(IAnyCAPluginConfigProvider config) public async Task SubmitNewOrderRequestAsync(NewOrderRequest newOrderRequest) { using (var resp = await RestClient.PostAsync("/rest/order/neworder", new StringContent( - JsonConvert.SerializeObject(newOrderRequest, _serializerSettings), Encoding.UTF8, "application/json"))) + Serialize(newOrderRequest), Encoding.UTF8, "application/json"))) { - _logger.LogTrace(JsonConvert.SerializeObject(newOrderRequest, _serializerSettings)); + _logger.LogTrace(Serialize(newOrderRequest)); resp.EnsureSuccessStatusCode(); var enrollmentResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -58,9 +69,9 @@ public async Task SubmitNewOrderRequestAsync(NewOrderRequest n public async Task SubmitEmailApproverRequestAsync(EmailApproverRequest newApproverRequest) { using (var resp = await RestClient.PostAsync("/rest/order/approverlist", new StringContent( - JsonConvert.SerializeObject(newApproverRequest, _serializerSettings), Encoding.UTF8, "application/json"))) + Serialize(newApproverRequest), Encoding.UTF8, "application/json"))) { - _logger.LogTrace(JsonConvert.SerializeObject(newApproverRequest, _serializerSettings)); + _logger.LogTrace(Serialize(newApproverRequest)); resp.EnsureSuccessStatusCode(); var enrollmentResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -71,7 +82,7 @@ public async Task SubmitEmailApproverRequestAsync(EmailAp public async Task SubmitReIssueRequestAsync(ReIssueRequest reIssueOrderRequest) { using (var resp = await RestClient.PostAsync("/rest/order/reissue", new StringContent( - JsonConvert.SerializeObject(reIssueOrderRequest, _serializerSettings), Encoding.UTF8, "application/json"))) + Serialize(reIssueOrderRequest), Encoding.UTF8, "application/json"))) { var orderStatusResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -82,9 +93,9 @@ public async Task SubmitReIssueRequestAsync(ReIssueRequest reI public async Task SubmitRenewRequestAsync(NewOrderRequest renewOrderRequest) { using (var resp = await RestClient.PostAsync("/rest/order/neworder", new StringContent( - JsonConvert.SerializeObject(renewOrderRequest, _serializerSettings), Encoding.UTF8, "application/json"))) + Serialize(renewOrderRequest), Encoding.UTF8, "application/json"))) { - _logger.LogTrace(JsonConvert.SerializeObject(renewOrderRequest, _serializerSettings)); + _logger.LogTrace(Serialize(renewOrderRequest)); resp.EnsureSuccessStatusCode(); var enrollmentResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -96,9 +107,9 @@ public async Task SubmitDownloadCertificateAsync( DownloadCertificateRequest downloadOrderRequest) { using (var resp = await RestClient.PostAsync("/rest/order/download", new StringContent( - JsonConvert.SerializeObject(downloadOrderRequest, _serializerSettings), Encoding.UTF8, "application/json"))) + Serialize(downloadOrderRequest), Encoding.UTF8, "application/json"))) { - _logger.LogTrace(JsonConvert.SerializeObject(downloadOrderRequest, _serializerSettings)); + _logger.LogTrace(Serialize(downloadOrderRequest)); resp.EnsureSuccessStatusCode(); var downloadOrderResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -122,7 +133,7 @@ public async Task SubmitQueryOrderRequestAsync(BlockingCollection>( await resp.Content.ReadAsStringAsync()); - _logger.LogTrace($"Order List JSON {JsonConvert.SerializeObject(batchResponse, _serializerSettings)}"); + _logger.LogTrace($"Order List JSON {Serialize(batchResponse)}"); var batchCount = batchResponse.Count; @@ -194,7 +205,7 @@ public async Task SubmitQueryOrderRequestAsync(BlockingCollection SubmitRevokeCertificateAsync(RevokeOrderRequest revokeOrderRequest) { using (var resp = await RestClient.PostAsync("/rest/order/refundrequest", new StringContent( - JsonConvert.SerializeObject(revokeOrderRequest, _serializerSettings), Encoding.UTF8, "application/json"))) + Serialize(revokeOrderRequest), Encoding.UTF8, "application/json"))) { var revocationResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -205,7 +216,7 @@ public async Task SubmitRevokeCertificateAsync(RevokeOrder public async Task SubmitOrderStatusRequestAsync(OrderStatusRequest orderStatusRequest) { using (var resp = await RestClient.PostAsync("/rest/order/status", new StringContent( - JsonConvert.SerializeObject(orderStatusRequest, _serializerSettings), Encoding.UTF8, "application/json"))) + Serialize(orderStatusRequest), Encoding.UTF8, "application/json"))) { var orderStatusResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); @@ -216,7 +227,7 @@ public async Task SubmitOrderStatusRequestAsync(OrderStatusRe public async Task SubmitOrganizationListAsync(OrganizationListRequest organizationListRequest) { using (var resp = await RestClient.PostAsync("/rest/digicert/organizationlist", new StringContent( - JsonConvert.SerializeObject(organizationListRequest, _serializerSettings), Encoding.UTF8, "application/json"))) + Serialize(organizationListRequest), Encoding.UTF8, "application/json"))) { var organizationListResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); From 64ba391e8699d8904cffc05b7d57fcef18b576d3 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Wed, 18 Mar 2026 11:35:46 -0400 Subject: [PATCH 09/42] fixed date issue --- SslStoreCaProxy/DcomJson.json | 189 +++++++++++++++++++++++++++ SslStoreCaProxy/RequestManager.cs | 5 +- SslStoreCaProxy/SslStoreRequest.json | 67 ++++++++++ 3 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 SslStoreCaProxy/DcomJson.json create mode 100644 SslStoreCaProxy/SslStoreRequest.json diff --git a/SslStoreCaProxy/DcomJson.json b/SslStoreCaProxy/DcomJson.json new file mode 100644 index 0000000..c578862 --- /dev/null +++ b/SslStoreCaProxy/DcomJson.json @@ -0,0 +1,189 @@ +{ + "AuthRequest": { + "PartnerCode": "82919874", + "AuthToken": "B76586C757D226D874D9DB82388EF70E", + "ReplayToken": null, + "UserAgent": null, + "TokenID": null, + "TokenCode": null, + "IPAddress": null, + "IsUsedForTokenSystem": false, + "Token": null + }, + "CustomOrderID": "08cc122e-4b54-438e-94eb-3db56d848b8e", + "ProductCode": "positivessl", + "OrganizationInfo": { + "OrganizationName": null, + "DUNS": null, + "Division": null, + "IncorporatingAgency": null, + "RegistrationNumber": null, + "JurisdictionCity": null, + "JurisdictionRegion": null, + "JurisdictionCountry": null, + "AssumedName": null, + "OrganizationAddress": { + "AddressLine1": null, + "AddressLine2": null, + "AddressLine3": null, + "City": null, + "Region": null, + "PostalCode": null, + "Country": null, + "Phone": null, + "Fax": null, + "LocalityName": null + } + }, + "TSSOrganizationId": 0, + "ValidityPeriod": 12, + "ServerCount": 1, + "CSR": "-----BEGIN CERTIFICATE REQUEST-----\r\nMIICXjCCAUYCAQAwGTEXMBUGA1UEAwwOd3d3LmJvaW5neS5jb20wggEiMA0GCSqG\r\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2VBd7Xz6GZdLRVIJPkcwBCMhxct/UvYlU\r\n1k3JV/OIQzpERoMx99M5MM/8Mjsu8QhihN5ji9TIMwaDlL34DWKLJBMlSy6Bttzi\r\nvowRz6mxXi2sTdkZ+1ow1K7tGA04iqvA9RFYdPqSqYSZl+r98aY/9QGALThKmw0i\r\nqBeiRemAxjfcyTJTv7gner/JaB40wksEhZK5bhACG5TxddN30pjfKTcg0g5WMarN\r\nn+9GFRiE0d2G/Rem/Nno/YRjImBverPoOkwSbQmyP0MgCQyTPPRXlU+KP6acuwEG\r\nE52Jztf0j1TZ2liDf9k6TtHKEqzmf/ZALPSDsfplP36ZyjgTYCnvAgMBAAGgADAN\r\nBgkqhkiG9w0BAQsFAAOCAQEAM4gJgBZow3sMlaTSptU6/3vE7XXWUWsheTrylIAt\r\nVKscCrJ/NsWVLLegS2M8WTL5DaAyPTqy/iGJzJbxdcGSTfwxuLVIlkDtpvpQ1jjN\r\nz9+D/nSeo6CORDCPUacNyi6wq8E5iCtJlwy29Q+zW9IBUHJ6lb++cOQOBm+c3mjL\r\niRc/UDB+X10QYhHV8dysqLasi4cUmWp5Od+7lajMDeLbQEy8P4TeymEzsTjaZDxY\r\nw5D65RGwtoHgRINx5yJDTbhDJkEuinpSVe/svjy/rhNj1GxZabcEwf0V9Sw4Bl6V\r\nUZg41dRsyRgRlCsfbMRSy3lonTpvLnxCEZ1IkELQpAGk2Q==\r\n-----END CERTIFICATE REQUEST-----\r\n", + "DomainName": null, + "WebServerType": "Other", + "isCUOrder": false, + "AutoWWW": true, + "isRenewalOrder": false, + "SpecialInstructions": null, + "isTrialOrder": false, + "AdminContact": { + "FirstName": null, + "LastName": null, + "SubjectFirstName": null, + "SubjectLastName": null, + "Phone": null, + "Fax": null, + "Email": "admin@boingy.com", + "Title": null, + "OrganizationName": null, + "AddressLine1": null, + "AddressLine2": null, + "City": null, + "Region": null, + "PostalCode": null, + "Country": null + }, + "TechnicalContact": { + "FirstName": null, + "LastName": null, + "SubjectFirstName": null, + "SubjectLastName": null, + "Phone": null, + "Fax": null, + "Email": null, + "Title": null, + "OrganizationName": null, + "AddressLine1": null, + "AddressLine2": null, + "City": null, + "Region": null, + "PostalCode": null, + "Country": null + }, + "ApproverEmail": "brian@boingy.com", + "ReserveSANCount": 0, + "AddInstallationSupport": false, + "FileAuthDVIndicator": false, + "CNAMEAuthDVIndicator": false, + "HTTPSFileAuthDVIndicator": false, + "SignatureHashAlgorithm": "PREFER_SHA2", + "CertTransparencyIndicator": false, + "RenewalDays": 0, + "isPKCS10": false, + "WildcardReserveSANCount": 0 +} +2026-03-18 14: 15: 27.2587 Keyfactor.AnyGateway.SslStore.Client.SslStoreClient [Trace +] - { + "AuthRequest": { + "PartnerCode": "82919874", + "AuthToken": "B76586C757D226D874D9DB82388EF70E", + "ReplayToken": null, + "UserAgent": null, + "TokenID": null, + "TokenCode": null, + "IPAddress": null, + "IsUsedForTokenSystem": false, + "Token": null + }, + "CustomOrderID": "08cc122e-4b54-438e-94eb-3db56d848b8e", + "ProductCode": "positivessl", + "OrganizationInfo": { + "OrganizationName": null, + "DUNS": null, + "Division": null, + "IncorporatingAgency": null, + "RegistrationNumber": null, + "JurisdictionCity": null, + "JurisdictionRegion": null, + "JurisdictionCountry": null, + "AssumedName": null, + "OrganizationAddress": { + "AddressLine1": null, + "AddressLine2": null, + "AddressLine3": null, + "City": null, + "Region": null, + "PostalCode": null, + "Country": null, + "Phone": null, + "Fax": null, + "LocalityName": null + } + }, + "TSSOrganizationId": 0, + "ValidityPeriod": 12, + "ServerCount": 1, + "CSR": "-----BEGIN CERTIFICATE REQUEST-----\r\nMIICXjCCAUYCAQAwGTEXMBUGA1UEAwwOd3d3LmJvaW5neS5jb20wggEiMA0GCSqG\r\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2VBd7Xz6GZdLRVIJPkcwBCMhxct/UvYlU\r\n1k3JV/OIQzpERoMx99M5MM/8Mjsu8QhihN5ji9TIMwaDlL34DWKLJBMlSy6Bttzi\r\nvowRz6mxXi2sTdkZ+1ow1K7tGA04iqvA9RFYdPqSqYSZl+r98aY/9QGALThKmw0i\r\nqBeiRemAxjfcyTJTv7gner/JaB40wksEhZK5bhACG5TxddN30pjfKTcg0g5WMarN\r\nn+9GFRiE0d2G/Rem/Nno/YRjImBverPoOkwSbQmyP0MgCQyTPPRXlU+KP6acuwEG\r\nE52Jztf0j1TZ2liDf9k6TtHKEqzmf/ZALPSDsfplP36ZyjgTYCnvAgMBAAGgADAN\r\nBgkqhkiG9w0BAQsFAAOCAQEAM4gJgBZow3sMlaTSptU6/3vE7XXWUWsheTrylIAt\r\nVKscCrJ/NsWVLLegS2M8WTL5DaAyPTqy/iGJzJbxdcGSTfwxuLVIlkDtpvpQ1jjN\r\nz9+D/nSeo6CORDCPUacNyi6wq8E5iCtJlwy29Q+zW9IBUHJ6lb++cOQOBm+c3mjL\r\niRc/UDB+X10QYhHV8dysqLasi4cUmWp5Od+7lajMDeLbQEy8P4TeymEzsTjaZDxY\r\nw5D65RGwtoHgRINx5yJDTbhDJkEuinpSVe/svjy/rhNj1GxZabcEwf0V9Sw4Bl6V\r\nUZg41dRsyRgRlCsfbMRSy3lonTpvLnxCEZ1IkELQpAGk2Q==\r\n-----END CERTIFICATE REQUEST-----\r\n", + "DomainName": null, + "WebServerType": "Other", + "isCUOrder": false, + "AutoWWW": true, + "isRenewalOrder": false, + "SpecialInstructions": null, + "isTrialOrder": false, + "AdminContact": { + "FirstName": null, + "LastName": null, + "SubjectFirstName": null, + "SubjectLastName": null, + "Phone": null, + "Fax": null, + "Email": "admin@boingy.com", + "Title": null, + "OrganizationName": null, + "AddressLine1": null, + "AddressLine2": null, + "City": null, + "Region": null, + "PostalCode": null, + "Country": null + }, + "TechnicalContact": { + "FirstName": null, + "LastName": null, + "SubjectFirstName": null, + "SubjectLastName": null, + "Phone": null, + "Fax": null, + "Email": null, + "Title": null, + "OrganizationName": null, + "AddressLine1": null, + "AddressLine2": null, + "City": null, + "Region": null, + "PostalCode": null, + "Country": null + }, + "ApproverEmail": "brian@boingy.com", + "ReserveSANCount": 0, + "AddInstallationSupport": false, + "FileAuthDVIndicator": false, + "CNAMEAuthDVIndicator": false, + "HTTPSFileAuthDVIndicator": false, + "SignatureHashAlgorithm": "PREFER_SHA2", + "CertTransparencyIndicator": false, + "RenewalDays": 0, + "isPKCS10": false, + "WildcardReserveSANCount": 0 +} \ No newline at end of file diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index 42fb2d3..9c31cc1 100644 --- a/SslStoreCaProxy/RequestManager.cs +++ b/SslStoreCaProxy/RequestManager.cs @@ -335,8 +335,9 @@ private long ConvertDaysToMonths(EnrollmentProductInfo productInfo) if (productInfo.ProductParameters.ContainsKey("Validity Period (In Days)") && long.TryParse(productInfo.ProductParameters["Validity Period (In Days)"], out var days)) { - // Convert days to months, rounding up so short-lived certs (e.g. 90 days) get at least 1 month - var months = (long)Math.Ceiling(days / 30.0); + // Round to nearest standard month value (30.44 days/month average) + // SSL Store only accepts specific values like 1, 3, 6, 12, 24, 36, etc. + var months = Math.Max(1, (long)Math.Round(days / 30.44)); _logger.LogTrace($"Validity conversion: {days} days -> {months} months"); return months; } diff --git a/SslStoreCaProxy/SslStoreRequest.json b/SslStoreCaProxy/SslStoreRequest.json new file mode 100644 index 0000000..ba6a0d2 --- /dev/null +++ b/SslStoreCaProxy/SslStoreRequest.json @@ -0,0 +1,67 @@ +{ + "AuthRequest": { + "PartnerCode": "82919874", + "AuthToken": "B76586C757D226D874D9DB82388EF70E", + "IsUsedForTokenSystem": false + }, + "CustomOrderID": "2edb6de2-5a4f-4a75-aca8-dae8e73f12fe", + "ProductCode": "positivessl", + "OrganizationInfo": { + "OrganizationName":null, + "JurisdictionCountry":null, + "OrganizationAddress": { + "AddressLine1":null, + "Region":null, + "PostalCode":null, + "Country":null, + "Phone":null, + "LocalityName":null + } + }, + "TSSOrganizationId": 0, + "ValidityPeriod": 13, + "ServerCount": 1, + "CSR": "-----BEGIN CERTIFICATE REQUEST-----\r\nMIICXjCCAUYCAQAwGTEXMBUGA1UEAwwOd3d3LmJvaW5neS5jb20wggEiMA0GCSqG\r\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCNtXaXt5SR+l8VCguwvbGErdWy5VqJd1j8\r\nTYUACDV+9P/BrgIbTC1J9iLUfF1OXIM5Q4fMpBew+Yowd75CO8VwDsEVdtKGB8F+\r\nqr7xpuKAQTjUaeqVSqRQe6L7cc4y1OijHftFowLmNugmFsac/dXWMTF/tv2esTra\r\nIwFXaSUQwdEXvsNG/39zVu7R1Q/9LMvu2E7YzeXsjW95/kEHjhLMpdvRRJn762M2\r\nyPPMXmngNdYg05XEyMvE+0N23C70942C5zeZbAIaBQCFpTsYF3AhXemt0G5gq1/Q\r\nxXUFavL1j8JCB8jJvDPKH7eNZsmWSDvel2bWllsaoPsQosF3HGG1AgMBAAGgADAN\r\nBgkqhkiG9w0BAQsFAAOCAQEAFlGDPta4UQ0EdkLhDNUkuWytHxVZE+fMrKtQgxFA\r\nSCDjYhWzaPYcYd8RXMstUSk/yBES4dwOnEVrwM4RmdJFqG57pnUddKExUt1V74Ho\r\npEqfxjKl0l1KFqL3s+bcftNsLW33+aYuAkpk7pXx/rvpbz3zE3rH/s30j+2GEhzN\r\n4RrSu6U5xM7BJ87IB/sFYwee72OE5FRAho1Y/3JJnHjmXkydao7aBYNwVenB3X76\r\nEHPtrAuvRWQ3oJiXUD28Sg0B440LANSaS7Wi7nkYHTU6LZo1l9wRAcblalzhMDWQ\r\nFEN2Z2q268XI4rSQ/fouFymLyu+nMo1jd3JrHkLKt7yj1Q==\r\n-----END CERTIFICATE REQUEST-----\r\n", + "DomainName": "www.boingy.com", + "WebServerType": "Other", + "DNSNames": [], + "isCUOrder": false, + "isRenewalOrder": false, + "isTrialOrder": false, + "AdminContact": { + "FirstName":null, + "LastName":null, + "Phone":null, + "Email": "admin@boingy.com", + "Title":null, + "OrganizationName":null, + "AddressLine1":null, + "City":null, + "Region":null, + "PostalCode":null, + "Country":null + }, + "TechnicalContact": { + "FirstName":null, + "LastName":null, + "Phone":null, + "Email":null, + "OrganizationName":null, + "AddressLine1":null, + "City":null, + "Region":null, + "PostalCode":null, + "Country":null + }, + "ApproverEmail": "admin@boingy.com", + "ReserveSANCount": 0, + "AddInstallationSupport": false, + "FileAuthDVIndicator": false, + "CNAMEAuthDVIndicator": false, + "HTTPSFileAuthDVIndicator": false, + "SignatureHashAlgorithm": "PREFER_SHA2", + "CertTransparencyIndicator": false, + "RenewalDays": 0, + "isPKCS10": false, + "WildcardReserveSANCount": 0 +} \ No newline at end of file From 11a7a1c4d95f490f024e2689659bcc20dd1c9bfb Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Wed, 18 Mar 2026 11:40:13 -0400 Subject: [PATCH 10/42] delete unnneed files --- SslStoreCaProxy/DcomJson.json | 189 ------------------------- SslStoreCaProxy/SslStoreCaProxy.csproj | 4 +- SslStoreCaProxy/SslStoreRequest.json | 67 --------- 3 files changed, 3 insertions(+), 257 deletions(-) delete mode 100644 SslStoreCaProxy/DcomJson.json delete mode 100644 SslStoreCaProxy/SslStoreRequest.json diff --git a/SslStoreCaProxy/DcomJson.json b/SslStoreCaProxy/DcomJson.json deleted file mode 100644 index c578862..0000000 --- a/SslStoreCaProxy/DcomJson.json +++ /dev/null @@ -1,189 +0,0 @@ -{ - "AuthRequest": { - "PartnerCode": "82919874", - "AuthToken": "B76586C757D226D874D9DB82388EF70E", - "ReplayToken": null, - "UserAgent": null, - "TokenID": null, - "TokenCode": null, - "IPAddress": null, - "IsUsedForTokenSystem": false, - "Token": null - }, - "CustomOrderID": "08cc122e-4b54-438e-94eb-3db56d848b8e", - "ProductCode": "positivessl", - "OrganizationInfo": { - "OrganizationName": null, - "DUNS": null, - "Division": null, - "IncorporatingAgency": null, - "RegistrationNumber": null, - "JurisdictionCity": null, - "JurisdictionRegion": null, - "JurisdictionCountry": null, - "AssumedName": null, - "OrganizationAddress": { - "AddressLine1": null, - "AddressLine2": null, - "AddressLine3": null, - "City": null, - "Region": null, - "PostalCode": null, - "Country": null, - "Phone": null, - "Fax": null, - "LocalityName": null - } - }, - "TSSOrganizationId": 0, - "ValidityPeriod": 12, - "ServerCount": 1, - "CSR": "-----BEGIN CERTIFICATE REQUEST-----\r\nMIICXjCCAUYCAQAwGTEXMBUGA1UEAwwOd3d3LmJvaW5neS5jb20wggEiMA0GCSqG\r\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2VBd7Xz6GZdLRVIJPkcwBCMhxct/UvYlU\r\n1k3JV/OIQzpERoMx99M5MM/8Mjsu8QhihN5ji9TIMwaDlL34DWKLJBMlSy6Bttzi\r\nvowRz6mxXi2sTdkZ+1ow1K7tGA04iqvA9RFYdPqSqYSZl+r98aY/9QGALThKmw0i\r\nqBeiRemAxjfcyTJTv7gner/JaB40wksEhZK5bhACG5TxddN30pjfKTcg0g5WMarN\r\nn+9GFRiE0d2G/Rem/Nno/YRjImBverPoOkwSbQmyP0MgCQyTPPRXlU+KP6acuwEG\r\nE52Jztf0j1TZ2liDf9k6TtHKEqzmf/ZALPSDsfplP36ZyjgTYCnvAgMBAAGgADAN\r\nBgkqhkiG9w0BAQsFAAOCAQEAM4gJgBZow3sMlaTSptU6/3vE7XXWUWsheTrylIAt\r\nVKscCrJ/NsWVLLegS2M8WTL5DaAyPTqy/iGJzJbxdcGSTfwxuLVIlkDtpvpQ1jjN\r\nz9+D/nSeo6CORDCPUacNyi6wq8E5iCtJlwy29Q+zW9IBUHJ6lb++cOQOBm+c3mjL\r\niRc/UDB+X10QYhHV8dysqLasi4cUmWp5Od+7lajMDeLbQEy8P4TeymEzsTjaZDxY\r\nw5D65RGwtoHgRINx5yJDTbhDJkEuinpSVe/svjy/rhNj1GxZabcEwf0V9Sw4Bl6V\r\nUZg41dRsyRgRlCsfbMRSy3lonTpvLnxCEZ1IkELQpAGk2Q==\r\n-----END CERTIFICATE REQUEST-----\r\n", - "DomainName": null, - "WebServerType": "Other", - "isCUOrder": false, - "AutoWWW": true, - "isRenewalOrder": false, - "SpecialInstructions": null, - "isTrialOrder": false, - "AdminContact": { - "FirstName": null, - "LastName": null, - "SubjectFirstName": null, - "SubjectLastName": null, - "Phone": null, - "Fax": null, - "Email": "admin@boingy.com", - "Title": null, - "OrganizationName": null, - "AddressLine1": null, - "AddressLine2": null, - "City": null, - "Region": null, - "PostalCode": null, - "Country": null - }, - "TechnicalContact": { - "FirstName": null, - "LastName": null, - "SubjectFirstName": null, - "SubjectLastName": null, - "Phone": null, - "Fax": null, - "Email": null, - "Title": null, - "OrganizationName": null, - "AddressLine1": null, - "AddressLine2": null, - "City": null, - "Region": null, - "PostalCode": null, - "Country": null - }, - "ApproverEmail": "brian@boingy.com", - "ReserveSANCount": 0, - "AddInstallationSupport": false, - "FileAuthDVIndicator": false, - "CNAMEAuthDVIndicator": false, - "HTTPSFileAuthDVIndicator": false, - "SignatureHashAlgorithm": "PREFER_SHA2", - "CertTransparencyIndicator": false, - "RenewalDays": 0, - "isPKCS10": false, - "WildcardReserveSANCount": 0 -} -2026-03-18 14: 15: 27.2587 Keyfactor.AnyGateway.SslStore.Client.SslStoreClient [Trace -] - { - "AuthRequest": { - "PartnerCode": "82919874", - "AuthToken": "B76586C757D226D874D9DB82388EF70E", - "ReplayToken": null, - "UserAgent": null, - "TokenID": null, - "TokenCode": null, - "IPAddress": null, - "IsUsedForTokenSystem": false, - "Token": null - }, - "CustomOrderID": "08cc122e-4b54-438e-94eb-3db56d848b8e", - "ProductCode": "positivessl", - "OrganizationInfo": { - "OrganizationName": null, - "DUNS": null, - "Division": null, - "IncorporatingAgency": null, - "RegistrationNumber": null, - "JurisdictionCity": null, - "JurisdictionRegion": null, - "JurisdictionCountry": null, - "AssumedName": null, - "OrganizationAddress": { - "AddressLine1": null, - "AddressLine2": null, - "AddressLine3": null, - "City": null, - "Region": null, - "PostalCode": null, - "Country": null, - "Phone": null, - "Fax": null, - "LocalityName": null - } - }, - "TSSOrganizationId": 0, - "ValidityPeriod": 12, - "ServerCount": 1, - "CSR": "-----BEGIN CERTIFICATE REQUEST-----\r\nMIICXjCCAUYCAQAwGTEXMBUGA1UEAwwOd3d3LmJvaW5neS5jb20wggEiMA0GCSqG\r\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2VBd7Xz6GZdLRVIJPkcwBCMhxct/UvYlU\r\n1k3JV/OIQzpERoMx99M5MM/8Mjsu8QhihN5ji9TIMwaDlL34DWKLJBMlSy6Bttzi\r\nvowRz6mxXi2sTdkZ+1ow1K7tGA04iqvA9RFYdPqSqYSZl+r98aY/9QGALThKmw0i\r\nqBeiRemAxjfcyTJTv7gner/JaB40wksEhZK5bhACG5TxddN30pjfKTcg0g5WMarN\r\nn+9GFRiE0d2G/Rem/Nno/YRjImBverPoOkwSbQmyP0MgCQyTPPRXlU+KP6acuwEG\r\nE52Jztf0j1TZ2liDf9k6TtHKEqzmf/ZALPSDsfplP36ZyjgTYCnvAgMBAAGgADAN\r\nBgkqhkiG9w0BAQsFAAOCAQEAM4gJgBZow3sMlaTSptU6/3vE7XXWUWsheTrylIAt\r\nVKscCrJ/NsWVLLegS2M8WTL5DaAyPTqy/iGJzJbxdcGSTfwxuLVIlkDtpvpQ1jjN\r\nz9+D/nSeo6CORDCPUacNyi6wq8E5iCtJlwy29Q+zW9IBUHJ6lb++cOQOBm+c3mjL\r\niRc/UDB+X10QYhHV8dysqLasi4cUmWp5Od+7lajMDeLbQEy8P4TeymEzsTjaZDxY\r\nw5D65RGwtoHgRINx5yJDTbhDJkEuinpSVe/svjy/rhNj1GxZabcEwf0V9Sw4Bl6V\r\nUZg41dRsyRgRlCsfbMRSy3lonTpvLnxCEZ1IkELQpAGk2Q==\r\n-----END CERTIFICATE REQUEST-----\r\n", - "DomainName": null, - "WebServerType": "Other", - "isCUOrder": false, - "AutoWWW": true, - "isRenewalOrder": false, - "SpecialInstructions": null, - "isTrialOrder": false, - "AdminContact": { - "FirstName": null, - "LastName": null, - "SubjectFirstName": null, - "SubjectLastName": null, - "Phone": null, - "Fax": null, - "Email": "admin@boingy.com", - "Title": null, - "OrganizationName": null, - "AddressLine1": null, - "AddressLine2": null, - "City": null, - "Region": null, - "PostalCode": null, - "Country": null - }, - "TechnicalContact": { - "FirstName": null, - "LastName": null, - "SubjectFirstName": null, - "SubjectLastName": null, - "Phone": null, - "Fax": null, - "Email": null, - "Title": null, - "OrganizationName": null, - "AddressLine1": null, - "AddressLine2": null, - "City": null, - "Region": null, - "PostalCode": null, - "Country": null - }, - "ApproverEmail": "brian@boingy.com", - "ReserveSANCount": 0, - "AddInstallationSupport": false, - "FileAuthDVIndicator": false, - "CNAMEAuthDVIndicator": false, - "HTTPSFileAuthDVIndicator": false, - "SignatureHashAlgorithm": "PREFER_SHA2", - "CertTransparencyIndicator": false, - "RenewalDays": 0, - "isPKCS10": false, - "WildcardReserveSANCount": 0 -} \ No newline at end of file diff --git a/SslStoreCaProxy/SslStoreCaProxy.csproj b/SslStoreCaProxy/SslStoreCaProxy.csproj index 38fbab3..303fdcd 100644 --- a/SslStoreCaProxy/SslStoreCaProxy.csproj +++ b/SslStoreCaProxy/SslStoreCaProxy.csproj @@ -1,6 +1,6 @@ - net6.0;net8.0 + net6.0;net8.0;net10.0 disable true false @@ -8,10 +8,12 @@ SslStoreCaProxy + + diff --git a/SslStoreCaProxy/SslStoreRequest.json b/SslStoreCaProxy/SslStoreRequest.json deleted file mode 100644 index ba6a0d2..0000000 --- a/SslStoreCaProxy/SslStoreRequest.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "AuthRequest": { - "PartnerCode": "82919874", - "AuthToken": "B76586C757D226D874D9DB82388EF70E", - "IsUsedForTokenSystem": false - }, - "CustomOrderID": "2edb6de2-5a4f-4a75-aca8-dae8e73f12fe", - "ProductCode": "positivessl", - "OrganizationInfo": { - "OrganizationName":null, - "JurisdictionCountry":null, - "OrganizationAddress": { - "AddressLine1":null, - "Region":null, - "PostalCode":null, - "Country":null, - "Phone":null, - "LocalityName":null - } - }, - "TSSOrganizationId": 0, - "ValidityPeriod": 13, - "ServerCount": 1, - "CSR": "-----BEGIN CERTIFICATE REQUEST-----\r\nMIICXjCCAUYCAQAwGTEXMBUGA1UEAwwOd3d3LmJvaW5neS5jb20wggEiMA0GCSqG\r\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCNtXaXt5SR+l8VCguwvbGErdWy5VqJd1j8\r\nTYUACDV+9P/BrgIbTC1J9iLUfF1OXIM5Q4fMpBew+Yowd75CO8VwDsEVdtKGB8F+\r\nqr7xpuKAQTjUaeqVSqRQe6L7cc4y1OijHftFowLmNugmFsac/dXWMTF/tv2esTra\r\nIwFXaSUQwdEXvsNG/39zVu7R1Q/9LMvu2E7YzeXsjW95/kEHjhLMpdvRRJn762M2\r\nyPPMXmngNdYg05XEyMvE+0N23C70942C5zeZbAIaBQCFpTsYF3AhXemt0G5gq1/Q\r\nxXUFavL1j8JCB8jJvDPKH7eNZsmWSDvel2bWllsaoPsQosF3HGG1AgMBAAGgADAN\r\nBgkqhkiG9w0BAQsFAAOCAQEAFlGDPta4UQ0EdkLhDNUkuWytHxVZE+fMrKtQgxFA\r\nSCDjYhWzaPYcYd8RXMstUSk/yBES4dwOnEVrwM4RmdJFqG57pnUddKExUt1V74Ho\r\npEqfxjKl0l1KFqL3s+bcftNsLW33+aYuAkpk7pXx/rvpbz3zE3rH/s30j+2GEhzN\r\n4RrSu6U5xM7BJ87IB/sFYwee72OE5FRAho1Y/3JJnHjmXkydao7aBYNwVenB3X76\r\nEHPtrAuvRWQ3oJiXUD28Sg0B440LANSaS7Wi7nkYHTU6LZo1l9wRAcblalzhMDWQ\r\nFEN2Z2q268XI4rSQ/fouFymLyu+nMo1jd3JrHkLKt7yj1Q==\r\n-----END CERTIFICATE REQUEST-----\r\n", - "DomainName": "www.boingy.com", - "WebServerType": "Other", - "DNSNames": [], - "isCUOrder": false, - "isRenewalOrder": false, - "isTrialOrder": false, - "AdminContact": { - "FirstName":null, - "LastName":null, - "Phone":null, - "Email": "admin@boingy.com", - "Title":null, - "OrganizationName":null, - "AddressLine1":null, - "City":null, - "Region":null, - "PostalCode":null, - "Country":null - }, - "TechnicalContact": { - "FirstName":null, - "LastName":null, - "Phone":null, - "Email":null, - "OrganizationName":null, - "AddressLine1":null, - "City":null, - "Region":null, - "PostalCode":null, - "Country":null - }, - "ApproverEmail": "admin@boingy.com", - "ReserveSANCount": 0, - "AddInstallationSupport": false, - "FileAuthDVIndicator": false, - "CNAMEAuthDVIndicator": false, - "HTTPSFileAuthDVIndicator": false, - "SignatureHashAlgorithm": "PREFER_SHA2", - "CertTransparencyIndicator": false, - "RenewalDays": 0, - "isPKCS10": false, - "WildcardReserveSANCount": 0 -} \ No newline at end of file From 4ab1f57c8b4035047c07cb4854f3fe1e575f96d8 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Wed, 18 Mar 2026 11:54:04 -0400 Subject: [PATCH 11/42] fixed order issue --- SslStoreCaProxy/SslStoreCaProxy.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs index 5fdd4c3..a2d5104 100644 --- a/SslStoreCaProxy/SslStoreCaProxy.cs +++ b/SslStoreCaProxy/SslStoreCaProxy.cs @@ -283,11 +283,18 @@ private EnrollmentResult GetEnrollmentResult(INewOrderResponse newOrderResponse) }; } + var majorStatus = newOrderResponse?.OrderStatus?.MajorStatus; + var status = _requestManager.MapReturnStatus(majorStatus); + var orderId = newOrderResponse?.TheSslStoreOrderId; + + _logger.LogTrace($"Order {orderId} status: {majorStatus} -> mapped to {status}"); _logger.MethodExit(); + return new EnrollmentResult { - Status = (int)EndEntityStatus.GENERATED, - StatusMessage = $"Order Successfully Created With Order Number {newOrderResponse?.TheSslStoreOrderId}" + CARequestID = orderId, + Status = status, + StatusMessage = $"Order Successfully Created With Order Number {orderId}" }; } From 3f0cab37e08e7b86841559eee7016281b1c29adb Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Wed, 18 Mar 2026 14:53:06 -0400 Subject: [PATCH 12/42] fixed external status --- SslStoreCaProxy/RequestManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index 9c31cc1..45dfbcd 100644 --- a/SslStoreCaProxy/RequestManager.cs +++ b/SslStoreCaProxy/RequestManager.cs @@ -184,7 +184,7 @@ public int MapReturnStatus(string sslStoreStatus) return (int)EndEntityStatus.GENERATED; case "Initial": case "Pending": - return (int)EndEntityStatus.INPROCESS; + return (int)EndEntityStatus.EXTERNALVALIDATION; case "Cancelled": return (int)EndEntityStatus.REVOKED; default: From 61759509b7aa44b51d5409d60aac0133d20800d9 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Wed, 18 Mar 2026 15:57:58 -0400 Subject: [PATCH 13/42] fixed renewal window issues --- SslStoreCaProxy/SslStoreCAPluginConfig.cs | 9 +++++++ SslStoreCaProxy/SslStoreCaProxy.cs | 32 ++++++++++++++++++----- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/SslStoreCaProxy/SslStoreCAPluginConfig.cs b/SslStoreCaProxy/SslStoreCAPluginConfig.cs index c520a10..2c375a9 100644 --- a/SslStoreCaProxy/SslStoreCAPluginConfig.cs +++ b/SslStoreCaProxy/SslStoreCAPluginConfig.cs @@ -14,6 +14,7 @@ public class ConfigConstants public static string AuthToken = "AuthToken"; public static string PageSize = "PageSize"; public static string Enabled = "Enabled"; + public static string RenewalWindow = "RenewalWindow"; } public class Config @@ -23,6 +24,7 @@ public class Config public string AuthToken { get; set; } public int PageSize { get; set; } = DefaultPageSize; public bool Enabled { get; set; } + public int RenewalWindow { get; set; } = 30; } public static Dictionary GetPluginAnnotations() @@ -63,6 +65,13 @@ public static Dictionary GetPluginAnnotations() Hidden = false, DefaultValue = true, Type = "Bool" + }, + [ConfigConstants.RenewalWindow] = new PropertyConfigInfo() + { + Comments = "Number of days before order expiry to trigger a renewal instead of a reissue.", + Hidden = false, + DefaultValue = 30, + Type = "Number" } }; } diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs index a2d5104..3e9d8d1 100644 --- a/SslStoreCaProxy/SslStoreCaProxy.cs +++ b/SslStoreCaProxy/SslStoreCaProxy.cs @@ -28,6 +28,7 @@ public class SslStoreCaProxy : IAnyCAPlugin public string PartnerCode { get; set; } public string AuthenticationToken { get; set; } public int PageSize { get; set; } + public int RenewalWindow { get; set; } public void Initialize(IAnyCAPluginConfigProvider configProvider, ICertificateDataReader certificateDataReader) { @@ -42,6 +43,7 @@ public void Initialize(IAnyCAPluginConfigProvider configProvider, ICertificateDa PartnerCode = _config.PartnerCode; AuthenticationToken = _config.AuthToken; PageSize = _config.PageSize > 0 ? _config.PageSize : SslStoreCAPluginConfig.DefaultPageSize; + RenewalWindow = _config.RenewalWindow > 0 ? _config.RenewalWindow : 30; _requestManager = new RequestManager(this); @@ -245,16 +247,32 @@ public async Task Enroll(string csr, string subject, Dictionar var orderStatusResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); _logger.LogTrace($"orderStatusResponse JSON {JsonConvert.SerializeObject(orderStatusResponse)}"); - // Try renewal first, fall back to reissue - var renewRequest = _requestManager.GetRenewalRequest(orderStatusResponse, csr); - _logger.LogTrace($"renewRequest JSON {JsonConvert.SerializeObject(renewRequest)}"); + // Determine renewal vs reissue based on order expiry and RenewalWindow + var shouldRenew = false; + if (DateTime.TryParse(orderStatusResponse.OrderExpiryDateInUtc, out var orderExpiry)) + { + var daysUntilOrderExpiry = (orderExpiry - DateTime.UtcNow).TotalDays; + _logger.LogTrace($"Order expiry: {orderExpiry:u}, days remaining: {daysUntilOrderExpiry:F0}, renewal window: {RenewalWindow} days"); + shouldRenew = daysUntilOrderExpiry <= RenewalWindow; + } + else + { + _logger.LogWarning($"Could not parse OrderExpiryDateInUTC '{orderStatusResponse.OrderExpiryDateInUtc}', defaulting to renewal"); + shouldRenew = true; + } - enrollmentResponse = await client.SubmitRenewRequestAsync(renewRequest); - _logger.LogTrace($"enrollmentResponse JSON {JsonConvert.SerializeObject(enrollmentResponse)}"); + if (shouldRenew) + { + _logger.LogTrace("Order is within renewal window, performing renewal (new order)..."); + var renewRequest = _requestManager.GetRenewalRequest(orderStatusResponse, csr); + _logger.LogTrace($"renewRequest JSON {JsonConvert.SerializeObject(renewRequest)}"); - if (enrollmentResponse != null && enrollmentResponse.AuthResponse != null && enrollmentResponse.AuthResponse.IsError) + enrollmentResponse = await client.SubmitRenewRequestAsync(renewRequest); + _logger.LogTrace($"enrollmentResponse JSON {JsonConvert.SerializeObject(enrollmentResponse)}"); + } + else { - _logger.LogTrace("Renewal failed, attempting reissue..."); + _logger.LogTrace("Order has life remaining, performing reissue (same order)..."); var reIssueRequest = _requestManager.GetReIssueRequest(orderStatusResponse, csr, false); _logger.LogTrace($"reIssueRequest JSON {JsonConvert.SerializeObject(reIssueRequest)}"); From c742f574f65c1acddc533275e3f7c2f85357a94d Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Wed, 18 Mar 2026 17:07:05 -0400 Subject: [PATCH 14/42] fixed everything to use CustomOrderId --- .../Models/DownloadCertificateRequest.cs | 7 ++-- .../Client/Models/OrderStatusRequest.cs | 7 ++-- .../Client/Models/ReIssueRequest.cs | 1 + .../Client/Models/RevokeOrderRequest.cs | 7 ++-- SslStoreCaProxy/RequestManager.cs | 23 +++++++++---- SslStoreCaProxy/SslStoreCaProxy.cs | 32 +++++++++---------- 6 files changed, 46 insertions(+), 31 deletions(-) diff --git a/SslStoreCaProxy/Client/Models/DownloadCertificateRequest.cs b/SslStoreCaProxy/Client/Models/DownloadCertificateRequest.cs index 23de171..76b3439 100644 --- a/SslStoreCaProxy/Client/Models/DownloadCertificateRequest.cs +++ b/SslStoreCaProxy/Client/Models/DownloadCertificateRequest.cs @@ -1,4 +1,4 @@ -using Keyfactor.AnyGateway.SslStore.Interfaces; +using Keyfactor.AnyGateway.SslStore.Interfaces; using Newtonsoft.Json; namespace Keyfactor.AnyGateway.SslStore.Client.Models @@ -6,6 +6,7 @@ namespace Keyfactor.AnyGateway.SslStore.Client.Models public class DownloadCertificateRequest : IDownloadCertificateRequest { public AuthRequest AuthRequest { get; set; } - [JsonProperty("TheSSLStoreOrderID")] public string TheSslStoreOrderId { get; set; } + [JsonProperty("TheSSLStoreOrderID", NullValueHandling = NullValueHandling.Ignore)] public string TheSslStoreOrderId { get; set; } + [JsonProperty("CustomOrderID", NullValueHandling = NullValueHandling.Ignore)] public string CustomOrderId { get; set; } } -} \ No newline at end of file +} diff --git a/SslStoreCaProxy/Client/Models/OrderStatusRequest.cs b/SslStoreCaProxy/Client/Models/OrderStatusRequest.cs index 81ac958..f69cc76 100644 --- a/SslStoreCaProxy/Client/Models/OrderStatusRequest.cs +++ b/SslStoreCaProxy/Client/Models/OrderStatusRequest.cs @@ -1,4 +1,4 @@ -using Keyfactor.AnyGateway.SslStore.Interfaces; +using Keyfactor.AnyGateway.SslStore.Interfaces; using Newtonsoft.Json; namespace Keyfactor.AnyGateway.SslStore.Client.Models @@ -6,6 +6,7 @@ namespace Keyfactor.AnyGateway.SslStore.Client.Models public class OrderStatusRequest : IOrderStatusRequest { public AuthRequest AuthRequest { get; set; } - [JsonProperty("TheSSLStoreOrderID")] public string TheSslStoreOrderId { get; set; } + [JsonProperty("TheSSLStoreOrderID", NullValueHandling = NullValueHandling.Ignore)] public string TheSslStoreOrderId { get; set; } + [JsonProperty("CustomOrderID", NullValueHandling = NullValueHandling.Ignore)] public string CustomOrderId { get; set; } } -} \ No newline at end of file +} diff --git a/SslStoreCaProxy/Client/Models/ReIssueRequest.cs b/SslStoreCaProxy/Client/Models/ReIssueRequest.cs index 17c55b3..d1aaf66 100644 --- a/SslStoreCaProxy/Client/Models/ReIssueRequest.cs +++ b/SslStoreCaProxy/Client/Models/ReIssueRequest.cs @@ -8,6 +8,7 @@ public class ReIssueRequest : IReIssueRequest { public AuthRequest AuthRequest { get; set; } [JsonProperty("TheSSLStoreOrderID")] public string TheSslStoreOrderId { get; set; } + [JsonProperty("CustomOrderID", NullValueHandling = NullValueHandling.Ignore)] public string CustomOrderId { get; set; } [JsonProperty("CSR")] public string Csr { get; set; } public string WebServerType { get; set; } [JsonProperty("DNSNames")] public List DnsNames { get; set; } diff --git a/SslStoreCaProxy/Client/Models/RevokeOrderRequest.cs b/SslStoreCaProxy/Client/Models/RevokeOrderRequest.cs index 2e71652..8faf24b 100644 --- a/SslStoreCaProxy/Client/Models/RevokeOrderRequest.cs +++ b/SslStoreCaProxy/Client/Models/RevokeOrderRequest.cs @@ -1,4 +1,4 @@ -using Keyfactor.AnyGateway.SslStore.Interfaces; +using Keyfactor.AnyGateway.SslStore.Interfaces; using Newtonsoft.Json; namespace Keyfactor.AnyGateway.SslStore.Client.Models @@ -6,7 +6,8 @@ namespace Keyfactor.AnyGateway.SslStore.Client.Models public class RevokeOrderRequest : IRevokeOrderRequest { public AuthRequest AuthRequest { get; set; } - [JsonProperty("TheSSLStoreOrderID")] public string TheSslStoreOrderId { get; set; } + [JsonProperty("TheSSLStoreOrderID", NullValueHandling = NullValueHandling.Ignore)] public string TheSslStoreOrderId { get; set; } + [JsonProperty("CustomOrderID", NullValueHandling = NullValueHandling.Ignore)] public string CustomOrderId { get; set; } public string SerialNumber { get; set; } } -} \ No newline at end of file +} diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index 45dfbcd..827693b 100644 --- a/SslStoreCaProxy/RequestManager.cs +++ b/SslStoreCaProxy/RequestManager.cs @@ -86,6 +86,7 @@ public ReIssueRequest GetReIssueRequest(INewOrderResponse orderData, string csr, { AuthRequest = GetAuthRequest(), TheSslStoreOrderId = orderData.TheSslStoreOrderId, + CustomOrderId = Guid.NewGuid().ToString(), Csr = csr, IsRenewalOrder = isRenewal, IsWildCard = orderData.ProductCode.Contains("wc") || orderData.ProductCode.Contains("wildcard"), @@ -132,21 +133,21 @@ public TechnicalContact GetTechnicalContact(EnrollmentProductInfo productInfo) }; } - public DownloadCertificateRequest GetCertificateRequest(string theSslStoreOrderId) + public DownloadCertificateRequest GetCertificateRequest(string customOrderId) { return new DownloadCertificateRequest { AuthRequest = GetAuthRequest(), - TheSslStoreOrderId = theSslStoreOrderId + CustomOrderId = customOrderId }; } - public RevokeOrderRequest GetRevokeOrderRequest(string theSslStoreOrderId) + public RevokeOrderRequest GetRevokeOrderRequest(string customOrderId) { return new RevokeOrderRequest { AuthRequest = GetAuthRequest(), - TheSslStoreOrderId = theSslStoreOrderId + CustomOrderId = customOrderId }; } @@ -167,12 +168,21 @@ public QueryOrderRequest GetQueryOrderRequest(int pageSize, int pageNumber) }; } - public OrderStatusRequest GetOrderStatusRequest(string theSslStoreId) + public OrderStatusRequest GetOrderStatusRequest(string customOrderId) + { + return new OrderStatusRequest + { + AuthRequest = GetAuthRequest(), + CustomOrderId = customOrderId + }; + } + + public OrderStatusRequest GetOrderStatusRequestBySslStoreId(string theSslStoreOrderId) { return new OrderStatusRequest { AuthRequest = GetAuthRequest(), - TheSslStoreOrderId = theSslStoreId + TheSslStoreOrderId = theSslStoreOrderId }; } @@ -197,6 +207,7 @@ public NewOrderRequest GetRenewalRequest(INewOrderResponse orderData, string csr return new NewOrderRequest { AuthRequest = GetAuthRequest(), + CustomOrderId = Guid.NewGuid().ToString(), RelatedTheSslStoreOrderId = orderData.TheSslStoreOrderId, ProductCode = orderData.ProductCode, AdminContact = GetAdminContact(orderData), diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs index 3e9d8d1..f878779 100644 --- a/SslStoreCaProxy/SslStoreCaProxy.cs +++ b/SslStoreCaProxy/SslStoreCaProxy.cs @@ -127,7 +127,7 @@ public Dictionary GetTemplateParameterAnnotations() public async Task Revoke(string caRequestId, string hexSerialNumber, uint revocationReason) { _logger.MethodEntry(); - var revokeOrderRequest = _requestManager.GetRevokeOrderRequest(caRequestId.Split('-')[0]); + var revokeOrderRequest = _requestManager.GetRevokeOrderRequest(caRequestId); _logger.LogTrace($"Revoke Request JSON {JsonConvert.SerializeObject(revokeOrderRequest)}"); try { @@ -238,10 +238,9 @@ public async Task Enroll(string csr, string subject, Dictionar _logger.LogTrace($"Prior Cert Serial Number: {sn}"); var caRequestId = await _certDataReader.GetRequestIDBySerialNumber(sn); - _logger.LogTrace($"Prior CA Request ID: {caRequestId}"); + _logger.LogTrace($"Prior CA Request ID (CustomOrderId): {caRequestId}"); - var orderId = caRequestId.Split('-')[0]; - var orderStatusRequest = _requestManager.GetOrderStatusRequest(orderId); + var orderStatusRequest = _requestManager.GetOrderStatusRequest(caRequestId); _logger.LogTrace($"orderStatusRequest JSON {JsonConvert.SerializeObject(orderStatusRequest)}"); var orderStatusResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); @@ -303,7 +302,7 @@ private EnrollmentResult GetEnrollmentResult(INewOrderResponse newOrderResponse) var majorStatus = newOrderResponse?.OrderStatus?.MajorStatus; var status = _requestManager.MapReturnStatus(majorStatus); - var orderId = newOrderResponse?.TheSslStoreOrderId; + var orderId = newOrderResponse?.CustomOrderId; _logger.LogTrace($"Order {orderId} status: {majorStatus} -> mapped to {status}"); _logger.MethodExit(); @@ -357,17 +356,25 @@ public async Task Synchronize(BlockingCollection blockin try { - _logger.LogTrace($"Took Certificate ID {currentResponseItem?.TheSslStoreOrderId} from Queue"); + _logger.LogTrace($"Took Certificate ID {currentResponseItem?.TheSslStoreOrderId} (CustomOrderId: {currentResponseItem?.CustomOrderId}) from Queue"); - var orderStatusRequest = _requestManager.GetOrderStatusRequest(currentResponseItem?.TheSslStoreOrderId); + // Use TheSslStoreOrderId for sync lookups since that's what the query returns + var orderStatusRequest = _requestManager.GetOrderStatusRequestBySslStoreId(currentResponseItem?.TheSslStoreOrderId); var orderStatusResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); + var customOrderId = orderStatusResponse.CustomOrderId; + if (string.IsNullOrEmpty(customOrderId)) + { + _logger.LogTrace($"Order {currentResponseItem?.TheSslStoreOrderId} has no CustomOrderId, skipping"); + continue; + } + var fileContent = ""; var certStatus = _requestManager.MapReturnStatus(orderStatusResponse.OrderStatus.MajorStatus); if (certStatus == (int)EndEntityStatus.GENERATED) { - var downloadCertificateRequest = _requestManager.GetCertificateRequest(orderStatusResponse.TheSslStoreOrderId); + var downloadCertificateRequest = _requestManager.GetCertificateRequest(customOrderId); var certResponse = await client.SubmitDownloadCertificateAsync(downloadCertificateRequest); if (!certResponse.AuthResponse.IsError) { @@ -378,16 +385,9 @@ public async Task Synchronize(BlockingCollection blockin if ((certStatus == (int)EndEntityStatus.GENERATED && fileContent.Length > 0) || certStatus == (int)EndEntityStatus.REVOKED) { - string serialNumber = ""; - if (fileContent.Length > 0) - { - var cert = new X509Certificate2(Encoding.UTF8.GetBytes(fileContent)); - serialNumber = cert.SerialNumber; - } - blockingBuffer.Add(new AnyCAPluginCertificate { - CARequestID = $"{orderStatusResponse.TheSslStoreOrderId}-{serialNumber}", + CARequestID = customOrderId, Certificate = fileContent, Status = certStatus, ProductID = $"{orderStatusResponse.ProductCode}" From 48a1311dc782700c8274c5286a3a79c61f1ade25 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Thu, 19 Mar 2026 09:53:11 -0400 Subject: [PATCH 15/42] changed to get end entity --- SslStoreCaProxy/SslStoreCaProxy.cs | 31 ++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs index f878779..dce2725 100644 --- a/SslStoreCaProxy/SslStoreCaProxy.cs +++ b/SslStoreCaProxy/SslStoreCaProxy.cs @@ -14,6 +14,8 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System.Linq; +using Keyfactor.PKI.X509; + namespace Keyfactor.AnyGateway.SslStore { @@ -323,15 +325,30 @@ public async Task GetSingleRecord(string caRequestId) var orderStatusRequest = _requestManager.GetOrderStatusRequest(caRequestId); _logger.LogTrace($"orderStatusRequest JSON {JsonConvert.SerializeObject(orderStatusRequest)}"); - var certResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); - _logger.LogTrace($"certResponse JSON {JsonConvert.SerializeObject(certResponse)}"); + var orderStatusResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); + _logger.LogTrace($"orderStatusResponse JSON {JsonConvert.SerializeObject(orderStatusResponse)}"); + + var certStatus = _requestManager.MapReturnStatus(orderStatusResponse?.OrderStatus.MajorStatus); + var certificate = string.Empty; + + if (certStatus == (int)EndEntityStatus.GENERATED) + { + var downloadCertificateRequest = _requestManager.GetCertificateRequest(caRequestId); + var certResponse = await client.SubmitDownloadCertificateAsync(downloadCertificateRequest); + if (!certResponse.AuthResponse.IsError) + { + var fullChain = string.Join("\n", certResponse.Certificates.Select(c => c.FileContent)); + var endEntityCert = X509Utilities.ExtractEndEntityCertificateContents(fullChain, null); + certificate = Convert.ToBase64String(endEntityCert.RawData); + } + } _logger.MethodExit(); return new AnyCAPluginCertificate { CARequestID = caRequestId, - Certificate = string.Empty, - Status = _requestManager.MapReturnStatus(certResponse?.OrderStatus.MajorStatus) + Certificate = certificate, + Status = certStatus }; } @@ -378,10 +395,12 @@ public async Task Synchronize(BlockingCollection blockin var certResponse = await client.SubmitDownloadCertificateAsync(downloadCertificateRequest); if (!certResponse.AuthResponse.IsError) { - fileContent = _requestManager.GetCertificateContent(certResponse.Certificates, orderStatusResponse.CommonName); + var fullChain = string.Join("\n", certResponse.Certificates.Select(c => c.FileContent)); + var endEntityCert = X509Utilities.ExtractEndEntityCertificateContents(fullChain, null); + fileContent = Convert.ToBase64String(endEntityCert.RawData); } } - + if ((certStatus == (int)EndEntityStatus.GENERATED && fileContent.Length > 0) || certStatus == (int)EndEntityStatus.REVOKED) { From 38d8ae75a751fa1d847bccd24dbf5d0662facc1a Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Fri, 20 Mar 2026 13:28:10 -0400 Subject: [PATCH 16/42] fixed dns issue --- SslStoreCaProxy/RequestManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index 827693b..fbbdbe4 100644 --- a/SslStoreCaProxy/RequestManager.cs +++ b/SslStoreCaProxy/RequestManager.cs @@ -259,7 +259,7 @@ private NewOrderRequest BuildNewOrderRequest(EnrollmentProductInfo productInfo, .FirstOrDefault() ?? ""; // Extract DNS SANs from Keyfactor san parameter - var dnsNames = san != null && san.ContainsKey("dns") ? san["dns"].ToList() : new List(); + var dnsNames = san != null && san.ContainsKey("dnsname") ? san["dnsname"].ToList() : new List(); return new NewOrderRequest { From 7be603ce1c40c37a3f154d1b2f775d86c015e34a Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Fri, 20 Mar 2026 15:27:13 -0400 Subject: [PATCH 17/42] Doc Updates --- ...low.yml => keyfactor-starter-workflow.yml} | 5 +- .gitignore | 1 + CHANGELOG.md | 28 +- README.md | 1554 ++++------------- docsource/configuration.md | 358 ++++ integration-manifest.json | 100 +- readme_source.md | 1246 +------------ 7 files changed, 795 insertions(+), 2497 deletions(-) rename .github/workflows/{keyfactor-bootstrap-workflow.yml => keyfactor-starter-workflow.yml} (71%) create mode 100644 docsource/configuration.md diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml similarity index 71% rename from .github/workflows/keyfactor-bootstrap-workflow.yml rename to .github/workflows/keyfactor-starter-workflow.yml index aa54b9c..64919a4 100644 --- a/.github/workflows/keyfactor-bootstrap-workflow.yml +++ b/.github/workflows/keyfactor-starter-workflow.yml @@ -11,9 +11,10 @@ on: jobs: call-starter-workflow: - uses: keyfactor/actions/.github/workflows/starter.yml@v2 + uses: keyfactor/actions/.github/workflows/starter.yml@v3 secrets: token: ${{ secrets.V2BUILDTOKEN}} APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} - gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} \ No newline at end of file + gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} + scan_token: ${{ secrets.SAST_TOKEN }} diff --git a/.gitignore b/.gitignore index adbb137..8791d97 100644 --- a/.gitignore +++ b/.gitignore @@ -417,3 +417,4 @@ FodyWeavers.xsd *.msm *.msp .claude/settings.local.json +.claude/settings.json diff --git a/CHANGELOG.md b/CHANGELOG.md index e82d4d6..1470e43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,22 @@ -v1.1.1 -- SSL Store Api Changed Encoding Rules, needed to fix integration to match - -v1.1.0 -- Added new AutoWWW field for single domain SSL Store products +# v2.0.0 +* Converted from AnyCA Gateway (DB) to AnyCA Gateway REST plugin architecture +* Migrated from CAProxy.AnyGateway (BaseCAConnector) to IAnyCAPlugin interface +* Fully async operations throughout (no more Task.Run().Result blocking) +* Self-describing plugin configuration with annotations (no external template JSON files) +* Built-in product registry with 80+ certificate products +* Smart renewal vs. reissue logic with configurable renewal window +* Uses CustomOrderId for stable order tracking +* End-entity certificate extraction using X509Utilities.ExtractEndEntityCertificateContents +* GetSingleRecord now downloads and returns the actual certificate +* Connection validation with required field checks +* Enable/disable toggle for CA connector lifecycle management +* Removed Keyfactor API client dependency (no more direct template updates) -v1.0.4: -- Original Release Version +# v1.1.1 +* SSL Store Api Changed Encoding Rules, needed to fix integration to match + +# v1.1.0 +* Added new AutoWWW field for single domain SSL Store products + +# v1.0.4 +* Original Release Version diff --git a/README.md b/README.md index 5914eda..69ee729 100644 --- a/README.md +++ b/README.md @@ -1,1274 +1,348 @@ -# SSLStore +

+ SSL Store AnyCA Gateway REST Plugin +

+ +

+ +Integration Status: production +Release +Issues +GitHub Downloads (all assets, all releases) +

+ +

+ + + Support + + · + + Requirements + + · + + Installation + + · + + License + + · + + Related Integrations + +

+ + +The SSL Store AnyCA Gateway REST plugin extends the capabilities of the SSL Store Certificate Authority Service to Keyfactor Command via the Keyfactor AnyCA Gateway. SSL Store is a certificate reseller providing access to 80+ certificate products from vendors including DigiCert, Sectigo, RapidSSL, GeoTrust, and Comodo through a single REST API. The plugin represents a fully featured AnyCA Plugin with the following capabilities: + +* **CA Sync**: + * Download all certificates issued through SSL Store + * Full synchronization of all orders with paginated retrieval + * Automatic extraction of end-entity certificates from certificate chains + * Resilient retry logic (up to 5 retries) for large certificate inventories +* **Certificate Enrollment**: + * Support for new certificate enrollment with CSR + * Intelligent renewal vs. reissue logic based on configurable renewal window + * Support for DV, OV, and EV certificate products + * Multi-domain (MDC/SAN) and wildcard certificate support + * Automatic domain validation with approver email verification + * 80+ pre-configured certificate products across DigiCert and Sectigo families +* **Certificate Revocation**: + * Request revocation of previously issued certificates via SSL Store refund request API + +## Compatibility + +The SSL Store AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 24.2 and later. + +## Support +The SSL Store AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. 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. + +## Requirements + +### SSL Store System Prerequisites + +Before configuring the AnyCA Gateway plugin, ensure the following prerequisites are met: + +1. **SSL Store Account**: + - Active SSL Store partner account with API access enabled + - Access to the SSL Store web-based API (WBAPI) + - SSL Store account configured and operational + +2. **API Credentials**: + - SSL Store Partner Code + - SSL Store Authentication Token + - These credentials must have permissions for: + - Certificate enrollment (new order submission) + - Certificate download + - Certificate revocation (refund request) + - Order query and status retrieval + - Email approver list retrieval + +3. **Network Connectivity**: + - Gateway server must have HTTPS access to the SSL Store API endpoint + - Production endpoint: `https://wbapi.thesslstore.com` + - Sandbox endpoint: `https://sandbox-wbapi.thesslstore.com` + - TLS 1.2 or higher must be supported + +### Obtaining Required Configuration Information + +#### 1. SSL Store Base URL + +The SSL Store Base URL is the root endpoint for the SSL Store REST API. + +**Available environments:** +- Production: `https://wbapi.thesslstore.com` +- Sandbox/Testing: `https://sandbox-wbapi.thesslstore.com` + +**To obtain your Base URL:** +1. Log in to your SSL Store partner portal +2. Determine whether you are using the production or sandbox environment +3. Verify the URL is accessible from the Gateway server + +#### 2. API Authentication Credentials + +The Gateway authenticates to SSL Store using a Partner Code and Authentication Token. + +**Steps to obtain API credentials:** + +1. **Access SSL Store Partner Portal**: + - Log in to your SSL Store partner account + - Navigate to API settings + +2. **Obtain Credentials**: + - **Partner Code**: Your unique partner identifier assigned by SSL Store + - **Authentication Token**: A secret token for API authentication + - Store these credentials securely + +3. **Verify Permissions**: + - Ensure the API credentials have permissions for: + - Order creation (`/rest/order/neworder`) + - Order reissue (`/rest/order/reissue`) + - Order query (`/rest/order/query`) + - Order status (`/rest/order/status`) + - Certificate download (`/rest/order/download`) + - Revocation/refund (`/rest/order/refundrequest`) + - Email approver list (`/rest/order/approverlist`) + +#### 3. Supported Certificate Products -SSLStore is a certificate reseller with access to over 80 certificate products. Vendors include Digicert and Sectigo and all their acquired companies such as RapidSSL, Geotrust and Comodo. There is one API for all these products so a single integration to the SSLStore can get you instant access to over 80 Certificate products. +The plugin supports 80+ certificate products from multiple vendors. Products are organized by validation type and vendor: -#### Integration status: Production - Ready for use in production environments. +**DigiCert Products:** +| Product Code | Description | Validation | +|-------------|-------------|------------| +| `digi_securesite_flex` | DigiCert Secure Site | OV | +| `digi_securesite_ev_flex` | DigiCert Secure Site EV | EV | +| `digi_securesite_pro_flex` | DigiCert Secure Site Pro | OV | +| `digi_securesite_pro_ev_flex` | DigiCert Secure Site Pro EV | EV | +| `digi_sslwebserver_flex` | DigiCert SSL Web Server | OV | +| `digi_sslwebserver_ev_flex` | DigiCert SSL Web Server EV | EV | +| `digi_truebizid_flex` | DigiCert TrueBizID | OV | +| `digi_truebizid_ev_flex` | DigiCert TrueBizID EV | EV | +| `digi_ssl_basic` | DigiCert Basic SSL | OV | +| `digi_ssl_ev_basic` | DigiCert Basic SSL EV | EV | +| `digi_rapidssl` | RapidSSL | DV | +| `digi_rapidssl_wc` | RapidSSL Wildcard | DV | +| `digi_ssl_dv_geotrust_flex` | GeoTrust DV SSL | DV | +| `digi_ssl123_flex` | GeoTrust SSL123 | DV | -## About the Keyfactor AnyGateway CA Connector +> **Note:** Most DigiCert products also have `-EO` (Enterprise Organization) variants that use a pre-configured DigiCert organization. See the [full product list](docsource/configuration.md) for details. -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. +**Sectigo/Comodo Products:** +| Product Code | Description | Validation | +|-------------|-------------|------------| +| `positivessl` | Positive SSL | DV | +| `positivesslwildcard` | Positive SSL Wildcard | DV | +| `positivemdcssl` | Positive SSL Multi-Domain | DV | +| `positiveevssl` | Positive EV SSL | EV | +| `sectigossl` | Sectigo SSL | DV | +| `sectigoovssl` | Sectigo OV SSL | OV | +| `sectigoevssl` | Sectigo EV SSL | EV | +| `sectigomdc` | Sectigo Multi-Domain | OV | +| `comodopremiumssl` | Comodo Premium SSL | OV | +| `comodoevssl` | Comodo EV SSL | EV | +| `instantssl` | InstantSSL | OV | +| `enterprisepro` | Enterprise Pro SSL | OV | +| `enterpriseproev` | Enterprise Pro EV | EV | + +> See [docsource/configuration.md](docsource/configuration.md) for the complete list of all 80+ supported products. + +#### 4. Certificate Validity Configuration + +Certificate validity is specified in days during enrollment and automatically converted to months for the SSL Store API: + +| Days | Months | +|------|--------| +| 90 | 3 | +| 180 | 6 | +| 365 | 12 | +| 730 | 24 | +| 1095 | 36 | -## Support for SSLStore +#### 5. Renewal vs. Reissue Logic -SSLStore 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 +The plugin uses a configurable **Renewal Window** (default: 30 days) to determine behavior during certificate renewal: -###### 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. +- If the existing order is **within** the renewal window (expiring within N days), the plugin performs a **renewal** (new order) +- If the existing order is **outside** the renewal window (still has life remaining), the plugin performs a **reissue** on the same order +## Installation ---- +1. Install the AnyCA Gateway REST per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm). + +2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [SSL Store AnyCA Gateway REST plugin](https://github.com/Keyfactor/sslstore-caplugin/releases/latest) from GitHub. +3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: + + ```shell + Depending on your AnyCA Gateway REST version, copy the unzipped directory to one of the following locations: + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions + ``` + > The directory containing the SSL Store AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. +4. Restart the AnyCA Gateway REST service. +5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the SSL Store plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. +## Configuration +1. Follow the [official AnyCA Gateway REST documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) to define a new Certificate Authority, and use the notes below to configure the **Gateway Registration** and **CA Connection** tabs: + * **Gateway Registration** ---- + ### CA Connection Configuration + When registering the SSL Store CA in the AnyCA Gateway, you'll need to provide the following configuration parameters: -*** + | Parameter | Description | Required | Default | + |-----------|-------------|----------|---------| + | **SSLStoreURL** | Full URL to the SSL Store API endpoint | Yes | `https://sandbox-wbapi.thesslstore.com` | + | **PartnerCode** | Partner Code obtained from SSL Store | Yes | | + | **AuthToken** | Authentication Token obtained from SSL Store | Yes | | + | **PageSize** | Number of records per page during synchronization | No | `100` | + | **Enabled** | Flag to Enable or Disable the CA connector | No | `true` | + | **RenewalWindow** | Days before order expiry to trigger renewal vs. reissue | No | `30` | -# Compatibility -This AnyGateway is designed to be used with version 21.3.2 of the Keyfactor AnyGateway Framework. + ### Gateway Registration Notes -# Getting Started + - Each defined Certificate Authority in the AnyCA Gateway REST can support one SSL Store API endpoint + - If you have multiple SSL Store environments (production/sandbox), define separate Certificate Authorities for each + - Each CA configuration will manifest in Command as a separate CA entry + - The plugin uses REST API authentication with Partner Code and Authentication Token + - The plugin automatically handles: + - Product discovery (80+ products) + - Certificate status mapping (Active, Pending, Cancelled) + - End-entity certificate extraction from certificate chains + - Paginated order synchronization with retry logic -## Integration Overview + ### Security Considerations -### Supported Functionality -- Certificate Sync - Full -- Certificate Enrollment for Domain Validated product suite (Regular, with SANs, and Wildcard) -- Certificate Enrollment for Organization Validated product suite (Regular, with SANs, and Wildcard) -- Certificate Enrollment for Extended Validation product suite (Regular and with SANs) -- Certificate Renewal/Reissue -- Certificate Revocation + 1. **Credential Storage**: The AuthToken field is configured as a secret/hidden field and should be stored securely + 2. **Network Security**: Ensure TLS/SSL is properly configured for all API communications + 3. **Least Privilege**: Request API credentials with minimal required permissions + 4. **Audit Logging**: Enable comprehensive logging in both the Gateway and SSL Store for security monitoring + 5. **Credential Rotation**: Regularly rotate API credentials according to your security policy + 6. **Sandbox Testing**: Use the sandbox endpoint (`https://sandbox-wbapi.thesslstore.com`) for initial configuration and testing before switching to production + * **CA Connection** -### Unsupported Functionality -- Certificate Sync - Partial (not possible through the SSL Store API library) -- Approval/Denial of Enrollment Requests (not possible through the SSL Store API library) + Populate using the configuration fields collected in the [requirements](#requirements) section. -### Documentation -**General Documentation** -[SSLStore API Documentation](https://www.thesslstore.com/api/) + * **SSLStoreURL** - The base URL for the SSL Store API endpoint. Use `https://wbapi.thesslstore.com` for production or `https://sandbox-wbapi.thesslstore.com` for testing. + * **PartnerCode** - The Partner Code obtained from your SSL Store partner account. + * **AuthToken** - The Authentication Token obtained from your SSL Store partner account. + * **PageSize** - Number of records to retrieve per page during certificate synchronization. Default is 100. + * **Enabled** - Flag to enable or disable the CA connector. Set to `true` to enable. + * **RenewalWindow** - Number of days before an order's expiration date to trigger a renewal (new order) instead of a reissue (same order). Default is 30 days. +2. ### Template (Product) Configuration -## Standard Gateway Installation -To begin, you must have the CA Gateway Service 21.3.2 installed and operational before attempting to configure the SSLStore Any Gateway plugin. This integration was tested with Keyfactor 8.7.0.0. -To install the gateway follow these instructions. + After adding the CA to the Gateway, certificate templates are automatically discovered from the plugin's built-in product registry. Each template may require different enrollment fields depending on the product type and validation level. -1) Gateway Server - run the installation .msi obtained from Keyfactor + **Enrollment fields vary by product type. Common categories include:** -2) Gateway Server - If you have the rights to install the database (usually in a Non SQL PAAS Environment) Using Powershell, run the following command to create the gateway database. + #### DV Products (Minimal Fields) - **SQL Server Windows Auth** - ``` - %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] - ``` - Note if you are using SQL Authentication, then you need to run - - **SQL Server SQL Authentication** - - ``` - %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] -u [sql user] -p [sql password] - ``` - - If you do **not** have rights to created the database then have the database created ahead of time by the support team and just populate the database - - ## Populate commands below - - **Windows Authentication** - - ``` - %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] - ``` - - **SQL Server SQL Authentication** - - ``` - %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] -u [sql user] -p [sql password] - ``` - -3) Gateway Server - run the following Powershell to import the Cmdlets - - C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll (must be imported into Powershell) - ```ps - Import-Module C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll - ``` - -4) Gateway Server - Run the Following Powershell script to set the gateway encryption cert - - ### Set-KeyfactorGatewayEncryptionCert - This cmdlet will generate a self-signed certificate used to encrypt the database connection string. It populates a registry value with the serial number of the certificate to be used. The certificate is stored in the LocalMachine Personal Store and the registry key populated is: - - HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvcProxy\Parameters\EncryptSerialNumber - No parameters are required to run this cmdlet. - -5) Gateway Server - Run the following Powershell Script to Set the Database Connection - - ### Set-KeyfactorGatewayDatabaseConnection - This cmdlet will set and encrypt the database connection string used by the AnyGateway service. - - **Windows Authentication** - ```ps - Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] - ``` - - **SQL Authentication** - ```ps - $KeyfactorCredentials = Get-Credentials - Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] -Account [$KeyfactorCredentials] - ``` -## Standard Gateway Configuration Finished ---- - - -## SSLStore AnyGateway Specific Configuration -It is important to note that importing the SSLStore configuration into the CA Gateway prior to installing the binaries must be completed. Additionally, the CA Gateway service -must be running in order to succesfully import the configuation. When the CA Gateway service starts it will attempt to validate the connection information to -the CA. Without the imported configuration, the service will fail to start. - -### Binary Installation - -1) Get the Latest Zip File from [Here](https://github.com/Keyfactor/quovadis-cagateway/releases) -2) Gateway Server - Copy the SSLStoreCaProxy.dll to the location where the Gateway Framework was installed (usually C:\Program Files\Keyfactor\Keyfactor AnyGateway) - -### Configuration Changes -1) Gateway Server - Edit the CAProxyServer.exe.config file and replace the line that says "NoOp" with the line below: - ``` - - ``` -2) Gateway Server - Install the Intermediate Comodo Certificate that was received from SSLStore - -3) Gateway Server - Take the sample Config.json located [Here](https://github.com/Keyfactor/quovadis-cagateway/raw/main/SampleConfig.json) and make the following modifications - -- *Security Settings Modifications* (Swap this out for the typical Gateway Security Settings for Test or Prod) - -``` - "Security": { - "KEYFACTOR\\administrator": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_AppPool": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_TimerService": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - } -``` -- *SSLStore Environment Settings* (Modify these with the keys and Urls obtained from SSLStore) -``` - "CAConnection": { - "SSLStoreURL": "https://sandbox-wbapi.thesslstore.com", - "PartnerCode": "SomePartnerCodeFromSSLStore", - "AuthToken": "SomeAuthTokenFromSSLStore", - "KeyfactorApiUrl": "https://kftrain.keyfactor.lab/KeyfactorAPI", - "KeyfactorApiUserId": "SomeKeyfactorAPIUser", - "KeyfactorApiPassword": "SomeKeyfactorAPIPassword", - "PageSize": "25", - "SampleRequest": { - "AuthRequest": { - "PartnerCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - }, - "AuthToken": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - } - }, - "ProductCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - }, - "TSSOrganizationId": { - "FieldData": { - "RequiredForProducts": [ - "None" - ], - "EnrollmentFieldMapping": "Organization ID" - } - }, - "OrganizationInfo": { - "OrganizationName": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization Name" - } - }, - "RegistrationNumber": { - "FieldData": { - "RequiredForProducts": [ - "certum" - ], - "EnrollmentFieldMapping": "Organization Registration Number" - } - }, - "JurisdictionCountry": { - "FieldData": { - "RequiredForProducts": [ - "comodoevssl", - "comodoevcsc", - "comodoevmdc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "positiveevssl" - ], - "EnrollmentFieldMapping": "Organization Jurisdiction Country" - } - }, - "OrganizationAddress": { - "AddressLine1": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization Address" - } - }, - "Region": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization State/Province" - } - }, - "PostalCode": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization Postal Code" - } - }, - "LocalityName": { - "FieldData": { - "RequiredForProducts": [ - "comodocsc", - "comodoevssl", - "comodoevcsc", - "comodoevmdc", - "comodomdc", - "comodomdcwildcard", - "comodouccwildcard", - "comodoucc", - "pacenterprise" - ], - "EnrollmentFieldMapping": "Organization Locality Name" - } - }, - "Country": { - "FieldData": { - "RequiredForProducts": [ - "truebizidmd", - "digi_ev_md_ssl", - "digi_md_ssl", - "digi_plus_ev_ssl", - "digi_plus_ssl", - "digi_securesite", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_ssl_basic", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev_flex", - "digi_securesite_flex", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex" - ], - "EnrollmentFieldMapping": "Organization Country" - } - }, - "Phone": { - "FieldData": { - "RequiredForProducts": [ - "truebizidmd", - "digi_ev_md_ssl", - "digi_md_ssl", - "digi_plus_ev_ssl", - "digi_plus_ssl", - "digi_securesite", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_ssl_basic", - "digi_sslwebserver_ev_flex", - "digi_truebizid_ev_flex", - "digi_securesite_flex", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex" - ], - "EnrollmentFieldMapping": "Organization Phone" - } - } - } - }, - "ValidityPeriod": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Validity Period (In Months)" - } - }, - "ServerCount": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Server Count" - } - }, - "CSR": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - }, - "DomainName": { - "FieldData": { - "RequiredForProducts": [ - "Certum" - ], - "EnrollmentFieldMapping": "Domain Name" - } - }, - "WebServerType": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Web Server Type" - } - }, - "DNSNames": { - "FieldData": { - "RequiredForProducts": [ - "digi_ssl_ev_basic", - "digi_ssl_ev_basic-EO", - "digi_securesite_ev_flex", - "digi_securesite_ev_flex-EO", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_ev_flex-EO", - "digi_securesite_pro_flex", - "digi_securesite_pro_flex-EO", - "digi_ssl_basic", - "digi_ssl_basic-EO", - "digi_securesite_flex", - "digi_securesite_flex-EO", - "digi_truebizid_flex", - "digi_truebizid_flex-EO", - "digi_truebizid_ev_flex", - "digi_truebizid_ev_flex-EO", - "digi_ssl_dv_geotrust_flex", - "digi_rapidssl", - "digi_rapidssl_wc", - "digi_ssl123_flex", - "digi_sslwebserver_flex", - "digi_sslwebserver_flex-EO", - "digi_sslwebserver_ev_flex", - "digi_sslwebserver_ev_flex-EO", - "positivemdcssl", - "positivemdcwildcard", - "sectigodvucc", - "sectigouccwildcard", - "sectigoevmdc", - "sectigomdcwildcard", - "sectigomdc" - ], - "EnrollmentFieldMapping": "DNS Names Comma Separated", - "Array": true - } - }, - "isCUOrder": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Is CU Order?" - } - }, - "isRenewalOrder": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Is Renewal Order?" - } - }, - "isTrialOrder": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Is Trial Order?" - } - }, - "AdminContact": { - "FirstName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - First Name" - } - }, - "LastName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Last Name" - } - }, - "Phone": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Phone" - } - }, - "Email": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Email" - } - }, - "Title": { - "FieldData": { - "RequiredForProducts": [ - "symantec", - "digi_ssl_ev_basic", - "digi_sslwebserver_ev_flex", - "digi_truebizid_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_ev_flex" - ], - "EnrollmentFieldMapping": "Admin Contact - Title" - } - }, - "OrganizationName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Organization Name" - } - }, - "AddressLine1": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Address" - } - }, - "City": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - City" - } - }, - "Region": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Region" - } - }, - "PostalCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Postal Code" - } - }, - "Country": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Country" - } - } - }, - "TechnicalContact": { - "FirstName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - First Name" - } - }, - "LastName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Last Name" - } - }, - "SubjectFirstName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Subject First Name" - } - }, - "SubjectLastName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Subject Last Name" - } - }, - "Phone": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Phone" - } - }, - "Email": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Email" - } - }, - "Title": { - "FieldData": { - "RequiredForProducts": [ - "symantec", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev_flex" - ], - "EnrollmentFieldMapping": "Technical Contact - Title" - } - }, - "AddressLine1": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Address" - } - }, - "City": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - City" - } - }, - "Region": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Region" - } - }, - "PostalCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Postal Code" - } - }, - "Country": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Country" - } - } - }, - "AutoWWW": { - "FieldData": { - "RequiredForProducts": [ - "positivessl" - ], - "EnrollmentFieldMapping": "AutoWWW" - } - }, - "ApproverEmail": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Approver Email" - } - }, - "FileAuthDVIndicator": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "File Auth Domain Validation" - } - }, - "CNAMEAuthDVIndicator": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "CName Auth Domain Validation" - } - }, - "SignatureHashAlgorithm": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Signature Hash Algorithm" - } - } - } - } -``` - -- *Template Settings - See Configuration Instructional Video on how these work* -``` - "Templates": { - "positivessl": { - "ProductID": "positivessl", - "Parameters": { - "AutoWWW": "True" - } - }, - "positiveevssl": { - "ProductID": "positiveevssl", - "Parameters": {} - }, - "enterpriseproev": { - "ProductID": "enterpriseproev", - "Parameters": {} - }, - "enterpriseproevmdc": { - "ProductID": "enterpriseproevmdc", - "Parameters": {} - }, - "positivesslwildcard": { - "ProductID": "positivesslwildcard", - "Parameters": {} - }, - "positivemdcssl": { - "ProductID": "positivemdcssl", - "Parameters": {} - }, - "positivemdcwildcard": { - "ProductID": "positivemdcwildcard", - "Parameters": {} - }, - "positiveevmdc": { - "ProductID": "positiveevmdc", - "Parameters": {} - }, - "instantssl": { - "ProductID": "instantssl", - "Parameters": {} - }, - "instantsslpro": { - "ProductID": "instantsslpro", - "Parameters": {} - }, - "comodopremiumssl": { - "ProductID": "comodopremiumssl", - "Parameters": {} - }, - "comodopremiumwildcard": { - "ProductID": "comodopremiumwildcard", - "Parameters": {} - }, - "enterprisepro": { - "ProductID": "enterprisepro", - "Parameters": {} - }, - "enterpriseprowc": { - "ProductID": "enterpriseprowc", - "Parameters": {} - }, - "sectigossl": { - "ProductID": "sectigossl", - "Parameters": {} - }, - "sectigodvucc": { - "ProductID": "sectigodvucc", - "Parameters": {} - }, - "sectigoevssl": { - "ProductID": "sectigoevssl", - "Parameters": {} - }, - "sectigoevmdc": { - "ProductID": "sectigoevmdc", - "Parameters": {} - }, - "sectigoovssl": { - "ProductID": "sectigoovssl", - "Parameters": {} - }, - "sectigomdc": { - "ProductID": "sectigomdc", - "Parameters": {} - }, - "sectigomdcwildcard": { - "ProductID": "sectigomdcwildcard", - "Parameters": {} - }, - "sectigoovwildcard": { - "ProductID": "sectigoovwildcard", - "Parameters": {} - }, - "sectigowildcard": { - "ProductID": "sectigowildcard", - "Parameters": {} - }, - "sectigouccwildcard": { - "ProductID": "sectigouccwildcard", - "Parameters": {} - }, - "digi_ssl_ev_basic": { - "ProductID": "digi_ssl_ev_basic", - "Parameters": {} - }, - "digi_ssl_ev_basic-EO": { - "ProductID": "digi_ssl_ev_basic-EO", - "Parameters": {} - }, - "digi_securesite_ev_flex": { - "ProductID": "digi_securesite_ev_flex", - "Parameters": {} - }, - "digi_securesite_ev_flex-EO": { - "ProductID": "digi_securesite_ev_flex-EO", - "Parameters": {} - }, - "digi_securesite_pro_ev_flex": { - "ProductID": "digi_securesite_pro_ev_flex", - "Parameters": {} - }, - "digi_securesite_pro_ev_flex-EO": { - "ProductID": "digi_securesite_pro_ev_flex-EO", - "Parameters": {} - }, - "digi_securesite_pro_flex": { - "ProductID": "digi_securesite_pro_flex", - "Parameters": {} - }, - "digi_securesite_pro_flex-EO": { - "ProductID": "digi_securesite_pro_flex-EO", - "Parameters": {} - }, - "digi_ssl_basic": { - "ProductID": "digi_ssl_basic", - "Parameters": {} - }, - "digi_ssl_basic-EO": { - "ProductID": "digi_ssl_basic-EO", - "Parameters": {} - }, - "digi_securesite_flex": { - "ProductID": "digi_securesite_flex", - "Parameters": {} - }, - "digi_securesite_flex-EO": { - "ProductID": "digi_securesite_flex-EO", - "Parameters": {} - }, - "digi_truebizid_flex": { - "ProductID": "digi_truebizid_flex", - "Parameters": {} - }, - "digi_truebizid_flex-EO": { - "ProductID": "digi_truebizid_flex-EO", - "Parameters": {} - }, - "digi_truebizid_ev_flex": { - "ProductID": "digi_truebizid_ev_flex", - "Parameters": {} - }, - "digi_truebizid_ev_flex-EO": { - "ProductID": "digi_truebizid_ev_flex-EO", - "Parameters": {} - }, - "digi_ssl_dv_geotrust_flex": { - "ProductID": "digi_ssl_dv_geotrust_flex", - "Parameters": {} - }, - "digi_rapidssl": { - "ProductID": "digi_rapidssl", - "Parameters": {} - }, - "digi_rapidssl_wc": { - "ProductID": "digi_rapidssl_wc", - "Parameters": {} - }, - "digi_ssl123_flex": { - "ProductID": "digi_ssl123_flex", - "Parameters": {} - }, - "digi_sslwebserver_flex": { - "ProductID": "digi_sslwebserver_flex", - "Parameters": {} - }, - "digi_sslwebserver_flex-EO": { - "ProductID": "digi_sslwebserver_flex-EO", - "Parameters": {} - }, - "digi_sslwebserver_ev_flex": { - "ProductID": "digi_sslwebserver_ev_flex", - "Parameters": {} - }, - "digi_sslwebserver_ev_flex-EO": { - "ProductID": "digi_sslwebserver_ev_flex-EO", - "Parameters": {} - } - } -``` - -- *Gateway Settings* -``` - "CertificateManagers": null, - "GatewayRegistration": { - "LogicalName": "SSLStore", - "GatewayCertificate": { - "StoreName": "CA", - "StoreLocation": "LocalMachine", - "Thumbprint": "339cdd57cfd5b141169b615ff31428782d1da639" - } - } -``` - -- *Service Settings* (Modify these to be in accordance with Keyfactor Standard Gateway Production Settings) -``` - "ServiceSettings": { - "ViewIdleMinutes": 1, - "FullScanPeriodHours": 1, - "PartialScanPeriodMinutes": 1 - } -``` - -5) Gateway Server - Save the newly modified config.json to the following location "C:\Program Files\Keyfactor\Keyfactor AnyGateway" - -### Template Installation - -1) Command Server - Copy and Unzip the Template Setup Files located [Here](https://github.com/Keyfactor/sslstore-cagateway/raw/main/TemplateSetup.zip) -2) Command Server - Change the Security Settings in the CaTemplateUserSecurity.csv file to the appropriate settings for Test or Production -3) Command Server - Run the CreateTemplate.ps1 file and choose option 1 to create the templates in active directory. - *Note if you get errors the security is likely wrong and you will have to add the security manually according to Keyfactor standards* -4) Command Server - Use the Keyfactor Portal to Import the Templates created in Active Directory in step #3 above -5) Command Server - Run the CreateTemplate.ps1 file and choose option 3 to create all the enrollment fields. - *Note You will have to override the default API Questions to the appropriate information.* - -### Certificate Authority Installation -1) Gateway Server - Start the Keyfactor Gateway Service -2) Run the set Gateway command similar to below -```ps -Set-KeyfactorGatewayConfig -LogicalName "SSLStore" -FilePath [path to json file] -PublishAd -``` -3) Command Server - Import the certificate authority in Keyfactor Portal - -### Release 1.1 Notes -Look over the AutoWWW field in both the Sample Config and readme. If you want to include it for a template see the positivessl sample in the readme. It is also needed as a new field in the SampleRequest Section of the file as shown in the readme. - -*** - -### License -[Apache](https://apache.org/licenses/LICENSE-2.0) + Products like `positivessl`, `sectigossl`, `sectigowildcard`: + + | Parameter | Description | Required | + |-----------|-------------|----------| + | **Admin Contact - Email** | Administrative contact email | Yes | + | **Approver Email** | Domain validation approver email | Yes | + | **Validity Period (In Days)** | Certificate validity in days | Yes | + + #### OV Products (Organization Fields) + + Products like `sectigoovssl`, `comodopremiumssl`, `instantssl`: + + | Parameter | Description | Required | + |-----------|-------------|----------| + | **Admin Contact - Email** | Administrative contact email | Yes | + | **Approver Email** | Domain validation approver email | Yes | + | **Validity Period (In Days)** | Certificate validity in days | Yes | + | **Organization Name** | Organization name | Yes | + | **Organization Address** | Organization street address | Yes | + | **Organization State/Province** | Organization state or province | Yes | + | **Organization Postal Code** | Organization postal/zip code | Yes | + | **Organization Country** | Two-letter country code (e.g. US) | Yes | + | **Organization Phone** | Organization phone number | Yes | + + #### DigiCert OV/EV Flex Products + + Products like `digi_securesite_flex`, `digi_securesite_ev_flex`, `digi_truebizid_flex`: + + | Parameter | Description | Required | + |-----------|-------------|----------| + | **Admin Contact - First Name** | Administrative contact first name | Yes | + | **Admin Contact - Last Name** | Administrative contact last name | Yes | + | **Admin Contact - Phone** | Administrative contact phone | Yes | + | **Admin Contact - Email** | Administrative contact email | Yes | + | **Admin Contact - Title** | Administrative contact title (EV only) | EV only | + | **Approver Email** | Domain validation approver email | Yes | + | **Validity Period (In Days)** | Certificate validity in days | Yes | + | **Organization Name** | Organization name | Yes | + | **Organization Address** | Organization street address | Yes | + | **Organization City** | Organization city | Yes | + | **Organization State/Province** | Organization state or province | Yes | + | **Organization Postal Code** | Organization postal/zip code | Yes | + | **Organization Country** | Two-letter country code | Yes | + | **Organization Phone** | Organization phone number | Yes | + + #### Enterprise Organization (-EO) Products + + Products like `digi_securesite_flex-EO`, `digi_sslwebserver_ev_flex-EO`: + + | Parameter | Description | Required | + |-----------|-------------|----------| + | **Validity Period (In Days)** | Certificate validity in days | Yes | + | **Organization ID** | DigiCert Organization ID | Yes | + + > See [docsource/configuration.md](docsource/configuration.md) for complete enrollment field details for all product categories. + + ### Domain Validation - Approver Emails + + The plugin validates approver emails against SSL Store's approved list for each domain before enrollment: + + - **DigiCert products**: Exactly one approver email is required and must be from the approved list + - **Sectigo/Comodo products**: At least one approver email must be from the approved list + - Emails are validated per-domain for multi-domain certificates + +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. + +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 appropriate for the product type. Refer to the tables above or [docsource/configuration.md](docsource/configuration.md) for the required fields per product. + + +## License + +Apache License 2.0, see [LICENSE](LICENSE). + +## Related Integrations +See all [Keyfactor Any CA Gateways (REST)](https://github.com/orgs/Keyfactor/repositories?q=anycagateway). diff --git a/docsource/configuration.md b/docsource/configuration.md new file mode 100644 index 0000000..6a1a36a --- /dev/null +++ b/docsource/configuration.md @@ -0,0 +1,358 @@ +## Overview + +The SSL Store AnyCA Gateway REST plugin extends the capabilities of the SSL Store Certificate Authority Service to Keyfactor Command via the Keyfactor AnyCA Gateway. SSL Store is a certificate reseller providing access to 80+ certificate products from vendors including DigiCert, Sectigo, RapidSSL, GeoTrust, and Comodo through a single REST API. The plugin represents a fully featured AnyCA Plugin with the following capabilities: + +* **CA Sync**: + * Download all certificates issued through SSL Store + * Full synchronization of all orders with paginated retrieval + * Automatic extraction of end-entity certificates from certificate chains + * Resilient retry logic (up to 5 retries) for large certificate inventories +* **Certificate Enrollment**: + * Support for new certificate enrollment with CSR + * Intelligent renewal vs. reissue logic based on configurable renewal window + * Support for DV, OV, and EV certificate products + * Multi-domain (MDC/SAN) and wildcard certificate support + * Automatic domain validation with approver email verification + * 80+ pre-configured certificate products across DigiCert and Sectigo families +* **Certificate Revocation**: + * Request revocation of previously issued certificates via SSL Store refund request API + +## Requirements + +### SSL Store System Prerequisites + +Before configuring the AnyCA Gateway plugin, ensure the following prerequisites are met: + +1. **SSL Store Account**: + - Active SSL Store partner account with API access enabled + - Access to the SSL Store web-based API (WBAPI) + - SSL Store account configured and operational + +2. **API Credentials**: + - SSL Store Partner Code + - SSL Store Authentication Token + - These credentials must have permissions for: + - Certificate enrollment (new order submission) + - Certificate download + - Certificate revocation (refund request) + - Order query and status retrieval + - Email approver list retrieval + +3. **Network Connectivity**: + - Gateway server must have HTTPS access to the SSL Store API endpoint + - Production endpoint: `https://wbapi.thesslstore.com` + - Sandbox endpoint: `https://sandbox-wbapi.thesslstore.com` + - TLS 1.2 or higher must be supported + +### Obtaining Required Configuration Information + +#### 1. SSL Store Base URL + +The SSL Store Base URL is the root endpoint for the SSL Store REST API. + +**Available environments:** +- Production: `https://wbapi.thesslstore.com` +- Sandbox/Testing: `https://sandbox-wbapi.thesslstore.com` + +**To obtain your Base URL:** +1. Log in to your SSL Store partner portal +2. Determine whether you are using the production or sandbox environment +3. Verify the URL is accessible from the Gateway server + +#### 2. API Authentication Credentials + +The Gateway authenticates to SSL Store using a Partner Code and Authentication Token. + +**Steps to obtain API credentials:** + +1. **Access SSL Store Partner Portal**: + - Log in to your SSL Store partner account + - Navigate to API settings + +2. **Obtain Credentials**: + - **Partner Code**: Your unique partner identifier assigned by SSL Store + - **Authentication Token**: A secret token for API authentication + - Store these credentials securely + +3. **Verify Permissions**: + - Ensure the API credentials have permissions for: + - Order creation (`/rest/order/neworder`) + - Order reissue (`/rest/order/reissue`) + - Order query (`/rest/order/query`) + - Order status (`/rest/order/status`) + - Certificate download (`/rest/order/download`) + - Revocation/refund (`/rest/order/refundrequest`) + - Email approver list (`/rest/order/approverlist`) + +#### 3. Supported Certificate Products + +The plugin supports 80+ certificate products from multiple vendors. Products are organized by validation type and vendor: + +**DigiCert Products:** + +| Product Code | Description | Validation | +|-------------|-------------|------------| +| `digi_securesite_flex` | DigiCert Secure Site | OV | +| `digi_securesite_flex-EO` | DigiCert Secure Site (Enterprise Org) | OV | +| `digi_securesite_ev_flex` | DigiCert Secure Site EV | EV | +| `digi_securesite_ev_flex-EO` | DigiCert Secure Site EV (Enterprise Org) | EV | +| `digi_securesite_pro_flex` | DigiCert Secure Site Pro | OV | +| `digi_securesite_pro_flex-EO` | DigiCert Secure Site Pro (Enterprise Org) | OV | +| `digi_securesite_pro_ev_flex` | DigiCert Secure Site Pro EV | EV | +| `digi_securesite_pro_ev_flex-EO` | DigiCert Secure Site Pro EV (Enterprise Org) | EV | +| `digi_sslwebserver_flex` | DigiCert SSL Web Server | OV | +| `digi_sslwebserver_flex-EO` | DigiCert SSL Web Server (Enterprise Org) | OV | +| `digi_sslwebserver_ev_flex` | DigiCert SSL Web Server EV | EV | +| `digi_sslwebserver_ev_flex-EO` | DigiCert SSL Web Server EV (Enterprise Org) | EV | +| `digi_truebizid_flex` | DigiCert TrueBizID | OV | +| `digi_truebizid_flex-EO` | DigiCert TrueBizID (Enterprise Org) | OV | +| `digi_truebizid_ev_flex` | DigiCert TrueBizID EV | EV | +| `digi_truebizid_ev_flex-EO` | DigiCert TrueBizID EV (Enterprise Org) | EV | +| `digi_ssl_basic` | DigiCert Basic SSL | OV | +| `digi_ssl_basic-EO` | DigiCert Basic SSL (Enterprise Org) | OV | +| `digi_ssl_ev_basic` | DigiCert Basic SSL EV | EV | +| `digi_ssl_ev_basic-EO` | DigiCert Basic SSL EV (Enterprise Org) | EV | +| `digi_rapidssl` | RapidSSL | DV | +| `digi_rapidssl_wc` | RapidSSL Wildcard | DV | +| `digi_ssl_dv_geotrust_flex` | GeoTrust DV SSL | DV | +| `digi_ssl123_flex` | GeoTrust SSL123 | DV | +| `digi_quickssl_md` | DigiCert QuickSSL Multi-Domain | DV | +| `digi_client_premium` | DigiCert Client Premium | Client | +| `digi_csc` | DigiCert Code Signing | Code Signing | +| `digi_csc_ev` | DigiCert EV Code Signing | EV Code Signing | +| `digi_doc_signing_ind_500` | DigiCert Document Signing Individual 500 | Document Signing | +| `digi_doc_signing_ind_2000` | DigiCert Document Signing Individual 2000 | Document Signing | +| `digi_doc_signing_org_2000` | DigiCert Document Signing Organization 2000 | Document Signing | +| `digi_doc_signing_org_5000` | DigiCert Document Signing Organization 5000 | Document Signing | + +**Sectigo/Comodo Products:** + +| Product Code | Description | Validation | +|-------------|-------------|------------| +| `positivessl` | Positive SSL | DV | +| `positivesslwildcard` | Positive SSL Wildcard | DV | +| `positivemdcssl` | Positive SSL Multi-Domain | DV | +| `positivemdcwildcard` | Positive SSL MDC Wildcard | DV | +| `positiveevssl` | Positive EV SSL | EV | +| `positiveevmdc` | Positive EV Multi-Domain | EV | +| `sectigossl` | Sectigo SSL | DV | +| `sectigowildcard` | Sectigo Wildcard | DV | +| `sectigoovssl` | Sectigo OV SSL | OV | +| `sectigoovwildcard` | Sectigo OV Wildcard | OV | +| `sectigoevssl` | Sectigo EV SSL | EV | +| `sectigodvucc` | Sectigo DV UCC | DV | +| `sectigouccwildcard` | Sectigo UCC Wildcard | DV | +| `sectigomdc` | Sectigo Multi-Domain | OV | +| `sectigomdcwildcard` | Sectigo MDC Wildcard | OV | +| `sectigoevmdc` | Sectigo EV Multi-Domain | EV | +| `comodopremiumssl` | Comodo Premium SSL | OV | +| `comodopremiumwildcard` | Comodo Premium Wildcard | OV | +| `comodossl` | Comodo SSL | OV | +| `comodoevssl` | Comodo EV SSL | EV | +| `comodomdc` | Comodo Multi-Domain | OV | +| `comodomdcwildcard` | Comodo MDC Wildcard | OV | +| `comodoevmdc` | Comodo EV Multi-Domain | EV | +| `comodoucc` | Comodo UCC | OV | +| `comodouccwildcard` | Comodo UCC Wildcard | OV | +| `comodowildcard` | Comodo Wildcard | OV | +| `comodocsc` | Comodo Code Signing | Code Signing | +| `comodoevcsc` | Comodo EV Code Signing | EV Code Signing | +| `comododvucc` | Comodo DV UCC | DV | +| `comodopciscan` | Comodo PCI Scan | Scanning | +| `instantssl` | InstantSSL | OV | +| `instantsslpro` | InstantSSL Pro | OV | +| `enterprisepro` | Enterprise Pro SSL | OV | +| `enterpriseprowc` | Enterprise Pro Wildcard | OV | +| `enterpriseproev` | Enterprise Pro EV | EV | +| `enterpriseproevmdc` | Enterprise Pro EV Multi-Domain | EV | +| `enterprisessl` | Enterprise SSL | OV | +| `essentialssl` | Essential SSL | DV | +| `essentialwildcard` | Essential Wildcard | DV | +| `elitessl` | Elite SSL | OV | + +**Note:** Products with the `-EO` suffix are Enterprise Organization variants that use a pre-configured DigiCert organization instead of requiring organization details during enrollment. These products require only a Validity Period and Organization ID. + +#### 4. Certificate Validity Configuration + +Certificate validity is specified in days during enrollment and automatically converted to months for the SSL Store API: + +| Days | Months | +|------|--------| +| 90 | 3 | +| 180 | 6 | +| 365 | 12 | +| 730 | 24 | +| 1095 | 36 | + +#### 5. Renewal vs. Reissue Logic + +The plugin uses a configurable **Renewal Window** (default: 30 days) to determine behavior during certificate renewal: + +- If the existing order is **within** the renewal window (i.e., expiring within N days), the plugin performs a **renewal** (new order linked to the original) +- If the existing order is **outside** the renewal window (still has significant life remaining), the plugin performs a **reissue** on the same order + +## Installation + +1. Install the AnyCA Gateway REST per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm). + +2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [SSL Store AnyCA Gateway REST plugin](https://github.com/Keyfactor/sslstore-caplugin/releases/latest) from GitHub. + +3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: + + ```shell + Depending on your AnyCA Gateway REST version, copy the unzipped directory to one of the following locations: + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions + ``` + + > The directory containing the SSL Store AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. + +4. Restart the AnyCA Gateway REST service. + +5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the SSL Store plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. + +## Gateway Registration + +### CA Connection Configuration + +When registering the SSL Store CA in the AnyCA Gateway, you'll need to provide the following configuration parameters: + +| Parameter | Description | Required | Default | +|-----------|-------------|----------|---------| +| **SSLStoreURL** | Full URL to the SSL Store API endpoint | Yes | `https://sandbox-wbapi.thesslstore.com` | +| **PartnerCode** | Partner Code obtained from SSL Store | Yes | | +| **AuthToken** | Authentication Token obtained from SSL Store | Yes | | +| **PageSize** | Number of records per page during synchronization | No | `100` | +| **Enabled** | Flag to Enable or Disable the CA connector | No | `true` | +| **RenewalWindow** | Days before order expiry to trigger renewal vs. reissue | No | `30` | + +### Gateway Registration Notes + +- Each defined Certificate Authority in the AnyCA Gateway REST can support one SSL Store API endpoint +- If you have multiple SSL Store environments (production/sandbox), define separate Certificate Authorities for each +- Each CA configuration will manifest in Command as a separate CA entry +- The plugin uses REST API authentication with Partner Code and Authentication Token +- The plugin automatically handles: + - Product discovery (80+ products) + - Certificate status mapping (Active, Pending, Cancelled) + - End-entity certificate extraction from certificate chains + - Paginated order synchronization with retry logic + +### Security Considerations + +1. **Credential Storage**: The AuthToken field is configured as a secret/hidden field and should be stored securely +2. **Network Security**: Ensure TLS/SSL is properly configured for all API communications +3. **Least Privilege**: Request API credentials with minimal required permissions +4. **Audit Logging**: Enable comprehensive logging in both the Gateway and SSL Store for security monitoring +5. **Credential Rotation**: Regularly rotate API credentials according to your security policy +6. **Sandbox Testing**: Use the sandbox endpoint (`https://sandbox-wbapi.thesslstore.com`) for initial configuration and testing before switching to production + +### CA Connection Fields + +Populate using the configuration fields collected in the [requirements](#requirements) section. + +* **SSLStoreURL** - The base URL for the SSL Store API endpoint. Use `https://wbapi.thesslstore.com` for production or `https://sandbox-wbapi.thesslstore.com` for testing. +* **PartnerCode** - The Partner Code obtained from your SSL Store partner account. +* **AuthToken** - The Authentication Token obtained from your SSL Store partner account. +* **PageSize** - Number of records to retrieve per page during certificate synchronization. Default is 100. +* **Enabled** - Flag to enable or disable the CA connector. Set to `true` to enable. +* **RenewalWindow** - Number of days before an order's expiration date to trigger a renewal (new order) instead of a reissue (same order). Default is 30 days. + +## Certificate Template Creation Step + +### Template (Product) Configuration + +After adding the CA to the Gateway, certificate templates are automatically discovered from the plugin's built-in product registry. Each template may require different enrollment fields depending on the product type and validation level. + +**Enrollment fields vary by product type. The following categories exist:** + +#### DV Products (Minimal Fields) + +Products like `positivessl`, `sectigossl`, `sectigowildcard`: + +| Parameter | Description | Required | +|-----------|-------------|----------| +| **Admin Contact - Email** | Administrative contact email | Yes | +| **Approver Email** | Domain validation approver email | Yes | +| **Validity Period (In Days)** | Certificate validity in days | Yes | + +#### OV Products (Organization Fields) + +Products like `sectigoovssl`, `comodopremiumssl`, `instantssl`: + +| Parameter | Description | Required | +|-----------|-------------|----------| +| **Admin Contact - Email** | Administrative contact email | Yes | +| **Approver Email** | Domain validation approver email | Yes | +| **Validity Period (In Days)** | Certificate validity in days | Yes | +| **Organization Name** | Organization name | Yes | +| **Organization Address** | Organization street address | Yes | +| **Organization State/Province** | Organization state or province | Yes | +| **Organization Postal Code** | Organization postal/zip code | Yes | +| **Organization Country** | Two-letter country code (e.g. US) | Yes | +| **Organization Phone** | Organization phone number | Yes | + +#### DigiCert OV Flex Products + +Products like `digi_securesite_flex`, `digi_sslwebserver_flex`, `digi_truebizid_flex`: + +| Parameter | Description | Required | +|-----------|-------------|----------| +| **Admin Contact - First Name** | Administrative contact first name | Yes | +| **Admin Contact - Last Name** | Administrative contact last name | Yes | +| **Admin Contact - Phone** | Administrative contact phone | Yes | +| **Admin Contact - Email** | Administrative contact email | Yes | +| **Approver Email** | Domain validation approver email | Yes | +| **Validity Period (In Days)** | Certificate validity in days | Yes | +| **Organization Name** | Organization name | Yes | +| **Organization Address** | Organization street address | Yes | +| **Organization City** | Organization city | Yes | +| **Organization State/Province** | Organization state or province | Yes | +| **Organization Postal Code** | Organization postal/zip code | Yes | +| **Organization Country** | Two-letter country code | Yes | +| **Organization Phone** | Organization phone number | Yes | + +#### DigiCert EV Flex Products + +Products like `digi_securesite_ev_flex`, `digi_ssl_ev_basic`, `digi_truebizid_ev_flex`: + +Same as DigiCert OV Flex, plus: + +| Parameter | Description | Required | +|-----------|-------------|----------| +| **Admin Contact - Title** | Administrative contact job title | Yes | + +#### Enterprise Organization (-EO) Products + +Products like `digi_securesite_flex-EO`, `digi_sslwebserver_ev_flex-EO`: + +| Parameter | Description | Required | +|-----------|-------------|----------| +| **Validity Period (In Days)** | Certificate validity in days | Yes | +| **Organization ID** | DigiCert Organization ID | Yes | + +#### EV Products with Jurisdiction + +Products like `enterpriseproev`, `positiveevssl`, `positiveevmdc`: + +Same as OV Products, plus: + +| Parameter | Description | Required | +|-----------|-------------|----------| +| **Organization Jurisdiction Country** | Jurisdiction country code for EV validation | Yes | + +### Domain Validation - Approver Emails + +The plugin validates approver emails against SSL Store's approved list for each domain before enrollment: + +- **DigiCert products**: Exactly one approver email is required and must be from the approved list +- **Sectigo/Comodo products**: At least one approver email must be from the approved list +- Emails are validated per-domain for multi-domain certificates + +### Important Notes + +- Product IDs are automatically registered from the plugin's built-in product registry +- The `Validity Period (In Days)` is automatically converted to months for the SSL Store API +- For `-EO` (Enterprise Organization) products, the Organization ID dropdown is populated from your DigiCert account's active organizations +- DNS names (SANs) are extracted from the Keyfactor enrollment request; they do not need to be provided as a separate enrollment field +- The Common Name (CN) is extracted from the CSR subject diff --git a/integration-manifest.json b/integration-manifest.json index 1a4403e..fcfff7b 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -1,11 +1,93 @@ { - "$schema": "https://keyfactor.github.io/integration-manifest-schema.json", - "integration_type": "ca-gateway", - "name": "SSLStore", - "status": "production", - "release_dir": "SslStoreCaProxy/bin/Release", - "support_level": "kf-supported", - "update_catalog": true, - "link_github": true, - "description": "SSLStore is a certificate reseller with access to over 80 certificate products. Vendors include Digicert and Sectigo and all their acquired companies such as RapidSSL, Geotrust and Comodo. There is one API for all these products so a single integration to the SSLStore can get you instant access to over 80 Certificate products." + "$schema": "https://keyfactor.github.io/v2/integration-manifest-schema.json", + "name": "SSL Store AnyCA REST plugin", + "release_dir": "SslStoreCaProxy/bin/Release", + "release_project": "SslStoreCaProxy/SslStoreCaProxy.csproj", + "description": "AnyCA Gateway REST plugin that extends SSL Store Certificate Authority Service to Keyfactor Command. SSL Store is a certificate reseller providing access to 80+ certificate products from vendors including DigiCert, Sectigo, RapidSSL, GeoTrust, and Comodo through a single API.", + "status": "production", + "integration_type": "anyca-plugin", + "support_level": "kf-supported", + "link_github": true, + "update_catalog": true, + "gateway_framework": "24.2", + "about": { + "carest": { + "ca_plugin_config": [ + { + "name": "SSLStoreURL", + "description": "The Base URL for the SSL Store API endpoint (e.g. https://sandbox-wbapi.thesslstore.com)." + }, + { + "name": "PartnerCode", + "description": "The Partner Code obtained from SSL Store." + }, + { + "name": "AuthToken", + "description": "The Authentication Token obtained from SSL Store." + }, + { + "name": "PageSize", + "description": "The number of records to return per page during synchronization (default: 100)." + }, + { + "name": "Enabled", + "description": "Flag to Enable or Disable the CA connector." + }, + { + "name": "RenewalWindow", + "description": "Number of days before order expiry to trigger a renewal instead of a reissue (default: 30)." + } + ], + "enrollment_config": [ + { + "name": "Approver Email", + "description": "Comma-separated approver email address(es) for domain validation." + }, + { + "name": "Validity Period (In Days)", + "description": "Certificate validity period in days (e.g. 90, 365, 730). Automatically converted to months for the SSL Store API." + }, + { + "name": "Admin Contact - First Name", + "description": "Administrative contact first name." + }, + { + "name": "Admin Contact - Last Name", + "description": "Administrative contact last name." + }, + { + "name": "Admin Contact - Phone", + "description": "Administrative contact phone number." + }, + { + "name": "Admin Contact - Email", + "description": "Administrative contact email address." + }, + { + "name": "Technical Contact - First Name", + "description": "Technical contact first name." + }, + { + "name": "Technical Contact - Last Name", + "description": "Technical contact last name." + }, + { + "name": "Technical Contact - Phone", + "description": "Technical contact phone number." + }, + { + "name": "Technical Contact - Email", + "description": "Technical contact email address." + }, + { + "name": "Organization Name", + "description": "Organization name for the certificate (required for OV/EV products)." + }, + { + "name": "Organization ID", + "description": "DigiCert organization ID for Enterprise Organization (-EO) products." + } + ] + } + } } diff --git a/readme_source.md b/readme_source.md index d30820f..ec93003 100644 --- a/readme_source.md +++ b/readme_source.md @@ -1,1242 +1,10 @@ -*** + +## Compatibility -# Compatibility -This AnyGateway is designed to be used with version 21.3.2 of the Keyfactor AnyGateway Framework. +The SSL Store AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 24.2 and later. -# Getting Started +## Support +The SSL Store AnyCA Gateway REST plugin 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. -## Integration Overview - -### Supported Functionality -- Certificate Sync - Full -- Certificate Enrollment for Domain Validated product suite (Regular, with SANs, and Wildcard) -- Certificate Enrollment for Organization Validated product suite (Regular, with SANs, and Wildcard) -- Certificate Enrollment for Extended Validation product suite (Regular and with SANs) -- Certificate Renewal/Reissue -- Certificate Revocation - - -### Unsupported Functionality -- Certificate Sync - Partial (not possible through the SSL Store API library) -- Approval/Denial of Enrollment Requests (not possible through the SSL Store API library) - -### Documentation -**General Documentation** -[SSLStore API Documentation](https://www.thesslstore.com/api/) - - -## Standard Gateway Installation -To begin, you must have the CA Gateway Service 21.3.2 installed and operational before attempting to configure the SSLStore Any Gateway plugin. This integration was tested with Keyfactor 8.7.0.0. -To install the gateway follow these instructions. - -1) Gateway Server - run the installation .msi obtained from Keyfactor - -2) Gateway Server - If you have the rights to install the database (usually in a Non SQL PAAS Environment) Using Powershell, run the following command to create the gateway database. - - **SQL Server Windows Auth** - ``` - %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] - ``` - Note if you are using SQL Authentication, then you need to run - - **SQL Server SQL Authentication** - - ``` - %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] -u [sql user] -p [sql password] - ``` - - If you do **not** have rights to created the database then have the database created ahead of time by the support team and just populate the database - - ## Populate commands below - - **Windows Authentication** - - ``` - %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] - ``` - - **SQL Server SQL Authentication** - - ``` - %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] -u [sql user] -p [sql password] - ``` - -3) Gateway Server - run the following Powershell to import the Cmdlets - - C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll (must be imported into Powershell) - ```ps - Import-Module C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll - ``` - -4) Gateway Server - Run the Following Powershell script to set the gateway encryption cert - - ### Set-KeyfactorGatewayEncryptionCert - This cmdlet will generate a self-signed certificate used to encrypt the database connection string. It populates a registry value with the serial number of the certificate to be used. The certificate is stored in the LocalMachine Personal Store and the registry key populated is: - - HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvcProxy\Parameters\EncryptSerialNumber - No parameters are required to run this cmdlet. - -5) Gateway Server - Run the following Powershell Script to Set the Database Connection - - ### Set-KeyfactorGatewayDatabaseConnection - This cmdlet will set and encrypt the database connection string used by the AnyGateway service. - - **Windows Authentication** - ```ps - Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] - ``` - - **SQL Authentication** - ```ps - $KeyfactorCredentials = Get-Credentials - Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] -Account [$KeyfactorCredentials] - ``` -## Standard Gateway Configuration Finished ---- - - -## SSLStore AnyGateway Specific Configuration -It is important to note that importing the SSLStore configuration into the CA Gateway prior to installing the binaries must be completed. Additionally, the CA Gateway service -must be running in order to succesfully import the configuation. When the CA Gateway service starts it will attempt to validate the connection information to -the CA. Without the imported configuration, the service will fail to start. - -### Binary Installation - -1) Get the Latest Zip File from [Here](https://github.com/Keyfactor/quovadis-cagateway/releases) -2) Gateway Server - Copy the SSLStoreCaProxy.dll to the location where the Gateway Framework was installed (usually C:\Program Files\Keyfactor\Keyfactor AnyGateway) - -### Configuration Changes -1) Gateway Server - Edit the CAProxyServer.exe.config file and replace the line that says "NoOp" with the line below: - ``` - - ``` -2) Gateway Server - Install the Intermediate Comodo Certificate that was received from SSLStore - -3) Gateway Server - Take the sample Config.json located [Here](https://github.com/Keyfactor/quovadis-cagateway/raw/main/SampleConfig.json) and make the following modifications - -- *Security Settings Modifications* (Swap this out for the typical Gateway Security Settings for Test or Prod) - -``` - "Security": { - "KEYFACTOR\\administrator": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_AppPool": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_TimerService": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - } -``` -- *SSLStore Environment Settings* (Modify these with the keys and Urls obtained from SSLStore) -``` - "CAConnection": { - "SSLStoreURL": "https://sandbox-wbapi.thesslstore.com", - "PartnerCode": "SomePartnerCodeFromSSLStore", - "AuthToken": "SomeAuthTokenFromSSLStore", - "KeyfactorApiUrl": "https://kftrain.keyfactor.lab/KeyfactorAPI", - "KeyfactorApiUserId": "SomeKeyfactorAPIUser", - "KeyfactorApiPassword": "SomeKeyfactorAPIPassword", - "PageSize": "25", - "SampleRequest": { - "AuthRequest": { - "PartnerCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - }, - "AuthToken": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - } - }, - "ProductCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - }, - "TSSOrganizationId": { - "FieldData": { - "RequiredForProducts": [ - "None" - ], - "EnrollmentFieldMapping": "Organization ID" - } - }, - "OrganizationInfo": { - "OrganizationName": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization Name" - } - }, - "RegistrationNumber": { - "FieldData": { - "RequiredForProducts": [ - "certum" - ], - "EnrollmentFieldMapping": "Organization Registration Number" - } - }, - "JurisdictionCountry": { - "FieldData": { - "RequiredForProducts": [ - "comodoevssl", - "comodoevcsc", - "comodoevmdc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "positiveevssl" - ], - "EnrollmentFieldMapping": "Organization Jurisdiction Country" - } - }, - "OrganizationAddress": { - "AddressLine1": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization Address" - } - }, - "Region": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization State/Province" - } - }, - "PostalCode": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization Postal Code" - } - }, - "LocalityName": { - "FieldData": { - "RequiredForProducts": [ - "comodocsc", - "comodoevssl", - "comodoevcsc", - "comodoevmdc", - "comodomdc", - "comodomdcwildcard", - "comodouccwildcard", - "comodoucc", - "pacenterprise" - ], - "EnrollmentFieldMapping": "Organization Locality Name" - } - }, - "Country": { - "FieldData": { - "RequiredForProducts": [ - "truebizidmd", - "digi_ev_md_ssl", - "digi_md_ssl", - "digi_plus_ev_ssl", - "digi_plus_ssl", - "digi_securesite", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_ssl_basic", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev_flex", - "digi_securesite_flex", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex" - ], - "EnrollmentFieldMapping": "Organization Country" - } - }, - "Phone": { - "FieldData": { - "RequiredForProducts": [ - "truebizidmd", - "digi_ev_md_ssl", - "digi_md_ssl", - "digi_plus_ev_ssl", - "digi_plus_ssl", - "digi_securesite", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_ssl_basic", - "digi_sslwebserver_ev_flex", - "digi_truebizid_ev_flex", - "digi_securesite_flex", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex" - ], - "EnrollmentFieldMapping": "Organization Phone" - } - } - } - }, - "ValidityPeriod": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Validity Period (In Months)" - } - }, - "ServerCount": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Server Count" - } - }, - "CSR": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - }, - "DomainName": { - "FieldData": { - "RequiredForProducts": [ - "Certum" - ], - "EnrollmentFieldMapping": "Domain Name" - } - }, - "WebServerType": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Web Server Type" - } - }, - "DNSNames": { - "FieldData": { - "RequiredForProducts": [ - "digi_ssl_ev_basic", - "digi_ssl_ev_basic-EO", - "digi_securesite_ev_flex", - "digi_securesite_ev_flex-EO", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_ev_flex-EO", - "digi_securesite_pro_flex", - "digi_securesite_pro_flex-EO", - "digi_ssl_basic", - "digi_ssl_basic-EO", - "digi_securesite_flex", - "digi_securesite_flex-EO", - "digi_truebizid_flex", - "digi_truebizid_flex-EO", - "digi_truebizid_ev_flex", - "digi_truebizid_ev_flex-EO", - "digi_ssl_dv_geotrust_flex", - "digi_rapidssl", - "digi_rapidssl_wc", - "digi_ssl123_flex", - "digi_sslwebserver_flex", - "digi_sslwebserver_flex-EO", - "digi_sslwebserver_ev_flex", - "digi_sslwebserver_ev_flex-EO", - "positivemdcssl", - "positivemdcwildcard", - "sectigodvucc", - "sectigouccwildcard", - "sectigoevmdc", - "sectigomdcwildcard", - "sectigomdc" - ], - "EnrollmentFieldMapping": "DNS Names Comma Separated", - "Array": true - } - }, - "isCUOrder": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Is CU Order?" - } - }, - "isRenewalOrder": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Is Renewal Order?" - } - }, - "isTrialOrder": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Is Trial Order?" - } - }, - "AdminContact": { - "FirstName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - First Name" - } - }, - "LastName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Last Name" - } - }, - "Phone": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Phone" - } - }, - "Email": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Email" - } - }, - "Title": { - "FieldData": { - "RequiredForProducts": [ - "symantec", - "digi_ssl_ev_basic", - "digi_sslwebserver_ev_flex", - "digi_truebizid_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_ev_flex" - ], - "EnrollmentFieldMapping": "Admin Contact - Title" - } - }, - "OrganizationName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Organization Name" - } - }, - "AddressLine1": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Address" - } - }, - "City": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - City" - } - }, - "Region": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Region" - } - }, - "PostalCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Postal Code" - } - }, - "Country": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Country" - } - } - }, - "TechnicalContact": { - "FirstName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - First Name" - } - }, - "LastName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Last Name" - } - }, - "SubjectFirstName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Subject First Name" - } - }, - "SubjectLastName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Subject Last Name" - } - }, - "Phone": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Phone" - } - }, - "Email": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Email" - } - }, - "Title": { - "FieldData": { - "RequiredForProducts": [ - "symantec", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev_flex" - ], - "EnrollmentFieldMapping": "Technical Contact - Title" - } - }, - "AddressLine1": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Address" - } - }, - "City": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - City" - } - }, - "Region": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Region" - } - }, - "PostalCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Postal Code" - } - }, - "Country": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Country" - } - } - }, - "AutoWWW": { - "FieldData": { - "RequiredForProducts": [ - "positivessl" - ], - "EnrollmentFieldMapping": "AutoWWW" - } - }, - "ApproverEmail": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Approver Email" - } - }, - "FileAuthDVIndicator": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "File Auth Domain Validation" - } - }, - "CNAMEAuthDVIndicator": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "CName Auth Domain Validation" - } - }, - "SignatureHashAlgorithm": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Signature Hash Algorithm" - } - } - } - } -``` - -- *Template Settings - See Configuration Instructional Video on how these work* -``` - "Templates": { - "positivessl": { - "ProductID": "positivessl", - "Parameters": { - "AutoWWW": "True" - } - }, - "positiveevssl": { - "ProductID": "positiveevssl", - "Parameters": {} - }, - "enterpriseproev": { - "ProductID": "enterpriseproev", - "Parameters": {} - }, - "enterpriseproevmdc": { - "ProductID": "enterpriseproevmdc", - "Parameters": {} - }, - "positivesslwildcard": { - "ProductID": "positivesslwildcard", - "Parameters": {} - }, - "positivemdcssl": { - "ProductID": "positivemdcssl", - "Parameters": {} - }, - "positivemdcwildcard": { - "ProductID": "positivemdcwildcard", - "Parameters": {} - }, - "positiveevmdc": { - "ProductID": "positiveevmdc", - "Parameters": {} - }, - "instantssl": { - "ProductID": "instantssl", - "Parameters": {} - }, - "instantsslpro": { - "ProductID": "instantsslpro", - "Parameters": {} - }, - "comodopremiumssl": { - "ProductID": "comodopremiumssl", - "Parameters": {} - }, - "comodopremiumwildcard": { - "ProductID": "comodopremiumwildcard", - "Parameters": {} - }, - "enterprisepro": { - "ProductID": "enterprisepro", - "Parameters": {} - }, - "enterpriseprowc": { - "ProductID": "enterpriseprowc", - "Parameters": {} - }, - "sectigossl": { - "ProductID": "sectigossl", - "Parameters": {} - }, - "sectigodvucc": { - "ProductID": "sectigodvucc", - "Parameters": {} - }, - "sectigoevssl": { - "ProductID": "sectigoevssl", - "Parameters": {} - }, - "sectigoevmdc": { - "ProductID": "sectigoevmdc", - "Parameters": {} - }, - "sectigoovssl": { - "ProductID": "sectigoovssl", - "Parameters": {} - }, - "sectigomdc": { - "ProductID": "sectigomdc", - "Parameters": {} - }, - "sectigomdcwildcard": { - "ProductID": "sectigomdcwildcard", - "Parameters": {} - }, - "sectigoovwildcard": { - "ProductID": "sectigoovwildcard", - "Parameters": {} - }, - "sectigowildcard": { - "ProductID": "sectigowildcard", - "Parameters": {} - }, - "sectigouccwildcard": { - "ProductID": "sectigouccwildcard", - "Parameters": {} - }, - "digi_ssl_ev_basic": { - "ProductID": "digi_ssl_ev_basic", - "Parameters": {} - }, - "digi_ssl_ev_basic-EO": { - "ProductID": "digi_ssl_ev_basic-EO", - "Parameters": {} - }, - "digi_securesite_ev_flex": { - "ProductID": "digi_securesite_ev_flex", - "Parameters": {} - }, - "digi_securesite_ev_flex-EO": { - "ProductID": "digi_securesite_ev_flex-EO", - "Parameters": {} - }, - "digi_securesite_pro_ev_flex": { - "ProductID": "digi_securesite_pro_ev_flex", - "Parameters": {} - }, - "digi_securesite_pro_ev_flex-EO": { - "ProductID": "digi_securesite_pro_ev_flex-EO", - "Parameters": {} - }, - "digi_securesite_pro_flex": { - "ProductID": "digi_securesite_pro_flex", - "Parameters": {} - }, - "digi_securesite_pro_flex-EO": { - "ProductID": "digi_securesite_pro_flex-EO", - "Parameters": {} - }, - "digi_ssl_basic": { - "ProductID": "digi_ssl_basic", - "Parameters": {} - }, - "digi_ssl_basic-EO": { - "ProductID": "digi_ssl_basic-EO", - "Parameters": {} - }, - "digi_securesite_flex": { - "ProductID": "digi_securesite_flex", - "Parameters": {} - }, - "digi_securesite_flex-EO": { - "ProductID": "digi_securesite_flex-EO", - "Parameters": {} - }, - "digi_truebizid_flex": { - "ProductID": "digi_truebizid_flex", - "Parameters": {} - }, - "digi_truebizid_flex-EO": { - "ProductID": "digi_truebizid_flex-EO", - "Parameters": {} - }, - "digi_truebizid_ev_flex": { - "ProductID": "digi_truebizid_ev_flex", - "Parameters": {} - }, - "digi_truebizid_ev_flex-EO": { - "ProductID": "digi_truebizid_ev_flex-EO", - "Parameters": {} - }, - "digi_ssl_dv_geotrust_flex": { - "ProductID": "digi_ssl_dv_geotrust_flex", - "Parameters": {} - }, - "digi_rapidssl": { - "ProductID": "digi_rapidssl", - "Parameters": {} - }, - "digi_rapidssl_wc": { - "ProductID": "digi_rapidssl_wc", - "Parameters": {} - }, - "digi_ssl123_flex": { - "ProductID": "digi_ssl123_flex", - "Parameters": {} - }, - "digi_sslwebserver_flex": { - "ProductID": "digi_sslwebserver_flex", - "Parameters": {} - }, - "digi_sslwebserver_flex-EO": { - "ProductID": "digi_sslwebserver_flex-EO", - "Parameters": {} - }, - "digi_sslwebserver_ev_flex": { - "ProductID": "digi_sslwebserver_ev_flex", - "Parameters": {} - }, - "digi_sslwebserver_ev_flex-EO": { - "ProductID": "digi_sslwebserver_ev_flex-EO", - "Parameters": {} - } - } -``` - -- *Gateway Settings* -``` - "CertificateManagers": null, - "GatewayRegistration": { - "LogicalName": "SSLStore", - "GatewayCertificate": { - "StoreName": "CA", - "StoreLocation": "LocalMachine", - "Thumbprint": "339cdd57cfd5b141169b615ff31428782d1da639" - } - } -``` - -- *Service Settings* (Modify these to be in accordance with Keyfactor Standard Gateway Production Settings) -``` - "ServiceSettings": { - "ViewIdleMinutes": 1, - "FullScanPeriodHours": 1, - "PartialScanPeriodMinutes": 1 - } -``` - -5) Gateway Server - Save the newly modified config.json to the following location "C:\Program Files\Keyfactor\Keyfactor AnyGateway" - -### Template Installation - -1) Command Server - Copy and Unzip the Template Setup Files located [Here](https://github.com/Keyfactor/sslstore-cagateway/raw/main/TemplateSetup.zip) -2) Command Server - Change the Security Settings in the CaTemplateUserSecurity.csv file to the appropriate settings for Test or Production -3) Command Server - Run the CreateTemplate.ps1 file and choose option 1 to create the templates in active directory. - *Note if you get errors the security is likely wrong and you will have to add the security manually according to Keyfactor standards* -4) Command Server - Use the Keyfactor Portal to Import the Templates created in Active Directory in step #3 above -5) Command Server - Run the CreateTemplate.ps1 file and choose option 3 to create all the enrollment fields. - *Note You will have to override the default API Questions to the appropriate information.* - -### Certificate Authority Installation -1) Gateway Server - Start the Keyfactor Gateway Service -2) Run the set Gateway command similar to below -```ps -Set-KeyfactorGatewayConfig -LogicalName "SSLStore" -FilePath [path to json file] -PublishAd -``` -3) Command Server - Import the certificate authority in Keyfactor Portal - -### Release 1.1 Notes -Look over the AutoWWW field in both the Sample Config and readme. If you want to include it for a template see the positivessl sample in the readme. It is also needed as a new field in the SampleRequest Section of the file as shown in the readme. - -*** - -### License -[Apache](https://apache.org/licenses/LICENSE-2.0) +> 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. + From e37c36d31b23a6f880699b72710b9e7392445619 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:28:13 -0400 Subject: [PATCH 18/42] Delete .claude/settings.local.json --- .claude/settings.local.json | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 591f74f..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "permissions": { - "allow": [ - "WebFetch(domain:www.thesslstore.com)", - "Bash(grep -r \"365\\\\|730\\\\|825\\\\|397\\\\|200\\\\|199\" /c/Users/bhill/source/repos/sslstore-cagateway/Setup/Templates/*.json)", - "Bash(start \"\" \"c:\\\\Users\\\\bhill\\\\source\\\\repos\\\\sslstore-cagateway\\\\docs\\\\ssl-validity-timeline.html\")", - "Bash(rm -f SslStoreCaProxy.sln)", - "Bash(dotnet new:*)", - "Bash(dotnet sln:*)", - "Bash(ls \"c:\\\\Users\\\\bhill\\\\source\\\\repos\\\\sslstore-cagateway\"/*.sln)", - "Bash(find c:Usersbhillsourcerepossslstore-cagateway -maxdepth 1 -name *.sln -type f)", - "Bash(dotnet restore:*)", - "Bash(dotnet build:*)", - "Bash(ls c:/Users/bhill/source/repos/sslstore-cagateway/*.json)", - "Bash(node -e \":*)", - "Bash(xargs grep:*)", - "Bash(dotnet tool:*)", - "Bash(powershell -Command \"[System.Reflection.Assembly]::LoadFrom\\(''C:\\\\Users\\\\bhill\\\\.nuget\\\\packages\\\\keyfactor.anygateway.ianycaplugin\\\\3.0.0\\\\lib\\\\net6.0\\\\Keyfactor.AnyGateway.IAnyCAPlugin.dll''\\).GetTypes\\(\\) | ForEach-Object { Write-Host $_.FullName; $_.GetMethods\\(\\) | ForEach-Object { Write-Host '' '' $_.Name ''\\('' \\($_.GetParameters\\(\\) | ForEach-Object { $_.ParameterType.Name + '' '' + $_.Name }\\) ''\\)'' } }\")", - "Bash(powershell -Command \"try { $asm = [System.Reflection.Assembly]::LoadFrom\\(''C:\\\\Users\\\\bhill\\\\.nuget\\\\packages\\\\keyfactor.anygateway.ianycaplugin\\\\3.0.0\\\\lib\\\\net6.0\\\\Keyfactor.AnyGateway.IAnyCAPlugin.dll''\\); $asm.GetTypes\\(\\) } catch [System.Reflection.ReflectionTypeLoadException] { $_.Exception.Types | Where-Object { $_ -ne $null } | ForEach-Object { Write-Host $_.FullName; $_.GetMethods\\(\\) | ForEach-Object { Write-Host '' '' $_.Name ''\\('' \\($_.GetParameters\\(\\) | ForEach-Object { $_.ParameterType.ToString\\(\\) + '' '' + $_.Name }\\) ''\\)'' } } }\")", - "Bash(powershell -Command \"try { $asm = [System.Reflection.Assembly]::LoadFrom\\(''C:\\\\Users\\\\bhill\\\\.nuget\\\\packages\\\\keyfactor.anygateway.ianycaplugin\\\\3.0.0\\\\lib\\\\net6.0\\\\Keyfactor.AnyGateway.IAnyCAPlugin.dll''\\); $asm.GetTypes\\(\\) } catch [System.Reflection.ReflectionTypeLoadException] { $_.Exception.Types | Where-Object { $_ -ne $null } | ForEach-Object { Write-Host $_.FullName; try { $_.GetMethods\\(\\) | ForEach-Object { Write-Host \\('' '' + $_.Name\\) } } catch { Write-Host '' \\(methods not loadable\\)'' } } }\")", - "Bash(xxd /c/Users/bhill/.nuget/packages/keyfactor.anygateway.ianycaplugin/3.0.0/lib/net6.0/Keyfactor.AnyGateway.IAnyCAPlugin.dll)", - "Bash(dotnet ildasm:*)", - "Bash(dotnet-ildasm /c/Users/bhill/.nuget/packages/keyfactor.anygateway.ianycaplugin/3.0.0/lib/net6.0/Keyfactor.AnyGateway.IAnyCAPlugin.dll)", - "Bash(python -c \":*)", - "Bash(powershell -Command \"$bytes = [System.IO.File]::ReadAllBytes\\(''C:\\\\Users\\\\bhill\\\\.nuget\\\\packages\\\\keyfactor.anygateway.ianycaplugin\\\\3.0.0\\\\lib\\\\net6.0\\\\Keyfactor.AnyGateway.IAnyCAPlugin.dll''\\); $text = [System.Text.Encoding]::ASCII.GetString\\($bytes\\); $matches = [regex]::Matches\\($text, ''[A-Za-z_][A-Za-z0-9_]{5,}''\\); $matches.Value | Sort-Object -Unique | Where-Object { $_ -match ''emplate|nroll|roduct|nnot|onfig|lugin|arameter|ingle|ync|evoke|ing$|alidat|nitializ|GetCA|IAny'' }\")" - ] - } -} From 24897283074611c35b77ec3515ae51c775541a98 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:29:52 -0400 Subject: [PATCH 19/42] Delete .vscode/settings.json --- .vscode/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 013007b..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "dotnet.preferCSharpExtension": true -} \ No newline at end of file From ed636ef7444235d1eecb6e574028cfa4f6786e4d Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Fri, 20 Mar 2026 19:32:03 +0000 Subject: [PATCH 20/42] Update generated docs --- README.md | 173 ++++++++++++++++++++++++++++--- integration-manifest.json | 207 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 359 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 69ee729..aa2c709 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Support - + · Requirements @@ -56,7 +56,7 @@ The SSL Store AnyCA Gateway REST plugin extends the capabilities of the SSL Stor The SSL Store AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 24.2 and later. ## Support -The SSL Store AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com. +The SSL Store AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. 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. @@ -136,21 +136,37 @@ The plugin supports 80+ certificate products from multiple vendors. Products are | Product Code | Description | Validation | |-------------|-------------|------------| | `digi_securesite_flex` | DigiCert Secure Site | OV | +| `digi_securesite_flex-EO` | DigiCert Secure Site (Enterprise Org) | OV | | `digi_securesite_ev_flex` | DigiCert Secure Site EV | EV | +| `digi_securesite_ev_flex-EO` | DigiCert Secure Site EV (Enterprise Org) | EV | | `digi_securesite_pro_flex` | DigiCert Secure Site Pro | OV | +| `digi_securesite_pro_flex-EO` | DigiCert Secure Site Pro (Enterprise Org) | OV | | `digi_securesite_pro_ev_flex` | DigiCert Secure Site Pro EV | EV | +| `digi_securesite_pro_ev_flex-EO` | DigiCert Secure Site Pro EV (Enterprise Org) | EV | | `digi_sslwebserver_flex` | DigiCert SSL Web Server | OV | +| `digi_sslwebserver_flex-EO` | DigiCert SSL Web Server (Enterprise Org) | OV | | `digi_sslwebserver_ev_flex` | DigiCert SSL Web Server EV | EV | +| `digi_sslwebserver_ev_flex-EO` | DigiCert SSL Web Server EV (Enterprise Org) | EV | | `digi_truebizid_flex` | DigiCert TrueBizID | OV | +| `digi_truebizid_flex-EO` | DigiCert TrueBizID (Enterprise Org) | OV | | `digi_truebizid_ev_flex` | DigiCert TrueBizID EV | EV | +| `digi_truebizid_ev_flex-EO` | DigiCert TrueBizID EV (Enterprise Org) | EV | | `digi_ssl_basic` | DigiCert Basic SSL | OV | +| `digi_ssl_basic-EO` | DigiCert Basic SSL (Enterprise Org) | OV | | `digi_ssl_ev_basic` | DigiCert Basic SSL EV | EV | +| `digi_ssl_ev_basic-EO` | DigiCert Basic SSL EV (Enterprise Org) | EV | | `digi_rapidssl` | RapidSSL | DV | | `digi_rapidssl_wc` | RapidSSL Wildcard | DV | | `digi_ssl_dv_geotrust_flex` | GeoTrust DV SSL | DV | | `digi_ssl123_flex` | GeoTrust SSL123 | DV | - -> **Note:** Most DigiCert products also have `-EO` (Enterprise Organization) variants that use a pre-configured DigiCert organization. See the [full product list](docsource/configuration.md) for details. +| `digi_quickssl_md` | DigiCert QuickSSL Multi-Domain | DV | +| `digi_client_premium` | DigiCert Client Premium | Client | +| `digi_csc` | DigiCert Code Signing | Code Signing | +| `digi_csc_ev` | DigiCert EV Code Signing | EV Code Signing | +| `digi_doc_signing_ind_500` | DigiCert Document Signing Individual 500 | Document Signing | +| `digi_doc_signing_ind_2000` | DigiCert Document Signing Individual 2000 | Document Signing | +| `digi_doc_signing_org_2000` | DigiCert Document Signing Organization 2000 | Document Signing | +| `digi_doc_signing_org_5000` | DigiCert Document Signing Organization 5000 | Document Signing | **Sectigo/Comodo Products:** @@ -159,18 +175,45 @@ The plugin supports 80+ certificate products from multiple vendors. Products are | `positivessl` | Positive SSL | DV | | `positivesslwildcard` | Positive SSL Wildcard | DV | | `positivemdcssl` | Positive SSL Multi-Domain | DV | +| `positivemdcwildcard` | Positive SSL MDC Wildcard | DV | | `positiveevssl` | Positive EV SSL | EV | +| `positiveevmdc` | Positive EV Multi-Domain | EV | | `sectigossl` | Sectigo SSL | DV | +| `sectigowildcard` | Sectigo Wildcard | DV | | `sectigoovssl` | Sectigo OV SSL | OV | +| `sectigoovwildcard` | Sectigo OV Wildcard | OV | | `sectigoevssl` | Sectigo EV SSL | EV | +| `sectigodvucc` | Sectigo DV UCC | DV | +| `sectigouccwildcard` | Sectigo UCC Wildcard | DV | | `sectigomdc` | Sectigo Multi-Domain | OV | +| `sectigomdcwildcard` | Sectigo MDC Wildcard | OV | +| `sectigoevmdc` | Sectigo EV Multi-Domain | EV | | `comodopremiumssl` | Comodo Premium SSL | OV | +| `comodopremiumwildcard` | Comodo Premium Wildcard | OV | +| `comodossl` | Comodo SSL | OV | | `comodoevssl` | Comodo EV SSL | EV | +| `comodomdc` | Comodo Multi-Domain | OV | +| `comodomdcwildcard` | Comodo MDC Wildcard | OV | +| `comodoevmdc` | Comodo EV Multi-Domain | EV | +| `comodoucc` | Comodo UCC | OV | +| `comodouccwildcard` | Comodo UCC Wildcard | OV | +| `comodowildcard` | Comodo Wildcard | OV | +| `comodocsc` | Comodo Code Signing | Code Signing | +| `comodoevcsc` | Comodo EV Code Signing | EV Code Signing | +| `comododvucc` | Comodo DV UCC | DV | +| `comodopciscan` | Comodo PCI Scan | Scanning | | `instantssl` | InstantSSL | OV | +| `instantsslpro` | InstantSSL Pro | OV | | `enterprisepro` | Enterprise Pro SSL | OV | +| `enterpriseprowc` | Enterprise Pro Wildcard | OV | | `enterpriseproev` | Enterprise Pro EV | EV | +| `enterpriseproevmdc` | Enterprise Pro EV Multi-Domain | EV | +| `enterprisessl` | Enterprise SSL | OV | +| `essentialssl` | Essential SSL | DV | +| `essentialwildcard` | Essential Wildcard | DV | +| `elitessl` | Elite SSL | OV | -> See [docsource/configuration.md](docsource/configuration.md) for the complete list of all 80+ supported products. +**Note:** Products with the `-EO` suffix are Enterprise Organization variants that use a pre-configured DigiCert organization instead of requiring organization details during enrollment. These products require only a Validity Period and Organization ID. #### 4. Certificate Validity Configuration @@ -188,8 +231,8 @@ Certificate validity is specified in days during enrollment and automatically co The plugin uses a configurable **Renewal Window** (default: 30 days) to determine behavior during certificate renewal: -- If the existing order is **within** the renewal window (expiring within N days), the plugin performs a **renewal** (new order) -- If the existing order is **outside** the renewal window (still has life remaining), the plugin performs a **reissue** on the same order +- If the existing order is **within** the renewal window (i.e., expiring within N days), the plugin performs a **renewal** (new order linked to the original) +- If the existing order is **outside** the renewal window (still has significant life remaining), the plugin performs a **reissue** on the same order ## Installation @@ -199,6 +242,7 @@ The plugin uses a configurable **Renewal Window** (default: 30 days) to determin 3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: + ```shell Depending on your AnyCA Gateway REST version, copy the unzipped directory to one of the following locations: Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions @@ -251,7 +295,7 @@ The plugin uses a configurable **Renewal Window** (default: 30 days) to determin 5. **Credential Rotation**: Regularly rotate API credentials according to your security policy 6. **Sandbox Testing**: Use the sandbox endpoint (`https://sandbox-wbapi.thesslstore.com`) for initial configuration and testing before switching to production - * **CA Connection** + ### CA Connection Fields Populate using the configuration fields collected in the [requirements](#requirements) section. @@ -262,11 +306,22 @@ The plugin uses a configurable **Renewal Window** (default: 30 days) to determin * **Enabled** - Flag to enable or disable the CA connector. Set to `true` to enable. * **RenewalWindow** - Number of days before an order's expiration date to trigger a renewal (new order) instead of a reissue (same order). Default is 30 days. + * **CA Connection** + + Populate using the configuration fields collected in the [requirements](#requirements) section. + + * **SSLStoreURL** - The Base URL for the SSL Store API endpoint (e.g. https://sandbox-wbapi.thesslstore.com). + * **PartnerCode** - The Partner Code obtained from SSL Store. + * **AuthToken** - The Authentication Token obtained from SSL Store. + * **PageSize** - The number of records to return per page during synchronization. + * **Enabled** - Flag to Enable or Disable the CA connector. + * **RenewalWindow** - Number of days before order expiry to trigger a renewal instead of a reissue. + 2. ### Template (Product) Configuration After adding the CA to the Gateway, certificate templates are automatically discovered from the plugin's built-in product registry. Each template may require different enrollment fields depending on the product type and validation level. - **Enrollment fields vary by product type. Common categories include:** + **Enrollment fields vary by product type. The following categories exist:** #### DV Products (Minimal Fields) @@ -294,9 +349,9 @@ The plugin uses a configurable **Renewal Window** (default: 30 days) to determin | **Organization Country** | Two-letter country code (e.g. US) | Yes | | **Organization Phone** | Organization phone number | Yes | - #### DigiCert OV/EV Flex Products + #### DigiCert OV Flex Products - Products like `digi_securesite_flex`, `digi_securesite_ev_flex`, `digi_truebizid_flex`: + Products like `digi_securesite_flex`, `digi_sslwebserver_flex`, `digi_truebizid_flex`: | Parameter | Description | Required | |-----------|-------------|----------| @@ -304,7 +359,6 @@ The plugin uses a configurable **Renewal Window** (default: 30 days) to determin | **Admin Contact - Last Name** | Administrative contact last name | Yes | | **Admin Contact - Phone** | Administrative contact phone | Yes | | **Admin Contact - Email** | Administrative contact email | Yes | - | **Admin Contact - Title** | Administrative contact title (EV only) | EV only | | **Approver Email** | Domain validation approver email | Yes | | **Validity Period (In Days)** | Certificate validity in days | Yes | | **Organization Name** | Organization name | Yes | @@ -315,6 +369,16 @@ The plugin uses a configurable **Renewal Window** (default: 30 days) to determin | **Organization Country** | Two-letter country code | Yes | | **Organization Phone** | Organization phone number | Yes | + #### DigiCert EV Flex Products + + Products like `digi_securesite_ev_flex`, `digi_ssl_ev_basic`, `digi_truebizid_ev_flex`: + + Same as DigiCert OV Flex, plus: + + | Parameter | Description | Required | + |-----------|-------------|----------| + | **Admin Contact - Title** | Administrative contact job title | Yes | + #### Enterprise Organization (-EO) Products Products like `digi_securesite_flex-EO`, `digi_sslwebserver_ev_flex-EO`: @@ -324,7 +388,15 @@ The plugin uses a configurable **Renewal Window** (default: 30 days) to determin | **Validity Period (In Days)** | Certificate validity in days | Yes | | **Organization ID** | DigiCert Organization ID | Yes | - > See [docsource/configuration.md](docsource/configuration.md) for complete enrollment field details for all product categories. + #### EV Products with Jurisdiction + + Products like `enterpriseproev`, `positiveevssl`, `positiveevmdc`: + + Same as OV Products, plus: + + | Parameter | Description | Required | + |-----------|-------------|----------| + | **Organization Jurisdiction Country** | Jurisdiction country code for EV validation | Yes | ### Domain Validation - Approver Emails @@ -334,9 +406,80 @@ The plugin uses a configurable **Renewal Window** (default: 30 days) to determin - **Sectigo/Comodo products**: At least one approver email must be from the approved list - Emails are validated per-domain for multi-domain certificates + ### Important Notes + + - Product IDs are automatically registered from the plugin's built-in product registry + - The `Validity Period (In Days)` is automatically converted to months for the SSL Store API + - For `-EO` (Enterprise Organization) products, the Organization ID dropdown is populated from your DigiCert account's active organizations + - DNS names (SANs) are extracted from the Keyfactor enrollment request; they do not need to be provided as a separate enrollment field + - The Common Name (CN) is extracted from the CSR subject + 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. -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 appropriate for the product type. Refer to the tables above or [docsource/configuration.md](docsource/configuration.md) for the required fields per product. +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: + + * **Approver Email** - Comma-separated approver email address(es) for domain validation. + * **Validity Period (In Days)** - Certificate validity period in days (e.g. 90, 365, 730). + * **Admin Contact - First Name** - Administrative contact first name. + * **Admin Contact - Last Name** - Administrative contact last name. + * **Admin Contact - Phone** - Administrative contact phone number. + * **Admin Contact - Email** - Administrative contact email address. + * **Admin Contact - Title** - Administrative contact job title. + * **Admin Contact - Organization Name** - Administrative contact organization name. + * **Admin Contact - Address** - Administrative contact street address. + * **Admin Contact - City** - Administrative contact city. + * **Admin Contact - Region** - Administrative contact state/province/region. + * **Admin Contact - Postal Code** - Administrative contact postal/zip code. + * **Admin Contact - Country** - Administrative contact two-letter country code (e.g. US). + * **Technical Contact - First Name** - Technical contact first name. + * **Technical Contact - Last Name** - Technical contact last name. + * **Technical Contact - Phone** - Technical contact phone number. + * **Technical Contact - Email** - Technical contact email address. + * **Technical Contact - Organization Name** - Technical contact organization name. + * **Technical Contact - Address** - Technical contact street address. + * **Technical Contact - City** - Technical contact city. + * **Technical Contact - Region** - Technical contact state/province/region. + * **Technical Contact - Postal Code** - Technical contact postal/zip code. + * **Technical Contact - Country** - Technical contact two-letter country code (e.g. US). + * **Organization Name** - Organization name for the certificate. + * **Organization Address** - Organization street address. + * **Organization City** - Organization city. + * **Organization Region** - Organization state/province/region. + * **Organization State/Province** - Organization state or province. + * **Organization Postal Code** - Organization postal/zip code. + * **Organization Country** - Organization two-letter country code (e.g. US). + * **Organization Phone** - Organization phone number. + * **Organization Jurisdiction Country** - Jurisdiction country code for EV certificates. + * **Organization ID** - DigiCert organization ID for EO (Enterprise Organization) products. + * **Server Count** - Number of server licenses for the certificate. + * **Web Server Type** - Web server type (e.g. apacheopenssl, iis, tomcat, Other). + * **Signature Hash Algorithm** - Signature hash algorithm (PREFER_SHA2, REQUIRE_SHA2, PREFER_SHA1). + * **File Auth Domain Validation** - Use file-based domain validation (True/False). + * **CName Auth Domain Validation** - Use CNAME-based domain validation (True/False). + * **Is CU Order?** - Is this a CU (Customer) order (True/False). + * **Is Renewal Order?** - Is this a renewal order (True/False). + * **Is Trial Order?** - Is this a trial order (True/False). + + +## Installation + +1. Install the AnyCA Gateway REST per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm). + +2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [SSL Store AnyCA Gateway REST plugin](https://github.com/Keyfactor/sslstore-caplugin/releases/latest) from GitHub. + +3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: + + ```shell + Depending on your AnyCA Gateway REST version, copy the unzipped directory to one of the following locations: + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions + ``` + + > The directory containing the SSL Store AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. + +4. Restart the AnyCA Gateway REST service. + +5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the SSL Store plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. ## License @@ -345,4 +488,4 @@ Apache License 2.0, see [LICENSE](LICENSE). ## Related Integrations -See all [Keyfactor Any CA Gateways (REST)](https://github.com/orgs/Keyfactor/repositories?q=anycagateway). +See all [Keyfactor Any CA Gateways (REST)](https://github.com/orgs/Keyfactor/repositories?q=anycagateway). \ No newline at end of file diff --git a/integration-manifest.json b/integration-manifest.json index fcfff7b..14c3fed 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -27,7 +27,7 @@ }, { "name": "PageSize", - "description": "The number of records to return per page during synchronization (default: 100)." + "description": "The number of records to return per page during synchronization." }, { "name": "Enabled", @@ -35,7 +35,7 @@ }, { "name": "RenewalWindow", - "description": "Number of days before order expiry to trigger a renewal instead of a reissue (default: 30)." + "description": "Number of days before order expiry to trigger a renewal instead of a reissue." } ], "enrollment_config": [ @@ -45,7 +45,7 @@ }, { "name": "Validity Period (In Days)", - "description": "Certificate validity period in days (e.g. 90, 365, 730). Automatically converted to months for the SSL Store API." + "description": "Certificate validity period in days (e.g. 90, 365, 730)." }, { "name": "Admin Contact - First Name", @@ -63,6 +63,34 @@ "name": "Admin Contact - Email", "description": "Administrative contact email address." }, + { + "name": "Admin Contact - Title", + "description": "Administrative contact job title." + }, + { + "name": "Admin Contact - Organization Name", + "description": "Administrative contact organization name." + }, + { + "name": "Admin Contact - Address", + "description": "Administrative contact street address." + }, + { + "name": "Admin Contact - City", + "description": "Administrative contact city." + }, + { + "name": "Admin Contact - Region", + "description": "Administrative contact state/province/region." + }, + { + "name": "Admin Contact - Postal Code", + "description": "Administrative contact postal/zip code." + }, + { + "name": "Admin Contact - Country", + "description": "Administrative contact two-letter country code (e.g. US)." + }, { "name": "Technical Contact - First Name", "description": "Technical contact first name." @@ -79,15 +107,182 @@ "name": "Technical Contact - Email", "description": "Technical contact email address." }, + { + "name": "Technical Contact - Organization Name", + "description": "Technical contact organization name." + }, + { + "name": "Technical Contact - Address", + "description": "Technical contact street address." + }, + { + "name": "Technical Contact - City", + "description": "Technical contact city." + }, + { + "name": "Technical Contact - Region", + "description": "Technical contact state/province/region." + }, + { + "name": "Technical Contact - Postal Code", + "description": "Technical contact postal/zip code." + }, + { + "name": "Technical Contact - Country", + "description": "Technical contact two-letter country code (e.g. US)." + }, { "name": "Organization Name", - "description": "Organization name for the certificate (required for OV/EV products)." + "description": "Organization name for the certificate." + }, + { + "name": "Organization Address", + "description": "Organization street address." + }, + { + "name": "Organization City", + "description": "Organization city." + }, + { + "name": "Organization Region", + "description": "Organization state/province/region." + }, + { + "name": "Organization State/Province", + "description": "Organization state or province." + }, + { + "name": "Organization Postal Code", + "description": "Organization postal/zip code." + }, + { + "name": "Organization Country", + "description": "Organization two-letter country code (e.g. US)." + }, + { + "name": "Organization Phone", + "description": "Organization phone number." + }, + { + "name": "Organization Jurisdiction Country", + "description": "Jurisdiction country code for EV certificates." }, { "name": "Organization ID", - "description": "DigiCert organization ID for Enterprise Organization (-EO) products." + "description": "DigiCert organization ID for EO (Enterprise Organization) products." + }, + { + "name": "Server Count", + "description": "Number of server licenses for the certificate." + }, + { + "name": "Web Server Type", + "description": "Web server type (e.g. apacheopenssl, iis, tomcat, Other)." + }, + { + "name": "Signature Hash Algorithm", + "description": "Signature hash algorithm (PREFER_SHA2, REQUIRE_SHA2, PREFER_SHA1)." + }, + { + "name": "File Auth Domain Validation", + "description": "Use file-based domain validation (True/False)." + }, + { + "name": "CName Auth Domain Validation", + "description": "Use CNAME-based domain validation (True/False)." + }, + { + "name": "Is CU Order?", + "description": "Is this a CU (Customer) order (True/False)." + }, + { + "name": "Is Renewal Order?", + "description": "Is this a renewal order (True/False)." + }, + { + "name": "Is Trial Order?", + "description": "Is this a trial order (True/False)." } + ], + "product_ids": [ + "comododvucc", + "comodoevcsc", + "comodoevmdc", + "comodoevssl", + "comodomdc", + "comodomdcwildcard", + "comodopciscan", + "comodossl", + "comodoucc", + "comodouccwildcard", + "comodowildcard", + "digi_client_premium", + "digi_csc", + "digi_csc_ev", + "digi_doc_signing_ind_2000", + "digi_doc_signing_ind_500", + "digi_doc_signing_org_2000", + "digi_doc_signing_org_5000", + "elitessl", + "enterprisessl", + "essentialssl", + "essentialwildcard", + "hackerprooftm", + "hgpcicontrolscan", + "pacbasic", + "pacpro", + "pacenterprise", + "comodocsc", + "digi_quickssl_md", + "digi_securesite_ev_flex-EO", + "digi_securesite_flex-EO", + "digi_securesite_pro_ev_flex-EO", + "digi_securesite_pro_flex", + "digi_securesite_pro_flex-EO", + "digi_ssl_basic-EO", + "digi_ssl_ev_basic-EO", + "digi_sslwebserver_ev_flex-EO", + "digi_sslwebserver_flex-EO", + "digi_truebizid_ev_flex-EO", + "digi_truebizid_flex-EO", + "comodopremiumssl", + "comodopremiumwildcard", + "enterpriseprowc", + "instantssl", + "instantsslpro", + "sectigoovssl", + "sectigoovwildcard", + "digi_securesite_flex", + "digi_ssl_basic", + "digi_sslwebserver_flex", + "digi_truebizid_flex", + "positivessl", + "positivesslwildcard", + "sectigoevssl", + "sectigossl", + "sectigowildcard", + "digi_securesite_ev_flex", + "digi_ssl_ev_basic", + "digi_sslwebserver_ev_flex", + "digi_truebizid_ev_flex", + "digi_securesite_pro_ev_flex", + "positivemdcssl", + "positivemdcwildcard", + "sectigodvucc", + "sectigouccwildcard", + "digi_rapidssl", + "digi_rapidssl_wc", + "digi_ssl_dv_geotrust_flex", + "digi_ssl123_flex", + "enterpriseproev", + "positiveevssl", + "positiveevmdc", + "sectigoevmdc", + "enterpriseproevmdc", + "sectigomdc", + "sectigomdcwildcard", + "enterprisepro" ] } } -} +} \ No newline at end of file From 6bd691bb981adeb5e7e296acab545729506c9d17 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:37:59 -0400 Subject: [PATCH 21/42] Update integration-manifest.json --- integration-manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-manifest.json b/integration-manifest.json index 14c3fed..cae479c 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -9,7 +9,7 @@ "support_level": "kf-supported", "link_github": true, "update_catalog": true, - "gateway_framework": "24.2", + "gateway_framework": "25.5", "about": { "carest": { "ca_plugin_config": [ @@ -285,4 +285,4 @@ ] } } -} \ No newline at end of file +} From 6ef10e98b8c21d24c20da4037fd3ba67d0ab28ff Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Fri, 20 Mar 2026 19:39:56 +0000 Subject: [PATCH 22/42] Update generated docs --- README.md | 2 +- integration-manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aa2c709..d127fd8 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ The SSL Store AnyCA Gateway REST plugin extends the capabilities of the SSL Stor ## Compatibility -The SSL Store AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 24.2 and later. +The SSL Store AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 25.5 and later. ## Support The SSL Store AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com. diff --git a/integration-manifest.json b/integration-manifest.json index cae479c..4f22c79 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -285,4 +285,4 @@ ] } } -} +} \ No newline at end of file From 6970e321743ef9e67bdcdab6d6c4d598240ae234 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:40:52 -0400 Subject: [PATCH 23/42] Update keyfactor-starter-workflow.yml --- .github/workflows/keyfactor-starter-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/keyfactor-starter-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml index 64919a4..f6949fd 100644 --- a/.github/workflows/keyfactor-starter-workflow.yml +++ b/.github/workflows/keyfactor-starter-workflow.yml @@ -11,7 +11,7 @@ on: jobs: call-starter-workflow: - uses: keyfactor/actions/.github/workflows/starter.yml@v3 + uses: keyfactor/actions/.github/workflows/starter.yml@v4 secrets: token: ${{ secrets.V2BUILDTOKEN}} APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} From c24d94ba0df216ea423d3a3493ed3819d0dea5e6 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:41:59 -0400 Subject: [PATCH 24/42] Update keyfactor-starter-workflow.yml --- .github/workflows/keyfactor-starter-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/keyfactor-starter-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml index f6949fd..64919a4 100644 --- a/.github/workflows/keyfactor-starter-workflow.yml +++ b/.github/workflows/keyfactor-starter-workflow.yml @@ -11,7 +11,7 @@ on: jobs: call-starter-workflow: - uses: keyfactor/actions/.github/workflows/starter.yml@v4 + uses: keyfactor/actions/.github/workflows/starter.yml@v3 secrets: token: ${{ secrets.V2BUILDTOKEN}} APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} From 5d9fc96d77b7fca8802d5e41ce87a32aa9bad2fa Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:53:59 -0400 Subject: [PATCH 25/42] Delete docs/ssl-validity-timeline.html --- docs/ssl-validity-timeline.html | 1323 ------------------------------- 1 file changed, 1323 deletions(-) delete mode 100644 docs/ssl-validity-timeline.html diff --git a/docs/ssl-validity-timeline.html b/docs/ssl-validity-timeline.html deleted file mode 100644 index 942e453..0000000 --- a/docs/ssl-validity-timeline.html +++ /dev/null @@ -1,1323 +0,0 @@ - - - - - -SSL Certificate Validity Timeline - Keyfactor CA Gateway Impact - - - - -

SSL/TLS Certificate Validity Reduction Timeline

-

Impact on Keyfactor AnyGateway ↔ TheSSLStore API Integration  |  CA/Browser Forum Ballot SC-081v3

- -
- - -

Regulatory Phase Timeline

-

CA/Browser Forum Ballot SC-081v3 — phased reduction of public TLS certificate max validity

- -
- - -
-
-
-
Before March 15, 2026
-

Current State — 398 Days Max

-

Templates offer 12-60 month validity. Renewals copy prior order validity. DCV reuse up to 398 days. Multi-year plans reissue once per year.

- CURRENT -
-
- - -
-
-
-
March 15, 2026 — 200 Days Max
-

Phase 1: Half the Validity

-

Max cert lifetime drops to 200 days (~6.5 months). DCV reuse drops to 200 days. Multi-year plans still valid — but certs must be reissued every ~6 months instead of every year. No extra cost, just more frequent reissues.

- IMMINENT — 13 DAYS AWAY -
-
- - -
-
-
-
March 15, 2027 — 100 Days Max
-

Phase 2: Quarterly Reissues

-

Max validity drops to 100 days. DCV reuse drops to 100 days. Multi-year plan = ~4 free reissues per year. AD template renewal windows need tightening.

- 1 YEAR AWAY -
-
- - -
-
-
-
March 15, 2029 — 47 Days Max
-

Phase 3: Full Automation Required

-

Max validity drops to 47 days. DCV reuse drops to 10 days. Multi-year plan = ~8 reissues/year. Manual workflows impossible. DCV re-validation on nearly every reissue.

- 3 YEARS AWAY -
-
- -
- - -

The SSLStore Multi-Year Subscription Model

-

SSLStore sells multi-year plans (2-3 years). You pay once. The actual certificate is only valid for the current max. When it expires, you reissue for free under the same order. You do NOT buy a new certificate.

- -
-

Key Concept: Order Expiry vs Certificate Expiry

-

The SSLStore API returns two different dates that the gateway must distinguish:

-
    -
  • OrderExpiryDate (NewOrderResponse.cs:35) — when the paid subscription plan expires (e.g., 2-3 years)
  • -
  • CertificateEndDate (NewOrderResponse.cs:15) — when the actual issued certificate expires (200 days after Phase 1)
  • -
-

When the cert expires but the order is still valid, the correct action is a free reissue (/rest/order/reissue), NOT a paid renewal (/rest/order/neworder).

-
- - -
-
-
Today: 2-Year Plan with 365-Day Certs (730 ÷ 2)
-
-
Order (paid)
-
-
2-year subscription plan (730 days)
-
-
-
-
Cert #1
-
-
365 days — included with plan
-
-
-
-
Cert #2 (reissue)
-
-
365 days — FREE reissue
-
-
-
- -
-
Phase 1: Same 2-Year Plan with ~183-Day Certs (730 ÷ 4)
-
-
Order (paid)
-
-
2-year subscription plan (730 days) — same price
-
-
-
-
Cert #1
-
-
183d
-
-
-
-
Cert #2 (reissue)
-
-
183d — FREE
-
-
-
-
Cert #3 (reissue)
-
-
183d — FREE
-
-
-
-
Cert #4 (reissue)
-
-
183d — FREE
-
-
-
- -
-
Phase 3: Same 2-Year Plan with 47-Day Certs
-
-
Order (paid)
-
-
2-year plan (730 days) — same price, ~16 reissues
-
-
-
-
Certs (reissues)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
~16 × 47-day certs — all FREE reissues under same order
-
-
-
-
- - -

The Renew vs Reissue Problem

-

The Keyfactor framework decides Renew vs Reissue based on the AD certificate template settings — but it doesn't know whether the SSLStore order is still active. This causes the wrong API call.

- -
-

Critical Bug: Keyfactor Sends "Renew" When It Should Send "Reissue"

-

The Keyfactor AnyGateway framework controls the enrollment type sent to the gateway. When a cert enters the AD template's renewal period, the framework sends EnrollmentType.Renew. The gateway then blindly calls /rest/order/neworder with IsRenewalOrder=true — creating a new paid order.

-

But if the customer has a multi-year plan, the order is still valid. The correct action is /rest/order/reissue (free). The good news: OrderExpiryDate is already returned by /rest/order/status (confirmed via Postman), already mapped in NewOrderResponse.cs:35, and already on the INewOrderResponse interface. The orderStatusResponse object in the Renew handler already has this value — no model or API changes required.

-
- -
-

Important: "Order Still Open" Is Not Enough — Remaining Time Must Fit the New Cert

-

Simply checking OrderExpiryDate > today is insufficient. Consider this scenario:

-
    -
  • Current cert expires in 30 days (inside renewal window — trigger fires)
  • -
  • Order expiry is 45 days away (order is technically still "open")
  • -
  • Desired new cert validity: 200 days (Phase 1 max)
  • -
-

The order is open, but there's only 45 days left — not enough room for a 200-day cert. Attempting a reissue here would either be rejected by the SSLStore API or result in a truncated cert. The gateway must compare remaining order time vs desired cert validity and fall back to a paid renewal when there isn't enough room.

-
- -
-
-
-

Current Behavior (WRONG)

- CAUSES UNNECESSARY CHARGES -
-
-
-
-
AD Template
-

Cert enters renewal window (6 weeks before expiry)

-

Framework sends EnrollmentType.Renew

-
-
-
-
CA Gateway
-

GetRenewalRequest() called

-

Copies old validity, sets IsRenewalOrder=true

- NO ORDER CHECK -
-
-
-
SSLStore API
-

/rest/order/neworder

-

Creates NEW paid order even though the existing order is still valid

- CUSTOMER CHARGED -
-
-
-
- -
-
-

Correct Behavior (NEEDED)

- FREE REISSUE UNDER EXISTING ORDER -
-
-
-
-
AD Template
-

Cert enters renewal window (framework sends Renew)

-

Framework behavior unchanged

-
-
-
-
CA Gateway (FIXED)
-

Check two conditions:
- 1. OrderExpiryDate > now
- 2. (OrderExpiryDate - now) ≥ desiredValidity

-

BOTH trueGetReIssueRequest() (free)
Either falseGetRenewalRequest() (new purchase)

- SMART ROUTING -
-
-
-
SSLStore API
-

If order valid: /rest/order/reissueFREE

-

If order expired: /rest/order/neworder → new purchase

- CORRECT API CALL -
-
-
-
-
- - -

AD Certificate Template Settings

-

The AD template's Validity Period and Renewal Period control when Keyfactor triggers renewals. These must be updated to match actual cert lifetimes, or the renewal window becomes miscalibrated.

- - -
-
-
Today: Validity = 1 Year, Renewal Window = 6 Weeks
-
-
Certificate
-
-
Active (319 days)
-
Renew (42d)
-
-
-
- -
-
Phase 1 Recommended: Validity = 6 Months, Renewal Window = 4 Weeks
-
-
Certificate
-
-
Active (~172 days)
-
Renew (28d)
-
-
-
- -
-
Phase 2 Recommended: Validity = 3 Months, Renewal Window = 3 Weeks
-
-
Certificate
-
-
Active (~79 days)
-
Renew (21d)
-
-
-
- -
-
Phase 3 Recommended: Validity = 2 Months, Renewal Window = 2 Weeks
-
-
Certificate
-
-
Active (~33 days)
-
Renew (14d)
-
-
-
- -
-
Phase 3 BROKEN: If you keep Validity = 1 Year, Renewal Window = 6 Weeks
-
-
Certificate
-
-
Cert is only 47 days — but KF thinks it has 365 days. Renewal never triggers!
-
-
-
-
- -
-

Important: Keyfactor Uses the Actual Cert Expiration Date

-

Keyfactor Command reads the NotAfter date from the synced certificate, not the AD template validity period, to determine when the cert actually expires. So the renewal window will fire based on real cert expiry. However:

-
    -
  • The AD template validity should still match actual cert validity to avoid confusion and audit issues
  • -
  • The renewal window duration (6 weeks) is what really matters — it must not exceed the cert lifetime
  • -
  • At 47 days (Phase 3), a 6-week renewal window means renewal triggers on day 5 — essentially immediately
  • -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhaseMax Cert ValidityAD Template ValidityAD Renewal PeriodEffective Active TimeReissues per Year
(2-yr plan)
Today398 days1 year6 weeks~319 days1
Phase 1 (Mar 2026)200 days6 months4 weeks~172 days~4
Phase 2 (Mar 2027)100 days3 months3 weeks~79 days~8
Phase 3 (Mar 2029)47 days2 months2 weeks~33 days~16
- - -

Template Validity Options: What Breaks When

-

Current enrollment field options (in months) from Setup/Templates/*.json mapped against each phase's maximum

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Template OptionDaysToday (398d max)Phase 1 (200d max)Phase 2 (100d max)Phase 3 (47d max)
60 months (5 yr)~1825Already invalid since 2020REJECTEDREJECTEDREJECTED
48 months (4 yr)~1460Already invalid since 2020REJECTEDREJECTEDREJECTED
36 months (3 yr)~1095Already invalid since 2020REJECTEDREJECTEDREJECTED
24 months (2 yr)~730Already invalid since 2020REJECTEDREJECTEDREJECTED
12 months (1 yr)~365VALIDREJECTEDREJECTEDREJECTED
6 months (new)~180VALIDVALIDREJECTEDREJECTED
3 months (new)~90VALIDVALIDVALIDREJECTED
1 month (new)~30VALIDVALIDVALIDVALID
- - -

Order Flow: Keyfactor GW ↔ SSLStore API

-

How new enrollment, renewal/reissue, and sync flows change across each phase

- -
-
Breaking Change
-
Warning / Needs Update
-
No Change Needed
-
Code Change Required
-
- -
- - -
-
-

Phase 1: March 15, 2026 — 200 Day Maximum

- MAX 200 DAYS -
-
- - -

New Enrollment Flow

-
-
-
1. Keyfactor Command
-

User selects template & picks validity from enrollment field dropdown

- BREAKS: 12-60 month options invalid -
-
-
-
2. CA Gateway
-

BuildNewOrderRequest() maps template validity to ValidityPeriod field

- UPDATE: Templates need 6-month option -
-
-
-
3. SSLStore API
-

/rest/order/neworder — API rejects if cert validity > 200 days

- API ENFORCES NEW LIMIT -
-
- - -

Cert Expiry on Multi-Year Plan (Renew vs Reissue)

-
-
-
1. Keyfactor Command
-

200-day cert enters renewal window. Framework sends EnrollmentType.Renew regardless of order status.

- ALWAYS SENDS RENEW -
-
-
-
2. CA Gateway (TODAY)
-

GetRenewalRequest() copies old validity, creates new paid order. Does NOT check if existing order is still valid.

- WRONG: CREATES NEW PAID ORDER -
-
-
-
3. SSLStore API
-

/rest/order/neworder — charges customer for a new order when a free reissue would have worked

- CUSTOMER OVERCHARGED -
-
- -
-
-
1. Keyfactor Command
-

Same trigger — no change to framework

- NO CHANGE -
-
-
-
2. CA Gateway (FIXED)
-

On Renew: query order status, check OrderExpiryDate. If order still valid → /rest/order/reissue (free). If expired → /rest/order/neworder.

- NEW: Smart renew/reissue routing -
-
-
-
3. SSLStore API
-

/rest/order/reissue → free cert under existing plan

- CORRECT: FREE REISSUE -
-
- - -

Sync / Inventory Flow

-
-
-
1. SSLStore API
-

/rest/order/query & /rest/order/status return shorter-lived certs

- NO CHANGE -
-
-
-
2. CA Gateway
-

Synchronize() downloads certs, maps status, stores in Keyfactor

- NO CHANGE -
-
-
-
3. Keyfactor Command
-

Inventory updated. Expiration alerts trigger sooner — 2x more renewals

- REVIEW: Alert thresholds & AD template renewal period -
-
-
-
- - -
-
-

Phase 2: March 15, 2027 — 100 Day Maximum

- MAX 100 DAYS -
-
- -

New Enrollment Flow

-
-
-
1. Keyfactor Command
-

Template dropdown now needs 3-month option (or less). AD template validity & renewal period updated.

- UPDATE: Templates & AD settings -
-
-
-
2. CA Gateway
-

ValidityPeriod must be ≤3 months. 6-month option now invalid. Smart reissue logic handles multi-year plans.

- UPDATE: Remove 6-month option -
-
-
-
3. SSLStore API
-

API enforces 100-day max. DCV reuse also 100 days. ~4 reissues/year on 2-yr plan.

- API ENFORCES -
-
- -

DCV Reuse Impact

-
-
-
CA Gateway
-

FileAuthDvIndicator / CNameAuthDvIndicator still reuse prior DCV

- DCV expires every 100 days -
-
-
-
SSLStore API
-

Prior DCV may be expired. Re-validation triggered more often.

- MORE DCV CHALLENGES -
-
-
-
Operations
-

DNS/File validation challenges ~4x/year per domain instead of 1x

- PROCESS IMPACT -
-
-
-
- - -
-
-

Phase 3: March 15, 2029 — 47 Day Maximum

- MAX 47 DAYS -
-
- -

Full Automation Required

-
-
-
Keyfactor Command
-

Must auto-trigger reissues ~14 days before expiry. ~16 reissues/year on 2-yr plan. Manual approval workflows become unsustainable.

- REQUIRES AUTO-RENEWAL -
-
-
-
CA Gateway
-

Smart reissue routing critical at this volume. Must handle 10-day DCV reuse — nearly every reissue needs fresh DCV.

- MAJOR: DCV REARCHITECT -
-
-
-
SSLStore API
-

47-day certs, 10-day DCV reuse. API will require automated DCV completion for every reissue.

- API CHANGES EXPECTED -
-
- -

Scale Impact

-
-
-
Volume
-

100 certs today = 800 reissue operations/year. Sync must handle increased order volume. API rate limits become a concern.

-
-
-
-
DCV
-

10-day reuse = DCV validation with almost every reissue. DNS automation (RFC 2136 / cloud API) becomes mandatory.

-
-
-
-
Operations
-

Zero-touch pipeline required end-to-end. Any manual step becomes a bottleneck at this reissue frequency.

-
-
-
-
- -
- - -

Specific Code Impacts

-

Files and methods in this gateway that require changes

- -
- -
-

1. Renew Handler — Needs Smart Reissue Routing

- SslStoreCaProxy/SslStoreCaProxy.cs:160-186 -

When Keyfactor sends EnrollmentType.Renew, the gateway must check if the SSLStore order is still valid. If so, perform a free reissue instead of creating a new paid order.

-
// Current: always creates new paid order
-case RequestUtilities.EnrollmentType.Renew:
-  var renewRequest = _requestManager
-    .GetRenewalRequest(orderStatusResponse, csr);
-  // calls /rest/order/neworder ← WRONG for multi-year plans
-
-// Needed: two-condition check
-var orderExpiry = DateTime.Parse(
-    orderStatusResponse.OrderExpiryDateInUtc);
-var desiredValidityDays = orderStatusResponse.Validity;
-var remainingDays =
-    (orderExpiry - DateTime.UtcNow).TotalDays;
-
-if (remainingDays >= desiredValidityDays) {
-  // Enough room in order → FREE reissue
-  reIssueRequest = _requestManager
-    .GetReIssueRequest(orderStatusResponse, csr, true);
-  // calls /rest/order/reissue ← FREE
-} else {
-  // Order expired OR not enough room for new cert
-  // → new purchase
-  var renewRequest = _requestManager
-    .GetRenewalRequest(orderStatusResponse, csr);
-  // calls /rest/order/neworder
-}
-
-// Examples:
-// Order has 400d left, want 200d cert → 400 >= 200 → REISSUE (free)
-// Order has 45d left,  want 200d cert → 45  <  200 → RENEW  (paid)
-// Order expired,       want 200d cert →  0  <  200 → RENEW  (paid)
-
- -
-

2. OrderExpiryDate — Already Available (No Model Changes)

- SslStoreCaProxy/Client/Models/NewOrderResponse.cs:35 & Interfaces/INewOrderResponse.cs:28 -

Confirmed via Postman: /rest/order/status already returns OrderExpiryDate. The model already maps it. The interface already exposes it. The orderStatusResponse in the Renew handler is already an INewOrderResponse — the data is there right now, just never checked.

-
// /rest/order/status response (confirmed):
-"OrderExpiryDate": "2/19/2022 12:00:00 AM",
-"OrderExpiryDateInUTC": "2/19/2022 5:00:00 AM"
-
-// NewOrderResponse.cs:35 - already mapped:
-public string OrderExpiryDate { get; set; }
-[JsonProperty("OrderExpiryDateInUTC")]
-public string OrderExpiryDateInUtc { get; set; }
-
-// INewOrderResponse.cs:28 - already on interface:
-string OrderExpiryDate { get; set; }
-string OrderExpiryDateInUtc { get; set; }
-
-// Fix is ONE if-check in SslStoreCaProxy.cs:
-// orderStatusResponse.OrderExpiryDate is
-// already populated. Just use it.
-
- -
-

3. Renewal Copies Old Validity

- SslStoreCaProxy/RequestManager.cs:211 -

GetRenewalRequest() blindly copies orderData.Validity from the prior order. Old 12-month orders will produce 12-month renewal requests that fail.

-
// Current code (line 211):
-ValidityPeriod = orderData.Validity,
-
-// Needs to cap to current max:
-ValidityPeriod = Math.Min(orderData.Validity, MAX_VALIDITY),
-
- -
-

4. Template Files — Validity Options

- Setup/Templates/*.json (80+ files) -

All templates list 12, 24, 36, 48, 60 month options. After Phase 1, only ≤6 months is valid.

-
"Name": "Validity Period (In Months)",
-"Options": [
-  "12",   ← REJECTED (365 days > 200)
-  "24",   ← REJECTED
-  "36",   ← REJECTED
-  "48",   ← REJECTED
-  "60"    ← REJECTED
-]
-// Replace with:
-"Options": [ "6" ]
-
- -
-

5. New Enrollment — No Validation

- SslStoreCaProxy/RequestManager.cs:281 -

BuildNewOrderRequest() passes validity straight through from the template with no bounds checking. The API will reject, but errors surface late.

-
// Line 281 - passed through unchecked:
-CreatePropertyFromTemplate(
-  "$.ValidityPeriod", productInfo,
-  newOrderRequest)
-
-// Consider: pre-validate before API call
-// to give users a clear error message
-
- -
-

6. Expired Cert Handling

- SslStoreCaProxy/SslStoreCaProxy.cs:152-157 -

If a cert expires before Keyfactor triggers renewal, the gateway rejects with a hard error. With shorter lifetimes this will happen more often. Consider auto-falling back to new enrollment.

-
return new EnrollmentResult {
-  Status = 30, //failure
-  StatusMessage = "You cannot renew an expired
-    cert please perform an new enrollment."
-};
-
-// Consider: auto-fallback to new enrollment
-// instead of hard failure
-
- -
- - -

Gameplan & Implementation Timeline

-

Prioritized action items across all three phases

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
WhenPriorityTypeActionFiles / Config
NOW
(before Mar 15)
P0CodeSmart Renew/Reissue routing — When gateway receives EnrollmentType.Renew, compare (OrderExpiryDate - today) against the desired cert validity. If remaining order time ≥ desired validity → free reissue. Otherwise → new paid renewal. OrderExpiryDate already populated on orderStatusResponse, no model changes needed.SslStoreCaProxy.cs:160-186
NOW
(before Mar 15)
P0CodeCap renewal validity — Fix GetRenewalRequest() to not blindly copy orderData.Validity. Cap to 6 months max.RequestManager.cs:211
NOW
(before Mar 15)
P0ConfigUpdate template validity options — Replace 12-60 month options with 6-month across all 80+ template filesSetup/Templates/*.json
NOW
(before Mar 15)
P0ConfigUpdate AD certificate templates — Set Validity Period to 6 months, Renewal Period to 4 weeksAD Certificate Templates (certtmpl.msc)
Q2 2026P1CodeAdd validity pre-validation in BuildNewOrderRequest() with clear error messages before hitting the APIRequestManager.cs:281
Q2 2026P1CodeImprove expired cert handling — auto-fallback to new enrollment instead of hard failure messageSslStoreCaProxy.cs:152-157
Q2 2026P1ConfigReview Keyfactor Command expiration alert thresholds for 200-day cert lifecycleKeyfactor Command config
Q4 2026P1ConfigPrepare for Phase 2: update templates to 3-month max, AD template validity to 3 months, renewal period to 3 weeksTemplates/*.json, AD templates
2028P2ArchArchitect automated DCV pipeline for 10-day reuse window. Evaluate DNS-01 automation (RFC 2136 / cloud provider APIs)RequestManager.cs, new DCV module
2028-2029P2ArchZero-touch pipeline: auto-DCV, auto-reissue, auto-deployment. AD templates at 2 months / 2 week renewal. 16 reissues/year on 2-yr plans.Full gateway + Keyfactor orchestrator
-
- -
- Generated for sslstore-cagateway (branch: sslapifixes)  |  Based on CA/Browser Forum Ballot SC-081v3  |  March 2, 2026
- Sources: thesslstore.com, digicert.com, sectigo.com, appviewx.com -
- - - From 0515a709146a23500727e2facfaf7c7a96cb9a24 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:56:56 -0400 Subject: [PATCH 26/42] Update keyfactor-starter-workflow.yml --- .github/workflows/keyfactor-starter-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/keyfactor-starter-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml index 64919a4..f6949fd 100644 --- a/.github/workflows/keyfactor-starter-workflow.yml +++ b/.github/workflows/keyfactor-starter-workflow.yml @@ -11,7 +11,7 @@ on: jobs: call-starter-workflow: - uses: keyfactor/actions/.github/workflows/starter.yml@v3 + uses: keyfactor/actions/.github/workflows/starter.yml@v4 secrets: token: ${{ secrets.V2BUILDTOKEN}} APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} From d9f8ae0cc1fde7b11e63a71818ca7c460f9c5235 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:58:09 -0400 Subject: [PATCH 27/42] Update keyfactor-starter-workflow.yml --- .github/workflows/keyfactor-starter-workflow.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/keyfactor-starter-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml index f6949fd..7b909a3 100644 --- a/.github/workflows/keyfactor-starter-workflow.yml +++ b/.github/workflows/keyfactor-starter-workflow.yml @@ -14,7 +14,6 @@ jobs: uses: keyfactor/actions/.github/workflows/starter.yml@v4 secrets: token: ${{ secrets.V2BUILDTOKEN}} - APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} scan_token: ${{ secrets.SAST_TOKEN }} From 9d93899e3fcabad7a6f5133bdfde64f44ecad125 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Mon, 23 Mar 2026 09:06:05 -0400 Subject: [PATCH 28/42] Update configuration.md --- docsource/configuration.md | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/docsource/configuration.md b/docsource/configuration.md index 6a1a36a..d3592a4 100644 --- a/docsource/configuration.md +++ b/docsource/configuration.md @@ -191,26 +191,6 @@ The plugin uses a configurable **Renewal Window** (default: 30 days) to determin - If the existing order is **within** the renewal window (i.e., expiring within N days), the plugin performs a **renewal** (new order linked to the original) - If the existing order is **outside** the renewal window (still has significant life remaining), the plugin performs a **reissue** on the same order -## Installation - -1. Install the AnyCA Gateway REST per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm). - -2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [SSL Store AnyCA Gateway REST plugin](https://github.com/Keyfactor/sslstore-caplugin/releases/latest) from GitHub. - -3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: - - ```shell - Depending on your AnyCA Gateway REST version, copy the unzipped directory to one of the following locations: - Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions - Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions - ``` - - > The directory containing the SSL Store AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. - -4. Restart the AnyCA Gateway REST service. - -5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the SSL Store plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. - ## Gateway Registration ### CA Connection Configuration From d3997a08a8d1b1ac80320b5c38b0d5763522a969 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Mon, 23 Mar 2026 13:08:11 +0000 Subject: [PATCH 29/42] Update generated docs --- README.md | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/README.md b/README.md index d127fd8..e4e1873 100644 --- a/README.md +++ b/README.md @@ -461,26 +461,6 @@ The plugin uses a configurable **Renewal Window** (default: 30 days) to determin * **Is Trial Order?** - Is this a trial order (True/False). -## Installation - -1. Install the AnyCA Gateway REST per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm). - -2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [SSL Store AnyCA Gateway REST plugin](https://github.com/Keyfactor/sslstore-caplugin/releases/latest) from GitHub. - -3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: - - ```shell - Depending on your AnyCA Gateway REST version, copy the unzipped directory to one of the following locations: - Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions - Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions - ``` - - > The directory containing the SSL Store AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. - -4. Restart the AnyCA Gateway REST service. - -5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the SSL Store plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. - ## License From 94c15f83c60edb9d7149cf6727f252aa53760a81 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 23 Mar 2026 09:29:43 -0400 Subject: [PATCH 30/42] adding .sln file --- SslStoreCaProxy.sln | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 SslStoreCaProxy.sln diff --git a/SslStoreCaProxy.sln b/SslStoreCaProxy.sln new file mode 100644 index 0000000..f5627b8 --- /dev/null +++ b/SslStoreCaProxy.sln @@ -0,0 +1,19 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SslStoreCaProxy", "SslStoreCaProxy\SslStoreCaProxy.csproj", "{8A3CDCC5-4B53-4D50-B163-2D18B7D1D895}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8A3CDCC5-4B53-4D50-B163-2D18B7D1D895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A3CDCC5-4B53-4D50-B163-2D18B7D1D895}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A3CDCC5-4B53-4D50-B163-2D18B7D1D895}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A3CDCC5-4B53-4D50-B163-2D18B7D1D895}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal From ffc9ecdf6837b8f437484a02724cfd4f5983f6db Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 23 Mar 2026 09:32:46 -0400 Subject: [PATCH 31/42] removed file --- SslStoreCaProxy.sln | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 SslStoreCaProxy.sln diff --git a/SslStoreCaProxy.sln b/SslStoreCaProxy.sln deleted file mode 100644 index f5627b8..0000000 --- a/SslStoreCaProxy.sln +++ /dev/null @@ -1,19 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SslStoreCaProxy", "SslStoreCaProxy\SslStoreCaProxy.csproj", "{8A3CDCC5-4B53-4D50-B163-2D18B7D1D895}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8A3CDCC5-4B53-4D50-B163-2D18B7D1D895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8A3CDCC5-4B53-4D50-B163-2D18B7D1D895}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8A3CDCC5-4B53-4D50-B163-2D18B7D1D895}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8A3CDCC5-4B53-4D50-B163-2D18B7D1D895}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal From 02a2638d67121db4ce7bff39d2b63ea4ce3e2e21 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 23 Mar 2026 09:44:47 -0400 Subject: [PATCH 32/42] added .sln --- SslStoreCaProxy.sln | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 SslStoreCaProxy.sln diff --git a/SslStoreCaProxy.sln b/SslStoreCaProxy.sln new file mode 100644 index 0000000..fde8b96 --- /dev/null +++ b/SslStoreCaProxy.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SslStoreCaProxy", "SslStoreCaProxy\SslStoreCaProxy.csproj", "{DB47A07B-C9DC-4626-9818-783A4717CF1C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|x64.ActiveCfg = Debug|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|x64.Build.0 = Debug|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|x86.ActiveCfg = Debug|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|x86.Build.0 = Debug|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|Any CPU.Build.0 = Release|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|x64.ActiveCfg = Release|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|x64.Build.0 = Release|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|x86.ActiveCfg = Release|Any CPU + {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal From 69a7bfd21cfb071e4e82341a10deb4f4affb6be8 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 23 Mar 2026 09:48:39 -0400 Subject: [PATCH 33/42] removed slnx --- SslStoreCaProxy.slnx | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 SslStoreCaProxy.slnx diff --git a/SslStoreCaProxy.slnx b/SslStoreCaProxy.slnx deleted file mode 100644 index ba17d13..0000000 --- a/SslStoreCaProxy.slnx +++ /dev/null @@ -1,3 +0,0 @@ - - - From 19a46f9ea226fd51df00cda399ae0e7493d4847d Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 23 Mar 2026 10:05:48 -0400 Subject: [PATCH 34/42] added back slnx --- SslStoreCaProxy.sln | 34 ---------------------------------- SslStoreCaProxy.slnx | 3 +++ 2 files changed, 3 insertions(+), 34 deletions(-) delete mode 100644 SslStoreCaProxy.sln create mode 100644 SslStoreCaProxy.slnx diff --git a/SslStoreCaProxy.sln b/SslStoreCaProxy.sln deleted file mode 100644 index fde8b96..0000000 --- a/SslStoreCaProxy.sln +++ /dev/null @@ -1,34 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SslStoreCaProxy", "SslStoreCaProxy\SslStoreCaProxy.csproj", "{DB47A07B-C9DC-4626-9818-783A4717CF1C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|x64.ActiveCfg = Debug|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|x64.Build.0 = Debug|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|x86.ActiveCfg = Debug|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Debug|x86.Build.0 = Debug|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|Any CPU.Build.0 = Release|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|x64.ActiveCfg = Release|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|x64.Build.0 = Release|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|x86.ActiveCfg = Release|Any CPU - {DB47A07B-C9DC-4626-9818-783A4717CF1C}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/SslStoreCaProxy.slnx b/SslStoreCaProxy.slnx new file mode 100644 index 0000000..ba17d13 --- /dev/null +++ b/SslStoreCaProxy.slnx @@ -0,0 +1,3 @@ + + + From 53548b44b4e44a7948b3888ea56d155da172655a Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 23 Mar 2026 10:17:16 -0400 Subject: [PATCH 35/42] removed old file --- SampleConfig.json | 1084 --------------------------------------------- 1 file changed, 1084 deletions(-) delete mode 100644 SampleConfig.json diff --git a/SampleConfig.json b/SampleConfig.json deleted file mode 100644 index dcb3f97..0000000 --- a/SampleConfig.json +++ /dev/null @@ -1,1084 +0,0 @@ -{ - "Security": { - "KEYFACTOR\\administrator": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_AppPool": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_TimerService": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - } - }, - "CAConnection": { - "SSLStoreURL": "https://sandbox-wbapi.thesslstore.com", - "PartnerCode": "SomePartnerCodeFromSSLStore", - "AuthToken": "SomeAuthTokenFromSSLStore", - "KeyfactorApiUrl": "https://kftrain.keyfactor.lab/KeyfactorAPI", - "KeyfactorApiUserId": "SomeKeyfactorAPIUser", - "KeyfactorApiPassword": "SomeKeyfactorAPIPassword", - "PageSize": "25", - "SampleRequest": { - "AuthRequest": { - "PartnerCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - }, - "AuthToken": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - } - }, - "ProductCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - }, - "TSSOrganizationId": { - "FieldData": { - "RequiredForProducts": [ - "None" - ], - "EnrollmentFieldMapping": "Organization ID" - } - }, - "OrganizationInfo": { - "OrganizationName": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization Name" - } - }, - "RegistrationNumber": { - "FieldData": { - "RequiredForProducts": [ - "certum" - ], - "EnrollmentFieldMapping": "Organization Registration Number" - } - }, - "JurisdictionCountry": { - "FieldData": { - "RequiredForProducts": [ - "comodoevssl", - "comodoevcsc", - "comodoevmdc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "positiveevssl" - ], - "EnrollmentFieldMapping": "Organization Jurisdiction Country" - } - }, - "OrganizationAddress": { - "AddressLine1": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization Address" - } - }, - "Region": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization State/Province" - } - }, - "PostalCode": { - "FieldData": { - "RequiredForProducts": [ - "digi_plus_ssl", - "digi_wc_ssl", - "digi_md_ssl", - "digi_securesite_md", - "digi_csc", - "digi_securesite", - "digi_securesite_pro", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_csc_ev", - "digi_ev_md_ssl", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_securesite_pro_ev_flex", - "digi_ssl_basic", - "digi_securesite_flex", - "digi_plus_ev_ssl", - "digi_doc_signing_org_2000", - "digi_doc_signing_org_5000", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_truebizid_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex", - "digi_sslwebserver_ev_flex", - "truebizid", - "truebusinessidev", - "truebusinessidevmd", - "truebusinessidwildcard", - "truebizidmdwc", - "truebizidmd", - "malwarescan", - "sslwebserverwildcard", - "thawtecsc", - "sslwebserver", - "sslwebserverev", - "sectigocsc", - "sectigoevssl", - "sectigoevcsc", - "sectigoevmdc", - "sectigoovssl", - "sectigomdc", - "sectigomdcwildcard", - "sectigoovwildcard", - "comodocsc", - "positiveevssl", - "comodoevssl", - "comodoevcsc", - "enterpriseproev", - "enterpriseproevmdc", - "positiveevmdc", - "comodoevmdc", - "comodomdc", - "instantssl", - "instantsslpro", - "comodopremiumssl", - "comodomdcwildcard", - "comodopremiumwildcard", - "comodouccwildcard", - "comodoucc", - "elitessl", - "comodopciscan", - "enterprisessl", - "enterprisepro", - "enterpriseprowc", - "pacenterprise", - "hackerprooftm", - "hgpcicontrolscan" - ], - "EnrollmentFieldMapping": "Organization Postal Code" - } - }, - "LocalityName": { - "FieldData": { - "RequiredForProducts": [ - "comodocsc", - "comodoevssl", - "comodoevcsc", - "comodoevmdc", - "comodomdc", - "comodomdcwildcard", - "comodouccwildcard", - "comodoucc", - "pacenterprise" - ], - "EnrollmentFieldMapping": "Organization Locality Name" - } - }, - "Country": { - "FieldData": { - "RequiredForProducts": [ - "truebizidmd", - "digi_ev_md_ssl", - "digi_md_ssl", - "digi_plus_ev_ssl", - "digi_plus_ssl", - "digi_securesite", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_ssl_basic", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev_flex", - "digi_securesite_flex", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex" - ], - "EnrollmentFieldMapping": "Organization Country" - } - }, - "Phone": { - "FieldData": { - "RequiredForProducts": [ - "truebizidmd", - "digi_ev_md_ssl", - "digi_md_ssl", - "digi_plus_ev_ssl", - "digi_plus_ssl", - "digi_securesite", - "digi_securesite_wc", - "digi_securesite_pro_ev", - "digi_securesite_ev_md", - "digi_securesite_ev", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_flex", - "digi_ssl_basic", - "digi_sslwebserver_ev_flex", - "digi_truebizid_ev_flex", - "digi_securesite_flex", - "digi_truebizid_ev", - "digi_truebizid", - "digi_truebizid_ev_md", - "digi_truebizid_wc", - "digi_truebizid_md", - "digi_truebizid_md_wc", - "digi_sslwebserver_ev", - "digi_sslwebserver", - "digi_sslwebserver_wc", - "digi_sslwebserver_md_wc", - "digi_sslwebserver_flex" - ], - "EnrollmentFieldMapping": "Organization Phone" - } - } - } - }, - "ValidityPeriod": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Validity Period (In Months)" - } - }, - "ServerCount": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Server Count" - } - }, - "CSR": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "None" - } - }, - "DomainName": { - "FieldData": { - "RequiredForProducts": [ - "Certum" - ], - "EnrollmentFieldMapping": "Domain Name" - } - }, - "WebServerType": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Web Server Type" - } - }, - "DNSNames": { - "FieldData": { - "RequiredForProducts": [ - "digi_ssl_ev_basic", - "digi_ssl_ev_basic-EO", - "digi_securesite_ev_flex", - "digi_securesite_ev_flex-EO", - "digi_securesite_pro_ev_flex", - "digi_securesite_pro_ev_flex-EO", - "digi_securesite_pro_flex", - "digi_securesite_pro_flex-EO", - "digi_ssl_basic", - "digi_ssl_basic-EO", - "digi_securesite_flex", - "digi_securesite_flex-EO", - "digi_truebizid_flex", - "digi_truebizid_flex-EO", - "digi_truebizid_ev_flex", - "digi_truebizid_ev_flex-EO", - "digi_ssl_dv_geotrust_flex", - "digi_rapidssl", - "digi_rapidssl_wc", - "digi_ssl123_flex", - "digi_sslwebserver_flex", - "digi_sslwebserver_flex-EO", - "digi_sslwebserver_ev_flex", - "digi_sslwebserver_ev_flex-EO", - "positivemdcssl", - "positivemdcwildcard", - "sectigodvucc", - "sectigouccwildcard", - "sectigoevmdc", - "sectigomdcwildcard", - "sectigomdc" - ], - "EnrollmentFieldMapping": "DNS Names Comma Separated", - "Array": true - } - }, - "isCUOrder": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Is CU Order?" - } - }, - "isRenewalOrder": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Is Renewal Order?" - } - }, - "isTrialOrder": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Is Trial Order?" - } - }, - "AdminContact": { - "FirstName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - First Name" - } - }, - "LastName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Last Name" - } - }, - "Phone": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Phone" - } - }, - "Email": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Email" - } - }, - "Title": { - "FieldData": { - "RequiredForProducts": [ - "symantec", - "digi_ssl_ev_basic", - "digi_sslwebserver_ev_flex", - "digi_truebizid_ev_flex", - "digi_securesite_pro_ev_flex", - "digi_securesite_ev_flex" - ], - "EnrollmentFieldMapping": "Admin Contact - Title" - } - }, - "OrganizationName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Organization Name" - } - }, - "AddressLine1": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Address" - } - }, - "City": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - City" - } - }, - "Region": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Region" - } - }, - "PostalCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Postal Code" - } - }, - "Country": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Admin Contact - Country" - } - } - }, - "TechnicalContact": { - "FirstName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - First Name" - } - }, - "LastName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Last Name" - } - }, - "SubjectFirstName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Subject First Name" - } - }, - "SubjectLastName": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Subject Last Name" - } - }, - "Phone": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Phone" - } - }, - "Email": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Email" - } - }, - "Title": { - "FieldData": { - "RequiredForProducts": [ - "symantec", - "digi_ssl_ev_basic", - "digi_securesite_ev_flex", - "digi_truebizid_ev_flex", - "digi_sslwebserver_ev_flex" - ], - "EnrollmentFieldMapping": "Technical Contact - Title" - } - }, - "AddressLine1": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Address" - } - }, - "City": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - City" - } - }, - "Region": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Region" - } - }, - "PostalCode": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Postal Code" - } - }, - "Country": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Technical Contact - Country" - } - } - }, - "ApproverEmail": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Approver Email" - } - }, - "AutoWWW": { - "FieldData": { - "RequiredForProducts": [ - "positivessl" - ], - "EnrollmentFieldMapping": "AutoWWW" - } - }, - "FileAuthDVIndicator": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "File Auth Domain Validation" - } - }, - "CNAMEAuthDVIndicator": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "CName Auth Domain Validation" - } - }, - "SignatureHashAlgorithm": { - "FieldData": { - "RequiredForProducts": [ - "All" - ], - "EnrollmentFieldMapping": "Signature Hash Algorithm" - } - } - } - }, - "Templates": { - "positivessl": { - "ProductID": "positivessl", - "Parameters": { - "Parameters": { - "AutoWWW": "True" - } - } - }, - "positiveevssl": { - "ProductID": "positiveevssl", - "Parameters": {} - }, - "enterpriseproev": { - "ProductID": "enterpriseproev", - "Parameters": {} - }, - "enterpriseproevmdc": { - "ProductID": "enterpriseproevmdc", - "Parameters": {} - }, - "positivesslwildcard": { - "ProductID": "positivesslwildcard", - "Parameters": {} - }, - "positivemdcssl": { - "ProductID": "positivemdcssl", - "Parameters": {} - }, - "positivemdcwildcard": { - "ProductID": "positivemdcwildcard", - "Parameters": {} - }, - "positiveevmdc": { - "ProductID": "positiveevmdc", - "Parameters": {} - }, - "instantssl": { - "ProductID": "instantssl", - "Parameters": {} - }, - "instantsslpro": { - "ProductID": "instantsslpro", - "Parameters": {} - }, - "comodopremiumssl": { - "ProductID": "comodopremiumssl", - "Parameters": {} - }, - "comodopremiumwildcard": { - "ProductID": "comodopremiumwildcard", - "Parameters": {} - }, - "enterprisepro": { - "ProductID": "enterprisepro", - "Parameters": {} - }, - "enterpriseprowc": { - "ProductID": "enterpriseprowc", - "Parameters": {} - }, - "sectigossl": { - "ProductID": "sectigossl", - "Parameters": {} - }, - "sectigodvucc": { - "ProductID": "sectigodvucc", - "Parameters": {} - }, - "sectigoevssl": { - "ProductID": "sectigoevssl", - "Parameters": {} - }, - "sectigoevmdc": { - "ProductID": "sectigoevmdc", - "Parameters": {} - }, - "sectigoovssl": { - "ProductID": "sectigoovssl", - "Parameters": {} - }, - "sectigomdc": { - "ProductID": "sectigomdc", - "Parameters": {} - }, - "sectigomdcwildcard": { - "ProductID": "sectigomdcwildcard", - "Parameters": {} - }, - "sectigoovwildcard": { - "ProductID": "sectigoovwildcard", - "Parameters": {} - }, - "sectigowildcard": { - "ProductID": "sectigowildcard", - "Parameters": {} - }, - "sectigouccwildcard": { - "ProductID": "sectigouccwildcard", - "Parameters": {} - }, - "digi_ssl_ev_basic": { - "ProductID": "digi_ssl_ev_basic", - "Parameters": {} - }, - "digi_ssl_ev_basic-EO": { - "ProductID": "digi_ssl_ev_basic-EO", - "Parameters": {} - }, - "digi_securesite_ev_flex": { - "ProductID": "digi_securesite_ev_flex", - "Parameters": {} - }, - "digi_securesite_ev_flex-EO": { - "ProductID": "digi_securesite_ev_flex-EO", - "Parameters": {} - }, - "digi_securesite_pro_ev_flex": { - "ProductID": "digi_securesite_pro_ev_flex", - "Parameters": {} - }, - "digi_securesite_pro_ev_flex-EO": { - "ProductID": "digi_securesite_pro_ev_flex-EO", - "Parameters": {} - }, - "digi_securesite_pro_flex": { - "ProductID": "digi_securesite_pro_flex", - "Parameters": {} - }, - "digi_securesite_pro_flex-EO": { - "ProductID": "digi_securesite_pro_flex-EO", - "Parameters": {} - }, - "digi_ssl_basic": { - "ProductID": "digi_ssl_basic", - "Parameters": {} - }, - "digi_ssl_basic-EO": { - "ProductID": "digi_ssl_basic-EO", - "Parameters": {} - }, - "digi_securesite_flex": { - "ProductID": "digi_securesite_flex", - "Parameters": {} - }, - "digi_securesite_flex-EO": { - "ProductID": "digi_securesite_flex-EO", - "Parameters": {} - }, - "digi_truebizid_flex": { - "ProductID": "digi_truebizid_flex", - "Parameters": {} - }, - "digi_truebizid_flex-EO": { - "ProductID": "digi_truebizid_flex-EO", - "Parameters": {} - }, - "digi_truebizid_ev_flex": { - "ProductID": "digi_truebizid_ev_flex", - "Parameters": {} - }, - "digi_truebizid_ev_flex-EO": { - "ProductID": "digi_truebizid_ev_flex-EO", - "Parameters": {} - }, - "digi_ssl_dv_geotrust_flex": { - "ProductID": "digi_ssl_dv_geotrust_flex", - "Parameters": {} - }, - "digi_rapidssl": { - "ProductID": "digi_rapidssl", - "Parameters": {} - }, - "digi_rapidssl_wc": { - "ProductID": "digi_rapidssl_wc", - "Parameters": {} - }, - "digi_ssl123_flex": { - "ProductID": "digi_ssl123_flex", - "Parameters": {} - }, - "digi_sslwebserver_flex": { - "ProductID": "digi_sslwebserver_flex", - "Parameters": {} - }, - "digi_sslwebserver_flex-EO": { - "ProductID": "digi_sslwebserver_flex-EO", - "Parameters": {} - }, - "digi_sslwebserver_ev_flex": { - "ProductID": "digi_sslwebserver_ev_flex", - "Parameters": {} - }, - "digi_sslwebserver_ev_flex-EO": { - "ProductID": "digi_sslwebserver_ev_flex-EO", - "Parameters": {} - } - }, - "CertificateManagers": null, - "GatewayRegistration": { - "LogicalName": "SSLStore", - "GatewayCertificate": { - "StoreName": "CA", - "StoreLocation": "LocalMachine", - "Thumbprint": "339cdd57cfd5b141169b615ff31428782d1da639" - } - }, - "ServiceSettings": { - "ViewIdleMinutes": 1, - "FullScanPeriodHours": 1, - "PartialScanPeriodMinutes": 1 - } -} \ No newline at end of file From 7e27ab6cbda5aadfc9bd220cfc5499f2e3cc6e1f Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Fri, 27 Mar 2026 12:04:13 -0400 Subject: [PATCH 36/42] Update integration-manifest.json --- integration-manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-manifest.json b/integration-manifest.json index 4f22c79..94ed669 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -7,8 +7,8 @@ "status": "production", "integration_type": "anyca-plugin", "support_level": "kf-supported", - "link_github": true, - "update_catalog": true, + "link_github": false, + "update_catalog": false, "gateway_framework": "25.5", "about": { "carest": { @@ -285,4 +285,4 @@ ] } } -} \ No newline at end of file +} From fe5b7e10d0d50967d399dc264ad0c65db7119a40 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Fri, 27 Mar 2026 16:06:06 +0000 Subject: [PATCH 37/42] Update generated docs --- integration-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-manifest.json b/integration-manifest.json index 94ed669..86be3f5 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -285,4 +285,4 @@ ] } } -} +} \ No newline at end of file From 8a13feb1e3ae3d84bcc83f35ffd7d0579dff0811 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 30 Mar 2026 13:12:15 -0400 Subject: [PATCH 38/42] fixed default status --- SslStoreCaProxy/RequestManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index fbbdbe4..e4694e1 100644 --- a/SslStoreCaProxy/RequestManager.cs +++ b/SslStoreCaProxy/RequestManager.cs @@ -198,7 +198,7 @@ public int MapReturnStatus(string sslStoreStatus) case "Cancelled": return (int)EndEntityStatus.REVOKED; default: - return (int)EndEntityStatus.FAILED; + return (int)EndEntityStatus.NEW; } } From 9be985e679d5dd57f5b6d43d5e1864cacf1b87b5 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 31 Mar 2026 10:13:08 -0400 Subject: [PATCH 39/42] fixed reissue issue --- SslStoreCaProxy/RequestManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index e4694e1..bac8730 100644 --- a/SslStoreCaProxy/RequestManager.cs +++ b/SslStoreCaProxy/RequestManager.cs @@ -86,7 +86,7 @@ public ReIssueRequest GetReIssueRequest(INewOrderResponse orderData, string csr, { AuthRequest = GetAuthRequest(), TheSslStoreOrderId = orderData.TheSslStoreOrderId, - CustomOrderId = Guid.NewGuid().ToString(), + CustomOrderId = orderData.CustomOrderId, Csr = csr, IsRenewalOrder = isRenewal, IsWildCard = orderData.ProductCode.Contains("wc") || orderData.ProductCode.Contains("wildcard"), From fe3d4459400c6d7f1ae76bd42705afcc2ec2e19d Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 31 Mar 2026 13:32:05 -0400 Subject: [PATCH 40/42] undo fix --- SslStoreCaProxy/RequestManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index bac8730..e4694e1 100644 --- a/SslStoreCaProxy/RequestManager.cs +++ b/SslStoreCaProxy/RequestManager.cs @@ -86,7 +86,7 @@ public ReIssueRequest GetReIssueRequest(INewOrderResponse orderData, string csr, { AuthRequest = GetAuthRequest(), TheSslStoreOrderId = orderData.TheSslStoreOrderId, - CustomOrderId = orderData.CustomOrderId, + CustomOrderId = Guid.NewGuid().ToString(), Csr = csr, IsRenewalOrder = isRenewal, IsWildCard = orderData.ProductCode.Contains("wc") || orderData.ProductCode.Contains("wildcard"), From 9133420a552206103a7a9fc4ae0cbb09810621dc Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 31 Mar 2026 13:42:28 -0400 Subject: [PATCH 41/42] fixe custom order id --- SslStoreCaProxy/SslStoreCaProxy.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs index dce2725..869edb9 100644 --- a/SslStoreCaProxy/SslStoreCaProxy.cs +++ b/SslStoreCaProxy/SslStoreCaProxy.cs @@ -279,6 +279,10 @@ public async Task Enroll(string csr, string subject, Dictionar enrollmentResponse = await client.SubmitReIssueRequestAsync(reIssueRequest); _logger.LogTrace($"reissue enrollmentResponse JSON {JsonConvert.SerializeObject(enrollmentResponse)}"); + + // SSL Store API ignores the CustomOrderId we send on reissue and returns the original order's ID. + // Override it with our generated ID so the framework can create a new DB record. + enrollmentResponse.CustomOrderId = reIssueRequest.CustomOrderId; } } From 0bbe7e984d404ba88120e104d42d94f298adea8a Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 31 Mar 2026 14:05:41 -0400 Subject: [PATCH 42/42] fixed order id --- SslStoreCaProxy/RequestManager.cs | 18 ++++++ SslStoreCaProxy/SslStoreCaProxy.cs | 99 ++++++++++++++++++++++++------ 2 files changed, 97 insertions(+), 20 deletions(-) diff --git a/SslStoreCaProxy/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index e4694e1..30718f8 100644 --- a/SslStoreCaProxy/RequestManager.cs +++ b/SslStoreCaProxy/RequestManager.cs @@ -142,6 +142,15 @@ public DownloadCertificateRequest GetCertificateRequest(string customOrderId) }; } + public DownloadCertificateRequest GetCertificateRequestBySslStoreId(string theSslStoreOrderId) + { + return new DownloadCertificateRequest + { + AuthRequest = GetAuthRequest(), + TheSslStoreOrderId = theSslStoreOrderId + }; + } + public RevokeOrderRequest GetRevokeOrderRequest(string customOrderId) { return new RevokeOrderRequest @@ -151,6 +160,15 @@ public RevokeOrderRequest GetRevokeOrderRequest(string customOrderId) }; } + public RevokeOrderRequest GetRevokeOrderRequestBySslStoreId(string theSslStoreOrderId) + { + return new RevokeOrderRequest + { + AuthRequest = GetAuthRequest(), + TheSslStoreOrderId = theSslStoreOrderId + }; + } + public int GetClientPageSize(IAnyCAPluginConfigProvider config) { if (config.CAConnectionData.ContainsKey(Constants.PageSize)) diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs index 869edb9..04bd232 100644 --- a/SslStoreCaProxy/SslStoreCaProxy.cs +++ b/SslStoreCaProxy/SslStoreCaProxy.cs @@ -129,7 +129,16 @@ public Dictionary GetTemplateParameterAnnotations() public async Task Revoke(string caRequestId, string hexSerialNumber, uint revocationReason) { _logger.MethodEntry(); - var revokeOrderRequest = _requestManager.GetRevokeOrderRequest(caRequestId); + var sslStoreOrderId = ParseSslStoreOrderId(caRequestId); + RevokeOrderRequest revokeOrderRequest; + if (sslStoreOrderId != null) + { + revokeOrderRequest = _requestManager.GetRevokeOrderRequestBySslStoreId(sslStoreOrderId); + } + else + { + revokeOrderRequest = _requestManager.GetRevokeOrderRequest(caRequestId); + } _logger.LogTrace($"Revoke Request JSON {JsonConvert.SerializeObject(revokeOrderRequest)}"); try { @@ -240,9 +249,20 @@ public async Task Enroll(string csr, string subject, Dictionar _logger.LogTrace($"Prior Cert Serial Number: {sn}"); var caRequestId = await _certDataReader.GetRequestIDBySerialNumber(sn); - _logger.LogTrace($"Prior CA Request ID (CustomOrderId): {caRequestId}"); + _logger.LogTrace($"Prior CA Request ID: {caRequestId}"); - var orderStatusRequest = _requestManager.GetOrderStatusRequest(caRequestId); + var priorSslStoreOrderId = ParseSslStoreOrderId(caRequestId); + OrderStatusRequest orderStatusRequest; + if (priorSslStoreOrderId != null) + { + _logger.LogTrace($"Parsed TheSSLStoreOrderID: {priorSslStoreOrderId}"); + orderStatusRequest = _requestManager.GetOrderStatusRequestBySslStoreId(priorSslStoreOrderId); + } + else + { + _logger.LogTrace($"Legacy GUID format, querying by CustomOrderId: {caRequestId}"); + orderStatusRequest = _requestManager.GetOrderStatusRequest(caRequestId); + } _logger.LogTrace($"orderStatusRequest JSON {JsonConvert.SerializeObject(orderStatusRequest)}"); var orderStatusResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); @@ -279,10 +299,6 @@ public async Task Enroll(string csr, string subject, Dictionar enrollmentResponse = await client.SubmitReIssueRequestAsync(reIssueRequest); _logger.LogTrace($"reissue enrollmentResponse JSON {JsonConvert.SerializeObject(enrollmentResponse)}"); - - // SSL Store API ignores the CustomOrderId we send on reissue and returns the original order's ID. - // Override it with our generated ID so the framework can create a new DB record. - enrollmentResponse.CustomOrderId = reIssueRequest.CustomOrderId; } } @@ -294,6 +310,36 @@ public async Task Enroll(string csr, string subject, Dictionar } } + /// + /// Builds a composite CARequestID in the format "{TheSSLStoreOrderID}-{PartnerOrderID}". + /// This ensures uniqueness across reissues (same order, different PartnerOrderID). + /// + private static string BuildCompositeRequestId(string theSslStoreOrderId, string partnerOrderId) + { + return $"{theSslStoreOrderId}-{partnerOrderId}"; + } + + /// + /// Parses the TheSSLStoreOrderID from a CARequestID. Supports both composite format + /// ("{TheSSLStoreOrderID}-{PartnerOrderID}") and legacy GUID format (falls back to + /// treating the whole string as a CustomOrderId for backward compatibility). + /// + private static string ParseSslStoreOrderId(string caRequestId) + { + if (string.IsNullOrEmpty(caRequestId)) return caRequestId; + + var dashIndex = caRequestId.IndexOf('-'); + // Composite IDs have a numeric TheSSLStoreOrderID before the first dash. + // Legacy GUIDs have hex chars before the first dash so we check for digits only. + if (dashIndex > 0 && caRequestId.Substring(0, dashIndex).All(char.IsDigit)) + { + return caRequestId.Substring(0, dashIndex); + } + + // Legacy GUID format — return as-is for backward compatibility + return null; + } + private EnrollmentResult GetEnrollmentResult(INewOrderResponse newOrderResponse) { if (newOrderResponse != null && newOrderResponse.AuthResponse.IsError) @@ -308,16 +354,16 @@ private EnrollmentResult GetEnrollmentResult(INewOrderResponse newOrderResponse) var majorStatus = newOrderResponse?.OrderStatus?.MajorStatus; var status = _requestManager.MapReturnStatus(majorStatus); - var orderId = newOrderResponse?.CustomOrderId; + var compositeId = BuildCompositeRequestId(newOrderResponse?.TheSslStoreOrderId, newOrderResponse?.PartnerOrderId); - _logger.LogTrace($"Order {orderId} status: {majorStatus} -> mapped to {status}"); + _logger.LogTrace($"Order {compositeId} (SSLStoreOrderId: {newOrderResponse?.TheSslStoreOrderId}, PartnerOrderId: {newOrderResponse?.PartnerOrderId}) status: {majorStatus} -> mapped to {status}"); _logger.MethodExit(); return new EnrollmentResult { - CARequestID = orderId, + CARequestID = compositeId, Status = status, - StatusMessage = $"Order Successfully Created With Order Number {orderId}" + StatusMessage = $"Order Successfully Created With Order Number {compositeId}" }; } @@ -326,8 +372,19 @@ public async Task GetSingleRecord(string caRequestId) _logger.MethodEntry(); var client = new SslStoreClient(Config); - var orderStatusRequest = _requestManager.GetOrderStatusRequest(caRequestId); - _logger.LogTrace($"orderStatusRequest JSON {JsonConvert.SerializeObject(orderStatusRequest)}"); + var sslStoreOrderId = ParseSslStoreOrderId(caRequestId); + + OrderStatusRequest orderStatusRequest; + if (sslStoreOrderId != null) + { + _logger.LogTrace($"Parsed TheSSLStoreOrderID: {sslStoreOrderId} from CARequestID: {caRequestId}"); + orderStatusRequest = _requestManager.GetOrderStatusRequestBySslStoreId(sslStoreOrderId); + } + else + { + _logger.LogTrace($"Legacy GUID format, querying by CustomOrderId: {caRequestId}"); + orderStatusRequest = _requestManager.GetOrderStatusRequest(caRequestId); + } var orderStatusResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); _logger.LogTrace($"orderStatusResponse JSON {JsonConvert.SerializeObject(orderStatusResponse)}"); @@ -337,7 +394,7 @@ public async Task GetSingleRecord(string caRequestId) if (certStatus == (int)EndEntityStatus.GENERATED) { - var downloadCertificateRequest = _requestManager.GetCertificateRequest(caRequestId); + var downloadCertificateRequest = _requestManager.GetCertificateRequestBySslStoreId(sslStoreOrderId ?? orderStatusResponse.TheSslStoreOrderId); var certResponse = await client.SubmitDownloadCertificateAsync(downloadCertificateRequest); if (!certResponse.AuthResponse.IsError) { @@ -383,19 +440,21 @@ public async Task Synchronize(BlockingCollection blockin var orderStatusRequest = _requestManager.GetOrderStatusRequestBySslStoreId(currentResponseItem?.TheSslStoreOrderId); var orderStatusResponse = await client.SubmitOrderStatusRequestAsync(orderStatusRequest); - var customOrderId = orderStatusResponse.CustomOrderId; - if (string.IsNullOrEmpty(customOrderId)) + var theSslStoreOrderId = orderStatusResponse.TheSslStoreOrderId; + var partnerOrderId = orderStatusResponse.PartnerOrderId; + if (string.IsNullOrEmpty(theSslStoreOrderId) || string.IsNullOrEmpty(partnerOrderId)) { - _logger.LogTrace($"Order {currentResponseItem?.TheSslStoreOrderId} has no CustomOrderId, skipping"); + _logger.LogTrace($"Order {currentResponseItem?.TheSslStoreOrderId} missing required IDs, skipping"); continue; } + var compositeId = BuildCompositeRequestId(theSslStoreOrderId, partnerOrderId); var fileContent = ""; var certStatus = _requestManager.MapReturnStatus(orderStatusResponse.OrderStatus.MajorStatus); if (certStatus == (int)EndEntityStatus.GENERATED) { - var downloadCertificateRequest = _requestManager.GetCertificateRequest(customOrderId); + var downloadCertificateRequest = _requestManager.GetCertificateRequestBySslStoreId(theSslStoreOrderId); var certResponse = await client.SubmitDownloadCertificateAsync(downloadCertificateRequest); if (!certResponse.AuthResponse.IsError) { @@ -404,13 +463,13 @@ public async Task Synchronize(BlockingCollection blockin fileContent = Convert.ToBase64String(endEntityCert.RawData); } } - + if ((certStatus == (int)EndEntityStatus.GENERATED && fileContent.Length > 0) || certStatus == (int)EndEntityStatus.REVOKED) { blockingBuffer.Add(new AnyCAPluginCertificate { - CARequestID = customOrderId, + CARequestID = compositeId, Certificate = fileContent, Status = certStatus, ProductID = $"{orderStatusResponse.ProductCode}"