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