Skip to content

Resolve renew/reissue from order expiry for ~200 day certs - #13

Merged
indrora merged 9 commits into
release-1.1from
feature/200-day-cert-renew-reissue
Oct 27, 2026
Merged

indrora merged 9 commits into
release-1.1from
feature/200-day-cert-renew-reissue

Conversation

@bhillkeyfactor

Copy link
Copy Markdown
Collaborator

Requests carrying a prior certificate are now resolved from the SSL Store order expiry instead of the certificate expiry: reissue under the active order outside RenewalWindowDays (default 30), renew inside it, and order new once the order has expired. Removes the expired-cert renewal rejection.

Adds FlowLogger step diagrams to Enroll, Synchronize, Revoke, GetSingleRecord and Initialize, and tightens error handling on the enrollment path.

Requests carrying a prior certificate are now resolved from the SSL Store
order expiry instead of the certificate expiry: reissue under the active
order outside RenewalWindowDays (default 30), renew inside it, and order
new once the order has expired. Removes the expired-cert renewal rejection.

Adds FlowLogger step diagrams to Enroll, Synchronize, Revoke,
GetSingleRecord and Initialize, and tightens error handling on the
enrollment path.
Request and response bodies are logged through LogRedactor, which masks
AuthToken, PartnerCode, Token, TokenCode, TokenID and password values.
The PartnerCode is no longer logged at Initialize.
Enroll results had no CARequestID, so orders waiting on domain validation
left a row Command could not refresh (GetSingleRecord called with null).
Return the order id with a pending status, accept order-serial IDs in
GetSingleRecord, and return the certificate once the order is issued.
Older records carry CA request IDs like {order}|{partner order}. Parse the
order id on either separator for revoke, renew/reissue and GetSingleRecord.
Stop a renewal or reissue when SSL Store reports an error for the prior
order instead of building a request from an empty response.
SSL Store returns HTTP 200 with AuthResponse.isError for problems such as
the hourly quota. Sync treated the error body as an order and logged
SUCCESS. Count and log these as errors for the order query, per-order
status and organization list, and flag them in GetSingleRecord.
Command sends PriorCertSN without the DER sign-padding byte, but the
gateway stores serials such as 00A3B8... from sync. Try the serial as
sent, stripped, and with a leading 00 so renewals of high-bit serials
resolve their prior order.
A reissue of an order returns the same SSL Store order id, so using it as the CARequestID hit the unique index on the gateway Certificates table when a second reissue was submitted. Append the partner order id, which changes with every submission.
…equest ID

SSL Store rejects a reissue or renewal with -9033 while the order awaits validation, so check the prior order status first and report it plainly. A failed enrollment also saved a gateway row with a null CARequestID, which Command reported as 'Certificate with ID n was not found' and hid the real reason, so failures now carry a unique placeholder id that GetSingleRecord answers as failed.
SSL Store only downloads the current certificate of an order. GetSingleRecord for an {order}-{serial} request id returned that certificate under the old id after a reissue, so the gateway replaced the older certificate's row with the new one and the prior serial could no longer be found for renewal. Only return the certificate when its serial matches the request id.
@indrora
indrora merged commit 9338bc3 into release-1.1 Oct 27, 2026
27 of 28 checks passed
indrora added a commit that referenced this pull request Oct 27, 2026
* Update readme_source.md

* Update generated README

* fix broken release build, revert previous changes

* use scripts from main

* AutoWWW addition to SSLStore API

* New Sample Config

* Create CHANGELOG.md

* Updated Documentaiton

* Updated Documentaiton

* Updated Documentaiton

* Update CHANGELOG.md

* update to bootstrap workflow

* Update generated README

* Release: 1.0.1

* fixed enconding issues with ssl store api changes

* Add comprehensive logging and null reference protection (#12)

Add extensive trace/error logging and null guards across all project
files to aid debugging and prevent NullReferenceExceptions:

- SslStoreCaProxy.cs: Harden Synchronize, Enroll, Revoke,
  GetSingleRecord, Initialize, ValidateEmails, GetEnrollmentResult
- SslStoreClient.cs: Add logging/null checks to all API methods,
  constructor, and query pagination
- KeyfactorClient.cs: Add logging/null checks to constructor,
  template update, and template query pagination
- RequestManager.cs: Add logging/null checks to all request builders,
  MapReturnStatus, GetCertificateContent, and contact helpers
- .gitignore: Add .claude/ directory

Fixes sync NullReferenceException and operator precedence bug.
AB#84952

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Resolve renew/reissue from order expiry for ~200 day certs (#13)

* Resolve renew/reissue from order expiry for ~200 day certs

Requests carrying a prior certificate are now resolved from the SSL Store
order expiry instead of the certificate expiry: reissue under the active
order outside RenewalWindowDays (default 30), renew inside it, and order
new once the order has expired. Removes the expired-cert renewal rejection.

Adds FlowLogger step diagrams to Enroll, Synchronize, Revoke,
GetSingleRecord and Initialize, and tightens error handling on the
enrollment path.

* Redact credentials and tokens from Trace logging

Request and response bodies are logged through LogRedactor, which masks
AuthToken, PartnerCode, Token, TokenCode, TokenID and password values.
The PartnerCode is no longer logged at Initialize.

* Return order id and pending status from enrollment

Enroll results had no CARequestID, so orders waiting on domain validation
left a row Command could not refresh (GetSingleRecord called with null).
Return the order id with a pending status, accept order-serial IDs in
GetSingleRecord, and return the certificate once the order is issued.

* Handle pipe-delimited CA request IDs and failed prior order lookups

Older records carry CA request IDs like {order}|{partner order}. Parse the
order id on either separator for revoke, renew/reissue and GetSingleRecord.
Stop a renewal or reissue when SSL Store reports an error for the prior
order instead of building a request from an empty response.

* Report SSL Store API errors during sync instead of succeeding silently

SSL Store returns HTTP 200 with AuthResponse.isError for problems such as
the hourly quota. Sync treated the error body as an order and logged
SUCCESS. Count and log these as errors for the order query, per-order
status and organization list, and flag them in GetSingleRecord.

* Match prior certificate serials with or without the leading 00 byte

Command sends PriorCertSN without the DER sign-padding byte, but the
gateway stores serials such as 00A3B8... from sync. Try the serial as
sent, stripped, and with a leading 00 so renewals of high-bit serials
resolve their prior order.

* Make pending enrollment request IDs unique per submission

A reissue of an order returns the same SSL Store order id, so using it as the CARequestID hit the unique index on the gateway Certificates table when a second reissue was submitted. Append the partner order id, which changes with every submission.

* Stop reissue of a pending order early and give failed enrollments a request ID

SSL Store rejects a reissue or renewal with -9033 while the order awaits validation, so check the prior order status first and report it plainly. A failed enrollment also saved a gateway row with a null CARequestID, which Command reported as 'Certificate with ID n was not found' and hid the real reason, so failures now carry a unique placeholder id that GetSingleRecord answers as failed.

* Do not overwrite older certificates with the order's current certificate

SSL Store only downloads the current certificate of an order. GetSingleRecord for an {order}-{serial} request id returned that certificate under the old id after a reissue, so the gateway replaced the older certificate's row with the new one and the prior serial could no longer be found for renewal. Only return the certificate when its serial matches the request id.

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>
Co-authored-by: Michael Henderson <mhenderson@keyfactor.com>
Co-authored-by: fiddlermikey <fiddlermikey@gmail.com>
Co-authored-by: Brian Hill <bhill@keyfactor.com>
Co-authored-by: Mikey Henderson <4452096+fiddlermikey@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants