Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSSE: add LDAPS endpoint identification to X509ExtendedTrustManager #227

Merged
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
2 changes: 1 addition & 1 deletion native/com_wolfssl_WolfSSLCertificate.c
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1check_1host

hostname = (*jenv)->GetStringUTFChars(jenv, chk, 0);
if (hostname != NULL) {
/* flags and peerNamePtr not used */
/* peerNamePtr not used */
ret = wolfSSL_X509_check_host(x509, hostname,
XSTRLEN(hostname), (unsigned int)flags, NULL);
}
Expand Down
5 changes: 5 additions & 0 deletions src/java/com/wolfssl/WolfSSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,11 @@ public enum TLS_VERSION {
* level with WolfSSLContext.setDevId() and WolfSSLSession.setDevId() */
public static int devId = WolfSSL.INVALID_DEVID;

/* ------------------------- Flag Values ---------------------------- */
/** WolfSSLCertificate.checkHost() match only wildcards in left-most
* position, used for LDAPS hostname verification. */
public static int WOLFSSL_LEFT_MOST_WILDCARD_ONLY = 0x40;

/* ---------------------------- locks ------------------------------- */

/* lock for cleanup */
Expand Down
24 changes: 23 additions & 1 deletion src/java/com/wolfssl/WolfSSLCertificate.java
Original file line number Diff line number Diff line change
Expand Up @@ -1439,10 +1439,32 @@ public int getExtensionSet(String oid) throws IllegalStateException {
*/
public int checkHost(String hostname) throws IllegalStateException {

return checkHost(hostname, 0);
}

/**
* Checks that given hostname matches this certificate SubjectAltName
* or CommonName entries, behavior can be controlled via flags.
*
* @param hostname Hostname to check certificate against
* @param flags Flags to control hostname check behavior. Supported options
* include WolfSSL.WOLFSSL_LEFT_MOST_WILDCARD_ONLY to only match
* wildcards on left-most position.
*
* @return WolfSSL.SSL_SUCCESS on successful hostname match,
* WolfSSL.SSL_FAILURE on invalid match or error, or
* WolfSSL.NOT_COMPILED_IN if native wolfSSL has been compiled
* with NO_ASN defined and native API is not available.
*
* @throws IllegalStateException if WolfSSLCertificate has been freed.
*/
public int checkHost(String hostname, long flags)
throws IllegalStateException {

confirmObjectIsActive();

synchronized (x509Lock) {
return X509_check_host(this.x509Ptr, hostname, 0, 0);
return X509_check_host(this.x509Ptr, hostname, flags, 0);
}
}

Expand Down
127 changes: 90 additions & 37 deletions src/java/com/wolfssl/provider/jsse/WolfSSLTrustX509.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@

/**
* wolfSSL implementation of X509TrustManager, extends
* X509ExtendedTrustManager for additional hostname verification for HTTPS.
* X509ExtendedTrustManager for additional hostname verification for
* HTTPS (RFC 2818) and LDAPS (RFC 2830).
*
* @author wolfSSL
*/
Expand All @@ -59,6 +60,11 @@ public final class WolfSSLTrustX509 extends X509ExtendedTrustManager

private KeyStore store = null;

/** X509ExtendedTrustManager hostname type HTTPS */
private static int HOSTNAME_TYPE_HTTPS = 1;
/** X509ExtendedTrustManager hostname type LDAPS */
private static int HOSTNAME_TYPE_LDAPS = 2;

/**
* Create new WolfSSLTrustX509 object
*
Expand Down Expand Up @@ -430,18 +436,25 @@ private List<X509Certificate> certManagerVerify(
}

/**
* Verify hostname using HTTPS verification method.
* Verify hostname using HTTPS or LDAPS verification method.
*
* This method does the following operations in an attempt to verify
* the HTTPS type hostname:
* For HTTPS hostname verification (RFC 2818):
*
* 1. If SNI name has been received during TLS handshake, try to
* - If SNI name has been received during TLS handshake, try to
* first verify peer certificate against that. Skip this step when
* on server side verifying the client, since server does not set
* an SNI for the client.
* 2. Otherwise, try to verify certificate against SSLSocket
* hostname (SSLSession.getHostName()).
* 3. If both of the above fail, fail hostname verification.
* - Otherwise, try to verify certificate against SSLSocket or SSLEngine
* hostname (getHandshakeSession().getHostName()).
* - If both of the above fail, fail hostname verification.
* - Hostname matching rules for HTTPS come from RFC 2818
*
* For LDAPS hostname verification (RFC 2830):
*
* - Try to verify certificate against hostname used to create
* the SSLSocket or SSLEngine, obtained via
* getHandshakeSession().getPeerHost().
* - Hostname matching rules for LDAPS come from RFC 2830
*
* @param cert peer certificate
* @param socket SSLSocket associated with connection to peer. Only one
Expand All @@ -452,10 +465,13 @@ private List<X509Certificate> certManagerVerify(
* null.
* @param isClient true if we are calling this from client side, otherwise
* false if calling from server side.
* @param type type of hostname to verify, options are
* HOSTNAME_TYPE_HTTPS or HOSTNAME_TYPE_LDAPS
* @throws CertificateException if hostname cannot be verified
*/
private void verifyHTTPSHostname(X509Certificate cert, SSLSocket socket,
SSLEngine engine, boolean isClient) throws CertificateException {
private void verifyHostnameByType(X509Certificate cert, SSLSocket socket,
SSLEngine engine, boolean isClient, int type)
throws CertificateException {

String peerHost = null;
List<SNIServerName> sniNames = null;
Expand All @@ -464,8 +480,16 @@ private void verifyHTTPSHostname(X509Certificate cert, SSLSocket socket,
WolfSSLCertificate peerCert = null;
int ret = WolfSSL.SSL_FAILURE;

WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"verifying HTTPS hostname");
if (type == HOSTNAME_TYPE_HTTPS) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"verifying hostname type HTTPS");
} else if (type == HOSTNAME_TYPE_LDAPS) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"verifying hostname type LDAPS");
} else {
throw new CertificateException("Unsupported hostname type, " +
"HTTPS and LDAPS only supported currently: " + type);
}

