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/jgss/GSSNameImpl.java
41159 views
1
/*
2
* Copyright (c) 2000, 2020, 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.jgss;
27
28
import org.ietf.jgss.*;
29
import sun.security.jgss.spi.*;
30
import java.util.Set;
31
import java.util.HashMap;
32
import java.util.HashSet;
33
import java.util.Arrays;
34
import java.io.IOException;
35
import sun.security.util.ObjectIdentifier;
36
import sun.security.util.DerInputStream;
37
import sun.security.util.DerOutputStream;
38
39
import static java.nio.charset.StandardCharsets.UTF_8;
40
41
/**
42
* This is the implementation class for GSSName. Conceptually the
43
* GSSName is a container with mechanism specific name elements. Each
44
* name element is a representation of how that particular mechanism
45
* would canonicalize this principal.
46
*
47
* Generally a GSSName is created by an application when it supplies
48
* a sequence of bytes and a nametype that helps each mechanism
49
* decide how to interpret those bytes.
50
*
51
* It is not necessary to create name elements for each available
52
* mechanism at the time the application creates the GSSName. This
53
* implementation does this lazily, as and when name elements for
54
* mechanisms are required to be handed out. (Generally, other GSS
55
* classes like GSSContext and GSSCredential request specific
56
* elements depending on the mechanisms that they are dealing with.)
57
* Assume that getting a mechanism to parse the applciation specified
58
* bytes is an expensive call.
59
*
60
* When a GSSName is canonicalized wrt some mechanism, it is supposed
61
* to discard all elements of other mechanisms and retain only the
62
* element for this mechanism. In GSS terminology this is called a
63
* Mechanism Name or MN. This implementation tries to retain the
64
* application provided bytes and name type just in case the MN is
65
* asked to produce an element for a mechanism that is different.
66
*
67
* When a GSSName is to be exported, the name element for the desired
68
* mechanism is converted to a byte representation and written
69
* out. It might happen that a name element for that mechanism cannot
70
* be obtained. This happens when the mechanism is just not supported
71
* in this GSS-API or when the mechanism is supported but bytes
72
* corresponding to the nametypes that it understands are not
73
* available in this GSSName.
74
*
75
* This class is safe for sharing. Each retrieval of a name element
76
* from getElement() might potentially add a new element to the
77
* hashmap of elements, but getElement() is synchronized.
78
*
79
* @author Mayank Upadhyay
80
* @since 1.4
81
*/
82
83
public class GSSNameImpl implements GSSName {
84
85
/**
86
* The old Oid used in RFC 2853. Now supported as
87
* input parameters in:
88
*
89
* 1. The four overloaded GSSManager.createName(*) methods
90
* 2. GSSManager.getMechsForName(Oid)
91
*
92
* Note that even if a GSSName is created with this old Oid,
93
* its internal name type and getStringNameType() output are
94
* always the new value.
95
*/
96
static final Oid oldHostbasedServiceName;
97
98
static {
99
Oid tmp = null;
100
try {
101
tmp = new Oid("1.3.6.1.5.6.2");
102
} catch (Exception e) {
103
// should never happen
104
}
105
oldHostbasedServiceName = tmp;
106
}
107
108
private GSSManagerImpl gssManager = null;
109
110
/*
111
* Store whatever the application passed in. We will use this to
112
* get individual mechanisms to create name elements as and when
113
* needed.
114
* Store both the String and the byte[]. Leave I18N to the
115
* mechanism by allowing it to extract bytes from the String!
116
*/
117
118
private String appNameStr = null;
119
private byte[] appNameBytes = null;
120
private Oid appNameType = null;
121
122
/*
123
* When we figure out what the printable name would be, we store
124
* both the name and its type.
125
*/
126
127
private String printableName = null;
128
private Oid printableNameType = null;
129
130
private HashMap<Oid, GSSNameSpi> elements = null;
131
private GSSNameSpi mechElement = null;
132
133
static GSSNameImpl wrapElement(GSSManagerImpl gssManager,
134
GSSNameSpi mechElement) throws GSSException {
135
return (mechElement == null ?
136
null : new GSSNameImpl(gssManager, mechElement));
137
}
138
139
GSSNameImpl(GSSManagerImpl gssManager, GSSNameSpi mechElement) {
140
this.gssManager = gssManager;
141
appNameStr = printableName = mechElement.toString();
142
appNameType = printableNameType = mechElement.getStringNameType();
143
this.mechElement = mechElement;
144
elements = new HashMap<Oid, GSSNameSpi>(1);
145
elements.put(mechElement.getMechanism(), this.mechElement);
146
}
147
148
GSSNameImpl(GSSManagerImpl gssManager,
149
Object appName,
150
Oid appNameType)
151
throws GSSException {
152
this(gssManager, appName, appNameType, null);
153
}
154
155
GSSNameImpl(GSSManagerImpl gssManager,
156
Object appName,
157
Oid appNameType,
158
Oid mech)
159
throws GSSException {
160
161
if (oldHostbasedServiceName.equals(appNameType)) {
162
appNameType = GSSName.NT_HOSTBASED_SERVICE;
163
}
164
if (appName == null)
165
throw new GSSExceptionImpl(GSSException.BAD_NAME,
166
"Cannot import null name");
167
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
168
if (NT_EXPORT_NAME.equals(appNameType)) {
169
importName(gssManager, appName);
170
} else {
171
init(gssManager, appName, appNameType, mech);
172
}
173
}
174
175
private void init(GSSManagerImpl gssManager,
176
Object appName, Oid appNameType,
177
Oid mech)
178
throws GSSException {
179
180
this.gssManager = gssManager;
181
this.elements =
182
new HashMap<Oid, GSSNameSpi>(gssManager.getMechs().length);
183
184
if (appName instanceof String) {
185
this.appNameStr = (String) appName;
186
/*
187
* If appNameType is null, then the nametype for this printable
188
* string is determined only by interrogating the
189
* mechanism. Thus, defer the setting of printableName and
190
* printableNameType till later.
191
*/
192
if (appNameType != null) {
193
printableName = appNameStr;
194
printableNameType = appNameType;
195
}
196
} else {
197
this.appNameBytes = (byte[]) appName;
198
}
199
200
this.appNameType = appNameType;
201
202
mechElement = getElement(mech);
203
204
/*
205
* printableName will be null if appName was in a byte[] or if
206
* appName was in a String but appNameType was null.
207
*/
208
if (printableName == null) {
209
printableName = mechElement.toString();
210
printableNameType = mechElement.getStringNameType();
211
}
212
213
/*
214
* At this point the GSSNameImpl has the following set:
215
* appNameStr or appNameBytes
216
* appNameType (could be null)
217
* printableName
218
* printableNameType
219
* mechElement (which also exists in the hashmap of elements)
220
*/
221
}
222
223
private void importName(GSSManagerImpl gssManager,
224
Object appName)
225
throws GSSException {
226
227
int pos = 0;
228
byte[] bytes = null;
229
230
if (appName instanceof String) {
231
bytes = ((String) appName).getBytes(UTF_8);
232
} else {
233
bytes = (byte[]) appName;
234
}
235
236
if ((bytes[pos++] != 0x04) ||
237
(bytes[pos++] != 0x01))
238
throw new GSSExceptionImpl(GSSException.BAD_NAME,
239
"Exported name token id is corrupted!");
240
241
int oidLen = (((0xFF & bytes[pos++]) << 8) |
242
(0xFF & bytes[pos++]));
243
ObjectIdentifier temp = null;
244
try {
245
DerInputStream din = new DerInputStream(bytes, pos,
246
oidLen);
247
temp = new ObjectIdentifier(din);
248
} catch (IOException e) {
249
throw new GSSExceptionImpl(GSSException.BAD_NAME,
250
"Exported name Object identifier is corrupted!");
251
}
252
Oid oid = new Oid(temp.toString());
253
pos += oidLen;
254
int mechPortionLen = (((0xFF & bytes[pos++]) << 24) |
255
((0xFF & bytes[pos++]) << 16) |
256
((0xFF & bytes[pos++]) << 8) |
257
(0xFF & bytes[pos++]));
258
259
if (mechPortionLen < 0 || pos > bytes.length - mechPortionLen) {
260
throw new GSSExceptionImpl(GSSException.BAD_NAME,
261
"Exported name mech name is corrupted!");
262
}
263
byte[] mechPortion = new byte[mechPortionLen];
264
System.arraycopy(bytes, pos, mechPortion, 0, mechPortionLen);
265
266
init(gssManager, mechPortion, NT_EXPORT_NAME, oid);
267
}
268
269
public GSSName canonicalize(Oid mech) throws GSSException {
270
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
271
272
return wrapElement(gssManager, getElement(mech));
273
}
274
275
/**
276
* This method may return false negatives. But if it says two
277
* names are equals, then there is some mechanism that
278
* authenticates them as the same principal.
279
*/
280
public boolean equals(GSSName other) throws GSSException {
281
282
if (this.isAnonymous() || other.isAnonymous())
283
return false;
284
285
if (other == this)
286
return true;
287
288
if (! (other instanceof GSSNameImpl))
289
return equals(gssManager.createName(other.toString(),
290
other.getStringNameType()));
291
292
/*
293
* XXX Do a comparison of the appNameStr/appNameBytes if
294
* available. If that fails, then proceed with this test.
295
*/
296
297
GSSNameImpl that = (GSSNameImpl) other;
298
299
GSSNameSpi myElement = this.mechElement;
300
GSSNameSpi element = that.mechElement;
301
302
/*
303
* XXX If they are not of the same mechanism type, convert both to
304
* Kerberos since it is guaranteed to be present.
305
*/
306
if ((myElement == null) && (element != null)) {
307
myElement = this.getElement(element.getMechanism());
308
} else if ((myElement != null) && (element == null)) {
309
element = that.getElement(myElement.getMechanism());
310
}
311
312
if (myElement != null && element != null) {
313
return myElement.equals(element);
314
}
315
316
if ((this.appNameType != null) &&
317
(that.appNameType != null)) {
318
if (!this.appNameType.equals(that.appNameType)) {
319
return false;
320
}
321
byte[] myBytes =
322
(this.appNameStr != null ?
323
this.appNameStr.getBytes(UTF_8) :
324
this.appNameBytes);
325
byte[] bytes =
326
(that.appNameStr != null ?
327
that.appNameStr.getBytes(UTF_8) :
328
that.appNameBytes);
329
return Arrays.equals(myBytes, bytes);
330
}
331
332
return false;
333
334
}
335
336
/**
337
* Returns a hashcode value for this GSSName.
338
*
339
* @return a hashCode value
340
*/
341
public int hashCode() {
342
/*
343
* XXX
344
* In order to get this to work reliably and properly(!), obtain a
345
* Kerberos name element for the name and then call hashCode on its
346
* string representation. But this cannot be done if the nametype
347
* is not one of those supported by the Kerberos provider and hence
348
* this name cannot be imported by Kerberos. In that case return a
349
* constant value!
350
*/
351
352
return 1;
353
}
354
355
public boolean equals(Object another) {
356
357
try {
358
// XXX This can lead to an infinite loop. Extract info
359
// and create a GSSNameImpl with it.
360
361
if (another instanceof GSSName)
362
return equals((GSSName) another);
363
} catch (GSSException e) {
364
// Squelch it and return false
365
}
366
367
return false;
368
}
369
370
/**
371
* Returns a flat name representation for this object. The name
372
* format is defined in RFC 2743:
373
*<pre>
374
* Length Name Description
375
* 2 TOK_ID Token Identifier
376
* For exported name objects, this
377
* must be hex 04 01.
378
* 2 MECH_OID_LEN Length of the Mechanism OID
379
* MECH_OID_LEN MECH_OID Mechanism OID, in DER
380
* 4 NAME_LEN Length of name
381
* NAME_LEN NAME Exported name; format defined in
382
* applicable mechanism draft.
383
*</pre>
384
*
385
* Note that it is not required to canonicalize a name before
386
* calling export(). i.e., the name need not be an MN. If it is
387
* not an MN, an implementation defined algorithm can be used for
388
* choosing the mechanism which should export this name.
389
*
390
* @return the flat name representation for this object
391
* @exception GSSException with major codes NAME_NOT_MN, BAD_NAME,
392
* BAD_NAME, FAILURE.
393
*/
394
public byte[] export() throws GSSException {
395
396
if (mechElement == null) {
397
/* Use default mech */
398
mechElement = getElement(ProviderList.DEFAULT_MECH_OID);
399
}
400
401
byte[] mechPortion = mechElement.export();
402
byte[] oidBytes = null;
403
ObjectIdentifier oid = null;
404
405
try {
406
oid = ObjectIdentifier.of
407
(mechElement.getMechanism().toString());
408
} catch (IOException e) {
409
throw new GSSExceptionImpl(GSSException.FAILURE,
410
"Invalid OID String ");
411
}
412
DerOutputStream dout = new DerOutputStream();
413
try {
414
dout.putOID(oid);
415
} catch (IOException e) {
416
throw new GSSExceptionImpl(GSSException.FAILURE,
417
"Could not ASN.1 Encode "
418
+ oid.toString());
419
}
420
oidBytes = dout.toByteArray();
421
422
byte[] retVal = new byte[2
423
+ 2 + oidBytes.length
424
+ 4 + mechPortion.length];
425
int pos = 0;
426
retVal[pos++] = 0x04;
427
retVal[pos++] = 0x01;
428
retVal[pos++] = (byte) (oidBytes.length>>>8);
429
retVal[pos++] = (byte) oidBytes.length;
430
System.arraycopy(oidBytes, 0, retVal, pos, oidBytes.length);
431
pos += oidBytes.length;
432
retVal[pos++] = (byte) (mechPortion.length>>>24);
433
retVal[pos++] = (byte) (mechPortion.length>>>16);
434
retVal[pos++] = (byte) (mechPortion.length>>>8);
435
retVal[pos++] = (byte) mechPortion.length;
436
System.arraycopy(mechPortion, 0, retVal, pos, mechPortion.length);
437
return retVal;
438
}
439
440
public String toString() {
441
return printableName;
442
443
}
444
445
public Oid getStringNameType() throws GSSException {
446
return printableNameType;
447
}
448
449
public boolean isAnonymous() {
450
if (printableNameType == null) {
451
return false;
452
} else {
453
return GSSName.NT_ANONYMOUS.equals(printableNameType);
454
}
455
}
456
457
public boolean isMN() {
458
return true; // Since always canonicalized for some mech
459
}
460
461
public synchronized GSSNameSpi getElement(Oid mechOid)
462
throws GSSException {
463
464
GSSNameSpi retVal = elements.get(mechOid);
465
466
if (retVal == null) {
467
if (appNameStr != null) {
468
retVal = gssManager.getNameElement
469
(appNameStr, appNameType, mechOid);
470
} else {
471
retVal = gssManager.getNameElement
472
(appNameBytes, appNameType, mechOid);
473
}
474
elements.put(mechOid, retVal);
475
}
476
return retVal;
477
}
478
479
Set<GSSNameSpi> getElements() {
480
return new HashSet<GSSNameSpi>(elements.values());
481
}
482
483
private static String getNameTypeStr(Oid nameTypeOid) {
484
485
if (nameTypeOid == null)
486
return "(NT is null)";
487
488
if (nameTypeOid.equals(NT_USER_NAME))
489
return "NT_USER_NAME";
490
if (nameTypeOid.equals(NT_HOSTBASED_SERVICE))
491
return "NT_HOSTBASED_SERVICE";
492
if (nameTypeOid.equals(NT_EXPORT_NAME))
493
return "NT_EXPORT_NAME";
494
if (nameTypeOid.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL))
495
return "NT_GSS_KRB5_PRINCIPAL";
496
else
497
return "Unknown";
498
}
499
}
500
501