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/RequestManager.cs b/SslStoreCaProxy/RequestManager.cs index fbbdbe4..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)) @@ -198,7 +216,7 @@ public int MapReturnStatus(string sslStoreStatus) case "Cancelled": return (int)EndEntityStatus.REVOKED; default: - return (int)EndEntityStatus.FAILED; + return (int)EndEntityStatus.NEW; } } diff --git a/SslStoreCaProxy/SslStoreCaProxy.cs b/SslStoreCaProxy/SslStoreCaProxy.cs index dce2725..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); @@ -290,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) @@ -304,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}" }; } @@ -322,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)}"); @@ -333,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) { @@ -379,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) { @@ -400,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}" diff --git a/integration-manifest.json b/integration-manifest.json index 4f22c79..86be3f5 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": {