Path: blob/master/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java
41161 views
/*1* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26*27* (C) Copyright IBM Corp. 1999 All Rights Reserved.28* Copyright 1997 The Open Group Research Institute. All rights reserved.29*/3031package sun.security.krb5.internal;3233import java.io.IOException;34import java.util.Vector;3536import static java.nio.charset.StandardCharsets.*;3738import sun.security.krb5.Asn1Exception;39import sun.security.krb5.internal.util.KerberosString;40import sun.security.krb5.internal.crypto.EType;41import sun.security.util.*;4243/**44* Implements the ASN.1 PA-DATA type.45*46* <pre>{@code47* PA-DATA ::= SEQUENCE {48* -- NOTE: first tag is [1], not [0]49* padata-type [1] Int32,50* padata-value [2] OCTET STRING -- might be encoded AP-REQ51* }52* }</pre>53*54* <p>55* This definition reflects the Network Working Group RFC 412056* specification available at57* <a href="http://www.ietf.org/rfc/rfc4120.txt">58* http://www.ietf.org/rfc/rfc4120.txt</a>.59*/6061public class PAData {62private int pADataType;63private byte[] pADataValue = null;64private static final byte TAG_PATYPE = 1;65private static final byte TAG_PAVALUE = 2;6667private PAData() {68}6970public PAData(int new_pADataType, byte[] new_pADataValue) {71pADataType = new_pADataType;72if (new_pADataValue != null) {73pADataValue = new_pADataValue.clone();74}75}7677public Object clone() {78PAData new_pAData = new PAData();79new_pAData.pADataType = pADataType;80if (pADataValue != null) {81new_pAData.pADataValue = new byte[pADataValue.length];82System.arraycopy(pADataValue, 0, new_pAData.pADataValue,830, pADataValue.length);84}85return new_pAData;86}8788/**89* Constructs a PAData object.90* @param encoding a Der-encoded data.91* @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.92* @exception IOException if an I/O error occurs while reading encoded data.93*/94public PAData(DerValue encoding) throws Asn1Exception, IOException {95DerValue der = null;96if (encoding.getTag() != DerValue.tag_Sequence) {97throw new Asn1Exception(Krb5.ASN1_BAD_ID);98}99der = encoding.getData().getDerValue();100if ((der.getTag() & 0x1F) == 0x01) {101this.pADataType = der.getData().getBigInteger().intValue();102}103else104throw new Asn1Exception(Krb5.ASN1_BAD_ID);105der = encoding.getData().getDerValue();106if ((der.getTag() & 0x1F) == 0x02) {107this.pADataValue = der.getData().getOctetString();108}109if (encoding.getData().available() > 0)110throw new Asn1Exception(Krb5.ASN1_BAD_ID);111}112113/**114* Encodes this object to an OutputStream.115*116* @return byte array of the encoded data.117* @exception IOException if an I/O error occurs while reading encoded data.118* @exception Asn1Exception on encoding errors.119*/120public byte[] asn1Encode() throws Asn1Exception, IOException {121122DerOutputStream bytes = new DerOutputStream();123DerOutputStream temp = new DerOutputStream();124125temp.putInteger(pADataType);126bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_PATYPE), temp);127temp = new DerOutputStream();128temp.putOctetString(pADataValue);129bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_PAVALUE), temp);130131temp = new DerOutputStream();132temp.write(DerValue.tag_Sequence, bytes);133return temp.toByteArray();134}135136// accessor methods137public int getType() {138return pADataType;139}140141public byte[] getValue() {142return ((pADataValue == null) ? null : pADataValue.clone());143}144145/**146* Parse (unmarshal) a PAData from a DER input stream. This form147* parsing might be used when expanding a value which is part of148* a constructed sequence and uses explicitly tagged type.149*150* @exception Asn1Exception if an Asn1Exception occurs.151* @param data the Der input stream value, which contains one or more152* marshaled values.153* @param explicitTag tag number.154* @param optional indicates if this data field is optional.155* @return an array of PAData.156*/157public static PAData[] parseSequence(DerInputStream data,158byte explicitTag, boolean optional)159throws Asn1Exception, IOException {160if ((optional) &&161(((byte)data.peekByte() & (byte)0x1F) != explicitTag))162return null;163DerValue subDer = data.getDerValue();164DerValue subsubDer = subDer.getData().getDerValue();165if (subsubDer.getTag() != DerValue.tag_SequenceOf) {166throw new Asn1Exception(Krb5.ASN1_BAD_ID);167}168Vector<PAData> v = new Vector<>();169while (subsubDer.getData().available() > 0) {170v.addElement(new PAData(subsubDer.getData().getDerValue()));171}172if (v.size() > 0) {173PAData[] pas = new PAData[v.size()];174v.copyInto(pas);175return pas;176}177return null;178}179180/**181* Gets the preferred etype from the PAData array.182* <ol>183* <li>ETYPE-INFO2-ENTRY with unknown s2kparams ignored</li>184* <li>ETYPE-INFO2 preferred to ETYPE-INFO</li>185* <li>Multiple entries for same etype in one PA-DATA, use the first one.</li>186* <li>Multiple PA-DATA with same type, choose the last one.</li>187* </ol>188* (This is useful when PA-DATAs from KRB-ERROR and AS-REP are combined).189*190* @return the etype, or defaultEType if not enough info191* @throws Asn1Exception|IOException if there is an encoding error192*/193public static int getPreferredEType(PAData[] pas, int defaultEType)194throws IOException, Asn1Exception {195196if (pas == null) return defaultEType;197198DerValue d = null, d2 = null;199for (PAData p: pas) {200if (p.getValue() == null) continue;201switch (p.getType()) {202case Krb5.PA_ETYPE_INFO:203d = new DerValue(p.getValue());204break;205case Krb5.PA_ETYPE_INFO2:206d2 = new DerValue(p.getValue());207break;208}209}210if (d2 != null) {211while (d2.data.available() > 0) {212DerValue value = d2.data.getDerValue();213ETypeInfo2 tmp = new ETypeInfo2(value);214if (EType.isNewer(tmp.getEType()) || tmp.getParams() == null) {215// we don't support non-null s2kparams for old etypes216return tmp.getEType();217}218}219}220if (d != null) {221while (d.data.available() > 0) {222DerValue value = d.data.getDerValue();223ETypeInfo tmp = new ETypeInfo(value);224return tmp.getEType();225}226}227return defaultEType;228}229230/**231* A place to store a pair of salt and s2kparams.232* An empty salt is changed to null, to be interoperable233* with Windows 2000 server. This is in fact not correct.234*/235public static class SaltAndParams {236public final String salt;237public final byte[] params;238public SaltAndParams(String s, byte[] p) {239if (s != null && s.isEmpty()) s = null;240this.salt = s;241this.params = p;242}243}244245/**246* Fetches salt and s2kparams value for eType in a series of PA-DATAs.247* 1. ETYPE-INFO2-ENTRY with unknown s2kparams ignored248* 2. PA-ETYPE-INFO2 preferred to PA-ETYPE-INFO preferred to PA-PW-SALT.249* 3. multiple entries for same etype in one PA-DATA, use the first one.250* 4. Multiple PA-DATA with same type, choose the last one251* (This is useful when PA-DATAs from KRB-ERROR and AS-REP are combined).252* @return salt and s2kparams. can be null if not found253*/254public static SaltAndParams getSaltAndParams(int eType, PAData[] pas)255throws Asn1Exception, IOException {256257if (pas == null) return null;258259DerValue d = null, d2 = null;260String paPwSalt = null;261262for (PAData p: pas) {263if (p.getValue() == null) continue;264switch (p.getType()) {265case Krb5.PA_PW_SALT:266paPwSalt = new String(p.getValue(),267KerberosString.MSNAME ? UTF_8 : ISO_8859_1);268break;269case Krb5.PA_ETYPE_INFO:270d = new DerValue(p.getValue());271break;272case Krb5.PA_ETYPE_INFO2:273d2 = new DerValue(p.getValue());274break;275}276}277if (d2 != null) {278while (d2.data.available() > 0) {279DerValue value = d2.data.getDerValue();280ETypeInfo2 tmp = new ETypeInfo2(value);281if (tmp.getEType() == eType &&282(EType.isNewer(eType) || tmp.getParams() == null)) {283// we don't support non-null s2kparams for old etypes284return new SaltAndParams(tmp.getSalt(), tmp.getParams());285}286}287}288if (d != null) {289while (d.data.available() > 0) {290DerValue value = d.data.getDerValue();291ETypeInfo tmp = new ETypeInfo(value);292if (tmp.getEType() == eType) {293return new SaltAndParams(tmp.getSalt(), null);294}295}296}297if (paPwSalt != null) {298return new SaltAndParams(paPwSalt, null);299}300return null;301}302303@Override304public String toString(){305StringBuilder sb = new StringBuilder();306sb.append(">>>Pre-Authentication Data:\n\t PA-DATA type = ")307.append(pADataType).append('\n');308309switch(pADataType) {310case Krb5.PA_ENC_TIMESTAMP:311sb.append("\t PA-ENC-TIMESTAMP");312break;313case Krb5.PA_ETYPE_INFO:314if (pADataValue != null) {315try {316DerValue der = new DerValue(pADataValue);317while (der.data.available() > 0) {318DerValue value = der.data.getDerValue();319ETypeInfo info = new ETypeInfo(value);320sb.append("\t PA-ETYPE-INFO etype = ")321.append(info.getEType())322.append(", salt = ")323.append(info.getSalt())324.append('\n');325}326} catch (IOException|Asn1Exception e) {327sb.append("\t <Unparseable PA-ETYPE-INFO>\n");328}329}330break;331case Krb5.PA_ETYPE_INFO2:332if (pADataValue != null) {333try {334DerValue der = new DerValue(pADataValue);335while (der.data.available() > 0) {336DerValue value = der.data.getDerValue();337ETypeInfo2 info2 = new ETypeInfo2(value);338sb.append("\t PA-ETYPE-INFO2 etype = ")339.append(info2.getEType())340.append(", salt = ")341.append(info2.getSalt())342.append(", s2kparams = ");343byte[] s2kparams = info2.getParams();344if (s2kparams == null) {345sb.append("null\n");346} else if (s2kparams.length == 0) {347sb.append("empty\n");348} else {349sb.append(new sun.security.util.HexDumpEncoder()350.encodeBuffer(s2kparams));351}352}353} catch (IOException|Asn1Exception e) {354sb.append("\t <Unparseable PA-ETYPE-INFO>\n");355}356}357break;358case Krb5.PA_FOR_USER:359sb.append("\t PA-FOR-USER\n");360break;361default:362// Unknown Pre-auth type363break;364}365return sb.toString();366}367}368369370