You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by co...@apache.org on 2017/07/21 15:03:30 UTC

[13/18] directory-kerby git commit: Refactoring the package and structure

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV2.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV2.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV2.java
new file mode 100644
index 0000000..5220900
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV2.java
@@ -0,0 +1,282 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.gss.impl;
+
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.MessageProp;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.MessageDigest;
+
+/**
+ * This class implements the token formats defined in RFC 4121.
+ */
+abstract class GssTokenV2 extends GssTokenBase {
+    public static final int CONFOUNDER_SIZE = 16;
+    public static final int TOKEN_HEADER_SIZE = 16;
+    private static final int OFFSET_EC = 4;
+    private static final int OFFSET_RRC = 6;
+
+    // context states
+    private boolean isInitiator = true;
+    private boolean acceptorSubKey = false;
+    private boolean confState = true;
+    private int sequenceNumber;
+
+    // token data
+    protected int tokenType;
+    private byte[] header = new byte[TOKEN_HEADER_SIZE];
+    protected byte[] tokenData;
+
+    protected byte[] checkSum;
+    private int ec;
+    private int rrc;
+
+    static final int KG_USAGE_ACCEPTOR_SEAL = 22;
+    static final int KG_USAGE_ACCEPTOR_SIGN = 23;
+    static final int KG_USAGE_INITIATOR_SEAL = 24;
+    static final int KG_USAGE_INITIATOR_SIGN = 25;
+    private int keyUsage;
+
+    private static final int FLAG_SENT_BY_ACCEPTOR = 1;
+    private static final int FLAG_SEALED = 2;
+    private static final int FLAG_ACCEPTOR_SUBKEY = 4;
+
+    protected GssEncryptor encryptor;
+
+
+    // Create a new token
+    GssTokenV2(int tokenType, GssContext context) throws GSSException {
+        initialize(tokenType, context, false);
+    }
+
+    private void initialize(int tokenType, GssContext context, boolean reconstruct) throws GSSException {
+        this.tokenType = tokenType;
+        this.isInitiator = context.isInitiator();
+        this.acceptorSubKey = context.getKeyComesFrom() == GssContext.ACCEPTOR_SUBKEY;
+        this.confState = context.getConfState();
+
+        boolean usageFlag = reconstruct ? !this.isInitiator : this.isInitiator;
+        if (tokenType == TOKEN_WRAP_V2) {
+            keyUsage = usageFlag ? KG_USAGE_INITIATOR_SEAL : KG_USAGE_ACCEPTOR_SEAL;
+        } else if (tokenType == TOKEN_MIC_V2) {
+            keyUsage = usageFlag ? KG_USAGE_INITIATOR_SIGN : KG_USAGE_ACCEPTOR_SIGN;
+        }
+
+        encryptor = context.getGssEncryptor();
+
+        if (!reconstruct) {
+            this.sequenceNumber = context.incMySequenceNumber();
+        }
+    }
+
+    // Reconstruct token from bytes received
+    GssTokenV2(int tokenType, GssContext context,
+               MessageProp prop, byte[] token, int offset, int len) throws GSSException {
+        this(tokenType, context, prop, new ByteArrayInputStream(token, offset, len));
+    }
+
+    // Reconstruct token from input stream
+    GssTokenV2(int tokenType, GssContext context,
+               MessageProp prop, InputStream is) throws GSSException {
+        initialize(tokenType, context, true);
+
+        if (!confState) {
+            prop.setPrivacy(false);
+        }
+
+        reconstructTokenHeader(prop, is);
+
+        int minSize;
+        if (tokenType == TOKEN_WRAP_V2 && prop.getPrivacy()) {
+            minSize = CONFOUNDER_SIZE + TOKEN_HEADER_SIZE + encryptor.getCheckSumSize();
+        } else {
+            minSize = encryptor.getCheckSumSize();
+        }
+
+        try {
+            int tokenLen = is.available();
+
+            if (tokenType == TOKEN_MIC_V2) {
+                tokenLen = minSize;
+                tokenData = new byte[tokenLen];
+                is.read(tokenData);
+            } else {
+                if (tokenLen >= minSize) {
+                    tokenData = new byte[tokenLen];
+                    is.read(tokenData);
+                } else {
+                    throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token length");
+                }
+            }
+
+            if (tokenType == TOKEN_WRAP_V2) {
+                tokenData = rotate(tokenData);
+            }
+
+            if (tokenType == TOKEN_MIC_V2
+                    || tokenType == TOKEN_WRAP_V2 && !prop.getPrivacy()) {
+                int checksumLen = encryptor.getCheckSumSize();
+
+                if (tokenType != TOKEN_MIC_V2 && checksumLen != ec) {
+                    throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid EC");
+                }
+
+                checkSum = new byte[checksumLen];
+                System.arraycopy(tokenData, tokenLen - checksumLen, checkSum, 0, checksumLen);
+            }
+        } catch (IOException e) {
+            throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token");
+        }
+    }
+
+    private byte[] rotate(byte[] data) {
+        int dataLen = data.length;
+        if (rrc % dataLen != 0) {
+            rrc = rrc % dataLen;
+            byte[] newBytes = new byte[dataLen];
+
+            System.arraycopy(data, rrc, newBytes, 0, dataLen - rrc);
+            System.arraycopy(data, 0, newBytes, dataLen - rrc, rrc);
+            data = newBytes;
+        }
+        return data;
+    }
+
+    public int getKeyUsage() {
+        return keyUsage;
+    }
+
+    public void generateCheckSum(MessageProp prop, byte[] data, int offset, int len) throws GSSException {
+        // generate token header
+        createTokenHeader(prop.getPrivacy());
+
+        if (tokenType == TOKEN_MIC_V2
+                || !prop.getPrivacy() && tokenType == TOKEN_WRAP_V2) {
+            checkSum = getCheckSum(data, offset, len);
+        }
+
+        if (!prop.getPrivacy() && tokenType == TOKEN_WRAP_V2) {
+            header[4] = (byte) (checkSum.length >>> 8);
+            header[5] = (byte) (checkSum.length & 0xFF);
+        }
+    }
+
+    public byte[] getCheckSum(byte[] data, int offset, int len) throws GSSException {
+        int confidentialFlag = header[2] & 2;
+        if (confidentialFlag == 0 && tokenType == TOKEN_WRAP_V2) {
+            header[4] = 0;
+            header[5] = 0;
+            header[6] = 0;
+            header[7] = 0;
+        }
+        return encryptor.calculateCheckSum(header, data, offset, len, keyUsage);
+    }
+
+    public boolean verifyCheckSum(byte[] data, int offset, int len) throws GSSException {
+        byte[] dataCheckSum = getCheckSum(data, offset, len);
+        return MessageDigest.isEqual(checkSum, dataCheckSum);
+    }
+
+    // Create a new header
+    private void createTokenHeader(boolean privacy) {
+        header[0] = (byte) (tokenType >>> 8);
+        header[1] = (byte) tokenType;
+
+        int flags = isInitiator ? 0 : FLAG_SENT_BY_ACCEPTOR;
+        flags |= privacy && tokenType != TOKEN_MIC_V2 ? FLAG_SEALED : 0;
+        flags |= acceptorSubKey ? FLAG_ACCEPTOR_SUBKEY : 0;
+
+        header[2] = (byte) (flags & 0xFF);
+        header[3] = (byte) 0xFF;
+
+        if (tokenType == TOKEN_WRAP_V2) {
+            header[4] = (byte) 0;
+            header[5] = (byte) 0;
+            header[6] = (byte) 0;
+            header[7] = (byte) 0;
+        } else if (tokenType == TOKEN_MIC_V2) {
+            header[4] = (byte) 0xFF;
+            header[5] = (byte) 0xFF;
+            header[6] = (byte) 0xFF;
+            header[7] = (byte) 0xFF;
+        }
+        writeBigEndian(header, 12, sequenceNumber);
+    }
+
+    // Reconstruct a token header
+    private void reconstructTokenHeader(MessageProp prop, InputStream is) throws GSSException {
+        try {
+            if (is.read(header, 0, header.length) != header.length) {
+                throw new GSSException(GSSException.FAILURE, -1, "Token header can not be read");
+            }
+            int tokenIDRecv = (((int) header[0]) << 8) + header[1];
+            if (tokenIDRecv != tokenType) {
+                throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
+                        "Token ID should be " + tokenType + " instead of " + tokenIDRecv);
+            }
+
+            int senderFlag = isInitiator ? FLAG_SENT_BY_ACCEPTOR : 0;
+            int senderFlagRecv = header[2] & FLAG_SENT_BY_ACCEPTOR;
+            if (senderFlagRecv != senderFlag) {
+                throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid acceptor flag");
+            }
+
+            int confFlagRecv = header[2] & FLAG_SEALED;
+            if (confFlagRecv == FLAG_SEALED && tokenType == TOKEN_WRAP_V2) {
+                prop.setPrivacy(true);
+            } else {
+                prop.setPrivacy(false);
+            }
+
+            if (tokenType == TOKEN_WRAP_V2) {
+                if (header[3] != (byte) 0xFF) {
+                    throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token filler");
+                }
+
+                ec = readBigEndian(header, OFFSET_EC, 2);
+                rrc = readBigEndian(header, OFFSET_RRC, 2);
+            } else if (tokenType == TOKEN_MIC_V2) {
+                for (int i = 3; i < 8; i++) {
+                    if ((header[i] & 0xFF) != 0xFF) {
+                        throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token filler");
+                    }
+                }
+            }
+
+            prop.setQOP(0);
+            sequenceNumber = readBigEndian(header, 0, 8);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Phrase token header failed");
+        }
+    }
+
+    public int encodeHeader(byte[] buf, int offset) {
+        System.arraycopy(header, 0, buf, offset, TOKEN_HEADER_SIZE);
+        return TOKEN_HEADER_SIZE;
+    }
+
+    public void encodeHeader(OutputStream os) throws IOException {
+        os.write(header);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java
new file mode 100644
index 0000000..372abcb
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java
@@ -0,0 +1,386 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.gss.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.client.KrbClientBase;
+import org.apache.kerby.kerberos.kerb.type.KerberosTime;
+import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationData;
+import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationDataEntry;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.HostAddress;
+import org.apache.kerby.kerberos.kerb.type.base.HostAddresses;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.apache.kerby.kerberos.kerb.type.kdc.EncAsRepPart;
+import org.apache.kerby.kerberos.kerb.type.kdc.EncKdcRepPart;
+import org.apache.kerby.kerberos.kerb.type.kdc.EncTgsRepPart;
+import org.apache.kerby.kerberos.kerb.type.ticket.KrbTicket;
+import org.apache.kerby.kerberos.kerb.type.ticket.SgtTicket;
+import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.apache.kerby.kerberos.kerb.type.ticket.Ticket;
+import org.apache.kerby.kerberos.kerb.type.ticket.TicketFlags;
+import org.ietf.jgss.GSSException;
+import sun.security.jgss.GSSCaller;
+
+import javax.crypto.SecretKey;
+import javax.security.auth.kerberos.KerberosKey;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KerberosTicket;
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Some utility functions to translate types between GSS and Kerby
+ */
+public class GssUtil {
+    private static final int KERBEROS_TICKET_NUM_FLAGS = 32;  // KerberosTicket.NUM_LENGTH
+
+    /**
+     * Construct TgtTicket from info contained in KerberosTicket
+     * @param kerberosTicket
+     * @return
+     * @throws GSSException
+     */
+    public static TgtTicket getTgtTicketFromKerberosTicket(KerberosTicket kerberosTicket) throws GSSException {
+        String clientName = kerberosTicket.getClient().getName();
+        PrincipalName clientPrincipal = new PrincipalName(clientName);
+
+        byte[] asn1Encoded = kerberosTicket.getEncoded();
+        Ticket ticket = getTicketFromAsn1Encoded(asn1Encoded);
+
+        EncAsRepPart encAsRepPart = new EncAsRepPart();
+        fillEncKdcRepPart(encAsRepPart, kerberosTicket);
+
+        TgtTicket tgt = new TgtTicket(ticket, encAsRepPart, clientPrincipal);
+        return tgt;
+    }
+
+    /**
+     *  Init encKdcRepPart members with info from kerberosTicket
+     * @param encKdcRepPart
+     * @param kerberosTicket
+     */
+    public static void fillEncKdcRepPart(EncKdcRepPart encKdcRepPart, KerberosTicket kerberosTicket) {
+        String clientName = kerberosTicket.getClient().getName();
+        PrincipalName clientPrincipal = new PrincipalName(clientName);
+
+        SecretKey secretKey = kerberosTicket.getSessionKey();
+        int keyType = kerberosTicket.getSessionKeyType();
+        EncryptionKey key = new EncryptionKey(keyType, secretKey.getEncoded());
+        encKdcRepPart.setKey(key);
+
+        encKdcRepPart.setSname(clientPrincipal);
+        Date authTimeDate = kerberosTicket.getAuthTime();
+        if (authTimeDate != null) {
+            encKdcRepPart.setAuthTime(new KerberosTime(authTimeDate.getTime()));
+        }
+        Date startTimeDate = kerberosTicket.getStartTime();
+        if (startTimeDate != null) {
+            encKdcRepPart.setStartTime(new KerberosTime(startTimeDate.getTime()));
+        }
+        KerberosTime endTime = new KerberosTime(kerberosTicket.getEndTime().getTime());
+        encKdcRepPart.setEndTime(endTime);
+
+
+        InetAddress[] clientAddresses = kerberosTicket.getClientAddresses();
+        HostAddresses hostAddresses = null;
+        if (clientAddresses != null) {
+            hostAddresses = new HostAddresses();
+            for (InetAddress iAddr : clientAddresses) {
+                hostAddresses.add(new HostAddress(iAddr));
+            }
+        }
+        encKdcRepPart.setCaddr(hostAddresses);
+
+        boolean[] tf = kerberosTicket.getFlags();
+        TicketFlags ticketFlags = getTicketFlags(tf);
+        encKdcRepPart.setFlags(ticketFlags);
+
+
+        /* encKdcRepPart.setKeyExpiration();
+        encKdcRepPart.setLastReq();
+        encKdcRepPart.setNonce(); */
+
+        Date renewTillDate = kerberosTicket.getRenewTill();
+        KerberosTime renewTill = renewTillDate == null ? null : new KerberosTime(renewTillDate.getTime());
+        encKdcRepPart.setRenewTill(renewTill);
+
+        String serverRealm = kerberosTicket.getServer().getRealm();
+        encKdcRepPart.setSrealm(serverRealm);
+    }
+
+    /**
+     * Generate TicketFlags instance from flags
+     * @param flags each item in flags identifies an bit setted or not
+     * @return
+     */
+    public static TicketFlags getTicketFlags(boolean[] flags) {
+        if (flags == null || flags.length != KERBEROS_TICKET_NUM_FLAGS) {
+            return null;
+        }
+        int value = 0;
+        for (boolean flag : flags) {
+            value = (value << 1) + (flag ? 1 : 0);
+        }
+        return new TicketFlags(value);
+    }
+
+    /**
+     * Decode each flag in ticketFlags into an boolean array
+     * @param ticketFlags
+     * @return
+     */
+    public static boolean[] ticketFlagsToBooleans(TicketFlags ticketFlags) {
+        boolean[] ret = new boolean[KERBEROS_TICKET_NUM_FLAGS];
+        int value = ticketFlags.getFlags();
+        for (int i = 0; i < KERBEROS_TICKET_NUM_FLAGS; i++) {
+            ret[KERBEROS_TICKET_NUM_FLAGS - i - 1] = (value & 0x1) != 0;
+            value = value >> 1;
+        }
+        return ret;
+    }
+
+    /**
+     * Construct a Ticket from bytes encoded by Asn1
+     * @param encoded
+     * @return
+     * @throws GSSException
+     */
+    public static Ticket getTicketFromAsn1Encoded(byte[] encoded) throws GSSException {
+        Ticket ticket = new Ticket();
+        ByteBuffer byteBuffer = ByteBuffer.wrap(encoded);
+        try {
+            ticket.decode(byteBuffer);
+            return ticket;
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
+        }
+    }
+
+    /**
+     * Scan current context for SgtTicket
+     * @param client
+     * @param service
+     * @return
+     */
+    public static SgtTicket getSgtCredentialFromContext(GSSCaller caller, String client, String service)
+            throws GSSException {
+        KerberosTicket ticket = CredUtils.getKerberosTicketFromContext(caller, client, service);
+        return getSgtTicketFromKerberosTicket(ticket);
+    }
+
+    /**
+     * Construct a SgtTicket from KerberosTicket
+     * @param kerberosTicket
+     * @return
+     * @throws GSSException
+     */
+    public static SgtTicket getSgtTicketFromKerberosTicket(KerberosTicket kerberosTicket) throws GSSException {
+        if (kerberosTicket == null) {
+            return null;
+        }
+
+        Ticket ticket = getTicketFromAsn1Encoded(kerberosTicket.getEncoded());
+
+        EncTgsRepPart encTgsRepPart = new EncTgsRepPart();
+        fillEncKdcRepPart(encTgsRepPart, kerberosTicket);
+
+        SgtTicket sgt = new SgtTicket(ticket, encTgsRepPart);
+        return sgt;
+    }
+
+    /**
+     *  Apply SgtTicket by sending TGS_REQ to KDC
+     * @param ticket
+     * @param service
+     * @return
+     */
+    public static SgtTicket applySgtCredential(KerberosTicket ticket, String service) throws GSSException {
+        TgtTicket tgt = getTgtTicketFromKerberosTicket(ticket);
+        return applySgtCredential(tgt, service);
+    }
+
+    public static SgtTicket applySgtCredential(TgtTicket tgt, String server) throws GSSException {
+        KrbClientBase client = getKrbClient();
+
+        SgtTicket sgt = null;
+        try {
+            client.init();
+            sgt = client.requestSgt(tgt, server);
+            return sgt;
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
+        }
+    }
+
+    public static KerberosTicket convertKrbTicketToKerberosTicket(KrbTicket krbTicket, String clientName)
+            throws GSSException {
+        byte[] asn1Encoding;
+        try {
+            asn1Encoding = krbTicket.getTicket().encode();
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
+        }
+
+        byte[] sessionKey = krbTicket.getSessionKey().getKeyData();
+        int keyType = krbTicket.getSessionKey().getKeyType().getValue();
+
+        EncKdcRepPart encKdcRepPart = krbTicket.getEncKdcRepPart();
+        KerberosPrincipal client = new KerberosPrincipal(clientName);
+
+        PrincipalName serverPrinc = krbTicket.getTicket().getSname();
+        String serverName = serverPrinc.getName() + "@" + krbTicket.getTicket().getRealm();
+        KerberosPrincipal server = new KerberosPrincipal(serverName, serverPrinc.getNameType().getValue());
+
+        TicketFlags ticketFlags = encKdcRepPart.getFlags();
+        boolean[] flags = ticketFlagsToBooleans(ticketFlags);
+
+        Date authTime = new Date(encKdcRepPart.getAuthTime().getTime());
+        Date startTime = new Date(encKdcRepPart.getStartTime().getTime());
+        Date endTime = new Date(encKdcRepPart.getEndTime().getTime());
+        Date renewTill = new Date(encKdcRepPart.getRenewTill().getTime());
+
+        InetAddress[] clientAddresses = null;
+        List<HostAddress> hostAddresses = encKdcRepPart.getCaddr().getElements();
+        if (hostAddresses != null) {
+            int i = 0;
+            clientAddresses = new InetAddress[hostAddresses.size()];
+            for (HostAddress hostAddr : hostAddresses) {
+                try {
+                    InetAddress iAddr = InetAddress.getByAddress(hostAddr.getAddress());
+                    clientAddresses[i++] = iAddr;
+                } catch (UnknownHostException e) {
+                    throw new GSSException(GSSException.FAILURE, -1, "Bad client address");
+                }
+            }
+        }
+
+        KerberosTicket ticket = new KerberosTicket(
+                asn1Encoding,
+                client,
+                server,
+                sessionKey,
+                keyType,
+                flags,
+                authTime,
+                startTime,
+                endTime,
+                renewTill,
+                clientAddresses
+        );
+        return ticket;
+    }
+
+    public static KrbClientBase getKrbClient() {
+        KrbClientBase client;
+        try {
+            File confSpecified = new File(getSystemProperty("java.security.krb5.conf"));
+            if (confSpecified != null) {
+                client = new KrbClientBase(confSpecified);
+            } else {
+                client = new KrbClientBase();   // get configure file from environment variable or default path
+            }
+
+            return client;
+        } catch (KrbException e) {
+            return null;
+        }
+    }
+
+    public static EncryptionKey[] convertKerberosKeyToEncryptionKey(KerberosKey[] krbKeys) {
+        if (krbKeys == null) {
+            return null;
+        }
+        EncryptionKey[] keys = new EncryptionKey[krbKeys.length];
+        int i = 0;
+        for (KerberosKey krbKey : krbKeys) {
+            keys[i++] = new EncryptionKey(krbKey.getKeyType(), krbKey.getEncoded());
+        }
+        return keys;
+    }
+
+    /**
+     * Filter out an appropriate KerberosKey from krbKeys and generate a
+     * EncryptionKey accordingly
+     *
+     * @param krbKeys
+     * @param encType
+     * @param kvno
+     * @return
+     */
+    public static EncryptionKey getEncryptionKey(KerberosKey[] krbKeys, int encType, int kvno) {
+        if (krbKeys == null) {
+            return null;
+        }
+        for (KerberosKey krbKey : krbKeys) {
+            if (krbKey.getKeyType() == encType && krbKey.getVersionNumber() == kvno && !krbKey.isDestroyed()) {
+                return new EncryptionKey(krbKey.getKeyType(), krbKey.getEncoded());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get value of predefined system property
+     * @param name
+     * @return
+     */
+    private static String getSystemProperty(String name) {
+        if (name == null) {
+            return null;
+        }
+
+        final String propertyName = name;
+        try {
+            return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<String>() {
+                        public String run() {
+                            return System.getProperty(propertyName);
+                        }
+                    });
+        } catch (PrivilegedActionException e) {
+            return null;    // ignored
+        }
+    }
+
+    public static com.sun.security.jgss.AuthorizationDataEntry[]
+    kerbyAuthorizationDataToJgssAuthorizationDataEntries(AuthorizationData authData) {
+        if (authData == null) {
+            return null;
+        }
+        List<AuthorizationDataEntry> kerbyEntries = authData.getElements();
+        com.sun.security.jgss.AuthorizationDataEntry[] entries =
+                new com.sun.security.jgss.AuthorizationDataEntry[kerbyEntries.size()];
+        for (int i = 0; i < kerbyEntries.size(); i++) {
+            entries[i] = new com.sun.security.jgss.AuthorizationDataEntry(
+                    kerbyEntries.get(i).getAuthzType().getValue(),
+                    kerbyEntries.get(i).getAuthzData());
+        }
+        return entries;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV1.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV1.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV1.java
new file mode 100644
index 0000000..63baa6b
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV1.java
@@ -0,0 +1,92 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.gss.impl;
+
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.MessageProp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class MicTokenV1 extends GssTokenV1 {
+    public MicTokenV1(GssContext context,
+                       byte[] inMsg,
+                       int msgOffset,
+                       int msgLength,
+                       MessageProp messageProp) throws GSSException {
+        super(TOKEN_MIC_V1, context);
+        calcPrivacyInfo(messageProp, null, inMsg, msgOffset, msgLength, 0);
+    }
+
+    // This is called to construct MicToken from MicToken bytes
+    MicTokenV1(GssContext context,
+               MessageProp messageProp,
+               byte[] inToken,
+               int tokenOffset,
+               int tokenLength) throws GSSException {
+        super(TOKEN_MIC_V1, context, messageProp, inToken, tokenOffset, tokenLength);
+    }
+
+    public int getMic(byte[] outToken, int offset) throws GSSException, IOException {
+        byte[] data = getMic();
+        System.arraycopy(data, 0, outToken, offset, data.length);
+        return data.length;
+    }
+
+    /**
+     * Get bytes for this Mic token
+     * @return
+     */
+    public byte[] getMic() throws GSSException {
+        ByteArrayOutputStream os = new ByteArrayOutputStream(64);
+        getMic(os);
+        return os.toByteArray();
+    }
+
+    public void getMic(OutputStream os) throws GSSException {
+        try {
+            encodeHeader(os);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Error in output MicTokenV1 bytes:" + e.getMessage());
+        }
+    }
+
+    public void verify(InputStream is) throws GSSException {
+        byte[] data;
+        try {
+            data = new byte[is.available()];
+            is.read(data);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1,
+                    "Read plain data for MicTokenV1 error:" + e.getMessage());
+        }
+        verify(data, 0, data.length);
+    }
+
+    public void verify(byte[] data, int offset, int len) throws GSSException {
+        verifyToken(null, data, offset, len, 0);
+    }
+
+    protected int getTokenSizeWithoutGssHeader() {
+        return getTokenHeaderSize();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV2.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV2.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV2.java
new file mode 100644
index 0000000..2441823
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV2.java
@@ -0,0 +1,94 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.gss.impl;
+
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.MessageProp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class MicTokenV2 extends GssTokenV2 {
+    private MessageProp prop;
+
+    // This is called to construct MicToken from user input
+    MicTokenV2(GssContext context,
+             byte[] inMsg,
+             int msgOffset,
+             int msgLength,
+             MessageProp messageProp) throws GSSException {
+        super(TOKEN_MIC_V2, context);
+
+        prop = messageProp;
+        if (prop == null) {
+            prop = new MessageProp(0, false);
+        }
+
+        generateCheckSum(prop, inMsg, msgOffset, msgLength);
+    }
+
+    // This is called to construct MicToken from MicToken bytes
+    MicTokenV2(GssContext context,
+             MessageProp messageProp,
+             byte[] inToken,
+             int tokenOffset,
+             int tokenLength) throws GSSException {
+        super(TOKEN_MIC_V2, context, messageProp, inToken, tokenOffset, tokenLength);
+        this.prop = messageProp;
+    }
+
+    public int getMic(byte[] outToken, int offset) {
+        encodeHeader(outToken, offset);
+        System.arraycopy(checkSum, 0, outToken, TOKEN_HEADER_SIZE + offset, checkSum.length);
+        return TOKEN_HEADER_SIZE + checkSum.length;
+    }
+
+    /**
+     * Get bytes for this Mic token
+     * @return
+     */
+    public byte[] getMic() {
+        byte[] ret = new byte[TOKEN_HEADER_SIZE + checkSum.length];
+        getMic(ret, 0);
+        return ret;
+    }
+
+    public void getMic(OutputStream os) throws GSSException {
+        try {
+            encodeHeader(os);
+            os.write(checkSum);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Output MicTokenV2 error:" + e.getMessage());
+        }
+    }
+
+    /**
+     * Calculate the checksum for inMsg and compare with it with this token, throw GssException if not equal
+     * @param inMsg
+     * @param msgOffset
+     * @param msgLen
+     * @throws GSSException
+     */
+    public void verify(byte[] inMsg, int msgOffset, int msgLen) throws GSSException {
+        if (!verifyCheckSum(inMsg, msgOffset, msgLen)) {
+            throw new GSSException(GSSException.BAD_MIC, -1, "Corrupt MIC token");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV1.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV1.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV1.java
new file mode 100644
index 0000000..03395bb
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV1.java
@@ -0,0 +1,196 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.gss.impl;
+
+import org.apache.kerby.kerberos.kerb.crypto.util.Random;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.MessageProp;
+import sun.security.jgss.GSSHeader;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class WrapTokenV1 extends GssTokenV1 {
+    public static final int CONFOUNDER_SIZE = 8;
+
+    private boolean privacy;
+
+    private byte[] inData;
+    private int inOffset;
+    private int inLen;
+
+    private int paddingLen;
+    private byte[] confounder;
+    private int tokenBodyLen;
+
+    private byte[] bodyData;
+    private int bodyOffset;
+    private int bodyLen;
+
+    // for reconstruct
+    private int rawDataLength;
+    private byte[] rawData;
+    private int rawDataOffset;
+
+
+    // Generate wrap token according user data
+    public WrapTokenV1(GssContext context,
+                       byte[] inMsg,
+                       int msgOffset,
+                       int msgLength,
+                       MessageProp prop) throws GSSException {
+        super(TOKEN_WRAP_V1, context);
+
+        paddingLen = getPaddingLength(msgLength);
+        confounder = Random.makeBytes(CONFOUNDER_SIZE);
+        tokenBodyLen = CONFOUNDER_SIZE + msgLength + paddingLen;
+
+        calcPrivacyInfo(prop, confounder, inMsg, msgOffset, msgLength, paddingLen);
+
+        if (!context.getConfState()) {
+            prop.setPrivacy(false);
+        }
+        privacy = prop.getPrivacy();
+        inData = inMsg;
+        inOffset = msgOffset;
+        inLen = msgLength;
+    }
+
+    // Reconstruct a token from token bytes
+    public WrapTokenV1(GssContext context, MessageProp prop,
+                       byte[] token, int offset, int len) throws GSSException {
+        super(TOKEN_WRAP_V1, context, prop, token, offset, len);
+        // adjust the offset to the beginning of the body
+        bodyData = token;
+        bodyOffset = offset + reconHeaderLen;
+        bodyLen = len - reconHeaderLen;
+        getRawData(prop);
+    }
+
+    // Reconstruct a token from token bytes stream
+    public WrapTokenV1(GssContext context, MessageProp prop, InputStream is) throws GSSException {
+        super(TOKEN_WRAP_V1, context, prop, is);
+        byte[] token;
+        int len;
+        try {
+            len = is.available();
+            token = new byte[len];
+            is.read(token);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Read wrap token V1 error:" + e.getMessage());
+        }
+        bodyData = token;
+        bodyOffset = 0;
+        bodyLen = len;
+        getRawData(prop);
+    }
+
+    private void getRawData(MessageProp prop) throws GSSException {
+        privacy = prop.getPrivacy();
+        tokenBodyLen = getGssHeader().getMechTokenLength() - getTokenHeaderSize();
+
+        if (bodyLen < tokenBodyLen) {
+            throw new GSSException(GSSException.FAILURE, -1, "Insufficient data for Wrap token V1");
+        }
+
+        if (privacy) {
+            rawData = encryptor.encryptTokenV1(null, bodyData, bodyOffset, tokenBodyLen, 0,
+                    encryptor.isArcFourHmac() ? getPlainSequenceBytes() : null, false);
+            paddingLen = rawData[rawData.length - 1];
+            rawDataOffset = CONFOUNDER_SIZE;
+        } else {
+            rawData = bodyData;
+            paddingLen = bodyData[bodyOffset + tokenBodyLen - 1];
+            rawDataOffset = bodyOffset + CONFOUNDER_SIZE;
+        }
+        rawDataLength = tokenBodyLen - CONFOUNDER_SIZE - paddingLen;
+
+        verifyToken(null, rawData, rawDataOffset - CONFOUNDER_SIZE, tokenBodyLen, 0);
+    }
+
+    // Get plain text data from token data bytes
+    public byte[] unwrap() throws GSSException {
+        byte[] ret = new byte[rawDataLength];
+        System.arraycopy(rawData, rawDataOffset, ret, 0, rawDataLength);
+        return ret;
+    }
+
+    public void unwrap(OutputStream os) throws GSSException {
+        try {
+            os.write(rawData, rawDataOffset, rawDataLength);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1,
+                    "Error in output wrap token v1 data bytes:" + e.getMessage());
+        }
+    }
+
+    public byte[] wrap() throws GSSException {
+        ByteArrayOutputStream os = new ByteArrayOutputStream(getTokenSizeWithoutGssHeader() + inLen + 64);
+        wrap(os);
+        return os.toByteArray();
+    }
+
+    public void wrap(OutputStream os) throws GSSException {
+        try {
+            encodeHeader(os);
+            if (privacy) {
+                byte[] enc = encryptor.encryptTokenV1(confounder, inData, inOffset, inLen, paddingLen,
+                        encryptor.isArcFourHmac() ? getPlainSequenceBytes() : null, true);
+                os.write(enc);
+            } else {
+                os.write(confounder);
+                os.write(inData, inOffset, inLen);
+                os.write(getPaddingBytes(paddingLen));
+            }
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Error in output wrap token v1 bytes:" + e.getMessage());
+        }
+    }
+
+    protected int getTokenSizeWithoutGssHeader() {
+        return tokenBodyLen + getTokenHeaderSize();
+    }
+
+    private int getPaddingLength(int dataLen) {
+        if (encryptor.isArcFourHmac()) {
+            return 1;
+        }
+        return 8 - (dataLen % 8);
+    }
+
+    private byte[] getPaddingBytes(int len) {
+        byte[] ret = new byte[len];
+        int i = 0;
+        while (i < len) {
+            ret[i++] = (byte) len;
+        }
+        return ret;
+    }
+
+    public static int getMsgSizeLimit(int qop, boolean confReq, int maxTokSize, GssEncryptor encryptor)
+            throws GSSException {
+        return GSSHeader.getMaxMechTokenSize(objId, maxTokSize)
+                - encryptor.getCheckSumSize()
+                - TOKEN_HEADER_COMM_SIZE - TOKEN_HEADER_SEQ_SIZE
+                - CONFOUNDER_SIZE - 8;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV2.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV2.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV2.java
new file mode 100644
index 0000000..8f4cae4
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV2.java
@@ -0,0 +1,159 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.gss.impl;
+
+import org.apache.kerby.kerberos.kerb.Message;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.MessageProp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+
+public class WrapTokenV2 extends GssTokenV2 {
+    private MessageProp prop;
+
+    // Generate a token from user input data
+    WrapTokenV2(GssContext context,
+              byte[] data,
+              int dataOffset,
+              int dataLength,
+              MessageProp messageProp) throws GSSException {
+        super(TOKEN_WRAP_V2, context);
+
+        prop = messageProp;
+
+        if (prop.getQOP() != 0) {
+            prop.setQOP(0);
+        }
+
+        if (!context.getConfState()) {
+            prop.setPrivacy(false);
+        }
+
+        generateCheckSum(prop, data, dataOffset, dataLength);
+
+        if (prop.getPrivacy()) {
+            byte[] toProcess = new byte[dataLength + TOKEN_HEADER_SIZE];
+            System.arraycopy(data, dataOffset, toProcess, 0, dataLength);
+            encodeHeader(toProcess, dataLength);
+
+            tokenData = encryptor.encryptData(toProcess, getKeyUsage());
+        } else {
+            tokenData = data; // keep it for now
+        }
+    }
+
+    /**
+     * Get bytes of the token
+     * @return
+     */
+    public byte[] wrap() {
+        int dataSize = tokenData.length;
+        int ckSize = checkSum == null ? 0 : checkSum.length;
+        byte[] ret = new byte[TOKEN_HEADER_SIZE + dataSize + ckSize];
+        encodeHeader(ret, 0);
+        System.arraycopy(tokenData, 0, ret, TOKEN_HEADER_SIZE, dataSize);
+        if (ckSize > 0) {
+            System.arraycopy(checkSum, 0, ret, TOKEN_HEADER_SIZE + dataSize, ckSize);
+        }
+        return ret;
+    }
+
+    public void wrap(OutputStream os) throws GSSException {
+        try {
+            encodeHeader(os);
+            os.write(tokenData);
+            int ckSize = checkSum == null ? 0 : checkSum.length;
+            if (ckSize > 0) {
+                os.write(checkSum);
+            }
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Output token error:" + e.getMessage());
+        }
+    }
+
+    // Reconstruct a token from token bytes
+    public WrapTokenV2(GssContext context, MessageProp prop, byte[] token, int offset, int len) throws GSSException {
+        super(TOKEN_WRAP_V2, context, prop, token, offset, len);
+        this.prop = prop;
+    }
+
+    // Reconstruct a token from token bytes stream
+    public WrapTokenV2(GssContext context, MessageProp prop, InputStream is) throws GSSException {
+        super(TOKEN_WRAP_V2, context, prop, is);
+        this.prop = prop;
+    }
+
+    /**
+     * Get plain text data from token bytes
+     * @param outBuffer
+     * @param offset
+     * @return plain text contained in the wrap token
+     * @throws GSSException
+     */
+    public byte[] unwrap(byte[] outBuffer, int offset) throws GSSException {
+        int lenToCopy;
+        if (prop.getPrivacy()) {
+            byte[] plainText = encryptor.decryptData(tokenData, getKeyUsage());
+            lenToCopy = plainText.length - TOKEN_HEADER_SIZE;
+            if (outBuffer == null) {
+                outBuffer = new byte[lenToCopy];
+                offset = 0;
+            }
+            System.arraycopy(plainText, 0, outBuffer, offset, lenToCopy);
+        } else {
+            lenToCopy = tokenData.length - encryptor.getCheckSumSize();
+            if (outBuffer == null) {
+                outBuffer = new byte[lenToCopy];
+                offset = 0;
+            }
+            System.arraycopy(tokenData, 0, outBuffer, offset, lenToCopy);
+
+            if (!verifyCheckSum(outBuffer, offset, lenToCopy)) {
+                throw new GSSException(GSSException.BAD_MIC, -1, "Corrupt token checksum");
+            }
+        }
+        return outBuffer;
+    }
+
+    public byte[] unwrap() throws GSSException {
+        return unwrap(null, 0);
+    }
+
+    public void unwrap(OutputStream os) throws GSSException {
+        byte[] data = unwrap();
+        try {
+            os.write(data);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Output token error:" + e.getMessage());
+        }
+    }
+
+    public static int getMsgSizeLimit(int qop, boolean confReq, int maxTokSize, GssEncryptor encryptor)
+            throws GSSException {
+        if (confReq) {
+            return maxTokSize - encryptor.getCheckSumSize() - TOKEN_HEADER_SIZE * 2 - CONFOUNDER_SIZE;
+        } else {
+            return maxTokSize - encryptor.getCheckSumSize() - TOKEN_HEADER_SIZE;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/KerbyMechFactory.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/KerbyMechFactory.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/KerbyMechFactory.java
deleted file mode 100644
index adacb27..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/KerbyMechFactory.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/**
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.gssapi;
-
-import org.apache.kerby.kerberos.kerb.gssapi.krb5.KerbyAcceptCred;
-import org.apache.kerby.kerberos.kerb.gssapi.krb5.KerbyContext;
-import org.apache.kerby.kerberos.kerb.gssapi.krb5.KerbyCredElement;
-import org.apache.kerby.kerberos.kerb.gssapi.krb5.KerbyInitCred;
-import org.apache.kerby.kerberos.kerb.gssapi.krb5.KerbyNameElement;
-import org.ietf.jgss.GSSCredential;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.GSSName;
-import org.ietf.jgss.Oid;
-import sun.security.jgss.GSSCaller;
-import sun.security.jgss.spi.GSSContextSpi;
-import sun.security.jgss.spi.GSSCredentialSpi;
-import sun.security.jgss.spi.GSSNameSpi;
-import sun.security.jgss.spi.MechanismFactory;
-
-import java.security.Provider;
-
-/**
- * Kerby Kerberos V5 plugin for JGSS
- */
-public class KerbyMechFactory implements MechanismFactory {
-    private static final Provider PROVIDER =
-            new org.apache.kerby.kerberos.kerb.gssapi.Provider();
-
-    private static final String KRB5_OID_STRING = "1.2.840.113554.1.2.2";
-    private static final Oid KRB5_OID = createOid(KRB5_OID_STRING);
-
-    private static Oid[] nameTypes =
-            new Oid[] {
-                    GSSName.NT_USER_NAME,
-                    GSSName.NT_EXPORT_NAME,
-                    GSSName.NT_HOSTBASED_SERVICE
-            };
-
-    private final GSSCaller caller;
-
-    public Oid getMechanismOid() {
-        return KRB5_OID;
-    }
-
-    public Provider getProvider() {
-        return PROVIDER;
-    }
-
-    public Oid[] getNameTypes() throws GSSException {
-        return nameTypes;
-    }
-
-    public KerbyMechFactory(GSSCaller caller) {
-        this.caller = caller;
-    }
-
-    public GSSNameSpi getNameElement(String nameStr, Oid nameType)
-            throws GSSException {
-        return KerbyNameElement.getInstance(nameStr, nameType);
-    }
-
-    public GSSNameSpi getNameElement(byte[] name, Oid nameType)
-            throws GSSException {
-        return KerbyNameElement.getInstance(name.toString(), nameType);
-    }
-
-    // Used by initiator
-    public GSSContextSpi getMechanismContext(GSSNameSpi peer,
-                                             GSSCredentialSpi myInitiatorCred,
-                                             int lifetime) throws GSSException {
-        if (peer != null && !(peer instanceof KerbyNameElement)) {
-            peer = KerbyNameElement.getInstance(peer.toString(), peer.getStringNameType());
-        }
-        if (myInitiatorCred == null) {
-            myInitiatorCred = getCredentialElement(null, lifetime, 0, GSSCredential.INITIATE_ONLY);
-        }
-        return new KerbyContext(caller, (KerbyNameElement) peer, (KerbyInitCred) myInitiatorCred, lifetime);
-    }
-
-    public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
-            throws GSSException {
-        if (myAcceptorCred == null) {
-            myAcceptorCred = getCredentialElement(null, 0,
-                    GSSCredential.INDEFINITE_LIFETIME, GSSCredential.ACCEPT_ONLY);
-        }
-        return new KerbyContext(caller, (KerbyAcceptCred) myAcceptorCred);
-    }
-
-    // Reconstruct from previously exported context
-    public GSSContextSpi getMechanismContext(byte[] exportedContext)
-            throws GSSException {
-       return new KerbyContext(caller, exportedContext);
-    }
-
-    public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
-                                                 int initLifetime,
-                                                 int acceptLifetime,
-                                                 int usage)
-            throws GSSException {
-        if (name != null && !(name instanceof KerbyNameElement)) {
-            name = KerbyNameElement.getInstance(name.toString(), name.getStringNameType());
-        }
-
-        KerbyCredElement credElement;
-
-        if (usage == GSSCredential.INITIATE_ONLY) {
-            credElement = KerbyInitCred.getInstance(caller, (KerbyNameElement) name, initLifetime);
-        } else if (usage == GSSCredential.ACCEPT_ONLY) {
-            credElement = KerbyAcceptCred.getInstance(caller, (KerbyNameElement) name, acceptLifetime);
-        } else if (usage == GSSCredential.INITIATE_AND_ACCEPT) {
-            throw new GSSException(GSSException.FAILURE, -1, "Unsupported usage mode: INITIATE_AND_ACCEPT");
-        } else {
-            throw new GSSException(GSSException.FAILURE, -1, "Unknown usage mode: " + usage);
-        }
-
-        return credElement;
-    }
-
-    private static Oid createOid(String oidStr) {
-        Oid retVal;
-        try {
-            retVal = new Oid(oidStr);
-        } catch (GSSException e) {
-            retVal = null;
-        }
-        return retVal;
-    }
-
-    public static Oid getOid() {
-        return KRB5_OID;
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/Provider.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/Provider.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/Provider.java
deleted file mode 100644
index ad3a614..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/Provider.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.gssapi;
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-
-/**
- * Proivder is used to register the implementation of gssapi mechanism into the system
- */
-public final class Provider extends java.security.Provider {
-    private static final long serialVersionUID = 3787378212107821987L;
-    private static final String INFO = "Kerby GssApi Provider";
-    private static final String MECHANISM_GSSAPI = "GssApiMechanism.1.2.840.113554.1.2.2";
-    private static final String MECHANISM_GSSAPI_CLASS = "org.apache.kerby.kerberos.kerb.gssapi.KerbyMechFactory";
-
-    public Provider() {
-        super("KerbyGssApi", 0.01d, INFO);
-
-        AccessController.doPrivileged(new PrivilegedAction<Void>() {
-            public Void run() {
-
-                put(MECHANISM_GSSAPI, MECHANISM_GSSAPI_CLASS);
-
-                return null;
-            }
-        });
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/CredUtils.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/CredUtils.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/CredUtils.java
deleted file mode 100644
index f7ddc31..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/CredUtils.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package org.apache.kerby.kerberos.kerb.gssapi.krb5;
-
-import org.ietf.jgss.GSSException;
-import sun.security.jgss.GSSCaller;
-
-import javax.security.auth.Subject;
-import javax.security.auth.kerberos.*;
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.Set;
-
-/**
- * Utility functions to deal with credentials in Context
- */
-public class CredUtils {
-
-    public static <T> Set<T> getContextPrivateCredentials(Class<T> credentialType, AccessControlContext acc) {
-        Subject subject = Subject.getSubject(acc);
-        Set<T> creds = subject.getPrivateCredentials(credentialType);
-        return creds;
-    }
-
-    public static <T> Set<T> getContextCredentials(final Class<T> credentialType) throws GSSException {
-        final AccessControlContext acc = AccessController.getContext();
-        try {
-            return AccessController.doPrivileged(
-                    new PrivilegedExceptionAction<Set<T>>() {
-                        public Set<T> run() throws Exception {
-                            return CredUtils.getContextPrivateCredentials(credentialType, acc);
-                        }
-                    });
-        } catch (PrivilegedActionException e) {
-            throw new GSSException(GSSException.NO_CRED, -1, "Get credential from context failed");
-        }
-    }
-
-    public static KerberosTicket getKerberosTicketFromContext(GSSCaller caller,
-                                                              final String clientName,
-                                                              final String serverName) throws GSSException {
-        Set<KerberosTicket> tickets = getContextCredentials(KerberosTicket.class);
-        for (KerberosTicket ticket : tickets) {
-            if (ticket.isCurrent() && (serverName == null || ticket.getServer().getName().equals(serverName))
-                    && (clientName == null || ticket.getClient().getName().equals(clientName))) {
-                return ticket;
-            }
-        }
-        return null;
-    }
-
-    public static KeyTab getKeyTabFromContext(KerberosPrincipal principal) throws GSSException {
-        Set<KeyTab> tabs = getContextCredentials(KeyTab.class);
-        for (KeyTab tab : tabs) {
-            KerberosKey[] keys = tab.getKeys(principal);
-            if (keys != null && keys.length > 0) {
-                return tab;
-            }
-        }
-        return null;
-    }
-
-    public static void addCredentialToSubject(final KerberosTicket ticket) throws GSSException {
-        final AccessControlContext acc = AccessController.getContext();
-
-        final Subject subject = AccessController.doPrivileged(
-                new java.security.PrivilegedAction<Subject>() {
-                    public Subject run() {
-                        return Subject.getSubject(acc);
-                    }
-                });
-
-        AccessController.doPrivileged(
-                new java.security.PrivilegedAction<Void>() {
-                    public Void run() {
-                        subject.getPrivateCredentials().add(ticket);
-                        return null;
-                    }
-                });
-    }
-
-    public static void checkPrincipalPermission(String principalName, String action) {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            ServicePermission sp = new ServicePermission(principalName, action);
-            sm.checkPermission(sp);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyAcceptCred.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyAcceptCred.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyAcceptCred.java
deleted file mode 100644
index a7331fa..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyAcceptCred.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.gssapi.krb5;
-
-
-import org.ietf.jgss.GSSException;
-import sun.security.jgss.GSSCaller;
-
-import javax.security.auth.kerberos.KerberosKey;
-import javax.security.auth.kerberos.KerberosPrincipal;
-import javax.security.auth.kerberos.KeyTab;
-
-public final class KerbyAcceptCred extends KerbyCredElement {
-
-    private final KeyTab keyTab;
-
-    public static KerbyAcceptCred getInstance(final GSSCaller caller,
-                                              KerbyNameElement name, int lifeTime) throws GSSException {
-
-        KerberosPrincipal princ = new KerberosPrincipal(name.getPrincipalName().getName(),
-                name.getPrincipalName().getNameType().getValue());
-        KeyTab keyTab = CredUtils.getKeyTabFromContext(princ);
-
-        if (keyTab == null) {
-            throw new GSSException(GSSException.NO_CRED, -1,
-                    "Failed to find any Kerberos credential for " + name.getPrincipalName().getName());
-        }
-
-        return new KerbyAcceptCred(caller, name, keyTab, lifeTime);
-    }
-
-    private KerbyAcceptCred(GSSCaller caller, KerbyNameElement name, KeyTab keyTab, int lifeTime) {
-        super(caller, name);
-        this.keyTab = keyTab;
-        this.accLifeTime = lifeTime;
-    }
-
-    public boolean isInitiatorCredential() throws GSSException {
-        return false;
-    }
-
-    public boolean isAcceptorCredential() throws GSSException {
-        return true;
-    }
-
-    public KeyTab getKeyTab() {
-        return this.keyTab;
-    }
-
-    public KerberosKey[] getKeys() {
-        KerberosPrincipal princ = new KerberosPrincipal(name.getPrincipalName().getName(),
-                name.getPrincipalName().getNameType().getValue());
-        return keyTab.getKeys(princ);
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyContext.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyContext.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyContext.java
deleted file mode 100644
index 5395afd..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyContext.java
+++ /dev/null
@@ -1,673 +0,0 @@
-/**
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.gssapi.krb5;
-
-import com.sun.security.jgss.InquireType;
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.gssapi.KerbyMechFactory;
-import org.apache.kerby.kerberos.kerb.request.ApRequest;
-import org.apache.kerby.kerberos.kerb.response.ApResponse;
-import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationData;
-import org.apache.kerby.kerberos.kerb.type.ap.ApRep;
-import org.apache.kerby.kerberos.kerb.type.ap.ApReq;
-import org.apache.kerby.kerberos.kerb.type.ap.Authenticator;
-import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
-import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
-import org.apache.kerby.kerberos.kerb.type.kdc.EncKdcRepPart;
-import org.apache.kerby.kerberos.kerb.type.ticket.EncTicketPart;
-import org.apache.kerby.kerberos.kerb.type.ticket.SgtTicket;
-import org.apache.kerby.kerberos.kerb.type.ticket.TicketFlags;
-import org.ietf.jgss.ChannelBinding;
-import org.ietf.jgss.GSSContext;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.MessageProp;
-import org.ietf.jgss.Oid;
-import sun.security.jgss.GSSCaller;
-import sun.security.jgss.spi.GSSContextSpi;
-import sun.security.jgss.spi.GSSCredentialSpi;
-import sun.security.jgss.spi.GSSNameSpi;
-
-import javax.security.auth.kerberos.KerberosTicket;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.security.Provider;
-
-@SuppressWarnings("PMD")
-public class KerbyContext implements GSSContextSpi {
-
-    private static final int STATE_NONE = 0;
-    private static final int STATE_ESTABLISHING = 1;
-    private static final int STATE_ESTABLISHED = 2;
-    private static final int STATE_DESTROYED = 3;
-
-    private static final byte[] MSG_AP_REQ = {(byte) 0x1, (byte) 0};
-    private static final byte[] MSG_AP_REP = {(byte) 0x2, (byte) 0};
-
-    private int ctxState = STATE_NONE;
-
-    private final GSSCaller caller;
-    private KerbyCredElement myCred;
-    private boolean initiator;
-    private KerbyNameElement myName;
-    private KerbyNameElement peerName;
-    private int lifeTime;
-    private ChannelBinding channelBinding;
-
-    private boolean mutualAuth  = true;
-    private boolean replayDet  = true;
-    private boolean sequenceDet  = true;
-    private boolean credDeleg  = false;
-    private boolean confState  = true;
-    private boolean integState  = true;
-    private boolean delegPolicy = false;
-
-    public static final int INVALID_KEY = 0;
-    public static final int SESSION_KEY = 1;
-    public static final int INITIATOR_SUBKEY = 2;
-    public static final int ACCEPTOR_SUBKEY = 4;
-    private int keyComesFrom = INVALID_KEY;
-
-    private EncryptionKey sessionKey;   // used between client and app server
-    private TicketFlags ticketFlags;
-    private ApReq outApReq;
-
-    private KerbyGssEncryptor gssEncryptor;
-
-    // Called on initiator's side.
-    public KerbyContext(GSSCaller caller, KerbyNameElement peerName, KerbyCredElement myCred,
-                        int lifeTime)
-            throws GSSException {
-        if (peerName == null) {
-            throw new IllegalArgumentException("Cannot have null peer name");
-        }
-
-        this.caller = caller;
-        this.peerName = peerName;
-        this.myCred = myCred;
-        this.lifeTime = lifeTime;
-        this.initiator = true;
-
-        mySequenceNumberLock = new Object();
-        peerSequenceNumberLock = new Object();
-    }
-
-    public KerbyContext(GSSCaller caller, KerbyAcceptCred myCred)
-            throws GSSException {
-        this.caller = caller;
-        this.myCred = myCred;
-        this.initiator = false;
-
-        mySequenceNumberLock = new Object();
-        peerSequenceNumberLock = new Object();
-    }
-
-    public KerbyContext(GSSCaller caller, byte[] interProcessToken)
-            throws GSSException {
-        throw new GSSException(GSSException.UNAVAILABLE, -1, "Unsupported feature");
-    }
-
-    public Provider getProvider() {
-        return new org.apache.kerby.kerberos.kerb.gssapi.Provider();
-    }
-
-    public void requestLifetime(int lifeTime) throws GSSException {
-        if (ctxState == STATE_NONE && isInitiator()) {
-            this.lifeTime = lifeTime;
-        }
-    }
-
-    public void requestMutualAuth(boolean state) throws GSSException {
-        if (ctxState == STATE_NONE && isInitiator()) {
-            mutualAuth  = state;
-        }
-    }
-
-    public void requestReplayDet(boolean state) throws GSSException {
-        if (ctxState == STATE_NONE && isInitiator()) {
-            replayDet = state;
-        }
-    }
-
-    public void requestSequenceDet(boolean state) throws GSSException {
-        if (ctxState == STATE_NONE && isInitiator()) {
-            replayDet = state;
-        }
-    }
-
-    public void requestCredDeleg(boolean state) throws GSSException {
-        if (ctxState == STATE_NONE && isInitiator() && myCred == null) {
-            credDeleg  = state;
-        }
-    }
-
-    public void requestAnonymity(boolean state) throws GSSException {
-        // anonymous context not supported
-    }
-
-    public void requestConf(boolean state) throws GSSException {
-        if (ctxState == STATE_NONE && isInitiator()) {
-            confState = state;
-        }
-    }
-
-    public void requestInteg(boolean state) throws GSSException {
-        if (ctxState == STATE_NONE && isInitiator()) {
-            integState = state;
-        }
-    }
-
-    public void requestDelegPolicy(boolean state) throws GSSException {
-        if (ctxState == STATE_NONE && isInitiator()) {
-            delegPolicy = state;
-        }
-    }
-
-    public void setChannelBinding(ChannelBinding cb) throws GSSException {
-        this.channelBinding = cb;
-    }
-
-    public boolean getCredDelegState() {
-        return credDeleg;
-    }
-
-    public boolean getMutualAuthState() {
-        return mutualAuth;
-    }
-
-    public boolean getReplayDetState() {
-        return replayDet || sequenceDet;
-    }
-
-    public boolean getSequenceDetState() {
-        return sequenceDet;
-    }
-
-    public boolean getAnonymityState() {
-        return false;
-    }
-
-    public boolean getDelegPolicyState() {
-        return delegPolicy;
-    }
-
-    public boolean isTransferable() throws GSSException {
-        return false;
-    }
-
-    public boolean isProtReady() {
-        return ctxState == STATE_ESTABLISHED;
-    }
-
-    public boolean isInitiator() {
-        return initiator;
-    }
-
-    public boolean getConfState() {
-        return confState;
-    }
-
-    public boolean getIntegState() {
-        return integState;
-    }
-
-    public int getLifetime() {
-        return GSSContext.INDEFINITE_LIFETIME;
-    }
-
-    public boolean isEstablished() {
-        return ctxState == STATE_ESTABLISHED;
-    }
-
-    public GSSNameSpi getSrcName() throws GSSException {
-        return isInitiator() ? myName : peerName;
-    }
-
-    public GSSNameSpi getTargName() throws GSSException {
-        return !isInitiator() ? myName : peerName;
-    }
-
-    public Oid getMech() throws GSSException {
-        return KerbyMechFactory.getOid();
-    }
-
-    public GSSCredentialSpi getDelegCred() throws GSSException {
-        throw new GSSException(GSSException.FAILURE, -1, "API not implemented");  // TODO:
-    }
-
-    public byte[] initSecContext(InputStream is, int mechTokenSize)
-            throws GSSException {
-        if (!isInitiator()) {
-            throw new GSSException(GSSException.FAILURE, -1, "initSecContext called on acceptor");
-        }
-
-        byte[] ret = null;
-
-        if (ctxState == STATE_NONE) {
-
-            if (!myCred.isInitiatorCredential()) {
-                throw new GSSException(GSSException.NO_CRED, -1, "No TGT available");
-            }
-
-            // check if service ticket already exists
-            // if not, prepare to get it through TGS_REQ
-            SgtTicket sgtTicket = null;
-            String serviceName = peerName.getPrincipalName().getName();
-            myName = (KerbyNameElement) myCred.getName();
-            PrincipalName clientPrincipal = myName.getPrincipalName();
-
-            sgtTicket = KerbyUtil.getSgtCredentialFromContext(caller, clientPrincipal.getName(), serviceName);
-
-            if (sgtTicket == null) {
-                sgtTicket = KerbyUtil.applySgtCredential(((KerbyInitCred) myCred).ticket, serviceName);
-
-                // add this service credential to context
-                final KerberosTicket ticket =
-                        KerbyUtil.convertKrbTicketToKerberosTicket(sgtTicket, myName.getPrincipalName().getName());
-                CredUtils.addCredentialToSubject(ticket);
-            }
-
-            ApRequest apRequest = new ApRequest(clientPrincipal, sgtTicket);
-            try {
-                outApReq = apRequest.getApReq();
-            } catch (KrbException e) {
-                throw new GSSException(GSSException.FAILURE, -1, "Generate ApReq failed: " + e.getMessage());
-            }
-            setupInitiatorContext(sgtTicket, apRequest);
-            try {
-                ByteBuffer outBuffer = ByteBuffer.allocate(outApReq.encodingLength() + 2);
-                outBuffer.put(MSG_AP_REQ);
-                outApReq.encode(outBuffer);
-                outBuffer.flip();
-                ret = outBuffer.array();
-            } catch (IOException e) {
-                throw new GSSException(GSSException.FAILURE, -1, "Generate ApReq bytes failed: " + e.getMessage());
-            }
-
-            ctxState = STATE_ESTABLISHING;
-            if (!getMutualAuthState()) {
-                gssEncryptor = new KerbyGssEncryptor(getSessionKey());
-                ctxState = STATE_ESTABLISHED;
-            }
-
-        } else if (ctxState == STATE_ESTABLISHING) {
-            verifyServerToken(is, mechTokenSize);
-            gssEncryptor = new KerbyGssEncryptor(getSessionKey());
-            outApReq = null;
-            ctxState = STATE_ESTABLISHED;
-        }
-        return ret;
-    }
-
-    private void setupInitiatorContext(SgtTicket sgt, ApRequest apRequest) throws GSSException {
-        EncKdcRepPart encKdcRepPart = sgt.getEncKdcRepPart();
-        TicketFlags ticketFlags = encKdcRepPart.getFlags();
-        setTicketFlags(ticketFlags);
-
-        setAuthTime(encKdcRepPart.getAuthTime().toString());
-
-        Authenticator auth;
-        try {
-            auth = apRequest.getApReq().getAuthenticator();
-        } catch (KrbException e) {
-            throw new GSSException(GSSException.FAILURE, -1, "ApReq failed in Initiator");
-        }
-        setMySequenceNumber(auth.getSeqNumber());
-
-        EncryptionKey subKey = auth.getSubKey();
-        if (subKey != null) {
-            setSessionKey(subKey, KerbyContext.INITIATOR_SUBKEY);
-        } else {
-            setSessionKey(sgt.getSessionKey(), KerbyContext.SESSION_KEY);
-        }
-
-        if (!getMutualAuthState()) {
-            setPeerSequenceNumber(0);
-        }
-    }
-
-    /**
-     * Verify the AP_REP from server and set context accordingly
-     * @param is
-     * @param mechTokenSize
-     * @return
-     * @throws GSSException
-     * @throws IOException
-     */
-    private void verifyServerToken(InputStream is, int mechTokenSize)
-            throws GSSException {
-        byte[] token;
-        ApRep apRep;
-        try {
-            if (!(is.read() == MSG_AP_REP[0] && is.read() == MSG_AP_REP[1])) {
-                throw new GSSException(GSSException.FAILURE, -1, "Invalid ApRep message ID");
-            }
-            token = new byte[mechTokenSize - MSG_AP_REP.length];
-            is.read(token);
-            apRep = new ApRep();
-            apRep.decode(token);
-        } catch (IOException e) {
-            throw new GSSException(GSSException.FAILURE, -1, "Invalid ApRep " + e.getMessage());
-        }
-
-        try {
-            ApResponse.validate(getSessionKey(), apRep, outApReq);
-        } catch (KrbException e) {
-            throw new GSSException(GSSException.UNAUTHORIZED, -1, "ApRep verification failed");
-        }
-
-        EncryptionKey key = apRep.getEncRepPart().getSubkey();
-        if (key != null) {
-            setSessionKey(key, ACCEPTOR_SUBKEY);
-        }
-
-        int seqNum = apRep.getEncRepPart().getSeqNumber();
-        setPeerSequenceNumber(seqNum == -1 ? 0 : seqNum);
-    }
-
-    public byte[] acceptSecContext(InputStream is, int mechTokenSize)
-            throws GSSException {
-        byte[] ret = null;
-
-        if (isInitiator()) {
-            throw new GSSException(GSSException.FAILURE, -1, "acceptSecContext called on initiator");
-        }
-
-        if (ctxState == STATE_NONE) {
-            ctxState = STATE_ESTABLISHING;
-            if (!myCred.isAcceptorCredential()) {
-                throw new GSSException(GSSException.FAILURE, -1, "No acceptor credential available");
-            }
-
-            KerbyAcceptCred acceptCred = (KerbyAcceptCred) myCred;
-            CredUtils.checkPrincipalPermission(
-                    ((KerbyNameElement) acceptCred.getName()).getPrincipalName().getName(), "accept");
-
-            if (getMutualAuthState()) {
-                ret = verifyClientToken(acceptCred, is, mechTokenSize);
-            }
-
-            gssEncryptor = new KerbyGssEncryptor(getSessionKey());
-
-            myCred = null;
-            ctxState = STATE_ESTABLISHED;
-        }
-
-        return ret;
-    }
-
-    private byte[] verifyClientToken(KerbyAcceptCred acceptCred, InputStream is, int mechTokenSize)
-            throws GSSException {
-        byte[] token;
-        ApReq apReq;
-        try {
-            if (!(is.read() == MSG_AP_REQ[0] && is.read() == MSG_AP_REQ[1])) {
-                throw new GSSException(GSSException.FAILURE, -1, "Invalid ApReq message ID");
-            }
-
-            token = new byte[mechTokenSize - MSG_AP_REQ.length];
-            is.read(token);
-            apReq = new ApReq();
-            apReq.decode(token);
-        } catch (IOException e) {
-            throw new GSSException(GSSException.UNAUTHORIZED, -1, "ApReq invalid:" + e.getMessage());
-        }
-
-        int kvno = apReq.getTicket().getEncryptedEncPart().getKvno();
-        int encryptType = apReq.getTicket().getEncryptedEncPart().getEType().getValue();
-
-        // Get server key from credential
-        EncryptionKey serverKey = KerbyUtil.getEncryptionKey(acceptCred.getKeys(), encryptType, kvno);
-        if (serverKey == null) {
-            throw new GSSException(GSSException.FAILURE, -1, "Server key not found");
-        }
-
-        try {
-            ApRequest.validate(serverKey, apReq, channelBinding.getInitiatorAddress(), 5 * 60 * 1000);
-        } catch (KrbException e) {
-            throw new GSSException(GSSException.UNAUTHORIZED, -1, "ApReq verification failed: " + e.getMessage());
-        }
-
-        ApResponse apResponse = new ApResponse(apReq);
-        ApRep apRep;
-        try {
-            apRep = apResponse.getApRep();
-        } catch (KrbException e) {
-            throw new GSSException(GSSException.UNAUTHORIZED, -1, "Generate ApRep failed");
-        }
-
-        EncTicketPart apReqTicketEncPart = apReq.getTicket().getEncPart();
-
-        EncryptionKey ssKey = apReqTicketEncPart.getKey();
-        Authenticator auth = apReq.getAuthenticator();
-        EncryptionKey subKey = auth.getSubKey();
-
-        if (subKey != null) {
-            setSessionKey(subKey, INITIATOR_SUBKEY);
-        } else {
-            setSessionKey(ssKey, SESSION_KEY);
-        }
-
-        // initial seqNumber
-        int seqNumber = auth.getSeqNumber();
-        setMySequenceNumber(seqNumber);
-        // initial authtime, tktflags, authdata,
-        setAuthTime(apReqTicketEncPart.getAuthTime().toString());
-        setTicketFlags(apReqTicketEncPart.getFlags());
-        setAuthData(apReqTicketEncPart.getAuthorizationData());
-
-        byte[] ret = null;
-        try {
-            ByteBuffer outBuffer = ByteBuffer.allocate(apRep.encodingLength() + 2);
-            outBuffer.put(MSG_AP_REP);
-            apRep.encode(outBuffer);
-            outBuffer.flip();
-            ret = outBuffer.array();
-        } catch (IOException e) {
-            throw new GSSException(GSSException.FAILURE, -1, "Generate ApRep bytes failed:" + e.getMessage());
-        }
-        return ret;
-    }
-
-    public int getWrapSizeLimit(int qop, boolean confReq, int maxTokSize)
-            throws GSSException {
-        if (gssEncryptor.isV2()) {
-            return WrapTokenV2.getMsgSizeLimit(qop, confReq, maxTokSize, gssEncryptor);
-        } else {
-            return WrapTokenV1.getMsgSizeLimit(qop, confReq, maxTokSize, gssEncryptor);
-        }
-    }
-
-    public void wrap(InputStream is, OutputStream os, MessageProp msgProp)
-            throws GSSException {
-        if (ctxState != STATE_ESTABLISHED) {
-            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for wrap");
-        }
-        if (gssEncryptor.isV2()) {
-             WrapTokenV2 token = new WrapTokenV2(this, inBuf, 0, len, msgProp);
-             token.wrap(os);
-        } else {
-             WrapTokenV1 token = new WrapTokenV1(this, inBuf, 0, len, msgProp);
-             token.wrap(os);
-        }
-    }
-
-    public byte[] wrap(byte[] inBuf, int offset, int len,
-                       MessageProp msgProp) throws GSSException {
-        if (ctxState != STATE_ESTABLISHED) {
-            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for wrap");
-        }
-        byte[] ret;
-        if (gssEncryptor.isV2()) {
-             WrapTokenV2 token = new WrapTokenV2(this, inBuf, offset, len, msgProp);
-             ret = token.wrap();
-        } else {
-             WrapTokenV1 token = new WrapTokenV1(this, inBuf, offset, len, msgProp);
-             ret = token.wrap();
-        }
-        return ret;
-    }
-
-    public void unwrap(InputStream is, OutputStream os,
-                       MessageProp msgProp) throws GSSException {
-        if (gssEncryptor.isV2()) {
-            WrapTokenV2 token = new WrapTokenV2(this, msgProp, is);
-            token.unwrap(os);
-        } else {
-            WrapTokenV1 token = new WrapTokenV1(this, msgProp, is);
-            token.unwrap(os);
-        }
-    }
-
-    public byte[] unwrap(byte[] inBuf, int offset, int len,
-                         MessageProp msgProp) throws GSSException {
-        if (ctxState != STATE_ESTABLISHED) {
-            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for unwrap");
-        }
-        byte[] ret;
-        if (gssEncryptor.isV2()) {
-             WrapTokenV2 token = new WrapTokenV2(this, msgProp, inBuf, offset, len);
-             ret = token.unwrap();
-        } else {
-            WrapTokenV1 token = new WrapTokenV1(this, msgProp, inBuf, offset, len);
-            ret = token.unwrap();
-        }
-        return ret;
-    }
-
-    public void getMIC(InputStream is, OutputStream os,
-                       MessageProp msgProp)
-            throws GSSException {
-    }
-
-    public byte[] getMIC(byte[] inMsg, int offset, int len,
-                         MessageProp msgProp) throws GSSException {
-        return null; // TODO: to be implemented
-    }
-
-    public void verifyMIC(InputStream is, InputStream msgStr,
-                          MessageProp msgProp) throws GSSException {
-    }
-
-    public void verifyMIC(byte[]inTok, int tokOffset, int tokLen,
-                          byte[] inMsg, int msgOffset, int msgLen,
-                          MessageProp msgProp) throws GSSException {
-    }
-
-    public byte[] export() throws GSSException {
-        throw new GSSException(GSSException.UNAVAILABLE, -1, "Unsupported export method");
-    }
-
-    public void dispose() throws GSSException {
-        ctxState = STATE_DESTROYED;
-        setSessionKey(null, 0);
-        peerName = null;
-        myCred = null;
-        myName = null;
-    }
-
-
-    private String authTime;
-    private void setAuthTime(String authTime) {
-        this.authTime = authTime;
-    }
-
-    public Object inquireSecContext(InquireType type) throws GSSException {
-        if (ctxState != STATE_ESTABLISHED) {
-            throw new GSSException(GSSException.NO_CONTEXT, -1, "Invalid context");
-        }
-
-        switch (type) {
-            case KRB5_GET_SESSION_KEY:
-                return getSessionKey();
-            case KRB5_GET_TKT_FLAGS:
-                return KerbyUtil.ticketFlagsToBooleans(ticketFlags);
-            case KRB5_GET_AUTHZ_DATA:
-                if (isInitiator()) {
-                    throw new GSSException(GSSException.UNAVAILABLE, -1,
-                            "Authorization data not available for initiator");
-                } else {
-                    return KerbyUtil.kerbyAuthorizationDataToJgssAuthorizationDataEntries(authData);
-                }
-            case KRB5_GET_AUTHTIME:
-                return authTime;
-        }
-        throw new GSSException(GSSException.UNAVAILABLE, -1, "Unsupported inquire type");
-    }
-
-
-    // functions not belong to SPI
-    private void setSessionKey(EncryptionKey encryptionKey, int keyComesFrom) {
-        this.sessionKey = encryptionKey;
-        this.keyComesFrom = keyComesFrom;
-    }
-
-    public int getKeyComesFrom() {
-        return keyComesFrom;
-    }
-
-    private EncryptionKey getSessionKey() {
-        return sessionKey;
-    }
-
-    private void setTicketFlags(TicketFlags ticketFlags) {
-        this.ticketFlags = ticketFlags;
-    }
-
-    private AuthorizationData authData;
-    private void setAuthData(AuthorizationData authData) {
-        this.authData = authData;
-    }
-
-
-    private int mySequenceNumber;
-    private int peerSequenceNumber;
-    private Object mySequenceNumberLock;
-    private Object peerSequenceNumberLock;
-
-    public void setMySequenceNumber(int sequenceNumber) {
-        synchronized (mySequenceNumberLock) {
-            mySequenceNumber = sequenceNumber;
-        }
-    }
-
-    public int incMySequenceNumber() {
-        synchronized (mySequenceNumberLock) {
-            return mySequenceNumber++;
-        }
-    }
-
-    public void setPeerSequenceNumber(int sequenceNumber) {
-        synchronized (peerSequenceNumberLock) {
-            peerSequenceNumber = sequenceNumber;
-        }
-    }
-
-    public int incPeerSequenceNumber() {
-        synchronized (peerSequenceNumberLock) {
-            return peerSequenceNumber++;
-        }
-    }
-
-    public KerbyGssEncryptor getGssEncryptor() {
-        return gssEncryptor;
-    }
-}