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