You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by pl...@apache.org on 2016/05/11 05:43:46 UTC
directory-kerby git commit: DIRKRB-565 Implement Gss tokens defined
in RFC 4121. Contributed by Wei.
Repository: directory-kerby
Updated Branches:
refs/heads/gssapi 33acad0b4 -> e680dab2b
DIRKRB-565 Implement Gss tokens defined in RFC 4121. Contributed by Wei.
Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/e680dab2
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/e680dab2
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/e680dab2
Branch: refs/heads/gssapi
Commit: e680dab2b3485cd6d7f3accb5c17fec279adf0ae
Parents: 33acad0
Author: plusplusjiajia <ji...@intel.com>
Authored: Wed May 11 13:48:55 2016 +0800
Committer: plusplusjiajia <ji...@intel.com>
Committed: Wed May 11 13:48:55 2016 +0800
----------------------------------------------------------------------
.../kerberos/kerb/gssapi/krb5/KerbyContext.java | 10 +
.../kerb/gssapi/krb5/KerbyGssEncryptor.java | 138 +++++++++
.../kerb/gssapi/krb5/KerbyGssTokenBase.java | 59 ++++
.../kerb/gssapi/krb5/KerbyGssTokenV2.java | 282 +++++++++++++++++++
.../kerberos/kerb/gssapi/krb5/KerbyUtil.java | 1 -
.../kerberos/kerb/gssapi/krb5/MicTokenV2.java | 94 +++++++
.../kerberos/kerb/gssapi/krb5/WrapTokenV2.java | 153 ++++++++++
7 files changed, 736 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/e680dab2/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
index e017683..b450cc9 100644
--- 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
@@ -86,6 +86,8 @@ public class KerbyContext implements GSSContextSpi {
private TicketFlags ticketFlags;
private ApReq outApReq;
+ private KerbyGssEncryptor gssEncryptor;
+
// Called on initiator's side.
public KerbyContext(GSSCaller caller, KerbyNameElement peerName, KerbyCredElement myCred,
int lifeTime)
@@ -294,11 +296,13 @@ public class KerbyContext implements GSSContextSpi {
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;
}
@@ -389,6 +393,8 @@ public class KerbyContext implements GSSContextSpi {
ret = verifyClientToken(acceptCred, is, mechTokenSize);
}
+ gssEncryptor = new KerbyGssEncryptor(getSessionKey());
+
myCred = null;
ctxState = STATE_ESTABLISHED;
}
@@ -607,4 +613,8 @@ public class KerbyContext implements GSSContextSpi {
return peerSequenceNumber++;
}
}
+
+ public KerbyGssEncryptor getGssEncryptor() {
+ return gssEncryptor;
+ }
}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/e680dab2/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssEncryptor.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssEncryptor.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssEncryptor.java
new file mode 100644
index 0000000..d65346b
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssEncryptor.java
@@ -0,0 +1,138 @@
+/**
+ * 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.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.crypto.CheckSumHandler;
+import org.apache.kerby.kerberos.kerb.crypto.CheckSumTypeHandler;
+import org.apache.kerby.kerberos.kerb.crypto.EncTypeHandler;
+import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
+import org.apache.kerby.kerberos.kerb.type.base.CheckSumType;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
+import org.ietf.jgss.GSSException;
+
+/**
+ * This class implements encryption related function used in GSS tokens
+ */
+public class KerbyGssEncryptor {
+
+ private EncryptionKey encKey;
+ private boolean isV2 = false;
+
+ public KerbyGssEncryptor(EncryptionKey key) throws GSSException {
+ encKey = key;
+ EncryptionType keyType = key.getKeyType();
+ // TODO: add support for other algorithms
+ if (keyType == EncryptionType.AES128_CTS_HMAC_SHA1_96
+ || keyType == EncryptionType.AES256_CTS_HMAC_SHA1_96) {
+ isV2 = true;
+ } else {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Invalid encryption type: " + key.getKeyType().getDisplayName());
+ }
+ }
+
+ /**
+ * Return true if it is encryption type defined in RFC 4121
+ * @return
+ */
+ public boolean isV2() {
+ return isV2;
+ }
+
+ public byte[] encryptData(byte[] tokenHeader, byte[] data,
+ int offset, int len, int keyUsage) throws GSSException {
+ byte[] ret;
+ byte[] toProcess = new byte[tokenHeader.length + len];
+ System.arraycopy(data, offset, toProcess, 0, len);
+ System.arraycopy(tokenHeader, 0, toProcess, len, tokenHeader.length);
+
+ ret = encryptData(toProcess, keyUsage);
+ return ret;
+ }
+
+ public byte[] encryptData(byte[] toProcess, int keyUsage) throws GSSException {
+ byte[] ret;
+ try {
+ EncTypeHandler encHandler = EncryptionHandler.getEncHandler(encKey.getKeyType());
+ ret = encHandler.encrypt(toProcess, encKey.getKeyData(), keyUsage);
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
+ }
+ return ret;
+ }
+
+ public byte[] decryptData(byte[] dataEncrypted, int keyUsage) throws GSSException {
+ byte[] ret;
+ try {
+ EncTypeHandler encHandler = EncryptionHandler.getEncHandler(encKey.getKeyType());
+ ret = encHandler.decrypt(dataEncrypted, encKey.getKeyData(), keyUsage);
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
+ }
+ return ret;
+ }
+
+ public byte[] calculateCheckSum(byte[] header, byte[] data, int offset, int len, int keyUsage)
+ throws GSSException {
+ int totalLen = len + (header == null ? 0 : header.length);
+ byte[] buffer = new byte[totalLen];
+ System.arraycopy(data, offset, buffer, 0, len);
+ if (header != null) {
+ System.arraycopy(header, 0, buffer, len, header.length);
+ }
+
+ try {
+ return getCheckSumHandler().checksumWithKey(buffer, encKey.getKeyData(), keyUsage);
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Exception in checksum calculation:" + encKey.getKeyType().getName());
+ }
+ }
+
+ private CheckSumTypeHandler getCheckSumHandler() throws GSSException {
+ CheckSumType checkSumType;
+ if (encKey.getKeyType() == EncryptionType.AES128_CTS_HMAC_SHA1_96) {
+ checkSumType = CheckSumType.HMAC_SHA1_96_AES128;
+ } else if (encKey.getKeyType() == EncryptionType.AES256_CTS_HMAC_SHA1_96) {
+ checkSumType = CheckSumType.HMAC_SHA1_96_AES256;
+ } else {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Unsupported checksum encryption type:" + encKey.getKeyType().getName());
+ }
+ try {
+ return CheckSumHandler.getCheckSumHandler(checkSumType);
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Unsupported checksum type:" + checkSumType.getName());
+ }
+ }
+
+ /**
+ * Get the size of the corresponding checksum algorithm
+ * @return
+ * @throws GSSException
+ */
+ public int getCheckSumSize() throws GSSException {
+ return getCheckSumHandler().cksumSize();
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/e680dab2/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenBase.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenBase.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenBase.java
new file mode 100644
index 0000000..ae5122f
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenBase.java
@@ -0,0 +1,59 @@
+/**
+ * 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;
+
+
+public abstract class KerbyGssTokenBase {
+ public static final int TOKEN_WRAP_V1 = 0x201;
+ public static final int TOKEN_MIC_V1 = 0x101;
+ public static final int TOKEN_WRAP_V2 = 0x504;
+ public static final int TOKEN_MIC_V2 = 0x404;
+
+ public void writeBigEndian(byte[] buf, int offset, int value) {
+ buf[offset] = (byte) (value >>> 24);
+ buf[offset + 1] = (byte) (value >>> 16);
+ buf[offset + 2] = (byte) (value >>> 8);
+ buf[offset + 3] = (byte) (value);
+ }
+
+ public int readBigEndian(byte[] buf, int offset) {
+ int value = 0;
+ value += (buf[offset] & 0xFF) << 24;
+ value += (buf[offset + 1] & 0xFF) << 16;
+ value += (buf[offset + 2] & 0xFF) << 8;
+ value += buf[offset + 3] & 0xFF;
+ return value;
+ }
+
+ /**
+ *
+ * @param buf
+ * @param offset
+ * @param len should not be larger than sizeof(int)
+ * @return
+ */
+ public int readBigEndian(byte[] buf, int offset, int len) {
+ int value = 0;
+ for (int i = 0; i < len; i++) {
+ value += (buf[offset + i] & 0xFF) << 8;
+ }
+ return value;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/e680dab2/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenV2.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenV2.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenV2.java
new file mode 100644
index 0000000..f2d220a
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenV2.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.gssapi.krb5;
+
+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 KerbyGssTokenV2 extends KerbyGssTokenBase {
+ 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 KerbyGssEncryptor encryptor;
+
+
+ // Create a new token
+ KerbyGssTokenV2(int tokenType, KerbyContext context) throws GSSException {
+ initialize(tokenType, context, false);
+ }
+
+ private void initialize(int tokenType, KerbyContext context, boolean reconstruct) throws GSSException {
+ this.tokenType = tokenType;
+ this.isInitiator = context.isInitiator();
+ this.acceptorSubKey = context.getKeyComesFrom() == KerbyContext.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
+ KerbyGssTokenV2(int tokenType, KerbyContext 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
+ KerbyGssTokenV2(int tokenType, KerbyContext 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/e680dab2/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyUtil.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyUtil.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyUtil.java
index a5abb46..081788b 100644
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyUtil.java
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyUtil.java
@@ -21,7 +21,6 @@ package org.apache.kerby.kerberos.kerb.gssapi.krb5;
import org.apache.kerby.kerberos.kerb.KrbException;
import org.apache.kerby.kerberos.kerb.client.KrbClientBase;
-import org.apache.kerby.kerberos.kerb.request.ApRequest;
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;
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/e680dab2/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/MicTokenV2.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/MicTokenV2.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/MicTokenV2.java
new file mode 100644
index 0000000..7ba27ab
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/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.gssapi.krb5;
+
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.MessageProp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class MicTokenV2 extends KerbyGssTokenV2 {
+ private MessageProp prop;
+
+ // This is called to construct MicToken from user input
+ MicTokenV2(KerbyContext 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(KerbyContext 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/e680dab2/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/WrapTokenV2.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/WrapTokenV2.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/WrapTokenV2.java
new file mode 100644
index 0000000..3a128a9
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/WrapTokenV2.java
@@ -0,0 +1,153 @@
+/**
+ * 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 org.ietf.jgss.MessageProp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+
+public class WrapTokenV2 extends KerbyGssTokenV2 {
+ private MessageProp prop;
+
+ // Generate a token from user input data
+ WrapTokenV2(KerbyContext 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(KerbyContext 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(KerbyContext 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());
+ }
+ }
+
+ static int getSizeLimit(int qop, boolean confReq, int maxTokSize) {
+ return maxTokSize; // TODO: to be implemented
+ }
+}