Repository navigation
Conversation
5a45d6d to
56d68ae
Compare
Signed-off-by: Madis Jaagup Laurson <madisjaagup.laurson@nortal.com>
b313adf to
1a97a19
Compare
|
|
||
| // It is guaranteed that if the signature verification succeeds, then the origin and challenge | ||
| // have been implicitly and correctly verified without the need to implement any additional checks. | ||
| authTokenSignatureValidator.validate(token.algorithm(), |
There was a problem hiding this comment.
The previous revocation check before token signature validation ordering was deliberate.
Certificate validation is the "admission gate" for token validation. The incoming token is attacker-controlled, including the certificate’s public key and its parameters. Until the certificate chain is validated, those parameters must be considered untrusted.
Validating the chain first establishes that an accepted issuer endorsed that key. Validity and revocation checks then establish whether it still remains eligible for authentication. Only afterward should we use it to process the token signature.
Moving signature verification earlier lets the caller direct cryptographic processing with an unauthorized key. Rejecting the certificate afterward cannot undo expensive or unsafe operations already performed. For example, an attacker can submit a fabricated certificate with an unusually large RSA public exponent, forcing expensive token signature verification before certificate validation rejects the untrusted key.
Please restore the original ordering.
There was a problem hiding this comment.
Also, while at it, please add a comment that the ordering is deliberate and explain shortly why, based on the previous comment.
| } | ||
| final boolean hasDigitalSignature = keyUsage.length > KEY_USAGE_DIGITAL_SIGNATURE_BIT_INDEX | ||
| && keyUsage[KEY_USAGE_DIGITAL_SIGNATURE_BIT_INDEX]; | ||
| // RFC 5280 section 4.2.1.12 also permits Non Repudiation for OCSP signing. |
There was a problem hiding this comment.
I think it is not necessary to specially bring up Non Repudiation here. The comment was only useful in the context of our discussions:
| // RFC 5280 section 4.2.1.12 also permits Non Repudiation for OCSP signing. |
| /** | ||
| * The flag controls whether Key Usage must be present. If present, Key Usage must include | ||
| * Digital Signature or Non Repudiation and must not include Certificate Signing. | ||
| */ |
There was a problem hiding this comment.
Nitpick, let's add a proper docstring:
| /** | |
| * The flag controls whether Key Usage must be present. If present, Key Usage must include | |
| * Digital Signature or Non Repudiation and must not include Certificate Signing. | |
| */ | |
| /** | |
| * Validates that the Key Usage extension permits OCSP response signing. | |
| * | |
| * <p>When present, the extension must include Digital Signature or Non Repudiation, | |
| * consistent with RFC 5280 section 4.2.1.12. | |
| * | |
| * @param certificate the OCSP responder certificate whose Key Usage is checked | |
| * @param isKeyUsageRequired whether the Key Usage extension must be present; | |
| * if false, an absent extension is accepted, but a present extension is still validated | |
| * @throws OCSPCertificateException if the required extension is absent or its usages fail these checks | |
| * @throws NullPointerException if {@code certificate} is null | |
| * @see <a href="https://www.rfc-editor.org/rfc/rfc5280.html#section-4.2.1.12">RFC 5280, section 4.2.1.12</a> | |
| */ |
| } | ||
| // The first certificate is the responder certificate, other certificates, if given, are the certificate's chain. | ||
| final X509CertificateHolder responderCert = basicResponse.getCerts()[0]; | ||
| OcspResponseValidator.validateResponseSignature(basicResponse, responderCert, ocspService.getAccessLocation()); |
There was a problem hiding this comment.
Like with AuthTokenValidatorImpl.validateToken() below, we should run validateResponderCertificate() before validateResponseSignature(). The certificate attached to an OCSP response is untrusted input, its key should reach the response signature verifier only after pinning or issuer verification succeeds.
OpenJDK follows this order as well. It verifies the delegated responder certificate using the issuer’s trusted key before verifying the response signature. This prevents unauthorized, attacker-chosen key parameters from driving response signature verification.
You can check the OpenJDK OCSPResponse and related code for other inspiration as well while we are improving OCSP code.
There was a problem hiding this comment.
Also, while at it, please add a comment that the ordering is deliberate and explain shortly why.
| throw new OCSPCertificateException("Certificate " + certificate.getSubjectX500Principal() + | ||
| " Key Usage extension does not contain Digital Signature or Non Repudiation, which is required for OCSP response signing"); | ||
| } | ||
| if (keyUsage.length > KEY_USAGE_KEY_CERT_SIGN_BIT_INDEX && keyUsage[KEY_USAGE_KEY_CERT_SIGN_BIT_INDEX]) { |
There was a problem hiding this comment.
Now I see that the Certificate Signing prohibition logically belongs to the "not CA" part in validateBasicConstraintsNotCA(), see the comment at validateBasicConstraintsNotCA().
| private static final int KEY_USAGE_NON_REPUDIATION_BIT_INDEX = 1; | ||
| private static final int KEY_USAGE_KEY_CERT_SIGN_BIT_INDEX = 5; | ||
| private static final String ERROR_PREFIX = "Certificate status update time check failed: "; | ||
|
|
There was a problem hiding this comment.
Let's add a docstring:
| /** | |
| * Validates that the responder certificate is not a CA and does not include Certificate Signing. | |
| * | |
| * <p>For a non-CA certificate, RFC 5280 section 4.2.1.9 prohibits the Certificate Signing | |
| * bit in Key Usage, including when the Basic Constraints extension is absent. | |
| * | |
| * @param certificate the OCSP responder certificate to validate | |
| * @throws OCSPCertificateException if the certificate is a CA or asserts Certificate Signing | |
| * @throws NullPointerException if {@code certificate} is null | |
| * @see <a href="https://www.rfc-editor.org/rfc/rfc5280.html#section-4.2.1.9">RFC 5280, section 4.2.1.9</a> | |
| */ |
| if (certificate.getBasicConstraints() >= 0) { | ||
| throw new OCSPCertificateException("Certificate " + certificate.getSubjectX500Principal() + | ||
| " must not be a CA certificate (Basic Constraints CA:TRUE is not allowed for OCSP responder)"); | ||
| } |
There was a problem hiding this comment.
Let's move the "non-CA" Certificate Signing in Key Usage here for consistency:
| } | |
| } | |
| final boolean[] keyUsage = certificate.getKeyUsage(); | |
| if (keyUsage != null && keyUsage.length > KEY_USAGE_KEY_CERT_SIGN_BIT_INDEX | |
| && keyUsage[KEY_USAGE_KEY_CERT_SIGN_BIT_INDEX]) { | |
| throw new OCSPCertificateException("Certificate " + certificate.getSubjectX500Principal() + | |
| " Key Usage extension contains Certificate Signing, which is not allowed for a non-CA OCSP responder certificate"); |
| * @param doesSupportNonce true if the service supports the OCSP protocol nonce extension | ||
| * @param maxThisUpdateAge the maximum age of the OCSP response's {@code thisUpdate} time, must be greater than zero | ||
| * @param maxNextUpdateAge the maximum age of the OCSP response's {@code nextUpdate} time, must be greater than zero | ||
| * @param isKeyUsageRequired true if the responder certificate must have the Key Usage extension with Digital Signature |
There was a problem hiding this comment.
| * @param isKeyUsageRequired true if the responder certificate must have the Key Usage extension with Digital Signature | |
| * @param isKeyUsageRequired true if the responder certificate must have the Key Usage extension |
| The two custom checker options and `withoutUserCertificateRevocationCheck()` are mutually exclusive. Combining them causes `build()` to throw `IllegalArgumentException`. Custom checker implementations must support concurrent validation calls. | ||
|
|
||
| Platform OCSP networking and response freshness are controlled by the JDK provider; see [Platform OCSP timeouts](#platform-ocsp-timeouts). The v3 API builder-level OCSP client, timeout, designated-service and response-age options are no longer available; use the custom OCSP checker below when those controls are needed. Its timing constants do not configure the platform checker. | ||
|
|
There was a problem hiding this comment.
Let's add a section about OCSP responder revocation limitation (add link to this section also to Contents):
| ## OCSP responder revocation check limitation | |
| The bundled custom OCSP checker and OpenJDK 17's OCSP implementation do not check delegated responder certificate revocation, even when `id-pkix-ocsp-nocheck` is absent. A revoked responder with a compromised key can therefore produce signed responses that are accepted. Applications requiring responder revocation checking must enforce it separately or supply a `CertificateRevocationChecker` that does so. |
AUT-2981
Signed-off-by: Madis Jaagup Laurson <madisjaagup.laurson@nortal.com>