/* Get session associated with SSLSocket or SSLEngine */
try {
Expand All @@ -485,12 +509,15 @@ else if (engine != null) {
peerHost = session.getPeerHost();
}

/* Get SNI name if SSLSocket has received that from peer. Only check
* this when on the client side and verifying a server since SNI
* holding expected server name is available on client-side but not
* vice-versa */
if (session != null && isClient &&
(session instanceof ExtendedSSLSession)) {
/* Get SNI name if SSLSocket/SSLEngine has received that from peer.
* Only check this when on the client side and verifying a server since
* SNI holding expected server name is available on client-side but not
* vice-versa. Also only checked for HTTPS type, not LDAPS. As per
* RFC 2830, the client MUST use the server hostname it used to open
* the LDAP connection. */
if ((session != null) && isClient &&
(session instanceof ExtendedSSLSession) &&
(type == HOSTNAME_TYPE_HTTPS)) {
sniNames = ((ExtendedSSLSession)session).getRequestedServerNames();

for (SNIServerName name : sniNames) {
Expand All @@ -517,8 +544,8 @@ else if (engine != null) {
throw new CertificateException(e);
}

/* Try verifying hostname against SNI name */
if (isClient) {
/* Try verifying hostname against SNI name, if HTTPS type */
if (isClient && (type == HOSTNAME_TYPE_HTTPS)) {
if (sniHostName != null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"trying hostname verification against SNI: " + sniHostName);
Expand All @@ -541,13 +568,18 @@ else if (engine != null) {
}
}

/* Try verifying hostname against peerHost from SSLSocket/Engine */
/* Try verifying hostname against peerHost from SSLSocket/SSLEngine */
if (peerHost != null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"trying hostname verification against peer host: " +
peerHost);
"trying hostname verification against peer host: " + peerHost);

ret = peerCert.checkHost(peerHost);
if (type == HOSTNAME_TYPE_LDAPS) {
/* LDAPS requires wildcard left-most matching only */
ret = peerCert.checkHost(peerHost,
WolfSSL.WOLFSSL_LEFT_MOST_WILDCARD_ONLY);
} else {
ret = peerCert.checkHost(peerHost);
}
if (ret == WolfSSL.SSL_SUCCESS) {
/* Hostname successfully verified against peer host name */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
Expand All @@ -558,10 +590,16 @@ else if (engine != null) {
}

if (isClient) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"hostname verification failed for server peer cert, " +
"tried SNI (" + sniHostName + "), peer host (" + peerHost +
")\n" + peerCert);
if (type == HOSTNAME_TYPE_HTTPS) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"hostname verification failed for server peer cert, " +
"tried SNI (" + sniHostName + "), peer host (" + peerHost +
")\n" + peerCert);
} else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"hostname verification failed for server peer cert, " +
"peer host (" + peerHost + ")\n" + peerCert);
}
} else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"hostname verification failed for client peer cert, " +
Expand Down Expand Up @@ -593,7 +631,7 @@ protected void verifyHostname(X509Certificate cert,
SSLParameters sslParams = null;
SSLSession session = null;

/* Hostname verification only done if Socket is of SSLSocket,
/* Hostname verification on Socket done only if Socket is of SSLSocket,
* not null, and connected */
if ((socket != null) && (socket instanceof SSLSocket) &&
(socket.isConnected())) {
Expand All @@ -614,8 +652,15 @@ protected void verifyHostname(X509Certificate cert,
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"verifying hostname, endpoint identification " +
"algorithm = HTTPS");
verifyHTTPSHostname(cert, (SSLSocket)socket,
null, isClient);
verifyHostnameByType(cert, (SSLSocket)socket,
null, isClient, HOSTNAME_TYPE_HTTPS);
}
else if (endpointIdAlgo.equals("LDAPS")) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"verifying hostname, endpoint identification " +
"algorithm = LDAPS");
verifyHostnameByType(cert, (SSLSocket)socket,
null, isClient, HOSTNAME_TYPE_LDAPS);
}
else {
throw new CertificateException(
Expand Down Expand Up @@ -647,7 +692,15 @@ else if (engine != null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"verifying hostname, endpoint identification " +
"algorithm = HTTPS");
verifyHTTPSHostname(cert, null, engine, isClient);
verifyHostnameByType(cert, null, engine, isClient,
HOSTNAME_TYPE_HTTPS);
}
else if (endpointIdAlgo.equals("LDAPS")) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"verifying hostname, endpoint identification " +
"algorithm = LDAPS");
verifyHostnameByType(cert, null, engine, isClient,
HOSTNAME_TYPE_LDAPS);
}
else {
throw new CertificateException(
Expand Down Expand Up @@ -708,13 +761,13 @@ public void checkClientTrusted(X509Certificate[] certs, String type)
* Try to build and validate the client certificate chain based on the
* provided certificates and authentication type.
*
* Also does hostname verification internally if Endpoint Identification
* Does hostname verification internally if Endpoint Identification
* Algorithm has been set by application in SSLParameters, and that
* Algorithm matches "HTTPS". If that is set, hostname verification is
* done using SNI first then peer host value.
* Algorithm matches "HTTPS" or "LDAPS". If "HTTPS" is set, hostname
* verification is done using SNI first then peer host value.
*
* Other Endpoint Identification Algorithms besides "HTTPS" are not
* currently supported.
* Other Endpoint Identification Algorithms besides "HTTPS" and "LDAPS"
* are not currently supported.
*
* @param certs peer certificate chain
* @param type authentication type based on the client certificate
Expand Down
Loading