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:48 UTC
[07/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/gss/impl/GssTokenV2.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV2.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV2.java
deleted file mode 100644
index 5220900..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV2.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.gss.impl;
-
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.MessageProp;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.MessageDigest;
-
-/**
- * This class implements the token formats defined in RFC 4121.
- */
-abstract class GssTokenV2 extends GssTokenBase {
- public static final int CONFOUNDER_SIZE = 16;
- public static final int TOKEN_HEADER_SIZE = 16;
- private static final int OFFSET_EC = 4;
- private static final int OFFSET_RRC = 6;
-
- // context states
- private boolean isInitiator = true;
- private boolean acceptorSubKey = false;
- private boolean confState = true;
- private int sequenceNumber;
-
- // token data
- protected int tokenType;
- private byte[] header = new byte[TOKEN_HEADER_SIZE];
- protected byte[] tokenData;
-
- protected byte[] checkSum;
- private int ec;
- private int rrc;
-
- static final int KG_USAGE_ACCEPTOR_SEAL = 22;
- static final int KG_USAGE_ACCEPTOR_SIGN = 23;
- static final int KG_USAGE_INITIATOR_SEAL = 24;
- static final int KG_USAGE_INITIATOR_SIGN = 25;
- private int keyUsage;
-
- private static final int FLAG_SENT_BY_ACCEPTOR = 1;
- private static final int FLAG_SEALED = 2;
- private static final int FLAG_ACCEPTOR_SUBKEY = 4;
-
- protected GssEncryptor encryptor;
-
-
- // Create a new token
- GssTokenV2(int tokenType, GssContext context) throws GSSException {
- initialize(tokenType, context, false);
- }
-
- private void initialize(int tokenType, GssContext context, boolean reconstruct) throws GSSException {
- this.tokenType = tokenType;
- this.isInitiator = context.isInitiator();
- this.acceptorSubKey = context.getKeyComesFrom() == GssContext.ACCEPTOR_SUBKEY;
- this.confState = context.getConfState();
-
- boolean usageFlag = reconstruct ? !this.isInitiator : this.isInitiator;
- if (tokenType == TOKEN_WRAP_V2) {
- keyUsage = usageFlag ? KG_USAGE_INITIATOR_SEAL : KG_USAGE_ACCEPTOR_SEAL;
- } else if (tokenType == TOKEN_MIC_V2) {
- keyUsage = usageFlag ? KG_USAGE_INITIATOR_SIGN : KG_USAGE_ACCEPTOR_SIGN;
- }
-
- encryptor = context.getGssEncryptor();
-
- if (!reconstruct) {
- this.sequenceNumber = context.incMySequenceNumber();
- }
- }
-
- // Reconstruct token from bytes received
- GssTokenV2(int tokenType, GssContext context,
- MessageProp prop, byte[] token, int offset, int len) throws GSSException {
- this(tokenType, context, prop, new ByteArrayInputStream(token, offset, len));
- }
-
- // Reconstruct token from input stream
- GssTokenV2(int tokenType, GssContext context,
- MessageProp prop, InputStream is) throws GSSException {
- initialize(tokenType, context, true);
-
- if (!confState) {
- prop.setPrivacy(false);
- }
-
- reconstructTokenHeader(prop, is);
-
- int minSize;
- if (tokenType == TOKEN_WRAP_V2 && prop.getPrivacy()) {
- minSize = CONFOUNDER_SIZE + TOKEN_HEADER_SIZE + encryptor.getCheckSumSize();
- } else {
- minSize = encryptor.getCheckSumSize();
- }
-
- try {
- int tokenLen = is.available();
-
- if (tokenType == TOKEN_MIC_V2) {
- tokenLen = minSize;
- tokenData = new byte[tokenLen];
- is.read(tokenData);
- } else {
- if (tokenLen >= minSize) {
- tokenData = new byte[tokenLen];
- is.read(tokenData);
- } else {
- throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token length");
- }
- }
-
- if (tokenType == TOKEN_WRAP_V2) {
- tokenData = rotate(tokenData);
- }
-
- if (tokenType == TOKEN_MIC_V2
- || tokenType == TOKEN_WRAP_V2 && !prop.getPrivacy()) {
- int checksumLen = encryptor.getCheckSumSize();
-
- if (tokenType != TOKEN_MIC_V2 && checksumLen != ec) {
- throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid EC");
- }
-
- checkSum = new byte[checksumLen];
- System.arraycopy(tokenData, tokenLen - checksumLen, checkSum, 0, checksumLen);
- }
- } catch (IOException e) {
- throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token");
- }
- }
-
- private byte[] rotate(byte[] data) {
- int dataLen = data.length;
- if (rrc % dataLen != 0) {
- rrc = rrc % dataLen;
- byte[] newBytes = new byte[dataLen];
-
- System.arraycopy(data, rrc, newBytes, 0, dataLen - rrc);
- System.arraycopy(data, 0, newBytes, dataLen - rrc, rrc);
- data = newBytes;
- }
- return data;
- }
-
- public int getKeyUsage() {
- return keyUsage;
- }
-
- public void generateCheckSum(MessageProp prop, byte[] data, int offset, int len) throws GSSException {
- // generate token header
- createTokenHeader(prop.getPrivacy());
-
- if (tokenType == TOKEN_MIC_V2
- || !prop.getPrivacy() && tokenType == TOKEN_WRAP_V2) {
- checkSum = getCheckSum(data, offset, len);
- }
-
- if (!prop.getPrivacy() && tokenType == TOKEN_WRAP_V2) {
- header[4] = (byte) (checkSum.length >>> 8);
- header[5] = (byte) (checkSum.length & 0xFF);
- }
- }
-
- public byte[] getCheckSum(byte[] data, int offset, int len) throws GSSException {
- int confidentialFlag = header[2] & 2;
- if (confidentialFlag == 0 && tokenType == TOKEN_WRAP_V2) {
- header[4] = 0;
- header[5] = 0;
- header[6] = 0;
- header[7] = 0;
- }
- return encryptor.calculateCheckSum(header, data, offset, len, keyUsage);
- }
-
- public boolean verifyCheckSum(byte[] data, int offset, int len) throws GSSException {
- byte[] dataCheckSum = getCheckSum(data, offset, len);
- return MessageDigest.isEqual(checkSum, dataCheckSum);
- }
-
- // Create a new header
- private void createTokenHeader(boolean privacy) {
- header[0] = (byte) (tokenType >>> 8);
- header[1] = (byte) tokenType;
-
- int flags = isInitiator ? 0 : FLAG_SENT_BY_ACCEPTOR;
- flags |= privacy && tokenType != TOKEN_MIC_V2 ? FLAG_SEALED : 0;
- flags |= acceptorSubKey ? FLAG_ACCEPTOR_SUBKEY : 0;
-
- header[2] = (byte) (flags & 0xFF);
- header[3] = (byte) 0xFF;
-
- if (tokenType == TOKEN_WRAP_V2) {
- header[4] = (byte) 0;
- header[5] = (byte) 0;
- header[6] = (byte) 0;
- header[7] = (byte) 0;
- } else if (tokenType == TOKEN_MIC_V2) {
- header[4] = (byte) 0xFF;
- header[5] = (byte) 0xFF;
- header[6] = (byte) 0xFF;
- header[7] = (byte) 0xFF;
- }
- writeBigEndian(header, 12, sequenceNumber);
- }
-
- // Reconstruct a token header
- private void reconstructTokenHeader(MessageProp prop, InputStream is) throws GSSException {
- try {
- if (is.read(header, 0, header.length) != header.length) {
- throw new GSSException(GSSException.FAILURE, -1, "Token header can not be read");
- }
- int tokenIDRecv = (((int) header[0]) << 8) + header[1];
- if (tokenIDRecv != tokenType) {
- throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
- "Token ID should be " + tokenType + " instead of " + tokenIDRecv);
- }
-
- int senderFlag = isInitiator ? FLAG_SENT_BY_ACCEPTOR : 0;
- int senderFlagRecv = header[2] & FLAG_SENT_BY_ACCEPTOR;
- if (senderFlagRecv != senderFlag) {
- throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid acceptor flag");
- }
-
- int confFlagRecv = header[2] & FLAG_SEALED;
- if (confFlagRecv == FLAG_SEALED && tokenType == TOKEN_WRAP_V2) {
- prop.setPrivacy(true);
- } else {
- prop.setPrivacy(false);
- }
-
- if (tokenType == TOKEN_WRAP_V2) {
- if (header[3] != (byte) 0xFF) {
- throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token filler");
- }
-
- ec = readBigEndian(header, OFFSET_EC, 2);
- rrc = readBigEndian(header, OFFSET_RRC, 2);
- } else if (tokenType == TOKEN_MIC_V2) {
- for (int i = 3; i < 8; i++) {
- if ((header[i] & 0xFF) != 0xFF) {
- throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "Invalid token filler");
- }
- }
- }
-
- prop.setQOP(0);
- sequenceNumber = readBigEndian(header, 0, 8);
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1, "Phrase token header failed");
- }
- }
-
- public int encodeHeader(byte[] buf, int offset) {
- System.arraycopy(header, 0, buf, offset, TOKEN_HEADER_SIZE);
- return TOKEN_HEADER_SIZE;
- }
-
- public void encodeHeader(OutputStream os) throws IOException {
- os.write(header);
- }
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java
deleted file mode 100644
index 372abcb..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.gss.impl;
-
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.client.KrbClientBase;
-import org.apache.kerby.kerberos.kerb.type.KerberosTime;
-import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationData;
-import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationDataEntry;
-import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
-import org.apache.kerby.kerberos.kerb.type.base.HostAddress;
-import org.apache.kerby.kerberos.kerb.type.base.HostAddresses;
-import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
-import org.apache.kerby.kerberos.kerb.type.kdc.EncAsRepPart;
-import org.apache.kerby.kerberos.kerb.type.kdc.EncKdcRepPart;
-import org.apache.kerby.kerberos.kerb.type.kdc.EncTgsRepPart;
-import org.apache.kerby.kerberos.kerb.type.ticket.KrbTicket;
-import org.apache.kerby.kerberos.kerb.type.ticket.SgtTicket;
-import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
-import org.apache.kerby.kerberos.kerb.type.ticket.Ticket;
-import org.apache.kerby.kerberos.kerb.type.ticket.TicketFlags;
-import org.ietf.jgss.GSSException;
-import sun.security.jgss.GSSCaller;
-
-import javax.crypto.SecretKey;
-import javax.security.auth.kerberos.KerberosKey;
-import javax.security.auth.kerberos.KerberosPrincipal;
-import javax.security.auth.kerberos.KerberosTicket;
-import java.io.File;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Some utility functions to translate types between GSS and Kerby
- */
-public class GssUtil {
- private static final int KERBEROS_TICKET_NUM_FLAGS = 32; // KerberosTicket.NUM_LENGTH
-
- /**
- * Construct TgtTicket from info contained in KerberosTicket
- * @param kerberosTicket
- * @return
- * @throws GSSException
- */
- public static TgtTicket getTgtTicketFromKerberosTicket(KerberosTicket kerberosTicket) throws GSSException {
- String clientName = kerberosTicket.getClient().getName();
- PrincipalName clientPrincipal = new PrincipalName(clientName);
-
- byte[] asn1Encoded = kerberosTicket.getEncoded();
- Ticket ticket = getTicketFromAsn1Encoded(asn1Encoded);
-
- EncAsRepPart encAsRepPart = new EncAsRepPart();
- fillEncKdcRepPart(encAsRepPart, kerberosTicket);
-
- TgtTicket tgt = new TgtTicket(ticket, encAsRepPart, clientPrincipal);
- return tgt;
- }
-
- /**
- * Init encKdcRepPart members with info from kerberosTicket
- * @param encKdcRepPart
- * @param kerberosTicket
- */
- public static void fillEncKdcRepPart(EncKdcRepPart encKdcRepPart, KerberosTicket kerberosTicket) {
- String clientName = kerberosTicket.getClient().getName();
- PrincipalName clientPrincipal = new PrincipalName(clientName);
-
- SecretKey secretKey = kerberosTicket.getSessionKey();
- int keyType = kerberosTicket.getSessionKeyType();
- EncryptionKey key = new EncryptionKey(keyType, secretKey.getEncoded());
- encKdcRepPart.setKey(key);
-
- encKdcRepPart.setSname(clientPrincipal);
- Date authTimeDate = kerberosTicket.getAuthTime();
- if (authTimeDate != null) {
- encKdcRepPart.setAuthTime(new KerberosTime(authTimeDate.getTime()));
- }
- Date startTimeDate = kerberosTicket.getStartTime();
- if (startTimeDate != null) {
- encKdcRepPart.setStartTime(new KerberosTime(startTimeDate.getTime()));
- }
- KerberosTime endTime = new KerberosTime(kerberosTicket.getEndTime().getTime());
- encKdcRepPart.setEndTime(endTime);
-
-
- InetAddress[] clientAddresses = kerberosTicket.getClientAddresses();
- HostAddresses hostAddresses = null;
- if (clientAddresses != null) {
- hostAddresses = new HostAddresses();
- for (InetAddress iAddr : clientAddresses) {
- hostAddresses.add(new HostAddress(iAddr));
- }
- }
- encKdcRepPart.setCaddr(hostAddresses);
-
- boolean[] tf = kerberosTicket.getFlags();
- TicketFlags ticketFlags = getTicketFlags(tf);
- encKdcRepPart.setFlags(ticketFlags);
-
-
- /* encKdcRepPart.setKeyExpiration();
- encKdcRepPart.setLastReq();
- encKdcRepPart.setNonce(); */
-
- Date renewTillDate = kerberosTicket.getRenewTill();
- KerberosTime renewTill = renewTillDate == null ? null : new KerberosTime(renewTillDate.getTime());
- encKdcRepPart.setRenewTill(renewTill);
-
- String serverRealm = kerberosTicket.getServer().getRealm();
- encKdcRepPart.setSrealm(serverRealm);
- }
-
- /**
- * Generate TicketFlags instance from flags
- * @param flags each item in flags identifies an bit setted or not
- * @return
- */
- public static TicketFlags getTicketFlags(boolean[] flags) {
- if (flags == null || flags.length != KERBEROS_TICKET_NUM_FLAGS) {
- return null;
- }
- int value = 0;
- for (boolean flag : flags) {
- value = (value << 1) + (flag ? 1 : 0);
- }
- return new TicketFlags(value);
- }
-
- /**
- * Decode each flag in ticketFlags into an boolean array
- * @param ticketFlags
- * @return
- */
- public static boolean[] ticketFlagsToBooleans(TicketFlags ticketFlags) {
- boolean[] ret = new boolean[KERBEROS_TICKET_NUM_FLAGS];
- int value = ticketFlags.getFlags();
- for (int i = 0; i < KERBEROS_TICKET_NUM_FLAGS; i++) {
- ret[KERBEROS_TICKET_NUM_FLAGS - i - 1] = (value & 0x1) != 0;
- value = value >> 1;
- }
- return ret;
- }
-
- /**
- * Construct a Ticket from bytes encoded by Asn1
- * @param encoded
- * @return
- * @throws GSSException
- */
- public static Ticket getTicketFromAsn1Encoded(byte[] encoded) throws GSSException {
- Ticket ticket = new Ticket();
- ByteBuffer byteBuffer = ByteBuffer.wrap(encoded);
- try {
- ticket.decode(byteBuffer);
- return ticket;
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
- }
- }
-
- /**
- * Scan current context for SgtTicket
- * @param client
- * @param service
- * @return
- */
- public static SgtTicket getSgtCredentialFromContext(GSSCaller caller, String client, String service)
- throws GSSException {
- KerberosTicket ticket = CredUtils.getKerberosTicketFromContext(caller, client, service);
- return getSgtTicketFromKerberosTicket(ticket);
- }
-
- /**
- * Construct a SgtTicket from KerberosTicket
- * @param kerberosTicket
- * @return
- * @throws GSSException
- */
- public static SgtTicket getSgtTicketFromKerberosTicket(KerberosTicket kerberosTicket) throws GSSException {
- if (kerberosTicket == null) {
- return null;
- }
-
- Ticket ticket = getTicketFromAsn1Encoded(kerberosTicket.getEncoded());
-
- EncTgsRepPart encTgsRepPart = new EncTgsRepPart();
- fillEncKdcRepPart(encTgsRepPart, kerberosTicket);
-
- SgtTicket sgt = new SgtTicket(ticket, encTgsRepPart);
- return sgt;
- }
-
- /**
- * Apply SgtTicket by sending TGS_REQ to KDC
- * @param ticket
- * @param service
- * @return
- */
- public static SgtTicket applySgtCredential(KerberosTicket ticket, String service) throws GSSException {
- TgtTicket tgt = getTgtTicketFromKerberosTicket(ticket);
- return applySgtCredential(tgt, service);
- }
-
- public static SgtTicket applySgtCredential(TgtTicket tgt, String server) throws GSSException {
- KrbClientBase client = getKrbClient();
-
- SgtTicket sgt = null;
- try {
- client.init();
- sgt = client.requestSgt(tgt, server);
- return sgt;
- } catch (KrbException e) {
- throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
- }
- }
-
- public static KerberosTicket convertKrbTicketToKerberosTicket(KrbTicket krbTicket, String clientName)
- throws GSSException {
- byte[] asn1Encoding;
- try {
- asn1Encoding = krbTicket.getTicket().encode();
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
- }
-
- byte[] sessionKey = krbTicket.getSessionKey().getKeyData();
- int keyType = krbTicket.getSessionKey().getKeyType().getValue();
-
- EncKdcRepPart encKdcRepPart = krbTicket.getEncKdcRepPart();
- KerberosPrincipal client = new KerberosPrincipal(clientName);
-
- PrincipalName serverPrinc = krbTicket.getTicket().getSname();
- String serverName = serverPrinc.getName() + "@" + krbTicket.getTicket().getRealm();
- KerberosPrincipal server = new KerberosPrincipal(serverName, serverPrinc.getNameType().getValue());
-
- TicketFlags ticketFlags = encKdcRepPart.getFlags();
- boolean[] flags = ticketFlagsToBooleans(ticketFlags);
-
- Date authTime = new Date(encKdcRepPart.getAuthTime().getTime());
- Date startTime = new Date(encKdcRepPart.getStartTime().getTime());
- Date endTime = new Date(encKdcRepPart.getEndTime().getTime());
- Date renewTill = new Date(encKdcRepPart.getRenewTill().getTime());
-
- InetAddress[] clientAddresses = null;
- List<HostAddress> hostAddresses = encKdcRepPart.getCaddr().getElements();
- if (hostAddresses != null) {
- int i = 0;
- clientAddresses = new InetAddress[hostAddresses.size()];
- for (HostAddress hostAddr : hostAddresses) {
- try {
- InetAddress iAddr = InetAddress.getByAddress(hostAddr.getAddress());
- clientAddresses[i++] = iAddr;
- } catch (UnknownHostException e) {
- throw new GSSException(GSSException.FAILURE, -1, "Bad client address");
- }
- }
- }
-
- KerberosTicket ticket = new KerberosTicket(
- asn1Encoding,
- client,
- server,
- sessionKey,
- keyType,
- flags,
- authTime,
- startTime,
- endTime,
- renewTill,
- clientAddresses
- );
- return ticket;
- }
-
- public static KrbClientBase getKrbClient() {
- KrbClientBase client;
- try {
- File confSpecified = new File(getSystemProperty("java.security.krb5.conf"));
- if (confSpecified != null) {
- client = new KrbClientBase(confSpecified);
- } else {
- client = new KrbClientBase(); // get configure file from environment variable or default path
- }
-
- return client;
- } catch (KrbException e) {
- return null;
- }
- }
-
- public static EncryptionKey[] convertKerberosKeyToEncryptionKey(KerberosKey[] krbKeys) {
- if (krbKeys == null) {
- return null;
- }
- EncryptionKey[] keys = new EncryptionKey[krbKeys.length];
- int i = 0;
- for (KerberosKey krbKey : krbKeys) {
- keys[i++] = new EncryptionKey(krbKey.getKeyType(), krbKey.getEncoded());
- }
- return keys;
- }
-
- /**
- * Filter out an appropriate KerberosKey from krbKeys and generate a
- * EncryptionKey accordingly
- *
- * @param krbKeys
- * @param encType
- * @param kvno
- * @return
- */
- public static EncryptionKey getEncryptionKey(KerberosKey[] krbKeys, int encType, int kvno) {
- if (krbKeys == null) {
- return null;
- }
- for (KerberosKey krbKey : krbKeys) {
- if (krbKey.getKeyType() == encType && krbKey.getVersionNumber() == kvno && !krbKey.isDestroyed()) {
- return new EncryptionKey(krbKey.getKeyType(), krbKey.getEncoded());
- }
- }
- return null;
- }
-
- /**
- * Get value of predefined system property
- * @param name
- * @return
- */
- private static String getSystemProperty(String name) {
- if (name == null) {
- return null;
- }
-
- final String propertyName = name;
- try {
- return AccessController.doPrivileged(
- new PrivilegedExceptionAction<String>() {
- public String run() {
- return System.getProperty(propertyName);
- }
- });
- } catch (PrivilegedActionException e) {
- return null; // ignored
- }
- }
-
- public static com.sun.security.jgss.AuthorizationDataEntry[]
- kerbyAuthorizationDataToJgssAuthorizationDataEntries(AuthorizationData authData) {
- if (authData == null) {
- return null;
- }
- List<AuthorizationDataEntry> kerbyEntries = authData.getElements();
- com.sun.security.jgss.AuthorizationDataEntry[] entries =
- new com.sun.security.jgss.AuthorizationDataEntry[kerbyEntries.size()];
- for (int i = 0; i < kerbyEntries.size(); i++) {
- entries[i] = new com.sun.security.jgss.AuthorizationDataEntry(
- kerbyEntries.get(i).getAuthzType().getValue(),
- kerbyEntries.get(i).getAuthzData());
- }
- return entries;
- }
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV1.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV1.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV1.java
deleted file mode 100644
index 63baa6b..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV1.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.gss.impl;
-
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.MessageProp;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-public class MicTokenV1 extends GssTokenV1 {
- public MicTokenV1(GssContext context,
- byte[] inMsg,
- int msgOffset,
- int msgLength,
- MessageProp messageProp) throws GSSException {
- super(TOKEN_MIC_V1, context);
- calcPrivacyInfo(messageProp, null, inMsg, msgOffset, msgLength, 0);
- }
-
- // This is called to construct MicToken from MicToken bytes
- MicTokenV1(GssContext context,
- MessageProp messageProp,
- byte[] inToken,
- int tokenOffset,
- int tokenLength) throws GSSException {
- super(TOKEN_MIC_V1, context, messageProp, inToken, tokenOffset, tokenLength);
- }
-
- public int getMic(byte[] outToken, int offset) throws GSSException, IOException {
- byte[] data = getMic();
- System.arraycopy(data, 0, outToken, offset, data.length);
- return data.length;
- }
-
- /**
- * Get bytes for this Mic token
- * @return
- */
- public byte[] getMic() throws GSSException {
- ByteArrayOutputStream os = new ByteArrayOutputStream(64);
- getMic(os);
- return os.toByteArray();
- }
-
- public void getMic(OutputStream os) throws GSSException {
- try {
- encodeHeader(os);
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1, "Error in output MicTokenV1 bytes:" + e.getMessage());
- }
- }
-
- public void verify(InputStream is) throws GSSException {
- byte[] data;
- try {
- data = new byte[is.available()];
- is.read(data);
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1,
- "Read plain data for MicTokenV1 error:" + e.getMessage());
- }
- verify(data, 0, data.length);
- }
-
- public void verify(byte[] data, int offset, int len) throws GSSException {
- verifyToken(null, data, offset, len, 0);
- }
-
- protected int getTokenSizeWithoutGssHeader() {
- return getTokenHeaderSize();
- }
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV2.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV2.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV2.java
deleted file mode 100644
index 2441823..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/MicTokenV2.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.gss.impl;
-
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.MessageProp;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-public class MicTokenV2 extends GssTokenV2 {
- private MessageProp prop;
-
- // This is called to construct MicToken from user input
- MicTokenV2(GssContext context,
- byte[] inMsg,
- int msgOffset,
- int msgLength,
- MessageProp messageProp) throws GSSException {
- super(TOKEN_MIC_V2, context);
-
- prop = messageProp;
- if (prop == null) {
- prop = new MessageProp(0, false);
- }
-
- generateCheckSum(prop, inMsg, msgOffset, msgLength);
- }
-
- // This is called to construct MicToken from MicToken bytes
- MicTokenV2(GssContext context,
- MessageProp messageProp,
- byte[] inToken,
- int tokenOffset,
- int tokenLength) throws GSSException {
- super(TOKEN_MIC_V2, context, messageProp, inToken, tokenOffset, tokenLength);
- this.prop = messageProp;
- }
-
- public int getMic(byte[] outToken, int offset) {
- encodeHeader(outToken, offset);
- System.arraycopy(checkSum, 0, outToken, TOKEN_HEADER_SIZE + offset, checkSum.length);
- return TOKEN_HEADER_SIZE + checkSum.length;
- }
-
- /**
- * Get bytes for this Mic token
- * @return
- */
- public byte[] getMic() {
- byte[] ret = new byte[TOKEN_HEADER_SIZE + checkSum.length];
- getMic(ret, 0);
- return ret;
- }
-
- public void getMic(OutputStream os) throws GSSException {
- try {
- encodeHeader(os);
- os.write(checkSum);
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1, "Output MicTokenV2 error:" + e.getMessage());
- }
- }
-
- /**
- * Calculate the checksum for inMsg and compare with it with this token, throw GssException if not equal
- * @param inMsg
- * @param msgOffset
- * @param msgLen
- * @throws GSSException
- */
- public void verify(byte[] inMsg, int msgOffset, int msgLen) throws GSSException {
- if (!verifyCheckSum(inMsg, msgOffset, msgLen)) {
- throw new GSSException(GSSException.BAD_MIC, -1, "Corrupt MIC token");
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV1.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV1.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV1.java
deleted file mode 100644
index 03395bb..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV1.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.gss.impl;
-
-import org.apache.kerby.kerberos.kerb.crypto.util.Random;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.MessageProp;
-import sun.security.jgss.GSSHeader;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-public class WrapTokenV1 extends GssTokenV1 {
- public static final int CONFOUNDER_SIZE = 8;
-
- private boolean privacy;
-
- private byte[] inData;
- private int inOffset;
- private int inLen;
-
- private int paddingLen;
- private byte[] confounder;
- private int tokenBodyLen;
-
- private byte[] bodyData;
- private int bodyOffset;
- private int bodyLen;
-
- // for reconstruct
- private int rawDataLength;
- private byte[] rawData;
- private int rawDataOffset;
-
-
- // Generate wrap token according user data
- public WrapTokenV1(GssContext context,
- byte[] inMsg,
- int msgOffset,
- int msgLength,
- MessageProp prop) throws GSSException {
- super(TOKEN_WRAP_V1, context);
-
- paddingLen = getPaddingLength(msgLength);
- confounder = Random.makeBytes(CONFOUNDER_SIZE);
- tokenBodyLen = CONFOUNDER_SIZE + msgLength + paddingLen;
-
- calcPrivacyInfo(prop, confounder, inMsg, msgOffset, msgLength, paddingLen);
-
- if (!context.getConfState()) {
- prop.setPrivacy(false);
- }
- privacy = prop.getPrivacy();
- inData = inMsg;
- inOffset = msgOffset;
- inLen = msgLength;
- }
-
- // Reconstruct a token from token bytes
- public WrapTokenV1(GssContext context, MessageProp prop,
- byte[] token, int offset, int len) throws GSSException {
- super(TOKEN_WRAP_V1, context, prop, token, offset, len);
- // adjust the offset to the beginning of the body
- bodyData = token;
- bodyOffset = offset + reconHeaderLen;
- bodyLen = len - reconHeaderLen;
- getRawData(prop);
- }
-
- // Reconstruct a token from token bytes stream
- public WrapTokenV1(GssContext context, MessageProp prop, InputStream is) throws GSSException {
- super(TOKEN_WRAP_V1, context, prop, is);
- byte[] token;
- int len;
- try {
- len = is.available();
- token = new byte[len];
- is.read(token);
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1, "Read wrap token V1 error:" + e.getMessage());
- }
- bodyData = token;
- bodyOffset = 0;
- bodyLen = len;
- getRawData(prop);
- }
-
- private void getRawData(MessageProp prop) throws GSSException {
- privacy = prop.getPrivacy();
- tokenBodyLen = getGssHeader().getMechTokenLength() - getTokenHeaderSize();
-
- if (bodyLen < tokenBodyLen) {
- throw new GSSException(GSSException.FAILURE, -1, "Insufficient data for Wrap token V1");
- }
-
- if (privacy) {
- rawData = encryptor.encryptTokenV1(null, bodyData, bodyOffset, tokenBodyLen, 0,
- encryptor.isArcFourHmac() ? getPlainSequenceBytes() : null, false);
- paddingLen = rawData[rawData.length - 1];
- rawDataOffset = CONFOUNDER_SIZE;
- } else {
- rawData = bodyData;
- paddingLen = bodyData[bodyOffset + tokenBodyLen - 1];
- rawDataOffset = bodyOffset + CONFOUNDER_SIZE;
- }
- rawDataLength = tokenBodyLen - CONFOUNDER_SIZE - paddingLen;
-
- verifyToken(null, rawData, rawDataOffset - CONFOUNDER_SIZE, tokenBodyLen, 0);
- }
-
- // Get plain text data from token data bytes
- public byte[] unwrap() throws GSSException {
- byte[] ret = new byte[rawDataLength];
- System.arraycopy(rawData, rawDataOffset, ret, 0, rawDataLength);
- return ret;
- }
-
- public void unwrap(OutputStream os) throws GSSException {
- try {
- os.write(rawData, rawDataOffset, rawDataLength);
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1,
- "Error in output wrap token v1 data bytes:" + e.getMessage());
- }
- }
-
- public byte[] wrap() throws GSSException {
- ByteArrayOutputStream os = new ByteArrayOutputStream(getTokenSizeWithoutGssHeader() + inLen + 64);
- wrap(os);
- return os.toByteArray();
- }
-
- public void wrap(OutputStream os) throws GSSException {
- try {
- encodeHeader(os);
- if (privacy) {
- byte[] enc = encryptor.encryptTokenV1(confounder, inData, inOffset, inLen, paddingLen,
- encryptor.isArcFourHmac() ? getPlainSequenceBytes() : null, true);
- os.write(enc);
- } else {
- os.write(confounder);
- os.write(inData, inOffset, inLen);
- os.write(getPaddingBytes(paddingLen));
- }
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1, "Error in output wrap token v1 bytes:" + e.getMessage());
- }
- }
-
- protected int getTokenSizeWithoutGssHeader() {
- return tokenBodyLen + getTokenHeaderSize();
- }
-
- private int getPaddingLength(int dataLen) {
- if (encryptor.isArcFourHmac()) {
- return 1;
- }
- return 8 - (dataLen % 8);
- }
-
- private byte[] getPaddingBytes(int len) {
- byte[] ret = new byte[len];
- int i = 0;
- while (i < len) {
- ret[i++] = (byte) len;
- }
- return ret;
- }
-
- public static int getMsgSizeLimit(int qop, boolean confReq, int maxTokSize, GssEncryptor encryptor)
- throws GSSException {
- return GSSHeader.getMaxMechTokenSize(objId, maxTokSize)
- - encryptor.getCheckSumSize()
- - TOKEN_HEADER_COMM_SIZE - TOKEN_HEADER_SEQ_SIZE
- - CONFOUNDER_SIZE - 8;
- }
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV2.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV2.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV2.java
deleted file mode 100644
index 8f4cae4..0000000
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/WrapTokenV2.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.gss.impl;
-
-import org.apache.kerby.kerberos.kerb.Message;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.MessageProp;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-
-public class WrapTokenV2 extends GssTokenV2 {
- private MessageProp prop;
-
- // Generate a token from user input data
- WrapTokenV2(GssContext context,
- byte[] data,
- int dataOffset,
- int dataLength,
- MessageProp messageProp) throws GSSException {
- super(TOKEN_WRAP_V2, context);
-
- prop = messageProp;
-
- if (prop.getQOP() != 0) {
- prop.setQOP(0);
- }
-
- if (!context.getConfState()) {
- prop.setPrivacy(false);
- }
-
- generateCheckSum(prop, data, dataOffset, dataLength);
-
- if (prop.getPrivacy()) {
- byte[] toProcess = new byte[dataLength + TOKEN_HEADER_SIZE];
- System.arraycopy(data, dataOffset, toProcess, 0, dataLength);
- encodeHeader(toProcess, dataLength);
-
- tokenData = encryptor.encryptData(toProcess, getKeyUsage());
- } else {
- tokenData = data; // keep it for now
- }
- }
-
- /**
- * Get bytes of the token
- * @return
- */
- public byte[] wrap() {
- int dataSize = tokenData.length;
- int ckSize = checkSum == null ? 0 : checkSum.length;
- byte[] ret = new byte[TOKEN_HEADER_SIZE + dataSize + ckSize];
- encodeHeader(ret, 0);
- System.arraycopy(tokenData, 0, ret, TOKEN_HEADER_SIZE, dataSize);
- if (ckSize > 0) {
- System.arraycopy(checkSum, 0, ret, TOKEN_HEADER_SIZE + dataSize, ckSize);
- }
- return ret;
- }
-
- public void wrap(OutputStream os) throws GSSException {
- try {
- encodeHeader(os);
- os.write(tokenData);
- int ckSize = checkSum == null ? 0 : checkSum.length;
- if (ckSize > 0) {
- os.write(checkSum);
- }
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1, "Output token error:" + e.getMessage());
- }
- }
-
- // Reconstruct a token from token bytes
- public WrapTokenV2(GssContext context, MessageProp prop, byte[] token, int offset, int len) throws GSSException {
- super(TOKEN_WRAP_V2, context, prop, token, offset, len);
- this.prop = prop;
- }
-
- // Reconstruct a token from token bytes stream
- public WrapTokenV2(GssContext context, MessageProp prop, InputStream is) throws GSSException {
- super(TOKEN_WRAP_V2, context, prop, is);
- this.prop = prop;
- }
-
- /**
- * Get plain text data from token bytes
- * @param outBuffer
- * @param offset
- * @return plain text contained in the wrap token
- * @throws GSSException
- */
- public byte[] unwrap(byte[] outBuffer, int offset) throws GSSException {
- int lenToCopy;
- if (prop.getPrivacy()) {
- byte[] plainText = encryptor.decryptData(tokenData, getKeyUsage());
- lenToCopy = plainText.length - TOKEN_HEADER_SIZE;
- if (outBuffer == null) {
- outBuffer = new byte[lenToCopy];
- offset = 0;
- }
- System.arraycopy(plainText, 0, outBuffer, offset, lenToCopy);
- } else {
- lenToCopy = tokenData.length - encryptor.getCheckSumSize();
- if (outBuffer == null) {
- outBuffer = new byte[lenToCopy];
- offset = 0;
- }
- System.arraycopy(tokenData, 0, outBuffer, offset, lenToCopy);
-
- if (!verifyCheckSum(outBuffer, offset, lenToCopy)) {
- throw new GSSException(GSSException.BAD_MIC, -1, "Corrupt token checksum");
- }
- }
- return outBuffer;
- }
-
- public byte[] unwrap() throws GSSException {
- return unwrap(null, 0);
- }
-
- public void unwrap(OutputStream os) throws GSSException {
- byte[] data = unwrap();
- try {
- os.write(data);
- } catch (IOException e) {
- throw new GSSException(GSSException.FAILURE, -1, "Output token error:" + e.getMessage());
- }
- }
-
- public static int getMsgSizeLimit(int qop, boolean confReq, int maxTokSize, GssEncryptor encryptor)
- throws GSSException {
- if (confReq) {
- return maxTokSize - encryptor.getCheckSumSize() - TOKEN_HEADER_SIZE * 2 - CONFOUNDER_SIZE;
- } else {
- return maxTokSize - encryptor.getCheckSumSize() - TOKEN_HEADER_SIZE;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/KerbyMechFactory.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/KerbyMechFactory.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/KerbyMechFactory.java
new file mode 100644
index 0000000..adacb27
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/KerbyMechFactory.java
@@ -0,0 +1,149 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.gssapi;
+
+import org.apache.kerby.kerberos.kerb.gssapi.krb5.KerbyAcceptCred;
+import org.apache.kerby.kerberos.kerb.gssapi.krb5.KerbyContext;
+import org.apache.kerby.kerberos.kerb.gssapi.krb5.KerbyCredElement;
+import org.apache.kerby.kerberos.kerb.gssapi.krb5.KerbyInitCred;
+import org.apache.kerby.kerberos.kerb.gssapi.krb5.KerbyNameElement;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSCaller;
+import sun.security.jgss.spi.GSSContextSpi;
+import sun.security.jgss.spi.GSSCredentialSpi;
+import sun.security.jgss.spi.GSSNameSpi;
+import sun.security.jgss.spi.MechanismFactory;
+
+import java.security.Provider;
+
+/**
+ * Kerby Kerberos V5 plugin for JGSS
+ */
+public class KerbyMechFactory implements MechanismFactory {
+ private static final Provider PROVIDER =
+ new org.apache.kerby.kerberos.kerb.gssapi.Provider();
+
+ private static final String KRB5_OID_STRING = "1.2.840.113554.1.2.2";
+ private static final Oid KRB5_OID = createOid(KRB5_OID_STRING);
+
+ private static Oid[] nameTypes =
+ new Oid[] {
+ GSSName.NT_USER_NAME,
+ GSSName.NT_EXPORT_NAME,
+ GSSName.NT_HOSTBASED_SERVICE
+ };
+
+ private final GSSCaller caller;
+
+ public Oid getMechanismOid() {
+ return KRB5_OID;
+ }
+
+ public Provider getProvider() {
+ return PROVIDER;
+ }
+
+ public Oid[] getNameTypes() throws GSSException {
+ return nameTypes;
+ }
+
+ public KerbyMechFactory(GSSCaller caller) {
+ this.caller = caller;
+ }
+
+ public GSSNameSpi getNameElement(String nameStr, Oid nameType)
+ throws GSSException {
+ return KerbyNameElement.getInstance(nameStr, nameType);
+ }
+
+ public GSSNameSpi getNameElement(byte[] name, Oid nameType)
+ throws GSSException {
+ return KerbyNameElement.getInstance(name.toString(), nameType);
+ }
+
+ // Used by initiator
+ public GSSContextSpi getMechanismContext(GSSNameSpi peer,
+ GSSCredentialSpi myInitiatorCred,
+ int lifetime) throws GSSException {
+ if (peer != null && !(peer instanceof KerbyNameElement)) {
+ peer = KerbyNameElement.getInstance(peer.toString(), peer.getStringNameType());
+ }
+ if (myInitiatorCred == null) {
+ myInitiatorCred = getCredentialElement(null, lifetime, 0, GSSCredential.INITIATE_ONLY);
+ }
+ return new KerbyContext(caller, (KerbyNameElement) peer, (KerbyInitCred) myInitiatorCred, lifetime);
+ }
+
+ public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
+ throws GSSException {
+ if (myAcceptorCred == null) {
+ myAcceptorCred = getCredentialElement(null, 0,
+ GSSCredential.INDEFINITE_LIFETIME, GSSCredential.ACCEPT_ONLY);
+ }
+ return new KerbyContext(caller, (KerbyAcceptCred) myAcceptorCred);
+ }
+
+ // Reconstruct from previously exported context
+ public GSSContextSpi getMechanismContext(byte[] exportedContext)
+ throws GSSException {
+ return new KerbyContext(caller, exportedContext);
+ }
+
+ public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
+ int initLifetime,
+ int acceptLifetime,
+ int usage)
+ throws GSSException {
+ if (name != null && !(name instanceof KerbyNameElement)) {
+ name = KerbyNameElement.getInstance(name.toString(), name.getStringNameType());
+ }
+
+ KerbyCredElement credElement;
+
+ if (usage == GSSCredential.INITIATE_ONLY) {
+ credElement = KerbyInitCred.getInstance(caller, (KerbyNameElement) name, initLifetime);
+ } else if (usage == GSSCredential.ACCEPT_ONLY) {
+ credElement = KerbyAcceptCred.getInstance(caller, (KerbyNameElement) name, acceptLifetime);
+ } else if (usage == GSSCredential.INITIATE_AND_ACCEPT) {
+ throw new GSSException(GSSException.FAILURE, -1, "Unsupported usage mode: INITIATE_AND_ACCEPT");
+ } else {
+ throw new GSSException(GSSException.FAILURE, -1, "Unknown usage mode: " + usage);
+ }
+
+ return credElement;
+ }
+
+ private static Oid createOid(String oidStr) {
+ Oid retVal;
+ try {
+ retVal = new Oid(oidStr);
+ } catch (GSSException e) {
+ retVal = null;
+ }
+ return retVal;
+ }
+
+ public static Oid getOid() {
+ return KRB5_OID;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/Provider.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/Provider.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/Provider.java
new file mode 100644
index 0000000..ad3a614
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/Provider.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.gssapi;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Proivder is used to register the implementation of gssapi mechanism into the system
+ */
+public final class Provider extends java.security.Provider {
+ private static final long serialVersionUID = 3787378212107821987L;
+ private static final String INFO = "Kerby GssApi Provider";
+ private static final String MECHANISM_GSSAPI = "GssApiMechanism.1.2.840.113554.1.2.2";
+ private static final String MECHANISM_GSSAPI_CLASS = "org.apache.kerby.kerberos.kerb.gssapi.KerbyMechFactory";
+
+ public Provider() {
+ super("KerbyGssApi", 0.01d, INFO);
+
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
+
+ put(MECHANISM_GSSAPI, MECHANISM_GSSAPI_CLASS);
+
+ return null;
+ }
+ });
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/CredUtils.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/CredUtils.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/CredUtils.java
new file mode 100644
index 0000000..f7ddc31
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/CredUtils.java
@@ -0,0 +1,89 @@
+package org.apache.kerby.kerberos.kerb.gssapi.krb5;
+
+import org.ietf.jgss.GSSException;
+import sun.security.jgss.GSSCaller;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.*;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Set;
+
+/**
+ * Utility functions to deal with credentials in Context
+ */
+public class CredUtils {
+
+ public static <T> Set<T> getContextPrivateCredentials(Class<T> credentialType, AccessControlContext acc) {
+ Subject subject = Subject.getSubject(acc);
+ Set<T> creds = subject.getPrivateCredentials(credentialType);
+ return creds;
+ }
+
+ public static <T> Set<T> getContextCredentials(final Class<T> credentialType) throws GSSException {
+ final AccessControlContext acc = AccessController.getContext();
+ try {
+ return AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Set<T>>() {
+ public Set<T> run() throws Exception {
+ return CredUtils.getContextPrivateCredentials(credentialType, acc);
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw new GSSException(GSSException.NO_CRED, -1, "Get credential from context failed");
+ }
+ }
+
+ public static KerberosTicket getKerberosTicketFromContext(GSSCaller caller,
+ final String clientName,
+ final String serverName) throws GSSException {
+ Set<KerberosTicket> tickets = getContextCredentials(KerberosTicket.class);
+ for (KerberosTicket ticket : tickets) {
+ if (ticket.isCurrent() && (serverName == null || ticket.getServer().getName().equals(serverName))
+ && (clientName == null || ticket.getClient().getName().equals(clientName))) {
+ return ticket;
+ }
+ }
+ return null;
+ }
+
+ public static KeyTab getKeyTabFromContext(KerberosPrincipal principal) throws GSSException {
+ Set<KeyTab> tabs = getContextCredentials(KeyTab.class);
+ for (KeyTab tab : tabs) {
+ KerberosKey[] keys = tab.getKeys(principal);
+ if (keys != null && keys.length > 0) {
+ return tab;
+ }
+ }
+ return null;
+ }
+
+ public static void addCredentialToSubject(final KerberosTicket ticket) throws GSSException {
+ final AccessControlContext acc = AccessController.getContext();
+
+ final Subject subject = AccessController.doPrivileged(
+ new java.security.PrivilegedAction<Subject>() {
+ public Subject run() {
+ return Subject.getSubject(acc);
+ }
+ });
+
+ AccessController.doPrivileged(
+ new java.security.PrivilegedAction<Void>() {
+ public Void run() {
+ subject.getPrivateCredentials().add(ticket);
+ return null;
+ }
+ });
+ }
+
+ public static void checkPrincipalPermission(String principalName, String action) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ ServicePermission sp = new ServicePermission(principalName, action);
+ sm.checkPermission(sp);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyAcceptCred.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyAcceptCred.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyAcceptCred.java
new file mode 100644
index 0000000..a7331fa
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyAcceptCred.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.gssapi.krb5;
+
+
+import org.ietf.jgss.GSSException;
+import sun.security.jgss.GSSCaller;
+
+import javax.security.auth.kerberos.KerberosKey;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KeyTab;
+
+public final class KerbyAcceptCred extends KerbyCredElement {
+
+ private final KeyTab keyTab;
+
+ public static KerbyAcceptCred getInstance(final GSSCaller caller,
+ KerbyNameElement name, int lifeTime) throws GSSException {
+
+ KerberosPrincipal princ = new KerberosPrincipal(name.getPrincipalName().getName(),
+ name.getPrincipalName().getNameType().getValue());
+ KeyTab keyTab = CredUtils.getKeyTabFromContext(princ);
+
+ if (keyTab == null) {
+ throw new GSSException(GSSException.NO_CRED, -1,
+ "Failed to find any Kerberos credential for " + name.getPrincipalName().getName());
+ }
+
+ return new KerbyAcceptCred(caller, name, keyTab, lifeTime);
+ }
+
+ private KerbyAcceptCred(GSSCaller caller, KerbyNameElement name, KeyTab keyTab, int lifeTime) {
+ super(caller, name);
+ this.keyTab = keyTab;
+ this.accLifeTime = lifeTime;
+ }
+
+ public boolean isInitiatorCredential() throws GSSException {
+ return false;
+ }
+
+ public boolean isAcceptorCredential() throws GSSException {
+ return true;
+ }
+
+ public KeyTab getKeyTab() {
+ return this.keyTab;
+ }
+
+ public KerberosKey[] getKeys() {
+ KerberosPrincipal princ = new KerberosPrincipal(name.getPrincipalName().getName(),
+ name.getPrincipalName().getNameType().getValue());
+ return keyTab.getKeys(princ);
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/96494e9a/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
new file mode 100644
index 0000000..5395afd
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gssapi/krb5/KerbyContext.java
@@ -0,0 +1,673 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.gssapi.krb5;
+
+import com.sun.security.jgss.InquireType;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.gssapi.KerbyMechFactory;
+import org.apache.kerby.kerberos.kerb.request.ApRequest;
+import org.apache.kerby.kerberos.kerb.response.ApResponse;
+import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationData;
+import org.apache.kerby.kerberos.kerb.type.ap.ApRep;
+import org.apache.kerby.kerberos.kerb.type.ap.ApReq;
+import org.apache.kerby.kerberos.kerb.type.ap.Authenticator;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.apache.kerby.kerberos.kerb.type.kdc.EncKdcRepPart;
+import org.apache.kerby.kerberos.kerb.type.ticket.EncTicketPart;
+import org.apache.kerby.kerberos.kerb.type.ticket.SgtTicket;
+import org.apache.kerby.kerberos.kerb.type.ticket.TicketFlags;
+import org.ietf.jgss.ChannelBinding;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.MessageProp;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSCaller;
+import sun.security.jgss.spi.GSSContextSpi;
+import sun.security.jgss.spi.GSSCredentialSpi;
+import sun.security.jgss.spi.GSSNameSpi;
+
+import javax.security.auth.kerberos.KerberosTicket;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.security.Provider;
+
+@SuppressWarnings("PMD")
+public class KerbyContext implements GSSContextSpi {
+
+ private static final int STATE_NONE = 0;
+ private static final int STATE_ESTABLISHING = 1;
+ private static final int STATE_ESTABLISHED = 2;
+ private static final int STATE_DESTROYED = 3;
+
+ private static final byte[] MSG_AP_REQ = {(byte) 0x1, (byte) 0};
+ private static final byte[] MSG_AP_REP = {(byte) 0x2, (byte) 0};
+
+ private int ctxState = STATE_NONE;
+
+ private final GSSCaller caller;
+ private KerbyCredElement myCred;
+ private boolean initiator;
+ private KerbyNameElement myName;
+ private KerbyNameElement peerName;
+ private int lifeTime;
+ private ChannelBinding channelBinding;
+
+ private boolean mutualAuth = true;
+ private boolean replayDet = true;
+ private boolean sequenceDet = true;
+ private boolean credDeleg = false;
+ private boolean confState = true;
+ private boolean integState = true;
+ private boolean delegPolicy = false;
+
+ public static final int INVALID_KEY = 0;
+ public static final int SESSION_KEY = 1;
+ public static final int INITIATOR_SUBKEY = 2;
+ public static final int ACCEPTOR_SUBKEY = 4;
+ private int keyComesFrom = INVALID_KEY;
+
+ private EncryptionKey sessionKey; // used between client and app server
+ private TicketFlags ticketFlags;
+ private ApReq outApReq;
+
+ private KerbyGssEncryptor gssEncryptor;
+
+ // Called on initiator's side.
+ public KerbyContext(GSSCaller caller, KerbyNameElement peerName, KerbyCredElement myCred,
+ int lifeTime)
+ throws GSSException {
+ if (peerName == null) {
+ throw new IllegalArgumentException("Cannot have null peer name");
+ }
+
+ this.caller = caller;
+ this.peerName = peerName;
+ this.myCred = myCred;
+ this.lifeTime = lifeTime;
+ this.initiator = true;
+
+ mySequenceNumberLock = new Object();
+ peerSequenceNumberLock = new Object();
+ }
+
+ public KerbyContext(GSSCaller caller, KerbyAcceptCred myCred)
+ throws GSSException {
+ this.caller = caller;
+ this.myCred = myCred;
+ this.initiator = false;
+
+ mySequenceNumberLock = new Object();
+ peerSequenceNumberLock = new Object();
+ }
+
+ public KerbyContext(GSSCaller caller, byte[] interProcessToken)
+ throws GSSException {
+ throw new GSSException(GSSException.UNAVAILABLE, -1, "Unsupported feature");
+ }
+
+ public Provider getProvider() {
+ return new org.apache.kerby.kerberos.kerb.gssapi.Provider();
+ }
+
+ public void requestLifetime(int lifeTime) throws GSSException {
+ if (ctxState == STATE_NONE && isInitiator()) {
+ this.lifeTime = lifeTime;
+ }
+ }
+
+ public void requestMutualAuth(boolean state) throws GSSException {
+ if (ctxState == STATE_NONE && isInitiator()) {
+ mutualAuth = state;
+ }
+ }
+
+ public void requestReplayDet(boolean state) throws GSSException {
+ if (ctxState == STATE_NONE && isInitiator()) {
+ replayDet = state;
+ }
+ }
+
+ public void requestSequenceDet(boolean state) throws GSSException {
+ if (ctxState == STATE_NONE && isInitiator()) {
+ replayDet = state;
+ }
+ }
+
+ public void requestCredDeleg(boolean state) throws GSSException {
+ if (ctxState == STATE_NONE && isInitiator() && myCred == null) {
+ credDeleg = state;
+ }
+ }
+
+ public void requestAnonymity(boolean state) throws GSSException {
+ // anonymous context not supported
+ }
+
+ public void requestConf(boolean state) throws GSSException {
+ if (ctxState == STATE_NONE && isInitiator()) {
+ confState = state;
+ }
+ }
+
+ public void requestInteg(boolean state) throws GSSException {
+ if (ctxState == STATE_NONE && isInitiator()) {
+ integState = state;
+ }
+ }
+
+ public void requestDelegPolicy(boolean state) throws GSSException {
+ if (ctxState == STATE_NONE && isInitiator()) {
+ delegPolicy = state;
+ }
+ }
+
+ public void setChannelBinding(ChannelBinding cb) throws GSSException {
+ this.channelBinding = cb;
+ }
+
+ public boolean getCredDelegState() {
+ return credDeleg;
+ }
+
+ public boolean getMutualAuthState() {
+ return mutualAuth;
+ }
+
+ public boolean getReplayDetState() {
+ return replayDet || sequenceDet;
+ }
+
+ public boolean getSequenceDetState() {
+ return sequenceDet;
+ }
+
+ public boolean getAnonymityState() {
+ return false;
+ }
+
+ public boolean getDelegPolicyState() {
+ return delegPolicy;
+ }
+
+ public boolean isTransferable() throws GSSException {
+ return false;
+ }
+
+ public boolean isProtReady() {
+ return ctxState == STATE_ESTABLISHED;
+ }
+
+ public boolean isInitiator() {
+ return initiator;
+ }
+
+ public boolean getConfState() {
+ return confState;
+ }
+
+ public boolean getIntegState() {
+ return integState;
+ }
+
+ public int getLifetime() {
+ return GSSContext.INDEFINITE_LIFETIME;
+ }
+
+ public boolean isEstablished() {
+ return ctxState == STATE_ESTABLISHED;
+ }
+
+ public GSSNameSpi getSrcName() throws GSSException {
+ return isInitiator() ? myName : peerName;
+ }
+
+ public GSSNameSpi getTargName() throws GSSException {
+ return !isInitiator() ? myName : peerName;
+ }
+
+ public Oid getMech() throws GSSException {
+ return KerbyMechFactory.getOid();
+ }
+
+ public GSSCredentialSpi getDelegCred() throws GSSException {
+ throw new GSSException(GSSException.FAILURE, -1, "API not implemented"); // TODO:
+ }
+
+ public byte[] initSecContext(InputStream is, int mechTokenSize)
+ throws GSSException {
+ if (!isInitiator()) {
+ throw new GSSException(GSSException.FAILURE, -1, "initSecContext called on acceptor");
+ }
+
+ byte[] ret = null;
+
+ if (ctxState == STATE_NONE) {
+
+ if (!myCred.isInitiatorCredential()) {
+ throw new GSSException(GSSException.NO_CRED, -1, "No TGT available");
+ }
+
+ // check if service ticket already exists
+ // if not, prepare to get it through TGS_REQ
+ SgtTicket sgtTicket = null;
+ String serviceName = peerName.getPrincipalName().getName();
+ myName = (KerbyNameElement) myCred.getName();
+ PrincipalName clientPrincipal = myName.getPrincipalName();
+
+ sgtTicket = KerbyUtil.getSgtCredentialFromContext(caller, clientPrincipal.getName(), serviceName);
+
+ if (sgtTicket == null) {
+ sgtTicket = KerbyUtil.applySgtCredential(((KerbyInitCred) myCred).ticket, serviceName);
+
+ // add this service credential to context
+ final KerberosTicket ticket =
+ KerbyUtil.convertKrbTicketToKerberosTicket(sgtTicket, myName.getPrincipalName().getName());
+ CredUtils.addCredentialToSubject(ticket);
+ }
+
+ ApRequest apRequest = new ApRequest(clientPrincipal, sgtTicket);
+ try {
+ outApReq = apRequest.getApReq();
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1, "Generate ApReq failed: " + e.getMessage());
+ }
+ setupInitiatorContext(sgtTicket, apRequest);
+ try {
+ ByteBuffer outBuffer = ByteBuffer.allocate(outApReq.encodingLength() + 2);
+ outBuffer.put(MSG_AP_REQ);
+ outApReq.encode(outBuffer);
+ outBuffer.flip();
+ ret = outBuffer.array();
+ } catch (IOException e) {
+ throw new GSSException(GSSException.FAILURE, -1, "Generate ApReq bytes failed: " + e.getMessage());
+ }
+
+ ctxState = STATE_ESTABLISHING;
+ if (!getMutualAuthState()) {
+ gssEncryptor = new KerbyGssEncryptor(getSessionKey());
+ ctxState = STATE_ESTABLISHED;
+ }
+
+ } else if (ctxState == STATE_ESTABLISHING) {
+ verifyServerToken(is, mechTokenSize);
+ gssEncryptor = new KerbyGssEncryptor(getSessionKey());
+ outApReq = null;
+ ctxState = STATE_ESTABLISHED;
+ }
+ return ret;
+ }
+
+ private void setupInitiatorContext(SgtTicket sgt, ApRequest apRequest) throws GSSException {
+ EncKdcRepPart encKdcRepPart = sgt.getEncKdcRepPart();
+ TicketFlags ticketFlags = encKdcRepPart.getFlags();
+ setTicketFlags(ticketFlags);
+
+ setAuthTime(encKdcRepPart.getAuthTime().toString());
+
+ Authenticator auth;
+ try {
+ auth = apRequest.getApReq().getAuthenticator();
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.FAILURE, -1, "ApReq failed in Initiator");
+ }
+ setMySequenceNumber(auth.getSeqNumber());
+
+ EncryptionKey subKey = auth.getSubKey();
+ if (subKey != null) {
+ setSessionKey(subKey, KerbyContext.INITIATOR_SUBKEY);
+ } else {
+ setSessionKey(sgt.getSessionKey(), KerbyContext.SESSION_KEY);
+ }
+
+ if (!getMutualAuthState()) {
+ setPeerSequenceNumber(0);
+ }
+ }
+
+ /**
+ * Verify the AP_REP from server and set context accordingly
+ * @param is
+ * @param mechTokenSize
+ * @return
+ * @throws GSSException
+ * @throws IOException
+ */
+ private void verifyServerToken(InputStream is, int mechTokenSize)
+ throws GSSException {
+ byte[] token;
+ ApRep apRep;
+ try {
+ if (!(is.read() == MSG_AP_REP[0] && is.read() == MSG_AP_REP[1])) {
+ throw new GSSException(GSSException.FAILURE, -1, "Invalid ApRep message ID");
+ }
+ token = new byte[mechTokenSize - MSG_AP_REP.length];
+ is.read(token);
+ apRep = new ApRep();
+ apRep.decode(token);
+ } catch (IOException e) {
+ throw new GSSException(GSSException.FAILURE, -1, "Invalid ApRep " + e.getMessage());
+ }
+
+ try {
+ ApResponse.validate(getSessionKey(), apRep, outApReq);
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.UNAUTHORIZED, -1, "ApRep verification failed");
+ }
+
+ EncryptionKey key = apRep.getEncRepPart().getSubkey();
+ if (key != null) {
+ setSessionKey(key, ACCEPTOR_SUBKEY);
+ }
+
+ int seqNum = apRep.getEncRepPart().getSeqNumber();
+ setPeerSequenceNumber(seqNum == -1 ? 0 : seqNum);
+ }
+
+ public byte[] acceptSecContext(InputStream is, int mechTokenSize)
+ throws GSSException {
+ byte[] ret = null;
+
+ if (isInitiator()) {
+ throw new GSSException(GSSException.FAILURE, -1, "acceptSecContext called on initiator");
+ }
+
+ if (ctxState == STATE_NONE) {
+ ctxState = STATE_ESTABLISHING;
+ if (!myCred.isAcceptorCredential()) {
+ throw new GSSException(GSSException.FAILURE, -1, "No acceptor credential available");
+ }
+
+ KerbyAcceptCred acceptCred = (KerbyAcceptCred) myCred;
+ CredUtils.checkPrincipalPermission(
+ ((KerbyNameElement) acceptCred.getName()).getPrincipalName().getName(), "accept");
+
+ if (getMutualAuthState()) {
+ ret = verifyClientToken(acceptCred, is, mechTokenSize);
+ }
+
+ gssEncryptor = new KerbyGssEncryptor(getSessionKey());
+
+ myCred = null;
+ ctxState = STATE_ESTABLISHED;
+ }
+
+ return ret;
+ }
+
+ private byte[] verifyClientToken(KerbyAcceptCred acceptCred, InputStream is, int mechTokenSize)
+ throws GSSException {
+ byte[] token;
+ ApReq apReq;
+ try {
+ if (!(is.read() == MSG_AP_REQ[0] && is.read() == MSG_AP_REQ[1])) {
+ throw new GSSException(GSSException.FAILURE, -1, "Invalid ApReq message ID");
+ }
+
+ token = new byte[mechTokenSize - MSG_AP_REQ.length];
+ is.read(token);
+ apReq = new ApReq();
+ apReq.decode(token);
+ } catch (IOException e) {
+ throw new GSSException(GSSException.UNAUTHORIZED, -1, "ApReq invalid:" + e.getMessage());
+ }
+
+ int kvno = apReq.getTicket().getEncryptedEncPart().getKvno();
+ int encryptType = apReq.getTicket().getEncryptedEncPart().getEType().getValue();
+
+ // Get server key from credential
+ EncryptionKey serverKey = KerbyUtil.getEncryptionKey(acceptCred.getKeys(), encryptType, kvno);
+ if (serverKey == null) {
+ throw new GSSException(GSSException.FAILURE, -1, "Server key not found");
+ }
+
+ try {
+ ApRequest.validate(serverKey, apReq, channelBinding.getInitiatorAddress(), 5 * 60 * 1000);
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.UNAUTHORIZED, -1, "ApReq verification failed: " + e.getMessage());
+ }
+
+ ApResponse apResponse = new ApResponse(apReq);
+ ApRep apRep;
+ try {
+ apRep = apResponse.getApRep();
+ } catch (KrbException e) {
+ throw new GSSException(GSSException.UNAUTHORIZED, -1, "Generate ApRep failed");
+ }
+
+ EncTicketPart apReqTicketEncPart = apReq.getTicket().getEncPart();
+
+ EncryptionKey ssKey = apReqTicketEncPart.getKey();
+ Authenticator auth = apReq.getAuthenticator();
+ EncryptionKey subKey = auth.getSubKey();
+
+ if (subKey != null) {
+ setSessionKey(subKey, INITIATOR_SUBKEY);
+ } else {
+ setSessionKey(ssKey, SESSION_KEY);
+ }
+
+ // initial seqNumber
+ int seqNumber = auth.getSeqNumber();
+ setMySequenceNumber(seqNumber);
+ // initial authtime, tktflags, authdata,
+ setAuthTime(apReqTicketEncPart.getAuthTime().toString());
+ setTicketFlags(apReqTicketEncPart.getFlags());
+ setAuthData(apReqTicketEncPart.getAuthorizationData());
+
+ byte[] ret = null;
+ try {
+ ByteBuffer outBuffer = ByteBuffer.allocate(apRep.encodingLength() + 2);
+ outBuffer.put(MSG_AP_REP);
+ apRep.encode(outBuffer);
+ outBuffer.flip();
+ ret = outBuffer.array();
+ } catch (IOException e) {
+ throw new GSSException(GSSException.FAILURE, -1, "Generate ApRep bytes failed:" + e.getMessage());
+ }
+ return ret;
+ }
+
+ public int getWrapSizeLimit(int qop, boolean confReq, int maxTokSize)
+ throws GSSException {
+ if (gssEncryptor.isV2()) {
+ return WrapTokenV2.getMsgSizeLimit(qop, confReq, maxTokSize, gssEncryptor);
+ } else {
+ return WrapTokenV1.getMsgSizeLimit(qop, confReq, maxTokSize, gssEncryptor);
+ }
+ }
+
+ public void wrap(InputStream is, OutputStream os, MessageProp msgProp)
+ throws GSSException {
+ if (ctxState != STATE_ESTABLISHED) {
+ throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for wrap");
+ }
+ if (gssEncryptor.isV2()) {
+ WrapTokenV2 token = new WrapTokenV2(this, inBuf, 0, len, msgProp);
+ token.wrap(os);
+ } else {
+ WrapTokenV1 token = new WrapTokenV1(this, inBuf, 0, len, msgProp);
+ token.wrap(os);
+ }
+ }
+
+ public byte[] wrap(byte[] inBuf, int offset, int len,
+ MessageProp msgProp) throws GSSException {
+ if (ctxState != STATE_ESTABLISHED) {
+ throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for wrap");
+ }
+ byte[] ret;
+ if (gssEncryptor.isV2()) {
+ WrapTokenV2 token = new WrapTokenV2(this, inBuf, offset, len, msgProp);
+ ret = token.wrap();
+ } else {
+ WrapTokenV1 token = new WrapTokenV1(this, inBuf, offset, len, msgProp);
+ ret = token.wrap();
+ }
+ return ret;
+ }
+
+ public void unwrap(InputStream is, OutputStream os,
+ MessageProp msgProp) throws GSSException {
+ if (gssEncryptor.isV2()) {
+ WrapTokenV2 token = new WrapTokenV2(this, msgProp, is);
+ token.unwrap(os);
+ } else {
+ WrapTokenV1 token = new WrapTokenV1(this, msgProp, is);
+ token.unwrap(os);
+ }
+ }
+
+ public byte[] unwrap(byte[] inBuf, int offset, int len,
+ MessageProp msgProp) throws GSSException {
+ if (ctxState != STATE_ESTABLISHED) {
+ throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for unwrap");
+ }
+ byte[] ret;
+ if (gssEncryptor.isV2()) {
+ WrapTokenV2 token = new WrapTokenV2(this, msgProp, inBuf, offset, len);
+ ret = token.unwrap();
+ } else {
+ WrapTokenV1 token = new WrapTokenV1(this, msgProp, inBuf, offset, len);
+ ret = token.unwrap();
+ }
+ return ret;
+ }
+
+ public void getMIC(InputStream is, OutputStream os,
+ MessageProp msgProp)
+ throws GSSException {
+ }
+
+ public byte[] getMIC(byte[] inMsg, int offset, int len,
+ MessageProp msgProp) throws GSSException {
+ return null; // TODO: to be implemented
+ }
+
+ public void verifyMIC(InputStream is, InputStream msgStr,
+ MessageProp msgProp) throws GSSException {
+ }
+
+ public void verifyMIC(byte[]inTok, int tokOffset, int tokLen,
+ byte[] inMsg, int msgOffset, int msgLen,
+ MessageProp msgProp) throws GSSException {
+ }
+
+ public byte[] export() throws GSSException {
+ throw new GSSException(GSSException.UNAVAILABLE, -1, "Unsupported export method");
+ }
+
+ public void dispose() throws GSSException {
+ ctxState = STATE_DESTROYED;
+ setSessionKey(null, 0);
+ peerName = null;
+ myCred = null;
+ myName = null;
+ }
+
+
+ private String authTime;
+ private void setAuthTime(String authTime) {
+ this.authTime = authTime;
+ }
+
+ public Object inquireSecContext(InquireType type) throws GSSException {
+ if (ctxState != STATE_ESTABLISHED) {
+ throw new GSSException(GSSException.NO_CONTEXT, -1, "Invalid context");
+ }
+
+ switch (type) {
+ case KRB5_GET_SESSION_KEY:
+ return getSessionKey();
+ case KRB5_GET_TKT_FLAGS:
+ return KerbyUtil.ticketFlagsToBooleans(ticketFlags);
+ case KRB5_GET_AUTHZ_DATA:
+ if (isInitiator()) {
+ throw new GSSException(GSSException.UNAVAILABLE, -1,
+ "Authorization data not available for initiator");
+ } else {
+ return KerbyUtil.kerbyAuthorizationDataToJgssAuthorizationDataEntries(authData);
+ }
+ case KRB5_GET_AUTHTIME:
+ return authTime;
+ }
+ throw new GSSException(GSSException.UNAVAILABLE, -1, "Unsupported inquire type");
+ }
+
+
+ // functions not belong to SPI
+ private void setSessionKey(EncryptionKey encryptionKey, int keyComesFrom) {
+ this.sessionKey = encryptionKey;
+ this.keyComesFrom = keyComesFrom;
+ }
+
+ public int getKeyComesFrom() {
+ return keyComesFrom;
+ }
+
+ private EncryptionKey getSessionKey() {
+ return sessionKey;
+ }
+
+ private void setTicketFlags(TicketFlags ticketFlags) {
+ this.ticketFlags = ticketFlags;
+ }
+
+ private AuthorizationData authData;
+ private void setAuthData(AuthorizationData authData) {
+ this.authData = authData;
+ }
+
+
+ private int mySequenceNumber;
+ private int peerSequenceNumber;
+ private Object mySequenceNumberLock;
+ private Object peerSequenceNumberLock;
+
+ public void setMySequenceNumber(int sequenceNumber) {
+ synchronized (mySequenceNumberLock) {
+ mySequenceNumber = sequenceNumber;
+ }
+ }
+
+ public int incMySequenceNumber() {
+ synchronized (mySequenceNumberLock) {
+ return mySequenceNumber++;
+ }
+ }
+
+ public void setPeerSequenceNumber(int sequenceNumber) {
+ synchronized (peerSequenceNumberLock) {
+ peerSequenceNumber = sequenceNumber;
+ }
+ }
+
+ public int incPeerSequenceNumber() {
+ synchronized (peerSequenceNumberLock) {
+ return peerSequenceNumber++;
+ }
+ }
+
+ public KerbyGssEncryptor getGssEncryptor() {
+ return gssEncryptor;
+ }
+}