pingidentity / ldapsdk

UnboundID LDAP SDK for Java
Other
331 stars 79 forks source link

Is LDAP channel binding and LDAP signing supported by UnboundID LDAP SDK? #74

Open ultimatesecpro opened 4 years ago

ultimatesecpro commented 4 years ago

Relatively recently Microsoft has added support for LDAP channel binding and LDAP signing:

https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/ADV190023

Is it part of LDAPv3 protocol? Is it supported by UnboundID LDAP SDK?

kenneth-ping commented 4 years ago

Hello Michael, the short answer is no, these are not currently supported, but this is a known issue we are tracking. Neil, who is on PTO this week, can provide a more thorough answer when he is able.

-Kenneth

On Mon, Nov 25, 2019 at 5:59 AM Michael Furman notifications@github.com wrote:

Relatively recently Microsoft has added support for LDAP channel binding and LDAP signing:

https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/ADV190023

Is it part of LDAPv3 protocol? Is it supported by UnboundID LDAP SDK?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/pingidentity/ldapsdk/issues/74?email_source=notifications&email_token=ABO4UAXWPCV2DH2ZUGVB3ELQVO43LA5CNFSM4JRH2DXKYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4H3ZIE4A, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABO4UATHNTA32FZ5LLTNT4LQVO43LANCNFSM4JRH2DXA .

-- https://www.pingidentity.com[image: Ping Identity] https://www.pingidentity.com Kenneth Suter Development Manager kennethsuter@pingidentity.com

Connect with us: [image: Glassdoor logo] https://www.glassdoor.com/Overview/Working-at-Ping-Identity-EI_IE380907.11,24.htm [image: LinkedIn logo] https://www.linkedin.com/company/21870 [image: twitter logo] https://twitter.com/pingidentity [image: facebook logo] https://www.facebook.com/pingidentitypage [image: youtube logo] https://www.youtube.com/user/PingIdentityTV [image: Blog logo] https://www.pingidentity.com/en/blog.html https://www.google.com/url?q=https://www.pingidentity.com/content/dam/ping-6-2-assets/Assets/faqs/en/consumer-attitudes-post-breach-era-3375.pdf?id%3Db6322a80-f285-11e3-ac10-0800200c9a66&source=gmail&ust=1541693608526000&usg=AFQjCNGBl5cPHCUAVKGZ_NnpuFj5PHGSUQ https://www.pingidentity.com/en/events/d/identify-2019.html https://www.pingidentity.com/content/dam/ping-6-2-assets/Assets/Misc/en/3464-consumersurvey-execsummary.pdf

-- CONFIDENTIALITY NOTICE: This email may contain confidential and privileged material for the sole use of the intended recipient(s). Any review, use, distribution or disclosure by others is strictly prohibited.  If you have received this communication in error, please notify the sender immediately by e-mail and delete the message and any file attachments from your computer. Thank you.

ultimatesecpro commented 4 years ago

Thanks! Do you know if it is part of the LDAPv3 protocol?

dirmgr commented 4 years ago

