You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by co...@apache.org on 2017/07/21 15:03:31 UTC
[14/18] directory-kerby git commit: Refactoring the package and
structure
Refactoring the package and structure
Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/976b16cf
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/976b16cf
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/976b16cf
Branch: refs/heads/trunk
Commit: 976b16cfc1f0caa16e1645b605d011a976f96418
Parents: 2bc1ac7
Author: Drankye <dr...@gmail.com>
Authored: Fri Jul 1 17:08:14 2016 +0800
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Fri Jul 21 14:59:37 2017 +0100
----------------------------------------------------------------------
.../kerb/integration/test/KerbyGssAppTest.java | 3 +-
.../kerby/kerberos/kerb/gss/GssMechFactory.java | 149 ++++
.../kerberos/kerb/gss/KerbyGssProvider.java | 46 ++
.../kerby/kerberos/kerb/gss/impl/CredUtils.java | 89 +++
.../kerberos/kerb/gss/impl/GssAcceptCred.java | 72 ++
.../kerberos/kerb/gss/impl/GssContext.java | 674 +++++++++++++++++++
.../kerberos/kerb/gss/impl/GssCredElement.java | 81 +++
.../kerberos/kerb/gss/impl/GssEncryptor.java | 388 +++++++++++
.../kerberos/kerb/gss/impl/GssInitCred.java | 53 ++
.../kerberos/kerb/gss/impl/GssNameElement.java | 135 ++++
.../kerberos/kerb/gss/impl/GssTokenBase.java | 59 ++
.../kerberos/kerb/gss/impl/GssTokenV1.java | 319 +++++++++
.../kerberos/kerb/gss/impl/GssTokenV2.java | 282 ++++++++
.../kerby/kerberos/kerb/gss/impl/GssUtil.java | 386 +++++++++++
.../kerberos/kerb/gss/impl/MicTokenV1.java | 92 +++
.../kerberos/kerb/gss/impl/MicTokenV2.java | 94 +++
.../kerberos/kerb/gss/impl/WrapTokenV1.java | 196 ++++++
.../kerberos/kerb/gss/impl/WrapTokenV2.java | 159 +++++
.../kerberos/kerb/gssapi/KerbyMechFactory.java | 149 ----
.../kerby/kerberos/kerb/gssapi/Provider.java | 46 --
.../kerberos/kerb/gssapi/krb5/CredUtils.java | 89 ---
.../kerb/gssapi/krb5/KerbyAcceptCred.java | 72 --
.../kerberos/kerb/gssapi/krb5/KerbyContext.java | 673 ------------------
.../kerb/gssapi/krb5/KerbyCredElement.java | 80 ---
.../kerb/gssapi/krb5/KerbyGssEncryptor.java | 388 -----------
.../kerb/gssapi/krb5/KerbyGssTokenBase.java | 59 --
.../kerb/gssapi/krb5/KerbyGssTokenV1.java | 319 ---------
.../kerb/gssapi/krb5/KerbyGssTokenV2.java | 282 --------
.../kerb/gssapi/krb5/KerbyInitCred.java | 53 --
.../kerb/gssapi/krb5/KerbyNameElement.java | 134 ----
.../kerberos/kerb/gssapi/krb5/KerbyUtil.java | 386 -----------
.../kerberos/kerb/gssapi/krb5/MicTokenV1.java | 92 ---
.../kerberos/kerb/gssapi/krb5/MicTokenV2.java | 94 ---
.../kerberos/kerb/gssapi/krb5/WrapTokenV1.java | 196 ------
.../kerberos/kerb/gssapi/krb5/WrapTokenV2.java | 159 -----
35 files changed, 3276 insertions(+), 3272 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyGssAppTest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyGssAppTest.java b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyGssAppTest.java
index d9030df..fbb3f3f 100644
--- a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyGssAppTest.java
+++ b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyGssAppTest.java
@@ -19,6 +19,7 @@
*/
package org.apache.kerby.kerberos.kerb.integration.test;
+import org.apache.kerby.kerberos.kerb.gss.KerbyGssProvider;
import org.junit.Before;
import org.junit.Test;
@@ -29,7 +30,7 @@ public class KerbyGssAppTest extends GssAppTest {
@Before
@Override
public void setUp() throws Exception {
- Provider provider = new org.apache.kerby.kerberos.kerb.gssapi.Provider();
+ Provider provider = new KerbyGssProvider();
java.security.Security.insertProviderAt(provider, 1);
super.setUp();
}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/GssMechFactory.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/GssMechFactory.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/GssMechFactory.java
new file mode 100644
index 0000000..735368b
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/GssMechFactory.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.gss;
+
+import org.apache.kerby.kerberos.kerb.gss.impl.GssAcceptCred;
+import org.apache.kerby.kerberos.kerb.gss.impl.GssContext;
+import org.apache.kerby.kerberos.kerb.gss.impl.GssCredElement;
+import org.apache.kerby.kerberos.kerb.gss.impl.GssInitCred;
+import org.apache.kerby.kerberos.kerb.gss.impl.GssNameElement;
+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 GssMechFactory implements MechanismFactory {
+ private static final Provider PROVIDER =
+ new KerbyGssProvider();
+
+ 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 GssMechFactory(GSSCaller caller) {
+ this.caller = caller;
+ }
+
+ public GSSNameSpi getNameElement(String nameStr, Oid nameType)
+ throws GSSException {
+ return GssNameElement.getInstance(nameStr, nameType);
+ }
+
+ public GSSNameSpi getNameElement(byte[] name, Oid nameType)
+ throws GSSException {
+ return GssNameElement.getInstance(name.toString(), nameType);
+ }
+
+ // Used by initiator
+ public GSSContextSpi getMechanismContext(GSSNameSpi peer,
+ GSSCredentialSpi myInitiatorCred,
+ int lifetime) throws GSSException {
+ if (peer != null && !(peer instanceof GssNameElement)) {
+ peer = GssNameElement.getInstance(peer.toString(), peer.getStringNameType());
+ }
+ if (myInitiatorCred == null) {
+ myInitiatorCred = getCredentialElement(null, lifetime, 0, GSSCredential.INITIATE_ONLY);
+ }
+ return new GssContext(caller, (GssNameElement) peer, (GssInitCred) myInitiatorCred, lifetime);
+ }
+
+ public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
+ throws GSSException {
+ if (myAcceptorCred == null) {
+ myAcceptorCred = getCredentialElement(null, 0,
+ GSSCredential.INDEFINITE_LIFETIME, GSSCredential.ACCEPT_ONLY);
+ }
+ return new GssContext(caller, (GssAcceptCred) myAcceptorCred);
+ }
+
+ // Reconstruct from previously exported context
+ public GSSContextSpi getMechanismContext(byte[] exportedContext)
+ throws GSSException {
+ return new GssContext(caller, exportedContext);
+ }
+
+ public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
+ int initLifetime,
+ int acceptLifetime,
+ int usage)
+ throws GSSException {
+ if (name != null && !(name instanceof GssNameElement)) {
+ name = GssNameElement.getInstance(name.toString(), name.getStringNameType());
+ }
+
+ GssCredElement credElement;
+
+ if (usage == GSSCredential.INITIATE_ONLY) {
+ credElement = GssInitCred.getInstance(caller, (GssNameElement) name, initLifetime);
+ } else if (usage == GSSCredential.ACCEPT_ONLY) {
+ credElement = GssAcceptCred.getInstance(caller, (GssNameElement) name, acceptLifetime);
+ } else if (usage == GSSCredential.INITIATE_AND_ACCEPT) {
+ throw new GSSException(GSSException.FAILURE, -1, "Unsupported usage mode: INITIATE_AND_ACCEPT");
+ } else {
+ throw new GSSException(GSSException.FAILURE, -1, "Unknown usage mode: " + usage);
+ }
+
+ return credElement;
+ }
+
+ private static Oid createOid(String oidStr) {
+ Oid retVal;
+ try {
+ retVal = new Oid(oidStr);
+ } catch (GSSException e) {
+ retVal = null;
+ }
+ return retVal;
+ }
+
+ public static Oid getOid() {
+ return KRB5_OID;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/KerbyGssProvider.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/KerbyGssProvider.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/KerbyGssProvider.java
new file mode 100644
index 0000000..83c5404
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/KerbyGssProvider.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.gss;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Proivder is used to register the implementation of gssapi mechanism into the system
+ */
+public final class KerbyGssProvider 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.gss.GssMechFactory";
+
+ public KerbyGssProvider() {
+ super("KerbyGssApi", 0.01d, INFO);
+
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
+
+ put(MECHANISM_GSSAPI, MECHANISM_GSSAPI_CLASS);
+
+ return null;
+ }
+ });
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/CredUtils.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/CredUtils.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/CredUtils.java
new file mode 100644
index 0000000..fdcb046
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/CredUtils.java
@@ -0,0 +1,89 @@
+package org.apache.kerby.kerberos.kerb.gss.impl;
+
+import org.ietf.jgss.GSSException;
+import sun.security.jgss.GSSCaller;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.*;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Set;
+
+/**
+ * Utility functions to deal with credentials in Context
+ */
+public class CredUtils {
+
+ public static <T> Set<T> getContextPrivateCredentials(Class<T> credentialType, AccessControlContext acc) {
+ Subject subject = Subject.getSubject(acc);
+ Set<T> creds = subject.getPrivateCredentials(credentialType);
+ return creds;
+ }
+
+ public static <T> Set<T> getContextCredentials(final Class<T> credentialType) throws GSSException {
+ final AccessControlContext acc = AccessController.getContext();
+ try {
+ return AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Set<T>>() {
+ public Set<T> run() throws Exception {
+ return CredUtils.getContextPrivateCredentials(credentialType, acc);
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw new GSSException(GSSException.NO_CRED, -1, "Get credential from context failed");
+ }
+ }
+
+ public static KerberosTicket getKerberosTicketFromContext(GSSCaller caller,
+ final String clientName,
+ final String serverName) throws GSSException {
+ Set<KerberosTicket> tickets = getContextCredentials(KerberosTicket.class);
+ for (KerberosTicket ticket : tickets) {
+ if (ticket.isCurrent() && (serverName == null || ticket.getServer().getName().equals(serverName))
+ && (clientName == null || ticket.getClient().getName().equals(clientName))) {
+ return ticket;
+ }
+ }
+ return null;
+ }
+
+ public static KeyTab getKeyTabFromContext(KerberosPrincipal principal) throws GSSException {
+ Set<KeyTab> tabs = getContextCredentials(KeyTab.class);
+ for (KeyTab tab : tabs) {
+ KerberosKey[] keys = tab.getKeys(principal);
+ if (keys != null && keys.length > 0) {
+ return tab;
+ }
+ }
+ return null;
+ }
+
+ public static void addCredentialToSubject(final KerberosTicket ticket) throws GSSException {
+ final AccessControlContext acc = AccessController.getContext();
+
+ final Subject subject = AccessController.doPrivileged(
+ new java.security.PrivilegedAction<Subject>() {
+ public Subject run() {
+ return Subject.getSubject(acc);
+ }
+ });
+
+ AccessController.doPrivileged(
+ new java.security.PrivilegedAction<Void>() {
+ public Void run() {
+ subject.getPrivateCredentials().add(ticket);
+ return null;
+ }
+ });
+ }
+
+ public static void checkPrincipalPermission(String principalName, String action) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ ServicePermission sp = new ServicePermission(principalName, action);
+ sm.checkPermission(sp);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssAcceptCred.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssAcceptCred.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssAcceptCred.java
new file mode 100644
index 0000000..9ba718f
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssAcceptCred.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.gss.impl;
+
+
+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 GssAcceptCred extends GssCredElement {
+
+ private final KeyTab keyTab;
+
+ public static GssAcceptCred getInstance(final GSSCaller caller,
+ GssNameElement 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 GssAcceptCred(caller, name, keyTab, lifeTime);
+ }
+
+ private GssAcceptCred(GSSCaller caller, GssNameElement name, KeyTab keyTab, int lifeTime) {
+ super(caller, name);
+ this.keyTab = keyTab;
+ this.accLifeTime = lifeTime;
+ }
+
+ public boolean isInitiatorCredential() throws GSSException {
+ return false;
+ }
+
+ public boolean isAcceptorCredential() throws GSSException {
+ return true;
+ }
+
+ public KeyTab getKeyTab() {
+ return this.keyTab;
+ }
+
+ public KerberosKey[] getKeys() {
+ KerberosPrincipal princ = new KerberosPrincipal(name.getPrincipalName().getName(),
+ name.getPrincipalName().getNameType().getValue());
+ return keyTab.getKeys(princ);
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssContext.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssContext.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssContext.java
new file mode 100644
index 0000000..bbb149a
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssContext.java
@@ -0,0 +1,674 @@
+/**
+ * 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 com.sun.security.jgss.InquireType;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.gss.GssMechFactory;
+import org.apache.kerby.kerberos.kerb.gss.KerbyGssProvider;
+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 GssContext 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 GssCredElement myCred;
+ private boolean initiator;
+ private GssNameElement myName;
+ private GssNameElement 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 GssEncryptor gssEncryptor;
+
+ // Called on initiator's side.
+ public GssContext(GSSCaller caller, GssNameElement peerName, GssCredElement 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 GssContext(GSSCaller caller, GssAcceptCred myCred)
+ throws GSSException {
+ this.caller = caller;
+ this.myCred = myCred;
+ this.initiator = false;
+
+ mySequenceNumberLock = new Object();
+ peerSequenceNumberLock = new Object();
+ }
+
+ public GssContext(GSSCaller caller, byte[] interProcessToken)
+ throws GSSException {
+ throw new GSSException(GSSException.UNAVAILABLE, -1, "Unsupported feature");
+ }
+
+ public Provider getProvider() {
+ return new KerbyGssProvider();
+ }
+
+ 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 GssMechFactory.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 = (GssNameElement) myCred.getName();
+ PrincipalName clientPrincipal = myName.getPrincipalName();
+
+ sgtTicket = GssUtil.getSgtCredentialFromContext(caller, clientPrincipal.getName(), serviceName);
+
+ if (sgtTicket == null) {
+ sgtTicket = GssUtil.applySgtCredential(((GssInitCred) myCred).ticket, serviceName);
+
+ // add this service credential to context
+ final KerberosTicket ticket =
+ GssUtil.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 GssEncryptor(getSessionKey());
+ ctxState = STATE_ESTABLISHED;
+ }
+
+ } else if (ctxState == STATE_ESTABLISHING) {
+ verifyServerToken(is, mechTokenSize);
+ gssEncryptor = new GssEncryptor(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, GssContext.INITIATOR_SUBKEY);
+ } else {
+ setSessionKey(sgt.getSessionKey(), GssContext.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");
+ }
+
+ GssAcceptCred acceptCred = (GssAcceptCred) myCred;
+ CredUtils.checkPrincipalPermission(
+ ((GssNameElement) acceptCred.getName()).getPrincipalName().getName(), "accept");
+
+ if (getMutualAuthState()) {
+ ret = verifyClientToken(acceptCred, is, mechTokenSize);
+ }
+
+ gssEncryptor = new GssEncryptor(getSessionKey());
+
+ myCred = null;
+ ctxState = STATE_ESTABLISHED;
+ }
+
+ return ret;
+ }
+
+ private byte[] verifyClientToken(GssAcceptCred 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 = GssUtil.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 GssUtil.ticketFlagsToBooleans(ticketFlags);
+ case KRB5_GET_AUTHZ_DATA:
+ if (isInitiator()) {
+ throw new GSSException(GSSException.UNAVAILABLE, -1,
+ "Authorization data not available for initiator");
+ } else {
+ return GssUtil.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 GssEncryptor getGssEncryptor() {
+ return gssEncryptor;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssCredElement.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssCredElement.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssCredElement.java
new file mode 100644
index 0000000..657f222
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssCredElement.java
@@ -0,0 +1,81 @@
+/**
+ * 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.gss.KerbyGssProvider;
+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 GssCredElement implements GSSCredentialSpi {
+
+ static final Oid KRB5_OID = createOid("1.2.840.113554.1.2.2");
+
+ protected GSSCaller caller;
+ protected GssNameElement name;
+ protected int initLifeTime;
+ protected int accLifeTime;
+
+ GssCredElement(GSSCaller caller, GssNameElement name) {
+ this.caller = caller;
+ this.name = name;
+ }
+
+ public Provider getProvider() {
+ return new KerbyGssProvider();
+ }
+
+ 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/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssEncryptor.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssEncryptor.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssEncryptor.java
new file mode 100644
index 0000000..4eb96e3
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssEncryptor.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.gss.impl;
+
+
+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 GssEncryptor {
+
+ 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 GssEncryptor(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 = GssTokenV1.SGN_ALG_DES_MAC_MD5;
+ sealAlg = GssTokenV1.SEAL_ALG_DES;
+ checkSumSize = 8;
+ } else if (encKeyType == EncryptionType.DES3_CBC_SHA1) {
+ sgnAlg = GssTokenV1.SGN_ALG_HMAC_SHA1_DES3_KD;
+ sealAlg = GssTokenV1.SEAL_ALG_DES3_KD;
+ checkSumSize = 20;
+ } else if (encKeyType == EncryptionType.ARCFOUR_HMAC) {
+ sgnAlg = GssTokenV1.SGN_ALG_RC4_HMAC;
+ sealAlg = GssTokenV1.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 = GssTokenV1.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 GssTokenV1.SGN_ALG_DES_MAC_MD5:
+ Md5Provider md5Provider = new Md5Provider();
+ md5Provider.hash(toProc);
+ toProc = md5Provider.output();
+
+ case GssTokenV1.SGN_ALG_DES_MAC:
+ DesProvider desProvider = new DesProvider();
+ return desProvider.cbcMac(encKeyBytes, IV_ZEROR_8B, toProc);
+
+ case GssTokenV1.SGN_ALG_HMAC_SHA1_DES3_KD:
+ chksumType = CheckSumType.HMAC_SHA1_DES3_KD;
+ break;
+ case GssTokenV1.SGN_ALG_RC4_HMAC:
+ chksumType = CheckSumType.MD5_HMAC_ARCFOUR;
+ if (isMic) {
+ keyUsage = GssTokenV1.KG_USAGE_MS_SIGN;
+ }
+ break;
+ case GssTokenV1.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 GssTokenV1.SGN_ALG_DES_MAC_MD5:
+ case GssTokenV1.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 GssTokenV1.SGN_ALG_HMAC_SHA1_DES3_KD:
+ handler = EncryptionHandler.getEncHandler(EncryptionType.DES3_CBC_SHA1_KD);
+ break;
+ case GssTokenV1.SGN_ALG_RC4_HMAC:
+ return encryptArcFourHmac(seqBytes, getKeyBytesWithLength(16), getFirstBytes(ivSrc, 8), encrypt);
+ case GssTokenV1.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, GssTokenV1.KG_USAGE_SEQ);
+ } else {
+ return handler.decryptRaw(seqBytes, key, iv, GssTokenV1.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 GssTokenV1.SEAL_ALG_DES:
+ handler = EncryptionHandler.getEncHandler(EncryptionType.DES_CBC_MD5);
+ break;
+ case GssTokenV1.SEAL_ALG_DES3_KD:
+ handler = EncryptionHandler.getEncHandler(EncryptionType.DES3_CBC_SHA1_KD);
+ break;
+ case GssTokenV1.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, GssTokenV1.KG_USAGE_SEAL);
+ } else {
+ return handler.decryptRaw(toProc, key, GssTokenV1.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/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssInitCred.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssInitCred.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssInitCred.java
new file mode 100644
index 0000000..0b2516d
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssInitCred.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.gss.impl;
+
+import org.ietf.jgss.GSSException;
+import sun.security.jgss.GSSCaller;
+
+import javax.security.auth.kerberos.KerberosTicket;
+
+public final class GssInitCred extends GssCredElement {
+
+ public KerberosTicket ticket;
+
+ private GssInitCred(GSSCaller caller, GssNameElement name, KerberosTicket ticket, int lifeTime) {
+ super(caller, name);
+ this.ticket = ticket;
+ this.initLifeTime = lifeTime;
+ }
+
+ public static GssInitCred getInstance(GSSCaller caller, GssNameElement name, int lifeTime) throws GSSException {
+ KerberosTicket ticket = CredUtils.getKerberosTicketFromContext(caller, name.getPrincipalName().getName(), null);
+ return new GssInitCred(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/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssNameElement.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssNameElement.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssNameElement.java
new file mode 100644
index 0000000..bd5c8a4
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssNameElement.java
@@ -0,0 +1,135 @@
+/**
+ * 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.gss.GssMechFactory;
+import org.apache.kerby.kerberos.kerb.gss.KerbyGssProvider;
+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 GssNameElement implements GSSNameSpi {
+
+ private PrincipalName principalName;
+ private Oid nameType = null;
+
+ GssNameElement(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 GssNameElement getInstance(String name, Oid oidNameType)
+ throws GSSException {
+ PrincipalName principalName = new PrincipalName(name, toKerbyNameType(oidNameType));
+ return new GssNameElement(principalName, oidNameType);
+ }
+
+ public Provider getProvider() {
+ return new KerbyGssProvider();
+ }
+
+ 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 GssMechFactory.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/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenBase.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenBase.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenBase.java
new file mode 100644
index 0000000..ec66aa5
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenBase.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.gss.impl;
+
+
+public abstract class GssTokenBase {
+ 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/976b16cf/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV1.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV1.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV1.java
new file mode 100644
index 0000000..1f063c3
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenV1.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.gss.impl;
+
+
+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 GssTokenV1 extends GssTokenBase {
+ // 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 GssEncryptor 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
+ GssTokenV1(int tokenType, GssContext context) throws GSSException {
+ initialize(tokenType, context, false);
+ createTokenHeader();
+ }
+
+ // Reconstruct a token
+ GssTokenV1(int tokenType, GssContext 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
+ GssTokenV1(int tokenType, GssContext context, MessageProp prop, InputStream is) throws GSSException {
+ reconstructInitializaion(tokenType, context, prop, is);
+ }
+
+ private void reconstructInitializaion(int tokenType, GssContext 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,
+ GssContext 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();
+}