JDK-7065337 : GSSException when using AES-128 encryption for LDAP connection to AD
  • Type: Bug
  • Component: security-libs
  • Sub-Component: org.ietf.jgss
  • Affected Version: 6
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_7
  • CPU: x86
  • Submitted: 2011-07-11
  • Updated: 2012-09-06
  • Resolved: 2012-04-11
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing)

and

java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Java HotSpot(TM) Client VM (build 17.1-b03, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Client:
- Microsoft Windows XP [Version 5.1.2600]
- Microsoft Windows [Version 6.1.7600]

ActiveDirectory Server:
- Microsoft Windows [Version 6.0.6001]

EXTRA RELEVANT SYSTEM CONFIGURATION :
Kerberos configuration (krb5.ini)

[libdefaults]
   default_realm = SSO.TEST.DE
   dns_lookup_kdc = true
   default_tgs_enctypes = aes256-cts aes128-cts des3-cbc-sha1 des-cbc-md5 des-cbc-crc
   dns_lookup_realm = true

[realms]
 	SSO.TEST.DE = {
		default_domain = SSO.TEST.DE
		kdc = WIN-6HYO3DBXS04:88
	}
	
[domain_realm]
    sso.test.de = SSO.TEST.DE
    .sso.test.de = SSO.TEST.DE

[login]
        krb4_convert = false
        krb4_get_tickets = false


A DESCRIPTION OF THE PROBLEM :
If I try to establish an AES-128 encrypted LDAP connection to an Microsoft Active Directory I always get an GSSException, if a none AES encryption is used, the connection could be established successful.




STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
- Set the default encryption types for kerberos to    default_tgs_enctypes = aes256-cts aes128-cts des3-cbc-sha1 des-cbc-md5 des-cbc-crc

- Get an Kerberos Ticket by using JAAS to login to the domain
- Use the Ticket to establish a connection to the LDAP server

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A connection to the LDAP-Server is established and ready to use, the LDAP communication is encrypted.
ACTUAL -
No connection is established, only an Exception is thrown

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Security Providers -
SUN version 1.6
SunRsaSign version 1.5
SunJSSE version 1.6
SunJCE version 1.6
SunJGSS version 1.0
SunSASL version 1.5
XMLDSig version 1.0
SunPCSC version 1.6
SunMSCAPI version 1.6
Debug is  true storeKey false useTicketCache false useKeyTab false doNotPrompt false ticketCache is null isInitiator true KeyTab is null refreshKrb5Config is false principal is null tryFirstPass is false useFirstPass is false storePass is false clearPass is false
		[Krb5LoginModule] user entered username: ids

Acquire TGT using AS Exchange
principal is ###@###.###
EncryptionKey: keyType=3 keyBytes (hex dump)=0000: 68 1F D9 37 EF 49 2C 16
EncryptionKey: keyType=1 keyBytes (hex dump)=0000: 68 1F D9 37 EF 49 2C 16
EncryptionKey: keyType=23 keyBytes (hex dump)=0000: 46 0F 3C 18 6B CE 1E 04   70 92 01 AE 0C 59 E4 1F  F.<.k...p....Y..

EncryptionKey: keyType=16 keyBytes (hex dump)=0000: F7 94 F8 86 E9 B0 5D 76   73 4F 0E 31 D5 80 2A 79  ......]vsO.1..*y
0010: 94 6D 46 10 F2 A1 A4 01
EncryptionKey: keyType=17 keyBytes (hex dump)=0000: 7F F4 0E B2 7C EB FF F7   E4 CC DE 21 1F 92 44 EF  ...........!..D.

EncryptionKey: keyType=18 keyBytes (hex dump)=0000: 17 B7 FE B7 31 80 5C 04   77 77 FA 20 6C 2C A2 1B  ....1.\.ww. l,..
0010: 8C 6B 3F 76 10 A0 0B 5E   83 DA 48 3E 20 FC 04 06  .k?v...^..H> ...

  Commit Succeeded

		No encryption was performed by peer.
javax.naming.AuthenticationException: GSSAPI [Root exception is javax.security.sasl.SaslException: Final handshake failed [Caused by GSSException: Token had invalid integrity check (Mechanism level: Corrupt checksum in Wrap token)]]
	at com.sun.jndi.ldap.sasl.LdapSasl.saslBind(Unknown Source)
	at com.sun.jndi.ldap.LdapClient.authenticate(Unknown Source)
	at com.sun.jndi.ldap.LdapCtx.connect(Unknown Source)
	at com.sun.jndi.ldap.LdapCtx.<init>(Unknown Source)
	at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(Unknown Source)
	at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(Unknown Source)
	at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(Unknown Source)
	at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(Unknown Source)
	at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
	at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)
	at javax.naming.InitialContext.init(Unknown Source)
	at javax.naming.InitialContext.<init>(Unknown Source)
	at javax.naming.directory.InitialDirContext.<init>(Unknown Source)
	at vsjtest.JRETalkToServerAction.run(JREClient.java:60)
	at java.security.AccessController.doPrivileged(Native Method)
	at javax.security.auth.Subject.doAs(Unknown Source)
	at vsjtest.JREClient.performLogin(JREClient.java:100)
	at vsjtest.JREClient.main(JREClient.java:120)