There are two parts to this answer. First, Microsoft really isn't using the correct term when they say "LDAP signing" because they're not talking about LDAP operation signatures as described in RFC 2649 (which the LDAP SDK doesn't currently support, and would honestly be pretty difficult to add because of the way that the signature is computed). They're really talking about SASL integrity protection, which the LDAP SDK does support when using either GSSAPI or DIGEST-MD5. But since you should absolutely never use DIGEST-MD5, then that leaves you with GSSAPI. However, I would recommend using confidentiality rather than integrity protection because with integrity protection, the traffic is still basically in the clear so any observer can see everything; they just can't change it in an undetectable way.

While the LDAP SDK does support SASL integrity and confidentiality, and it seems to work just fine against a third-party known-compliant implementation in OpenLDAP, we have had a report that it doesn't always work properly against Active Directory (https://github.com/pingidentity/ldapsdk/issues/68). There's only been one such report, so I'm not sure if there actually is a problem, but if it is then it might be a JVM issue because we're relying entirely on the JVM to do all of the SASL processing for GSSAPI, including the integrity and confidentiality processing.

However, as far as I can tell, this really applies to unencrypted LDAP communication. It doesn't seem to apply to LDAP connections that are encrypted with TLS (which you should be using anyway, and provides all of the same protections in a much better way). The Microsoft page about LDAP signing (https://support.microsoft.com/en-us/help/935834/how-to-enable-ldap-signing-in-windows-server-2008) suggests that the "require signing" option doesn't apply to simple binds over TLS.

With regard to channel binding, Java does not currently support channel binding for TLS. We can't support that in the LDAP SDK until the JVM supports it. It does look like Java might have some degree of channel binding support that specifically applies to GSSAPI, but the Microsoft document about channel binding (https://support.microsoft.com/en-us/help/4034879/how-to-add-the-ldapenforcechannelbinding-registry-entry) only mentions TLS and not SASL or GSSAPI. I haven't yet looked into whether it's actually possible to use channel binding in conjunction with GSSAPI or whether any additional work is required. If it does work, then you'd probably at least need to use a custom configuration file. It's something that I do plan to look into, but it will take some time to get an environment set up for testing.

ultimatesecpro commented 4 years ago

THANKS!!!

griffjames100 commented 3 years ago

I know that the policy is not to accept external contributions directly but I do have a relatively simple set of changes that create the channel binding token when using LDAPS and pass it into the Java Sasl client. Are you interested?

dirmgr commented 3 years ago

Unfortunately, our current policy is to not accept third-party contributions. However, if you can point me at documentation that describes how to do this, I can look into providing my own implementation.

Note, however, that the LDAP SDK currently supports Java 7 and later. If adding this support would require using an API that's not available in Java 7, then that may make it substantially more difficult. It may be possible through reflection if it's available in a wide enough range of Java versions, although I'd like to avoid that if possible.

griffjames100 commented 3 years ago

Hi Neil,

The relevant RFC is: https://datatracker.ietf.org/doc/html/rfc5929

Here's the original Java change to implement LDAPS channel binding: https://github.com/openjdk/jdk13u-dev/commit/97ba018b

I don't think support goes as far back as Java7. However, the ldapsdk only needs to generate the binding token as per the RFC and pass it in as a new environment property when creating the SASL client. Hence, generating and passing the token wouldn't break older versions of Java. i.e.

  saslProperties.put("jdk.internal.sasl.tlschannelbinding", cbToken.getData());

  final String[] mechanisms = { GSSAPI_MECHANISM_NAME };
  saslClient = Sasl.createSaslClient(mechanisms, authorizationID,
       servicePrincipalProtocol, serverName, saslProperties, this);
dirmgr commented 3 years ago

Thanks for the reference. I'll take a look into this, although it may be a little time before I can get to it.

dirmgr commented 2 years ago

I finally got a chance to look into this, and I’ve made a set of code changes that I think should add support for the tls-server-end-point channel binding type. I’ve tested them against a server that doesn’t require GSSAPI channel binding and it doesn’t seem to break anything there, but I don’t have ready access to a server configured to require channel binding, so I can’t really test these changes.

Would you be willing to test them? I’ve created a build containing these changes and uploaded it to https://docs.ldap.com/ldap-sdk/files/unboundid-ldapsdk-6.0.2-gssapi-channel-binding-test.zip. To enable channel binding, you will need to use the new GSSAPIBindRequestProperties.setChannelBindingType method, and you can provide it with a value of GSSAPIChannelBindingType.TLS_SERVER_END_POINT to enable that type of channel binding.

Here’s a small set of code that I used for testing:

import com.unboundid.ldap.sdk.GSSAPIBindRequest;
import com.unboundid.ldap.sdk.GSSAPIBindRequestProperties;
import com.unboundid.ldap.sdk.GSSAPIChannelBindingType;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.util.ssl.SSLUtil;
import com.unboundid.util.ssl.TrustAllTrustManager;

public class GSSAPIChannelBindingTest
{
  public static void main(final String... args)
         throws Exception
  {
    final SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
    try (LDAPConnection conn = new LDAPConnection(
              sslUtil.createSSLSocketFactory(), "ldap.example.com", 636))
    {
      final GSSAPIBindRequestProperties properties =
           new GSSAPIBindRequestProperties("test.user@EXAMPLE.COM", "password");
      properties.setKDCAddress("kdc.example.com");
      properties.setRealm("EXAMPLE.COM");
      properties.setChannelBindingType(
           GSSAPIChannelBindingType.TLS_SERVER_END_POINT);

      final GSSAPIBindRequest bindRequest = new GSSAPIBindRequest(properties);
      conn.bind(bindRequest);
    }
  }
}
griffjames100 commented 2 years ago

Thanks Neil. I'll give your changes a try this week and update here...

griffjames100 commented 2 years ago

Hi Neil, I've tested the changes against 2 of my test domains, both of which are configured to require channel binding. Everything works as expected.

Using GSSAPIChannelBindingType.NONE fails (to double check the CB token is required by the domain's DCs). Changing to GSSAPIChannelBindingType.TLS_SERVER_END_POINT succeeds.

Thanks for making the updates.

Do you when they'll be included in an official release?

dirmgr commented 2 years ago

I'm glad the changes work. I'll add a couple of tests early next week and push the changes to GitHub.

As of right now, the next release is slated for late November/early December. However, you're free to use the build that I provided, or code that you build yourself from GitHub once the changes are pushed\, and I'll support it just like an official release.

griffjames100 commented 2 years ago

ok, thanks Neil

dirmgr commented 2 years ago

The changes were committed yesterday. Also, because of an issue that I found in the JVM-default trust manager that could affect its ability to use cross-signed certificates in some cases, I went ahead and put out a new 6.0.2 release of the LDAP SDK, so these changes are available in a release now.

griffjames100 commented 2 years ago

ok thanks Neil. I'll change to 6.0.2 soon.

vanxa commented 2 years ago

Hi all, I can confirm the changes work for domains that have LDAP channel binding configured. I have a question on fallback behavior - if the AD has not configured LDAP channel binding, but GSSAPIChannelBindingType.TLS_SERVER_END_POINT is set in the client, do you know if this is going to break communication? I've also tested this change with an AD that accepts bind requests without channel binding, and it works, but I'm not sure if this is a specific configuration case, or whether such mismatch is accepted.

dirmgr commented 2 years ago

To be honest, I'm not sure. I don't really have ready access to an Active Directory server that I can use for testing. My guess is that it will probably work if the client offers it but the server doesn't require it, but not if the server requires it and the client doesn't provide it, and that does seem to agree with your results, but I can't answer with any degree of authority. That's probably more a question for Active Directory support.

griffjames100 commented 2 years ago

It's up to the server (AD in this case) to enforce the channel binding token.

In the case of AD, there is a GPO setting with 3 possible values detailed in https://support.microsoft.com/en-us/topic/2020-ldap-channel-binding-and-ldap-signing-requirements-for-windows-ef185fb8-00f7-167d-744c-f299a66fc00a.

0: means the server doesn't validate the CB token even if the client sends one. 1: means the server will validate the CB token but only if the client sends one. If the client doesn't send a CB token it can still connect. 2: means the client must send a validate CB token, period.

There are no issues with sending a CB token from the client.