提交 25280618 编写于 作者: W weijun

7067974: multiple ETYPE-INFO-ENTRY with same etype and different salt

Reviewed-by: valeriep
上级 28916744
...@@ -150,12 +150,37 @@ public class EncryptionKey ...@@ -150,12 +150,37 @@ public class EncryptionKey
return ktab.readServiceKeys(princ); return ktab.readServiceKeys(princ);
} }
/**
* Obtains a key for a given etype of a principal with possible new salt
* and s2kparams
* @param cname NOT null
* @param password NOT null
* @param etype
* @param snp can be NULL
* @returns never null
*/
public static EncryptionKey acquireSecretKey(PrincipalName cname,
char[] password, int etype, PAData.SaltAndParams snp)
throws KrbException {
String salt;
byte[] s2kparams;
if (snp != null) {
salt = snp.salt != null ? snp.salt : cname.getSalt();
s2kparams = snp.params;
} else {
salt = cname.getSalt();
s2kparams = null;
}
return acquireSecretKey(password, salt, etype, s2kparams);
}
/** /**
* Obtains a key for a given etype with salt and optional s2kparams * Obtains a key for a given etype with salt and optional s2kparams
* @param password NOT null * @param password NOT null
* @param salt NOT null * @param salt NOT null
* @param etype * @param etype
* @param s2kparams can be NULL * @param s2kparams can be NULL
* @returns never null
*/ */
public static EncryptionKey acquireSecretKey(char[] password, public static EncryptionKey acquireSecretKey(char[] password,
String salt, int etype, byte[] s2kparams) String salt, int etype, byte[] s2kparams)
......
...@@ -131,13 +131,11 @@ class KrbAsRep extends KrbKdcRep { ...@@ -131,13 +131,11 @@ class KrbAsRep extends KrbKdcRep {
KrbAsReq asReq, PrincipalName cname) KrbAsReq asReq, PrincipalName cname)
throws KrbException, Asn1Exception, IOException { throws KrbException, Asn1Exception, IOException {
int encPartKeyType = rep.encPart.getEType(); int encPartKeyType = rep.encPart.getEType();
PAData.SaltAndParams snp = EncryptionKey dkey = EncryptionKey.acquireSecretKey(
PAData.getSaltAndParams(encPartKeyType, rep.pAData); cname,
EncryptionKey dkey = null; password,
dkey = EncryptionKey.acquireSecretKey(password,
snp.salt == null ? cname.getSalt() : snp.salt,
encPartKeyType, encPartKeyType,
snp.params); PAData.getSaltAndParams(encPartKeyType, rep.pAData));
decrypt(dkey, asReq); decrypt(dkey, asReq);
} }
......
...@@ -169,35 +169,45 @@ public final class KrbAsReqBuilder { ...@@ -169,35 +169,45 @@ public final class KrbAsReqBuilder {
* from a keytab on acceptor, but unfortunately (?) Java supports * from a keytab on acceptor, but unfortunately (?) Java supports
* acceptor using password. In this case, if the service ticket is * acceptor using password. In this case, if the service ticket is
* encrypted using an etype which we don't have PA-DATA new salt, * encrypted using an etype which we don't have PA-DATA new salt,
* using the default salt is normally wrong (say, case-insensitive * using the default salt might be wrong (say, case-insensitive
* user name). Instead, we would use the new salt of another etype. * user name). Instead, we would use the new salt of another etype.
*/ */
String salt = null; // the saved new salt String salt = null; // the saved new salt
try {
for (int i=0; i<eTypes.length; i++) { for (int i=0; i<eTypes.length; i++) {
// First round, only calculate those have a PA entry
PAData.SaltAndParams snp = PAData.SaltAndParams snp =
PAData.getSaltAndParams(eTypes[i], paList); PAData.getSaltAndParams(eTypes[i], paList);
// First round, only calculate those with new salt if (snp != null) {
if (snp.salt != null) { // Never uses a salt for rc4-hmac, it does not use
// a salt at all
if (eTypes[i] != EncryptedData.ETYPE_ARCFOUR_HMAC &&
snp.salt != null) {
salt = snp.salt; salt = snp.salt;
result[i] = EncryptionKey.acquireSecretKey(password, }
snp.salt, result[i] = EncryptionKey.acquireSecretKey(cname,
password,
eTypes[i], eTypes[i],
snp.params); snp);
} }
} }
// No new salt from PA, maybe empty, maybe only rc4-hmac
if (salt == null) salt = cname.getSalt(); if (salt == null) salt = cname.getSalt();
for (int i=0; i<eTypes.length; i++) { for (int i=0; i<eTypes.length; i++) {
// Second round, calculate those with no new salt // Second round, calculate those with no PA entry
if (result[i] == null) { if (result[i] == null) {
PAData.SaltAndParams snp =
PAData.getSaltAndParams(eTypes[i], paList);
result[i] = EncryptionKey.acquireSecretKey(password, result[i] = EncryptionKey.acquireSecretKey(password,
salt, salt,
eTypes[i], eTypes[i],
snp.params); null);
} }
} }
} catch (IOException ioe) {
KrbException ke = new KrbException(Krb5.ASN1_PARSE_ERROR);
ke.initCause(ioe);
throw ke;
}
return result; return result;
} else { } else {
throw new IllegalStateException("Required password not provided"); throw new IllegalStateException("Required password not provided");
...@@ -315,27 +325,19 @@ public final class KrbAsReqBuilder { ...@@ -315,27 +325,19 @@ public final class KrbAsReqBuilder {
} }
preAuthFailedOnce = true; preAuthFailedOnce = true;
KRBError kerr = ke.getError(); KRBError kerr = ke.getError();
int paEType = PAData.getPreferredEType(kerr.getPA(),
EType.getDefaults("default_tkt_enctypes")[0]);
if (password == null) { if (password == null) {
EncryptionKey[] ks = Krb5Util.keysFromJavaxKeyTab(ktab, cname); EncryptionKey[] ks = Krb5Util.keysFromJavaxKeyTab(ktab, cname);
pakey = EncryptionKey.findKey(kerr.getEType(), ks); pakey = EncryptionKey.findKey(paEType, ks);
if (pakey != null) pakey = (EncryptionKey)pakey.clone(); if (pakey != null) pakey = (EncryptionKey)pakey.clone();
for (EncryptionKey k: ks) k.destroy(); for (EncryptionKey k: ks) k.destroy();
} else { } else {
PAData.SaltAndParams snp = PAData.getSaltAndParams( pakey = EncryptionKey.acquireSecretKey(cname,
kerr.getEType(), kerr.getPA()); password,
if (kerr.getEType() == 0) { paEType,
// Possible if PA-PW-SALT is in KRB-ERROR. RFC PAData.getSaltAndParams(
// does not recommend this paEType, kerr.getPA()));
pakey = EncryptionKey.acquireSecretKey(password,
snp.salt == null ? cname.getSalt() : snp.salt,
EType.getDefaults("default_tkt_enctypes")[0],
null);
} else {
pakey = EncryptionKey.acquireSecretKey(password,
snp.salt == null ? cname.getSalt() : snp.salt,
kerr.getEType(),
snp.params);
}
} }
paList = kerr.getPA(); // Update current paList paList = kerr.getPA(); // Update current paList
} else { } else {
......
...@@ -99,7 +99,6 @@ public class KRBError implements java.io.Serializable { ...@@ -99,7 +99,6 @@ public class KRBError implements java.io.Serializable {
private Checksum eCksum; //optional private Checksum eCksum; //optional
private PAData[] pa; // PA-DATA in eData private PAData[] pa; // PA-DATA in eData
private int pa_eType; // The 1st etype appeared in salt-related PAData
private static boolean DEBUG = Krb5.DEBUG; private static boolean DEBUG = Krb5.DEBUG;
...@@ -266,50 +265,8 @@ public class KRBError implements java.io.Serializable { ...@@ -266,50 +265,8 @@ public class KRBError implements java.io.Serializable {
DerValue tmp = derPA.data.getDerValue(); DerValue tmp = derPA.data.getDerValue();
PAData pa_data = new PAData(tmp); PAData pa_data = new PAData(tmp);
paList.add(pa_data); paList.add(pa_data);
int pa_type = pa_data.getType();
byte[] pa_value = pa_data.getValue();
if (DEBUG) { if (DEBUG) {
System.out.println(">>>Pre-Authentication Data:"); System.out.println(pa_data);
System.out.println("\t PA-DATA type = " + pa_type);
}
switch(pa_type) {
case Krb5.PA_ENC_TIMESTAMP:
if (DEBUG) {
System.out.println("\t PA-ENC-TIMESTAMP");
}
break;
case Krb5.PA_ETYPE_INFO:
if (pa_value != null) {
DerValue der = new DerValue(pa_value);
while (der.data.available() > 0) {
DerValue value = der.data.getDerValue();
ETypeInfo info = new ETypeInfo(value);
if (pa_eType == 0) pa_eType = info.getEType();
if (DEBUG) {
System.out.println("\t PA-ETYPE-INFO etype = " + info.getEType());
System.out.println("\t PA-ETYPE-INFO salt = " + info.getSalt());
}
}
}
break;
case Krb5.PA_ETYPE_INFO2:
if (pa_value != null) {
DerValue der = new DerValue(pa_value);
while (der.data.available() > 0) {
DerValue value = der.data.getDerValue();
ETypeInfo2 info2 = new ETypeInfo2(value);
if (pa_eType == 0) pa_eType = info2.getEType();
if (DEBUG) {
System.out.println("\t PA-ETYPE-INFO2 etype = " + info2.getEType());
System.out.println("\t PA-ETYPE-INFO2 salt = " + info2.getSalt());
}
}
}
break;
default:
// Unknown Pre-auth type
break;
} }
} }
pa = paList.toArray(new PAData[paList.size()]); pa = paList.toArray(new PAData[paList.size()]);
...@@ -340,10 +297,6 @@ public class KRBError implements java.io.Serializable { ...@@ -340,10 +297,6 @@ public class KRBError implements java.io.Serializable {
return pa; return pa;
} }
public final int getEType() {
return pa_eType;
}
public final String getErrorString() { public final String getErrorString() {
return eText; return eText;
} }
......
...@@ -138,10 +138,57 @@ public class PAData { ...@@ -138,10 +138,57 @@ public class PAData {
return ((pADataValue == null) ? null : pADataValue.clone()); return ((pADataValue == null) ? null : pADataValue.clone());
} }
/**
* Gets the preferred etype from the PAData array.
* 1. ETYPE-INFO2-ENTRY with unknown s2kparams ignored
* 2. ETYPE-INFO2 preferred to ETYPE-INFO
* 3. multiple entries for same etype in one PA-DATA, use the first one.
* 4. Multiple PA-DATA with same type, choose the last one
* (This is useful when PA-DATAs from KRB-ERROR and AS-REP are combined).
* @return the etype, or defaultEType if not enough info
* @throws Asn1Exception|IOException if there is an encoding error
*/
public static int getPreferredEType(PAData[] pas, int defaultEType)
throws IOException, Asn1Exception {
if (pas == null) return defaultEType;
DerValue d = null, d2 = null;
for (PAData p: pas) {
if (p.getValue() == null) continue;
switch (p.getType()) {
case Krb5.PA_ETYPE_INFO:
d = new DerValue(p.getValue());
break;
case Krb5.PA_ETYPE_INFO2:
d2 = new DerValue(p.getValue());
break;
}
}
if (d2 != null) {
while (d2.data.available() > 0) {
DerValue value = d2.data.getDerValue();
ETypeInfo2 tmp = new ETypeInfo2(value);
if (tmp.getParams() == null) {
// we don't support non-null s2kparams
return tmp.getEType();
}
}
}
if (d != null) {
while (d.data.available() > 0) {
DerValue value = d.data.getDerValue();
ETypeInfo tmp = new ETypeInfo(value);
return tmp.getEType();
}
}
return defaultEType;
}
/** /**
* A place to store a pair of salt and s2kparams. * A place to store a pair of salt and s2kparams.
* An empty salt is changed to null, to be interopable * An empty salt is changed to null, to be interoperable
* with Windows 2000 server. * with Windows 2000 server. This is in fact not correct.
*/ */
public static class SaltAndParams { public static class SaltAndParams {
public final String salt; public final String salt;
...@@ -155,57 +202,120 @@ public class PAData { ...@@ -155,57 +202,120 @@ public class PAData {
/** /**
* Fetches salt and s2kparams value for eType in a series of PA-DATAs. * Fetches salt and s2kparams value for eType in a series of PA-DATAs.
* The preference order is PA-ETYPE-INFO2 > PA-ETYPE-INFO > PA-PW-SALT. * 1. ETYPE-INFO2-ENTRY with unknown s2kparams ignored
* If multiple PA-DATA for the same etype appears, use the last one. * 2. PA-ETYPE-INFO2 preferred to PA-ETYPE-INFO preferred to PA-PW-SALT.
* 3. multiple entries for same etype in one PA-DATA, use the first one.
* 4. Multiple PA-DATA with same type, choose the last one
* (This is useful when PA-DATAs from KRB-ERROR and AS-REP are combined). * (This is useful when PA-DATAs from KRB-ERROR and AS-REP are combined).
* @return salt and s2kparams. never null, its field might be null. * @return salt and s2kparams. can be null if not found
*/ */
public static SaltAndParams getSaltAndParams(int eType, PAData[] pas) public static SaltAndParams getSaltAndParams(int eType, PAData[] pas)
throws Asn1Exception, KrbException { throws Asn1Exception, IOException {
if (pas == null || pas.length == 0) { if (pas == null) return null;
return new SaltAndParams(null, null);
}
DerValue d = null, d2 = null;
String paPwSalt = null; String paPwSalt = null;
ETypeInfo2 info2 = null;
ETypeInfo info = null;
for (PAData p: pas) { for (PAData p: pas) {
if (p.getValue() != null) { if (p.getValue() == null) continue;
try {
switch (p.getType()) { switch (p.getType()) {
case Krb5.PA_PW_SALT: case Krb5.PA_PW_SALT:
paPwSalt = new String(p.getValue(), paPwSalt = new String(p.getValue(),
KerberosString.MSNAME?"UTF8":"8859_1"); KerberosString.MSNAME?"UTF8":"8859_1");
break; break;
case Krb5.PA_ETYPE_INFO: case Krb5.PA_ETYPE_INFO:
DerValue der = new DerValue(p.getValue()); d = new DerValue(p.getValue());
while (der.data.available() > 0) { break;
DerValue value = der.data.getDerValue(); case Krb5.PA_ETYPE_INFO2:
d2 = new DerValue(p.getValue());
break;
}
}
if (d2 != null) {
while (d2.data.available() > 0) {
DerValue value = d2.data.getDerValue();
ETypeInfo2 tmp = new ETypeInfo2(value);
if (tmp.getParams() == null && tmp.getEType() == eType) {
// we don't support non-null s2kparams
return new SaltAndParams(tmp.getSalt(), tmp.getParams());
}
}
}
if (d != null) {
while (d.data.available() > 0) {
DerValue value = d.data.getDerValue();
ETypeInfo tmp = new ETypeInfo(value); ETypeInfo tmp = new ETypeInfo(value);
if (tmp.getEType() == eType) info = tmp; if (tmp.getEType() == eType) {
return new SaltAndParams(tmp.getSalt(), null);
}
} }
}
if (paPwSalt != null) {
return new SaltAndParams(paPwSalt, null);
}
return null;
}
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append(">>>Pre-Authentication Data:\n\t PA-DATA type = ")
.append(pADataType).append('\n');
switch(pADataType) {
case Krb5.PA_ENC_TIMESTAMP:
sb.append("\t PA-ENC-TIMESTAMP");
break; break;
case Krb5.PA_ETYPE_INFO2: case Krb5.PA_ETYPE_INFO:
der = new DerValue(p.getValue()); if (pADataValue != null) {
try {
DerValue der = new DerValue(pADataValue);
while (der.data.available() > 0) { while (der.data.available() > 0) {
DerValue value = der.data.getDerValue(); DerValue value = der.data.getDerValue();
ETypeInfo2 tmp = new ETypeInfo2(value); ETypeInfo info = new ETypeInfo(value);
if (tmp.getEType() == eType) info2 = tmp; sb.append("\t PA-ETYPE-INFO etype = ")
.append(info.getEType())
.append(", salt = ")
.append(info.getSalt())
.append('\n');
}
} catch (IOException|Asn1Exception e) {
sb.append("\t <Unparseable PA-ETYPE-INFO>\n");
}
} }
break; break;
case Krb5.PA_ETYPE_INFO2:
if (pADataValue != null) {
try {
DerValue der = new DerValue(pADataValue);
while (der.data.available() > 0) {
DerValue value = der.data.getDerValue();
ETypeInfo2 info2 = new ETypeInfo2(value);
sb.append("\t PA-ETYPE-INFO2 etype = ")
.append(info2.getEType())
.append(", salt = ")
.append(info2.getSalt())
.append(", s2kparams = ");
byte[] s2kparams = info2.getParams();
if (s2kparams == null) {
sb.append("null\n");
} else if (s2kparams.length == 0) {
sb.append("empty\n");
} else {
sb.append(new sun.misc.HexDumpEncoder()
.encodeBuffer(s2kparams));
} }
} catch (IOException ioe) {
// Ignored
} }
} catch (IOException|Asn1Exception e) {
sb.append("\t <Unparseable PA-ETYPE-INFO>\n");
} }
} }
if (info2 != null) { break;
return new SaltAndParams(info2.getSalt(), info2.getParams()); default:
} else if (info != null) { // Unknown Pre-auth type
return new SaltAndParams(info.getSalt(), null); break;
} }
return new SaltAndParams(paPwSalt, null); return sb.toString();
} }
} }
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7067974
* @summary multiple ETYPE-INFO-ENTRY with same etype and different salt
* @compile -XDignore.symbol.file DupEtypes.java
* @run main/othervm DupEtypes 1
* @run main/othervm DupEtypes 2
* @run main/othervm/fail DupEtypes 3
* @run main/othervm DupEtypes 4
* @run main/othervm DupEtypes 5
*/
import sun.security.jgss.GSSUtil;
public class DupEtypes {
public static void main(String[] args) throws Exception {
OneKDC kdc = new OneKDC(null);
kdc.writeJAASConf();
// Different test cases, read KDC.processAsReq for details
kdc.setOption(KDC.Option.DUP_ETYPE, Integer.parseInt(args[0]));
Context c, s;
c = Context.fromJAAS("client");
s = Context.fromJAAS("server");
c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
Context.handshake(c, s);
Context.transmit("i say high --", c, s);
Context.transmit(" you say low", s, c);
s.dispose();
c.dispose();
}
}
...@@ -174,6 +174,10 @@ public class KDC { ...@@ -174,6 +174,10 @@ public class KDC {
* Set all name-type to a value in response * Set all name-type to a value in response
*/ */
RESP_NT, RESP_NT,
/**
* Multiple ETYPE-INFO-ENTRY with same etype but different salt
*/
DUP_ETYPE,
}; };
static { static {
...@@ -881,6 +885,57 @@ public class KDC { ...@@ -881,6 +885,57 @@ public class KDC {
bFlags[Krb5.TKT_OPTS_INITIAL] = true; bFlags[Krb5.TKT_OPTS_INITIAL] = true;
// Creating PA-DATA // Creating PA-DATA
DerValue[] pas2 = null, pas = null;
if (options.containsKey(KDC.Option.DUP_ETYPE)) {
int n = (Integer)options.get(KDC.Option.DUP_ETYPE);
switch (n) {
case 1: // customer's case in 7067974
pas2 = new DerValue[] {
new DerValue(new ETypeInfo2(1, null, null).asn1Encode()),
new DerValue(new ETypeInfo2(1, "", null).asn1Encode()),
new DerValue(new ETypeInfo2(1, OneKDC.REALM, new byte[]{1}).asn1Encode()),
};
pas = new DerValue[] {
new DerValue(new ETypeInfo(1, null).asn1Encode()),
new DerValue(new ETypeInfo(1, "").asn1Encode()),
new DerValue(new ETypeInfo(1, OneKDC.REALM).asn1Encode()),
};
break;
case 2: // we still reject non-null s2kparams and prefer E2 over E
pas2 = new DerValue[] {
new DerValue(new ETypeInfo2(1, OneKDC.REALM, new byte[]{1}).asn1Encode()),
new DerValue(new ETypeInfo2(1, null, null).asn1Encode()),
new DerValue(new ETypeInfo2(1, "", null).asn1Encode()),
};
pas = new DerValue[] {
new DerValue(new ETypeInfo(1, OneKDC.REALM).asn1Encode()),
new DerValue(new ETypeInfo(1, null).asn1Encode()),
new DerValue(new ETypeInfo(1, "").asn1Encode()),
};
break;
case 3: // but only E is wrong
pas = new DerValue[] {
new DerValue(new ETypeInfo(1, OneKDC.REALM).asn1Encode()),
new DerValue(new ETypeInfo(1, null).asn1Encode()),
new DerValue(new ETypeInfo(1, "").asn1Encode()),
};
break;
case 4: // we also ignore rc4-hmac
pas = new DerValue[] {
new DerValue(new ETypeInfo(23, "ANYTHING").asn1Encode()),
new DerValue(new ETypeInfo(1, null).asn1Encode()),
new DerValue(new ETypeInfo(1, "").asn1Encode()),
};
break;
case 5: // "" should be wrong, but we accept it now
// See s.s.k.internal.PAData$SaltAndParams
pas = new DerValue[] {
new DerValue(new ETypeInfo(1, "").asn1Encode()),
new DerValue(new ETypeInfo(1, null).asn1Encode()),
};
break;
}
} else {
int[] epas = eTypes; int[] epas = eTypes;
if (options.containsKey(KDC.Option.RC4_FIRST_PREAUTH)) { if (options.containsKey(KDC.Option.RC4_FIRST_PREAUTH)) {
for (int i=1; i<epas.length; i++) { for (int i=1; i<epas.length; i++) {
...@@ -893,20 +948,14 @@ public class KDC { ...@@ -893,20 +948,14 @@ public class KDC {
} else if (options.containsKey(KDC.Option.ONLY_ONE_PREAUTH)) { } else if (options.containsKey(KDC.Option.ONLY_ONE_PREAUTH)) {
epas = new int[] { eTypes[0] }; epas = new int[] { eTypes[0] };
} }
pas2 = new DerValue[epas.length];
DerValue[] pas = new DerValue[epas.length];
for (int i=0; i<epas.length; i++) { for (int i=0; i<epas.length; i++) {
pas[i] = new DerValue(new ETypeInfo2( pas2[i] = new DerValue(new ETypeInfo2(
epas[i], epas[i],
epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC ? epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC ?
null : getSalt(body.cname), null : getSalt(body.cname),
null).asn1Encode()); null).asn1Encode());
} }
DerOutputStream eid = new DerOutputStream();
eid.putSequence(pas);
outPAs.add(new PAData(Krb5.PA_ETYPE_INFO2, eid.toByteArray()));
boolean allOld = true; boolean allOld = true;
for (int i: eTypes) { for (int i: eTypes) {
if (i == EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96 || if (i == EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96 ||
...@@ -916,6 +965,7 @@ public class KDC { ...@@ -916,6 +965,7 @@ public class KDC {
} }
} }
if (allOld) { if (allOld) {
pas = new DerValue[epas.length];
for (int i=0; i<epas.length; i++) { for (int i=0; i<epas.length; i++) {
pas[i] = new DerValue(new ETypeInfo( pas[i] = new DerValue(new ETypeInfo(
epas[i], epas[i],
...@@ -923,6 +973,16 @@ public class KDC { ...@@ -923,6 +973,16 @@ public class KDC {
null : getSalt(body.cname) null : getSalt(body.cname)
).asn1Encode()); ).asn1Encode());
} }
}
}
DerOutputStream eid;
if (pas2 != null) {
eid = new DerOutputStream();
eid.putSequence(pas2);
outPAs.add(new PAData(Krb5.PA_ETYPE_INFO2, eid.toByteArray()));
}
if (pas != null) {
eid = new DerOutputStream(); eid = new DerOutputStream();
eid.putSequence(pas); eid.putSequence(pas);
outPAs.add(new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray())); outPAs.add(new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray()));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册