Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/x509/IPAddressName.java
41159 views
1
/*
2
* Copyright (c) 1997, 2018, 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
package sun.security.x509;
27
28
import java.io.IOException;
29
import java.lang.Integer;
30
import java.net.InetAddress;
31
import java.util.Arrays;
32
import sun.security.util.HexDumpEncoder;
33
import sun.security.util.BitArray;
34
import sun.security.util.DerOutputStream;
35
import sun.security.util.DerValue;
36
37
/**
38
* This class implements the IPAddressName as required by the GeneralNames
39
* ASN.1 object. Both IPv4 and IPv6 addresses are supported using the
40
* formats specified in IETF PKIX RFC 5280.
41
* <p>
42
* [RFC 5280 4.2.1.6 Subject Alternative Name]
43
* When the subjectAltName extension contains an iPAddress, the address
44
* MUST be stored in the octet string in "network byte order", as
45
* specified in [RFC791]. The least significant bit (LSB) of each octet
46
* is the LSB of the corresponding byte in the network address. For IP
47
* version 4, as specified in [RFC791], the octet string MUST contain
48
* exactly four octets. For IP version 6, as specified in
49
* [RFC 2460], the octet string MUST contain exactly sixteen octets.
50
* <p>
51
* [RFC 5280 4.2.1.10 Name Constraints]
52
* The syntax of iPAddress MUST be as described in Section 4.2.1.6 with
53
* the following additions specifically for name constraints. For IPv4
54
* addresses, the iPAddress field of GeneralName MUST contain eight (8)
55
* octets, encoded in the style of RFC 4632 (CIDR) to represent an
56
* address range [RFC 4632]. For IPv6 addresses, the iPAddress field
57
* MUST contain 32 octets similarly encoded. For example, a name
58
* constraint for "class C" subnet 192.0.2.0 is represented as the
59
* octets C0 00 02 00 FF FF FF 00, representing the CIDR notation
60
* 192.0.2.0/24 (mask 255.255.255.0).
61
* <p>
62
* @see GeneralName
63
* @see GeneralNameInterface
64
* @see GeneralNames
65
*
66
*
67
* @author Amit Kapoor
68
* @author Hemma Prafullchandra
69
*/
70
public class IPAddressName implements GeneralNameInterface {
71
private byte[] address;
72
private boolean isIPv4;
73
private String name;
74
75
/**
76
* Create the IPAddressName object from the passed encoded Der value.
77
*
78
* @param derValue the encoded DER IPAddressName.
79
* @exception IOException on error.
80
*/
81
public IPAddressName(DerValue derValue) throws IOException {
82
this(derValue.getOctetString());
83
}
84
85
/**
86
* Create the IPAddressName object with the specified octets.
87
*
88
* @param address the IP address
89
* @throws IOException if address is not a valid IPv4 or IPv6 address
90
*/
91
public IPAddressName(byte[] address) throws IOException {
92
/*
93
* A valid address must consist of 4 bytes of address and
94
* optional 4 bytes of 4 bytes of mask, or 16 bytes of address
95
* and optional 16 bytes of mask.
96
*/
97
if (address.length == 4 || address.length == 8) {
98
isIPv4 = true;
99
} else if (address.length == 16 || address.length == 32) {
100
isIPv4 = false;
101
} else {
102
throw new IOException("Invalid IPAddressName");
103
}
104
this.address = address;
105
}
106
107
/**
108
* Create an IPAddressName from a String.
109
* [IETF RFC1338 Supernetting {@literal &} IETF RFC1519 Classless Inter-Domain
110
* Routing (CIDR)] For IPv4 addresses, the forms are
111
* "b1.b2.b3.b4" or "b1.b2.b3.b4/m1.m2.m3.m4", where b1 - b4 are decimal
112
* byte values 0-255 and m1 - m4 are decimal mask values
113
* 0 - 255.
114
* <p>
115
* [IETF RFC2373 IP Version 6 Addressing Architecture]
116
* For IPv6 addresses, the forms are "a1:a2:...:a8" or "a1:a2:...:a8/n",
117
* where a1-a8 are hexadecimal values representing the eight 16-bit pieces
118
* of the address. If /n is used, n is a decimal number indicating how many
119
* of the leftmost contiguous bits of the address comprise the prefix for
120
* this subnet. Internally, a mask value is created using the prefix length.
121
*
122
* @param name String form of IPAddressName
123
* @throws IOException if name can not be converted to a valid IPv4 or IPv6
124
* address
125
*/
126
public IPAddressName(String name) throws IOException {
127
128
if (name == null || name.isEmpty()) {
129
throw new IOException("IPAddress cannot be null or empty");
130
}
131
if (name.charAt(name.length() - 1) == '/') {
132
throw new IOException("Invalid IPAddress: " + name);
133
}
134
135
if (name.indexOf(':') >= 0) {
136
// name is IPv6: uses colons as value separators
137
// Parse name into byte-value address components and optional
138
// prefix
139
parseIPv6(name);
140
isIPv4 = false;
141
} else if (name.indexOf('.') >= 0) {
142
//name is IPv4: uses dots as value separators
143
parseIPv4(name);
144
isIPv4 = true;
145
} else {
146
throw new IOException("Invalid IPAddress: " + name);
147
}
148
}
149
150
/**
151
* Parse an IPv4 address.
152
*
153
* @param name IPv4 address with optional mask values
154
* @throws IOException on error
155
*/
156
private void parseIPv4(String name) throws IOException {
157
158
// Parse name into byte-value address components
159
int slashNdx = name.indexOf('/');
160
if (slashNdx == -1) {
161
address = InetAddress.getByName(name).getAddress();
162
} else {
163
address = new byte[8];
164
165
// parse mask
166
byte[] mask = InetAddress.getByName
167
(name.substring(slashNdx+1)).getAddress();
168
169
// parse base address
170
byte[] host = InetAddress.getByName
171
(name.substring(0, slashNdx)).getAddress();
172
173
System.arraycopy(host, 0, address, 0, 4);
174
System.arraycopy(mask, 0, address, 4, 4);
175
}
176
}
177
178
/**
179
* Parse an IPv6 address.
180
*
181
* @param name String IPv6 address with optional /<prefix length>
182
* If /<prefix length> is present, address[] array will
183
* be 32 bytes long, otherwise 16.
184
* @throws IOException on error
185
*/
186
private static final int MASKSIZE = 16;
187
private void parseIPv6(String name) throws IOException {
188
189
int slashNdx = name.indexOf('/');
190
if (slashNdx == -1) {
191
address = InetAddress.getByName(name).getAddress();
192
} else {
193
address = new byte[32];
194
byte[] base = InetAddress.getByName
195
(name.substring(0, slashNdx)).getAddress();
196
System.arraycopy(base, 0, address, 0, 16);
197
198
// append a mask corresponding to the num of prefix bits specified
199
int prefixLen = Integer.parseInt(name.substring(slashNdx+1));
200
if (prefixLen < 0 || prefixLen > 128) {
201
throw new IOException("IPv6Address prefix length (" +
202
prefixLen + ") in out of valid range [0,128]");
203
}
204
205
// create new bit array initialized to zeros
206
BitArray bitArray = new BitArray(MASKSIZE * 8);
207
208
// set all most significant bits up to prefix length
209
for (int i = 0; i < prefixLen; i++)
210
bitArray.set(i, true);
211
byte[] maskArray = bitArray.toByteArray();
212
213
// copy mask bytes into mask portion of address
214
for (int i = 0; i < MASKSIZE; i++)
215
address[MASKSIZE+i] = maskArray[i];
216
}
217
}
218
219
/**
220
* Return the type of the GeneralName.
221
*/
222
public int getType() {
223
return NAME_IP;
224
}
225
226
/**
227
* Encode the IPAddress name into the DerOutputStream.
228
*
229
* @param out the DER stream to encode the IPAddressName to.
230
* @exception IOException on encoding errors.
231
*/
232
public void encode(DerOutputStream out) throws IOException {
233
out.putOctetString(address);
234
}
235
236
/**
237
* Return a printable string of IPaddress
238
*/
239
public String toString() {
240
try {
241
return "IPAddress: " + getName();
242
} catch (IOException ioe) {
243
// dump out hex rep for debugging purposes
244
HexDumpEncoder enc = new HexDumpEncoder();
245
return "IPAddress: " + enc.encodeBuffer(address);
246
}
247
}
248
249
/**
250
* Return a standard String representation of IPAddress.
251
* See IPAddressName(String) for the formats used for IPv4
252
* and IPv6 addresses.
253
*
254
* @throws IOException if the IPAddress cannot be converted to a String
255
*/
256
public String getName() throws IOException {
257
if (name != null)
258
return name;
259
260
if (isIPv4) {
261
//IPv4 address or subdomain
262
byte[] host = new byte[4];
263
System.arraycopy(address, 0, host, 0, 4);
264
name = InetAddress.getByAddress(host).getHostAddress();
265
if (address.length == 8) {
266
byte[] mask = new byte[4];
267
System.arraycopy(address, 4, mask, 0, 4);
268
name = name + '/' +
269
InetAddress.getByAddress(mask).getHostAddress();
270
}
271
} else {
272
//IPv6 address or subdomain
273
byte[] host = new byte[16];
274
System.arraycopy(address, 0, host, 0, 16);
275
name = InetAddress.getByAddress(host).getHostAddress();
276
if (address.length == 32) {
277
// IPv6 subdomain: display prefix length
278
279
// copy subdomain into new array and convert to BitArray
280
byte[] maskBytes = new byte[16];
281
for (int i=16; i < 32; i++)
282
maskBytes[i-16] = address[i];
283
BitArray ba = new BitArray(16*8, maskBytes);
284
// Find first zero bit
285
int i=0;
286
for (; i < 16*8; i++) {
287
if (!ba.get(i))
288
break;
289
}
290
name = name + '/' + i;
291
// Verify remaining bits 0
292
for (; i < 16*8; i++) {
293
if (ba.get(i)) {
294
throw new IOException("Invalid IPv6 subdomain - set " +
295
"bit " + i + " not contiguous");
296
}
297
}
298
}
299
}
300
return name;
301
}
302
303
/**
304
* Returns this IPAddress name as a byte array.
305
*/
306
public byte[] getBytes() {
307
return address.clone();
308
}
309
310
/**
311
* Compares this name with another, for equality.
312
*
313
* @return true iff the names are identical.
314
*/
315
public boolean equals(Object obj) {
316
if (this == obj)
317
return true;
318
319
if (!(obj instanceof IPAddressName))
320
return false;
321
322
IPAddressName otherName = (IPAddressName)obj;
323
byte[] other = otherName.address;
324
325
if (other.length != address.length)
326
return false;
327
328
if (address.length == 8 || address.length == 32) {
329
// Two subnet addresses
330
// Mask each and compare masked values
331
int maskLen = address.length/2;
332
for (int i=0; i < maskLen; i++) {
333
byte maskedThis = (byte)(address[i] & address[i+maskLen]);
334
byte maskedOther = (byte)(other[i] & other[i+maskLen]);
335
if (maskedThis != maskedOther) {
336
return false;
337
}
338
}
339
// Now compare masks
340
for (int i=maskLen; i < address.length; i++)
341
if (address[i] != other[i])
342
return false;
343
return true;
344
} else {
345
// Two IPv4 host addresses or two IPv6 host addresses
346
// Compare bytes
347
return Arrays.equals(other, address);
348
}
349
}
350
351
/**
352
* Returns the hash code value for this object.
353
*
354
* @return a hash code value for this object.
355
*/
356
public int hashCode() {
357
int retval = 0;
358
359
for (int i=0; i<address.length; i++)
360
retval += address[i] * i;
361
362
return retval;
363
}
364
365
/**
366
* Return type of constraint inputName places on this name:<ul>
367
* <li>NAME_DIFF_TYPE = -1: input name is different type from name
368
* (i.e. does not constrain).
369
* <li>NAME_MATCH = 0: input name matches name.
370
* <li>NAME_NARROWS = 1: input name narrows name (is lower in the naming
371
* subtree)
372
* <li>NAME_WIDENS = 2: input name widens name (is higher in the naming
373
* subtree)
374
* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but
375
* is same type.
376
* </ul>. These results are used in checking NameConstraints during
377
* certification path verification.
378
* <p>
379
* [RFC 5280 4.2.1.10 Name Constraints]
380
* The syntax of iPAddress MUST be as described in Section 4.2.1.6 with
381
* the following additions specifically for name constraints. For IPv4
382
* addresses, the iPAddress field of GeneralName MUST contain eight (8)
383
* octets, encoded in the style of RFC 4632 (CIDR) to represent an
384
* address range [RFC 4632]. For IPv6 addresses, the iPAddress field
385
* MUST contain 32 octets similarly encoded. For example, a name
386
* constraint for "class C" subnet 192.0.2.0 is represented as the
387
* octets C0 00 02 00 FF FF FF 00, representing the CIDR notation
388
* 192.0.2.0/24 (mask 255.255.255.0).
389
*
390
* @param inputName to be checked for being constrained
391
* @return constraint type above
392
* @throws UnsupportedOperationException if name is not exact match, but
393
* narrowing and widening are not supported for this name type.
394
*/
395
public int constrains(GeneralNameInterface inputName)
396
throws UnsupportedOperationException {
397
int constraintType;
398
if (inputName == null)
399
constraintType = NAME_DIFF_TYPE;
400
else if (inputName.getType() != NAME_IP)
401
constraintType = NAME_DIFF_TYPE;
402
else if (((IPAddressName)inputName).equals(this))
403
constraintType = NAME_MATCH;
404
else {
405
IPAddressName otherName = (IPAddressName)inputName;
406
byte[] otherAddress = otherName.address;
407
if (otherAddress.length == 4 && address.length == 4)
408
// Two host addresses
409
constraintType = NAME_SAME_TYPE;
410
else if ((otherAddress.length == 8 && address.length == 8) ||
411
(otherAddress.length == 32 && address.length == 32)) {
412
// Two subnet addresses
413
// See if one address fully encloses the other address
414
boolean otherSubsetOfThis = true;
415
boolean thisSubsetOfOther = true;
416
boolean thisEmpty = false;
417
boolean otherEmpty = false;
418
int maskOffset = address.length/2;
419
for (int i=0; i < maskOffset; i++) {
420
if ((byte)(address[i] & address[i+maskOffset]) != address[i])
421
thisEmpty=true;
422
if ((byte)(otherAddress[i] & otherAddress[i+maskOffset]) != otherAddress[i])
423
otherEmpty=true;
424
if (!(((byte)(address[i+maskOffset] & otherAddress[i+maskOffset]) == address[i+maskOffset]) &&
425
((byte)(address[i] & address[i+maskOffset]) == (byte)(otherAddress[i] & address[i+maskOffset])))) {
426
otherSubsetOfThis = false;
427
}
428
if (!(((byte)(otherAddress[i+maskOffset] & address[i+maskOffset]) == otherAddress[i+maskOffset]) &&
429
((byte)(otherAddress[i] & otherAddress[i+maskOffset]) == (byte)(address[i] & otherAddress[i+maskOffset])))) {
430
thisSubsetOfOther = false;
431
}
432
}
433
if (thisEmpty || otherEmpty) {
434
if (thisEmpty && otherEmpty)
435
constraintType = NAME_MATCH;
436
else if (thisEmpty)
437
constraintType = NAME_WIDENS;
438
else
439
constraintType = NAME_NARROWS;
440
} else if (otherSubsetOfThis)
441
constraintType = NAME_NARROWS;
442
else if (thisSubsetOfOther)
443
constraintType = NAME_WIDENS;
444
else
445
constraintType = NAME_SAME_TYPE;
446
} else if (otherAddress.length == 8 || otherAddress.length == 32) {
447
//Other is a subnet, this is a host address
448
int i = 0;
449
int maskOffset = otherAddress.length/2;
450
for (; i < maskOffset; i++) {
451
// Mask this address by other address mask and compare to other address
452
// If all match, then this address is in other address subnet
453
if ((address[i] & otherAddress[i+maskOffset]) != otherAddress[i])
454
break;
455
}
456
if (i == maskOffset)
457
constraintType = NAME_WIDENS;
458
else
459
constraintType = NAME_SAME_TYPE;
460
} else if (address.length == 8 || address.length == 32) {
461
//This is a subnet, other is a host address
462
int i = 0;
463
int maskOffset = address.length/2;
464
for (; i < maskOffset; i++) {
465
// Mask other address by this address mask and compare to this address
466
if ((otherAddress[i] & address[i+maskOffset]) != address[i])
467
break;
468
}
469
if (i == maskOffset)
470
constraintType = NAME_NARROWS;
471
else
472
constraintType = NAME_SAME_TYPE;
473
} else {
474
constraintType = NAME_SAME_TYPE;
475
}
476
}
477
return constraintType;
478
}
479
480
/**
481
* Return subtree depth of this name for purposes of determining
482
* NameConstraints minimum and maximum bounds and for calculating
483
* path lengths in name subtrees.
484
*
485
* @return distance of name from root
486
* @throws UnsupportedOperationException if not supported for this name type
487
*/
488
public int subtreeDepth() throws UnsupportedOperationException {
489
throw new UnsupportedOperationException
490
("subtreeDepth() not defined for IPAddressName");
491
}
492
}
493
494