"Fossies" - the Fresh Open Source Software Archive

Member "spnegohelp/derparse.c" (10 Apr 2005, 23063 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 //
   16 // DERPARSE.C
   17 //
   18 // SPNEGO Token Handler Source File
   19 //
   20 // Contains implementation of ASN.1 DER read/write functions
   21 // as defined in DERPARSE.H.
   22 //
   23 /////////////////////////////////////////////////////////////
   24 
   25 #include <stdlib.h>
   26 #include <stdio.h>
   27 #include <memory.h>
   28 #include "spnego.h"
   29 #include "derparse.h"
   30 
   31 //
   32 // The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in
   33 // the array below, that a mechanism can be found.
   34 //
   35 MECH_OID g_stcMechOIDList [] =
   36 {
   37    { (unsigned char*) "\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02",  11, 9, spnego_mech_oid_Kerberos_V5_Legacy  },  //  1.2.840.48018.1.2.2 
   38    { (unsigned char*) "\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02",  11, 9, spnego_mech_oid_Kerberos_V5         },  //  1.2.840.113554.1.2.2
   39    { (unsigned char*) "\x06\x06\x2b\x06\x01\x05\x05\x02",               8, 6, spnego_mech_oid_Spnego              },  //  1.3.6.1.1.5.5.2
   40    { (unsigned char*) "",                                               0, 0, spnego_mech_oid_NotUsed             }   //  Placeholder
   41 };
   42 
   43 /////////////////////////////////////////////////////////////////////////////
   44 //
   45 // Function:
   46 //    ASNDerGetLength
   47 //
   48 // Parameters:
   49 //    [in]  pbLengthData      -  DER Length Data
   50 //    [in]  nBoundaryLength   -  Length that value must not exceed.
   51 //    [out] pnLength          -  Filled out with length value
   52 //    [out] pnNumLengthBytes  -  Filled out with number of bytes
   53 //                               consumed by DER length.
   54 //
   55 // Returns:
   56 //    int   Success - SPNEGO_E_SUCCESS
   57 //          Failure - SPNEGO API Error code
   58 //
   59 // Comments :
   60 //    Interprets the data at pbLengthData as a DER length.  The length must
   61 //    fit within the bounds of nBoundary length.  We do not currently
   62 //    process lengths that take more than 4 bytes.
   63 //
   64 ////////////////////////////////////////////////////////////////////////////
   65 
   66 int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength,
   67                      long* pnNumLengthBytes )
   68 {
   69    int   nReturn = SPNEGO_E_INVALID_LENGTH;
   70    int   nNumLengthBytes = 0;
   71 
   72    // First check if the extended length bit is set
   73 
   74    if ( *pbLengthData & LEN_XTND )
   75    {
   76       // Lower 7 bits contain the number of trailing bytes that describe the length
   77       nNumLengthBytes = *pbLengthData & LEN_MASK;
   78 
   79       // Check that the number of bytes we are about to read is within our boundary
   80       // constraints
   81 
   82       if ( nNumLengthBytes <= nBoundaryLength - 1 )
   83       {
   84 
   85          // For now, our handler won't deal with lengths greater than 4 bytes
   86          if ( nNumLengthBytes >= 1 && nNumLengthBytes <= 4 )
   87          {
   88             // 0 out the initial length
   89             *pnLength = 0L;
   90 
   91             // Bump by 1 byte
   92             pbLengthData++;
   93 
   94    #ifdef __LITTLE_ENDIAN__
   95 
   96             // There may be a cleaner way to do this, but for now, this seems to be
   97             // an easy way to do the transformation
   98             switch ( nNumLengthBytes )
   99             {
  100                case 1:
  101                {
  102                   *( ( (unsigned char*) pnLength ) ) = *pbLengthData;
  103                   break;
  104                }
  105 
  106                case 2:
  107                {
  108                   *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 1);
  109                   *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData);
  110 
  111                   break;
  112                }
  113 
  114                case 3:
  115                {
  116                   *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 2);
  117                   *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1);
  118                   *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData);
  119                   break;
  120                }
  121 
  122                case 4:
  123                {
  124                   *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 3);
  125                   *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData + 2);
  126                   *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1);
  127                   *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData);
  128                   break;
  129                }
  130 
  131             }  // SWITCH ( nNumLengthBytes )
  132 
  133    #else
  134             // We are Big-Endian, so the length can be copied in from the source
  135             // as is.  Ensure that we adjust for the number of bytes we actually
  136             // copy.
  137 
  138             memcpy( ( (unsigned char *) pnLength ) + ( 4 - nNumLengthBytes ),
  139                      pbLengthData, nNumLengthBytes );
  140    #endif
  141 
  142             // Account for the initial length byte
  143             *pnNumLengthBytes = nNumLengthBytes + 1;
  144             nReturn = SPNEGO_E_SUCCESS;
  145 
  146          }  // IF Valid Length
  147 
  148       }  // IF num bytes to read is within the boundary length
  149 
  150    }  // IF xtended length
  151    else
  152    {
  153 
  154       // Extended bit is not set, so the length is in the value and the one
  155       // byte describes the length
  156       *pnLength = *pbLengthData & LEN_MASK;
  157       *pnNumLengthBytes = 1;
  158       nReturn = SPNEGO_E_SUCCESS;
  159 
  160    }
  161    LOG(("ASNDerGetLength returned %d\n",nReturn));
  162    return nReturn;
  163 }
  164 
  165 
  166 /////////////////////////////////////////////////////////////////////////////
  167 //
  168 // Function:
  169 //    ASNDerCheckToken
  170 //
  171 // Parameters:
  172 //    [in]  pbTokenData       -  Token Data
  173 //    [in]  nToken            -  Token identifier to check for
  174 //    [in]  nLengthWithToken  -  Expected token length (with data)
  175 //    [in]  nBoundaryLength   -  Length that value must not exceed.
  176 //    [out] pnLength          -  Filled out with data length
  177 //    [out] pnTokenLength     -  Filled out with number of bytes 
  178 //                               consumed by token identifier and length.
  179 //
  180 // Returns:
  181 //    int   Success - SPNEGO_E_SUCCESS
  182 //          Failure - SPNEGO API Error code
  183 //
  184 // Comments :
  185 //    Checks the data pointed to by pbTokenData for the specified token
  186 //    identifier and the length that immediately follows.  If
  187 //    nLengthWithToken is > 0, the calculated length must match.  The
  188 //    length must also not exceed the specified boundary length .
  189 //
  190 ////////////////////////////////////////////////////////////////////////////
  191 
  192 int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
  193                         long nLengthWithToken, long nBoundaryLength,
  194                         long* pnLength, long* pnTokenLength )
  195 {
  196 
  197    int   nReturn = SPNEGO_E_INVALID_LENGTH;
  198    long  nNumLengthBytes = 0L;
  199 
  200    // Make sure that we've at least got 2 bytes of room to work with
  201 
  202    if ( nBoundaryLength >= 2 )
  203    {
  204       // The first byte of the token data MUST match the specified token
  205       if ( *pbTokenData == nToken )
  206       {
  207          // Next byte indicates the length
  208          pbTokenData++;
  209 
  210          // Get the length described by the token
  211          if ( ( nReturn = ASNDerGetLength( pbTokenData, nBoundaryLength, pnLength,
  212                                              &nNumLengthBytes )  ) == SPNEGO_E_SUCCESS )
  213          {
  214             // Verify that the length is LESS THAN the boundary length
  215             // (this should prevent us walking out of our buffer)
  216             if ( ( nBoundaryLength - ( nNumLengthBytes + 1 ) < *pnLength ) )
  217             {
  218 
  219                nReturn = SPNEGO_E_INVALID_LENGTH;
  220 
  221             }
  222 
  223             // If we were passed a length to check, do so now
  224             if ( nLengthWithToken > 0L )
  225             {
  226 
  227                // Check that the expected length matches
  228                if ( ( nLengthWithToken - ( nNumLengthBytes + 1 ) ) != *pnLength )
  229                {
  230 
  231                   nReturn = SPNEGO_E_INVALID_LENGTH;
  232 
  233                }
  234 
  235             }  // IF need to validate length
  236 
  237             if ( SPNEGO_E_SUCCESS == nReturn )
  238             {
  239                *pnTokenLength = nNumLengthBytes + 1;
  240             }
  241 
  242          }  // IF ASNDerGetLength
  243 
  244       }  // IF token matches
  245       else
  246       {
  247          nReturn = SPNEGO_E_TOKEN_NOT_FOUND;
  248       }
  249 
  250    }  // IF Boundary Length is at least 2 bytes 
  251 
  252    LOG(("ASNDerCheckToken returned %d\n",nReturn));
  253    return nReturn;
  254 }
  255 
  256 /////////////////////////////////////////////////////////////////////////////
  257 //
  258 // Function:
  259 //    ASNDerCheckOID
  260 //
  261 // Parameters:
  262 //    [in]  pbTokenData       -  Token Data
  263 //    [in]  nMechOID          -  OID we are looking for
  264 //    [in]  nBoundaryLength   -  Length that value must not exceed.
  265 //    [out] pnTokenLength     -  Filled out with number of bytes
  266 //                               consumed by token and data.
  267 //
  268 // Returns:
  269 //    int   Success - SPNEGO_E_SUCCESS
  270 //          Failure - SPNEGO API Error code
  271 //
  272 // Comments :
  273 //    Checks the data pointed to by pbTokenData for the specified OID.
  274 //
  275 ////////////////////////////////////////////////////////////////////////////
  276 
  277 int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength,
  278                      long* pnTokenLength )
  279 {
  280    int   nReturn = 0L;
  281    long  nLength = 0L;
  282 
  283    // Verify that we have an OID token
  284    if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, 0L, nBoundaryLength, 
  285                                        &nLength, pnTokenLength ) ) == SPNEGO_E_SUCCESS )
  286    {
  287       // Add the data length to the Token Length
  288       *pnTokenLength += nLength;
  289 
  290       // Token Lengths plus the actual length must match the length in our OID list element.
  291       // If it doesn't, we're done
  292       if ( *pnTokenLength == g_stcMechOIDList[nMechOID].iLen )
  293       {
  294          // Memcompare the token and the expected field
  295          if ( memcmp( pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength ) != 0 )
  296          {
  297         LOG(("ASNDerCheckOID memcmp failed\n"));
  298             nReturn = SPNEGO_E_UNEXPECTED_OID;
  299          }
  300       }
  301       else
  302       {
  303          LOG(("ASNDerCheckOID token length failed\n"));
  304          nReturn = SPNEGO_E_UNEXPECTED_OID;
  305       }
  306 
  307    }  // IF OID Token CHecks
  308 
  309    LOG(("ASNDerCheckOID returned %d\n",nReturn));
  310    return nReturn;
  311 }
  312 
  313 /////////////////////////////////////////////////////////////////////////////
  314 //
  315 // Function:
  316 //    ASNDerCalcNumLengthBytes
  317 //
  318 // Parameters:
  319 //    [in]  nLength           -  Length to calculate length bytes for.
  320 //
  321 // Returns:
  322 //    int   Number of bytes necessary to represent length
  323 //
  324 // Comments :
  325 //    Helper function to calculate the number of length bytes necessary to
  326 //    represent a length value.  For our purposes, a 32-bit value should be
  327 //    enough to describea length.
  328 //
  329 ////////////////////////////////////////////////////////////////////////////
  330 
  331 int ASNDerCalcNumLengthBytes( long nLength )
  332 {
  333       if ( nLength <= 0x7F )
  334       {
  335          // A single byte will be sufficient for describing this length.
  336          // The byte will simply contain the length
  337          return 1;
  338       }
  339       else if ( nLength <= 0xFF )
  340       {
  341          // Two bytes are necessary, one to say how many following bytes
  342          // describe the length, and one to give the length
  343          return 2;
  344       }
  345       else if ( nLength <= 0xFFFF )
  346       {
  347          // Three bytes are necessary, one to say how many following bytes
  348          // describe the length, and two to give the length
  349          return 3;
  350       }
  351       else if ( nLength <= 0xFFFFFF )
  352       {
  353          // Four bytes are necessary, one to say how many following bytes
  354          // describe the length, and three to give the length
  355          return 4;
  356       }
  357       else
  358       {
  359          // Five bytes are necessary, one to say how many following bytes
  360          // describe the length, and four to give the length
  361          return 5;
  362       }
  363 }
  364 
  365 
  366 /////////////////////////////////////////////////////////////////////////////
  367 //
  368 // Function:
  369 //    ASNDerCalcTokenLength
  370 //
  371 // Parameters:
  372 //    [in]  nLength           -  Length to calculate length bytes for.
  373 //    [in]  nDataLength       -  Actual Data length value.
  374 //
  375 // Returns:
  376 //    long  Number of bytes necessary to represent a token, length and data
  377 //
  378 // Comments :
  379 //    Helper function to calculate a token and value size, based on a
  380 //    supplied length value, and any binary data that will need to be
  381 //    written out.
  382 //
  383 ////////////////////////////////////////////////////////////////////////////
  384 
  385 long ASNDerCalcTokenLength( long nLength, long nDataLength )
  386 {
  387    // Add a byte to the length size to account for a single byte to
  388    // hold the token type.
  389    long  nTotalLength = ASNDerCalcNumLengthBytes( nLength ) + 1;
  390 
  391    return nTotalLength + nDataLength;
  392 }
  393 
  394 
  395 /////////////////////////////////////////////////////////////////////////////
  396 //
  397 // Function:
  398 //    ASNDerCalcElementLength
  399 //
  400 // Parameters:
  401 //    [in]  nDataLength       -  Length of data.
  402 //    [out] pnInternalLength  -  Filled out with length of element
  403 //                               without sequence info.
  404 //
  405 // Returns:
  406 //    long  Number of bytes necessary to represent an element
  407 //
  408 // Comments :
  409 //    Helper function to calculate an element length.  An element consists
  410 //    of a sequence token, a type token and then the data.
  411 //
  412 ////////////////////////////////////////////////////////////////////////////
  413 
  414 long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength )
  415 {
  416    // First the type token and the actual data
  417    long  nTotalLength = ASNDerCalcTokenLength( nDataLength, nDataLength );
  418 
  419    // Internal length is the length without the element sequence token
  420    if ( NULL != pnInternalLength )
  421    {
  422       *pnInternalLength = nTotalLength;
  423    }
  424 
  425    // Next add in the element's sequence token (remember that its
  426    // length is the total length of the type token and data)
  427    nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
  428 
  429    return nTotalLength;
  430 }
  431 
  432 /////////////////////////////////////////////////////////////////////////////
  433 //
  434 // Function:
  435 //    ASNDerCalcMechListLength
  436 //
  437 // Parameters:
  438 //    [in]  mechoid           -  Mech OID to put in list.
  439 //    [out] pnInternalLength  -  Filled out with length of element
  440 //                               without the primary sequence token.
  441 //
  442 // Returns:
  443 //    long  Number of bytes necessary to represent a mechList
  444 //
  445 // Comments :
  446 //    Helper function to calculate a MechList length.  A mechlist consists
  447 //    of a NegTokenInit sequence token, a sequence token for the MechList
  448 //    and finally a list of OIDs.  In our case, we only really have one
  449 //    OID.
  450 //
  451 ////////////////////////////////////////////////////////////////////////////
  452 
  453 long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength )
  454 {
  455    // First the OID
  456    long  nTotalLength = g_stcMechOIDList[mechoid].iLen;
  457 
  458    // Next add in a sequence token
  459    nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
  460 
  461    // Internal length is the length without the element sequence token
  462    if ( NULL != pnInternalLength )
  463    {
  464       *pnInternalLength = nTotalLength;
  465    }
  466 
  467    // Finally add in the element's sequence token
  468    nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
  469 
  470    return nTotalLength;
  471 }
  472 
  473 
  474 /////////////////////////////////////////////////////////////////////////////
  475 //
  476 // Function:
  477 //    ASNDerWriteLength
  478 //
  479 // Parameters:
  480 //    [out] pbData            -  Buffer to write into.
  481 //    [in]  nLength           -  Length to write out.
  482 //
  483 // Returns:
  484 //    int   Number of bytes written out
  485 //
  486 // Comments :
  487 //    Helper function to write out a length value following DER rules .
  488 //
  489 ////////////////////////////////////////////////////////////////////////////
  490 
  491 int ASNDerWriteLength( unsigned char* pbData, long nLength )
  492 {
  493    int   nNumBytesRequired = ASNDerCalcNumLengthBytes( nLength );
  494    int   nNumLengthBytes = nNumBytesRequired - 1;
  495 
  496 
  497    if ( nNumBytesRequired > 1 )
  498    {
  499 
  500       // Write out the number of bytes following which will be used
  501       *pbData = (unsigned char ) ( LEN_XTND | nNumLengthBytes );
  502 
  503       // Point to where we'll actually write the length
  504       pbData++;
  505 
  506 #ifdef __LITTLE_ENDIAN__
  507 
  508       // There may be a cleaner way to do this, but for now, this seems to be
  509       // an easy way to do the transformation
  510       switch ( nNumLengthBytes )
  511       {
  512          case 1:
  513          {
  514             // Cast the length to a single byte, since we know that it
  515             // is 0x7F or less (or we wouldn't only need a single byte).
  516       
  517             *pbData = (unsigned char) nLength;
  518             break;
  519          }
  520 
  521          case 2:
  522          {
  523             *pbData = *( ( (unsigned char*) &nLength ) + 1 );
  524             *( pbData + 1) = *( ( (unsigned char*) &nLength ) );
  525             break;
  526          }
  527 
  528          case 3:
  529          {
  530             *pbData = *( ( (unsigned char*) &nLength ) + 3 );
  531             *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 );
  532             *( pbData + 2) = *( ( (unsigned char*) &nLength ) );
  533             break;
  534          }
  535 
  536          case 4:
  537          {
  538             *pbData = *( ( (unsigned char*) &nLength ) + 3 );
  539             *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 );
  540             *( pbData + 2) = *( ( (unsigned char*) &nLength ) + 1 );
  541             *( pbData + 3) = *( ( (unsigned char*) &nLength ) );
  542             break;
  543          }
  544 
  545       }  // SWITCH ( nNumLengthBytes )
  546 
  547 #else
  548       // We are Big-Endian, so the length can be copied in from the source
  549       // as is.  Ensure that we adjust for the number of bytes we actually
  550       // copy.
  551 
  552       memcpy( pbData,
  553                ( (unsigned char *) &nLength ) + ( 4 - nNumLengthBytes ), nNumLengthBytes );
  554 #endif
  555 
  556    }  // IF > 1 byte for length
  557    else
  558    {
  559       // Cast the length to a single byte, since we know that it
  560       // is 0x7F or less (or we wouldn't only need a single byte).
  561       
  562       *pbData = (unsigned char) nLength;
  563    }
  564 
  565    return nNumBytesRequired;
  566 }
  567 
  568 /////////////////////////////////////////////////////////////////////////////
  569 //
  570 // Function:
  571 //    ASNDerWriteToken
  572 //
  573 // Parameters:
  574 //    [out] pbData            -  Buffer to write into.
  575 //    [in]  ucType            -  Token Type
  576 //    [in]  pbTokenValue      -  Actual Value
  577 //    [in]  nLength           -  Length of Data.
  578 //
  579 // Returns:
  580 //    int   Number of bytes written out
  581 //
  582 // Comments :
  583 //    Helper function to write out a token and any associated data.  If
  584 //    pbTokenValue is non-NULL, then it is written out in addition to the
  585 //    token identifier and the length bytes.
  586 //
  587 ////////////////////////////////////////////////////////////////////////////
  588 
  589 int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType,
  590                      unsigned char* pbTokenValue, long nLength )
  591 {
  592    int   nTotalBytesWrittenOut = 0L;
  593    int   nNumLengthBytesWritten = 0L;
  594 
  595    // Write out the type
  596    *pbData = ucType;
  597 
  598    // Wrote 1 byte, and move data pointer
  599    nTotalBytesWrittenOut++;
  600    pbData++;
  601 
  602    // Now write out the length and adjust the number of bytes written out
  603    nNumLengthBytesWritten = ASNDerWriteLength( pbData, nLength );
  604 
  605    nTotalBytesWrittenOut += nNumLengthBytesWritten;
  606    pbData += nNumLengthBytesWritten;
  607 
  608    // Write out the token value if we got one.  The assumption is that the
  609    // nLength value indicates how many bytes are in pbTokenValue.
  610 
  611    if ( NULL != pbTokenValue )
  612    {
  613       memcpy( pbData, pbTokenValue, nLength );
  614       nTotalBytesWrittenOut += nLength;
  615    }
  616 
  617    return nTotalBytesWrittenOut;
  618 }
  619 
  620 
  621 /////////////////////////////////////////////////////////////////////////////
  622 //
  623 // Function:
  624 //    ASNDerWriteOID
  625 //
  626 // Parameters:
  627 //    [out] pbData            -  Buffer to write into.
  628 //    [in]  eMechOID          -  OID to write out.
  629 //
  630 // Returns:
  631 //    int   Number of bytes written out
  632 //
  633 // Comments :
  634 //    Helper function to write out an OID.  For these we have the raw bytes
  635 //    listed in a global structure.  The caller simply indicates which OID
  636 //    should be written and we will splat out the data.
  637 //
  638 ////////////////////////////////////////////////////////////////////////////
  639 
  640 int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID )
  641 {
  642 
  643    memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen );
  644 
  645    return g_stcMechOIDList[eMechOID].iLen;
  646 }
  647 
  648 
  649 /////////////////////////////////////////////////////////////////////////////
  650 //
  651 // Function:
  652 //    ASNDerWriteMechList
  653 //
  654 // Parameters:
  655 //    [out] pbData            -  Buffer to write into.
  656 //    [in]  eMechOID          -  OID to put in MechList.
  657 //
  658 // Returns:
  659 //    int   Number of bytes written out
  660 //
  661 // Comments :
  662 //    Helper function to write out a MechList.  A MechList consists of the
  663 //    Init Token Sequence, a sequence token and then the list of OIDs.  In
  664 //    our case the OID is from a global array of known OIDs.
  665 //
  666 ////////////////////////////////////////////////////////////////////////////
  667 
  668 long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid )
  669 {
  670    // First get the length
  671    long  nInternalLength = 0L;
  672    long  nMechListLength = ASNDerCalcMechListLength( mechoid, &nInternalLength );
  673    long  nTempLength = 0L;
  674 
  675    nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
  676                                     NULL, nInternalLength );
  677 
  678    // Adjust the data pointer
  679    pbData += nTempLength;
  680 
  681    // Now write the Sequence token and the OID (the OID is a BLOB in the global
  682    // structure.
  683 
  684    nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE,
  685                                     g_stcMechOIDList[mechoid].ucOid,
  686                                     g_stcMechOIDList[mechoid].iLen );
  687 
  688    return nMechListLength;
  689 }
  690 
  691 
  692 /////////////////////////////////////////////////////////////////////////////
  693 //
  694 // Function:
  695 //    ASNDerWriteElement
  696 //
  697 // Parameters:
  698 //    [out] pbData            -  Buffer to write into.
  699 //    [in]  ucElementSequence -  Sequence Token
  700 //    [in]  ucType            -  Token Type
  701 //    [in]  pbTokenValue      -  Actual Value
  702 //    [in]  nLength           -  Length of Data.
  703 //
  704 // Returns:
  705 //    int   Number of bytes written out
  706 //
  707 // Comments :
  708 //    Helper function to write out a SPNEGO Token element.  An element
  709 //    consists of a sequence token, a type token and the associated data.
  710 //
  711 ////////////////////////////////////////////////////////////////////////////
  712 
  713 int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence,
  714                         unsigned char ucType, unsigned char* pbTokenValue, long nLength )
  715 {
  716    // First get the length
  717    long  nInternalLength = 0L;
  718    long  nElementLength = ASNDerCalcElementLength( nLength, &nInternalLength );
  719    long  nTempLength = 0L;
  720 
  721    // Write out the sequence byte and the length of the type and data
  722    nTempLength = ASNDerWriteToken( pbData, ucElementSequence, NULL, nInternalLength );
  723 
  724    // Adjust the data pointer
  725    pbData += nTempLength;
  726 
  727    // Now write the type and the data.
  728    nTempLength = ASNDerWriteToken( pbData, ucType, pbTokenValue, nLength );
  729 
  730    return nElementLength;
  731 }
  732