Skip to content

Conversation

aryan-25
Copy link
Contributor

@aryan-25 aryan-25 commented Oct 8, 2025

Motivation:

New initializers for ExpiryPolicy, RFC5280Policy, and OCSPVerifierPolicy were introduced in #266. These initializers were added to prevent users from specifying Date.now as the time to validate certificate expiry against. For context, the problem was that Date.now would be evaluated at initialization, but validation could occur at a later stage, at which point the validation time would become stale.

These initializers had a fixedValidationTime: Date? = nil argument, where a non-nil value denoted a fixed time to validate against, and a nil value denoted that the current time, evaluated at the point of validation, would be used for validation (the common case). Although the dangers of specifying fixedValidationTime = .now were documented, in practice, it is very easy for users to miss this and continue using the API in an incorrect way.

Given that most users will validate certificate expiry against the current time, we want to default to this and remove the validation time argument from the public initializers entirely. Users who want to specify a fixed predetermined time must explicitly opt-in by using @_spi(FixedExpiryValidationTime) to access the initializers that have a non-optional fixedExpiryValidationTime argument.

Modifications:

  • Deprecated the initializers of RFC5280Policy and OCSPVerifierPolicy and introduced two new initializers for each: one without a validation time argument (common case), and one with a non-optional validation time argument guarded behind an SPI
  • Updated the initializers of ExpiryPolicy (an internal type)
  • Additional changes:
    • Updated test cases to use new initializers
    • Updated examples in documentation to use new initializers

Result:

RFC5280Policy and OCSPVerifierPolicy can be used more safely

New initializers for `ExpiryPolicy`, `RFC5280Policy`, and `OCSPVerifierPolicy` were introduced in apple#266. These initializers were added to prevent users from specifying `Date.now` as the time to validate certificate expiry against. For context, the problem was that `Date.now` would be evaluated at initialization, but validation could occur at a later stage, at which point the validation time would become stale.

These initializers had a `fixedValidationTime: Date? = nil` argument, where a non-`nil` value denoted a *fixed* time to validate against, and a `nil` value denoted that the current time, evaluated at the point of validation, would be used for validation (the common case). Although the dangers of specifying `fixedValidationTime = .now` were documented, in practice, it is very easy for users to miss this and continue using the API in an incorrect way.

Given that most users will validate certificate expiry against the current time, we want to default to this and remove the validation time argument from the public initializers entirely. Users who want to specify a fixed predetermined time must explicitly opt-in by using `@_spi(FixedValidationTime)` to access the initializers that have a *non-optional* `fixedValidationTime` argument.

Modifications:
- Deprecated the initializers of `RFC5280Policy` and `OCSPVerifierPolicy` and introduced two new initializers for each: one without a validation time argument (common case), and one with a *non-optional* validation time argument backed behind an SPI
- Updated the initializers of `ExpiryPolicy` (an internal type)
- Additional changes:
  - Updated test cases to use new initializers
  - Updated examples in documentation to use new initializers

Result:
`RFC5280Policy` and `OCSPVerifierPolicy` can be used more safely
/// - Warning: Only use this initializer if you want to validate the certificates against a *fixed* time. Most users
/// should use ``init()``: the expiry of the certificates will be validated against the current time (evaluated at
/// the point of validation) when using that initializer.
@_spi(FixedValidationTime)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not convinced that we should be using SPI for this. SPI is an undocumented feature and hard to discover. What if we either:

  1. Make this a factory method instead of an init so it is harder to discover and gets a concrete name
  2. Use package traits to guard this API

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making this hard to discover is absolutely intentional. We changed the behaviour, but users continued to misuse it, so we're trying to take this API away from almost everyone.

@aryan-25 aryan-25 added the 🆕 semver/minor Adds new public API. label Oct 10, 2025
/// - Parameter requester: A requester instance conforming to ``OCSPRequester``.
/// - Parameter fixedValidationTime: The *fixed* time to compare against when determining if the request is recent. A fixed time is a *specific*
/// time, either in the past or future, but **not** the current time. To compare against the current time *at the point of validation*, pass `nil` to
/// `fixedValidationTime`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please restore these doc comments to the deprecated methods?

@Lukasa Lukasa merged commit f4cd9e7 into apple:main Oct 13, 2025
45 of 47 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🆕 semver/minor Adds new public API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants