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