GSSException: Failure unspecified at GSS-API level (Mechanism level: Could not use DES Cipher - Output buffer must be (at least) 16 bytes long)

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

GSSException: Failure unspecified at GSS-API level (Mechanism level: Could not use DES Cipher - Output buffer must be (at least) 16 bytes long)

hunterae
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. The server
performs all of its encryption as a Kerberos principal service. The
client logins into Kerberos as a standard Kerberos user and initializes
a SecurityContext with the server's Kerberos principal service. All
messages passed back and forth between the client and server are then
encrypted using wrap and unwrap. This all works fine if both the client
and server are run using java 1.4 or 1.5. However if one is java 1.4
and one is java 1.5, I get the above exception. I need to get around
this in some way as I will not be sure which version of java the
various clients will be using. Any ideas what may be causing this and
how to fix it?

________________________________________________
Kerberos mailing list           [hidden email]
https://mailman.mit.edu/mailman/listinfo/kerberos
Reply | Threaded
Open this post in threaded view
|

Re: GSSException: Failure unspecified at GSS-API level (Mechanismbytes long)

Seema Malkani
Such an error is returned if DES computation on the checksum failed.

Have you configured to use the DES encryption type ? Is this error
returned when using J2SE 1.4 or J2SE 1.5 ? Can you provide more details
on this.

Seema

hunterae wrote:

>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. The server
>performs all of its encryption as a Kerberos principal service. The
>client logins into Kerberos as a standard Kerberos user and initializes
>a SecurityContext with the server's Kerberos principal service. All
>messages passed back and forth between the client and server are then
>encrypted using wrap and unwrap. This all works fine if both the client
>and server are run using java 1.4 or 1.5. However if one is java 1.4
>and one is java 1.5, I get the above exception. I need to get around
>this in some way as I will not be sure which version of java the
>various clients will be using. Any ideas what may be causing this and
>how to fix it?
>
>________________________________________________
>Kerberos mailing list           [hidden email]
>https://mailman.mit.edu/mailman/listinfo/kerberos
>  
>


________________________________________________
Kerberos mailing list           [hidden email]
https://mailman.mit.edu/mailman/listinfo/kerberos
Reply | Threaded
Open this post in threaded view
|

Re: GSSException: Failure unspecified at GSS-API level (Mechanismbytes long)

hunterae
In reply to this post by hunterae
Hey, thanks for the response. I'm sorry it's taken me so long to get
back to you but I sort of sidelined this problem for a little while.
Here is the stack trace of the error I'm receiving:

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.MessageToken.getDesCbcChecksum(MessageToken.java:530)
    at
sun.security.jgss.krb5.MessageToken.getChecksum(MessageToken.java:453)
    at
sun.security.jgss.krb5.MessageToken.verifySignAndSeqNumber(MessageToken.java:325)
    at
sun.security.jgss.krb5.WrapToken.getDataFromBuffer(WrapToken.java:269)
    at sun.security.jgss.krb5.WrapToken.getData(WrapToken.java:198)
    at sun.security.jgss.krb5.WrapToken.getData(WrapToken.java:171)
    at sun.security.jgss.krb5.Krb5Context.unwrap(Krb5Context.java:876)
    at sun.security.jgss.GSSContextImpl.unwrap(GSSContextImpl.java:362)
    at
edu.bu.rcs.objects.security.SecurityContext.unwrap(SecurityContext.java:186)
    at edu.bu.rcs.legend.client.Client.issueCommand(Client.java:184)
    at edu.bu.rcs.legend.client.Client.issueCommand(Client.java:153)
    at edu.bu.rcs.legend.client.Client$1.run(Client.java:289)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:437)
    at
edu.bu.rcs.objects.security.SecurityContext.doAsPrivileged(SecurityContext.java:334)
    at edu.bu.rcs.legend.client.Client.login(Client.java:281)
    at
edu.bu.rcs.legend.gui.main.MainWindowPanel$3.run(MainWindowPanel.java:381)

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.

Both client and server have the following code in the main functions:
        URL config = Client.class.getResource("jaas.conf");
        System.setProperty("java.security.auth.login.config", config
                .toExternalForm());

        String krb5Realm = "bu.edu";
        System.setProperty("java.security.krb5.realm", krb5Realm);

        String krb5Kdc = "kerberos1.bu.edu";
        System.setProperty("java.security.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.Krb5LoginModule required;
};
The server jaas file looks like:
Server {
   com.sun.security.auth.module.Krb5LoginModule 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("Authentication Failed");
                try {
                    Thread.sleep(3000);
                } catch (Exception e) {
                    // ignore
                }

            } catch (Exception e) {

                //System.err.println("Unexpected 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((GSSCredential) 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(serverName, 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(callbacks[i],
                        "Unrecognized Callback");
            }
        }
    }

    public Subject getSubject() {
        if (lc != null)
            return lc.getSubject();

        return null;
    }

    public Object doAsPrivileged(PrivilegedAction action) {
        if (lc != null)
            return Subject.doAsPrivileged(lc.getSubject(), 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;
    }

}

I think that should hopefully be all the information you will need.
Thanks in advance.
Andrew

________________________________________________
Kerberos mailing list           [hidden email]
https://mailman.mit.edu/mailman/listinfo/kerberos