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