0N/A/*
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A *
0N/A * (C) Copyright IBM Corp. 1999 All Rights Reserved.
0N/A * Copyright 1997 The Open Group Research Institute. All rights reserved.
0N/A */
0N/A
0N/Apackage sun.security.krb5.internal;
0N/A
3054N/Aimport sun.security.krb5.KrbException;
0N/Aimport sun.security.util.*;
0N/Aimport sun.security.krb5.Asn1Exception;
0N/Aimport java.io.IOException;
3054N/Aimport sun.security.krb5.internal.util.KerberosString;
0N/A
0N/A/**
0N/A * Implements the ASN.1 PA-DATA type.
0N/A *
0N/A * <xmp>
0N/A * PA-DATA ::= SEQUENCE {
0N/A * -- NOTE: first tag is [1], not [0]
0N/A * padata-type [1] Int32,
0N/A * padata-value [2] OCTET STRING -- might be encoded AP-REQ
0N/A * }
0N/A * </xmp>
0N/A *
0N/A * <p>
0N/A * This definition reflects the Network Working Group RFC 4120
0N/A * specification available at
0N/A * <a href="http://www.ietf.org/rfc/rfc4120.txt">
0N/A * http://www.ietf.org/rfc/rfc4120.txt</a>.
0N/A */
0N/A
0N/Apublic class PAData {
0N/A private int pADataType;
0N/A private byte[] pADataValue = null;
0N/A private static final byte TAG_PATYPE = 1;
0N/A private static final byte TAG_PAVALUE = 2;
0N/A
0N/A private PAData() {
0N/A }
0N/A
0N/A public PAData(int new_pADataType, byte[] new_pADataValue) {
0N/A pADataType = new_pADataType;
0N/A if (new_pADataValue != null) {
0N/A pADataValue = new_pADataValue.clone();
0N/A }
0N/A }
0N/A
0N/A public Object clone() {
0N/A PAData new_pAData = new PAData();
0N/A new_pAData.pADataType = pADataType;
0N/A if (pADataValue != null) {
0N/A new_pAData.pADataValue = new byte[pADataValue.length];
0N/A System.arraycopy(pADataValue, 0, new_pAData.pADataValue,
0N/A 0, pADataValue.length);
0N/A }
0N/A return new_pAData;
0N/A }
0N/A
0N/A /**
0N/A * Constructs a PAData object.
0N/A * @param encoding a Der-encoded data.
0N/A * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
0N/A * @exception IOException if an I/O error occurs while reading encoded data.
0N/A */
0N/A public PAData(DerValue encoding) throws Asn1Exception, IOException {
0N/A DerValue der = null;
0N/A if (encoding.getTag() != DerValue.tag_Sequence) {
0N/A throw new Asn1Exception(Krb5.ASN1_BAD_ID);
0N/A }
0N/A der = encoding.getData().getDerValue();
0N/A if ((der.getTag() & 0x1F) == 0x01) {
0N/A this.pADataType = der.getData().getBigInteger().intValue();
0N/A }
0N/A else
0N/A throw new Asn1Exception(Krb5.ASN1_BAD_ID);
0N/A der = encoding.getData().getDerValue();
0N/A if ((der.getTag() & 0x1F) == 0x02) {
0N/A this.pADataValue = der.getData().getOctetString();
0N/A }
0N/A if (encoding.getData().available() > 0)
0N/A throw new Asn1Exception(Krb5.ASN1_BAD_ID);
0N/A }
0N/A
0N/A /**
0N/A * Encodes this object to an OutputStream.
0N/A *
0N/A * @return byte array of the encoded data.
0N/A * @exception IOException if an I/O error occurs while reading encoded data.
0N/A * @exception Asn1Exception on encoding errors.
0N/A */
0N/A public byte[] asn1Encode() throws Asn1Exception, IOException {
0N/A
0N/A DerOutputStream bytes = new DerOutputStream();
0N/A DerOutputStream temp = new DerOutputStream();
0N/A
0N/A temp.putInteger(pADataType);
0N/A bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_PATYPE), temp);
0N/A temp = new DerOutputStream();
0N/A temp.putOctetString(pADataValue);
0N/A bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_PAVALUE), temp);
0N/A
0N/A temp = new DerOutputStream();
0N/A temp.write(DerValue.tag_Sequence, bytes);
0N/A return temp.toByteArray();
0N/A }
0N/A
0N/A // accessor methods
0N/A public int getType() {
0N/A return pADataType;
0N/A }
0N/A
0N/A public byte[] getValue() {
0N/A return ((pADataValue == null) ? null : pADataValue.clone());
0N/A }
3054N/A
3054N/A /**
4391N/A * Gets the preferred etype from the PAData array.
4391N/A * 1. ETYPE-INFO2-ENTRY with unknown s2kparams ignored
4391N/A * 2. ETYPE-INFO2 preferred to ETYPE-INFO
4391N/A * 3. multiple entries for same etype in one PA-DATA, use the first one.
4391N/A * 4. Multiple PA-DATA with same type, choose the last one
4391N/A * (This is useful when PA-DATAs from KRB-ERROR and AS-REP are combined).
4391N/A * @return the etype, or defaultEType if not enough info
4391N/A * @throws Asn1Exception|IOException if there is an encoding error
4391N/A */
4391N/A public static int getPreferredEType(PAData[] pas, int defaultEType)
4391N/A throws IOException, Asn1Exception {
4391N/A
4391N/A if (pas == null) return defaultEType;
4391N/A
4391N/A DerValue d = null, d2 = null;
4391N/A for (PAData p: pas) {
4391N/A if (p.getValue() == null) continue;
4391N/A switch (p.getType()) {
4391N/A case Krb5.PA_ETYPE_INFO:
4391N/A d = new DerValue(p.getValue());
4391N/A break;
4391N/A case Krb5.PA_ETYPE_INFO2:
4391N/A d2 = new DerValue(p.getValue());
4391N/A break;
4391N/A }
4391N/A }
4391N/A if (d2 != null) {
4391N/A while (d2.data.available() > 0) {
4391N/A DerValue value = d2.data.getDerValue();
4391N/A ETypeInfo2 tmp = new ETypeInfo2(value);
4391N/A if (tmp.getParams() == null) {
4391N/A // we don't support non-null s2kparams
4391N/A return tmp.getEType();
4391N/A }
4391N/A }
4391N/A }
4391N/A if (d != null) {
4391N/A while (d.data.available() > 0) {
4391N/A DerValue value = d.data.getDerValue();
4391N/A ETypeInfo tmp = new ETypeInfo(value);
4391N/A return tmp.getEType();
4391N/A }
4391N/A }
4391N/A return defaultEType;
4391N/A }
4391N/A
4391N/A /**
3054N/A * A place to store a pair of salt and s2kparams.
4391N/A * An empty salt is changed to null, to be interoperable
4391N/A * with Windows 2000 server. This is in fact not correct.
3054N/A */
3054N/A public static class SaltAndParams {
3054N/A public final String salt;
3054N/A public final byte[] params;
3054N/A public SaltAndParams(String s, byte[] p) {
3054N/A if (s != null && s.isEmpty()) s = null;
3054N/A this.salt = s;
3054N/A this.params = p;
3054N/A }
3054N/A }
3054N/A
3054N/A /**
3054N/A * Fetches salt and s2kparams value for eType in a series of PA-DATAs.
4391N/A * 1. ETYPE-INFO2-ENTRY with unknown s2kparams ignored
4391N/A * 2. PA-ETYPE-INFO2 preferred to PA-ETYPE-INFO preferred to PA-PW-SALT.
4391N/A * 3. multiple entries for same etype in one PA-DATA, use the first one.
4391N/A * 4. Multiple PA-DATA with same type, choose the last one
3054N/A * (This is useful when PA-DATAs from KRB-ERROR and AS-REP are combined).
4391N/A * @return salt and s2kparams. can be null if not found
3054N/A */
3054N/A public static SaltAndParams getSaltAndParams(int eType, PAData[] pas)
4391N/A throws Asn1Exception, IOException {
3054N/A
4391N/A if (pas == null) return null;
3054N/A
4391N/A DerValue d = null, d2 = null;
3054N/A String paPwSalt = null;
3054N/A
3054N/A for (PAData p: pas) {
4391N/A if (p.getValue() == null) continue;
4391N/A switch (p.getType()) {
4391N/A case Krb5.PA_PW_SALT:
4391N/A paPwSalt = new String(p.getValue(),
4391N/A KerberosString.MSNAME?"UTF8":"8859_1");
4391N/A break;
4391N/A case Krb5.PA_ETYPE_INFO:
4391N/A d = new DerValue(p.getValue());
4391N/A break;
4391N/A case Krb5.PA_ETYPE_INFO2:
4391N/A d2 = new DerValue(p.getValue());
4391N/A break;
4391N/A }
4391N/A }
4391N/A if (d2 != null) {
4391N/A while (d2.data.available() > 0) {
4391N/A DerValue value = d2.data.getDerValue();
4391N/A ETypeInfo2 tmp = new ETypeInfo2(value);
4391N/A if (tmp.getParams() == null && tmp.getEType() == eType) {
4391N/A // we don't support non-null s2kparams
4391N/A return new SaltAndParams(tmp.getSalt(), tmp.getParams());
4391N/A }
4391N/A }
4391N/A }
4391N/A if (d != null) {
4391N/A while (d.data.available() > 0) {
4391N/A DerValue value = d.data.getDerValue();
4391N/A ETypeInfo tmp = new ETypeInfo(value);
4391N/A if (tmp.getEType() == eType) {
4391N/A return new SaltAndParams(tmp.getSalt(), null);
3054N/A }
3054N/A }
3054N/A }
4391N/A if (paPwSalt != null) {
4391N/A return new SaltAndParams(paPwSalt, null);
3054N/A }
4391N/A return null;
4391N/A }
4391N/A
4391N/A @Override
4391N/A public String toString(){
4391N/A StringBuilder sb = new StringBuilder();
4391N/A sb.append(">>>Pre-Authentication Data:\n\t PA-DATA type = ")
4391N/A .append(pADataType).append('\n');
4391N/A
4391N/A switch(pADataType) {
4391N/A case Krb5.PA_ENC_TIMESTAMP:
4391N/A sb.append("\t PA-ENC-TIMESTAMP");
4391N/A break;
4391N/A case Krb5.PA_ETYPE_INFO:
4391N/A if (pADataValue != null) {
4391N/A try {
4391N/A DerValue der = new DerValue(pADataValue);
4391N/A while (der.data.available() > 0) {
4391N/A DerValue value = der.data.getDerValue();
4391N/A ETypeInfo info = new ETypeInfo(value);
4391N/A sb.append("\t PA-ETYPE-INFO etype = ")
4391N/A .append(info.getEType())
4391N/A .append(", salt = ")
4391N/A .append(info.getSalt())
4391N/A .append('\n');
4391N/A }
4391N/A } catch (IOException|Asn1Exception e) {
4391N/A sb.append("\t <Unparseable PA-ETYPE-INFO>\n");
4391N/A }
4391N/A }
4391N/A break;
4391N/A case Krb5.PA_ETYPE_INFO2:
4391N/A if (pADataValue != null) {
4391N/A try {
4391N/A DerValue der = new DerValue(pADataValue);
4391N/A while (der.data.available() > 0) {
4391N/A DerValue value = der.data.getDerValue();
4391N/A ETypeInfo2 info2 = new ETypeInfo2(value);
4391N/A sb.append("\t PA-ETYPE-INFO2 etype = ")
4391N/A .append(info2.getEType())
4391N/A .append(", salt = ")
4391N/A .append(info2.getSalt())
4391N/A .append(", s2kparams = ");
4391N/A byte[] s2kparams = info2.getParams();
4391N/A if (s2kparams == null) {
4391N/A sb.append("null\n");
4391N/A } else if (s2kparams.length == 0) {
4391N/A sb.append("empty\n");
4391N/A } else {
4391N/A sb.append(new sun.misc.HexDumpEncoder()
4391N/A .encodeBuffer(s2kparams));
4391N/A }
4391N/A }
4391N/A } catch (IOException|Asn1Exception e) {
4391N/A sb.append("\t <Unparseable PA-ETYPE-INFO>\n");
4391N/A }
4391N/A }
4391N/A break;
4391N/A default:
4391N/A // Unknown Pre-auth type
4391N/A break;
4391N/A }
4391N/A return sb.toString();
3054N/A }
0N/A}