Skip to content

Commit

Permalink
Use case insensitive hostname comparison for validating certificate (#…
Browse files Browse the repository at this point in the history
…1337)

Implements case insentive hostname comparison to follow the RFC 3986 - https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1

Signed-off-by: Rodrigo Oliveira <[email protected]>
  • Loading branch information
oliveirars authored Oct 29, 2024
1 parent d73a216 commit 13a6a8e
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,17 @@ public static void checkValidity(X509Certificate certificate, boolean endEntity)
}
}

/**
* Creates a predicate to compare a hostname against a SubjectAltName DNSName entry in a
* certificate. The comparison is case-insensitive, following RFC 3986.
*
* @param hostname the hostname to compare against.
* @return a predicate that returns {@code true} if the hostname matches the DNSName entry.
*/
private static Predicate<Object> hostnameValidationPredicate(String hostname) {
return input -> input instanceof String && hostname.equalsIgnoreCase((String) input);
}

/**
* Validate that one of {@code hostNames} matches a SubjectAltName DNSName or IPAddress entry in the certificate.
*
Expand All @@ -513,7 +524,7 @@ public static void checkHostnameOrIpAddress(
return checkSubjectAltNameField(
certificate,
SUBJECT_ALT_NAME_DNS_NAME,
n::equals
hostnameValidationPredicate(n)
);
} catch (Throwable t) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import static com.google.common.collect.Sets.newHashSet;
import static java.util.Collections.emptySet;
import static org.eclipse.milo.opcua.stack.core.util.validation.CertificateValidationUtil.buildTrustedCertPath;
import static org.eclipse.milo.opcua.stack.core.util.validation.CertificateValidationUtil.checkHostnameOrIpAddress;
import static org.eclipse.milo.opcua.stack.core.util.validation.CertificateValidationUtil.validateTrustedCertPath;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
Expand Down Expand Up @@ -451,6 +452,15 @@ public void testUriWithSpaces() throws Exception {
);
}

@Test
public void testHostnameWithCaseInsensitive() throws Exception {
String hostname = "digitalpetri.com";
checkHostnameOrIpAddress(createSelfSignedCertificate("digitalpetri.com"), hostname);
checkHostnameOrIpAddress(createSelfSignedCertificate("DIGITALPETRI.COM"), hostname);
checkHostnameOrIpAddress(createSelfSignedCertificate("DIGITALPETRI.com"), hostname);
checkHostnameOrIpAddress(createSelfSignedCertificate("DigitalPetri.com"), hostname);
}

private X509CRL generateCrl(X509Certificate ca, PrivateKey caPrivateKey, X509Certificate... revoked) throws Exception {
X509v2CRLBuilder builder = new X509v2CRLBuilder(
new X500Name(ca.getSubjectDN().getName()),
Expand Down Expand Up @@ -487,4 +497,14 @@ private X509Certificate getCertificate(String alias) throws KeyStoreException {
return certificate;
}

private static X509Certificate createSelfSignedCertificate(String dnsName) throws Exception {
KeyPair keyPair = SelfSignedCertificateGenerator.generateRsaKeyPair(2048);

SelfSignedCertificateBuilder builder = new SelfSignedCertificateBuilder(keyPair)
.setApplicationUri("urn:eclipse:milo:test")
.addDnsName(dnsName);

return builder.build();
}

}

0 comments on commit 13a6a8e

Please sign in to comment.