Skip to content

Commit e01db4b

Browse files
committed
JSSE: add LDAPS endpoint identification to X509ExtendedTrustManager
1 parent ad59d74 commit e01db4b

12 files changed

Lines changed: 815 additions & 161 deletions

native/com_wolfssl_WolfSSLCertificate.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1check_1host
776776

777777
hostname = (*jenv)->GetStringUTFChars(jenv, chk, 0);
778778
if (hostname != NULL) {
779-
/* flags and peerNamePtr not used */
779+
/* peerNamePtr not used */
780780
ret = wolfSSL_X509_check_host(x509, hostname,
781781
XSTRLEN(hostname), (unsigned int)flags, NULL);
782782
}

src/java/com/wolfssl/WolfSSL.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,11 @@ public enum TLS_VERSION {
549549
* level with WolfSSLContext.setDevId() and WolfSSLSession.setDevId() */
550550
public static int devId = WolfSSL.INVALID_DEVID;
551551

552+
/* ------------------------- Flag Values ---------------------------- */
553+
/** WolfSSLCertificate.checkHost() match only wildcards in left-most
554+
* position, used for LDAPS hostname verification. */
555+
public static int WOLFSSL_LEFT_MOST_WILDCARD_ONLY = 0x40;
556+
552557
/* ---------------------------- locks ------------------------------- */
553558

554559
/* lock for cleanup */

src/java/com/wolfssl/WolfSSLCertificate.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1439,10 +1439,32 @@ public int getExtensionSet(String oid) throws IllegalStateException {
14391439
*/
14401440
public int checkHost(String hostname) throws IllegalStateException {
14411441

1442+
return checkHost(hostname, 0);
1443+
}
1444+
1445+
/**
1446+
* Checks that given hostname matches this certificate SubjectAltName
1447+
* or CommonName entries, behavior can be controlled via flags.
1448+
*
1449+
* @param hostname Hostname to check certificate against
1450+
* @param flags Flags to control hostname check behavior. Supported options
1451+
* include WolfSSL.WOLFSSL_LEFT_MOST_WILDCARD_ONLY to only match
1452+
* wildcards on left-most position.
1453+
*
1454+
* @return WolfSSL.SSL_SUCCESS on successful hostname match,
1455+
* WolfSSL.SSL_FAILURE on invalid match or error, or
1456+
* WolfSSL.NOT_COMPILED_IN if native wolfSSL has been compiled
1457+
* with NO_ASN defined and native API is not available.
1458+
*
1459+
* @throws IllegalStateException if WolfSSLCertificate has been freed.
1460+
*/
1461+
public int checkHost(String hostname, long flags)
1462+
throws IllegalStateException {
1463+
14421464
confirmObjectIsActive();
14431465

14441466
synchronized (x509Lock) {
1445-
return X509_check_host(this.x509Ptr, hostname, 0, 0);
1467+
return X509_check_host(this.x509Ptr, hostname, flags, 0);
14461468
}
14471469
}
14481470

src/java/com/wolfssl/provider/jsse/WolfSSLTrustX509.java

Lines changed: 90 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@
5050

5151
/**
5252
* wolfSSL implementation of X509TrustManager, extends
53-
* X509ExtendedTrustManager for additional hostname verification for HTTPS.
53+
* X509ExtendedTrustManager for additional hostname verification for
54+
* HTTPS (RFC 2818) and LDAPS (RFC 2830).
5455
*
5556
* @author wolfSSL
5657
*/
@@ -59,6 +60,11 @@ public final class WolfSSLTrustX509 extends X509ExtendedTrustManager
5960

6061
private KeyStore store = null;
6162

63+
/** X509ExtendedTrustManager hostname type HTTPS */
64+
private static int HOSTNAME_TYPE_HTTPS = 1;
65+
/** X509ExtendedTrustManager hostname type LDAPS */
66+
private static int HOSTNAME_TYPE_LDAPS = 2;
67+
6268
/**
6369
* Create new WolfSSLTrustX509 object
6470
*
@@ -430,18 +436,25 @@ private List<X509Certificate> certManagerVerify(
430436
}
431437

432438
/**
433-
* Verify hostname using HTTPS verification method.
439+
* Verify hostname using HTTPS or LDAPS verification method.
434440
*
435-
* This method does the following operations in an attempt to verify
436-
* the HTTPS type hostname:
441+
* For HTTPS hostname verification (RFC 2818):
437442
*
438-
* 1. If SNI name has been received during TLS handshake, try to
443+
* - If SNI name has been received during TLS handshake, try to
439444
* first verify peer certificate against that. Skip this step when
440445
* on server side verifying the client, since server does not set
441446
* an SNI for the client.
442-
* 2. Otherwise, try to verify certificate against SSLSocket
443-
* hostname (SSLSession.getHostName()).
444-
* 3. If both of the above fail, fail hostname verification.
447+
* - Otherwise, try to verify certificate against SSLSocket or SSLEngine
448+
* hostname (getHandshakeSession().getHostName()).
449+
* - If both of the above fail, fail hostname verification.
450+
* - Hostname matching rules for HTTPS come from RFC 2818
451+
*
452+
* For LDAPS hostname verification (RFC 2830):
453+
*
454+
* - Try to verify certificate against hostname used to create
455+
* the SSLSocket or SSLEngine, obtained via
456+
* getHandshakeSession().getPeerHost().
457+
* - Hostname matching rules for LDAPS come from RFC 2830
445458
*
446459
* @param cert peer certificate
447460
* @param socket SSLSocket associated with connection to peer. Only one
@@ -452,10 +465,13 @@ private List<X509Certificate> certManagerVerify(
452465
* null.
453466
* @param isClient true if we are calling this from client side, otherwise
454467
* false if calling from server side.
468+
* @param type type of hostname to verify, options are
469+
* HOSTNAME_TYPE_HTTPS or HOSTNAME_TYPE_LDAPS
455470
* @throws CertificateException if hostname cannot be verified
456471
*/
457-
private void verifyHTTPSHostname(X509Certificate cert, SSLSocket socket,
458-
SSLEngine engine, boolean isClient) throws CertificateException {
472+
private void verifyHostnameByType(X509Certificate cert, SSLSocket socket,
473+
SSLEngine engine, boolean isClient, int type)
474+
throws CertificateException {
459475

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

467-
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
468-
"verifying HTTPS hostname");
483+
if (type == HOSTNAME_TYPE_HTTPS) {
484+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
485+
"verifying hostname type HTTPS");
486+
} else if (type == HOSTNAME_TYPE_LDAPS) {
487+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
488+
"verifying hostname type LDAPS");
489+
} else {
490+
throw new CertificateException("Unsupported hostname type, " +
491+
"HTTPS and LDAPS only supported currently: " + type);
492+
}
469493

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

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

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

520-
/* Try verifying hostname against SNI name */
521-
if (isClient) {
547+
/* Try verifying hostname against SNI name, if HTTPS type */
548+
if (isClient && (type == HOSTNAME_TYPE_HTTPS)) {
522549
if (sniHostName != null) {
523550
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
524551
"trying hostname verification against SNI: " + sniHostName);
@@ -541,13 +568,18 @@ else if (engine != null) {
541568
}
542569
}
543570

544-
/* Try verifying hostname against peerHost from SSLSocket/Engine */
571+
/* Try verifying hostname against peerHost from SSLSocket/SSLEngine */
545572
if (peerHost != null) {
546573
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
547-
"trying hostname verification against peer host: " +
548-
peerHost);
574+
"trying hostname verification against peer host: " + peerHost);
549575

550-
ret = peerCert.checkHost(peerHost);
576+
if (type == HOSTNAME_TYPE_LDAPS) {
577+
/* LDAPS requires wildcard left-most matching only */
578+
ret = peerCert.checkHost(peerHost,
579+
WolfSSL.WOLFSSL_LEFT_MOST_WILDCARD_ONLY);
580+
} else {
581+
ret = peerCert.checkHost(peerHost);
582+
}
551583
if (ret == WolfSSL.SSL_SUCCESS) {
552584
/* Hostname successfully verified against peer host name */
553585
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
@@ -558,10 +590,16 @@ else if (engine != null) {
558590
}
559591

560592
if (isClient) {
561-
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
562-
"hostname verification failed for server peer cert, " +
563-
"tried SNI (" + sniHostName + "), peer host (" + peerHost +
564-
")\n" + peerCert);
593+
if (type == HOSTNAME_TYPE_HTTPS) {
594+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
595+
"hostname verification failed for server peer cert, " +
596+
"tried SNI (" + sniHostName + "), peer host (" + peerHost +
597+
")\n" + peerCert);
598+
} else {
599+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
600+
"hostname verification failed for server peer cert, " +
601+
"peer host (" + peerHost + ")\n" + peerCert);
602+
}
565603
} else {
566604
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
567605
"hostname verification failed for client peer cert, " +
@@ -593,7 +631,7 @@ protected void verifyHostname(X509Certificate cert,
593631
SSLParameters sslParams = null;
594632
SSLSession session = null;
595633

596-
/* Hostname verification only done if Socket is of SSLSocket,
634+
/* Hostname verification on Socket done only if Socket is of SSLSocket,
597635
* not null, and connected */
598636
if ((socket != null) && (socket instanceof SSLSocket) &&
599637
(socket.isConnected())) {
@@ -614,8 +652,15 @@ protected void verifyHostname(X509Certificate cert,
614652
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
615653
"verifying hostname, endpoint identification " +
616654
"algorithm = HTTPS");
617-
verifyHTTPSHostname(cert, (SSLSocket)socket,
618-
null, isClient);
655+
verifyHostnameByType(cert, (SSLSocket)socket,
656+
null, isClient, HOSTNAME_TYPE_HTTPS);
657+
}
658+
else if (endpointIdAlgo.equals("LDAPS")) {
659+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
660+
"verifying hostname, endpoint identification " +
661+
"algorithm = LDAPS");
662+
verifyHostnameByType(cert, (SSLSocket)socket,
663+
null, isClient, HOSTNAME_TYPE_LDAPS);
619664
}
620665
else {
621666
throw new CertificateException(
@@ -647,7 +692,15 @@ else if (engine != null) {
647692
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
648693
"verifying hostname, endpoint identification " +
649694
"algorithm = HTTPS");
650-
verifyHTTPSHostname(cert, null, engine, isClient);
695+
verifyHostnameByType(cert, null, engine, isClient,
696+
HOSTNAME_TYPE_HTTPS);
697+
}
698+
else if (endpointIdAlgo.equals("LDAPS")) {
699+
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
700+
"verifying hostname, endpoint identification " +
701+
"algorithm = LDAPS");
702+
verifyHostnameByType(cert, null, engine, isClient,
703+
HOSTNAME_TYPE_LDAPS);
651704
}
652705
else {
653706
throw new CertificateException(
@@ -708,13 +761,13 @@ public void checkClientTrusted(X509Certificate[] certs, String type)
708761
* Try to build and validate the client certificate chain based on the
709762
* provided certificates and authentication type.
710763
*
711-
* Also does hostname verification internally if Endpoint Identification
764+
* Does hostname verification internally if Endpoint Identification
712765
* Algorithm has been set by application in SSLParameters, and that
713-
* Algorithm matches "HTTPS". If that is set, hostname verification is
714-
* done using SNI first then peer host value.
766+
* Algorithm matches "HTTPS" or "LDAPS". If "HTTPS" is set, hostname
767+
* verification is done using SNI first then peer host value.
715768
*
716-
* Other Endpoint Identification Algorithms besides "HTTPS" are not
717-
* currently supported.
769+
* Other Endpoint Identification Algorithms besides "HTTPS" and "LDAPS"
770+
* are not currently supported.
718771
*
719772
* @param certs peer certificate chain
720773
* @param type authentication type based on the client certificate

0 commit comments

Comments
 (0)