From 316a1dadc26e484a27ef5c0b84fb427c04b0f133 Mon Sep 17 00:00:00 2001 From: Krzysztof Benedyczak Date: Fri, 21 Aug 2026 13:20:28 +0200 Subject: [PATCH 1/2] Document pre-refactor validation baseline --- docs/changes/0002-validation-baseline.md | 51 ++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 docs/changes/0002-validation-baseline.md diff --git a/docs/changes/0002-validation-baseline.md b/docs/changes/0002-validation-baseline.md new file mode 100644 index 0000000..c4c95c9 --- /dev/null +++ b/docs/changes/0002-validation-baseline.md @@ -0,0 +1,51 @@ +# Validation baseline + +This records the test-suite baseline before the lite PKI validation refactor. +It is a comparison point, not a statement that every legacy behavior will be +retained. + +## Source and environment + +- Source commit: `89762d4` (`master`, "The grand refactoring plan") +- Recorded: 2026-08-21 +- Maven: 3.9.12 +- Java: OpenJDK 25.0.3 + +## Default suite + +Command: + +```console +mvn clean test +``` + +Result: **BUILD SUCCESS** + +```text +Tests run: 274, Failures: 0, Errors: 0, Skipped: 1 +``` + +The skipped test is in `ProxyGenerationTest`; its existing skip reason is +`TODO: test certificates have expired`. + +## Opt-in risky integration suite + +Command: + +```console +mvn test -PriskyTests +``` + +Result: **BUILD FAILURE** + +```text +Tests run: 8, Failures: 1, Errors: 0, Skipped: 3 +``` + +The failure is `CRLTest.testLoadPlain`, which expects one CRL but loads none +from an external fixture URL. The three skipped tests are the existing OCSP +integration/cache/client tests. The OpenSSL validator stress tests pass. + +The risky profile depends on external services and fixtures. Its failure is +therefore preserved as part of the baseline rather than treated as a failure +introduced by the refactor. From 1fcd89533e6449d9a0c3dbc14987351535609cdf Mon Sep 17 00:00:00 2001 From: Krzysztof Benedyczak Date: Fri, 21 Aug 2026 13:30:33 +0200 Subject: [PATCH 2/2] Freeze lite PKI validation contract --- API-Changes.txt | 28 +++- docs/changes/0001-lite-pki-validation-plan.md | 8 +- docs/changes/0003-lite-pki-contract.md | 142 ++++++++++++++++++ 3 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 docs/changes/0003-lite-pki-contract.md diff --git a/API-Changes.txt b/API-Changes.txt index 4829e6f..9a24ba2 100644 --- a/API-Changes.txt +++ b/API-Changes.txt @@ -1,3 +1,30 @@ +NEXT MAJOR VERSION - LITE PKI VALIDATION + +This release is deliberately source- and binary-incompatible with 2.x. The +behavioral contract and migration rules are in +docs/changes/0003-lite-pki-contract.md. + +Planned removals include all proxy-certificate APIs, namespace-policy APIs, +legacy OpenSSL subject hashes, and the detailed copied-reviewer validation +error catalogue. Validator constructors and parameter objects will no longer +accept proxy or namespace settings. + +Certificate-array validation treats the first certificate as the target and +the rest as path-building candidates. Successful results contain the resolved +chain and selected trust anchor. Invalid results report one primary native-PKIX +failure with its cause, stage, and certificate position. Error listeners can +observe failures but can no longer suppress them. + +OCSP remains supported. Core native OCSP and CRL modes are migrated first; +responder configuration, ordering, nonce, and cache behavior follow in +separately reviewed changes. No OCSP capability is removed silently. + +The exact removed and replacement Java symbols will be appended by the PR that +changes each part of the API. + + +2.x HISTORICAL CHANGES + 1) changed semantics of the DN compare methods operating on the string representation. 2) changed ParseException to (runtime) IllegalArgumentException in X500NameUtils. 3) changed slightly X500NameUtils.getAttributeValues description @@ -44,4 +71,3 @@ two trusted v1 certificates with the same subject but different keys) is not sup - Known issue: due to bug in BC (http://www.bouncycastle.org/jira/browse/BJA-370) only masks 8, 16, 24 and 32 are working correctly in Proxy certificate target/source restrictions. - diff --git a/docs/changes/0001-lite-pki-validation-plan.md b/docs/changes/0001-lite-pki-validation-plan.md index e755ff0..e1332de 100644 --- a/docs/changes/0001-lite-pki-validation-plan.md +++ b/docs/changes/0001-lite-pki-validation-plan.md @@ -19,6 +19,7 @@ Native Bouncy Castle `CertPathBuilder` and `CertPathValidator` are to be the val - Treat the first certificate in an array as the target and the remainder as path-building candidates. - Accept an exact trusted self-signed input and keep trust anchors outside PKIX path validation. - Use native revocation behavior for the modes that BC represents accurately. Do not emulate optional behavior through exception-message matching. +- Retain OCSP validation. Migrate its core validation to native BC first, then preserve responder configuration, fallback and ordering, caching, and nonce behavior in separately reviewed layers wherever each feature can be implemented precisely and tested deterministically. - Remove residual gLite/Grid compatibility utilities, test corpora, documentation, and obsolete build metadata while preserving required attribution for retained derived code. ## Sequence @@ -78,9 +79,10 @@ Exit condition: invalid TLS and direct-validation calls provide an actionable pr ### 6. Implement the retained native revocation modes - Implement revocation-disabled and strict native CRL behavior. -- If OCSP is retained, expose only behavior that maps clearly to native BC, such as required OCSP or native preferred-mechanism fallback. -- Remove custom responder ordering, cache, nonce, and multi-mechanism semantics unless they are separately justified and tested. -- Add focused tests for missing, expired, malformed, badly signed, and revoking CRLs, plus equivalent OCSP outcomes for any retained OCSP modes. +- Implement required OCSP and native preferred-mechanism fallback. +- Preserve certificate AIA responder discovery and explicitly configured responders. +- Migrate responder ordering, cache, nonce, and multi-mechanism semantics in separate changes. Retain each behavior that can be specified precisely and tested without replacing native BC as the validation authority. +- Add focused tests for missing, expired, malformed, badly signed, and revoking CRLs, plus equivalent OCSP outcomes. Exit condition: every advertised revocation mode has precise tests and no mode claims optional/soft-fail semantics that BC does not actually provide. diff --git a/docs/changes/0003-lite-pki-contract.md b/docs/changes/0003-lite-pki-contract.md new file mode 100644 index 0000000..5931fae --- /dev/null +++ b/docs/changes/0003-lite-pki-contract.md @@ -0,0 +1,142 @@ +# Lite PKI behavioral and migration contract + +This document freezes the intended externally observable behavior before the +implementation is replaced. It describes the final target. Intermediate +branches may deliberately support a smaller subset while the stacked changes +are under review, but each such limitation must be stated in that branch. + +## Compatibility boundary + +Compatibility is defined by validation verdicts and actionable primary error +reporting. The new implementation is not required to reproduce the legacy +reviewer's complete list or ordering of errors. + +The refactor deliberately removes: + +- proxy certificate generation, inspection, configuration, and validation; +- Globus `.signing_policy` and EUGridPMA `.namespaces` processing; +- pre-OpenSSL-1.0 subject hashes; +- copied Bouncy Castle path-validation code and its detailed error catalogue; +- gLite/Grid-specific utilities that have no retained callers. + +The corresponding public packages, types, constructor arguments, flags, +listeners, and error codes will be removed rather than retained as no-ops. +Removal PRs must extend the migration notes with the exact symbols they delete. + +Standard X.509 path validation, TLS trust management, OpenSSL-style hashed CA +and CRL stores, CRL revocation, and OCSP revocation are retained. + +## Certificate input and path contract + +- For an `X509Certificate[]`, element zero is the target. Remaining elements + are unordered path-building candidates; their supplied order is not treated + as an asserted path. +- A `CertPath` is an asserted coherent path and is validated directly. +- Trust anchors are configured separately and are never validated as path + certificates. +- If an asserted or built path contains its trust anchor certificate, that + certificate is removed from the path passed to native validation. +- An input consisting of an exact trusted self-signed certificate is valid. +- Successful results contain the resolved target-to-anchor chain, including + the selected trust-anchor certificate. +- Native Bouncy Castle `CertPathBuilder` and `CertPathValidator`, selected with + the BC provider explicitly, are the path-building and validation authority. + +## Validation result contract + +A result contains: + +- the validation verdict; +- no validation errors for a valid result; +- one primary error for an invalid result; +- unresolved critical-extension OIDs when the provider exposes them without a + second validation implementation; +- the resolved chain only for a valid result. + +`getErrors()` remains as a compatibility convenience, but returns an immutable +empty or single-element list. `getPrimaryError()` returns the single error or +`null` for a valid result. The public `ValidationResult` constructors, +`addErrors()`, and `setErrors()` are removed from the consumer API. + +The primary error contains: + +- a stable error code and broad category; +- the validation stage (`INPUT`, `PATH_BUILDING`, `PATH_VALIDATION`, or + `REVOCATION`); +- a zero-based certificate index and certificate when a position is known; +- the original provider message; +- the original exception as its cause. + +Index zero denotes the target. An unknown or whole-path position is `-1`. +Provider-specific text is diagnostic data and is not a stable API value. + +The stable error-code set is limited to standard reasons: + +- `INVALID_INPUT`; +- `PATH_BUILDING_FAILED` and `NO_TRUST_ANCHOR`; +- `CERTIFICATE_EXPIRED` and `CERTIFICATE_NOT_YET_VALID`; +- `INVALID_SIGNATURE` and `ALGORITHM_CONSTRAINED`; +- `INVALID_NAME_CHAINING`; +- `INVALID_KEY_USAGE`, `NOT_CA`, and `PATH_TOO_LONG`; +- `INVALID_NAME_CONSTRAINT` and `INVALID_POLICY`; +- `UNRESOLVED_CRITICAL_EXTENSION`; +- `CERTIFICATE_REVOKED` and `UNDETERMINED_REVOCATION_STATUS`; +- `PKIX_FAILURE` for all unspecified/provider-specific reasons. + +The retained broad categories are `INPUT`, `PATH`, `CERTIFICATE`, +`NAME_CONSTRAINT`, `POLICY`, `REVOCATION`, and `OTHER`. + +Validation-error listeners are notification-only. A listener cannot suppress +an error, change an invalid verdict, or mutate the primary error. TLS-facing +`CertificateException`s preserve the primary validation exception as their +cause. + +## Revocation contract + +OCSP is required retained functionality. The implementation will be migrated +in layers so that custom mechanics do not remain entangled with path +validation. + +The required core modes are: + +- disabled revocation; +- strict CRL validation; +- strict OCSP validation; +- native OCSP-first fallback to CRL; +- native CRL-first fallback to OCSP; +- native soft-fail OCSP-first fallback for compatibility with the current + default. + +The compatibility default is OCSP first, followed by CRL, with native +soft-fail behavior when status cannot be obtained. A definitive revoked status +always fails. Malformed, forged, badly signed, or otherwise invalid revocation +data is not converted into success by soft-fail handling. + +The following OCSP capabilities are migration requirements, each implemented +and reviewed separately after core native OCSP validation: + +- responder discovery from certificate AIA; +- explicitly configured responder URL and trusted responder certificate; +- preference and ordering between configured and discovered responders; +- connection timeout; +- request nonce generation and response nonce enforcement; +- bounded in-memory response caching and configured cache TTL; +- optional persistent response caching; +- ordering between OCSP and CRL mechanisms; +- the existing require-all-enabled-mechanisms behavior where it can be layered + around independent native validation without weakening either result. + +No item in this compatibility list is silently dropped. If a capability cannot +be retained without copied validation code, provider-message matching, or a +security regression, its dedicated PR must demonstrate that limitation and +make the final decision explicit. + +The legacy CRL `IF_VALID` name is not retained. If its present-but-enforced +behavior passes the separate decision gate, it is exposed as `IF_PRESENT`. + +## Review and verification rule + +Every behavior-changing branch must state which contract clauses it implements +or intentionally defers. Valid/invalid verdict comparisons use the recorded +baseline where the behavior remains in scope. New native revocation behavior +uses deterministic local CRL and OCSP fixtures rather than public responders.