Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ public ChainVerifier(Set<InputStream> rootCertificates) {
}

public PublicKey verifyChain(String[] certificates, boolean performRevocationChecking, Date effectiveDate) throws VerificationException {
if (certificates == null) {
throw new VerificationException(VerificationStatus.INVALID_CHAIN_LENGTH);
}
if (performRevocationChecking && certificates.length > 0) {
// If revocation checking is enabled (which also implies effectiveDate is now), check the cache
PublicKey cachedKey = getCachedPublicKey(Arrays.asList(certificates));
Expand All @@ -77,6 +80,10 @@ public PublicKey verifyChain(String[] certificates, boolean performRevocationChe
}

PublicKey verifyChainWithoutCaching(String[] certificates, boolean performRevocationChecking, Date effectiveDate) throws VerificationException {
if (certificates.length != EXPECTED_CHAIN_LENGTH) {
throw new VerificationException(VerificationStatus.INVALID_CHAIN_LENGTH);
}

CertificateFactory certificateFactory;
CertPathValidator certPathValidator;
try {
Expand All @@ -95,10 +102,6 @@ PublicKey verifyChainWithoutCaching(String[] certificates, boolean performRevoca
throw new VerificationException(VerificationStatus.INVALID_CERTIFICATE, e);
}

if (parsedCertificates.size() != EXPECTED_CHAIN_LENGTH) {
throw new VerificationException(VerificationStatus.INVALID_CHAIN_LENGTH);
}

try {
//We don't include the root cert in the path, due to OCSP not being supported
CertPath certPath = certificateFactory.generateCertPath(parsedCertificates.subList(0, EXPECTED_CHAIN_LENGTH - 1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
import java.security.PublicKey;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateFactory;
import java.time.Clock;
import java.time.Instant;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

Expand Down Expand Up @@ -105,6 +108,32 @@ public void testInvalidChainLength() {
Assertions.assertEquals(VerificationStatus.INVALID_CHAIN_LENGTH, exception.getStatus());
}

@Test
public void testInvalidChainLengthsAreRejectedBeforeParsingCertificates() throws Exception {
ChainVerifier verifier = getChainVerifier(ROOT_CA_BASE64_ENCODED);
CertificateFactory certificateFactory = Mockito.mock(CertificateFactory.class);
String[] oversizedChain = new String[1_000];
Arrays.fill(oversizedChain, ROOT_CA_BASE64_ENCODED);

try (MockedStatic<CertificateFactory> mockedCertificateFactory = Mockito.mockStatic(CertificateFactory.class)) {
mockedCertificateFactory.when(() -> CertificateFactory.getInstance("X.509")).thenReturn(certificateFactory);

for (String[] invalidChain : List.<String[]>of(
new String[0],
new String[] {ROOT_CA_BASE64_ENCODED},
new String[] {ROOT_CA_BASE64_ENCODED, ROOT_CA_BASE64_ENCODED},
new String[] {ROOT_CA_BASE64_ENCODED, ROOT_CA_BASE64_ENCODED, ROOT_CA_BASE64_ENCODED, ROOT_CA_BASE64_ENCODED},
oversizedChain)) {
VerificationException exception = Assertions.assertThrows(
VerificationException.class,
() -> verifier.verifyChain(invalidChain, false, EFFECTIVE_DATE));
Assertions.assertEquals(VerificationStatus.INVALID_CHAIN_LENGTH, exception.getStatus());
}

Mockito.verifyNoInteractions(certificateFactory);
}
}

@Test
public void testMalformedBase64InCertificateList() {
ChainVerifier verifier = getChainVerifier(ROOT_CA_BASE64_ENCODED);
Expand Down