Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.security.jgss/share/classes/sun/security/jgss/spnego/SpNegoContext.java
67792 views
1
/*
2
* Copyright (c) 2005, 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.spnego;
27
28
import java.io.*;
29
import java.security.Provider;
30
import org.ietf.jgss.*;
31
import sun.security.action.GetBooleanAction;
32
import sun.security.jgss.*;
33
import sun.security.jgss.spi.*;
34
import sun.security.util.*;
35
36
/**
37
* Implements the mechanism specific context class for SPNEGO
38
* GSS-API mechanism
39
*
40
* @author Seema Malkani
41
* @since 1.6
42
*/
43
public class SpNegoContext implements GSSContextSpi {
44
45
/*
46
* The different states that this context can be in.
47
*/
48
private static final int STATE_NEW = 1;
49
private static final int STATE_IN_PROCESS = 2;
50
private static final int STATE_DONE = 3;
51
private static final int STATE_DELETED = 4;
52
53
private int state = STATE_NEW;
54
55
/*
56
* Optional features that the application can set and their default
57
* values.
58
*/
59
private boolean credDelegState = false;
60
private boolean mutualAuthState = true;
61
private boolean replayDetState = true;
62
private boolean sequenceDetState = true;
63
private boolean confState = true;
64
private boolean integState = true;
65
private boolean delegPolicyState = false;
66
67
private GSSNameSpi peerName = null;
68
private GSSNameSpi myName = null;
69
private SpNegoCredElement myCred = null;
70
71
private GSSContext mechContext = null;
72
private byte[] DER_mechTypes = null;
73
74
private int lifetime;
75
private ChannelBinding channelBinding;
76
private boolean initiator;
77
78
// the underlying negotiated mechanism
79
private Oid internal_mech = null;
80
81
// the SpNegoMechFactory that creates this context
82
private final SpNegoMechFactory factory;
83
84
// debug property
85
static final boolean DEBUG = GetBooleanAction
86
.privilegedGetProperty("sun.security.spnego.debug");
87
88
/**
89
* Constructor for SpNegoContext to be called on the context initiator's
90
* side.
91
*/
92
public SpNegoContext(SpNegoMechFactory factory, GSSNameSpi peerName,
93
GSSCredentialSpi myCred,
94
int lifetime) throws GSSException {
95
96
if (peerName == null)
97
throw new IllegalArgumentException("Cannot have null peer name");
98
if ((myCred != null) && !(myCred instanceof SpNegoCredElement)) {
99
throw new IllegalArgumentException("Wrong cred element type");
100
}
101
this.peerName = peerName;
102
this.myCred = (SpNegoCredElement) myCred;
103
this.lifetime = lifetime;
104
this.initiator = true;
105
this.factory = factory;
106
}
107
108
/**
109
* Constructor for SpNegoContext to be called on the context acceptor's
110
* side.
111
*/
112
public SpNegoContext(SpNegoMechFactory factory, GSSCredentialSpi myCred)
113
throws GSSException {
114
if ((myCred != null) && !(myCred instanceof SpNegoCredElement)) {
115
throw new IllegalArgumentException("Wrong cred element type");
116
}
117
this.myCred = (SpNegoCredElement) myCred;
118
this.initiator = false;
119
this.factory = factory;
120
}
121
122
/**
123
* Constructor for SpNegoContext to import a previously exported context.
124
*/
125
public SpNegoContext(SpNegoMechFactory factory, byte [] interProcessToken)
126
throws GSSException {
127
throw new GSSException(GSSException.UNAVAILABLE,
128
-1, "GSS Import Context not available");
129
}
130
131
/**
132
* Requests that confidentiality be available.
133
*/
134
public final void requestConf(boolean value) throws GSSException {
135
if (state == STATE_NEW && isInitiator())
136
confState = value;
137
}
138
139
/**
140
* Is confidentiality available?
141
*/
142
public final boolean getConfState() {
143
return confState;
144
}
145
146
/**
147
* Requests that integrity be available.
148
*/
149
public final void requestInteg(boolean value) throws GSSException {
150
if (state == STATE_NEW && isInitiator())
151
integState = value;
152
}
153
154
/**
155
* Requests that deleg policy be respected.
156
*/
157
public final void requestDelegPolicy(boolean value) throws GSSException {
158
if (state == STATE_NEW && isInitiator())
159
delegPolicyState = value;
160
}
161
162
/**
163
* Is integrity available?
164
*/
165
public final boolean getIntegState() {
166
return integState;
167
}
168
169
/**
170
* Is deleg policy respected?
171
*/
172
public final boolean getDelegPolicyState() {
173
if (isInitiator() && mechContext != null &&
174
mechContext instanceof GSSContextImpl &&
175
(state == STATE_IN_PROCESS || state == STATE_DONE)) {
176
return ((GSSContextImpl)mechContext).getDelegPolicyState();
177
} else {
178
return delegPolicyState;
179
}
180
}
181
182
/**
183
* Requests that credential delegation be done during context
184
* establishment.
185
*/
186
public final void requestCredDeleg(boolean value) throws GSSException {
187
if (state == STATE_NEW && isInitiator())
188
credDelegState = value;
189
}
190
191
/**
192
* Is credential delegation enabled?
193
*/
194
public final boolean getCredDelegState() {
195
if (isInitiator() && mechContext != null &&
196
(state == STATE_IN_PROCESS || state == STATE_DONE)) {
197
return mechContext.getCredDelegState();
198
} else {
199
return credDelegState;
200
}
201
}
202
203
/**
204
* Requests that mutual authentication be done during context
205
* establishment. Since this is fromm the client's perspective, it
206
* essentially requests that the server be authenticated.
207
*/
208
public final void requestMutualAuth(boolean value) throws GSSException {
209
if (state == STATE_NEW && isInitiator()) {
210
mutualAuthState = value;
211
}
212
}
213
214
/**
215
* Is mutual authentication enabled? Since this is from the client's
216
* perspective, it essentially meas that the server is being
217
* authenticated.
218
*/
219
public final boolean getMutualAuthState() {
220
return mutualAuthState;
221
}
222
223
/**
224
* Returns the mechanism oid.
225
*
226
* @return the Oid of this context
227
*/
228
public final Oid getMech() {
229
if (isEstablished()) {
230
return getNegotiatedMech();
231
}
232
return (SpNegoMechFactory.GSS_SPNEGO_MECH_OID);
233
}
234
235
public final Oid getNegotiatedMech() {
236
return (internal_mech);
237
}
238
239
public final Provider getProvider() {
240
return SpNegoMechFactory.PROVIDER;
241
}
242
243
public final void dispose() throws GSSException {
244
mechContext = null;
245
state = STATE_DELETED;
246
}
247
248
/**
249
* Tests if this is the initiator side of the context.
250
*
251
* @return boolean indicating if this is initiator (true)
252
* or target (false)
253
*/
254
public final boolean isInitiator() {
255
return initiator;
256
}
257
258
/**
259
* Tests if the context can be used for per-message service.
260
* Context may allow the calls to the per-message service
261
* functions before being fully established.
262
*
263
* @return boolean indicating if per-message methods can
264
* be called.
265
*/
266
public final boolean isProtReady() {
267
return (state == STATE_DONE);
268
}
269
270
/**
271
* Initiator context establishment call. This method may be
272
* required to be called several times. A CONTINUE_NEEDED return
273
* call indicates that more calls are needed after the next token
274
* is received from the peer.
275
*
276
* @param is contains the token received from the peer. On the
277
* first call it will be ignored.
278
* @return any token required to be sent to the peer
279
* It is responsibility of the caller to send the token
280
* to its peer for processing.
281
* @exception GSSException
282
*/
283
@Deprecated(since="11")
284
public final byte[] initSecContext(InputStream is, int mechTokenSize)
285
throws GSSException {
286
287
byte[] retVal = null;
288
NegTokenInit initToken = null;
289
byte[] mechToken = null;
290
int errorCode = GSSException.FAILURE;
291
292
if (DEBUG) {
293
System.out.println("Entered SpNego.initSecContext with " +
294
"state=" + printState(state));
295
}
296
if (!isInitiator()) {
297
throw new GSSException(GSSException.FAILURE, -1,
298
"initSecContext on an acceptor GSSContext");
299
}
300
301
try {
302
if (state == STATE_NEW) {
303
state = STATE_IN_PROCESS;
304
305
errorCode = GSSException.NO_CRED;
306
307
// determine available mech set
308
Oid[] mechList = getAvailableMechs();
309
DER_mechTypes = getEncodedMechs(mechList);
310
311
// pull out first mechanism
312
internal_mech = mechList[0];
313
314
// get the token for first mechanism
315
mechToken = GSS_initSecContext(null);
316
317
errorCode = GSSException.DEFECTIVE_TOKEN;
318
// generate SPNEGO token
319
initToken = new NegTokenInit(DER_mechTypes, getContextFlags(),
320
mechToken, null);
321
if (DEBUG) {
322
System.out.println("SpNegoContext.initSecContext: " +
323
"sending token of type = " +
324
SpNegoToken.getTokenName(initToken.getType()));
325
}
326
// get the encoded token
327
retVal = initToken.getEncoded();
328
329
} else if (state == STATE_IN_PROCESS) {
330
331
errorCode = GSSException.FAILURE;
332
if (is == null) {
333
throw new GSSException(errorCode, -1,
334
"No token received from peer!");
335
}
336
337
errorCode = GSSException.DEFECTIVE_TOKEN;
338
byte[] server_token = new byte[is.available()];
339
SpNegoToken.readFully(is, server_token);
340
if (DEBUG) {
341
System.out.println("SpNegoContext.initSecContext: " +
342
"process received token = " +
343
SpNegoToken.getHexBytes(server_token));
344
}
345
346
// read the SPNEGO token
347
// token will be validated when parsing
348
NegTokenTarg targToken = new NegTokenTarg(server_token);
349
350
if (DEBUG) {
351
System.out.println("SpNegoContext.initSecContext: " +
352
"received token of type = " +
353
SpNegoToken.getTokenName(targToken.getType()));
354
}
355
356
// pull out mechanism
357
internal_mech = targToken.getSupportedMech();
358
if (internal_mech == null) {
359
// return with failure
360
throw new GSSException(errorCode, -1,
361
"supported mechanism from server is null");
362
}
363
364
// get the negotiated result
365
SpNegoToken.NegoResult negoResult = null;
366
int result = targToken.getNegotiatedResult();
367
switch (result) {
368
case 0:
369
negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;
370
state = STATE_DONE;
371
break;
372
case 1:
373
negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;
374
state = STATE_IN_PROCESS;
375
break;
376
case 2:
377
negoResult = SpNegoToken.NegoResult.REJECT;
378
state = STATE_DELETED;
379
break;
380
default:
381
state = STATE_DONE;
382
break;
383
}
384
385
errorCode = GSSException.BAD_MECH;
386
387
if (negoResult == SpNegoToken.NegoResult.REJECT) {
388
throw new GSSException(errorCode, -1,
389
internal_mech.toString());
390
}
391
392
errorCode = GSSException.DEFECTIVE_TOKEN;
393
394
if ((negoResult == SpNegoToken.NegoResult.ACCEPT_COMPLETE) ||
395
(negoResult == SpNegoToken.NegoResult.ACCEPT_INCOMPLETE)) {
396
397
// pull out the mechanism token
398
byte[] accept_token = targToken.getResponseToken();
399
if (accept_token == null) {
400
if (!isMechContextEstablished()) {
401
// return with failure
402
throw new GSSException(errorCode, -1,
403
"mechanism token from server is null");
404
}
405
} else {
406
mechToken = GSS_initSecContext(accept_token);
407
}
408
// verify MIC
409
if (!GSSUtil.useMSInterop()) {
410
byte[] micToken = targToken.getMechListMIC();
411
if (!verifyMechListMIC(DER_mechTypes, micToken)) {
412
throw new GSSException(errorCode, -1,
413
"verification of MIC on MechList Failed!");
414
}
415
}
416
if (isMechContextEstablished()) {
417
state = STATE_DONE;
418
retVal = mechToken;
419
if (DEBUG) {
420
System.out.println("SPNEGO Negotiated Mechanism = "
421
+ internal_mech + " " +
422
GSSUtil.getMechStr(internal_mech));
423
}
424
} else {
425
// generate SPNEGO token
426
initToken = new NegTokenInit(null, null,
427
mechToken, null);
428
if (DEBUG) {
429
System.out.println("SpNegoContext.initSecContext:" +
430
" continue sending token of type = " +
431
SpNegoToken.getTokenName(initToken.getType()));
432
}
433
// get the encoded token
434
retVal = initToken.getEncoded();
435
}
436
}
437
438
} else {
439
// XXX Use logging API
440
if (DEBUG) {
441
System.out.println(state);
442
}
443
}
444
if (DEBUG) {
445
if (retVal != null) {
446
System.out.println("SNegoContext.initSecContext: " +
447
"sending token = " + SpNegoToken.getHexBytes(retVal));
448
}
449
}
450
} catch (GSSException e) {
451
GSSException gssException =
452
new GSSException(errorCode, -1, e.getMessage());
453
gssException.initCause(e);
454
throw gssException;
455
} catch (IOException e) {
456
GSSException gssException =
457
new GSSException(GSSException.FAILURE, -1, e.getMessage());
458
gssException.initCause(e);
459
throw gssException;
460
}
461
462
return retVal;
463
}
464
465
466
/**
467
* Acceptor's context establishment call. This method may be
468
* required to be called several times. A CONTINUE_NEEDED return
469
* call indicates that more calls are needed after the next token
470
* is received from the peer.
471
*
472
* @param is contains the token received from the peer.
473
* @return any token required to be sent to the peer
474
* It is responsibility of the caller to send the token
475
* to its peer for processing.
476
* @exception GSSException
477
*/
478
@Deprecated(since="11")
479
public final byte[] acceptSecContext(InputStream is, int mechTokenSize)
480
throws GSSException {
481
482
byte[] retVal = null;
483
SpNegoToken.NegoResult negoResult;
484
boolean valid = true;
485
486
if (DEBUG) {
487
System.out.println("Entered SpNegoContext.acceptSecContext with " +
488
"state=" + printState(state));
489
}
490
491
if (isInitiator()) {
492
throw new GSSException(GSSException.FAILURE, -1,
493
"acceptSecContext on an initiator " +
494
"GSSContext");
495
}
496
try {
497
if (state == STATE_NEW) {
498
state = STATE_IN_PROCESS;
499
500
// read data
501
byte[] token = new byte[is.available()];
502
SpNegoToken.readFully(is, token);
503
if (DEBUG) {
504
System.out.println("SpNegoContext.acceptSecContext: " +
505
"receiving token = " +
506
SpNegoToken.getHexBytes(token));
507
}
508
509
// read the SPNEGO token
510
// token will be validated when parsing
511
NegTokenInit initToken = new NegTokenInit(token);
512
513
if (DEBUG) {
514
System.out.println("SpNegoContext.acceptSecContext: " +
515
"received token of type = " +
516
SpNegoToken.getTokenName(initToken.getType()));
517
}
518
519
Oid[] mechList = initToken.getMechTypeList();
520
DER_mechTypes = initToken.getMechTypes();
521
if (DER_mechTypes == null) {
522
valid = false;
523
}
524
525
/*
526
* Select the best match between the list of mechs
527
* that the initiator requested and the list that
528
* the acceptor will support.
529
*/
530
Oid[] supported_mechSet = getAvailableMechs();
531
Oid mech_wanted =
532
negotiate_mech_type(supported_mechSet, mechList);
533
if (mech_wanted == null) {
534
valid = false;
535
}
536
// save the desired mechanism
537
internal_mech = mech_wanted;
538
539
// get the token for mechanism
540
byte[] accept_token;
541
542
if (mechList[0].equals(mech_wanted) ||
543
(GSSUtil.isKerberosMech(mechList[0]) &&
544
GSSUtil.isKerberosMech(mech_wanted))) {
545
// get the mechanism token
546
if (DEBUG && !mech_wanted.equals(mechList[0])) {
547
System.out.println("SpNegoContext.acceptSecContext: " +
548
"negotiated mech adjusted to " + mechList[0]);
549
}
550
byte[] mechToken = initToken.getMechToken();
551
if (mechToken == null) {
552
throw new GSSException(GSSException.FAILURE, -1,
553
"mechToken is missing");
554
}
555
accept_token = GSS_acceptSecContext(mechToken);
556
mech_wanted = mechList[0];
557
} else {
558
accept_token = null;
559
}
560
561
// verify MIC
562
if (!GSSUtil.useMSInterop() && valid) {
563
valid = verifyMechListMIC(DER_mechTypes,
564
initToken.getMechListMIC());
565
}
566
567
// determine negotiated result status
568
if (valid) {
569
if (isMechContextEstablished()) {
570
negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;
571
state = STATE_DONE;
572
// now set the context flags for acceptor
573
setContextFlags();
574
// print the negotiated mech info
575
if (DEBUG) {
576
System.out.println("SPNEGO Negotiated Mechanism = "
577
+ internal_mech + " " +
578
GSSUtil.getMechStr(internal_mech));
579
}
580
} else {
581
negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;
582
state = STATE_IN_PROCESS;
583
}
584
} else {
585
negoResult = SpNegoToken.NegoResult.REJECT;
586
state = STATE_DELETED;
587
throw new GSSException(GSSException.FAILURE);
588
}
589
590
if (DEBUG) {
591
System.out.println("SpNegoContext.acceptSecContext: " +
592
"mechanism wanted = " + mech_wanted);
593
System.out.println("SpNegoContext.acceptSecContext: " +
594
"negotiated result = " + negoResult);
595
}
596
597
// generate SPNEGO token
598
NegTokenTarg targToken = new NegTokenTarg(negoResult.ordinal(),
599
mech_wanted, accept_token, null);
600
if (DEBUG) {
601
System.out.println("SpNegoContext.acceptSecContext: " +
602
"sending token of type = " +
603
SpNegoToken.getTokenName(targToken.getType()));
604
}
605
// get the encoded token
606
retVal = targToken.getEncoded();
607
608
} else if (state == STATE_IN_PROCESS) {
609
// read data
610
byte[] token = new byte[is.available()];
611
SpNegoToken.readFully(is, token);
612
if (DEBUG) {
613
System.out.println("SpNegoContext.acceptSecContext: " +
614
"receiving token = " +
615
SpNegoToken.getHexBytes(token));
616
}
617
618
// read the SPNEGO token
619
// token will be validated when parsing
620
NegTokenTarg inputToken = new NegTokenTarg(token);
621
622
if (DEBUG) {
623
System.out.println("SpNegoContext.acceptSecContext: " +
624
"received token of type = " +
625
SpNegoToken.getTokenName(inputToken.getType()));
626
}
627
628
// read the token
629
byte[] client_token = inputToken.getResponseToken();
630
byte[] accept_token = GSS_acceptSecContext(client_token);
631
if (accept_token == null) {
632
valid = false;
633
}
634
635
// determine negotiated result status
636
if (valid) {
637
if (isMechContextEstablished()) {
638
negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;
639
state = STATE_DONE;
640
} else {
641
negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;
642
state = STATE_IN_PROCESS;
643
}
644
} else {
645
negoResult = SpNegoToken.NegoResult.REJECT;
646
state = STATE_DELETED;
647
throw new GSSException(GSSException.FAILURE);
648
}
649
650
// generate SPNEGO token
651
NegTokenTarg targToken = new NegTokenTarg(negoResult.ordinal(),
652
null, accept_token, null);
653
if (DEBUG) {
654
System.out.println("SpNegoContext.acceptSecContext: " +
655
"sending token of type = " +
656
SpNegoToken.getTokenName(targToken.getType()));
657
}
658
// get the encoded token
659
retVal = targToken.getEncoded();
660
661
} else {
662
// XXX Use logging API
663
if (DEBUG) {
664
System.out.println("AcceptSecContext: state = " + state);
665
}
666
}
667
if (DEBUG) {
668
System.out.println("SpNegoContext.acceptSecContext: " +
669
"sending token = " + SpNegoToken.getHexBytes(retVal));
670
}
671
} catch (IOException e) {
672
GSSException gssException =
673
new GSSException(GSSException.FAILURE, -1, e.getMessage());
674
gssException.initCause(e);
675
throw gssException;
676
}
677
678
if (state == STATE_DONE) {
679
// now set the context flags for acceptor
680
setContextFlags();
681
}
682
return retVal;
683
}
684
685
/**
686
* obtain the available mechanisms
687
*/
688
private Oid[] getAvailableMechs() {
689
if (myCred != null) {
690
Oid[] mechs = new Oid[1];
691
mechs[0] = myCred.getInternalMech();
692
return mechs;
693
} else {
694
return factory.availableMechs;
695
}
696
}
697
698
/**
699
* get the DER encoded MechList
700
*/
701
private byte[] getEncodedMechs(Oid[] mechSet)
702
throws IOException, GSSException {
703
704
DerOutputStream mech = new DerOutputStream();
705
for (int i = 0; i < mechSet.length; i++) {
706
byte[] mechType = mechSet[i].getDER();
707
mech.write(mechType);
708
}
709
// insert in SEQUENCE
710
DerOutputStream mechTypeList = new DerOutputStream();
711
mechTypeList.write(DerValue.tag_Sequence, mech);
712
byte[] encoded = mechTypeList.toByteArray();
713
return encoded;
714
}
715
716
/**
717
* get the context flags
718
*/
719
private BitArray getContextFlags() {
720
BitArray out = new BitArray(7);
721
722
if (getCredDelegState()) out.set(0, true);
723
if (getMutualAuthState()) out.set(1, true);
724
if (getReplayDetState()) out.set(2, true);
725
if (getSequenceDetState()) out.set(3, true);
726
if (getConfState()) out.set(5, true);
727
if (getIntegState()) out.set(6, true);
728
729
return out;
730
}
731
732
// Only called on acceptor side. On the initiator side, most flags
733
// are already set at request. For those that might get chanegd,
734
// state from mech below is used.
735
private void setContextFlags() {
736
737
if (mechContext != null) {
738
// default for cred delegation is false
739
if (mechContext.getCredDelegState()) {
740
credDelegState = true;
741
}
742
// default for the following are true
743
if (!mechContext.getMutualAuthState()) {
744
mutualAuthState = false;
745
}
746
if (!mechContext.getReplayDetState()) {
747
replayDetState = false;
748
}
749
if (!mechContext.getSequenceDetState()) {
750
sequenceDetState = false;
751
}
752
if (!mechContext.getIntegState()) {
753
integState = false;
754
}
755
if (!mechContext.getConfState()) {
756
confState = false;
757
}
758
}
759
}
760
761
/**
762
* generate MIC on mechList. Not used at the moment.
763
*/
764
/*private byte[] generateMechListMIC(byte[] mechTypes)
765
throws GSSException {
766
767
// sanity check the required input
768
if (mechTypes == null) {
769
if (DEBUG) {
770
System.out.println("SpNegoContext: no MIC token included");
771
}
772
return null;
773
}
774
775
// check if mechanism supports integrity
776
if (!mechContext.getIntegState()) {
777
if (DEBUG) {
778
System.out.println("SpNegoContext: no MIC token included" +
779
" - mechanism does not support integrity");
780
}
781
return null;
782
}
783
784
// compute MIC on DER encoded mechanism list
785
byte[] mic = null;
786
try {
787
MessageProp prop = new MessageProp(0, true);
788
mic = getMIC(mechTypes, 0, mechTypes.length, prop);
789
if (DEBUG) {
790
System.out.println("SpNegoContext: getMIC = " +
791
SpNegoToken.getHexBytes(mic));
792
}
793
} catch (GSSException e) {
794
mic = null;
795
if (DEBUG) {
796
System.out.println("SpNegoContext: no MIC token included" +
797
" - getMIC failed : " + e.getMessage());
798
}
799
}
800
return mic;
801
}*/
802
803
/**
804
* verify MIC on MechList
805
*/
806
private boolean verifyMechListMIC(byte[] mechTypes, byte[] token)
807
throws GSSException {
808
809
// sanity check the input
810
if (token == null) {
811
if (DEBUG) {
812
System.out.println("SpNegoContext: no MIC token validation");
813
}
814
return true;
815
}
816
817
// check if mechanism supports integrity
818
if (!mechContext.getIntegState()) {
819
if (DEBUG) {
820
System.out.println("SpNegoContext: no MIC token validation" +
821
" - mechanism does not support integrity");
822
}
823
return true;
824
}
825
826
// now verify the token
827
boolean valid = false;
828
try {
829
MessageProp prop = new MessageProp(0, true);
830
verifyMIC(token, 0, token.length, mechTypes,
831
0, mechTypes.length, prop);
832
valid = true;
833
} catch (GSSException e) {
834
valid = false;
835
if (DEBUG) {
836
System.out.println("SpNegoContext: MIC validation failed! " +
837
e.getMessage());
838
}
839
}
840
return valid;
841
}
842
843
/**
844
* call gss_init_sec_context for the corresponding underlying mechanism
845
*/
846
private byte[] GSS_initSecContext(byte[] token) throws GSSException {
847
byte[] tok = null;
848
849
if (mechContext == null) {
850
// initialize mech context
851
GSSName serverName =
852
factory.manager.createName(peerName.toString(),
853
peerName.getStringNameType(), internal_mech);
854
GSSCredential cred = null;
855
if (myCred != null) {
856
// create context with provided credential
857
cred = new GSSCredentialImpl(factory.manager,
858
myCred.getInternalCred());
859
}
860
mechContext =
861
factory.manager.createContext(serverName,
862
internal_mech, cred, GSSContext.DEFAULT_LIFETIME);
863
mechContext.requestConf(confState);
864
mechContext.requestInteg(integState);
865
mechContext.requestCredDeleg(credDelegState);
866
mechContext.requestMutualAuth(mutualAuthState);
867
mechContext.requestReplayDet(replayDetState);
868
mechContext.requestSequenceDet(sequenceDetState);
869
mechContext.setChannelBinding(channelBinding);
870
if (mechContext instanceof GSSContextImpl) {
871
((GSSContextImpl)mechContext).requestDelegPolicy(
872
delegPolicyState);
873
}
874
}
875
876
// pass token
877
if (token != null) {
878
tok = token;
879
} else {
880
tok = new byte[0];
881
}
882
883
// pass token to mechanism initSecContext
884
byte[] init_token = mechContext.initSecContext(tok, 0, tok.length);
885
886
return init_token;
887
}
888
889
/**
890
* call gss_accept_sec_context for the corresponding underlying mechanism
891
*/
892
private byte[] GSS_acceptSecContext(byte[] token) throws GSSException {
893
894
if (mechContext == null) {
895
// initialize mech context
896
GSSCredential cred = null;
897
if (myCred != null) {
898
// create context with provided credential
899
cred = new GSSCredentialImpl(factory.manager,
900
myCred.getInternalCred());
901
}
902
mechContext = factory.manager.createContext(cred);
903
mechContext.setChannelBinding(channelBinding);
904
}
905
906
// pass token to mechanism acceptSecContext
907
byte[] accept_token =
908
mechContext.acceptSecContext(token, 0, token.length);
909
910
return accept_token;
911
}
912
913
/**
914
* This routine compares the received mechset to the mechset that
915
* this server can support. It looks sequentially through the mechset
916
* and the first one that matches what the server can support is
917
* chosen as the negotiated mechanism. If one is found, negResult
918
* is set to ACCEPT_COMPLETE, otherwise we return NULL and negResult
919
* is set to REJECT.
920
*/
921
private static Oid negotiate_mech_type(Oid[] supported_mechSet,
922
Oid[] mechSet) {
923
for (int i = 0; i < supported_mechSet.length; i++) {
924
for (int j = 0; j < mechSet.length; j++) {
925
if (mechSet[j].equals(supported_mechSet[i])) {
926
if (DEBUG) {
927
System.out.println("SpNegoContext: " +
928
"negotiated mechanism = " + mechSet[j]);
929
}
930
return (mechSet[j]);
931
}
932
}
933
}
934
return null;
935
}
936
937
public final boolean isEstablished() {
938
return (state == STATE_DONE);
939
}
940
941
public final boolean isMechContextEstablished() {
942
if (mechContext != null) {
943
return mechContext.isEstablished();
944
} else {
945
if (DEBUG) {
946
System.out.println("The underlying mechanism context has " +
947
"not been initialized");
948
}
949
return false;
950
}
951
}
952
953
public final byte [] export() throws GSSException {
954
throw new GSSException(GSSException.UNAVAILABLE, -1,
955
"GSS Export Context not available");
956
}
957
958
/**
959
* Sets the channel bindings to be used during context
960
* establishment.
961
*/
962
public final void setChannelBinding(ChannelBinding channelBinding)
963
throws GSSException {
964
this.channelBinding = channelBinding;
965
}
966
967
final ChannelBinding getChannelBinding() {
968
return channelBinding;
969
}
970
971
/*
972
* Anonymity is a little different in that after an application
973
* requests anonymity it will want to know whether the mechanism
974
* can support it or not, prior to sending any tokens across for
975
* context establishment. Since this is from the initiator's
976
* perspective, it essentially requests that the initiator be
977
* anonymous.
978
*/
979
public final void requestAnonymity(boolean value) throws GSSException {
980
// Ignore silently. Application will check back with
981
// getAnonymityState.
982
}
983
984
// RFC 2853 actually calls for this to be called after context
985
// establishment to get the right answer, but that is
986
// incorrect. The application may not want to send over any
987
// tokens if anonymity is not available.
988
public final boolean getAnonymityState() {
989
return false;
990
}
991
992
/**
993
* Requests the desired lifetime. Can only be used on the context
994
* initiator's side.
995
*/
996
public void requestLifetime(int lifetime) throws GSSException {
997
if (state == STATE_NEW && isInitiator())
998
this.lifetime = lifetime;
999
}
1000
1001
/**
1002
* The lifetime remaining for this context.
1003
*/
1004
public final int getLifetime() {
1005
if (mechContext != null) {
1006
return mechContext.getLifetime();
1007
} else {
1008
return GSSContext.INDEFINITE_LIFETIME;
1009
}
1010
}
1011
1012
public final boolean isTransferable() throws GSSException {
1013
return false;
1014
}
1015
1016
/**
1017
* Requests that sequence checking be done on the GSS wrap and MIC
1018
* tokens.
1019
*/
1020
public final void requestSequenceDet(boolean value) throws GSSException {
1021
if (state == STATE_NEW && isInitiator())
1022
sequenceDetState = value;
1023
}
1024
1025
/**
1026
* Is sequence checking enabled on the GSS Wrap and MIC tokens?
1027
* We enable sequence checking if replay detection is enabled.
1028
*/
1029
public final boolean getSequenceDetState() {
1030
return sequenceDetState || replayDetState;
1031
}
1032
1033
/**
1034
* Requests that replay detection be done on the GSS wrap and MIC
1035
* tokens.
1036
*/
1037
public final void requestReplayDet(boolean value) throws GSSException {
1038
if (state == STATE_NEW && isInitiator())
1039
replayDetState = value;
1040
}
1041
1042
/**
1043
* Is replay detection enabled on the GSS wrap and MIC tokens?
1044
* We enable replay detection if sequence checking is enabled.
1045
*/
1046
public final boolean getReplayDetState() {
1047
return replayDetState || sequenceDetState;
1048
}
1049
1050
public final GSSNameSpi getTargName() throws GSSException {
1051
// fill-in the GSSName
1052
// get the peer name for the mechanism
1053
if (mechContext != null) {
1054
GSSNameImpl targName = (GSSNameImpl)mechContext.getTargName();
1055
peerName = targName.getElement(internal_mech);
1056
return peerName;
1057
} else {
1058
if (DEBUG) {
1059
System.out.println("The underlying mechanism context has " +
1060
"not been initialized");
1061
}
1062
return null;
1063
}
1064
}
1065
1066
public final GSSNameSpi getSrcName() throws GSSException {
1067
// fill-in the GSSName
1068
// get the src name for the mechanism
1069
if (mechContext != null) {
1070
GSSNameImpl srcName = (GSSNameImpl)mechContext.getSrcName();
1071
myName = srcName.getElement(internal_mech);
1072
return myName;
1073
} else {
1074
if (DEBUG) {
1075
System.out.println("The underlying mechanism context has " +
1076
"not been initialized");
1077
}
1078
return null;
1079
}
1080
}
1081
1082
/**
1083
* Returns the delegated credential for the context. This
1084
* is an optional feature of contexts which not all
1085
* mechanisms will support. A context can be requested to
1086
* support credential delegation by using the <b>CRED_DELEG</b>.
1087
* This is only valid on the acceptor side of the context.
1088
* @return GSSCredentialSpi object for the delegated credential
1089
* @exception GSSException
1090
* @see GSSContext#getCredDelegState
1091
*/
1092
public final GSSCredentialSpi getDelegCred() throws GSSException {
1093
if (state != STATE_IN_PROCESS && state != STATE_DONE)
1094
throw new GSSException(GSSException.NO_CONTEXT);
1095
if (mechContext != null) {
1096
GSSCredentialImpl delegCred =
1097
(GSSCredentialImpl)mechContext.getDelegCred();
1098
if (delegCred == null) {
1099
return null;
1100
}
1101
// determine delegated cred element usage
1102
boolean initiate = false;
1103
if (delegCred.getUsage() == GSSCredential.INITIATE_ONLY) {
1104
initiate = true;
1105
}
1106
GSSCredentialSpi mechCred =
1107
delegCred.getElement(internal_mech, initiate);
1108
SpNegoCredElement cred = new SpNegoCredElement(mechCred);
1109
return cred.getInternalCred();
1110
} else {
1111
throw new GSSException(GSSException.NO_CONTEXT, -1,
1112
"getDelegCred called in invalid state!");
1113
}
1114
}
1115
1116
public final int getWrapSizeLimit(int qop, boolean confReq,
1117
int maxTokSize) throws GSSException {
1118
if (mechContext != null) {
1119
return mechContext.getWrapSizeLimit(qop, confReq, maxTokSize);
1120
} else {
1121
throw new GSSException(GSSException.NO_CONTEXT, -1,
1122
"getWrapSizeLimit called in invalid state!");
1123
}
1124
}
1125
1126
public final byte[] wrap(byte inBuf[], int offset, int len,
1127
MessageProp msgProp) throws GSSException {
1128
if (mechContext != null) {
1129
return mechContext.wrap(inBuf, offset, len, msgProp);
1130
} else {
1131
throw new GSSException(GSSException.NO_CONTEXT, -1,
1132
"Wrap called in invalid state!");
1133
}
1134
}
1135
1136
@Deprecated(since="11")
1137
public final void wrap(InputStream is, OutputStream os,
1138
MessageProp msgProp) throws GSSException {
1139
if (mechContext != null) {
1140
mechContext.wrap(is, os, msgProp);
1141
} else {
1142
throw new GSSException(GSSException.NO_CONTEXT, -1,
1143
"Wrap called in invalid state!");
1144
}
1145
}
1146
1147
public final byte[] unwrap(byte inBuf[], int offset, int len,
1148
MessageProp msgProp)
1149
throws GSSException {
1150
if (mechContext != null) {
1151
return mechContext.unwrap(inBuf, offset, len, msgProp);
1152
} else {
1153
throw new GSSException(GSSException.NO_CONTEXT, -1,
1154
"UnWrap called in invalid state!");
1155
}
1156
}
1157
1158
@Deprecated(since="11")
1159
public final void unwrap(InputStream is, OutputStream os,
1160
MessageProp msgProp) throws GSSException {
1161
if (mechContext != null) {
1162
mechContext.unwrap(is, os, msgProp);
1163
} else {
1164
throw new GSSException(GSSException.NO_CONTEXT, -1,
1165
"UnWrap called in invalid state!");
1166
}
1167
}
1168
1169
public final byte[] getMIC(byte []inMsg, int offset, int len,
1170
MessageProp msgProp)
1171
throws GSSException {
1172
if (mechContext != null) {
1173
return mechContext.getMIC(inMsg, offset, len, msgProp);
1174
} else {
1175
throw new GSSException(GSSException.NO_CONTEXT, -1,
1176
"getMIC called in invalid state!");
1177
}
1178
}
1179
1180
@Deprecated(since="11")
1181
public final void getMIC(InputStream is, OutputStream os,
1182
MessageProp msgProp) throws GSSException {
1183
if (mechContext != null) {
1184
mechContext.getMIC(is, os, msgProp);
1185
} else {
1186
throw new GSSException(GSSException.NO_CONTEXT, -1,
1187
"getMIC called in invalid state!");
1188
}
1189
}
1190
1191
public final void verifyMIC(byte []inTok, int tokOffset, int tokLen,
1192
byte[] inMsg, int msgOffset, int msgLen,
1193
MessageProp msgProp)
1194
throws GSSException {
1195
if (mechContext != null) {
1196
mechContext.verifyMIC(inTok, tokOffset, tokLen, inMsg, msgOffset,
1197
msgLen, msgProp);
1198
} else {
1199
throw new GSSException(GSSException.NO_CONTEXT, -1,
1200
"verifyMIC called in invalid state!");
1201
}
1202
}
1203
1204
@Deprecated(since="11")
1205
public final void verifyMIC(InputStream is, InputStream msgStr,
1206
MessageProp msgProp) throws GSSException {
1207
if (mechContext != null) {
1208
mechContext.verifyMIC(is, msgStr, msgProp);
1209
} else {
1210
throw new GSSException(GSSException.NO_CONTEXT, -1,
1211
"verifyMIC called in invalid state!");
1212
}
1213
}
1214
1215
private static String printState(int state) {
1216
switch (state) {
1217
case STATE_NEW:
1218
return ("STATE_NEW");
1219
case STATE_IN_PROCESS:
1220
return ("STATE_IN_PROCESS");
1221
case STATE_DONE:
1222
return ("STATE_DONE");
1223
case STATE_DELETED:
1224
return ("STATE_DELETED");
1225
default:
1226
return ("Unknown state " + state);
1227
}
1228
}
1229
1230
/**
1231
* Retrieve attribute of the context for {@code type}.
1232
*/
1233
public Object inquireSecContext(String type)
1234
throws GSSException {
1235
if (mechContext == null) {
1236
throw new GSSException(GSSException.NO_CONTEXT, -1,
1237
"Underlying mech not established.");
1238
}
1239
if (mechContext instanceof GSSContextImpl) {
1240
return ((GSSContextImpl)mechContext).inquireSecContext(type);
1241
} else {
1242
throw new GSSException(GSSException.BAD_MECH, -1,
1243
"inquireSecContext not supported by underlying mech.");
1244
}
1245
}
1246
}
1247
1248
1249