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/24 11:50:47 UTC
[06/18] directory-kerby git commit: Revert "Refactoring the package
and structure"
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyCredElement.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyCredElement.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyCredElement.java
new file mode 100644
index 0000000..c52b3ea
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyCredElement.java
@@ -0,0 +1,80 @@
+/**
+ * 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.Oid;
+import sun.security.jgss.GSSCaller;
+import sun.security.jgss.spi.GSSCredentialSpi;
+import sun.security.jgss.spi.GSSNameSpi;
+
+import java.security.Provider;
+
+public abstract class KerbyCredElement implements GSSCredentialSpi {
+
+ static final Oid KRB5_OID = createOid("1.2.840.113554.1.2.2");
+
+ protected GSSCaller caller;
+ protected KerbyNameElement name;
+ protected int initLifeTime;
+ protected int accLifeTime;
+
+ KerbyCredElement(GSSCaller caller, KerbyNameElement name) {
+ this.caller = caller;
+ this.name = name;
+ }
+
+ public Provider getProvider() {
+ return new org.apache.kerby.kerberos.kerb.gssapi.Provider();
+ }
+
+ public void dispose() throws GSSException {
+ }
+
+ public GSSNameSpi getName() throws GSSException {
+ return name;
+ }
+
+ public int getInitLifetime() throws GSSException {
+ return initLifeTime;
+ }
+
+ public int getAcceptLifetime() throws GSSException {
+ return accLifeTime;
+ }
+
+ public Oid getMechanism() {
+ return KRB5_OID;
+ }
+
+ public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
+ throw new GSSException(GSSException.FAILURE, -1, "Unsupported feature"); // TODO:
+ }
+
+ private static Oid createOid(String oidStr) {
+ Oid retVal;
+ try {
+ retVal = new Oid(oidStr);
+ } catch (GSSException e) {
+ retVal = null; // get rid of blank catch block warning
+ }
+ return retVal;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/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..9aff63e
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssEncryptor.java
@@ -0,0 +1,388 @@
+/**
+ * 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.crypto.cksum.provider.Md5Provider;
+import org.apache.kerby.kerberos.kerb.crypto.enc.provider.DesProvider;
+import org.apache.kerby.kerberos.kerb.crypto.enc.provider.Rc4Provider;
+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;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * This class implements encryption related function used in GSS tokens
+ */
+public class KerbyGssEncryptor {
+
+ private final EncryptionKey encKey;
+ private final EncryptionType encKeyType; // The following two variables used for convenience
+ private final byte[] encKeyBytes;
+
+ private CheckSumType checkSumTypeDef;
+ private int checkSumSize;
+
+ private boolean isV2 = false;
+ private int sgnAlg = 0xFFFF;
+ private int sealAlg = 0xFFFF;
+ private boolean isArcFourHmac = false;
+
+ private static final byte[] IV_ZEROR_8B = new byte[8];
+
+ public KerbyGssEncryptor(EncryptionKey key) throws GSSException {
+ encKey = key;
+ encKeyBytes = encKey.getKeyData();
+ encKeyType = key.getKeyType();
+
+ if (encKeyType == EncryptionType.AES128_CTS_HMAC_SHA1_96) {
+ checkSumSize = 12;
+ checkSumTypeDef = CheckSumType.HMAC_SHA1_96_AES128;
+ isV2 = true;
+ } else if (encKeyType == EncryptionType.AES256_CTS_HMAC_SHA1_96) {
+ checkSumSize = 12;
+ checkSumTypeDef = CheckSumType.HMAC_SHA1_96_AES256;
+ isV2 = true;
+ } else if (encKeyType == EncryptionType.DES_CBC_CRC || encKeyType == EncryptionType.DES_CBC_MD5) {
+ sgnAlg = KerbyGssTokenV1.SGN_ALG_DES_MAC_MD5;
+ sealAlg = KerbyGssTokenV1.SEAL_ALG_DES;
+ checkSumSize = 8;
+ } else if (encKeyType == EncryptionType.DES3_CBC_SHA1) {
+ sgnAlg = KerbyGssTokenV1.SGN_ALG_HMAC_SHA1_DES3_KD;
+ sealAlg = KerbyGssTokenV1.SEAL_ALG_DES3_KD;
+ checkSumSize = 20;
+ } else if (encKeyType == EncryptionType.ARCFOUR_HMAC) {
+ sgnAlg = KerbyGssTokenV1.SGN_ALG_RC4_HMAC;
+ sealAlg = KerbyGssTokenV1.SEAL_ALG_RC4_HMAC;
+ checkSumSize = 16;
+ isArcFourHmac = true;
+ } else {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Invalid encryption type: " + encKeyType.getDisplayName());
+ }
+ }
+
+ /**
+ * Return true if it is encryption type defined in RFC 4121
+ * @return
+ */
+ public boolean isV2() {
+ return isV2;
+ }
+
+ public int getSgnAlg() {
+ return sgnAlg;
+ }
+
+ public int getSealAlg() {
+ return sealAlg;
+ }
+
+ public boolean isArcFourHmac() {
+ return isArcFourHmac;
+ }
+
+ 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 CheckSumHandler.getCheckSumHandler(checkSumTypeDef)
+ .checksumWithKey(buffer, encKey.getKeyData(), keyUsage);
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Exception in checksum calculation:" + e.getMessage());
+ }
+ }
+
+ /**
+ * Get the size of the corresponding checksum algorithm
+ * @return
+ * @throws GSSException
+ */
+ public int getCheckSumSize() throws GSSException {
+ return checkSumSize;
+ }
+
+
+ private void addPadding(int paddingLen, byte[] outBuf, int offset) {
+ for (int i = 0; i < paddingLen; i++) {
+ outBuf[offset + i] = (byte) paddingLen;
+ }
+ }
+
+ private byte[] getFirstBytes(byte[] src, int len) {
+ if (len < src.length) {
+ byte[] ret = new byte[len];
+ System.arraycopy(src, 0, ret, 0, len);
+ return ret;
+ }
+ return src;
+ }
+
+ private byte[] getKeyBytesWithLength(int len) {
+ return getFirstBytes(encKeyBytes, len);
+ }
+
+ public byte[] calculateCheckSum(byte[] confounder, byte[] header,
+ byte[] data, int offset, int len, int paddingLen, boolean isMic)
+ throws GSSException {
+ byte[] ret;
+ int keyUsage = KerbyGssTokenV1.KG_USAGE_SIGN;
+ CheckSumTypeHandler handler;
+
+ int keySize;
+ byte[] key;
+ byte[] toProc;
+ int toOffset;
+ int toLen = (confounder == null ? 0 : confounder.length)
+ + (header == null ? 0 : header.length) + len + paddingLen;
+ if (toLen == len) {
+ toProc = data;
+ toOffset = offset;
+ } else {
+ toOffset = 0;
+ int idx = 0;
+ toProc = new byte[toLen];
+
+ if (header != null) {
+ System.arraycopy(header, 0, toProc, idx, header.length);
+ idx += header.length;
+ }
+
+ if (confounder != null) {
+ System.arraycopy(confounder, 0, toProc, idx, confounder.length);
+ idx += confounder.length;
+ }
+
+ System.arraycopy(data, offset, toProc, idx, len);
+ addPadding(paddingLen, toProc, len + idx);
+ }
+
+ CheckSumType chksumType;
+ try {
+ switch (sgnAlg) {
+ case KerbyGssTokenV1.SGN_ALG_DES_MAC_MD5:
+ Md5Provider md5Provider = new Md5Provider();
+ md5Provider.hash(toProc);
+ toProc = md5Provider.output();
+
+ case KerbyGssTokenV1.SGN_ALG_DES_MAC:
+ DesProvider desProvider = new DesProvider();
+ return desProvider.cbcMac(encKeyBytes, IV_ZEROR_8B, toProc);
+
+ case KerbyGssTokenV1.SGN_ALG_HMAC_SHA1_DES3_KD:
+ chksumType = CheckSumType.HMAC_SHA1_DES3_KD;
+ break;
+ case KerbyGssTokenV1.SGN_ALG_RC4_HMAC:
+ chksumType = CheckSumType.MD5_HMAC_ARCFOUR;
+ if (isMic) {
+ keyUsage = KerbyGssTokenV1.KG_USAGE_MS_SIGN;
+ }
+ break;
+ case KerbyGssTokenV1.SGN_ALG_MD25:
+ throw new GSSException(GSSException.FAILURE, -1, "CheckSum not implemented for SGN_ALG_MD25");
+ default:
+ throw new GSSException(GSSException.FAILURE, -1, "CheckSum not implemented for sgnAlg=" + sgnAlg);
+ }
+ handler = CheckSumHandler.getCheckSumHandler(chksumType);
+ keySize = handler.keySize();
+ key = getKeyBytesWithLength(keySize);
+ ret = handler.checksumWithKey(toProc, toOffset, toLen, key, keyUsage);
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Exception in checksum calculation sgnAlg = " + sgnAlg + " : " + e.getMessage());
+ }
+ return ret;
+ }
+
+ public byte[] encryptSequenceNumber(byte[] seqBytes, byte[] ivSrc, boolean encrypt)
+ throws GSSException {
+ EncTypeHandler handler;
+ try {
+ switch (sgnAlg) {
+ case KerbyGssTokenV1.SGN_ALG_DES_MAC_MD5:
+ case KerbyGssTokenV1.SGN_ALG_DES_MAC:
+ DesProvider desProvider = new DesProvider();
+ byte[] data = seqBytes.clone();
+ if (encrypt) {
+ desProvider.encrypt(encKeyBytes, ivSrc, data);
+ } else {
+ desProvider.decrypt(encKeyBytes, ivSrc, data);
+ }
+ return data;
+ case KerbyGssTokenV1.SGN_ALG_HMAC_SHA1_DES3_KD:
+ handler = EncryptionHandler.getEncHandler(EncryptionType.DES3_CBC_SHA1_KD);
+ break;
+ case KerbyGssTokenV1.SGN_ALG_RC4_HMAC:
+ return encryptArcFourHmac(seqBytes, getKeyBytesWithLength(16), getFirstBytes(ivSrc, 8), encrypt);
+ case KerbyGssTokenV1.SGN_ALG_MD25:
+ throw new GSSException(GSSException.FAILURE, -1, "EncSeq not implemented for SGN_ALG_MD25");
+ default:
+ throw new GSSException(GSSException.FAILURE, -1, "EncSeq not implemented for sgnAlg=" + sgnAlg);
+ }
+ int keySize = handler.keySize();
+ byte[] key = getKeyBytesWithLength(keySize);
+ int ivLen = handler.encProvider().blockSize();
+ byte[] iv = getFirstBytes(ivSrc, ivLen);
+ if (encrypt) {
+ return handler.encryptRaw(seqBytes, key, iv, KerbyGssTokenV1.KG_USAGE_SEQ);
+ } else {
+ return handler.decryptRaw(seqBytes, key, iv, KerbyGssTokenV1.KG_USAGE_SEQ);
+ }
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Exception in encrypt seq number sgnAlg = " + sgnAlg + " : " + e.getMessage());
+ }
+ }
+
+ private byte[] getHmacMd5(byte[] key, byte[] salt) throws GSSException {
+ try {
+ SecretKey secretKey = new SecretKeySpec(key, "HmacMD5");
+ Mac mac = Mac.getInstance("HmacMD5");
+ mac.init(secretKey);
+ return mac.doFinal(salt);
+ } catch (Exception e) {
+ throw new GSSException(GSSException.FAILURE, -1, "Get HmacMD5 failed: " + e.getMessage());
+ }
+ }
+
+ private byte[] encryptArcFourHmac(byte[] data, byte[] key, byte[] iv, boolean encrypt)
+ throws GSSException {
+ byte[] sk1 = getHmacMd5(key, new byte[4]);
+ byte[] sk2 = getHmacMd5(sk1, iv);
+ Rc4Provider provider = new Rc4Provider();
+ try {
+ byte[] ret = data.clone();
+ if (encrypt) {
+ provider.encrypt(sk2, ret);
+ } else {
+ provider.decrypt(sk2, ret);
+ }
+ return ret;
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "En/Decrypt sequence failed for ArcFourHmac: " + e.getMessage());
+ }
+ }
+
+ private byte[] encryptDataArcFourHmac(byte[] data, byte[] key, byte[] seqNum, boolean encrypt) throws GSSException {
+ byte[] dataKey = new byte[key.length];
+ for (int i = 0; i <= 15; i++) {
+ dataKey[i] = (byte) (key[i] ^ 0xF0);
+ }
+ return encryptArcFourHmac(data, dataKey, seqNum, encrypt);
+ }
+
+ public byte[] encryptTokenV1(byte[] confounder, byte[] data, int offset, int len,
+ int paddingLen, byte[] seqNumber, boolean encrypt) throws GSSException {
+ byte[] toProc;
+ if (encrypt) {
+ int toLen = (confounder == null ? 0 : confounder.length) + len + paddingLen;
+ int index = 0;
+ toProc = new byte[toLen];
+ if (confounder != null) {
+ System.arraycopy(confounder, 0, toProc, 0, confounder.length);
+ index += confounder.length;
+ }
+ System.arraycopy(data, offset, toProc, index, len);
+ addPadding(paddingLen, toProc, index + len);
+ } else {
+ toProc = data;
+ if (data.length != len) {
+ toProc = new byte[len];
+ System.arraycopy(data, offset, toProc, 0, len);
+ }
+ }
+ EncTypeHandler handler;
+ try {
+ switch (sealAlg) {
+ case KerbyGssTokenV1.SEAL_ALG_DES:
+ handler = EncryptionHandler.getEncHandler(EncryptionType.DES_CBC_MD5);
+ break;
+ case KerbyGssTokenV1.SEAL_ALG_DES3_KD:
+ handler = EncryptionHandler.getEncHandler(EncryptionType.DES3_CBC_SHA1_KD);
+ break;
+ case KerbyGssTokenV1.SEAL_ALG_RC4_HMAC:
+ return encryptDataArcFourHmac(toProc, getKeyBytesWithLength(16), seqNumber, encrypt);
+ default:
+ throw new GSSException(GSSException.FAILURE, -1, "Unknown encryption type sealAlg = " + sealAlg);
+ }
+
+ int keySize = handler.keySize();
+ byte[] key = getKeyBytesWithLength(keySize);
+ if (encrypt) {
+ return handler.encryptRaw(toProc, key, KerbyGssTokenV1.KG_USAGE_SEAL);
+ } else {
+ return handler.decryptRaw(toProc, key, KerbyGssTokenV1.KG_USAGE_SEAL);
+ }
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Exception in encrypt data sealAlg = " + sealAlg + " : " + e.getMessage());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/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/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenV1.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenV1.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenV1.java
new file mode 100644
index 0000000..6b1a2c7
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyGssTokenV1.java
@@ -0,0 +1,319 @@
+/**
+ * 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 sun.security.jgss.GSSHeader;
+import sun.security.util.ObjectIdentifier;
+
+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 1964 and its updates
+ *
+ * The GSS Wrap token has the following format:
+ *
+ * Byte no Name Description
+ * 0..1 TOK_ID 0201
+ *
+ * 2..3 SGN_ALG Checksum algorithm indicator.
+ * 00 00 DES MAC MD5
+ * 01 00 MD2.5
+ * 02 00 DES MAC
+ * 04 00 HMAC SHA1 DES3-KD
+ * 11 00 RC4-HMAC used by Microsoft Windows, RFC 4757
+ * 4..5 SEAL_ALG ff ff none
+ * 00 00 DES
+ * 02 00 DES3-KD
+ * 10 00 RC4-HMAC
+ * 6..7 Filler FF FF
+ * 8..15 SND_SEQ Encrypted sequence number field.
+ * 16..23 SNG_CKSUM Checksum of plaintext padded data,
+ * calculated according to algorithm
+ * specified in SGN_ALG field.
+ * 24.. Data Encrypted or plaintext padded data
+ *
+ *
+ *
+ * Use of the GSS MIC token has the following format:
+
+ * Byte no Name Description
+ * 0..1 TOK_ID 0101
+ * 2..3 SGN_ALG Integrity algorithm indicator.
+ * 4..7 Filler Contains ff ff ff ff
+ * 8..15 SND_SEQ Sequence number field.
+ * 16..23 SGN_CKSUM Checksum of "to-be-signed data",
+ * calculated according to algorithm
+ * specified in SGN_ALG field.
+ *
+ */
+abstract class KerbyGssTokenV1 extends KerbyGssTokenBase {
+ // SGN ALG
+ public static final int SGN_ALG_DES_MAC_MD5 = 0;
+ public static final int SGN_ALG_MD25 = 0x0100;
+ public static final int SGN_ALG_DES_MAC = 0x0200;
+ public static final int SGN_ALG_HMAC_SHA1_DES3_KD = 0x0400;
+ public static final int SGN_ALG_RC4_HMAC = 0x1100;
+
+ // SEAL ALG
+ public static final int SEAL_ALG_NONE = 0xFFFF;
+ public static final int SEAL_ALG_DES = 0x0; // "DES/CBC/NoPadding"
+ public static final int SEAL_ALG_DES3_KD = 0x0200;
+ public static final int SEAL_ALG_RC4_HMAC = 0x1000;
+
+ public static final int KG_USAGE_SEAL = 22;
+ public static final int KG_USAGE_SIGN = 23;
+ public static final int KG_USAGE_SEQ = 24;
+ public static final int KG_USAGE_MS_SIGN = 15;
+
+ private boolean isInitiator;
+ private boolean confState;
+ private int sequenceNumber;
+
+ protected KerbyGssEncryptor encryptor;
+
+ private GSSHeader gssHeader;
+
+ public static final int TOKEN_HEADER_COMM_SIZE = 8;
+ public static final int TOKEN_HEADER_SEQ_SIZE = 8;
+
+ // Token commHeader data
+ private int tokenType;
+ private byte[] commHeader = new byte[TOKEN_HEADER_COMM_SIZE];
+ private int sgnAlg;
+ private int sealAlg;
+
+ private byte[] plainSequenceBytes;
+ private byte[] encryptedSequenceNumber = new byte[TOKEN_HEADER_SEQ_SIZE];
+ private byte[] checkSum;
+ private int checkSumSize;
+
+ protected int reconHeaderLen; // only used for certain reason
+
+ public static ObjectIdentifier objId;
+
+ static {
+ try {
+ objId = new ObjectIdentifier("1.2.840.113554.1.2.2");
+ } catch (IOException ioe) { // NOPMD
+ }
+ }
+
+ protected int getTokenHeaderSize() {
+ return TOKEN_HEADER_COMM_SIZE + TOKEN_HEADER_SEQ_SIZE + checkSumSize;
+ }
+
+ protected byte[] getPlainSequenceBytes() {
+ byte[] ret = new byte[4];
+ ret[0] = plainSequenceBytes[0];
+ ret[1] = plainSequenceBytes[1];
+ ret[2] = plainSequenceBytes[2];
+ ret[3] = plainSequenceBytes[3];
+ return ret;
+ }
+
+ // Generate a new token
+ KerbyGssTokenV1(int tokenType, KerbyContext context) throws GSSException {
+ initialize(tokenType, context, false);
+ createTokenHeader();
+ }
+
+ // Reconstruct a token
+ KerbyGssTokenV1(int tokenType, KerbyContext context, MessageProp prop,
+ byte[] token, int offset, int size) throws GSSException {
+ int proxLen = size > 64 ? 64 : size;
+ InputStream is = new ByteArrayInputStream(token, offset, proxLen);
+ reconstructInitializaion(tokenType, context, prop, is);
+ reconHeaderLen = gssHeader.getLength() + getTokenHeaderSize();
+ }
+
+ // Reconstruct a token
+ KerbyGssTokenV1(int tokenType, KerbyContext context, MessageProp prop, InputStream is) throws GSSException {
+ reconstructInitializaion(tokenType, context, prop, is);
+ }
+
+ private void reconstructInitializaion(int tokenType, KerbyContext context, MessageProp prop, InputStream is)
+ throws GSSException {
+ initialize(tokenType, context, true);
+ if (!confState) {
+ prop.setPrivacy(false);
+ }
+
+ try {
+ gssHeader = new GSSHeader(is);
+ } catch (IOException e) {
+ throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token:" + e.getMessage());
+ }
+
+ if (!gssHeader.getOid().equals((Object) objId)) {
+ throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token OID");
+ }
+
+ reconstructTokenHeader(is, prop);
+ }
+
+ private void initialize(int tokenType,
+ KerbyContext context,
+ boolean reconstruct) throws GSSException {
+ this.tokenType = tokenType;
+ this.isInitiator = context.isInitiator();
+ this.confState = context.getConfState();
+ this.encryptor = context.getGssEncryptor();
+ this.checkSumSize = encryptor.getCheckSumSize();
+ if (!reconstruct) {
+ this.sequenceNumber = context.incMySequenceNumber();
+ } else {
+ checkSum = new byte[checkSumSize];
+ }
+ }
+
+ protected void calcPrivacyInfo(MessageProp prop, byte[] confounder, byte[] data,
+ int dataOffset, int dataLength, int paddingLen) throws GSSException {
+ prop.setQOP(0);
+ if (!confState) {
+ prop.setPrivacy(false);
+ }
+
+ checkSum = calcCheckSum(confounder, commHeader, data, dataOffset, dataLength, paddingLen);
+ encryptSequenceNumber();
+ }
+
+ protected void verifyToken(byte[] confounder, byte[] data, int dataOffset, int dataLength, int paddingLen)
+ throws GSSException {
+ byte[] sum = calcCheckSum(confounder, commHeader, data, dataOffset, dataLength, paddingLen);
+ if (!MessageDigest.isEqual(checkSum, sum)) {
+ throw new GSSException(GSSException.BAD_MIC, -1,
+ "Corrupt token checksum for " + (tokenType == TOKEN_MIC_V1 ? "Mic" : "Wrap") + "TokenV1");
+ }
+ }
+
+ private byte[] calcCheckSum(byte[] confounder, byte[] header, byte[] data,
+ int dataOffset, int dataLength, int paddingLen) throws GSSException {
+ return encryptor.calculateCheckSum(confounder, header, data, dataOffset, dataLength, paddingLen,
+ tokenType == TOKEN_MIC_V1);
+ }
+
+ private void encryptSequenceNumber() throws GSSException {
+ plainSequenceBytes = new byte[8];
+ if (encryptor.isArcFourHmac()) {
+ writeBigEndian(plainSequenceBytes, 0, sequenceNumber);
+ } else {
+ plainSequenceBytes[0] = (byte) sequenceNumber;
+ plainSequenceBytes[1] = (byte) (sequenceNumber >>> 8);
+ plainSequenceBytes[2] = (byte) (sequenceNumber >>> 16);
+ plainSequenceBytes[3] = (byte) (sequenceNumber >>> 24);
+ }
+
+ // Hex 0 - sender is the context initiator, Hex FF - sender is the context acceptor
+ if (!isInitiator) {
+ plainSequenceBytes[4] = (byte) 0xFF;
+ plainSequenceBytes[5] = (byte) 0xFF;
+ plainSequenceBytes[6] = (byte) 0xFF;
+ plainSequenceBytes[7] = (byte) 0xFF;
+ }
+
+ encryptedSequenceNumber = encryptor.encryptSequenceNumber(plainSequenceBytes, checkSum, true);
+ }
+
+ public void encodeHeader(OutputStream os) throws GSSException, IOException {
+ // | GSSHeader | TokenHeader |
+ GSSHeader gssHeader = new GSSHeader(objId, getTokenSizeWithoutGssHeader());
+ gssHeader.encode(os);
+ os.write(commHeader);
+ os.write(encryptedSequenceNumber);
+ os.write(checkSum);
+ }
+
+ private void createTokenHeader() {
+ commHeader[0] = (byte) (tokenType >>> 8);
+ commHeader[1] = (byte) tokenType;
+
+ sgnAlg = encryptor.getSgnAlg();
+ commHeader[2] = (byte) (sgnAlg >>> 8);
+ commHeader[3] = (byte) sgnAlg;
+
+ if (tokenType == TOKEN_WRAP_V1) {
+ sealAlg = encryptor.getSealAlg();
+ commHeader[4] = (byte) (sealAlg >>> 8);
+ commHeader[5] = (byte) sealAlg;
+ } else {
+ commHeader[4] = (byte) 0xFF;
+ commHeader[5] = (byte) 0xFF;
+ }
+
+ commHeader[6] = (byte) 0xFF;
+ commHeader[7] = (byte) 0xFF;
+ }
+
+ // Re-construct token commHeader
+ private void reconstructTokenHeader(InputStream is, MessageProp prop) throws GSSException {
+ try {
+ if (is.read(commHeader) != commHeader.length
+ || is.read(encryptedSequenceNumber) != encryptedSequenceNumber.length
+ || is.read(checkSum) != checkSum.length) {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Insufficient in reconstruct token header");
+ }
+ initTokenHeader(commHeader, prop);
+
+ plainSequenceBytes = encryptor.encryptSequenceNumber(encryptedSequenceNumber, checkSum, false);
+ byte dirc = isInitiator ? (byte) 0xFF : 0;
+ // Hex 0 - sender is the context initiator, Hex FF - sender is the context acceptor
+ if (!(plainSequenceBytes[4] == dirc && plainSequenceBytes[5] == dirc
+ && plainSequenceBytes[6] == dirc && plainSequenceBytes[7] == dirc)) {
+ throw new GSSException(GSSException.BAD_MIC, -1,
+ "Corrupt token sequence for " + (tokenType == TOKEN_MIC_V1 ? "Mic" : "Wrap") + "TokenV1");
+ }
+ } catch (IOException e) {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Error in reconstruct token header:" + e.getMessage());
+ }
+ }
+
+ private void initTokenHeader(byte[] tokenBytes, MessageProp prop) throws GSSException {
+ int tokenIDRecv = (((int) tokenBytes[0]) << 8) + tokenBytes[1];
+ if (tokenType != tokenIDRecv) {
+ throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
+ "Token ID should be " + tokenType + " instead of " + tokenIDRecv);
+ }
+
+ sgnAlg = (((int) tokenBytes[2]) << 8) + tokenBytes[3];
+ sealAlg = (((int) tokenBytes[4]) << 8) + tokenBytes[5];
+
+ if (tokenBytes[6] != (byte) 0xFF || tokenBytes[7] != (byte) 0xFF) {
+ throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token head filler");
+ }
+
+ prop.setQOP(0);
+ prop.setPrivacy(sealAlg != SEAL_ALG_NONE);
+ }
+
+ protected GSSHeader getGssHeader() {
+ return gssHeader;
+ }
+
+ abstract int getTokenSizeWithoutGssHeader();
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/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/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyInitCred.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyInitCred.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyInitCred.java
new file mode 100644
index 0000000..d04f915
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyInitCred.java
@@ -0,0 +1,53 @@
+/**
+ * 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.KerberosTicket;
+
+public final class KerbyInitCred extends KerbyCredElement {
+
+ public KerberosTicket ticket;
+
+ private KerbyInitCred(GSSCaller caller, KerbyNameElement name, KerberosTicket ticket, int lifeTime) {
+ super(caller, name);
+ this.ticket = ticket;
+ this.initLifeTime = lifeTime;
+ }
+
+ public static KerbyInitCred getInstance(GSSCaller caller, KerbyNameElement name, int lifeTime) throws GSSException {
+ KerberosTicket ticket = CredUtils.getKerberosTicketFromContext(caller, name.getPrincipalName().getName(), null);
+ return new KerbyInitCred(caller, name, ticket, lifeTime);
+ }
+
+ public boolean isInitiatorCredential() throws GSSException {
+ return true;
+ }
+
+ public boolean isAcceptorCredential() throws GSSException {
+ return false;
+ }
+
+ public KerberosTicket getKerberosTicket() {
+ return ticket;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyNameElement.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyNameElement.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyNameElement.java
new file mode 100644
index 0000000..9c93143
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyNameElement.java
@@ -0,0 +1,134 @@
+/**
+ * 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.gssapi.KerbyMechFactory;
+import org.apache.kerby.kerberos.kerb.type.base.NameType;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.spi.GSSNameSpi;
+import java.io.UnsupportedEncodingException;
+import java.security.Provider;
+
+public class KerbyNameElement implements GSSNameSpi {
+
+ private PrincipalName principalName;
+ private Oid nameType = null;
+
+ KerbyNameElement(PrincipalName principalName,
+ Oid nameType) {
+ this.principalName = principalName;
+ this.nameType = nameType;
+ }
+
+ public PrincipalName toKerbyPrincipalName(sun.security.krb5.PrincipalName name) {
+ return new PrincipalName(name.getNameString(), toKerbyNameType(name.getNameType()));
+ }
+
+ private NameType toKerbyNameType(int intNameType) {
+ return NameType.fromValue(intNameType);
+ }
+
+ public static NameType toKerbyNameType(Oid nameType) throws GSSException {
+ NameType kerbyNameType;
+
+ if (nameType == null) {
+ throw new GSSException(GSSException.BAD_NAMETYPE);
+ }
+
+ if (nameType.equals(GSSName.NT_EXPORT_NAME) || nameType.equals(GSSName.NT_USER_NAME)) {
+ kerbyNameType = NameType.NT_PRINCIPAL;
+ } else if (nameType.equals(GSSName.NT_HOSTBASED_SERVICE)) {
+ kerbyNameType = NameType.NT_SRV_HST;
+ } else {
+ throw new GSSException(GSSException.BAD_NAMETYPE, 0, "Unsupported Oid name type");
+ }
+ return kerbyNameType;
+ }
+
+ public static KerbyNameElement getInstance(String name, Oid oidNameType)
+ throws GSSException {
+ PrincipalName principalName = new PrincipalName(name, toKerbyNameType(oidNameType));
+ return new KerbyNameElement(principalName, oidNameType);
+ }
+
+ public Provider getProvider() {
+ return new org.apache.kerby.kerberos.kerb.gssapi.Provider();
+ }
+
+ public boolean equals(GSSNameSpi name) throws GSSException {
+ if (name == null || name.isAnonymousName() || isAnonymousName()) {
+ return false;
+ }
+ return this.toString().equals(name.toString()) && this.getStringNameType().equals(name.getStringNameType());
+ }
+
+ public final PrincipalName getPrincipalName() {
+ return principalName;
+ }
+
+ public boolean equals(Object another) {
+ if (another == null) {
+ return false;
+ }
+
+ try {
+ if (another instanceof GSSNameSpi) {
+ return equals((GSSNameSpi) another);
+ }
+ } catch (GSSException e) {
+ return false;
+ }
+
+ return false;
+ }
+
+ public int hashCode() {
+ return principalName.hashCode();
+ }
+
+ public byte[] export() throws GSSException {
+ byte[] retVal;
+ try {
+ retVal = principalName.getName().getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new GSSException(GSSException.BAD_NAME, -1, e.getMessage());
+ }
+ return retVal;
+ }
+
+ public Oid getMechanism() {
+ return KerbyMechFactory.getOid();
+ }
+
+ public String toString() {
+ return principalName.toString();
+ }
+
+ public Oid getStringNameType() {
+ return nameType;
+ }
+
+ public boolean isAnonymousName() {
+ return nameType.equals(GSSName.NT_ANONYMOUS);
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/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
new file mode 100644
index 0000000..081788b
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyUtil.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.gssapi.krb5;
+
+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 KerbyUtil {
+ 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/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/MicTokenV1.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/MicTokenV1.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/MicTokenV1.java
new file mode 100644
index 0000000..6a76e4c
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/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.gssapi.krb5;
+
+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 KerbyGssTokenV1 {
+ public MicTokenV1(KerbyContext 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(KerbyContext 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/96494e9a/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/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/WrapTokenV1.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/WrapTokenV1.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/WrapTokenV1.java
new file mode 100644
index 0000000..8ecdae4
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/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.gssapi.krb5;
+
+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 KerbyGssTokenV1 {
+ 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(KerbyContext 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(KerbyContext 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(KerbyContext 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, KerbyGssEncryptor encryptor)
+ throws GSSException {
+ return GSSHeader.getMaxMechTokenSize(objId, maxTokSize)
+ - encryptor.getCheckSumSize()
+ - TOKEN_HEADER_COMM_SIZE - TOKEN_HEADER_SEQ_SIZE
+ - CONFOUNDER_SIZE - 8;
+ }
+}