I am having a problem that may seem to indicate an issue between java 1.4 and 1.5 communication. I am using the GSS-API as a means of communication between a client and server application. This problem only occurs when the server is being run using java 1.5 and I connect from a client using java 1.4 or vice versa. I'm not sure how to go about configuring to use the DES encryption type as you had mentioned. I created a special SecurityContext class which both the client and server use and simplifies the login/encryption/decryption process for the client and server. Essentially, on startup, the server logins into the SecurityContext object (using its login function) as a Kerberos principal server. On startup, the client logins into the SecurityContext object as a Kerberos principal user. The client then using SecurityContext's initSecContext to initialize a GSSContext to the Kerberos principal server, which the server later accepts using the
acceptSecContext method. Finally, wrap and unwrap are used to encrypt/decrypt messages passed back and forth. Here is the stack trace of the exception I am getting: GSSException: Failure unspecified at GSS-API level (Mechanism level: Could not use DES Cipher - Output buffer must be (at least) 16 bytes long) at sun.security.jgss.krb5.Message Token.getDesCbcChecksum(Messag eToken.java:530) at sun.security.jgss.krb5.Message Token.getChecksum(MessageToken .java:453) at sun.security.jgss.krb5.Message Token.verifySignAndSeqNumber(M essageToken.java:325) at sun.security.jgss.krb5.WrapTok en.getDataFromBuffer(WrapToken .java:269) at sun.security.jgss.krb5.WrapTok en.getData(WrapToken.java:198) at sun.security.jgss.krb5.WrapTok en.getData(WrapToken.java:171) at sun.security.jgss.krb5.Krb5Con text.unwrap(Krb5Context.java:8 76) at sun.security.jgss.GSSContextIm pl.unwrap(GSSContextImpl.java: 362) at edu.bu.rcs.objects.security.Se curityContext.unwrap(SecurityC ontext.java:186) at edu.bu.rcs.legend.client.Clien t.issueCommand(Client.java:184 ) at edu.bu.rcs.legend.client.Clien t.issueCommand(Client.java:153 ) at edu.bu.rcs.legend.client.Clien t$1.run(Client.java:289) at java.security.AccessController .doPrivileged(Native Method) at javax.security.auth.Subject.do AsPrivileged(Subject.java:437) at edu.bu.rcs.objects.security.Se curityContext.doAsPrivileged(S ecurityContext.java:334) at edu.bu.rcs.legend.client.Clien t.login(Client.java:281) at edu.bu.rcs.legend.gui.main.Mai nWindowPanel$3.run(MainWindowP anel.java:381) Both client and server have the following code in the main functions: URL config = Client.class.getResource("jaas .conf"); System.setProperty("java.secur ity.auth.login.config", config .toExternalForm()); String krb5Realm = "bu.edu"; System.setProperty("java.secur ity.krb5.realm", krb5Realm); String krb5Kdc = "kerberos1.bu.edu"; System.setProperty("java.secur ity.krb5.kdc", krb5Kdc); I did this so I wouldn't have to pass this information as vm arguments. The client jaas file looks like: Client { com.sun.security.auth.module.K rb5LoginModule required; }; The server jaas file looks like: Server { com.sun.security.auth.module.K rb5LoginModule required storeKey=true; }; public class SecurityContext implements CallbackHandler { protected GSSContext context = null; protected LoginContext lc = null; protected String service = null; protected String username; protected char[] password; public SecurityContext() { } public void setServiceName(String service) { this.service = service; } public boolean login(String loginContext, String username, char[] password) { this.username = username; this.password = password; lc = null; try { lc = new LoginContext(loginContext, this); } catch (LoginException le) { System.err .println("Cannot create LoginContext. " + le.getMessage()); System.exit(-1); } catch (SecurityException se) { System.err .println("Cannot create LoginContext. " + se.getMessage()); System.exit(-1); } int i; for (i = 0; i < 3; i++) { try { lc.login(); return true; } catch (AccountExpiredException aee) { System.err.println("Your account has expired. " + "Please notify your administrator."); System.exit(-1); } catch (CredentialExpiredException cee) { System.err.println("Your credentials have expired."); System.exit(-1); } catch (FailedLoginException fle) { System.err.println("Authentica tion Failed"); try { Thread.sleep(3000); } catch (Exception e) { // ignore } } catch (Exception e) { //System.err.println("Unexpect ed Exception - unable to continue"); //e.printStackTrace(); return false; } } // did they fail three times? if (i == 3) { System.err.println("Sorry"); } return false; } public byte[] acceptSecContext(byte[] token) { try { GSSManager manager = GSSManager.getInstance(); context = manager.createContext((GSSCred ential) null); while (!context.isEstablished()) { /* * Create a GSSContext to receive the incoming request from the * client. Use null for the server credentials passed in. This * tells the underlying mechanism to use whatever credentials it * has available that can be used to accept this connection. */ token = context.acceptSecContext(token , 0, token.length); if (token != null) return token; } } catch (GSSException e) { e.printStackTrace(); } return token; } public synchronized byte[] wrap(Object object) { /* * The first MessageProp argument is 0 to request the default * Quality-of-Protection. The second argument is true to request privacy * (encryption of the message). */ MessageProp prop = new MessageProp(0, true); /* * Encrypt the data and send it across. Integrity protection is always * applied, irrespective of confidentiality (i.e., encryption). You can * use the same token (byte array) as that used when establishing the * context. */ byte[] token = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos; try { oos = new ObjectOutputStream(baos); oos.writeObject(object); byte[] messageBytes = baos.toByteArray(); token = context.wrap(messageBytes, 0, messageBytes.length, prop); oos.close(); baos.close(); } catch (IOException e) { e.printStackTrace(); } catch (GSSException e) { e.printStackTrace(); } return token; } public synchronized Object unwrap(byte[] token) { MessageProp prop = new MessageProp(0, true); Object object = null; try { token = context.unwrap(token, 0, token.length, prop); ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream(token)); object = ois.readObject(); ois.close(); } catch (GSSException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return object; } public byte[] initSecContext(byte[] token) { try { if (context == null) { /* * This Oid is used to represent the Kerberos version 5 GSS-API * mechanism. It is defined in RFC 1964. We will use this Oid * whenever we need to indicate to the GSS-API that it must use * Kerberos for some purpose. */ Oid krb5Oid = new Oid("1.2.840.113554.1.2.2"); GSSManager manager = GSSManager.getInstance(); /* * Create a GSSName out of the server's name. The null indicates * that this application does not wish to make any claims about * the syntax of this name and that the underlying mechanism * should try to parse it as per whatever default syntax it * chooses. */ GSSName serverName = manager.createName(service, null); /* * Create a GSSContext for mutual authentication with the * server. - serverName is the GSSName that represents the * server. - krb5Oid is the Oid that represents the mechanism to * use. The client chooses the mechanism to use. - null is * passed in for client credentials - DEFAULT_LIFETIME lets the * mechanism decide how long the context can remain valid. Note: * Passing in null for the credentials asks GSS-API to use the * default credentials. This means that the mechanism will look * among the credentials stored in the current Subject to find * the right kind of credentials that it needs. */ context = manager.createContext(serverNa me, krb5Oid, null, GSSContext.DEFAULT_LIFETIME); // Set the desired optional features on the context. The client // chooses these options. context.requestMutualAuth(true ); // Mutual authentication //context.requestConf(true); // Will use confidentiality later //context.requestInteg(true); // Will use integrity later } // token is ignored on the first call if (token == null) token = new byte[0]; token = context.initSecContext(token, 0, token.length); } catch (GSSException e) { e.printStackTrace(); } return token; } public void dispose() { if (context != null) try { context.dispose(); } catch (GSSException e) { e.printStackTrace(); } } public void logout() { if (lc != null) { try { lc.logout(); } catch (LoginException e) { e.printStackTrace(); } lc = null; } } public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { if (callbacks[i] instanceof TextOutputCallback) { // display the message according to the specified type TextOutputCallback toc = (TextOutputCallback) callbacks[i]; switch (toc.getMessageType()) { case TextOutputCallback.INFORMATION : break; case TextOutputCallback.ERROR: break; case TextOutputCallback.WARNING: break; default: throw new IOException("Unsupported message type: " + toc.getMessageType()); } } else if (callbacks[i] instanceof NameCallback) { // prompt the user for a username NameCallback nc = (NameCallback) callbacks[i]; nc.setName(username); } else if (callbacks[i] instanceof PasswordCallback) { // prompt the user for sensitive information PasswordCallback pc = (PasswordCallback) callbacks[i]; pc.setPassword(password); } else { throw new UnsupportedCallbackException(c allbacks[i], "Unrecognized Callback"); } } } public Subject getSubject() { if (lc != null) return lc.getSubject(); return null; } public Object doAsPrivileged(PrivilegedActio n action) { if (lc != null) return Subject.doAsPrivileged(lc.getS ubject(), action, null); return null; } public boolean isEstablished() { if (context == null) return false; return context.isEstablished(); } public String getUsername() { try { GSSName name = context.getSrcName(); if (name != null) return name.toString(); } catch (GSSException e) { } return null; } } ________________________________________________ Kerberos mailing list Kerberos@mit.edu https://mailman.mit.edu/mailman/listinfo/kerberos