Caused by: javax.security.sasl.SaslException: Final handshake failed [Caused by GSSException: Token had invalid integrity check (Mechanism level: Corrupt checksum in Wrap token)]
	at com.sun.security.sasl.gsskerb.GssKrb5Client.doFinalHandshake(Unknown Source)
	at com.sun.security.sasl.gsskerb.GssKrb5Client.evaluateChallenge(Unknown Source)
	... 18 more
Caused by: GSSException: Token had invalid integrity check (Mechanism level: Corrupt checksum in Wrap token)
	at sun.security.jgss.krb5.WrapToken_v2.getDataFromBuffer(Unknown Source)
	at sun.security.jgss.krb5.WrapToken_v2.getData(Unknown Source)
	at sun.security.jgss.krb5.WrapToken_v2.getData(Unknown Source)
	at sun.security.jgss.krb5.Krb5Context.unwrap(Unknown Source)
	at sun.security.jgss.GSSContextImpl.unwrap(Unknown Source)
	... 20 more


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
UsernamePasswordHandler.java
/**
 * An implemeentation of the JAAS CallbackHandler interface that handles
 * NameCallbacks and PasswordCallbac
 */
public class UsernamePasswordHandler implements CallbackHandler {

  private String username;
  private char[] password;

  public UsernamePasswordHandler(String username, char[] password) {
    this.username = username;
    this.password = password;
  }

  public void handle(Callback[] callbacks) throws IOException,
      UnsupportedCallbackException {
    for (int i = 0; i < callbacks.length; i++) {
      Callback c = callbacks[i];
      if( c instanceof NameCallback ) {
        NameCallback nc = (NameCallback) c;
        nc.setName(username);
      }
      else if( c instanceof PasswordCallback ) {
        PasswordCallback pc = (PasswordCallback) c;
        pc.setPassword(password);
      }
      else {
        throw new UnsupportedCallbackException(c, "Unrecognized Callback");
      }
    }
  }
}


JREClient.java:

/**
 * This class provides most of the credential gathering and processing inside a
 * privileged action environment.
 */
class JRETalkToServerAction implements PrivilegedExceptionAction {

  private String serverUrl;
  private Subject subject;

  /**
   * Create a TalkToServerAction.
   *
   * @param serverAddress
   *          the URL of the server we are contacting.
   * @param subject
   */
  public JRETalkToServerAction(String serverAddress, Subject subject) {
    this.serverUrl = serverAddress;
    this.subject = subject;
  }

  /**
   * This method performs the SPNEGO authenthentication with server whose URL is
   * given. After authentication, the method will get an InputStream for server
   * data.
   *
   * @return the InputStream for the server.
   */
  public Object run() throws GSSException, IOException {

    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, serverUrl);
    env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
    env.put("javax.security.sasl.qop", "auth-conf");
    env.put("javax.security.sasl.server.authentication", "true");
    try {
      DirContext ctx = new InitialDirContext(env);

      String[] justOneAttr = { "name" };

      Attributes result = ctx.getAttributes("CN=Users,DC=sso,DC=test,DC=de", justOneAttr);
      System.out.println(result.toString());
      String userName = "CN=thomas,CN=Users,DC=sso,DC=test,DC=de";
      // String newPassword = "##Test!!!1";
      String newPassword = "Service##";
      // Replace the "unicdodePwd" attribute with a new value
      // Password must be both Unicode and a quoted string
      String newQuotedPassword = "\"" + newPassword + "\"";
      byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
      ModificationItem[] mods = new ModificationItem[1];
      mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));

      ctx.modifyAttributes(userName, mods);

    } catch (NamingException e) {
      e.printStackTrace();
    }
    return null;
  }
}

public class JREClient {

  static void outputProviders() {
    System.out.println("Security Providers -");
    Provider[] providers = Security.getProviders();
    for (int i = 0; i < providers.length; i++) {
      System.out.println(providers[i]);
    }
  }

  static void performLogin(LoginContext lc, String serverAddress) throws LoginException, PrivilegedActionException, IOException {
    lc.login();
    Subject subject = lc.getSubject();

    // Perform the authentication as the generated subject
    Subject.doAs(subject, new JRETalkToServerAction(serverAddress, subject));

  }

  public static void main(String[] args) throws Exception {
    if (args.length < 3) {
      System.out.println("Usage: java fatclient.UsernamePasswordClient [url] [username] [password]");
      System.exit(0);
    }

    String serverAddress = args[0];
    String username = args[1];
    String password = args[2];

   

    outputProviders();

    LoginContext lc = new LoginContext("JREUsernamePassword", new UsernamePasswordHandler(username, password.toCharArray()));

    performLogin(lc, serverAddress);
  }

}

jaas.config:

/*
 Copyright 2007 Quest Software, Inc.

 ALL RIGHTS RESERVED.

 Permission to use, copy, modify, and distribute this software and its
 documentation is hereby granted for internal and non-commercial use only.

 Quest reserves all other rights.  No other use of the software, documentation,
 or modifications thereto is permitted without prior written consent from
 Quest Software, Inc.
 
 This software is being provided "AS IS" without warranty of any kind and without
 any particular purpose.  In no event shall Quest Software,  Inc be liable for
 damage of any kind arising out of or in connection with the use or performance
 of this software.
 */


JREUsernamePassword {
 com.sun.security.auth.module.Krb5LoginModule sufficient debug=true;
};


---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
- Use  SSL to get an encrypted LDAP Connection
- Use the Kerberos Implementation from Vintela