directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From plusplusjia...@apache.org
Subject [1/2] directory-kerby git commit: Add some implemention of pkinit anonymous.
Date Tue, 24 Nov 2015 07:48:51 GMT
Repository: directory-kerby
Updated Branches:
  refs/heads/pkinit-support f6d5088bc -> 146967182


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/NameType.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/NameType.java
b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/NameType.java
index 9672883..1120665 100644
--- a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/NameType.java
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/NameType.java
@@ -27,7 +27,8 @@ public enum NameType implements KrbEnum {
     NT_SRV_INST(2),
     NT_SRV_HST(3),
     NT_SRV_XHST(4),
-    NT_UID(5);
+    NT_UID(5),
+    KRB5_NT_WELLKNOWN(11);
     
     private int value;
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/AlgorithmIdentifier.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/AlgorithmIdentifier.java
b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/AlgorithmIdentifier.java
index ed7a736..6f5d1b2 100644
--- a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/AlgorithmIdentifier.java
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/AlgorithmIdentifier.java
@@ -20,11 +20,9 @@
 package org.apache.kerby.kerberos.kerb.spec.cms;
 
 
-import org.apache.kerby.asn1.type.Asn1Any;
 import org.apache.kerby.asn1.type.Asn1FieldInfo;
 import org.apache.kerby.asn1.type.Asn1ObjectIdentifier;
 import org.apache.kerby.asn1.type.Asn1SequenceType;
-import org.apache.kerby.asn1.type.Asn1Type;
 
 /**
  AlgorithmIdentifier  ::=  SEQUENCE  {
@@ -38,7 +36,7 @@ public class AlgorithmIdentifier extends Asn1SequenceType {
 
     static Asn1FieldInfo[] fieldInfos = new Asn1FieldInfo[] {
             new Asn1FieldInfo(ALGORITHM, -1, Asn1ObjectIdentifier.class),
-            new Asn1FieldInfo(PARAMETERS, -1, Asn1Any.class)
+            new Asn1FieldInfo(PARAMETERS, -1, DHParameter.class)
     };
 
     public AlgorithmIdentifier() {
@@ -53,11 +51,11 @@ public class AlgorithmIdentifier extends Asn1SequenceType {
         setFieldAs(ALGORITHM, algorithm);
     }
 
-    public Asn1Type getParameters() {
-        return getFieldAsAny(PARAMETERS);
+    public DHParameter getParameters() {
+        return getFieldAs(PARAMETERS, DHParameter.class);
     }
 
-    public void setParameters(Asn1Type parameters) {
+    public void setParameters(DHParameter parameters) {
         setFieldAsAny(PARAMETERS, parameters);
     }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/DHParameter.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/DHParameter.java
b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/DHParameter.java
new file mode 100644
index 0000000..6e4f81d
--- /dev/null
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/DHParameter.java
@@ -0,0 +1,51 @@
+package org.apache.kerby.kerberos.kerb.spec.cms;
+
+import org.apache.kerby.asn1.type.Asn1FieldInfo;
+import org.apache.kerby.asn1.type.Asn1Integer;
+import org.apache.kerby.asn1.type.Asn1SequenceType;
+
+import java.math.BigInteger;
+
+public class DHParameter extends Asn1SequenceType {
+
+    private static final int P = 0;
+    private static final int G = 1;
+    private static final int Q = 2;
+
+    static Asn1FieldInfo[] fieldInfos = new Asn1FieldInfo[] {
+            new Asn1FieldInfo(P, -1, Asn1Integer.class),
+            new Asn1FieldInfo(G, -1, Asn1Integer.class),
+            new Asn1FieldInfo(Q, -1, Asn1Integer.class),
+    };
+
+    public DHParameter() {
+        super(fieldInfos);
+    }
+
+    public void setP(BigInteger p) {
+        setFieldAsBigInteger(P, p);
+    }
+
+    public BigInteger getP() {
+        Asn1Integer p = getFieldAs(P, Asn1Integer.class);
+        return p.getValue();
+    }
+
+    public void setG(BigInteger g) {
+        setFieldAsBigInteger(G, g);
+    }
+
+    public BigInteger getG() {
+        Asn1Integer g = getFieldAs(G, Asn1Integer.class);
+        return g.getValue();
+    }
+
+    public void setQ(BigInteger q) {
+        setFieldAsBigInteger(Q, q);
+    }
+
+    public BigInteger getQ() {
+        Asn1Integer q = getFieldAs(Q, Asn1Integer.class);
+        return q.getValue();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/SubjectPublicKeyInfo.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/SubjectPublicKeyInfo.java
b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/SubjectPublicKeyInfo.java
index e6e4392..d273da7 100644
--- a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/SubjectPublicKeyInfo.java
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/cms/SubjectPublicKeyInfo.java
@@ -50,8 +50,8 @@ public class SubjectPublicKeyInfo extends Asn1SequenceType {
         setFieldAs(ALGORITHM, algorithm);
     }
 
-    public byte[] getSubjectPubKey() {
-        return getFieldAsOctets(SUBJECT_PUBLIC_KEY);
+    public Asn1BitString getSubjectPubKey() {
+        return getFieldAs(SUBJECT_PUBLIC_KEY, Asn1BitString.class);
     }
 
     public void setSubjectPubKey(byte[] subjectPubKey) {

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/pa/pkinit/KdcDHKeyInfo.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/pa/pkinit/KdcDHKeyInfo.java
b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/pa/pkinit/KdcDHKeyInfo.java
index 0e9504e..d21217d 100644
--- a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/pa/pkinit/KdcDHKeyInfo.java
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/pa/pkinit/KdcDHKeyInfo.java
@@ -62,4 +62,12 @@ public class KdcDHKeyInfo extends KrbSequenceType {
     public void setNonce(int nonce) {
         setFieldAsInt(NONCE, nonce);
     }
+
+    public KerberosTime getDHKeyExpiration() {
+        return getFieldAsTime(DH_KEY_EXPIRATION);
+    }
+
+    public void setDHKeyExpiration(KerberosTime time) {
+        setFieldAs(DH_KEY_EXPIRATION, time);
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfig.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfig.java
b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfig.java
index 82b8dfd..8d1565e 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfig.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfig.java
@@ -174,4 +174,14 @@ public class KdcConfig extends Conf {
     public List<String> getIssuers() {
         return Arrays.asList(KrbConfHelper.getStringArrayUnderSection(this, KdcConfigKey.ISSUERS));
     }
+
+    public List<String> getPkinitAnchors() {
+        return Arrays.asList(KrbConfHelper.getStringArrayUnderSection(this,
+                KdcConfigKey.PKINIT_ANCHORS));
+    }
+
+    public String getPkinitIdentity() {
+        return KrbConfHelper.getStringUnderSection(this,
+                KdcConfigKey.PKINIT_IDENTITY);
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfigKey.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfigKey.java
b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfigKey.java
index 178d19d..5e7d8a4 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfigKey.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfigKey.java
@@ -51,7 +51,9 @@ public enum KdcConfigKey implements SectionConfigKey {
     KDC_MAX_DGRAM_REPLY_SIZE(4096, "kdcdefaults"),
     VERIFY_KEY(null, "kdcdefaults"),
     DECRYPTION_KEY(null, "kdcdefaults"),
-    ISSUERS(null, "kdcdefaults");
+    ISSUERS(null, "kdcdefaults"),
+    PKINIT_IDENTITY(null, "libdefaults"),
+    PKINIT_ANCHORS(null, "libdefaults");
 
     private Object defaultValue;
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthContext.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthContext.java
b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthContext.java
index 551e1b3..51e14e2 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthContext.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthContext.java
@@ -19,15 +19,19 @@
  */
 package org.apache.kerby.kerberos.kerb.server.preauth;
 
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.spec.pa.PaData;
+
 import java.util.ArrayList;
 import java.util.List;
 
 public class PreauthContext {
     private boolean preauthRequired = true;
     private List<PreauthHandle> handles = new ArrayList<PreauthHandle>(5);
+    private PaData outputPaData;
 
     public PreauthContext() {
-
+        this.outputPaData = new PaData();
     }
 
     public boolean isPreauthRequired() {
@@ -41,4 +45,12 @@ public class PreauthContext {
     public List<PreauthHandle> getHandles() {
         return handles;
     }
+
+    public void reset() {
+        this.outputPaData = new PaData();
+    }
+
+    public PaData getOutputPaData() throws KrbException {
+        return outputPaData;
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthHandler.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthHandler.java
b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthHandler.java
index cff6ba6..baa6324 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthHandler.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthHandler.java
@@ -23,6 +23,7 @@ import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.server.KdcContext;
 import org.apache.kerby.kerberos.kerb.server.preauth.builtin.EncTsPreauth;
 import org.apache.kerby.kerberos.kerb.server.preauth.builtin.TgtPreauth;
+import org.apache.kerby.kerberos.kerb.server.preauth.pkinit.PkinitPreauth;
 import org.apache.kerby.kerberos.kerb.server.preauth.token.TokenPreauth;
 import org.apache.kerby.kerberos.kerb.server.request.KdcRequest;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaData;
@@ -54,6 +55,9 @@ public class PreauthHandler {
 
         preauth = new TokenPreauth();
         preauths.add(preauth);
+
+        preauth = new PkinitPreauth();
+        preauths.add(preauth);
     }
 
     /**
@@ -70,6 +74,7 @@ public class PreauthHandler {
         PreauthContext preauthContext = new PreauthContext();
 
         KdcContext kdcContext = kdcRequest.getKdcContext();
+        initWith(kdcContext);
         preauthContext.setPreauthRequired(kdcContext.getConfig().isPreauthRequired());
 
         for (KdcPreauth preauth : preauths) {
@@ -133,4 +138,13 @@ public class PreauthHandler {
         }
         return false;
     }
+
+    public static boolean isPkinit(PaData paData) {
+        for (PaDataEntry paEntry : paData.getElements()) {
+            if (paEntry.getPaDataType() == PaDataType.PK_AS_REQ) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/DhServer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/DhServer.java
b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/DhServer.java
new file mode 100644
index 0000000..d8bf903
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/DhServer.java
@@ -0,0 +1,133 @@
+/*
+ *  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.server.preauth.pkinit;
+
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+
+
+/**
+ * The server-side of Diffie-Hellman key agreement for Kerberos PKINIT.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+class DhServer {
+    private static AlgorithmParameterSpec aesIv = new IvParameterSpec(new byte[16]);
+
+    private KeyAgreement serverKeyAgree;
+    private SecretKey serverAesKey;
+
+
+    PublicKey initAndDoPhase(byte[] clientPubKeyEnc) throws Exception {
+        /*
+         * The server has received the client's public key in encoded format.  The
+         * server instantiates a DH public key from the encoded key material.
+         */
+        KeyFactory serverKeyFac = KeyFactory.getInstance("DH");
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(clientPubKeyEnc);
+        PublicKey clientPubKey = serverKeyFac.generatePublic(x509KeySpec);
+
+        /*
+         * The server gets the DH parameters associated with the client's public
+         * key.  The server must use the same parameters when it generates its own key pair.
+         */
+        DHParameterSpec dhParamSpec = ((DHPublicKey) clientPubKey).getParams();
+
+        // The server creates its own DH key pair.
+        KeyPairGenerator serverKpairGen = KeyPairGenerator.getInstance("DH");
+        serverKpairGen.initialize(dhParamSpec);
+        KeyPair serverKpair = serverKpairGen.generateKeyPair();
+
+        // The server creates and initializes its DH KeyAgreement object.
+        serverKeyAgree = KeyAgreement.getInstance("DH");
+        serverKeyAgree.init(serverKpair.getPrivate());
+
+        /*
+         * The server uses the client's public key for the only phase of its
+         * side of the DH protocol.
+         */
+        serverKeyAgree.doPhase(clientPubKey, true);
+
+        // The server encodes its public key, and sends it over to the client.
+        return serverKpair.getPublic();
+    }
+
+
+    byte[] generateKey(byte[] clientDhNonce, byte[] serverDhNonce) {
+        // ZZ length will be same as public key.
+        byte[] dhSharedSecret = serverKeyAgree.generateSecret();
+        byte[] x = dhSharedSecret;
+
+        if (clientDhNonce != null && clientDhNonce.length > 0
+                && serverDhNonce != null && serverDhNonce.length > 0)
{
+            x = concatenateBytes(dhSharedSecret, clientDhNonce);
+            x = concatenateBytes(x, serverDhNonce);
+        }
+
+        byte[] secret = OctetString2Key.kTruncate(dhSharedSecret.length, x);
+        serverAesKey = new SecretKeySpec(secret, 0, 16, "AES");
+
+        return serverAesKey.getEncoded();
+    }
+
+
+    /**
+     * Encrypt using AES in CTS mode.
+     *
+     * @param clearText
+     * @return The cipher text.
+     * @throws Exception
+     */
+    byte[] encryptAes(byte[] clearText) throws Exception {
+        // Use the secret key to encrypt/decrypt data.
+        Cipher serverCipher = Cipher.getInstance("AES/CTS/NoPadding");
+        serverCipher.init(Cipher.ENCRYPT_MODE, serverAesKey, aesIv);
+
+        return serverCipher.doFinal(clearText);
+    }
+
+
+    byte[] concatenateBytes(byte[] array1, byte[] array2) {
+        byte[] concatenatedBytes = new byte[array1.length + array2.length];
+
+        for (int i = 0; i < array1.length; i++) {
+            concatenatedBytes[i] = array1[i];
+        }
+
+        for (int j = array1.length; j < concatenatedBytes.length; j++) {
+            concatenatedBytes[j] = array2[j - array1.length];
+        }
+
+        return concatenatedBytes;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/OctetString2Key.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/OctetString2Key.java
b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/OctetString2Key.java
new file mode 100644
index 0000000..9829642
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/OctetString2Key.java
@@ -0,0 +1,93 @@
+/*
+ *  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.server.preauth.pkinit;
+
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+
+/**
+ * From RFC 4556:
+ * <p/>
+ * Define the function octetstring2key() as follows:
+ * <p/>
+ * octetstring2key(x) == random-to-key(K-truncate(
+ * SHA1(0x00 | x) |
+ * SHA1(0x01 | x) |
+ * SHA1(0x02 | x) |
+ * ...
+ * ))
+ * <p/>
+ * where x is an octet string; | is the concatenation operator; 0x00,
+ * 0x01, 0x02, etc. are each represented as a single octet; random-
+ * to-key() is an operation that generates a protocol key from a
+ * bitstring of length K; and K-truncate truncates its input to the
+ * first K bits.  Both K and random-to-key() are as defined in the
+ * kcrypto profile [RFC3961] for the enctype of the AS reply key.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class OctetString2Key {
+    /**
+     * Performs the function K-truncate to generate the AS reply key k.
+     *
+     * @param k
+     * @param x
+     * @return The AS reply key value.
+     */
+    public static byte[] kTruncate(int k, byte[] x) {
+        int numberOfBytes = k / 8;
+        byte[] result = new byte[numberOfBytes];
+
+        int count = 0;
+        byte[] filler = calculateIntegrity((byte) count, x);
+
+        int position = 0;
+
+        for (int i = 0; i < numberOfBytes; i++) {
+            if (position < filler.length) {
+                result[i] = filler[position];
+                position++;
+            } else {
+                count++;
+                filler = calculateIntegrity((byte) count, x);
+                position = 0;
+                result[i] = filler[position];
+                position++;
+            }
+        }
+
+        return result;
+    }
+
+
+    private static byte[] calculateIntegrity(byte count, byte[] data) {
+        try {
+            MessageDigest digester = MessageDigest.getInstance("SHA1");
+            digester.update(count);
+
+            return digester.digest(data);
+        } catch (NoSuchAlgorithmException nsae) {
+            return new byte[0];
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitKdcContext.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitKdcContext.java
b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitKdcContext.java
index 9fb9e51..137b64f 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitKdcContext.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitKdcContext.java
@@ -1,30 +1,31 @@
 /**
- *  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. 
- *  
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.server.preauth.pkinit;
 
 import org.apache.kerby.kerberos.kerb.preauth.pkinit.IdentityOpts;
+import org.apache.kerby.kerberos.kerb.preauth.pkinit.PkinitPlgCryptoContext;
 import org.apache.kerby.kerberos.kerb.preauth.pkinit.PluginOpts;
 
 public class PkinitKdcContext {
 
-    public PluginOpts pluginOpts;
-    public IdentityOpts identityOpts;
+    public PkinitPlgCryptoContext cryptoctx = new PkinitPlgCryptoContext();
+    public PluginOpts pluginOpts = new PluginOpts();
+    public IdentityOpts identityOpts = new IdentityOpts();
     public String realm;
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java
b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java
index 08baa0e..54f0693 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java
@@ -1,42 +1,86 @@
 /**
- *  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. 
- *  
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.server.preauth.pkinit;
 
+import org.apache.kerby.asn1.type.Asn1Integer;
 import org.apache.kerby.kerberos.kerb.KrbCodec;
+import org.apache.kerby.kerberos.kerb.KrbErrorCode;
 import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.common.CheckSumUtil;
+import org.apache.kerby.kerberos.kerb.common.KrbUtil;
 import org.apache.kerby.kerberos.kerb.preauth.PluginRequestContext;
+import org.apache.kerby.kerberos.kerb.preauth.pkinit.CMSMessageType;
+import org.apache.kerby.kerberos.kerb.preauth.pkinit.CertificateHelper;
+import org.apache.kerby.kerberos.kerb.preauth.pkinit.PkinitCrypto;
 import org.apache.kerby.kerberos.kerb.preauth.pkinit.PkinitPreauthMeta;
 import org.apache.kerby.kerberos.kerb.server.KdcContext;
 import org.apache.kerby.kerberos.kerb.server.preauth.AbstractPreauthPlugin;
 import org.apache.kerby.kerberos.kerb.server.request.KdcRequest;
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.base.CheckSum;
+import org.apache.kerby.kerberos.kerb.spec.base.CheckSumType;
 import org.apache.kerby.kerberos.kerb.spec.base.PrincipalName;
+import org.apache.kerby.kerberos.kerb.spec.cms.DHParameter;
+import org.apache.kerby.kerberos.kerb.spec.cms.SubjectPublicKeyInfo;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcOption;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaDataEntry;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaDataType;
+import org.apache.kerby.kerberos.kerb.spec.pa.pkinit.AuthPack;
+import org.apache.kerby.kerberos.kerb.spec.pa.pkinit.DHRepInfo;
+import org.apache.kerby.kerberos.kerb.spec.pa.pkinit.KdcDHKeyInfo;
+import org.apache.kerby.kerberos.kerb.spec.pa.pkinit.PaPkAsRep;
 import org.apache.kerby.kerberos.kerb.spec.pa.pkinit.PaPkAsReq;
+import org.apache.kerby.kerberos.kerb.spec.pa.pkinit.PkAuthenticator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import sun.security.pkcs.ContentInfo;
+import sun.security.pkcs.PKCS7;
+import sun.security.pkcs.SignerInfo;
+import sun.security.util.DerValue;
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.AlgorithmId;
 
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPublicKeySpec;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Scanner;
 
 public class PkinitPreauth extends AbstractPreauthPlugin {
 
+    private static final Logger LOG = LoggerFactory.getLogger(PkinitPreauth.class);
     private final Map<String, PkinitKdcContext> pkinitContexts;
+    private static final String ID_PKINIT_DHKEYDATA = "1.3.6.1.5.2.3.2";
 
     public PkinitPreauth() {
         super(new PkinitPreauthMeta());
@@ -50,6 +94,10 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
 
         PkinitKdcContext tmp = new PkinitKdcContext();
         tmp.realm = kdcContext.getKdcRealm();
+
+        String pkinitIdentity = kdcContext.getConfig().getPkinitIdentity();
+        tmp.identityOpts.identity = pkinitIdentity;
+
         pkinitContexts.put(kdcContext.getKdcRealm(), tmp);
     }
 
@@ -66,18 +114,129 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
     public boolean verify(KdcRequest kdcRequest, PluginRequestContext requestContext,
                           PaDataEntry paData) throws KrbException {
 
+        LOG.info("pkinit verify padata: entered!");
+
         PkinitRequestContext reqCtx = (PkinitRequestContext) requestContext;
-        PkinitKdcContext pkinitContext = findContext(kdcRequest.getServerPrincipal());
+        PrincipalName serverPrincipal = kdcRequest.getServerEntry().getPrincipal();
+        kdcRequest.setServerPrincipal(serverPrincipal);
+        PkinitKdcContext pkinitContext = findContext(serverPrincipal);
         if (pkinitContext == null) {
             return false;
         }
 
         reqCtx.paType = paData.getPaDataType();
         if (paData.getPaDataType() == PaDataType.PK_AS_REQ) {
+
+            LOG.info("processing PK_AS_REQ");
             PaPkAsReq paPkAsReq = KrbCodec.decode(paData.getPaDataValue(), PaPkAsReq.class);
-            if (paPkAsReq == null) {
-                return false;
+
+            byte[] signedAuthPack = paPkAsReq.getSignedAuthPack();
+            PKCS7 pkcs7 = null;
+            try {
+                pkcs7 = PkinitCrypto.verifyCMSSignedData(pkinitContext.cryptoctx,
+                        CMSMessageType.CMS_SIGN_CLIENT, signedAuthPack);
+            } catch (IOException e) {
+                e.getMessage();
+            }
+
+            Boolean isSigned = PkinitCrypto.isSigned(pkcs7);
+            if (isSigned) {
+                //TODO
+                LOG.info("Signed data.");
+            } else {
+                PrincipalName clientPrincial = kdcRequest.getClientEntry().getPrincipal();
+                PrincipalName anonymousPrincipal = KrbUtil.makeAnonymousPrincipal();
+
+                /* If anonymous requests are being used, adjust the realm of the client principal.
*/
+                if (kdcRequest.getKdcOptions().isFlagSet(KdcOption.REQUEST_ANONYMOUS)
+                        && !KrbUtil.pricipalCompareIgnoreRealm(clientPrincial, anonymousPrincipal))
{
+                    String errMsg = "Pkinit request not signed, but client not anonymous.";
+                    LOG.error(errMsg);
+                    throw new KrbException(KrbErrorCode.KDC_ERR_PREAUTH_FAILED, errMsg);
+                }
             }
+
+            ContentInfo contentInfo = pkcs7.getContentInfo();
+            AuthPack authPack = null;
+            try {
+                authPack = KrbCodec.decode(contentInfo.getContentBytes(), AuthPack.class);
+            } catch (IOException e) {
+                LOG.error("failed to decode AuthPack " + e.getMessage());
+            }
+
+            PkAuthenticator pkAuthenticator = authPack.getPkAuthenticator();
+
+            checkClockskew(kdcRequest, pkAuthenticator.getCtime());
+            DHParameter dhParameter = null;
+            if (authPack.getClientPublicValue() != null) {
+                dhParameter = authPack.getClientPublicValue().getAlgorithm().getParameters();
+                PkinitCrypto.serverCheckDH(pkinitContext.pluginOpts, pkinitContext.cryptoctx,
dhParameter);
+            } else if (!isSigned) {
+                /*Anonymous pkinit requires DH*/
+                String errMessage = "Anonymous pkinit without DH public value not supported.";
+                LOG.error(errMessage);
+                throw new KrbException(KrbErrorCode.KDC_ERR_PREAUTH_FAILED, errMessage);
+            }
+
+            CheckSum expectedCheckSum = null;
+            try {
+                expectedCheckSum = CheckSumUtil.makeCheckSum(CheckSumType.NIST_SHA,
+                        kdcRequest.getKdcReq().getReqBody().encode());
+            } catch (KrbException e) {
+                LOG.error("Unable to calculate AS REQ checksum.", e.getMessage());
+            }
+
+            CheckSum receivedCheckSum = KrbCodec.decode(pkAuthenticator.getPaChecksum(),
CheckSum.class);
+
+            if (expectedCheckSum.encodingLength() != receivedCheckSum.encodingLength()
+                    || !Arrays.equals(expectedCheckSum.getChecksum(), receivedCheckSum.getChecksum()))
{
+                LOG.debug("Received checksum type: " + receivedCheckSum.getCksumtype()
+                        + ", received checksum length: " + receivedCheckSum.encodingLength()
+                        + ", expected checksum type: " + expectedCheckSum.getCksumtype()
+                        + ", expected checksum length: " + expectedCheckSum.encodingLength());
+                String errorMessage = "Failed to match the checksum.";
+                LOG.error(errorMessage);
+                throw new KrbException(KrbErrorCode.KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED,
errorMessage);
+            }
+
+            BigInteger p = dhParameter.getP();
+            BigInteger g = dhParameter.getG();
+
+            SubjectPublicKeyInfo publicKeyInfo = authPack.getClientPublicValue();
+            byte[] clientSubjectPubKey = publicKeyInfo.getSubjectPubKey().getValue();
+            Asn1Integer clientPubKey = KrbCodec.decode(clientSubjectPubKey, Asn1Integer.class);
+            BigInteger y = clientPubKey.getValue();
+
+            DHPublicKeySpec dhPublicKeySpec = new DHPublicKeySpec(y, p, g);
+
+            KeyFactory keyFactory = null;
+            try {
+                keyFactory = KeyFactory.getInstance("DH");
+            } catch (NoSuchAlgorithmException e) {
+                e.printStackTrace();
+            }
+            DHPublicKey dhPublicKey = null;
+            try {
+                dhPublicKey = (DHPublicKey) keyFactory.generatePublic(dhPublicKeySpec);
+            } catch (InvalidKeySpecException e) {
+                e.printStackTrace();
+            }
+
+            DhServer server = new DhServer();
+            DHPublicKey serverPubKey = null;
+            try {
+                serverPubKey = (DHPublicKey) server.initAndDoPhase(dhPublicKey.getEncoded());
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            server.generateKey(null, null);
+
+            String identity = pkinitContext.identityOpts.identity;
+
+            PaPkAsRep paPkAsRep = makePaPkAsRep(serverPubKey, identity);
+            PaDataEntry paDataEntry = makeEntry(paPkAsRep);
+
+            kdcRequest.getPreauthContext().getOutputPaData().add(paDataEntry);
         }
 
         return true;
@@ -90,4 +249,109 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
         }
         return null;
     }
+
+    /**
+     * Make padata entry.
+     *
+     * @param paPkAsRep The PaPkAsRep
+     * @return PaDataEntry to be made.
+     */
+    private PaDataEntry makeEntry(PaPkAsRep paPkAsRep) throws KrbException {
+
+        PaDataEntry paDataEntry = new PaDataEntry();
+        paDataEntry.setPaDataType(PaDataType.PK_AS_REP);
+        paDataEntry.setPaDataValue(paPkAsRep.encode());
+        return paDataEntry;
+    }
+
+    private PaPkAsRep makePaPkAsRep(DHPublicKey severPubKey, String identityString) {
+
+        List<String> identityList = Arrays.asList(identityString.split(","));
+
+        List<X509Certificate> certificates = new ArrayList<>();
+        for (String identity : identityList) {
+            File file = new File(identity);
+
+            try {
+                Scanner scanner = new Scanner(file);
+                String found = scanner.findInLine("CERTIFICATE");
+
+                if (found != null) {
+                    InputStream res = null;
+                    try {
+                        res = new FileInputStream(identity);
+                    } catch (FileNotFoundException e) {
+                        e.printStackTrace();
+                    }
+                    X509Certificate certificate = null;
+                    try {
+                        certificate = (X509Certificate) CertificateHelper.loadCerts(res).iterator().next();
+                    } catch (KrbException e) {
+                        e.printStackTrace();
+                    }
+                    certificates.add(certificate);
+                }
+            } catch (FileNotFoundException e) {
+                e.getMessage();
+            }
+        }
+
+        PaPkAsRep paPkAsRep = new PaPkAsRep();
+
+        DHRepInfo dhRepInfo = new DHRepInfo();
+
+        KdcDHKeyInfo kdcDhKeyInfo = new KdcDHKeyInfo();
+
+        Asn1Integer publickey = new Asn1Integer(severPubKey.getY());
+        kdcDhKeyInfo.setSubjectPublicKey(publickey.encode());
+        kdcDhKeyInfo.setNonce(1);
+        kdcDhKeyInfo.setDHKeyExpiration(
+                new KerberosTime(System.currentTimeMillis() + KerberosTime.DAY));
+
+        ByteArrayOutputStream signedData = null;
+        try {
+            signedData = cmsSignedDataCreate(kdcDhKeyInfo, certificates);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        dhRepInfo.setDHSignedData(signedData.toByteArray());
+
+        paPkAsRep.setDHRepInfo(dhRepInfo);
+//        paPkAsRep.setEncKeyPack("enckey".getBytes());
+
+        return paPkAsRep;
+    }
+
+
+    public static ContentInfo createContentInfo(byte[] data, ObjectIdentifier oid) {
+
+        ContentInfo contentInfo = new ContentInfo(
+                oid,
+                new DerValue(DerValue.tag_OctetString, data));
+        return contentInfo;
+    }
+
+    public static ByteArrayOutputStream cmsSignedDataCreate(KdcDHKeyInfo kdcDHKeyInfo,
+                                                            List<X509Certificate> certificates)
throws IOException {
+
+        ObjectIdentifier oid = new ObjectIdentifier(ID_PKINIT_DHKEYDATA);
+        ContentInfo contentInfo = createContentInfo(kdcDHKeyInfo.encode(), oid);
+
+        PKCS7 p7 = new PKCS7(new AlgorithmId[0], contentInfo,
+                certificates.toArray(new X509Certificate[certificates.size()]), new SignerInfo[0]);
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        p7.encodeSignedData(bytes);
+        return bytes;
+    }
+
+    public boolean checkClockskew(KdcRequest kdcRequest, KerberosTime time) throws KrbException
{
+        long clockSkew = kdcRequest.getKdcContext().getConfig().getAllowableClockSkew() *
1000;
+
+        if (!time.isInClockSkew(clockSkew)) {
+            throw new KrbException(KrbErrorCode.KDC_ERR_PREAUTH_FAILED);
+        } else {
+            return true;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
index 2765673..6ccd774 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
@@ -129,6 +129,10 @@ public class AsRequest extends KdcRequest {
             clientKey, KeyUsage.AS_REP_ENCPART);
         reply.setEncryptedEncPart(encryptedData);
 
+        if (isPkinit()) {
+            reply.setPaData(getPreauthContext().getOutputPaData());
+        }
+
         setReply(reply);
     }
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
index 521ab51..2a014b1 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
@@ -54,6 +54,8 @@ import org.apache.kerby.kerberos.kerb.spec.fast.ArmorType;
 import org.apache.kerby.kerberos.kerb.spec.fast.KrbFastArmor;
 import org.apache.kerby.kerberos.kerb.spec.fast.KrbFastArmoredReq;
 import org.apache.kerby.kerberos.kerb.spec.fast.KrbFastReq;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcOption;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcOptions;
 import org.apache.kerby.kerberos.kerb.spec.kdc.KdcRep;
 import org.apache.kerby.kerberos.kerb.spec.kdc.KdcReq;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaData;
@@ -92,6 +94,7 @@ public abstract class KdcRequest {
     private byte[] innerBodyout;
     private AuthToken token;
     private Boolean isToken = false;
+    private Boolean isPkinit = false;
     private EncryptionKey sessionKey;
 
     /**
@@ -167,6 +170,9 @@ public abstract class KdcRequest {
             checkClient();
             checkServer();
         } else {
+            if (PreauthHandler.isPkinit(getKdcReq().getPaData())) {
+                isPkinit = true;
+            }
             checkClient();
             checkServer();
             preauth();
@@ -537,10 +543,17 @@ public abstract class KdcRequest {
         PaData preAuthData = request.getPaData();
 
         if (isPreauthRequired()) {
+            if (getKdcOptions().isFlagSet(KdcOption.REQUEST_ANONYMOUS) && !isPkinit)
{
+                LOG.info("Need PKINIT.");
+                KrbError krbError = makePreAuthenticationError(kdcContext, request,
+                        KrbErrorCode.KDC_ERR_PREAUTH_REQUIRED, true);
+                throw new KdcRecoverableException(krbError);
+            }
+
             if (preAuthData == null || preAuthData.isEmpty()) {
                 LOG.info("The preauth data is empty.");
                 KrbError krbError = makePreAuthenticationError(kdcContext, request,
-                        KrbErrorCode.KDC_ERR_PREAUTH_REQUIRED);
+                        KrbErrorCode.KDC_ERR_PREAUTH_REQUIRED, false);
                 throw new KdcRecoverableException(krbError);
             } else {
                 getPreauthHandler().verify(this, preAuthData);
@@ -646,7 +659,7 @@ public abstract class KdcRequest {
      * @return The krb error reply to client
      */
     protected KrbError makePreAuthenticationError(KdcContext kdcContext, KdcReq request,
-                                                  KrbErrorCode errorCode)
+                                                  KrbErrorCode errorCode, boolean pkinit)
             throws KrbException {
         List<EncryptionType> encryptionTypes = kdcContext.getConfig().getEncryptionTypes();
         List<EncryptionType> clientEtypes = request.getReqBody().getEtypes();
@@ -685,6 +698,11 @@ public abstract class KdcRequest {
         }
         methodData.add(new PaDataEntry(PaDataType.ETYPE_INFO2, encTypeInfo2));
 
+        if(pkinit) {
+            methodData.add(new PaDataEntry(PaDataType.PK_AS_REQ, "empty".getBytes()));
+            methodData.add(new PaDataEntry(PaDataType.PK_AS_REP, "empty".getBytes()));
+        }
+
         KrbError krbError = new KrbError();
         krbError.setErrorCode(errorCode);
         byte[] encodedData = KrbCodec.encode(methodData);
@@ -782,4 +800,12 @@ public abstract class KdcRequest {
     protected AuthToken getToken() {
         return token;
     }
+
+    protected boolean isPkinit() {
+        return isPkinit;
+    }
+
+    public KdcOptions getKdcOptions() {
+        return kdcReq.getReqBody().getKdcOptions();
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/14696718/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitTool.java
----------------------------------------------------------------------
diff --git a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitTool.java
b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitTool.java
index a89e4f5..5ea108a 100644
--- a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitTool.java
+++ b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitTool.java
@@ -116,6 +116,7 @@ public class KinitTool {
 
         if (ktOptions.contains(KinitOption.ANONYMOUS)) {
             ktOptions.add(KrbOption.USE_PKINIT_ANONYMOUS);
+            ktOptions.add(KrbOption.PKINIT_X509_ANCHORS);
         } else if (!ktOptions.contains(KinitOption.USE_KEYTAB)) {
             //If not request tickets by keytab than by password.
             ktOptions.add(KinitOption.USE_PASSWD);


Mime
View raw message