"Fossies" - the Fresh Open Source Software Archive

Member "spnegohelp/spnegoparse.c" (10 Apr 2005, 62377 Bytes) of package /linux/www/apache_httpd_modules/old/modgssapache-0.0.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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