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