Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java
41159 views
1
/*
2
* Copyright (c) 2000, 2021, 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;
33
34
import sun.security.krb5.internal.*;
35
import sun.security.util.*;
36
import java.net.*;
37
import java.util.Vector;
38
import java.util.Locale;
39
import java.io.IOException;
40
import java.math.BigInteger;
41
import java.util.Arrays;
42
import sun.security.krb5.internal.ccache.CCacheOutputStream;
43
import sun.security.krb5.internal.util.KerberosString;
44
45
46
/**
47
* Implements the ASN.1 PrincipalName type and its realm in a single class.
48
* <pre>{@code
49
* Realm ::= KerberosString
50
*
51
* PrincipalName ::= SEQUENCE {
52
* name-type [0] Int32,
53
* name-string [1] SEQUENCE OF KerberosString
54
* }
55
* }</pre>
56
* This class is immutable.
57
* @see Realm
58
*/
59
public class PrincipalName implements Cloneable {
60
61
//name types
62
63
/**
64
* Name type not known
65
*/
66
public static final int KRB_NT_UNKNOWN = 0;
67
68
/**
69
* Just the name of the principal as in DCE, or for users
70
*/
71
public static final int KRB_NT_PRINCIPAL = 1;
72
73
/**
74
* Service and other unique instance (krbtgt)
75
*/
76
public static final int KRB_NT_SRV_INST = 2;
77
78
/**
79
* Service with host name as instance (telnet, rcommands)
80
*/
81
public static final int KRB_NT_SRV_HST = 3;
82
83
/**
84
* Service with host as remaining components
85
*/
86
public static final int KRB_NT_SRV_XHST = 4;
87
88
/**
89
* Unique ID
90
*/
91
public static final int KRB_NT_UID = 5;
92
93
/**
94
* Enterprise name (alias)
95
*/
96
public static final int KRB_NT_ENTERPRISE = 10;
97
98
/**
99
* TGS Name
100
*/
101
public static final String TGS_DEFAULT_SRV_NAME = "krbtgt";
102
public static final int TGS_DEFAULT_NT = KRB_NT_SRV_INST;
103
104
public static final char NAME_COMPONENT_SEPARATOR = '/';
105
public static final char NAME_REALM_SEPARATOR = '@';
106
public static final char REALM_COMPONENT_SEPARATOR = '.';
107
108
public static final String NAME_COMPONENT_SEPARATOR_STR = "/";
109
public static final String NAME_REALM_SEPARATOR_STR = "@";
110
public static final String REALM_COMPONENT_SEPARATOR_STR = ".";
111
112
// Instance fields.
113
114
/**
115
* The name type, from PrincipalName's name-type field.
116
*/
117
private final int nameType;
118
119
/**
120
* The name strings, from PrincipalName's name-strings field. This field
121
* must be neither null nor empty. Each entry of it must also be neither
122
* null nor empty. Make sure to clone the field when it's passed in or out.
123
*/
124
private final String[] nameStrings;
125
126
/**
127
* The realm this principal belongs to.
128
*/
129
private final Realm nameRealm; // not null
130
131
132
/**
133
* When constructing a PrincipalName, whether the realm is included in
134
* the input, or deduced from default realm or domain-realm mapping.
135
*/
136
private final boolean realmDeduced;
137
138
// cached default salt, not used in clone
139
private transient String salt = null;
140
141
// There are 3 basic constructors. All other constructors must call them.
142
// All basic constructors must call validateNameStrings.
143
// 1. From name components
144
// 2. From name
145
// 3. From DER encoding
146
147
/**
148
* Creates a PrincipalName.
149
*/
150
public PrincipalName(int nameType, String[] nameStrings, Realm nameRealm) {
151
if (nameRealm == null) {
152
throw new IllegalArgumentException("Null realm not allowed");
153
}
154
validateNameStrings(nameStrings);
155
this.nameType = nameType;
156
this.nameStrings = nameStrings.clone();
157
this.nameRealm = nameRealm;
158
this.realmDeduced = false;
159
}
160
161
// Warning: called by NativeCreds.c
162
public PrincipalName(String[] nameParts, String realm) throws RealmException {
163
this(KRB_NT_UNKNOWN, nameParts, new Realm(realm));
164
}
165
166
// Validate a nameStrings argument
167
private static void validateNameStrings(String[] ns) {
168
if (ns == null) {
169
throw new IllegalArgumentException("Null nameStrings not allowed");
170
}
171
if (ns.length == 0) {
172
throw new IllegalArgumentException("Empty nameStrings not allowed");
173
}
174
for (String s: ns) {
175
if (s == null) {
176
throw new IllegalArgumentException("Null nameString not allowed");
177
}
178
if (s.isEmpty()) {
179
throw new IllegalArgumentException("Empty nameString not allowed");
180
}
181
}
182
}
183
184
public Object clone() {
185
try {
186
PrincipalName pName = (PrincipalName) super.clone();
187
UNSAFE.putReference(this, NAME_STRINGS_OFFSET, nameStrings.clone());
188
return pName;
189
} catch (CloneNotSupportedException ex) {
190
throw new AssertionError("Should never happen");
191
}
192
}
193
194
private static final long NAME_STRINGS_OFFSET;
195
private static final jdk.internal.misc.Unsafe UNSAFE;
196
static {
197
try {
198
jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
199
NAME_STRINGS_OFFSET = unsafe.objectFieldOffset(
200
PrincipalName.class.getDeclaredField("nameStrings"));
201
UNSAFE = unsafe;
202
} catch (ReflectiveOperationException e) {
203
throw new Error(e);
204
}
205
}
206
207
@Override
208
public boolean equals(Object o) {
209
if (this == o) {
210
return true;
211
}
212
if (o instanceof PrincipalName) {
213
PrincipalName other = (PrincipalName)o;
214
return nameRealm.equals(other.nameRealm) &&
215
Arrays.equals(nameStrings, other.nameStrings);
216
}
217
return false;
218
}
219
220
/**
221
* Returns the ASN.1 encoding of the
222
* <pre>{@code
223
* PrincipalName ::= SEQUENCE {
224
* name-type [0] Int32,
225
* name-string [1] SEQUENCE OF KerberosString
226
* }
227
*
228
* KerberosString ::= GeneralString (IA5String)
229
* }</pre>
230
*
231
* <p>
232
* This definition reflects the Network Working Group RFC 4120
233
* specification available at
234
* <a href="http://www.ietf.org/rfc/rfc4120.txt">
235
* http://www.ietf.org/rfc/rfc4120.txt</a>.
236
*
237
* @param encoding DER-encoded PrincipalName (without Realm)
238
* @param realm the realm for this name
239
* @exception Asn1Exception if an error occurs while decoding
240
* an ASN1 encoded data.
241
* @exception Asn1Exception if there is an ASN1 encoding error
242
* @exception IOException if an I/O error occurs
243
* @exception IllegalArgumentException if encoding is null
244
* reading encoded data.
245
*/
246
public PrincipalName(DerValue encoding, Realm realm)
247
throws Asn1Exception, IOException {
248
if (realm == null) {
249
throw new IllegalArgumentException("Null realm not allowed");
250
}
251
realmDeduced = false;
252
nameRealm = realm;
253
DerValue der;
254
if (encoding == null) {
255
throw new IllegalArgumentException("Null encoding not allowed");
256
}
257
if (encoding.getTag() != DerValue.tag_Sequence) {
258
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
259
}
260
der = encoding.getData().getDerValue();
261
if ((der.getTag() & 0x1F) == 0x00) {
262
BigInteger bint = der.getData().getBigInteger();
263
nameType = bint.intValue();
264
} else {
265
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
266
}
267
der = encoding.getData().getDerValue();
268
if ((der.getTag() & 0x01F) == 0x01) {
269
DerValue subDer = der.getData().getDerValue();
270
if (subDer.getTag() != DerValue.tag_SequenceOf) {
271
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
272
}
273
Vector<String> v = new Vector<>();
274
DerValue subSubDer;
275
while(subDer.getData().available() > 0) {
276
subSubDer = subDer.getData().getDerValue();
277
String namePart = new KerberosString(subSubDer).toString();
278
v.addElement(namePart);
279
}
280
nameStrings = new String[v.size()];
281
v.copyInto(nameStrings);
282
validateNameStrings(nameStrings);
283
} else {
284
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
285
}
286
}
287
288
/**
289
* Parse (unmarshal) a <code>PrincipalName</code> from a DER
290
* input stream. This form
291
* parsing might be used when expanding a value which is part of
292
* a constructed sequence and uses explicitly tagged type.
293
*
294
* @exception Asn1Exception on error.
295
* @param data the Der input stream value, which contains one or
296
* more marshaled value.
297
* @param explicitTag tag number.
298
* @param optional indicate if this data field is optional
299
* @param realm the realm for the name
300
* @return an instance of <code>PrincipalName</code>, or null if the
301
* field is optional and missing.
302
*/
303
public static PrincipalName parse(DerInputStream data,
304
byte explicitTag, boolean
305
optional,
306
Realm realm)
307
throws Asn1Exception, IOException, RealmException {
308
309
if ((optional) && (((byte)data.peekByte() & (byte)0x1F) !=
310
explicitTag))
311
return null;
312
DerValue der = data.getDerValue();
313
if (explicitTag != (der.getTag() & (byte)0x1F)) {
314
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
315
} else {
316
DerValue subDer = der.getData().getDerValue();
317
if (realm == null) {
318
realm = Realm.getDefault();
319
}
320
return new PrincipalName(subDer, realm);
321
}
322
}
323
324
325
// XXX Error checkin consistent with MIT krb5_parse_name
326
// Code repetition, realm parsed again by class Realm
327
private static String[] parseName(String name) {
328
329
Vector<String> tempStrings = new Vector<>();
330
String temp = name;
331
int i = 0;
332
int componentStart = 0;
333
String component;
334
335
while (i < temp.length()) {
336
if (temp.charAt(i) == NAME_COMPONENT_SEPARATOR) {
337
/*
338
* If this separator is escaped then don't treat it
339
* as a separator
340
*/
341
if (i > 0 && temp.charAt(i - 1) == '\\') {
342
temp = temp.substring(0, i - 1) +
343
temp.substring(i, temp.length());
344
continue;
345
}
346
else {
347
if (componentStart <= i) {
348
component = temp.substring(componentStart, i);
349
tempStrings.addElement(component);
350
}
351
componentStart = i + 1;
352
}
353
} else {
354
if (temp.charAt(i) == NAME_REALM_SEPARATOR) {
355
/*
356
* If this separator is escaped then don't treat it
357
* as a separator
358
*/
359
if (i > 0 && temp.charAt(i - 1) == '\\') {
360
temp = temp.substring(0, i - 1) +
361
temp.substring(i, temp.length());
362
continue;
363
} else {
364
if (componentStart < i) {
365
component = temp.substring(componentStart, i);
366
tempStrings.addElement(component);
367
}
368
componentStart = i + 1;
369
break;
370
}
371
}
372
}
373
i++;
374
}
375
376
if (i == temp.length()) {
377
component = temp.substring(componentStart, i);
378
tempStrings.addElement(component);
379
}
380
381
String[] result = new String[tempStrings.size()];
382
tempStrings.copyInto(result);
383
return result;
384
}
385
386
/**
387
* Constructs a PrincipalName from a string.
388
* @param name the name
389
* @param type the type
390
* @param realm the realm, null if not known. Note that when realm is not
391
* null, it will be always used even if there is a realm part in name. When
392
* realm is null, will read realm part from name, or try to map a realm
393
* (for KRB_NT_SRV_HST), or use the default realm, or fail
394
* @throws RealmException
395
*/
396
public PrincipalName(String name, int type, String realm)
397
throws RealmException {
398
if (name == null) {
399
throw new IllegalArgumentException("Null name not allowed");
400
}
401
String[] nameParts = parseName(name);
402
validateNameStrings(nameParts);
403
if (realm == null) {
404
realm = Realm.parseRealmAtSeparator(name);
405
}
406
407
// No realm info from parameter and string, must deduce later
408
realmDeduced = realm == null;
409
410
switch (type) {
411
case KRB_NT_SRV_HST:
412
if (nameParts.length >= 2) {
413
String hostName = nameParts[1];
414
Boolean option;
415
try {
416
// If true, try canonicalizing and accept it if it starts
417
// with the short name. Otherwise, never. Default true.
418
option = Config.getInstance().getBooleanObject(
419
"libdefaults", "dns_canonicalize_hostname");
420
} catch (KrbException e) {
421
option = null;
422
}
423
if (option != Boolean.FALSE) {
424
try {
425
// RFC4120 does not recommend canonicalizing a hostname.
426
// However, for compatibility reason, we will try
427
// canonicalizing it and see if the output looks better.
428
429
String canonicalized = (InetAddress.getByName(hostName)).
430
getCanonicalHostName();
431
432
// Looks if canonicalized is a longer format of hostName,
433
// we accept cases like
434
// bunny -> bunny.rabbit.hole
435
if (canonicalized.toLowerCase(Locale.ENGLISH).startsWith(
436
hostName.toLowerCase(Locale.ENGLISH) + ".")) {
437
hostName = canonicalized;
438
}
439
} catch (UnknownHostException | SecurityException e) {
440
// not canonicalized or no permission to do so, use old
441
}
442
if (hostName.endsWith(".")) {
443
hostName = hostName.substring(0, hostName.length() - 1);
444
}
445
}
446
nameParts[1] = hostName.toLowerCase(Locale.ENGLISH);
447
}
448
nameStrings = nameParts;
449
nameType = type;
450
451
if (realm != null) {
452
nameRealm = new Realm(realm);
453
} else {
454
// We will try to get realm name from the mapping in
455
// the configuration. If it is not specified
456
// we will use the default realm. This nametype does
457
// not allow a realm to be specified. The name string must of
458
// the form service@host and this is internally changed into
459
// service/host by Kerberos
460
String mapRealm = mapHostToRealm(nameParts[1]);
461
if (mapRealm != null) {
462
nameRealm = new Realm(mapRealm);
463
} else {
464
nameRealm = Realm.getDefault();
465
}
466
}
467
break;
468
case KRB_NT_UNKNOWN:
469
case KRB_NT_PRINCIPAL:
470
case KRB_NT_SRV_INST:
471
case KRB_NT_SRV_XHST:
472
case KRB_NT_UID:
473
case KRB_NT_ENTERPRISE:
474
nameStrings = nameParts;
475
nameType = type;
476
if (realm != null) {
477
nameRealm = new Realm(realm);
478
} else {
479
nameRealm = Realm.getDefault();
480
}
481
break;
482
default:
483
throw new IllegalArgumentException("Illegal name type");
484
}
485
}
486
487
// Warning: called by nativeccache.c
488
public PrincipalName(String name, int type) throws RealmException {
489
this(name, type, (String)null);
490
}
491
492
public PrincipalName(String name) throws RealmException {
493
this(name, KRB_NT_UNKNOWN);
494
}
495
496
public PrincipalName(String name, String realm) throws RealmException {
497
this(name, KRB_NT_UNKNOWN, realm);
498
}
499
500
public static PrincipalName tgsService(String r1, String r2)
501
throws KrbException {
502
return new PrincipalName(PrincipalName.KRB_NT_SRV_INST,
503
new String[] {PrincipalName.TGS_DEFAULT_SRV_NAME, r1},
504
new Realm(r2));
505
}
506
507
public String getRealmAsString() {
508
return getRealmString();
509
}
510
511
public String getPrincipalNameAsString() {
512
StringBuilder temp = new StringBuilder(nameStrings[0]);
513
for (int i = 1; i < nameStrings.length; i++)
514
temp.append(nameStrings[i]);
515
return temp.toString();
516
}
517
518
public int hashCode() {
519
return toString().hashCode();
520
}
521
522
public String getName() {
523
return toString();
524
}
525
526
public int getNameType() {
527
return nameType;
528
}
529
530
public String[] getNameStrings() {
531
return nameStrings.clone();
532
}
533
534
public byte[][] toByteArray() {
535
byte[][] result = new byte[nameStrings.length][];
536
for (int i = 0; i < nameStrings.length; i++) {
537
result[i] = nameStrings[i].getBytes();
538
}
539
return result;
540
}
541
542
public String getRealmString() {
543
return nameRealm.toString();
544
}
545
546
public Realm getRealm() {
547
return nameRealm;
548
}
549
550
public String getSalt() {
551
if (salt == null) {
552
StringBuilder salt = new StringBuilder();
553
salt.append(nameRealm.toString());
554
for (int i = 0; i < nameStrings.length; i++) {
555
salt.append(nameStrings[i]);
556
}
557
return salt.toString();
558
}
559
return salt;
560
}
561
562
public String toString() {
563
StringBuilder str = new StringBuilder();
564
for (int i = 0; i < nameStrings.length; i++) {
565
if (i > 0)
566
str.append("/");
567
String n = nameStrings[i];
568
n = n.replace("@", "\\@");
569
str.append(n);
570
}
571
str.append("@");
572
str.append(nameRealm.toString());
573
return str.toString();
574
}
575
576
public String getNameString() {
577
StringBuilder str = new StringBuilder();
578
for (int i = 0; i < nameStrings.length; i++) {
579
if (i > 0)
580
str.append("/");
581
str.append(nameStrings[i]);
582
}
583
return str.toString();
584
}
585
586
/**
587
* Encodes a <code>PrincipalName</code> object. Note that only the type and
588
* names are encoded. To encode the realm, call getRealm().asn1Encode().
589
* @return the byte array of the encoded PrncipalName object.
590
* @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
591
* @exception IOException if an I/O error occurs while reading encoded data.
592
*
593
*/
594
public byte[] asn1Encode() throws Asn1Exception, IOException {
595
DerOutputStream bytes = new DerOutputStream();
596
DerOutputStream temp = new DerOutputStream();
597
BigInteger bint = BigInteger.valueOf(this.nameType);
598
temp.putInteger(bint);
599
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp);
600
temp = new DerOutputStream();
601
DerValue[] der = new DerValue[nameStrings.length];
602
for (int i = 0; i < nameStrings.length; i++) {
603
der[i] = new KerberosString(nameStrings[i]).toDerValue();
604
}
605
temp.putSequence(der);
606
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), temp);
607
temp = new DerOutputStream();
608
temp.write(DerValue.tag_Sequence, bytes);
609
return temp.toByteArray();
610
}
611
612
613
/**
614
* Checks if two <code>PrincipalName</code> objects have identical values in their corresponding data fields.
615
*
616
* @param pname the other <code>PrincipalName</code> object.
617
* @return true if two have identical values, otherwise, return false.
618
*/
619
// It is used in <code>sun.security.krb5.internal.ccache</code> package.
620
public boolean match(PrincipalName pname) {
621
boolean matched = true;
622
//name type is just a hint, no two names can be the same ignoring name type.
623
// if (this.nameType != pname.nameType) {
624
// matched = false;
625
// }
626
if ((this.nameRealm != null) && (pname.nameRealm != null)) {
627
if (!(this.nameRealm.toString().equalsIgnoreCase(pname.nameRealm.toString()))) {
628
matched = false;
629
}
630
}
631
if (this.nameStrings.length != pname.nameStrings.length) {
632
matched = false;
633
} else {
634
for (int i = 0; i < this.nameStrings.length; i++) {
635
if (!(this.nameStrings[i].equalsIgnoreCase(pname.nameStrings[i]))) {
636
matched = false;
637
}
638
}
639
}
640
return matched;
641
}
642
643
/**
644
* Writes data field values of <code>PrincipalName</code> in FCC format to an output stream.
645
*
646
* @param cos a <code>CCacheOutputStream</code> for writing data.
647
* @exception IOException if an I/O exception occurs.
648
* @see sun.security.krb5.internal.ccache.CCacheOutputStream
649
*/
650
public void writePrincipal(CCacheOutputStream cos) throws IOException {
651
cos.write32(nameType);
652
cos.write32(nameStrings.length);
653
byte[] realmBytes = null;
654
realmBytes = nameRealm.toString().getBytes();
655
cos.write32(realmBytes.length);
656
cos.write(realmBytes, 0, realmBytes.length);
657
byte[] bytes = null;
658
for (int i = 0; i < nameStrings.length; i++) {
659
bytes = nameStrings[i].getBytes();
660
cos.write32(bytes.length);
661
cos.write(bytes, 0, bytes.length);
662
}
663
}
664
665
/**
666
* Returns the instance component of a name.
667
* In a multi-component name such as a KRB_NT_SRV_INST
668
* name, the second component is returned.
669
* Null is returned if there are not two or more
670
* components in the name.
671
*
672
* @return instance component of a multi-component name.
673
*/
674
public String getInstanceComponent()
675
{
676
if (nameStrings != null && nameStrings.length >= 2)
677
{
678
return new String(nameStrings[1]);
679
}
680
681
return null;
682
}
683
684
static String mapHostToRealm(String name) {
685
String result = null;
686
try {
687
String subname = null;
688
Config c = Config.getInstance();
689
if ((result = c.get("domain_realm", name)) != null)
690
return result;
691
else {
692
for (int i = 1; i < name.length(); i++) {
693
if ((name.charAt(i) == '.') && (i != name.length() - 1)) { //mapping could be .ibm.com = AUSTIN.IBM.COM
694
subname = name.substring(i);
695
result = c.get("domain_realm", subname);
696
if (result != null) {
697
break;
698
}
699
else {
700
subname = name.substring(i + 1); //or mapping could be ibm.com = AUSTIN.IBM.COM
701
result = c.get("domain_realm", subname);
702
if (result != null) {
703
break;
704
}
705
}
706
}
707
}
708
}
709
} catch (KrbException e) {
710
}
711
return result;
712
}
713
714
public boolean isRealmDeduced() {
715
return realmDeduced;
716
}
717
}
718
719