1 // Copyright (C) 2002 Microsoft Corporation 2 // All rights reserved. 3 // 4 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" 5 // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 6 // OR IMPLIED, INCLUDING BUT NOT LIMITED 7 // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY 8 // AND/OR FITNESS FOR A PARTICULAR PURPOSE. 9 // 10 // Date - 10/08/2002 11 // Author - Sanj Surati 12 13 ///////////////////////////////////////////////////////////// 14 // 15 // SPNEGOPARSE.C 16 // 17 // SPNEGO Token Handler Source File 18 // 19 // Contains implementation of SPNEGO Token parsing functions. 20 // 21 ///////////////////////////////////////////////////////////// 22 23 #include <stdlib.h> 24 #include <stdio.h> 25 #include <memory.h> 26 #include "spnego.h" 27 #include "derparse.h" 28 #include "spnegoparse.h" 29 30 // 31 // Defined in DERPARSE.C 32 // 33 34 extern MECH_OID g_stcMechOIDList []; 35 36 /**********************************************************************/ 37 /** **/ 38 /** **/ 39 /** **/ 40 /** **/ 41 /** Local SPNEGO Helper definitions **/ 42 /** **/ 43 /** **/ 44 /** **/ 45 /** **/ 46 /**********************************************************************/ 47 48 49 ///////////////////////////////////////////////////////////////////////////// 50 // 51 // Function: 52 // CalculateMinSpnegoInitTokenSize 53 // 54 // Parameters: 55 // [in] nMechTokenLength - Length of the MechToken Element 56 // [in] nMechListMICLength - Length of the MechListMIC Element 57 // [in] mechOID - OID for MechList 58 // [in] nReqFlagsAvailable - Is ContextFlags element available 59 // [out] pnTokenSize - Filled out with total size of token 60 // [out] pnInternalTokenLength - Filled out with length minus length 61 // for initial token. 62 // 63 // Returns: 64 // int Success - SPNEGO_E_SUCCESS 65 // Failure - SPNEGO API Error code 66 // 67 // Comments : 68 // Calculates the required length for a SPNEGO NegTokenInit token based 69 // on the supplied variable length values and which elements are present. 70 // Note that because the lengths can be represented by an arbitrary 71 // number of bytes in DER encodings, we actually calculate the lengths 72 // backwards, so we always know how many bytes we will potentially be 73 // writing out. 74 // 75 //////////////////////////////////////////////////////////////////////////// 76 77 int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, 78 long nMechListMICLength, SPNEGO_MECH_OID mechOid, 79 int nReqFlagsAvailable, long* pnTokenSize, 80 long* pnInternalTokenLength ) 81 { 82 int nReturn = SPNEGO_E_INVALID_LENGTH; 83 84 // Start at 0. 85 long nTotalLength = 0; 86 long nTempLength= 0L; 87 88 // We will calculate this by walking the token backwards 89 90 // Start with MIC Element 91 if ( nMechListMICLength > 0L ) 92 { 93 nTempLength = ASNDerCalcElementLength( nMechListMICLength, NULL ); 94 95 // Check for rollover error 96 if ( nTempLength < nMechListMICLength ) 97 { 98 goto xEndTokenInitLength; 99 } 100 101 nTotalLength += nTempLength; 102 } 103 104 // Next is the MechToken 105 if ( nMechTokenLength > 0L ) 106 { 107 nTempLength += ASNDerCalcElementLength( nMechTokenLength, NULL ); 108 109 // Check for rollover error 110 if ( nTempLength < nTotalLength ) 111 { 112 goto xEndTokenInitLength; 113 } 114 115 nTotalLength = nTempLength; 116 } 117 118 // Next is the ReqFlags 119 if ( nReqFlagsAvailable ) 120 { 121 nTempLength += ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, NULL ); 122 123 // Check for rollover error 124 if ( nTempLength < nTotalLength ) 125 { 126 goto xEndTokenInitLength; 127 } 128 129 nTotalLength = nTempLength; 130 } 131 132 // Next is the MechList - This is REQUIRED 133 nTempLength += ASNDerCalcMechListLength( mechOid, NULL ); 134 135 // Check for rollover error 136 if ( nTempLength < nTotalLength ) 137 { 138 goto xEndTokenInitLength; 139 } 140 141 nTotalLength = nTempLength; 142 143 // Following four fields are the basic header tokens 144 145 // Sequence Token 146 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); 147 148 // Check for rollover error 149 if ( nTempLength < nTotalLength ) 150 { 151 goto xEndTokenInitLength; 152 } 153 154 nTotalLength = nTempLength; 155 156 // Neg Token Identifier Token 157 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); 158 159 // Check for rollover error 160 if ( nTempLength < nTotalLength ) 161 { 162 goto xEndTokenInitLength; 163 } 164 165 nTotalLength = nTempLength; 166 167 // SPNEGO OID Token 168 nTempLength += g_stcMechOIDList[spnego_mech_oid_Spnego].iLen; 169 170 // Check for rollover error 171 if ( nTempLength < nTotalLength ) 172 { 173 goto xEndTokenInitLength; 174 } 175 176 nTotalLength = nTempLength; 177 178 // App Constructed Token 179 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); 180 181 // Check for rollover error 182 if ( nTempLength < nTotalLength ) 183 { 184 goto xEndTokenInitLength; 185 } 186 187 // The internal length doesn't include the number of bytes 188 // for the initial token 189 *pnInternalTokenLength = nTotalLength; 190 nTotalLength = nTempLength; 191 192 // We're done 193 *pnTokenSize = nTotalLength; 194 nReturn = SPNEGO_E_SUCCESS; 195 196 xEndTokenInitLength: 197 198 return nReturn; 199 200 } 201 202 ///////////////////////////////////////////////////////////////////////////// 203 // 204 // Function: 205 // CreateSpnegoInitToken 206 // 207 // Parameters: 208 // [in] MechType - OID in MechList 209 // [in] ucContextFlags - ContextFlags value 210 // [in] pbMechToken - Mech Token Binary Data 211 // [in] ulMechTokenLen - Length of Mech Token 212 // [in] pbMechListMIC - MechListMIC Binary Data 213 // [in] ulMechListMICn - Length of MechListMIC 214 // [out] pbTokenData - Buffer to write token into. 215 // [in] nTokenLength - Length of pbTokenData buffer 216 // [in] nInternalTokenLength - Length of full token without leading 217 // token bytes. 218 // 219 // Returns: 220 // int Success - SPNEGO_E_SUCCESS 221 // Failure - SPNEGO API Error code 222 // 223 // Comments : 224 // Uses DER to fill out pbTokenData with a SPNEGO NegTokenInit Token 225 // Note that because the lengths can be represented by an arbitrary 226 // number of bytes in DER encodings, we actually calculate the lengths 227 // backwards, so we always know how many bytes we will potentially be 228 // writing out. 229 // 230 //////////////////////////////////////////////////////////////////////////// 231 232 int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType, 233 unsigned char ucContextFlags, unsigned char* pbMechToken, 234 unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, 235 unsigned long ulMechListMICLen, unsigned char* pbTokenData, 236 long nTokenLength, long nInternalTokenLength ) 237 { 238 int nReturn = SPNEGO_E_INVALID_LENGTH; 239 240 // Start at 0. 241 long nTempLength= 0L; 242 long nTotalBytesWritten = 0L; 243 long nInternalLength = 0L; 244 245 unsigned char* pbWriteTokenData = pbTokenData + nTokenLength; 246 247 // Temporary buffer to hold the REQ Flags as BIT String Data 248 unsigned char abTempReqFlags[SPNEGO_NEGINIT_MAXLEN_REQFLAGS]; 249 250 251 // We will write the token out backwards to properly handle the cases 252 // where the length bytes become adjustable 253 254 // Start with MIC Element 255 if ( ulMechListMICLen > 0L ) 256 { 257 nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength ); 258 259 // Decrease the pbWriteTokenData, now we know the length and 260 // write it out. 261 262 pbWriteTokenData -= nTempLength; 263 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC, 264 OCTETSTRING, pbMechListMIC, ulMechListMICLen ); 265 266 // Adjust Values and sanity check 267 nTotalBytesWritten += nTempLength; 268 nInternalTokenLength -= nTempLength; 269 270 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 271 { 272 goto xEndWriteNegTokenInit; 273 } 274 275 } // IF MechListMIC is present 276 277 // Next is the MechToken 278 if ( ulMechTokenLen > 0L ) 279 { 280 nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength ); 281 282 // Decrease the pbWriteTokenData, now we know the length and 283 // write it out. 284 pbWriteTokenData -= nTempLength; 285 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, 286 OCTETSTRING, pbMechToken, ulMechTokenLen ); 287 // Adjust Values and sanity check 288 nTotalBytesWritten += nTempLength; 289 nInternalTokenLength -= nTempLength; 290 291 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 292 { 293 goto xEndWriteNegTokenInit; 294 } 295 296 } // IF MechToken Length is present 297 298 // Next is the ReqFlags 299 if ( ucContextFlags > 0L ) 300 { 301 302 nTempLength = ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, &nInternalLength ); 303 304 // We need a byte that indicates how many bits difference between the number 305 // of bits used in final octet (we only have one) and the max (8) 306 307 abTempReqFlags[0] = SPNEGO_NEGINIT_REQFLAGS_BITDIFF; 308 abTempReqFlags[1] = ucContextFlags; 309 310 // Decrease the pbWriteTokenData, now we know the length and 311 // write it out. 312 pbWriteTokenData -= nTempLength; 313 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_REQFLAGS, 314 BITSTRING, abTempReqFlags, SPNEGO_NEGINIT_MAXLEN_REQFLAGS ); 315 316 // Adjust Values and sanity check 317 nTotalBytesWritten += nTempLength; 318 nInternalTokenLength -= nTempLength; 319 320 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 321 { 322 goto xEndWriteNegTokenInit; 323 } 324 325 } // IF ContextFlags 326 327 // Next is the MechList - This is REQUIRED 328 nTempLength = ASNDerCalcMechListLength( MechType, &nInternalLength ); 329 330 // Decrease the pbWriteTokenData, now we know the length and 331 // write it out. 332 pbWriteTokenData -= nTempLength; 333 nTempLength = ASNDerWriteMechList( pbWriteTokenData, MechType ); 334 335 // Adjust Values and sanity check 336 nTotalBytesWritten += nTempLength; 337 nInternalTokenLength -= nTempLength; 338 339 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 340 { 341 goto xEndWriteNegTokenInit; 342 } 343 344 // The next tokens we're writing out reflect the total number of bytes 345 // we have actually written out. 346 347 // Sequence Token 348 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); 349 350 // Decrease the pbWriteTokenData, now we know the length and 351 // write it out. 352 pbWriteTokenData -= nTempLength; 353 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, 354 NULL, nTotalBytesWritten ); 355 356 // Adjust Values and sanity check 357 nTotalBytesWritten += nTempLength; 358 nInternalTokenLength -= nTempLength; 359 360 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 361 { 362 goto xEndWriteNegTokenInit; 363 } 364 365 // Neg Init Token Identifier Token 366 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); 367 368 // Decrease the pbWriteTokenData, now we know the length and 369 // write it out. 370 pbWriteTokenData -= nTempLength; 371 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER, 372 NULL, nTotalBytesWritten ); 373 374 // Adjust Values and sanity check 375 nTotalBytesWritten += nTempLength; 376 nInternalTokenLength -= nTempLength; 377 378 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 379 { 380 goto xEndWriteNegTokenInit; 381 } 382 383 // SPNEGO OID Token 384 nTempLength = g_stcMechOIDList[spnego_mech_oid_Spnego].iLen; 385 386 // Decrease the pbWriteTokenData, now we know the length and 387 // write it out. 388 pbWriteTokenData -= nTempLength; 389 nTempLength = ASNDerWriteOID( pbWriteTokenData, spnego_mech_oid_Spnego ); 390 391 // Adjust Values and sanity check 392 nTotalBytesWritten += nTempLength; 393 nInternalTokenLength -= nTempLength; 394 395 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 396 { 397 goto xEndWriteNegTokenInit; 398 } 399 400 // App Constructed Token 401 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); 402 403 // Decrease the pbWriteTokenData, now we know the length and 404 // write it out. 405 pbWriteTokenData -= nTempLength; 406 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, 407 NULL, nTotalBytesWritten ); 408 409 // Adjust Values and sanity check 410 nTotalBytesWritten += nTempLength; 411 412 // Don't adjust the internal token length here, it doesn't account 413 // the initial bytes written out (we really don't need to keep 414 // a running count here, but for debugging, it helps to be able 415 // to see the total number of bytes written out as well as the 416 // number of bytes left to write). 417 418 if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 && 419 pbWriteTokenData == pbTokenData ) 420 { 421 nReturn = SPNEGO_E_SUCCESS; 422 } 423 424 xEndWriteNegTokenInit: 425 426 return nReturn; 427 428 } 429 430 ///////////////////////////////////////////////////////////////////////////// 431 // 432 // Function: 433 // CalculateMinSpnegoTargTokenSize 434 // 435 // Parameters: 436 // [in] MechType - Supported MechType 437 // [in] spnegoNegResult - Neg Result 438 // [in] nMechTokenLength - Length of the MechToken Element 439 // [in] nMechListMICLength - Length of the MechListMIC Element 440 // [out] pnTokenSize - Filled out with total size of token 441 // [out] pnInternalTokenLength - Filled out with length minus length 442 // for initial token. 443 // 444 // Returns: 445 // int Success - SPNEGO_E_SUCCESS 446 // Failure - SPNEGO API Error code 447 // 448 // Comments : 449 // Calculates the required length for a SPNEGO NegTokenTarg token based 450 // on the supplied variable length values and which elements are present. 451 // Note that because the lengths can be represented by an arbitrary 452 // number of bytes in DER encodings, we actually calculate the lengths 453 // backwards, so we always know how many bytes we will potentially be 454 // writing out. 455 // 456 //////////////////////////////////////////////////////////////////////////// 457 458 int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, 459 SPNEGO_NEGRESULT spnegoNegResult, long nMechTokenLen, 460 long nMechListMICLen, long* pnTokenSize, 461 long* pnInternalTokenLength ) 462 { 463 int nReturn = SPNEGO_E_INVALID_LENGTH; 464 465 // Start at 0. 466 long nTotalLength = 0; 467 long nTempLength= 0L; 468 469 // We will calculate this by walking the token backwards 470 471 // Start with MIC Element 472 if ( nMechListMICLen > 0L ) 473 { 474 nTempLength = ASNDerCalcElementLength( nMechListMICLen, NULL ); 475 476 // Check for rollover error 477 if ( nTempLength < nMechListMICLen ) 478 { 479 goto xEndTokenTargLength; 480 } 481 482 nTotalLength += nTempLength; 483 } 484 485 // Next is the MechToken 486 if ( nMechTokenLen > 0L ) 487 { 488 nTempLength += ASNDerCalcElementLength( nMechTokenLen, NULL ); 489 490 // Check for rollover error 491 if ( nTempLength < nTotalLength ) 492 { 493 goto xEndTokenTargLength; 494 } 495 496 nTotalLength = nTempLength; 497 } 498 499 // Supported MechType 500 if ( spnego_mech_oid_NotUsed != MechType ) 501 { 502 // Supported MechOID element - we use the token function since 503 // we already know the size of the OID token and value 504 nTempLength += ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen, 505 NULL ); 506 507 // Check for rollover error 508 if ( nTempLength < nTotalLength ) 509 { 510 goto xEndTokenTargLength; 511 } 512 513 nTotalLength = nTempLength; 514 515 } // IF MechType is available 516 517 // NegResult Element 518 if ( spnego_negresult_NotUsed != spnegoNegResult ) 519 { 520 nTempLength += ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, NULL ); 521 522 // Check for rollover error 523 if ( nTempLength < nTotalLength ) 524 { 525 goto xEndTokenTargLength; 526 } 527 528 nTotalLength = nTempLength; 529 530 } // IF negResult is available 531 532 // Following two fields are the basic header tokens 533 534 // Sequence Token 535 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); 536 537 // Check for rollover error 538 if ( nTempLength < nTotalLength ) 539 { 540 goto xEndTokenTargLength; 541 } 542 543 nTotalLength = nTempLength; 544 545 // Neg Token Identifier Token 546 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); 547 548 // Check for rollover error 549 if ( nTempLength < nTotalLength ) 550 { 551 goto xEndTokenTargLength; 552 } 553 554 // The internal length doesn't include the number of bytes 555 // for the initial token 556 *pnInternalTokenLength = nTotalLength; 557 nTotalLength = nTempLength; 558 559 // We're done 560 *pnTokenSize = nTotalLength; 561 nReturn = SPNEGO_E_SUCCESS; 562 563 xEndTokenTargLength: 564 565 return nReturn; 566 567 } 568 569 ///////////////////////////////////////////////////////////////////////////// 570 // 571 // Function: 572 // CreateSpnegoTargToken 573 // 574 // Parameters: 575 // [in] MechType - Supported MechType 576 // [in] eNegResult - NegResult value 577 // [in] pbMechToken - Mech Token Binary Data 578 // [in] ulMechTokenLen - Length of Mech Token 579 // [in] pbMechListMIC - MechListMIC Binary Data 580 // [in] ulMechListMICn - Length of MechListMIC 581 // [out] pbTokenData - Buffer to write token into. 582 // [in] nTokenLength - Length of pbTokenData buffer 583 // [in] nInternalTokenLength - Length of full token without leading 584 // token bytes. 585 // 586 // Returns: 587 // int Success - SPNEGO_E_SUCCESS 588 // Failure - SPNEGO API Error code 589 // 590 // Comments : 591 // Uses DER to fill out pbTokenData with a SPNEGO NegTokenTarg Token 592 // Note that because the lengths can be represented by an arbitrary 593 // number of bytes in DER encodings, we actually calculate the lengths 594 // backwards, so we always know how many bytes we will potentially be 595 // writing out. 596 // 597 //////////////////////////////////////////////////////////////////////////// 598 599 int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType, 600 SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken, 601 unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, 602 unsigned long ulMechListMICLen, unsigned char* pbTokenData, 603 long nTokenLength, long nInternalTokenLength ) 604 { 605 int nReturn = SPNEGO_E_INVALID_LENGTH; 606 607 // Start at 0. 608 long nTempLength= 0L; 609 long nTotalBytesWritten = 0L; 610 long nInternalLength = 0L; 611 612 unsigned char ucTemp = 0; 613 614 // We will write the token out backwards to properly handle the cases 615 // where the length bytes become adjustable, so the write location 616 // is initialized to point *just* past the end of the buffer. 617 618 unsigned char* pbWriteTokenData = pbTokenData + nTokenLength; 619 620 621 // Start with MIC Element 622 if ( ulMechListMICLen > 0L ) 623 { 624 nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength ); 625 626 // Decrease the pbWriteTokenData, now we know the length and 627 // write it out. 628 629 pbWriteTokenData -= nTempLength; 630 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC, 631 OCTETSTRING, pbMechListMIC, ulMechListMICLen ); 632 633 // Adjust Values and sanity check 634 nTotalBytesWritten += nTempLength; 635 nInternalTokenLength -= nTempLength; 636 637 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 638 { 639 goto xEndWriteNegTokenTarg; 640 } 641 642 } // IF MechListMIC is present 643 644 // Next is the MechToken 645 if ( ulMechTokenLen > 0L ) 646 { 647 nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength ); 648 649 // Decrease the pbWriteTokenData, now we know the length and 650 // write it out. 651 pbWriteTokenData -= nTempLength; 652 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, 653 OCTETSTRING, pbMechToken, ulMechTokenLen ); 654 // Adjust Values and sanity check 655 nTotalBytesWritten += nTempLength; 656 nInternalTokenLength -= nTempLength; 657 658 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 659 { 660 goto xEndWriteNegTokenTarg; 661 } 662 663 } // IF MechToken Length is present 664 665 // Supported Mech Type 666 if ( spnego_mech_oid_NotUsed != MechType ) 667 { 668 669 nTempLength = ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen, 670 &nInternalLength ); 671 672 // Decrease the pbWriteTokenData, now we know the length and 673 // write it out. 674 pbWriteTokenData -= nTempLength; 675 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH, 676 g_stcMechOIDList[MechType].ucOid, 677 g_stcMechOIDList[MechType].iLen ); 678 679 // Adjust Values and sanity check 680 nTotalBytesWritten += nTempLength; 681 nInternalTokenLength -= nTempLength; 682 683 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 684 { 685 goto xEndWriteNegTokenTarg; 686 } 687 688 } // IF MechType is present 689 690 // Neg Result 691 // NegResult Element 692 if ( spnego_negresult_NotUsed != eNegResult ) 693 { 694 ucTemp = (unsigned char) eNegResult; 695 696 nTempLength = ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, &nInternalLength ); 697 698 // Decrease the pbWriteTokenData, now we know the length and 699 // write it out. 700 pbWriteTokenData -= nTempLength; 701 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_NEGRESULT, 702 ENUMERATED, &ucTemp, SPNEGO_NEGTARG_MAXLEN_NEGRESULT ); 703 704 // Adjust Values and sanity check 705 nTotalBytesWritten += nTempLength; 706 nInternalTokenLength -= nTempLength; 707 708 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 709 { 710 goto xEndWriteNegTokenTarg; 711 } 712 713 } // If eNegResult is available 714 715 // The next tokens we're writing out reflect the total number of bytes 716 // we have actually written out. 717 718 // Sequence Token 719 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); 720 721 // Decrease the pbWriteTokenData, now we know the length and 722 // write it out. 723 pbWriteTokenData -= nTempLength; 724 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, 725 NULL, nTotalBytesWritten ); 726 727 // Adjust Values and sanity check 728 nTotalBytesWritten += nTempLength; 729 nInternalTokenLength -= nTempLength; 730 731 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) 732 { 733 goto xEndWriteNegTokenTarg; 734 } 735 736 // Neg Targ Token Identifier Token 737 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); 738 739 // Decrease the pbWriteTokenData, now we know the length and 740 // write it out. 741 pbWriteTokenData -= nTempLength; 742 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER, 743 NULL, nTotalBytesWritten ); 744 745 // Adjust Values and sanity check 746 nTotalBytesWritten += nTempLength; 747 748 // Don't adjust the internal token length here, it doesn't account 749 // the initial bytes written out (we really don't need to keep 750 // a running count here, but for debugging, it helps to be able 751 // to see the total number of bytes written out as well as the 752 // number of bytes left to write). 753 754 if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 && 755 pbWriteTokenData == pbTokenData ) 756 { 757 nReturn = SPNEGO_E_SUCCESS; 758 } 759 760 761 xEndWriteNegTokenTarg: 762 763 return nReturn; 764 765 766 } 767 768 769 ///////////////////////////////////////////////////////////////////////////// 770 // 771 // Function: 772 // AllocEmptySpnegoToken 773 // 774 // Parameters: 775 // [in] ucCopyData - Flag to copy data or pointer. 776 // [in] ulFlags - Flags for SPNEGO_TOKEN data member. 777 // [in] pbTokenData - Binary token data. 778 // [in] ulTokenSize - Size of pbTokenData. 779 // 780 // Returns: 781 // SPNEGO_TOKEN* Success - Pointer to initialized SPNEGO_TOKEN struct 782 // Failure - NULL 783 // 784 // Comments : 785 // Allocates a SPNEGO_TOKEN data structure and initializes it. Based on 786 // the value of ucCopyData, if non-zero, we copy the data into a buffer 787 // we allocate in this function, otherwise, we copy the data pointer 788 // direcly. 789 // 790 //////////////////////////////////////////////////////////////////////////// 791 792 SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags, 793 unsigned char * pbTokenData, unsigned long ulTokenSize ) 794 { 795 SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) calloc( 1, sizeof(SPNEGO_TOKEN) ); 796 797 if ( NULL != pSpnegoToken ) 798 { 799 // Set the token size 800 pSpnegoToken->nStructSize = SPNEGO_TOKEN_SIZE; 801 802 // Initialize the element array 803 InitSpnegoTokenElementArray( pSpnegoToken ); 804 805 // Assign the flags value 806 pSpnegoToken->ulFlags = ulFlags; 807 808 // 809 // IF ucCopyData is TRUE, we will allocate a buffer and copy data into it. 810 // Otherwise, we will just copy the pointer and the length. This is so we 811 // can cut out additional allocations for performance reasons 812 // 813 814 if ( SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA == ucCopyData ) 815 { 816 // Alloc the internal buffer. Cleanup on failure. 817 pSpnegoToken->pbBinaryData = (unsigned char*) calloc( ulTokenSize, sizeof(unsigned char) ); 818 819 if ( NULL != pSpnegoToken->pbBinaryData ) 820 { 821 // We must ALWAYS free this buffer 822 pSpnegoToken->ulFlags |= SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA; 823 824 // Copy the data locally 825 memcpy( pSpnegoToken->pbBinaryData, pbTokenData, ulTokenSize ); 826 pSpnegoToken->ulBinaryDataLen = ulTokenSize; 827 } 828 else 829 { 830 free( pSpnegoToken ); 831 pSpnegoToken = NULL; 832 } 833 834 } // IF ucCopyData 835 else 836 { 837 // Copy the pointer and the length directly - ulFlags will control whether or not 838 // we are allowed to free the value 839 840 pSpnegoToken->pbBinaryData = pbTokenData; 841 pSpnegoToken->ulBinaryDataLen = ulTokenSize; 842 } 843 844 } 845 846 return pSpnegoToken; 847 } 848 849 ///////////////////////////////////////////////////////////////////////////// 850 // 851 // Function: 852 // FreeSpnegoToken 853 // 854 // Parameters: 855 // [in] pSpnegoToken - Points to SPNEGO_TOKEN to free. 856 // 857 // Returns: 858 // void 859 // 860 // Comments : 861 // If non-NULL, interprets pSpnegoToken, freeing any internal allocations 862 // and finally the actual structure. 863 // 864 //////////////////////////////////////////////////////////////////////////// 865 866 void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ) 867 { 868 if ( NULL != pSpnegoToken ) 869 { 870 871 // Cleanup internal allocation per the flags 872 if ( pSpnegoToken->ulFlags & SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA && 873 NULL != pSpnegoToken->pbBinaryData ) 874 { 875 free( pSpnegoToken->pbBinaryData ); 876 pSpnegoToken->pbBinaryData = NULL; 877 } 878 879 free ( pSpnegoToken ); 880 } 881 } 882 883 ///////////////////////////////////////////////////////////////////////////// 884 // 885 // Function: 886 // InitSpnegoTokenElementArray 887 // 888 // Parameters: 889 // [in] pSpnegoToken - Points to SPNEGO_TOKEN structure. 890 // 891 // Returns: 892 // void 893 // 894 // Comments : 895 // Initializes the element array data member of a SPNEGO_TOKEN data 896 // structure. 897 // 898 //////////////////////////////////////////////////////////////////////////// 899 900 void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken ) 901 { 902 int nCtr; 903 904 // Set the number of elemnts 905 pSpnegoToken->nNumElements = MAX_NUM_TOKEN_ELEMENTS; 906 907 // 908 // Initially, all elements are unavailable 909 // 910 911 for ( nCtr = 0; nCtr < MAX_NUM_TOKEN_ELEMENTS; nCtr++ ) 912 { 913 // Set the element size as well 914 pSpnegoToken->aElementArray[ nCtr ].nStructSize = SPNEGO_ELEMENT_SIZE; 915 pSpnegoToken->aElementArray[ nCtr ].iElementPresent = SPNEGO_TOKEN_ELEMENT_UNAVAILABLE; 916 } 917 918 } 919 920 ///////////////////////////////////////////////////////////////////////////// 921 // 922 // Function: 923 // InitSpnegoTokenType 924 // 925 // Parameters: 926 // [in] pSpnegoToken - Points to SPNEGO_TOKEN structure. 927 // [out] pnTokenLength - Filled out with total token length 928 // [out] pnRemainingTokenLength - Filled out with remaining length 929 // after header is parsed 930 // [out] ppbFirstElement - Filled out with pointer to first 931 // element after header info. 932 // 933 // Returns: 934 // int Success - SPNEGO_E_SUCCESS 935 // Failure - SPNEGO API Error code 936 // 937 // Comments : 938 // Walks the underlying binary data for a SPNEGO_TOKEN data structure 939 // and determines the type of the underlying token based on token header 940 // information. 941 // 942 //////////////////////////////////////////////////////////////////////////// 943 944 int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength, 945 long* pnRemainingTokenLength, unsigned char** ppbFirstElement ) 946 { 947 int nReturn = SPNEGO_E_INVALID_TOKEN; 948 long nActualTokenLength = 0L; 949 long nBoundaryLength = pSpnegoToken->ulBinaryDataLen; 950 unsigned char* pbTokenData = pSpnegoToken->pbBinaryData; 951 952 // 953 // First byte MUST be either an APP_CONSTRUCT or the NEGTARG_TOKEN_TARG 954 // 955 956 if ( SPNEGO_NEGINIT_APP_CONSTRUCT == *pbTokenData ) 957 { 958 // Validate the above token - this will tell us the actual length of the token 959 // per the encoding (minus the actual token bytes) 960 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, 0L, nBoundaryLength, 961 pnTokenLength, &nActualTokenLength ) ) 962 == SPNEGO_E_SUCCESS ) 963 { 964 // Initialize the remaining token length value. This will be used 965 // to tell the caller how much token there is left once we've parsed 966 // the header (they could calculate it from the other values, but this 967 // is a bit friendlier) 968 *pnRemainingTokenLength = *pnTokenLength; 969 970 // Make adjustments to next token 971 pbTokenData += nActualTokenLength; 972 nBoundaryLength -= nActualTokenLength; 973 974 // The next token should be an OID 975 if ( ( nReturn = ASNDerCheckOID( pbTokenData, spnego_mech_oid_Spnego, nBoundaryLength, 976 &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) 977 { 978 // Make adjustments to next token 979 pbTokenData += nActualTokenLength; 980 nBoundaryLength -= nActualTokenLength; 981 *pnRemainingTokenLength -= nActualTokenLength; 982 983 // The next token should specify the NegTokenInit 984 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER, 985 *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, 986 &nActualTokenLength ) ) 987 == SPNEGO_E_SUCCESS ) 988 { 989 // Make adjustments to next token 990 pbTokenData += nActualTokenLength; 991 nBoundaryLength -= nActualTokenLength; 992 *pnRemainingTokenLength -= nActualTokenLength; 993 994 // The next token should specify the start of a sequence 995 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, 996 *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, 997 &nActualTokenLength ) ) 998 == SPNEGO_E_SUCCESS ) 999 { 1000 // NegTokenInit header is now checked out! 1001 1002 // Make adjustments to next token 1003 *pnRemainingTokenLength -= nActualTokenLength; 1004 1005 // Store pointer to first element 1006 *ppbFirstElement = pbTokenData + nActualTokenLength; 1007 pSpnegoToken->ucTokenType = SPNEGO_TOKEN_INIT; 1008 } // IF Check Sequence Token 1009 1010 } // IF Check NegTokenInit token 1011 1012 1013 } // IF Check for SPNEGO OID 1014 1015 1016 } // IF check app construct token 1017 1018 } 1019 else if ( SPNEGO_NEGTARG_TOKEN_IDENTIFIER == *pbTokenData ) 1020 { 1021 1022 // The next token should specify the NegTokenInit 1023 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER, 1024 *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, 1025 &nActualTokenLength ) ) 1026 == SPNEGO_E_SUCCESS ) 1027 { 1028 // Initialize the remaining token length value. This will be used 1029 // to tell the caller how much token there is left once we've parsed 1030 // the header (they could calculate it from the other values, but this 1031 // is a bit friendlier) 1032 *pnRemainingTokenLength = *pnTokenLength; 1033 1034 // Make adjustments to next token 1035 pbTokenData += nActualTokenLength; 1036 nBoundaryLength -= nActualTokenLength; 1037 1038 // The next token should specify the start of a sequence 1039 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, 1040 *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, 1041 &nActualTokenLength ) ) 1042 == SPNEGO_E_SUCCESS ) 1043 { 1044 // NegTokenInit header is now checked out! 1045 1046 // Make adjustments to next token 1047 *pnRemainingTokenLength -= nActualTokenLength; 1048 1049 // Store pointer to first element 1050 *ppbFirstElement = pbTokenData + nActualTokenLength; 1051 pSpnegoToken->ucTokenType = SPNEGO_TOKEN_TARG; 1052 } // IF Check Sequence Token 1053 1054 } // IF Check NegTokenInit token 1055 1056 } // ELSE IF it's a NegTokenTarg 1057 1058 return nReturn; 1059 } 1060 1061 1062 ///////////////////////////////////////////////////////////////////////////// 1063 // 1064 // Function: 1065 // GetSpnegoInitTokenMechList 1066 // 1067 // Parameters: 1068 // [in] pbTokenData - Points to binary MechList element 1069 // in NegTokenInit. 1070 // [in] nMechListLength - Length of the MechList 1071 // [out] pSpnegoElement - Filled out with MechList Element 1072 // data. 1073 // 1074 // Returns: 1075 // int Success - SPNEGO_E_SUCCESS 1076 // Failure - SPNEGO API Error code 1077 // 1078 // Comments : 1079 // Checks that pbTokenData is pointing at something that at least 1080 // *looks* like a MechList and then fills out the supplied 1081 // SPNEGO_ELEMENT structure. 1082 // 1083 //////////////////////////////////////////////////////////////////////////// 1084 1085 int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength, 1086 SPNEGO_ELEMENT* pSpnegoElement ) 1087 { 1088 int nReturn = SPNEGO_E_INVALID_TOKEN; 1089 long nLength = 0L; 1090 long nActualTokenLength = 0L; 1091 1092 // Actual MechList is prepended by a Constructed Sequence Token 1093 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, 1094 nMechListLength, nMechListLength, 1095 &nLength, &nActualTokenLength ) ) 1096 == SPNEGO_E_SUCCESS ) 1097 { 1098 // Adjust for this token 1099 nMechListLength -= nActualTokenLength; 1100 pbTokenData += nActualTokenLength; 1101 1102 // Perform simple validation of the actual MechList (i.e. ensure that 1103 // the OIDs in the MechList are reasonable). 1104 1105 if ( ( nReturn = ValidateMechList( pbTokenData, nLength ) ) == SPNEGO_E_SUCCESS ) 1106 { 1107 // Initialize the element now 1108 pSpnegoElement->eElementType = spnego_init_mechtypes; 1109 pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; 1110 pSpnegoElement->type = SPNEGO_MECHLIST_TYPE; 1111 pSpnegoElement->nDatalength = nLength; 1112 pSpnegoElement->pbData = pbTokenData; 1113 } 1114 1115 } // IF Check Token 1116 1117 return nReturn; 1118 } 1119 1120 ///////////////////////////////////////////////////////////////////////////// 1121 // 1122 // Function: 1123 // InitSpnegoTokenElementFromBasicType 1124 // 1125 // Parameters: 1126 // [in] pbTokenData - Points to binary element data in 1127 // a SPNEGO token. 1128 // [in] nElementLength - Length of the element 1129 // [in] ucExpectedType - Expected DER type. 1130 // [in] spnegoElementType - Which element is this? 1131 // [out] pSpnegoElement - Filled out with element data. 1132 // 1133 // Returns: 1134 // int Success - SPNEGO_E_SUCCESS 1135 // Failure - SPNEGO API Error code 1136 // 1137 // Comments : 1138 // Checks that pbTokenData is pointing at the specified DER type. If so, 1139 // then we verify that lengths are proper and then fill out the 1140 // SPNEGO_ELEMENT data structure. 1141 // 1142 //////////////////////////////////////////////////////////////////////////// 1143 1144 int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength, 1145 unsigned char ucExpectedType, 1146 SPNEGO_ELEMENT_TYPE spnegoElementType, 1147 SPNEGO_ELEMENT* pSpnegoElement ) 1148 { 1149 int nReturn = SPNEGO_E_UNEXPECTED_TYPE; 1150 long nLength = 0L; 1151 long nActualTokenLength = 0L; 1152 1153 // The type BYTE must match our token data or something is badly wrong 1154 if ( *pbTokenData == ucExpectedType ) 1155 { 1156 1157 // Check that we are pointing at the specified type 1158 if ( ( nReturn = ASNDerCheckToken( pbTokenData, ucExpectedType, 1159 nElementLength, nElementLength, 1160 &nLength, &nActualTokenLength ) ) 1161 == SPNEGO_E_SUCCESS ) 1162 { 1163 // Adjust for this token 1164 nElementLength -= nActualTokenLength; 1165 pbTokenData += nActualTokenLength; 1166 1167 // Initialize the element now 1168 pSpnegoElement->eElementType = spnegoElementType; 1169 pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; 1170 pSpnegoElement->type = ucExpectedType; 1171 pSpnegoElement->nDatalength = nLength; 1172 pSpnegoElement->pbData = pbTokenData; 1173 } 1174 1175 } // IF type makes sense 1176 1177 return nReturn; 1178 } 1179 1180 1181 ///////////////////////////////////////////////////////////////////////////// 1182 // 1183 // Function: 1184 // InitSpnegoTokenElementFromOID 1185 // 1186 // Parameters: 1187 // [in] pbTokenData - Points to binary element data in 1188 // a SPNEGO token. 1189 // [in] nElementLength - Length of the element 1190 // [in] spnegoElementType - Which element is this? 1191 // [out] pSpnegoElement - Filled out with element data. 1192 // 1193 // Returns: 1194 // int Success - SPNEGO_E_SUCCESS 1195 // Failure - SPNEGO API Error code 1196 // 1197 // Comments : 1198 // Initializes a SpnegoElement from an OID - normally, this would have 1199 // used the Basic Type function above, but since we do binary compares 1200 // on the OIDs against the DER information as well as the OID, we need 1201 // to account for that. 1202 // 1203 //////////////////////////////////////////////////////////////////////////// 1204 1205 int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength, 1206 SPNEGO_ELEMENT_TYPE spnegoElementType, 1207 SPNEGO_ELEMENT* pSpnegoElement ) 1208 { 1209 int nReturn = SPNEGO_E_UNEXPECTED_TYPE; 1210 long nLength = 0L; 1211 long nActualTokenLength = 0L; 1212 1213 // The type BYTE must match our token data or something is badly wrong 1214 if ( *pbTokenData == OID ) 1215 { 1216 1217 // Check that we are pointing at an OID type 1218 if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, 1219 nElementLength, nElementLength, 1220 &nLength, &nActualTokenLength ) ) 1221 == SPNEGO_E_SUCCESS ) 1222 { 1223 // Don't adjust any values for this function 1224 1225 // Initialize the element now 1226 pSpnegoElement->eElementType = spnegoElementType; 1227 pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; 1228 pSpnegoElement->type = OID; 1229 pSpnegoElement->nDatalength = nElementLength; 1230 pSpnegoElement->pbData = pbTokenData; 1231 } 1232 1233 } // IF type makes sense 1234 1235 return nReturn; 1236 } 1237 1238 1239 ///////////////////////////////////////////////////////////////////////////// 1240 // 1241 // Function: 1242 // InitSpnegoTokenElements 1243 // 1244 // Parameters: 1245 // [in] pSpnegoToken - Points to SPNEGO_TOKEN struct 1246 // [in] pbTokenData - Points to initial binary element 1247 // data in a SPNEGO token. 1248 // [in] nRemainingTokenLength - Length remaining past header 1249 // 1250 // Returns: 1251 // int Success - SPNEGO_E_SUCCESS 1252 // Failure - SPNEGO API Error code 1253 // 1254 // Comments : 1255 // Interprets the data at pbTokenData based on the TokenType in 1256 // pSpnegoToken. Since some elements are optional (technically all are 1257 // but the token becomes quite useless if this is so), we check if 1258 // an element exists before filling out the element in the array. 1259 // 1260 //////////////////////////////////////////////////////////////////////////// 1261 1262 int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData, 1263 long nRemainingTokenLength ) 1264 { 1265 // 1266 // The following arrays contain the token identifiers for the elements 1267 // comprising the actual token. All values are optional, and there are 1268 // no defaults. 1269 // 1270 1271 static unsigned char abNegTokenInitElements[] = 1272 { SPNEGO_NEGINIT_ELEMENT_MECHTYPES, SPNEGO_NEGINIT_ELEMENT_REQFLAGS, 1273 SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC }; 1274 1275 static unsigned char abNegTokenTargElements[] = 1276 { SPNEGO_NEGTARG_ELEMENT_NEGRESULT, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH, 1277 SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC }; 1278 1279 int nReturn = SPNEGO_E_SUCCESS; 1280 int nCtr = 0L; 1281 long nElementLength = 0L; 1282 long nActualTokenLength = 0L; 1283 unsigned char* pbElements = NULL; 1284 unsigned char * ptok; 1285 long tlen, elen, len; 1286 1287 // Point to the correct array 1288 switch( pSpnegoToken->ucTokenType ) 1289 { 1290 case SPNEGO_TOKEN_INIT: 1291 { 1292 pbElements = abNegTokenInitElements; 1293 } 1294 break; 1295 1296 case SPNEGO_TOKEN_TARG: 1297 { 1298 pbElements = abNegTokenTargElements; 1299 } 1300 break; 1301 1302 } // SWITCH tokentype 1303 1304 // 1305 // Enumerate the element arrays and look for the tokens at our current location 1306 // 1307 1308 for ( nCtr = 0L; 1309 SPNEGO_E_SUCCESS == nReturn && 1310 nCtr < MAX_NUM_TOKEN_ELEMENTS && 1311 nRemainingTokenLength > 0L; 1312 nCtr++ ) 1313 { 1314 1315 // Check if the token exists 1316 if ( ( nReturn = ASNDerCheckToken( pbTokenData, pbElements[nCtr], 1317 0L, nRemainingTokenLength, 1318 &nElementLength, &nActualTokenLength ) ) 1319 == SPNEGO_E_SUCCESS ) 1320 { 1321 1322 // Token data should skip over the sequence token and then 1323 // call the appropriate function to initialize the element 1324 pbTokenData += nActualTokenLength; 1325 1326 // Lengths in the elements should NOT go beyond the element 1327 // length 1328 1329 // Different tokens mean different elements 1330 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) 1331 { 1332 1333 // Handle each element as appropriate 1334 switch( pbElements[nCtr] ) 1335 { 1336 1337 case SPNEGO_NEGINIT_ELEMENT_MECHTYPES: 1338 { 1339 // 1340 // This is a Mech List that specifies which OIDs the 1341 // originator of the Init Token supports. 1342 // 1343 1344 nReturn = GetSpnegoInitTokenMechList( pbTokenData, nElementLength, 1345 &pSpnegoToken->aElementArray[nCtr] ); 1346 1347 } 1348 break; 1349 1350 case SPNEGO_NEGINIT_ELEMENT_REQFLAGS: 1351 { 1352 // 1353 // This is a BITSTRING which specifies the flags that the receiver 1354 // pass to the gss_accept_sec_context() function. 1355 // 1356 1357 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, 1358 BITSTRING, spnego_init_reqFlags, 1359 &pSpnegoToken->aElementArray[nCtr] ); 1360 } 1361 break; 1362 1363 case SPNEGO_NEGINIT_ELEMENT_MECHTOKEN: 1364 { 1365 // 1366 // This is an OCTETSTRING which contains a GSSAPI token corresponding 1367 // to the first OID in the MechList. 1368 // 1369 1370 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, 1371 OCTETSTRING, spnego_init_mechToken, 1372 &pSpnegoToken->aElementArray[nCtr] ); 1373 } 1374 break; 1375 1376 case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC: 1377 { 1378 // 1379 // This is an OCTETSTRING which contains a message integrity BLOB. 1380 // 1381 1382 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, 1383 OCTETSTRING, spnego_init_mechListMIC, 1384 &pSpnegoToken->aElementArray[nCtr] ); 1385 /* 1386 * don't believe everything you read in RFCs (and MS 1387 * sample code)... win2k is sending not an octet string, 1388 * but a "general string", wrapped in a sequence. 1389 */ 1390 if (nReturn != SPNEGO_E_UNEXPECTED_TYPE) 1391 break; 1392 ptok = pbTokenData; 1393 elen = nElementLength; 1394 if ((nReturn = ASNDerCheckToken(ptok, SPNEGO_CONSTRUCTED_SEQUENCE, elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS) 1395 break; 1396 elen -= tlen; 1397 ptok += tlen; 1398 1399 if ((nReturn = ASNDerCheckToken(ptok, SEQ_ELM(0), elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS) 1400 break; 1401 elen -= tlen; 1402 ptok += tlen; 1403 nReturn = InitSpnegoTokenElementFromBasicType(ptok, elen, GENERALSTR, spnego_init_mechListMIC, &pSpnegoToken->aElementArray[nCtr]); 1404 } 1405 break; 1406 1407 } // SWITCH Element 1408 } 1409 else 1410 { 1411 1412 switch( pbElements[nCtr] ) 1413 { 1414 1415 case SPNEGO_NEGTARG_ELEMENT_NEGRESULT: 1416 { 1417 // 1418 // This is an ENUMERATION which specifies result of the last GSS 1419 // token negotiation call. 1420 // 1421 1422 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, 1423 ENUMERATED, spnego_targ_negResult, 1424 &pSpnegoToken->aElementArray[nCtr] ); 1425 } 1426 break; 1427 1428 case SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH: 1429 { 1430 // 1431 // This is an OID which specifies a supported mechanism. 1432 // 1433 1434 nReturn = InitSpnegoTokenElementFromOID( pbTokenData, nElementLength, 1435 spnego_targ_mechListMIC, 1436 &pSpnegoToken->aElementArray[nCtr] ); 1437 } 1438 break; 1439 1440 case SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN: 1441 { 1442 // 1443 // This is an OCTETSTRING which specifies results of the last GSS 1444 // token negotiation call. 1445 // 1446 1447 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, 1448 OCTETSTRING, spnego_targ_responseToken, 1449 &pSpnegoToken->aElementArray[nCtr] ); 1450 } 1451 break; 1452 1453 case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC: 1454 { 1455 // 1456 // This is an OCTETSTRING which specifies a message integrity BLOB. 1457 // 1458 1459 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, 1460 OCTETSTRING, spnego_targ_mechListMIC, 1461 &pSpnegoToken->aElementArray[nCtr] ); 1462 } 1463 break; 1464 1465 } // SWITCH Element 1466 1467 } // ELSE !NegTokenInit 1468 1469 // Account for the entire token and following data 1470 nRemainingTokenLength -= ( nActualTokenLength + nElementLength ); 1471 1472 // Token data should skip past the element length now 1473 pbTokenData += nElementLength; 1474 1475 } // IF Token found 1476 else if ( SPNEGO_E_TOKEN_NOT_FOUND == nReturn ) 1477 { 1478 // For now, this is a benign error (remember, all elements are optional, so 1479 // if we don't find one, it's okay). 1480 1481 nReturn = SPNEGO_E_SUCCESS; 1482 } 1483 1484 } // FOR enum elements 1485 1486 // 1487 // We should always run down to 0 remaining bytes in the token. If not, we've got 1488 // a bad token. 1489 // 1490 1491 if ( SPNEGO_E_SUCCESS == nReturn && nRemainingTokenLength != 0L ) 1492 { 1493 nReturn = SPNEGO_E_INVALID_TOKEN; 1494 } 1495 1496 return nReturn; 1497 } 1498 1499 1500 ///////////////////////////////////////////////////////////////////////////// 1501 // 1502 // Function: 1503 // FindMechOIDInMechList 1504 // 1505 // Parameters: 1506 // [in] pSpnegoElement - SPNEGO_ELEMENT for MechList 1507 // [in] MechOID - OID we're looking for. 1508 // [out] piMechTypeIndex - Index in the list where OID was 1509 // found 1510 // 1511 // Returns: 1512 // int Success - SPNEGO_E_SUCCESS 1513 // Failure - SPNEGO API Error code 1514 // 1515 // Comments : 1516 // Walks the MechList for MechOID. When it is found, the index in the 1517 // list is written to piMechTypeIndex. 1518 // 1519 //////////////////////////////////////////////////////////////////////////// 1520 1521 int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID, 1522 int * piMechTypeIndex ) 1523 { 1524 int nReturn = SPNEGO_E_NOT_FOUND; 1525 int nCtr = 0; 1526 long nLength = 0L; 1527 long nBoundaryLength = pSpnegoElement->nDatalength; 1528 unsigned char* pbMechListData = pSpnegoElement->pbData; 1529 1530 while( SPNEGO_E_SUCCESS != nReturn && nBoundaryLength > 0L ) 1531 { 1532 1533 // Use the helper function to check the OID 1534 if ( ( nReturn = ASNDerCheckOID( pbMechListData, MechOID, nBoundaryLength, &nLength ) ) 1535 == SPNEGO_E_SUCCESS ) 1536 { 1537 *piMechTypeIndex = nCtr; 1538 } 1539 1540 // Adjust for the current OID 1541 pbMechListData += nLength; 1542 nBoundaryLength -= nLength; 1543 nCtr++; 1544 1545 } // WHILE enuming OIDs 1546 1547 return nReturn; 1548 1549 } 1550 1551 1552 ///////////////////////////////////////////////////////////////////////////// 1553 // 1554 // Function: 1555 // ValidateMechList 1556 // 1557 // Parameters: 1558 // [in] pbMechListData - Pointer to binary MechList data 1559 // [in] nBoundaryLength - Length we must not exceed 1560 // 1561 // Returns: 1562 // int Success - SPNEGO_E_SUCCESS 1563 // Failure - SPNEGO API Error code 1564 // 1565 // Comments : 1566 // Checks the data at pbMechListData to see if it looks like a MechList. 1567 // As part of this, we walk the list and ensure that none of the OIDs 1568 // have a length that takes us outside of nBoundaryLength. 1569 // 1570 //////////////////////////////////////////////////////////////////////////// 1571 1572 int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength ) 1573 { 1574 int nReturn = SPNEGO_E_SUCCESS; 1575 long nLength = 0L; 1576 long nTokenLength = 0L; 1577 1578 while( SPNEGO_E_SUCCESS == nReturn && nBoundaryLength > 0L ) 1579 { 1580 // Verify that we have something that at least *looks* like an OID - in other 1581 // words it has an OID identifier and specifies a length that doesn't go beyond 1582 // the size of the list. 1583 nReturn = ASNDerCheckToken( pbMechListData, OID, 0L, nBoundaryLength, 1584 &nLength, &nTokenLength ); 1585 1586 // Adjust for the current OID 1587 pbMechListData += ( nLength + nTokenLength ); 1588 nBoundaryLength -= ( nLength + nTokenLength ); 1589 1590 } // WHILE enuming OIDs 1591 1592 return nReturn; 1593 1594 } 1595 1596 ///////////////////////////////////////////////////////////////////////////// 1597 // 1598 // Function: 1599 // IsValidMechOid 1600 // 1601 // Parameters: 1602 // [in] mechOid - mechOID id enumeration 1603 // 1604 // Returns: 1605 // int Success - 1 1606 // Failure - 0 1607 // 1608 // Comments : 1609 // Checks for a valid mechOid value. 1610 // 1611 //////////////////////////////////////////////////////////////////////////// 1612 1613 int IsValidMechOid( SPNEGO_MECH_OID mechOid ) 1614 { 1615 return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy && 1616 mechOid <= spnego_mech_oid_NTLMSSP ); 1617 } 1618 1619 ///////////////////////////////////////////////////////////////////////////// 1620 // 1621 // Function: 1622 // IsValidContextFlags 1623 // 1624 // Parameters: 1625 // [in] ucContextFlags - ContextFlags value 1626 // 1627 // Returns: 1628 // int Success - 1 1629 // Failure - 0 1630 // 1631 // Comments : 1632 // Checks for a valid ContextFlags value. 1633 // 1634 //////////////////////////////////////////////////////////////////////////// 1635 1636 int IsValidContextFlags( unsigned char ucContextFlags ) 1637 { 1638 // Mask out our valid bits. If there is anything leftover, this 1639 // is not a valid value for Context Flags 1640 return ( ( ucContextFlags & ~SPNEGO_NEGINIT_CONTEXT_MASK ) == 0 ); 1641 } 1642 1643 ///////////////////////////////////////////////////////////////////////////// 1644 // 1645 // Function: 1646 // IsValidNegResult 1647 // 1648 // Parameters: 1649 // [in] negResult - NegResult value 1650 // 1651 // Returns: 1652 // int Success - 1 1653 // Failure - 0 1654 // 1655 // Comments : 1656 // Checks for a valid NegResult value. 1657 // 1658 //////////////////////////////////////////////////////////////////////////// 1659 1660 int IsValidNegResult( SPNEGO_NEGRESULT negResult ) 1661 { 1662 return ( negResult >= spnego_negresult_success && 1663 negResult <= spnego_negresult_rejected ); 1664 } 1665 1666 ///////////////////////////////////////////////////////////////////////////// 1667 // 1668 // Function: 1669 // IsValidSpnegoToken 1670 // 1671 // Parameters: 1672 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure 1673 // 1674 // Returns: 1675 // int Success - 1 1676 // Failure - 0 1677 // 1678 // Comments : 1679 // Performs simple heuristic on location pointed to by pSpnegoToken. 1680 // 1681 //////////////////////////////////////////////////////////////////////////// 1682 1683 int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ) 1684 { 1685 int nReturn = 0; 1686 1687 // Parameter should be non-NULL 1688 if ( NULL != pSpnegoToken ) 1689 { 1690 // Length should be at least the size defined in the header 1691 if ( pSpnegoToken->nStructSize >= SPNEGO_TOKEN_SIZE ) 1692 { 1693 // Number of elements should be >= our maximum - if it's greater, that's 1694 // okay, since we'll only be accessing the elements up to MAX_NUM_TOKEN_ELEMENTS 1695 if ( pSpnegoToken->nNumElements >= MAX_NUM_TOKEN_ELEMENTS ) 1696 { 1697 // Check for proper token type 1698 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType || 1699 SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType ) 1700 { 1701 nReturn = 1; 1702 } 1703 } 1704 1705 } // IF struct size makes sense 1706 1707 } // IF non-NULL spnego Token 1708 1709 return nReturn; 1710 } 1711 1712 ///////////////////////////////////////////////////////////////////////////// 1713 // 1714 // Function: 1715 // IsValidSpnegoElement 1716 // 1717 // Parameters: 1718 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure 1719 // [in] spnegoElement - spnegoElement Type from enumeration 1720 // 1721 // Returns: 1722 // int Success - 1 1723 // Failure - 0 1724 // 1725 // Comments : 1726 // Checks that spnegoElement has a valid value and is appropriate for 1727 // the SPNEGO token encapsulated by pSpnegoToken. 1728 // 1729 //////////////////////////////////////////////////////////////////////////// 1730 1731 int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ) 1732 { 1733 int nReturn = 0; 1734 1735 // Check boundaries 1736 if ( spnegoElement > spnego_element_min && 1737 spnegoElement < spnego_element_max ) 1738 { 1739 1740 // Check for appropriateness to token type 1741 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) 1742 { 1743 nReturn = ( spnegoElement >= spnego_init_mechtypes && 1744 spnegoElement <= spnego_init_mechListMIC ); 1745 } 1746 else 1747 { 1748 nReturn = ( spnegoElement >= spnego_targ_negResult && 1749 spnegoElement <= spnego_targ_mechListMIC ); 1750 } 1751 1752 } // IF boundary conditions are met 1753 1754 return nReturn; 1755 } 1756 1757 ///////////////////////////////////////////////////////////////////////////// 1758 // 1759 // Function: 1760 // CalculateElementArrayIndex 1761 // 1762 // Parameters: 1763 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure 1764 // [in] spnegoElement - spnegoElement Type from enumeration 1765 // 1766 // Returns: 1767 // int index in the SPNEGO_TOKEN element array that the element can 1768 // can be found 1769 // 1770 // Comments : 1771 // Based on the Token Type, calculates the index in the element array 1772 // at which the specified element can be found. 1773 // 1774 //////////////////////////////////////////////////////////////////////////// 1775 1776 int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ) 1777 { 1778 int nReturn = 0; 1779 1780 // Offset is difference between value and initial element identifier 1781 // (these differ based on ucTokenType) 1782 1783 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) 1784 { 1785 nReturn = spnegoElement - spnego_init_mechtypes; 1786 } 1787 else 1788 { 1789 nReturn = spnegoElement - spnego_targ_negResult; 1790 } 1791 1792 return nReturn; 1793 } 1794 1795 ///////////////////////////////////////////////////////////////////////////// 1796 // 1797 // Function: 1798 // InitTokenFromBinary 1799 // 1800 // Parameters: 1801 // [in] ucCopyData - Flag indicating if data should be copied 1802 // [in] ulFlags - Flags value for structure 1803 // [in] pnTokenData - Binary Token Data 1804 // [in] ulLength - Length of the data 1805 // [out] ppSpnegoToken - Pointer to call allocated SPNEGO Token 1806 // data structure 1807 // 1808 // Returns: 1809 // int Success - SPNEGO_E_SUCCESS 1810 // Failure - SPNEGO API Error code 1811 // 1812 // Comments : 1813 // Allocates a SPNEGO_TOKEN data structure and fills it out as 1814 // appropriate based in the flags passed into the function. 1815 // 1816 //////////////////////////////////////////////////////////////////////////// 1817 1818 1819 // Initializes SPNEGO_TOKEN structure from DER encoded binary data 1820 int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags, 1821 unsigned char* pbTokenData, unsigned long ulLength, 1822 SPNEGO_TOKEN** ppSpnegoToken ) 1823 { 1824 int nReturn = SPNEGO_E_INVALID_PARAMETER; 1825 SPNEGO_TOKEN* pSpnegoToken = NULL; 1826 unsigned char* pbFirstElement = NULL; 1827 long nTokenLength = 0L; 1828 long nRemainingTokenLength = 0L; 1829 1830 // Basic Parameter Validation 1831 1832 if ( NULL != pbTokenData && 1833 NULL != ppSpnegoToken && 1834 0L != ulLength ) 1835 { 1836 1837 // 1838 // Allocate the empty token, then initialize the data structure. 1839 // 1840 1841 pSpnegoToken = AllocEmptySpnegoToken( ucCopyData, ulFlags, pbTokenData, ulLength ); 1842 1843 if ( NULL != pSpnegoToken ) 1844 { 1845 1846 // Copy the binary data locally 1847 1848 1849 // Initialize the token type 1850 if ( ( nReturn = InitSpnegoTokenType( pSpnegoToken, &nTokenLength, 1851 &nRemainingTokenLength, &pbFirstElement ) ) 1852 == SPNEGO_E_SUCCESS ) 1853 { 1854 1855 // Initialize the element array 1856 if ( ( nReturn = InitSpnegoTokenElements( pSpnegoToken, pbFirstElement, 1857 nRemainingTokenLength ) ) 1858 == SPNEGO_E_SUCCESS ) 1859 { 1860 *ppSpnegoToken = pSpnegoToken; 1861 } 1862 1863 } // IF Init Token Type 1864 1865 // Cleanup on error condition 1866 if ( SPNEGO_E_SUCCESS != nReturn ) 1867 { 1868 spnegoFreeData( pSpnegoToken ); 1869 } 1870 1871 } 1872 else 1873 { 1874 nReturn = SPNEGO_E_OUT_OF_MEMORY; 1875 } 1876 1877 } // IF Valid parameters 1878 1879 1880 return nReturn; 1881 } 1882