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/krb5/Krb5Context.java
41161 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
package sun.security.jgss.krb5;
27
28
import org.ietf.jgss.*;
29
import sun.security.util.HexDumpEncoder;
30
import sun.security.jgss.GSSUtil;
31
import sun.security.jgss.GSSCaller;
32
import sun.security.jgss.spi.*;
33
import sun.security.jgss.TokenTracker;
34
import sun.security.krb5.*;
35
import java.io.InputStream;
36
import java.io.OutputStream;
37
import java.io.IOException;
38
import java.security.Provider;
39
import java.security.AccessController;
40
import java.security.AccessControlContext;
41
import java.security.Key;
42
import java.security.PrivilegedActionException;
43
import java.security.PrivilegedExceptionAction;
44
import javax.security.auth.Subject;
45
import javax.security.auth.kerberos.ServicePermission;
46
import javax.security.auth.kerberos.KerberosCredMessage;
47
import javax.security.auth.kerberos.KerberosPrincipal;
48
import javax.security.auth.kerberos.KerberosTicket;
49
import sun.security.krb5.internal.Ticket;
50
import sun.security.krb5.internal.AuthorizationData;
51
52
/**
53
* Implements the mechanism specific context class for the Kerberos v5
54
* GSS-API mechanism.
55
*
56
* @author Mayank Upadhyay
57
* @author Ram Marti
58
* @since 1.4
59
*/
60
class Krb5Context implements GSSContextSpi {
61
62
/*
63
* The different states that this context can be in.
64
*/
65
66
private static final int STATE_NEW = 1;
67
private static final int STATE_IN_PROCESS = 2;
68
private static final int STATE_DONE = 3;
69
private static final int STATE_DELETED = 4;
70
71
private int state = STATE_NEW;
72
73
public static final int SESSION_KEY = 0;
74
public static final int INITIATOR_SUBKEY = 1;
75
public static final int ACCEPTOR_SUBKEY = 2;
76
77
/*
78
* Optional features that the application can set and their default
79
* values.
80
*/
81
82
private boolean credDelegState = false; // now only useful at client
83
private boolean mutualAuthState = true;
84
private boolean replayDetState = true;
85
private boolean sequenceDetState = true;
86
private boolean confState = true;
87
private boolean integState = true;
88
private boolean delegPolicyState = false;
89
90
private boolean isConstrainedDelegationTried = false;
91
92
private int mySeqNumber;
93
private int peerSeqNumber;
94
private int keySrc;
95
private TokenTracker peerTokenTracker;
96
97
private CipherHelper cipherHelper = null;
98
99
/*
100
* Separate locks for the sequence numbers allow the application to
101
* receive tokens at the same time that it is sending tokens. Note
102
* that the application must synchronize the generation and
103
* transmission of tokens such that tokens are processed in the same
104
* order that they are generated. This is important when sequence
105
* checking of per-message tokens is enabled.
106
*/
107
108
private Object mySeqNumberLock = new Object();
109
private Object peerSeqNumberLock = new Object();
110
111
private EncryptionKey key;
112
private Krb5NameElement myName;
113
private Krb5NameElement peerName;
114
private int lifetime;
115
private boolean initiator;
116
private ChannelBinding channelBinding;
117
118
private Krb5CredElement myCred;
119
private Krb5CredElement delegatedCred; // Set only on acceptor side
120
121
// XXX See if the required info from these can be extracted and
122
// stored elsewhere
123
private Credentials tgt;
124
private Credentials serviceCreds;
125
private KrbApReq apReq;
126
Ticket serviceTicket;
127
private final GSSCaller caller;
128
private static final boolean DEBUG = Krb5Util.DEBUG;
129
130
/**
131
* Constructor for Krb5Context to be called on the context initiator's
132
* side.
133
*/
134
Krb5Context(GSSCaller caller, Krb5NameElement peerName, Krb5CredElement myCred,
135
int lifetime)
136
throws GSSException {
137
138
if (peerName == null)
139
throw new IllegalArgumentException("Cannot have null peer name");
140
141
this.caller = caller;
142
this.peerName = peerName;
143
this.myCred = myCred;
144
this.lifetime = lifetime;
145
this.initiator = true;
146
}
147
148
/**
149
* Constructor for Krb5Context to be called on the context acceptor's
150
* side.
151
*/
152
Krb5Context(GSSCaller caller, Krb5CredElement myCred)
153
throws GSSException {
154
this.caller = caller;
155
this.myCred = myCred;
156
this.initiator = false;
157
}
158
159
/**
160
* Constructor for Krb5Context to import a previously exported context.
161
*/
162
public Krb5Context(GSSCaller caller, byte[] interProcessToken)
163
throws GSSException {
164
throw new GSSException(GSSException.UNAVAILABLE,
165
-1, "GSS Import Context not available");
166
}
167
168
/**
169
* Method to determine if the context can be exported and then
170
* re-imported.
171
*/
172
public final boolean isTransferable() throws GSSException {
173
return false;
174
}
175
176
/**
177
* The lifetime remaining for this context.
178
*/
179
public final int getLifetime() {
180
// XXX Return service ticket lifetime
181
return GSSContext.INDEFINITE_LIFETIME;
182
}
183
184
/*
185
* Methods that may be invoked by the GSS framework in response
186
* to an application request for setting/getting these
187
* properties.
188
*
189
* These can only be called on the initiator side.
190
*
191
* Notice that an application can only request these
192
* properties. The mechanism may or may not support them. The
193
* application must make getXXX calls after context establishment
194
* to see if the mechanism implementations on both sides support
195
* these features. requestAnonymity is an exception where the
196
* application will want to call getAnonymityState prior to sending any
197
* GSS token during context establishment.
198
*
199
* Also note that the requests can only be placed before context
200
* establishment starts. i.e. when state is STATE_NEW
201
*/
202
203
/**
204
* Requests the desired lifetime. Can only be used on the context
205
* initiator's side.
206
*/
207
public void requestLifetime(int lifetime) throws GSSException {
208
if (state == STATE_NEW && isInitiator())
209
this.lifetime = lifetime;
210
}
211
212
/**
213
* Requests that confidentiality be available.
214
*/
215
public final void requestConf(boolean value) throws GSSException {
216
if (state == STATE_NEW && isInitiator())
217
confState = value;
218
}
219
220
/**
221
* Is confidentiality available?
222
*/
223
public final boolean getConfState() {
224
return confState;
225
}
226
227
/**
228
* Requests that integrity be available.
229
*/
230
public final void requestInteg(boolean value) throws GSSException {
231
if (state == STATE_NEW && isInitiator())
232
integState = value;
233
}
234
235
/**
236
* Is integrity available?
237
*/
238
public final boolean getIntegState() {
239
return integState;
240
}
241
242
/**
243
* Requests that credential delegation be done during context
244
* establishment.
245
*/
246
public final void requestCredDeleg(boolean value) throws GSSException {
247
if (state == STATE_NEW && isInitiator()) {
248
if (myCred == null || !(myCred instanceof Krb5ProxyCredential)) {
249
credDelegState = value;
250
}
251
}
252
}
253
254
/**
255
* Is credential delegation enabled?
256
*/
257
public final boolean getCredDelegState() {
258
if (isInitiator()) {
259
return credDelegState;
260
} else {
261
// Server side deleg state is not flagged by credDelegState.
262
// It can use constrained delegation.
263
tryConstrainedDelegation();
264
return delegatedCred != null;
265
}
266
}
267
268
/**
269
* Requests that mutual authentication be done during context
270
* establishment. Since this is fromm the client's perspective, it
271
* essentially requests that the server be authenticated.
272
*/
273
public final void requestMutualAuth(boolean value) throws GSSException {
274
if (state == STATE_NEW && isInitiator()) {
275
mutualAuthState = value;
276
}
277
}
278
279
/**
280
* Is mutual authentication enabled? Since this is from the client's
281
* perspective, it essentially meas that the server is being
282
* authenticated.
283
*/
284
public final boolean getMutualAuthState() {
285
return mutualAuthState;
286
}
287
288
/**
289
* Requests that replay detection be done on the GSS wrap and MIC
290
* tokens.
291
*/
292
public final void requestReplayDet(boolean value) throws GSSException {
293
if (state == STATE_NEW && isInitiator())
294
replayDetState = value;
295
}
296
297
/**
298
* Is replay detection enabled on the GSS wrap and MIC tokens?
299
* We enable replay detection if sequence checking is enabled.
300
*/
301
public final boolean getReplayDetState() {
302
return replayDetState || sequenceDetState;
303
}
304
305
/**
306
* Requests that sequence checking be done on the GSS wrap and MIC
307
* tokens.
308
*/
309
public final void requestSequenceDet(boolean value) throws GSSException {
310
if (state == STATE_NEW && isInitiator())
311
sequenceDetState = value;
312
}
313
314
/**
315
* Is sequence checking enabled on the GSS Wrap and MIC tokens?
316
* We enable sequence checking if replay detection is enabled.
317
*/
318
public final boolean getSequenceDetState() {
319
return sequenceDetState || replayDetState;
320
}
321
322
/**
323
* Requests that the deleg policy be respected.
324
*/
325
public final void requestDelegPolicy(boolean value) {
326
if (state == STATE_NEW && isInitiator())
327
delegPolicyState = value;
328
}
329
330
/**
331
* Is deleg policy respected?
332
*/
333
public final boolean getDelegPolicyState() {
334
return delegPolicyState;
335
}
336
337
/*
338
* Anonymity is a little different in that after an application
339
* requests anonymity it will want to know whether the mechanism
340
* can support it or not, prior to sending any tokens across for
341
* context establishment. Since this is from the initiator's
342
* perspective, it essentially requests that the initiator be
343
* anonymous.
344
*/
345
346
public final void requestAnonymity(boolean value) throws GSSException {
347
// Ignore silently. Application will check back with
348
// getAnonymityState.
349
}
350
351
// RFC 2853 actually calls for this to be called after context
352
// establishment to get the right answer, but that is
353
// incorrect. The application may not want to send over any
354
// tokens if anonymity is not available.
355
public final boolean getAnonymityState() {
356
return false;
357
}
358
359
/*
360
* Package private methods invoked by other Krb5 plugin classes.
361
*/
362
363
/**
364
* Get the context specific DESCipher instance, invoked in
365
* MessageToken.init()
366
*/
367
final CipherHelper getCipherHelper(EncryptionKey ckey) throws GSSException {
368
EncryptionKey cipherKey = null;
369
if (cipherHelper == null) {
370
cipherKey = (getKey() == null) ? ckey: getKey();
371
cipherHelper = new CipherHelper(cipherKey);
372
}
373
return cipherHelper;
374
}
375
376
final int incrementMySequenceNumber() {
377
int retVal;
378
synchronized (mySeqNumberLock) {
379
retVal = mySeqNumber;
380
mySeqNumber = retVal + 1;
381
}
382
return retVal;
383
}
384
385
final void resetMySequenceNumber(int seqNumber) {
386
if (DEBUG) {
387
System.out.println("Krb5Context setting mySeqNumber to: "
388
+ seqNumber);
389
}
390
synchronized (mySeqNumberLock) {
391
mySeqNumber = seqNumber;
392
}
393
}
394
395
final void resetPeerSequenceNumber(int seqNumber) {
396
if (DEBUG) {
397
System.out.println("Krb5Context setting peerSeqNumber to: "
398
+ seqNumber);
399
}
400
synchronized (peerSeqNumberLock) {
401
peerSeqNumber = seqNumber;
402
peerTokenTracker = new TokenTracker(peerSeqNumber);
403
}
404
}
405
406
final void setKey(int keySrc, EncryptionKey key) throws GSSException {
407
this.key = key;
408
this.keySrc = keySrc;
409
// %%% to do: should clear old cipherHelper first
410
cipherHelper = new CipherHelper(key); // Need to use new key
411
}
412
413
public final int getKeySrc() {
414
return keySrc;
415
}
416
417
private final EncryptionKey getKey() {
418
return key;
419
}
420
421
/**
422
* Called on the acceptor side to store the delegated credentials
423
* received in the AcceptSecContextToken.
424
*/
425
final void setDelegCred(Krb5CredElement delegatedCred) {
426
this.delegatedCred = delegatedCred;
427
}
428
429
/*
430
* While the application can only request the following features,
431
* other classes in the package can call the actual set methods
432
* for them. They are called as context establishment tokens are
433
* received on an acceptor side and the context feature list that
434
* the initiator wants becomes known.
435
*/
436
437
/*
438
* This method is also called by InitialToken.OverloadedChecksum if the
439
* TGT is not forwardable and the user requested delegation.
440
*/
441
final void setCredDelegState(boolean state) {
442
credDelegState = state;
443
}
444
445
final void setMutualAuthState(boolean state) {
446
mutualAuthState = state;
447
}
448
449
final void setReplayDetState(boolean state) {
450
replayDetState = state;
451
}
452
453
final void setSequenceDetState(boolean state) {
454
sequenceDetState = state;
455
}
456
457
final void setConfState(boolean state) {
458
confState = state;
459
}
460
461
final void setIntegState(boolean state) {
462
integState = state;
463
}
464
465
final void setDelegPolicyState(boolean state) {
466
delegPolicyState = state;
467
}
468
469
/**
470
* Sets the channel bindings to be used during context
471
* establishment.
472
*/
473
public final void setChannelBinding(ChannelBinding channelBinding)
474
throws GSSException {
475
this.channelBinding = channelBinding;
476
}
477
478
final ChannelBinding getChannelBinding() {
479
return channelBinding;
480
}
481
482
/**
483
* Returns the mechanism oid.
484
*
485
* @return the Oid of this context
486
*/
487
public final Oid getMech() {
488
return (Krb5MechFactory.GSS_KRB5_MECH_OID);
489
}
490
491
/**
492
* Returns the context initiator name.
493
*
494
* @return initiator name
495
* @exception GSSException
496
*/
497
public final GSSNameSpi getSrcName() throws GSSException {
498
return (isInitiator()? myName : peerName);
499
}
500
501
/**
502
* Returns the context acceptor.
503
*
504
* @return context acceptor(target) name
505
* @exception GSSException
506
*/
507
public final GSSNameSpi getTargName() throws GSSException {
508
return (!isInitiator()? myName : peerName);
509
}
510
511
/**
512
* Returns the delegated credential for the context. This
513
* is an optional feature of contexts which not all
514
* mechanisms will support. A context can be requested to
515
* support credential delegation by using the <b>CRED_DELEG</b>,
516
* or it can request for a constrained delegation.
517
* This is only valid on the acceptor side of the context.
518
* @return GSSCredentialSpi object for the delegated credential
519
* @exception GSSException
520
* @see GSSContext#getDelegCredState
521
*/
522
public final GSSCredentialSpi getDelegCred() throws GSSException {
523
if (state != STATE_IN_PROCESS && state != STATE_DONE)
524
throw new GSSException(GSSException.NO_CONTEXT);
525
if (isInitiator()) {
526
throw new GSSException(GSSException.NO_CRED);
527
}
528
tryConstrainedDelegation();
529
if (delegatedCred == null) {
530
throw new GSSException(GSSException.NO_CRED);
531
}
532
return delegatedCred;
533
}
534
535
private void tryConstrainedDelegation() {
536
if (state != STATE_IN_PROCESS && state != STATE_DONE) {
537
return;
538
}
539
// We will only try constrained delegation once (if necessary).
540
if (!isConstrainedDelegationTried) {
541
if (delegatedCred == null) {
542
if (DEBUG) {
543
System.out.println(">>> Constrained deleg from " + caller);
544
}
545
// The constrained delegation part. The acceptor needs to have
546
// isInitiator=true in order to get a TGT, either earlier at
547
// logon stage, if useSubjectCredsOnly, or now.
548
try {
549
delegatedCred = new Krb5ProxyCredential(
550
Krb5InitCredential.getInstance(
551
GSSCaller.CALLER_ACCEPT, myName, lifetime),
552
peerName, serviceTicket);
553
} catch (GSSException gsse) {
554
// OK, delegatedCred is null then
555
}
556
}
557
isConstrainedDelegationTried = true;
558
}
559
}
560
/**
561
* Tests if this is the initiator side of the context.
562
*
563
* @return boolean indicating if this is initiator (true)
564
* or target (false)
565
*/
566
public final boolean isInitiator() {
567
return initiator;
568
}
569
570
/**
571
* Tests if the context can be used for per-message service.
572
* Context may allow the calls to the per-message service
573
* functions before being fully established.
574
*
575
* @return boolean indicating if per-message methods can
576
* be called.
577
*/
578
public final boolean isProtReady() {
579
return (state == STATE_DONE);
580
}
581
582
/**
583
* Initiator context establishment call. This method may be
584
* required to be called several times. A CONTINUE_NEEDED return
585
* call indicates that more calls are needed after the next token
586
* is received from the peer.
587
*
588
* @param is contains the token received from the peer. On the
589
* first call it will be ignored.
590
* @return any token required to be sent to the peer
591
* It is responsibility of the caller
592
* to send the token to its peer for processing.
593
* @exception GSSException
594
*/
595
public final byte[] initSecContext(InputStream is, int mechTokenSize)
596
throws GSSException {
597
598
byte[] retVal = null;
599
InitialToken token = null;
600
int errorCode = GSSException.FAILURE;
601
if (DEBUG) {
602
System.out.println("Entered Krb5Context.initSecContext with " +
603
"state=" + printState(state));
604
}
605
if (!isInitiator()) {
606
throw new GSSException(GSSException.FAILURE, -1,
607
"initSecContext on an acceptor " +
608
"GSSContext");
609
}
610
611
try {
612
if (state == STATE_NEW) {
613
state = STATE_IN_PROCESS;
614
615
errorCode = GSSException.NO_CRED;
616
617
if (myCred == null) {
618
myCred = Krb5InitCredential.getInstance(caller, myName,
619
GSSCredential.DEFAULT_LIFETIME);
620
myCred = Krb5ProxyCredential.tryImpersonation(
621
caller, (Krb5InitCredential)myCred);
622
} else if (!myCred.isInitiatorCredential()) {
623
throw new GSSException(errorCode, -1,
624
"No TGT available");
625
}
626
myName = (Krb5NameElement) myCred.getName();
627
final Krb5ProxyCredential second;
628
if (myCred instanceof Krb5InitCredential) {
629
second = null;
630
tgt = ((Krb5InitCredential) myCred).getKrb5Credentials();
631
} else {
632
second = (Krb5ProxyCredential) myCred;
633
tgt = second.self.getKrb5Credentials();
634
}
635
636
checkPermission(peerName.getKrb5PrincipalName().getName(),
637
"initiate");
638
/*
639
* If useSubjectCredsonly is true then
640
* we check whether we already have the ticket
641
* for this service in the Subject and reuse it
642
*/
643
644
@SuppressWarnings("removal")
645
final AccessControlContext acc =
646
AccessController.getContext();
647
648
if (GSSUtil.useSubjectCredsOnly(caller)) {
649
KerberosTicket kerbTicket = null;
650
try {
651
// get service ticket from caller's subject
652
@SuppressWarnings("removal")
653
var tmp = AccessController.doPrivileged(
654
new PrivilegedExceptionAction<KerberosTicket>() {
655
public KerberosTicket run() throws Exception {
656
// XXX to be cleaned
657
// highly consider just calling:
658
// Subject.getSubject
659
// SubjectComber.find
660
// instead of Krb5Util.getServiceTicket
661
return Krb5Util.getServiceTicket(
662
GSSCaller.CALLER_UNKNOWN,
663
// since it's useSubjectCredsOnly here,
664
// don't worry about the null
665
second == null ?
666
myName.getKrb5PrincipalName().getName():
667
second.getName().getKrb5PrincipalName().getName(),
668
peerName.getKrb5PrincipalName().getName(),
669
acc);
670
}});
671
kerbTicket = tmp;
672
} catch (PrivilegedActionException e) {
673
if (DEBUG) {
674
System.out.println("Attempt to obtain service"
675
+ " ticket from the subject failed!");
676
}
677
}
678
if (kerbTicket != null) {
679
if (DEBUG) {
680
System.out.println("Found service ticket in " +
681
"the subject" +
682
kerbTicket);
683
}
684
685
// convert Ticket to serviceCreds
686
// XXX Should merge these two object types
687
// avoid converting back and forth
688
serviceCreds = Krb5Util.ticketToCreds(kerbTicket);
689
}
690
}
691
if (serviceCreds == null) {
692
// either we did not find the serviceCreds in the
693
// Subject or useSubjectCreds is false
694
if (DEBUG) {
695
System.out.println("Service ticket not found in " +
696
"the subject");
697
}
698
// Get Service ticket using the Kerberos protocols
699
if (second == null) {
700
serviceCreds = Credentials.acquireServiceCreds(
701
peerName.getKrb5PrincipalName().getName(),
702
tgt);
703
} else {
704
serviceCreds = Credentials.acquireS4U2proxyCreds(
705
peerName.getKrb5PrincipalName().getName(),
706
second.tkt,
707
second.getName().getKrb5PrincipalName(),
708
tgt);
709
}
710
if (GSSUtil.useSubjectCredsOnly(caller)) {
711
@SuppressWarnings("removal")
712
final Subject subject =
713
AccessController.doPrivileged(
714
new java.security.PrivilegedAction<Subject>() {
715
public Subject run() {
716
return (Subject.getSubject(acc));
717
}
718
});
719
if (subject != null &&
720
!subject.isReadOnly()) {
721
/*
722
* Store the service credentials as
723
* javax.security.auth.kerberos.KerberosTicket in
724
* the Subject. We could wait until the context is
725
* successfully established; however it is easier
726
* to do it here and there is no harm.
727
*/
728
final KerberosTicket kt =
729
Krb5Util.credsToTicket(serviceCreds);
730
@SuppressWarnings("removal")
731
var dummy = AccessController.doPrivileged (
732
new java.security.PrivilegedAction<Void>() {
733
public Void run() {
734
subject.getPrivateCredentials().add(kt);
735
return null;
736
}
737
});
738
} else {
739
// log it for debugging purpose
740
if (DEBUG) {
741
System.out.println("Subject is " +
742
"readOnly;Kerberos Service "+
743
"ticket not stored");
744
}
745
}
746
}
747
}
748
749
errorCode = GSSException.FAILURE;
750
token = new InitSecContextToken(this, tgt, serviceCreds);
751
apReq = ((InitSecContextToken)token).getKrbApReq();
752
retVal = token.encode();
753
myCred = null;
754
if (!getMutualAuthState()) {
755
state = STATE_DONE;
756
}
757
if (DEBUG) {
758
System.out.println("Created InitSecContextToken:\n"+
759
new HexDumpEncoder().encodeBuffer(retVal));
760
}
761
} else if (state == STATE_IN_PROCESS) {
762
// No need to write anything;
763
// just validate the incoming token
764
new AcceptSecContextToken(this, serviceCreds, apReq, is);
765
apReq = null;
766
state = STATE_DONE;
767
} else {
768
// XXX Use logging API?
769
if (DEBUG) {
770
System.out.println(state);
771
}
772
}
773
} catch (KrbException e) {
774
if (DEBUG) {
775
e.printStackTrace();
776
}
777
GSSException gssException =
778
new GSSException(errorCode, -1, e.getMessage());
779
gssException.initCause(e);
780
throw gssException;
781
} catch (IOException e) {
782
GSSException gssException =
783
new GSSException(errorCode, -1, e.getMessage());
784
gssException.initCause(e);
785
throw gssException;
786
}
787
return retVal;
788
}
789
790
public final boolean isEstablished() {
791
return (state == STATE_DONE);
792
}
793
794
/**
795
* Acceptor's context establishment call. This method may be
796
* required to be called several times. A CONTINUE_NEEDED return
797
* call indicates that more calls are needed after the next token
798
* is received from the peer.
799
*
800
* @param is contains the token received from the peer.
801
* @return any token required to be sent to the peer
802
* It is responsibility of the caller
803
* to send the token to its peer for processing.
804
* @exception GSSException
805
*/
806
public final byte[] acceptSecContext(InputStream is, int mechTokenSize)
807
throws GSSException {
808
809
byte[] retVal = null;
810
811
if (DEBUG) {
812
System.out.println("Entered Krb5Context.acceptSecContext with " +
813
"state=" + printState(state));
814
}
815
816
if (isInitiator()) {
817
throw new GSSException(GSSException.FAILURE, -1,
818
"acceptSecContext on an initiator " +
819
"GSSContext");
820
}
821
try {
822
if (state == STATE_NEW) {
823
state = STATE_IN_PROCESS;
824
if (myCred == null) {
825
myCred = Krb5AcceptCredential.getInstance(caller, myName);
826
} else if (!myCred.isAcceptorCredential()) {
827
throw new GSSException(GSSException.NO_CRED, -1,
828
"No Secret Key available");
829
}
830
myName = (Krb5NameElement) myCred.getName();
831
832
// If there is already a bound name, check now
833
if (myName != null) {
834
Krb5MechFactory.checkAcceptCredPermission(myName, myName);
835
}
836
837
InitSecContextToken token = new InitSecContextToken(this,
838
(Krb5AcceptCredential) myCred, is);
839
PrincipalName clientName = token.getKrbApReq().getClient();
840
peerName = Krb5NameElement.getInstance(clientName);
841
842
// If unbound, check after the bound name is found
843
if (myName == null) {
844
myName = Krb5NameElement.getInstance(
845
token.getKrbApReq().getCreds().getServer());
846
Krb5MechFactory.checkAcceptCredPermission(myName, myName);
847
}
848
849
if (getMutualAuthState()) {
850
retVal = new AcceptSecContextToken(this,
851
token.getKrbApReq()).encode();
852
}
853
serviceTicket = token.getKrbApReq().getCreds().getTicket();
854
myCred = null;
855
state = STATE_DONE;
856
} else {
857
// XXX Use logging API?
858
if (DEBUG) {
859
System.out.println(state);
860
}
861
}
862
} catch (KrbException e) {
863
GSSException gssException =
864
new GSSException(GSSException.FAILURE, -1, e.getMessage());
865
gssException.initCause(e);
866
throw gssException;
867
} catch (IOException e) {
868
if (DEBUG) {
869
e.printStackTrace();
870
}
871
GSSException gssException =
872
new GSSException(GSSException.FAILURE, -1, e.getMessage());
873
gssException.initCause(e);
874
throw gssException;
875
}
876
877
return retVal;
878
}
879
880
/**
881
* Queries the context for largest data size to accommodate
882
* the specified protection and be <= maxTokSize.
883
*
884
* @param qop the quality of protection that the context will be
885
* asked to provide.
886
* @param confReq a flag indicating whether confidentiality will be
887
* requested or not
888
* @param outputSize the maximum size of the output token
889
* @return the maximum size for the input message that can be
890
* provided to the wrap() method in order to guarantee that these
891
* requirements are met.
892
* @throws GSSException
893
*/
894
public final int getWrapSizeLimit(int qop, boolean confReq,
895
int maxTokSize) throws GSSException {
896
897
int retVal = 0;
898
if (cipherHelper.getProto() == 0) {
899
retVal = WrapToken.getSizeLimit(qop, confReq, maxTokSize,
900
getCipherHelper(null));
901
} else if (cipherHelper.getProto() == 1) {
902
retVal = WrapToken_v2.getSizeLimit(qop, confReq, maxTokSize,
903
getCipherHelper(null));
904
}
905
return retVal;
906
}
907
908
/*
909
* Per-message calls depend on the sequence number. The sequence number
910
* synchronization is at a finer granularity because wrap and getMIC
911
* care about the local sequence number (mySeqNumber) where are unwrap
912
* and verifyMIC care about the remote sequence number (peerSeqNumber).
913
*/
914
915
public final byte[] wrap(byte[] inBuf, int offset, int len,
916
MessageProp msgProp) throws GSSException {
917
if (DEBUG) {
918
System.out.println("Krb5Context.wrap: data=["
919
+ getHexBytes(inBuf, offset, len)
920
+ "]");
921
}
922
923
if (state != STATE_DONE)
924
throw new GSSException(GSSException.NO_CONTEXT, -1,
925
"Wrap called in invalid state!");
926
927
byte[] encToken = null;
928
try {
929
if (cipherHelper.getProto() == 0) {
930
WrapToken token =
931
new WrapToken(this, msgProp, inBuf, offset, len);
932
encToken = token.encode();
933
} else if (cipherHelper.getProto() == 1) {
934
WrapToken_v2 token =
935
new WrapToken_v2(this, msgProp, inBuf, offset, len);
936
encToken = token.encode();
937
}
938
if (DEBUG) {
939
System.out.println("Krb5Context.wrap: token=["
940
+ getHexBytes(encToken, 0, encToken.length)
941
+ "]");
942
}
943
return encToken;
944
} catch (IOException e) {
945
encToken = null;
946
GSSException gssException =
947
new GSSException(GSSException.FAILURE, -1, e.getMessage());
948
gssException.initCause(e);
949
throw gssException;
950
}
951
}
952
953
public final int wrap(byte[] inBuf, int inOffset, int len,
954
byte[] outBuf, int outOffset,
955
MessageProp msgProp) throws GSSException {
956
957
if (state != STATE_DONE)
958
throw new GSSException(GSSException.NO_CONTEXT, -1,
959
"Wrap called in invalid state!");
960
961
int retVal = 0;
962
try {
963
if (cipherHelper.getProto() == 0) {
964
WrapToken token =
965
new WrapToken(this, msgProp, inBuf, inOffset, len);
966
retVal = token.encode(outBuf, outOffset);
967
} else if (cipherHelper.getProto() == 1) {
968
WrapToken_v2 token =
969
new WrapToken_v2(this, msgProp, inBuf, inOffset, len);
970
retVal = token.encode(outBuf, outOffset);
971
}
972
if (DEBUG) {
973
System.out.println("Krb5Context.wrap: token=["
974
+ getHexBytes(outBuf, outOffset, retVal)
975
+ "]");
976
}
977
return retVal;
978
} catch (IOException e) {
979
retVal = 0;
980
GSSException gssException =
981
new GSSException(GSSException.FAILURE, -1, e.getMessage());
982
gssException.initCause(e);
983
throw gssException;
984
}
985
}
986
987
public final void wrap(byte[] inBuf, int offset, int len,
988
OutputStream os, MessageProp msgProp)
989
throws GSSException {
990
991
if (state != STATE_DONE)
992
throw new GSSException(GSSException.NO_CONTEXT, -1,
993
"Wrap called in invalid state!");
994
995
byte[] encToken = null;
996
try {
997
if (cipherHelper.getProto() == 0) {
998
WrapToken token =
999
new WrapToken(this, msgProp, inBuf, offset, len);
1000
token.encode(os);
1001
if (DEBUG) {
1002
encToken = token.encode();
1003
}
1004
} else if (cipherHelper.getProto() == 1) {
1005
WrapToken_v2 token =
1006
new WrapToken_v2(this, msgProp, inBuf, offset, len);
1007
token.encode(os);
1008
if (DEBUG) {
1009
encToken = token.encode();
1010
}
1011
}
1012
} catch (IOException e) {
1013
GSSException gssException =
1014
new GSSException(GSSException.FAILURE, -1, e.getMessage());
1015
gssException.initCause(e);
1016
throw gssException;
1017
}
1018
1019
if (DEBUG) {
1020
System.out.println("Krb5Context.wrap: token=["
1021
+ getHexBytes(encToken, 0, encToken.length)
1022
+ "]");
1023
}
1024
}
1025
1026
public final void wrap(InputStream is, OutputStream os,
1027
MessageProp msgProp) throws GSSException {
1028
1029
byte[] data;
1030
try {
1031
data = new byte[is.available()];
1032
is.read(data);
1033
} catch (IOException e) {
1034
GSSException gssException =
1035
new GSSException(GSSException.FAILURE, -1, e.getMessage());
1036
gssException.initCause(e);
1037
throw gssException;
1038
}
1039
wrap(data, 0, data.length, os, msgProp);
1040
}
1041
1042
public final byte[] unwrap(byte[] inBuf, int offset, int len,
1043
MessageProp msgProp)
1044
throws GSSException {
1045
1046
if (DEBUG) {
1047
System.out.println("Krb5Context.unwrap: token=["
1048
+ getHexBytes(inBuf, offset, len)
1049
+ "]");
1050
}
1051
1052
if (state != STATE_DONE) {
1053
throw new GSSException(GSSException.NO_CONTEXT, -1,
1054
" Unwrap called in invalid state!");
1055
}
1056
1057
byte[] data = null;
1058
if (cipherHelper.getProto() == 0) {
1059
WrapToken token =
1060
new WrapToken(this, inBuf, offset, len, msgProp);
1061
data = token.getData();
1062
setSequencingAndReplayProps(token, msgProp);
1063
} else if (cipherHelper.getProto() == 1) {
1064
WrapToken_v2 token =
1065
new WrapToken_v2(this, inBuf, offset, len, msgProp);
1066
data = token.getData();
1067
setSequencingAndReplayProps(token, msgProp);
1068
}
1069
1070
if (DEBUG) {
1071
System.out.println("Krb5Context.unwrap: data=["
1072
+ getHexBytes(data, 0, data.length)
1073
+ "]");
1074
}
1075
1076
return data;
1077
}
1078
1079
public final int unwrap(byte[] inBuf, int inOffset, int len,
1080
byte[] outBuf, int outOffset,
1081
MessageProp msgProp) throws GSSException {
1082
1083
if (state != STATE_DONE)
1084
throw new GSSException(GSSException.NO_CONTEXT, -1,
1085
"Unwrap called in invalid state!");
1086
1087
if (cipherHelper.getProto() == 0) {
1088
WrapToken token =
1089
new WrapToken(this, inBuf, inOffset, len, msgProp);
1090
len = token.getData(outBuf, outOffset);
1091
setSequencingAndReplayProps(token, msgProp);
1092
} else if (cipherHelper.getProto() == 1) {
1093
WrapToken_v2 token =
1094
new WrapToken_v2(this, inBuf, inOffset, len, msgProp);
1095
len = token.getData(outBuf, outOffset);
1096
setSequencingAndReplayProps(token, msgProp);
1097
}
1098
return len;
1099
}
1100
1101
public final int unwrap(InputStream is,
1102
byte[] outBuf, int outOffset,
1103
MessageProp msgProp) throws GSSException {
1104
1105
if (state != STATE_DONE)
1106
throw new GSSException(GSSException.NO_CONTEXT, -1,
1107
"Unwrap called in invalid state!");
1108
1109
int len = 0;
1110
if (cipherHelper.getProto() == 0) {
1111
WrapToken token = new WrapToken(this, is, msgProp);
1112
len = token.getData(outBuf, outOffset);
1113
setSequencingAndReplayProps(token, msgProp);
1114
} else if (cipherHelper.getProto() == 1) {
1115
WrapToken_v2 token = new WrapToken_v2(this, is, msgProp);
1116
len = token.getData(outBuf, outOffset);
1117
setSequencingAndReplayProps(token, msgProp);
1118
}
1119
return len;
1120
}
1121
1122
1123
public final void unwrap(InputStream is, OutputStream os,
1124
MessageProp msgProp) throws GSSException {
1125
1126
if (state != STATE_DONE)
1127
throw new GSSException(GSSException.NO_CONTEXT, -1,
1128
"Unwrap called in invalid state!");
1129
1130
byte[] data = null;
1131
if (cipherHelper.getProto() == 0) {
1132
WrapToken token = new WrapToken(this, is, msgProp);
1133
data = token.getData();
1134
setSequencingAndReplayProps(token, msgProp);
1135
} else if (cipherHelper.getProto() == 1) {
1136
WrapToken_v2 token = new WrapToken_v2(this, is, msgProp);
1137
data = token.getData();
1138
setSequencingAndReplayProps(token, msgProp);
1139
}
1140
1141
try {
1142
os.write(data);
1143
} catch (IOException e) {
1144
GSSException gssException =
1145
new GSSException(GSSException.FAILURE, -1, e.getMessage());
1146
gssException.initCause(e);
1147
throw gssException;
1148
}
1149
}
1150
1151
public final byte[] getMIC(byte[] inMsg, int offset, int len,
1152
MessageProp msgProp)
1153
throws GSSException {
1154
1155
byte[] micToken = null;
1156
try {
1157
if (cipherHelper.getProto() == 0) {
1158
MicToken token =
1159
new MicToken(this, msgProp, inMsg, offset, len);
1160
micToken = token.encode();
1161
} else if (cipherHelper.getProto() == 1) {
1162
MicToken_v2 token =
1163
new MicToken_v2(this, msgProp, inMsg, offset, len);
1164
micToken = token.encode();
1165
}
1166
return micToken;
1167
} catch (IOException e) {
1168
micToken = null;
1169
GSSException gssException =
1170
new GSSException(GSSException.FAILURE, -1, e.getMessage());
1171
gssException.initCause(e);
1172
throw gssException;
1173
}
1174
}
1175
1176
private int getMIC(byte[] inMsg, int offset, int len,
1177
byte[] outBuf, int outOffset,
1178
MessageProp msgProp)
1179
throws GSSException {
1180
1181
int retVal = 0;
1182
try {
1183
if (cipherHelper.getProto() == 0) {
1184
MicToken token =
1185
new MicToken(this, msgProp, inMsg, offset, len);
1186
retVal = token.encode(outBuf, outOffset);
1187
} else if (cipherHelper.getProto() == 1) {
1188
MicToken_v2 token =
1189
new MicToken_v2(this, msgProp, inMsg, offset, len);
1190
retVal = token.encode(outBuf, outOffset);
1191
}
1192
return retVal;
1193
} catch (IOException e) {
1194
retVal = 0;
1195
GSSException gssException =
1196
new GSSException(GSSException.FAILURE, -1, e.getMessage());
1197
gssException.initCause(e);
1198
throw gssException;
1199
}
1200
}
1201
1202
/*
1203
* Checksum calculation requires a byte[]. Hence might as well pass
1204
* a byte[] into the MicToken constructor. However, writing the
1205
* token can be optimized for cases where the application passed in
1206
* an OutputStream.
1207
*/
1208
1209
private void getMIC(byte[] inMsg, int offset, int len,
1210
OutputStream os, MessageProp msgProp)
1211
throws GSSException {
1212
1213
try {
1214
if (cipherHelper.getProto() == 0) {
1215
MicToken token =
1216
new MicToken(this, msgProp, inMsg, offset, len);
1217
token.encode(os);
1218
} else if (cipherHelper.getProto() == 1) {
1219
MicToken_v2 token =
1220
new MicToken_v2(this, msgProp, inMsg, offset, len);
1221
token.encode(os);
1222
}
1223
} catch (IOException e) {
1224
GSSException gssException =
1225
new GSSException(GSSException.FAILURE, -1, e.getMessage());
1226
gssException.initCause(e);
1227
throw gssException;
1228
}
1229
}
1230
1231
public final void getMIC(InputStream is, OutputStream os,
1232
MessageProp msgProp) throws GSSException {
1233
byte[] data;
1234
try {
1235
data = new byte[is.available()];
1236
is.read(data);
1237
} catch (IOException e) {
1238
GSSException gssException =
1239
new GSSException(GSSException.FAILURE, -1, e.getMessage());
1240
gssException.initCause(e);
1241
throw gssException;
1242
}
1243
getMIC(data, 0, data.length, os, msgProp);
1244
}
1245
1246
public final void verifyMIC(byte[] inTok, int tokOffset, int tokLen,
1247
byte[] inMsg, int msgOffset, int msgLen,
1248
MessageProp msgProp)
1249
throws GSSException {
1250
1251
if (cipherHelper.getProto() == 0) {
1252
MicToken token =
1253
new MicToken(this, inTok, tokOffset, tokLen, msgProp);
1254
token.verify(inMsg, msgOffset, msgLen);
1255
setSequencingAndReplayProps(token, msgProp);
1256
} else if (cipherHelper.getProto() == 1) {
1257
MicToken_v2 token =
1258
new MicToken_v2(this, inTok, tokOffset, tokLen, msgProp);
1259
token.verify(inMsg, msgOffset, msgLen);
1260
setSequencingAndReplayProps(token, msgProp);
1261
}
1262
}
1263
1264
private void verifyMIC(InputStream is,
1265
byte[] inMsg, int msgOffset, int msgLen,
1266
MessageProp msgProp)
1267
throws GSSException {
1268
1269
if (cipherHelper.getProto() == 0) {
1270
MicToken token = new MicToken(this, is, msgProp);
1271
token.verify(inMsg, msgOffset, msgLen);
1272
setSequencingAndReplayProps(token, msgProp);
1273
} else if (cipherHelper.getProto() == 1) {
1274
MicToken_v2 token = new MicToken_v2(this, is, msgProp);
1275
token.verify(inMsg, msgOffset, msgLen);
1276
setSequencingAndReplayProps(token, msgProp);
1277
}
1278
}
1279
1280
public final void verifyMIC(InputStream is, InputStream msgStr,
1281
MessageProp mProp) throws GSSException {
1282
byte[] msg;
1283
try {
1284
msg = new byte[msgStr.available()];
1285
msgStr.read(msg);
1286
} catch (IOException e) {
1287
GSSException gssException =
1288
new GSSException(GSSException.FAILURE, -1, e.getMessage());
1289
gssException.initCause(e);
1290
throw gssException;
1291
}
1292
verifyMIC(is, msg, 0, msg.length, mProp);
1293
}
1294
1295
/**
1296
* Produces a token representing this context. After this call
1297
* the context will no longer be usable until an import is
1298
* performed on the returned token.
1299
*
1300
* @param os the output token will be written to this stream
1301
* @exception GSSException
1302
*/
1303
public final byte[] export() throws GSSException {
1304
throw new GSSException(GSSException.UNAVAILABLE, -1,
1305
"GSS Export Context not available");
1306
}
1307
1308
/**
1309
* Releases context resources and terminates the
1310
* context between 2 peer.
1311
*
1312
* @exception GSSException with major codes NO_CONTEXT, FAILURE.
1313
*/
1314
1315
public final void dispose() throws GSSException {
1316
state = STATE_DELETED;
1317
delegatedCred = null;
1318
tgt = null;
1319
serviceCreds = null;
1320
key = null;
1321
}
1322
1323
public final Provider getProvider() {
1324
return Krb5MechFactory.PROVIDER;
1325
}
1326
1327
/**
1328
* Sets replay and sequencing information for a message token received
1329
* form the peer.
1330
*/
1331
private void setSequencingAndReplayProps(MessageToken token,
1332
MessageProp prop) {
1333
if (replayDetState || sequenceDetState) {
1334
int seqNum = token.getSequenceNumber();
1335
peerTokenTracker.getProps(seqNum, prop);
1336
}
1337
}
1338
1339
/**
1340
* Sets replay and sequencing information for a message token received
1341
* form the peer.
1342
*/
1343
private void setSequencingAndReplayProps(MessageToken_v2 token,
1344
MessageProp prop) {
1345
if (replayDetState || sequenceDetState) {
1346
int seqNum = token.getSequenceNumber();
1347
peerTokenTracker.getProps(seqNum, prop);
1348
}
1349
}
1350
1351
private void checkPermission(String principal, String action) {
1352
@SuppressWarnings("removal")
1353
SecurityManager sm = System.getSecurityManager();
1354
if (sm != null) {
1355
ServicePermission perm =
1356
new ServicePermission(principal, action);
1357
sm.checkPermission(perm);
1358
}
1359
}
1360
1361
private static String getHexBytes(byte[] bytes, int pos, int len) {
1362
1363
StringBuilder sb = new StringBuilder();
1364
for (int i = 0; i < len; i++) {
1365
1366
int b1 = (bytes[i]>>4) & 0x0f;
1367
int b2 = bytes[i] & 0x0f;
1368
1369
sb.append(Integer.toHexString(b1));
1370
sb.append(Integer.toHexString(b2));
1371
sb.append(' ');
1372
}
1373
return sb.toString();
1374
}
1375
1376
private static String printState(int state) {
1377
switch (state) {
1378
case STATE_NEW:
1379
return ("STATE_NEW");
1380
case STATE_IN_PROCESS:
1381
return ("STATE_IN_PROCESS");
1382
case STATE_DONE:
1383
return ("STATE_DONE");
1384
case STATE_DELETED:
1385
return ("STATE_DELETED");
1386
default:
1387
return ("Unknown state " + state);
1388
}
1389
}
1390
1391
GSSCaller getCaller() {
1392
// Currently used by InitialToken only
1393
return caller;
1394
}
1395
1396
/**
1397
* The session key returned by inquireSecContext(KRB5_INQ_SSPI_SESSION_KEY)
1398
*/
1399
static class KerberosSessionKey implements Key {
1400
private static final long serialVersionUID = 699307378954123869L;
1401
1402
@SuppressWarnings("serial") // Not statically typed as Serializable
1403
private final EncryptionKey key;
1404
1405
KerberosSessionKey(EncryptionKey key) {
1406
this.key = key;
1407
}
1408
1409
@Override
1410
public String getAlgorithm() {
1411
return Integer.toString(key.getEType());
1412
}
1413
1414
@Override
1415
public String getFormat() {
1416
return "RAW";
1417
}
1418
1419
@Override
1420
public byte[] getEncoded() {
1421
return key.getBytes().clone();
1422
}
1423
1424
@Override
1425
public String toString() {
1426
return "Kerberos session key: etype: " + key.getEType() + "\n" +
1427
new HexDumpEncoder().encodeBuffer(key.getBytes());
1428
}
1429
}
1430
1431
/**
1432
* Return the mechanism-specific attribute associated with {@code type}.
1433
*/
1434
public Object inquireSecContext(String type)
1435
throws GSSException {
1436
if (!isEstablished()) {
1437
throw new GSSException(GSSException.NO_CONTEXT, -1,
1438
"Security context not established.");
1439
}
1440
switch (type) {
1441
case "KRB5_GET_SESSION_KEY":
1442
return new KerberosSessionKey(key);
1443
case "KRB5_GET_SESSION_KEY_EX":
1444
return new javax.security.auth.kerberos.EncryptionKey(
1445
key.getBytes(), key.getEType());
1446
case "KRB5_GET_TKT_FLAGS":
1447
return tktFlags.clone();
1448
case "KRB5_GET_AUTHZ_DATA":
1449
if (isInitiator()) {
1450
throw new GSSException(GSSException.UNAVAILABLE, -1,
1451
"AuthzData not available on initiator side.");
1452
} else {
1453
return authzData;
1454
}
1455
case "KRB5_GET_AUTHTIME":
1456
return authTime;
1457
case "KRB5_GET_KRB_CRED":
1458
if (!isInitiator()) {
1459
throw new GSSException(GSSException.UNAVAILABLE, -1,
1460
"KRB_CRED not available on acceptor side.");
1461
}
1462
KerberosPrincipal sender = new KerberosPrincipal(
1463
myName.getKrb5PrincipalName().getName());
1464
KerberosPrincipal recipient = new KerberosPrincipal(
1465
peerName.getKrb5PrincipalName().getName());
1466
try {
1467
byte[] krbCred = new KrbCred(tgt, serviceCreds, key)
1468
.getMessage();
1469
return new KerberosCredMessage(
1470
sender, recipient, krbCred);
1471
} catch (KrbException | IOException e) {
1472
GSSException gsse = new GSSException(GSSException.UNAVAILABLE, -1,
1473
"KRB_CRED not generated correctly.");
1474
gsse.initCause(e);
1475
throw gsse;
1476
}
1477
}
1478
throw new GSSException(GSSException.UNAVAILABLE, -1,
1479
"Inquire type not supported.");
1480
}
1481
1482
// Helpers for inquireSecContext
1483
private boolean[] tktFlags;
1484
private String authTime;
1485
private AuthorizationData authzData;
1486
1487
public void setTktFlags(boolean[] tktFlags) {
1488
this.tktFlags = tktFlags;
1489
}
1490
1491
public void setAuthTime(String authTime) {
1492
this.authTime = authTime;
1493
}
1494
1495
public void setAuthzData(AuthorizationData authzData) {
1496
this.authzData = authzData;
1497
}
1498
1499
}
1500
1501