1 /* 2 * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * 28 * (C) Copyright IBM Corp. 1999 All Rights Reserved. 29 * Copyright 1997 The Open Group Research Institute. All rights reserved. 30 */ 31 32 package sun.security.krb5.internal; 33 34 import sun.security.krb5.Config; 35 import sun.security.krb5.Asn1Exception; 36 import sun.security.util.*; 37 import java.net.InetAddress; 38 import java.net.Inet4Address; 39 import java.net.Inet6Address; 40 import java.net.UnknownHostException; 41 import java.io.IOException; 42 import java.util.Arrays; 43 44 /** 45 * Implements the ASN.1 HostAddress type. 46 * 47 * <pre>{@code 48 * HostAddress ::= SEQUENCE { 49 * addr-type [0] Int32, 50 * address [1] OCTET STRING 51 * } 52 * }</pre> 53 * 54 * <p> 55 * This definition reflects the Network Working Group RFC 4120 56 * specification available at 57 * <a href="http://www.ietf.org/rfc/rfc4120.txt"> 58 * http://www.ietf.org/rfc/rfc4120.txt</a>. 59 */ 60 61 public class HostAddress implements Cloneable { 62 int addrType; 63 byte[] address = null; 64 65 private static InetAddress localInetAddress; //caches local inet address 66 private static final boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; 67 private volatile int hashCode = 0; 68 HostAddress(int dummy)69 private HostAddress(int dummy) {} 70 clone()71 public Object clone() { 72 HostAddress new_hostAddress = new HostAddress(0); 73 new_hostAddress.addrType = addrType; 74 if (address != null) { 75 new_hostAddress.address = address.clone(); 76 } 77 return new_hostAddress; 78 } 79 80 hashCode()81 public int hashCode() { 82 if (hashCode == 0) { 83 int result = 17; 84 result = 37*result + addrType; 85 if (address != null) { 86 for (int i=0; i < address.length; i++) { 87 result = 37*result + address[i]; 88 } 89 } 90 hashCode = result; 91 } 92 return hashCode; 93 94 } 95 equals(Object obj)96 public boolean equals(Object obj) { 97 if (this == obj) { 98 return true; 99 } 100 101 if (!(obj instanceof HostAddress)) { 102 return false; 103 } 104 105 HostAddress h = (HostAddress)obj; 106 if (addrType != h.addrType || 107 (address != null && h.address == null) || 108 (address == null && h.address != null)) 109 return false; 110 if (address != null && h.address != null) { 111 if (address.length != h.address.length) 112 return false; 113 for (int i = 0; i < address.length; i++) 114 if (address[i] != h.address[i]) 115 return false; 116 } 117 return true; 118 } 119 getLocalInetAddress()120 private static synchronized InetAddress getLocalInetAddress() 121 throws UnknownHostException { 122 123 if (localInetAddress == null) { 124 localInetAddress = InetAddress.getLocalHost(); 125 } 126 if (localInetAddress == null) { 127 throw new UnknownHostException(); 128 } 129 return (localInetAddress); 130 } 131 132 /** 133 * Gets the InetAddress of this HostAddress. 134 * @return the IP address for this specified host. 135 * @exception UnknownHostException if no IP address for the host could be found. 136 * 137 */ getInetAddress()138 public InetAddress getInetAddress() throws UnknownHostException { 139 // the type of internet addresses is 2. 140 if (addrType == Krb5.ADDRTYPE_INET || 141 addrType == Krb5.ADDRTYPE_INET6) { 142 return (InetAddress.getByAddress(address)); 143 } else { 144 // if it is other type (ISO address, XNS address, etc) 145 return null; 146 } 147 } 148 getAddrType(InetAddress inetAddress)149 private int getAddrType(InetAddress inetAddress) { 150 int addressType = 0; 151 if (inetAddress instanceof Inet4Address) 152 addressType = Krb5.ADDRTYPE_INET; 153 else if (inetAddress instanceof Inet6Address) 154 addressType = Krb5.ADDRTYPE_INET6; 155 return (addressType); 156 } 157 158 // implicit default not in Config.java HostAddress()159 public HostAddress() throws UnknownHostException { 160 InetAddress inetAddress = getLocalInetAddress(); 161 addrType = getAddrType(inetAddress); 162 address = inetAddress.getAddress(); 163 } 164 165 /** 166 * Creates a HostAddress from the specified address and address type. 167 * 168 * @param new_addrType the value of the address type which matches the defined 169 * address family constants in the Berkeley Standard 170 * Distributions of Unix. 171 * @param new_address network address. 172 * @exception KrbApErrException if address type and address length do not match defined value. 173 * 174 */ HostAddress(int new_addrType, byte[] new_address)175 public HostAddress(int new_addrType, byte[] new_address) 176 throws KrbApErrException, UnknownHostException { 177 switch(new_addrType) { 178 case Krb5.ADDRTYPE_INET: //Internet address 179 if (new_address.length != 4) 180 throw new KrbApErrException(0, "Invalid Internet address"); 181 break; 182 case Krb5.ADDRTYPE_CHAOS: 183 if (new_address.length != 2) //CHAOSnet address 184 throw new KrbApErrException(0, "Invalid CHAOSnet address"); 185 break; 186 case Krb5.ADDRTYPE_ISO: // ISO address 187 break; 188 case Krb5.ADDRTYPE_IPX: // XNS address 189 if (new_address.length != 6) 190 throw new KrbApErrException(0, "Invalid XNS address"); 191 break; 192 case Krb5.ADDRTYPE_APPLETALK: //AppleTalk DDP address 193 if (new_address.length != 3) 194 throw new KrbApErrException(0, "Invalid DDP address"); 195 break; 196 case Krb5.ADDRTYPE_DECNET: //DECnet Phase IV address 197 if (new_address.length != 2) 198 throw new KrbApErrException(0, "Invalid DECnet Phase IV address"); 199 break; 200 case Krb5.ADDRTYPE_INET6: //Internet IPv6 address 201 if (new_address.length != 16) 202 throw new KrbApErrException(0, "Invalid Internet IPv6 address"); 203 break; 204 } 205 206 addrType = new_addrType; 207 if (new_address != null) { 208 address = new_address.clone(); 209 } 210 if (DEBUG) { 211 if (addrType == Krb5.ADDRTYPE_INET || 212 addrType == Krb5.ADDRTYPE_INET6) { 213 System.out.println("Host address is " + 214 InetAddress.getByAddress(address)); 215 } 216 } 217 } 218 HostAddress(InetAddress inetAddress)219 public HostAddress(InetAddress inetAddress) { 220 addrType = getAddrType(inetAddress); 221 address = inetAddress.getAddress(); 222 } 223 224 /** 225 * Constructs a host address from a single DER-encoded value. 226 * @param encoding a single DER-encoded value. 227 * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. 228 * @exception IOException if an I/O error occurs while reading encoded data. 229 * 230 */ HostAddress(DerValue encoding)231 public HostAddress(DerValue encoding) throws Asn1Exception, IOException { 232 DerValue der = encoding.getData().getDerValue(); 233 if ((der.getTag() & (byte)0x1F) == (byte)0x00) { 234 addrType = der.getData().getBigInteger().intValue(); 235 } 236 else 237 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 238 der = encoding.getData().getDerValue(); 239 if ((der.getTag() & (byte)0x1F) == (byte)0x01) { 240 address = der.getData().getOctetString(); 241 } 242 else 243 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 244 if (encoding.getData().available() > 0) 245 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 246 } 247 248 /** 249 * Encodes a HostAddress object. 250 * @return a byte array of encoded HostAddress object. 251 * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. 252 * @exception IOException if an I/O error occurs while reading encoded data. 253 * 254 */ 255 asn1Encode()256 public byte[] asn1Encode() throws Asn1Exception, IOException { 257 DerOutputStream bytes = new DerOutputStream(); 258 DerOutputStream temp = new DerOutputStream(); 259 temp.putInteger(this.addrType); 260 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp); 261 temp = new DerOutputStream(); 262 temp.putOctetString(address); 263 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), temp); 264 temp = new DerOutputStream(); 265 temp.write(DerValue.tag_Sequence, bytes); 266 return temp.toByteArray(); 267 } 268 269 /** 270 * Parses (unmarshal) a host address from a DER input stream. This form 271 * parsing might be used when expanding a value which is part of 272 * a constructed sequence and uses explicitly tagged type. 273 * 274 * @exception Asn1Exception on error. 275 * @exception IOException if an I/O error occurs while reading encoded data. 276 * @param data the Der input stream value, which contains one or more marshaled value. 277 * @param explicitTag tag number. 278 * @param optional indicates if this data field is optional 279 * @return an instance of HostAddress. 280 * 281 */ parse(DerInputStream data, byte explicitTag, boolean optional)282 public static HostAddress parse(DerInputStream data, byte explicitTag, 283 boolean optional) 284 throws Asn1Exception, IOException{ 285 if ((optional) && 286 (((byte)data.peekByte() & (byte)0x1F) != explicitTag)) { 287 return null; 288 } 289 DerValue der = data.getDerValue(); 290 if (explicitTag != (der.getTag() & (byte)0x1F)) { 291 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 292 } 293 else { 294 DerValue subDer = der.getData().getDerValue(); 295 return new HostAddress(subDer); 296 } 297 } 298 299 @Override toString()300 public String toString() { 301 StringBuilder sb = new StringBuilder(); 302 sb.append(Arrays.toString(address)); 303 sb.append('(').append(addrType).append(')'); 304 return sb.toString(); 305 } 306 } 307