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