xref: /illumos-gate/usr/src/lib/libsmbfs/smb/derparse.c (revision 613a2f6ba31e891e3d947a356daf5e563d43c1ce)
14bff34e3Sthurlow // Copyright (C) 2002 Microsoft Corporation
24bff34e3Sthurlow // All rights reserved.
34bff34e3Sthurlow //
44bff34e3Sthurlow // THIS CODE AND INFORMATION IS PROVIDED "AS IS"
54bff34e3Sthurlow // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
64bff34e3Sthurlow // OR IMPLIED, INCLUDING BUT NOT LIMITED
74bff34e3Sthurlow // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
84bff34e3Sthurlow // AND/OR FITNESS FOR A PARTICULAR PURPOSE.
94bff34e3Sthurlow //
104bff34e3Sthurlow // Date    - 10/08/2002
114bff34e3Sthurlow // Author  - Sanj Surati
124bff34e3Sthurlow 
134bff34e3Sthurlow 
144bff34e3Sthurlow /////////////////////////////////////////////////////////////
154bff34e3Sthurlow //
164bff34e3Sthurlow // DERPARSE.C
174bff34e3Sthurlow //
184bff34e3Sthurlow // SPNEGO Token Handler Source File
194bff34e3Sthurlow //
204bff34e3Sthurlow // Contains implementation of ASN.1 DER read/write functions
214bff34e3Sthurlow // as defined in DERPARSE.H.
224bff34e3Sthurlow //
234bff34e3Sthurlow /////////////////////////////////////////////////////////////
244bff34e3Sthurlow 
254bff34e3Sthurlow #include <stdlib.h>
264bff34e3Sthurlow #include <stdio.h>
274bff34e3Sthurlow #include <memory.h>
284bff34e3Sthurlow #include <sys/byteorder.h>
294bff34e3Sthurlow #include "spnego.h"
304bff34e3Sthurlow #include "derparse.h"
314bff34e3Sthurlow 
324bff34e3Sthurlow //
334bff34e3Sthurlow // The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in
344bff34e3Sthurlow // the array below, that a mechanism can be found.
354bff34e3Sthurlow //
36*613a2f6bSGordon Ross 
374bff34e3Sthurlow #pragma error_messages (off,E_INITIALIZATION_TYPE_MISMATCH)
384bff34e3Sthurlow MECH_OID g_stcMechOIDList [] =
394bff34e3Sthurlow {
404bff34e3Sthurlow 	{"\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02",	11,  9,
414bff34e3Sthurlow 	 spnego_mech_oid_Kerberos_V5_Legacy	},	// 1.2.840.48018.1.2.2
424bff34e3Sthurlow 	{"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02",	11,  9,
434bff34e3Sthurlow 	 spnego_mech_oid_Kerberos_V5		}, // 1.2.840.113554.1.2.2
444bff34e3Sthurlow 	{"\x06\x06\x2b\x06\x01\x05\x05\x02",			 8,  6,
454bff34e3Sthurlow 	 spnego_mech_oid_Spnego			}, // 1.3.6.1.5.5.2
464bff34e3Sthurlow 	{"\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a",	12, 10,
474bff34e3Sthurlow 	 spnego_mech_oid_NTLMSSP		}, // 1.3.6.1.4.1.311.2.2.10
484bff34e3Sthurlow 	{"", 0,  0, spnego_mech_oid_NotUsed	}  // Placeholder
494bff34e3Sthurlow };
504bff34e3Sthurlow #pragma error_messages (default,E_INITIALIZATION_TYPE_MISMATCH)
514bff34e3Sthurlow 
524bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
534bff34e3Sthurlow //
544bff34e3Sthurlow // Function:
554bff34e3Sthurlow //    ASNDerGetLength
564bff34e3Sthurlow //
574bff34e3Sthurlow // Parameters:
584bff34e3Sthurlow //    [in]  pbLengthData      -  DER Length Data
594bff34e3Sthurlow //    [in]  nBoundaryLength   -  Length that value must not exceed.
604bff34e3Sthurlow //    [out] pnLength          -  Filled out with length value
614bff34e3Sthurlow //    [out] pnNumLengthBytes  -  Filled out with number of bytes
624bff34e3Sthurlow //                               consumed by DER length.
634bff34e3Sthurlow //
644bff34e3Sthurlow // Returns:
654bff34e3Sthurlow //    int   Success - SPNEGO_E_SUCCESS
664bff34e3Sthurlow //          Failure - SPNEGO API Error code
674bff34e3Sthurlow //
684bff34e3Sthurlow // Comments :
694bff34e3Sthurlow //    Interprets the data at pbLengthData as a DER length.  The length must
704bff34e3Sthurlow //    fit within the bounds of nBoundary length.  We do not currently
714bff34e3Sthurlow //    process lengths that take more than 4 bytes.
724bff34e3Sthurlow //
734bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
744bff34e3Sthurlow 
754bff34e3Sthurlow int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength,
764bff34e3Sthurlow                      long* pnNumLengthBytes )
774bff34e3Sthurlow {
784bff34e3Sthurlow    int   nReturn = SPNEGO_E_INVALID_LENGTH;
794bff34e3Sthurlow    int   nNumLengthBytes = 0;
804bff34e3Sthurlow 
814bff34e3Sthurlow    // First check if the extended length bit is set
824bff34e3Sthurlow 
834bff34e3Sthurlow    if ( *pbLengthData & LEN_XTND )
844bff34e3Sthurlow    {
854bff34e3Sthurlow       // Lower 7 bits contain the number of trailing bytes that describe the length
864bff34e3Sthurlow       nNumLengthBytes = *pbLengthData & LEN_MASK;
874bff34e3Sthurlow 
884bff34e3Sthurlow       // Check that the number of bytes we are about to read is within our boundary
894bff34e3Sthurlow       // constraints
904bff34e3Sthurlow 
914bff34e3Sthurlow       if ( nNumLengthBytes <= nBoundaryLength - 1 )
924bff34e3Sthurlow       {
934bff34e3Sthurlow 
944bff34e3Sthurlow          // For now, our handler won't deal with lengths greater than 4 bytes
954bff34e3Sthurlow          if ( nNumLengthBytes >= 1 && nNumLengthBytes <= 4 )
964bff34e3Sthurlow          {
974bff34e3Sthurlow             // 0 out the initial length
984bff34e3Sthurlow             *pnLength = 0L;
994bff34e3Sthurlow 
1004bff34e3Sthurlow             // Bump by 1 byte
1014bff34e3Sthurlow             pbLengthData++;
1024bff34e3Sthurlow 
1034bff34e3Sthurlow    #ifdef _LITTLE_ENDIAN
1044bff34e3Sthurlow 
1054bff34e3Sthurlow             // There may be a cleaner way to do this, but for now, this seems to be
1064bff34e3Sthurlow             // an easy way to do the transformation
1074bff34e3Sthurlow             switch ( nNumLengthBytes )
1084bff34e3Sthurlow             {
1094bff34e3Sthurlow                case 1:
1104bff34e3Sthurlow                {
1114bff34e3Sthurlow                   *( ( (unsigned char*) pnLength ) ) = *pbLengthData;
1124bff34e3Sthurlow                   break;
1134bff34e3Sthurlow                }
1144bff34e3Sthurlow 
1154bff34e3Sthurlow                case 2:
1164bff34e3Sthurlow                {
1174bff34e3Sthurlow                   *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 1);
1184bff34e3Sthurlow                   *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData);
1194bff34e3Sthurlow 
1204bff34e3Sthurlow                   break;
1214bff34e3Sthurlow                }
1224bff34e3Sthurlow 
1234bff34e3Sthurlow                case 3:
1244bff34e3Sthurlow                {
1254bff34e3Sthurlow                   *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 2);
1264bff34e3Sthurlow                   *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1);
1274bff34e3Sthurlow                   *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData);
1284bff34e3Sthurlow                   break;
1294bff34e3Sthurlow                }
1304bff34e3Sthurlow 
1314bff34e3Sthurlow                case 4:
1324bff34e3Sthurlow                {
1334bff34e3Sthurlow                   *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 3);
1344bff34e3Sthurlow                   *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData + 2);
1354bff34e3Sthurlow                   *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1);
1364bff34e3Sthurlow                   *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData);
1374bff34e3Sthurlow                   break;
1384bff34e3Sthurlow                }
1394bff34e3Sthurlow 
1404bff34e3Sthurlow             }  // SWITCH ( nNumLengthBytes )
1414bff34e3Sthurlow 
1424bff34e3Sthurlow    #else
1434bff34e3Sthurlow             // We are Big-Endian, so the length can be copied in from the source
1444bff34e3Sthurlow             // as is.  Ensure that we adjust for the number of bytes we actually
1454bff34e3Sthurlow             // copy.
1464bff34e3Sthurlow 
1474bff34e3Sthurlow             memcpy( ( (unsigned char *) pnLength ) + ( 4 - nNumLengthBytes ),
1484bff34e3Sthurlow                      pbLengthData, nNumLengthBytes );
1494bff34e3Sthurlow    #endif
1504bff34e3Sthurlow 
1514bff34e3Sthurlow             // Account for the initial length byte
1524bff34e3Sthurlow             *pnNumLengthBytes = nNumLengthBytes + 1;
1534bff34e3Sthurlow             nReturn = SPNEGO_E_SUCCESS;
1544bff34e3Sthurlow 
1554bff34e3Sthurlow          }  // IF Valid Length
1564bff34e3Sthurlow 
1574bff34e3Sthurlow       }  // IF num bytes to read is within the boundary length
1584bff34e3Sthurlow 
1594bff34e3Sthurlow    }  // IF xtended length
1604bff34e3Sthurlow    else
1614bff34e3Sthurlow    {
1624bff34e3Sthurlow 
1634bff34e3Sthurlow       // Extended bit is not set, so the length is in the value and the one
1644bff34e3Sthurlow       // byte describes the length
1654bff34e3Sthurlow       *pnLength = *pbLengthData & LEN_MASK;
1664bff34e3Sthurlow       *pnNumLengthBytes = 1;
1674bff34e3Sthurlow       nReturn = SPNEGO_E_SUCCESS;
1684bff34e3Sthurlow 
1694bff34e3Sthurlow    }
1704bff34e3Sthurlow 
1714bff34e3Sthurlow    return nReturn;
1724bff34e3Sthurlow }
1734bff34e3Sthurlow 
1744bff34e3Sthurlow 
1754bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
1764bff34e3Sthurlow //
1774bff34e3Sthurlow // Function:
1784bff34e3Sthurlow //    ASNDerCheckToken
1794bff34e3Sthurlow //
1804bff34e3Sthurlow // Parameters:
1814bff34e3Sthurlow //    [in]  pbTokenData       -  Token Data
1824bff34e3Sthurlow //    [in]  nToken            -  Token identifier to check for
1834bff34e3Sthurlow //    [in]  nLengthWithToken  -  Expected token length (with data)
1844bff34e3Sthurlow //    [in]  nBoundaryLength   -  Length that value must not exceed.
1854bff34e3Sthurlow //    [out] pnLength          -  Filled out with data length
1864bff34e3Sthurlow //    [out] pnTokenLength     -  Filled out with number of bytes
1874bff34e3Sthurlow //                               consumed by token identifier and length.
1884bff34e3Sthurlow //
1894bff34e3Sthurlow // Returns:
1904bff34e3Sthurlow //    int   Success - SPNEGO_E_SUCCESS
1914bff34e3Sthurlow //          Failure - SPNEGO API Error code
1924bff34e3Sthurlow //
1934bff34e3Sthurlow // Comments :
1944bff34e3Sthurlow //    Checks the data pointed to by pbTokenData for the specified token
1954bff34e3Sthurlow //    identifier and the length that immediately follows.  If
1964bff34e3Sthurlow //    nLengthWithToken is > 0, the calculated length must match.  The
1974bff34e3Sthurlow //    length must also not exceed the specified boundary length .
1984bff34e3Sthurlow //
1994bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
2004bff34e3Sthurlow 
2014bff34e3Sthurlow int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
2024bff34e3Sthurlow                         long nLengthWithToken, long nBoundaryLength,
2034bff34e3Sthurlow                         long* pnLength, long* pnTokenLength )
2044bff34e3Sthurlow {
2054bff34e3Sthurlow 
2064bff34e3Sthurlow    int   nReturn = SPNEGO_E_INVALID_LENGTH;
2074bff34e3Sthurlow    long  nNumLengthBytes = 0L;
2084bff34e3Sthurlow 
2094bff34e3Sthurlow    // Make sure that we've at least got 2 bytes of room to work with
2104bff34e3Sthurlow 
2114bff34e3Sthurlow    if ( nBoundaryLength >= 2 )
2124bff34e3Sthurlow    {
2134bff34e3Sthurlow       // The first byte of the token data MUST match the specified token
2144bff34e3Sthurlow       if ( *pbTokenData == nToken )
2154bff34e3Sthurlow       {
2164bff34e3Sthurlow          // Next byte indicates the length
2174bff34e3Sthurlow          pbTokenData++;
2184bff34e3Sthurlow 
2194bff34e3Sthurlow          // Get the length described by the token
2204bff34e3Sthurlow          if ( ( nReturn = ASNDerGetLength( pbTokenData, nBoundaryLength, pnLength,
2214bff34e3Sthurlow                                              &nNumLengthBytes )  ) == SPNEGO_E_SUCCESS )
2224bff34e3Sthurlow          {
2234bff34e3Sthurlow             // Verify that the length is LESS THAN the boundary length
2244bff34e3Sthurlow             // (this should prevent us walking out of our buffer)
2254bff34e3Sthurlow             if ( ( nBoundaryLength - ( nNumLengthBytes + 1 ) < *pnLength ) )
2264bff34e3Sthurlow             {
2274bff34e3Sthurlow 
2284bff34e3Sthurlow                nReturn = SPNEGO_E_INVALID_LENGTH;
2294bff34e3Sthurlow 
2304bff34e3Sthurlow             }
2314bff34e3Sthurlow 
2324bff34e3Sthurlow             // If we were passed a length to check, do so now
2334bff34e3Sthurlow             if ( nLengthWithToken > 0L )
2344bff34e3Sthurlow             {
2354bff34e3Sthurlow 
2364bff34e3Sthurlow                // Check that the expected length matches
2374bff34e3Sthurlow                if ( ( nLengthWithToken - ( nNumLengthBytes + 1 ) ) != *pnLength )
2384bff34e3Sthurlow                {
2394bff34e3Sthurlow 
2404bff34e3Sthurlow                   nReturn = SPNEGO_E_INVALID_LENGTH;
2414bff34e3Sthurlow 
2424bff34e3Sthurlow                }
2434bff34e3Sthurlow 
2444bff34e3Sthurlow             }  // IF need to validate length
2454bff34e3Sthurlow 
2464bff34e3Sthurlow             if ( SPNEGO_E_SUCCESS == nReturn )
2474bff34e3Sthurlow             {
2484bff34e3Sthurlow                *pnTokenLength = nNumLengthBytes + 1;
2494bff34e3Sthurlow             }
2504bff34e3Sthurlow 
2514bff34e3Sthurlow          }  // IF ASNDerGetLength
2524bff34e3Sthurlow 
2534bff34e3Sthurlow       }  // IF token matches
2544bff34e3Sthurlow       else
2554bff34e3Sthurlow       {
2564bff34e3Sthurlow          nReturn = SPNEGO_E_TOKEN_NOT_FOUND;
2574bff34e3Sthurlow       }
2584bff34e3Sthurlow 
2594bff34e3Sthurlow    }  // IF Boundary Length is at least 2 bytes
2604bff34e3Sthurlow 
2614bff34e3Sthurlow    return nReturn;
2624bff34e3Sthurlow }
2634bff34e3Sthurlow 
2644bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
2654bff34e3Sthurlow //
2664bff34e3Sthurlow // Function:
2674bff34e3Sthurlow //    ASNDerCheckOID
2684bff34e3Sthurlow //
2694bff34e3Sthurlow // Parameters:
2704bff34e3Sthurlow //    [in]  pbTokenData       -  Token Data
2714bff34e3Sthurlow //    [in]  nMechOID          -  OID we are looking for
2724bff34e3Sthurlow //    [in]  nBoundaryLength   -  Length that value must not exceed.
2734bff34e3Sthurlow //    [out] pnTokenLength     -  Filled out with number of bytes
2744bff34e3Sthurlow //                               consumed by token and data.
2754bff34e3Sthurlow //
2764bff34e3Sthurlow // Returns:
2774bff34e3Sthurlow //    int   Success - SPNEGO_E_SUCCESS
2784bff34e3Sthurlow //          Failure - SPNEGO API Error code
2794bff34e3Sthurlow //
2804bff34e3Sthurlow // Comments :
2814bff34e3Sthurlow //    Checks the data pointed to by pbTokenData for the specified OID.
2824bff34e3Sthurlow //
2834bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
2844bff34e3Sthurlow 
2854bff34e3Sthurlow int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength,
2864bff34e3Sthurlow                      long* pnTokenLength )
2874bff34e3Sthurlow {
2884bff34e3Sthurlow    int   nReturn = 0L;
2894bff34e3Sthurlow    long  nLength = 0L;
2904bff34e3Sthurlow 
2914bff34e3Sthurlow    // Verify that we have an OID token
2924bff34e3Sthurlow    if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, 0L, nBoundaryLength,
2934bff34e3Sthurlow                                        &nLength, pnTokenLength ) ) == SPNEGO_E_SUCCESS )
2944bff34e3Sthurlow    {
2954bff34e3Sthurlow       // Add the data length to the Token Length
2964bff34e3Sthurlow       *pnTokenLength += nLength;
2974bff34e3Sthurlow 
2984bff34e3Sthurlow       // Token Lengths plus the actual length must match the length in our OID list element.
2994bff34e3Sthurlow       // If it doesn't, we're done
3004bff34e3Sthurlow       if ( *pnTokenLength == g_stcMechOIDList[nMechOID].iLen )
3014bff34e3Sthurlow       {
3024bff34e3Sthurlow          // Memcompare the token and the expected field
3034bff34e3Sthurlow          if ( memcmp( pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength ) != 0 )
3044bff34e3Sthurlow          {
3054bff34e3Sthurlow             nReturn = SPNEGO_E_UNEXPECTED_OID;
3064bff34e3Sthurlow          }
3074bff34e3Sthurlow       }
3084bff34e3Sthurlow       else
3094bff34e3Sthurlow       {
3104bff34e3Sthurlow          nReturn = SPNEGO_E_UNEXPECTED_OID;
3114bff34e3Sthurlow       }
3124bff34e3Sthurlow 
3134bff34e3Sthurlow    }  // IF OID Token CHecks
3144bff34e3Sthurlow 
3154bff34e3Sthurlow    return nReturn;
3164bff34e3Sthurlow }
3174bff34e3Sthurlow 
3184bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
3194bff34e3Sthurlow //
3204bff34e3Sthurlow // Function:
3214bff34e3Sthurlow //    ASNDerCalcNumLengthBytes
3224bff34e3Sthurlow //
3234bff34e3Sthurlow // Parameters:
3244bff34e3Sthurlow //    [in]  nLength           -  Length to calculate length bytes for.
3254bff34e3Sthurlow //
3264bff34e3Sthurlow // Returns:
3274bff34e3Sthurlow //    int   Number of bytes necessary to represent length
3284bff34e3Sthurlow //
3294bff34e3Sthurlow // Comments :
3304bff34e3Sthurlow //    Helper function to calculate the number of length bytes necessary to
3314bff34e3Sthurlow //    represent a length value.  For our purposes, a 32-bit value should be
3324bff34e3Sthurlow //    enough to describea length.
3334bff34e3Sthurlow //
3344bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
3354bff34e3Sthurlow 
3364bff34e3Sthurlow int ASNDerCalcNumLengthBytes( long nLength )
3374bff34e3Sthurlow {
3384bff34e3Sthurlow       if ( nLength <= 0x7F )
3394bff34e3Sthurlow       {
3404bff34e3Sthurlow          // A single byte will be sufficient for describing this length.
3414bff34e3Sthurlow          // The byte will simply contain the length
3424bff34e3Sthurlow          return 1;
3434bff34e3Sthurlow       }
3444bff34e3Sthurlow       else if ( nLength <= 0xFF )
3454bff34e3Sthurlow       {
3464bff34e3Sthurlow          // Two bytes are necessary, one to say how many following bytes
3474bff34e3Sthurlow          // describe the length, and one to give the length
3484bff34e3Sthurlow          return 2;
3494bff34e3Sthurlow       }
3504bff34e3Sthurlow       else if ( nLength <= 0xFFFF )
3514bff34e3Sthurlow       {
3524bff34e3Sthurlow          // Three bytes are necessary, one to say how many following bytes
3534bff34e3Sthurlow          // describe the length, and two to give the length
3544bff34e3Sthurlow          return 3;
3554bff34e3Sthurlow       }
3564bff34e3Sthurlow       else if ( nLength <= 0xFFFFFF )
3574bff34e3Sthurlow       {
3584bff34e3Sthurlow          // Four bytes are necessary, one to say how many following bytes
3594bff34e3Sthurlow          // describe the length, and three to give the length
3604bff34e3Sthurlow          return 4;
3614bff34e3Sthurlow       }
3624bff34e3Sthurlow       else
3634bff34e3Sthurlow       {
3644bff34e3Sthurlow          // Five bytes are necessary, one to say how many following bytes
3654bff34e3Sthurlow          // describe the length, and four to give the length
3664bff34e3Sthurlow          return 5;
3674bff34e3Sthurlow       }
3684bff34e3Sthurlow }
3694bff34e3Sthurlow 
3704bff34e3Sthurlow 
3714bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
3724bff34e3Sthurlow //
3734bff34e3Sthurlow // Function:
3744bff34e3Sthurlow //    ASNDerCalcTokenLength
3754bff34e3Sthurlow //
3764bff34e3Sthurlow // Parameters:
3774bff34e3Sthurlow //    [in]  nLength           -  Length to calculate length bytes for.
3784bff34e3Sthurlow //    [in]  nDataLength       -  Actual Data length value.
3794bff34e3Sthurlow //
3804bff34e3Sthurlow // Returns:
3814bff34e3Sthurlow //    long  Number of bytes necessary to represent a token, length and data
3824bff34e3Sthurlow //
3834bff34e3Sthurlow // Comments :
3844bff34e3Sthurlow //    Helper function to calculate a token and value size, based on a
3854bff34e3Sthurlow //    supplied length value, and any binary data that will need to be
3864bff34e3Sthurlow //    written out.
3874bff34e3Sthurlow //
3884bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
3894bff34e3Sthurlow 
3904bff34e3Sthurlow long ASNDerCalcTokenLength( long nLength, long nDataLength )
3914bff34e3Sthurlow {
3924bff34e3Sthurlow    // Add a byte to the length size to account for a single byte to
3934bff34e3Sthurlow    // hold the token type.
3944bff34e3Sthurlow    long  nTotalLength = ASNDerCalcNumLengthBytes( nLength ) + 1;
3954bff34e3Sthurlow 
3964bff34e3Sthurlow    return nTotalLength + nDataLength;
3974bff34e3Sthurlow }
3984bff34e3Sthurlow 
3994bff34e3Sthurlow 
4004bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
4014bff34e3Sthurlow //
4024bff34e3Sthurlow // Function:
4034bff34e3Sthurlow //    ASNDerCalcElementLength
4044bff34e3Sthurlow //
4054bff34e3Sthurlow // Parameters:
4064bff34e3Sthurlow //    [in]  nDataLength       -  Length of data.
4074bff34e3Sthurlow //    [out] pnInternalLength  -  Filled out with length of element
4084bff34e3Sthurlow //                               without sequence info.
4094bff34e3Sthurlow //
4104bff34e3Sthurlow // Returns:
4114bff34e3Sthurlow //    long  Number of bytes necessary to represent an element
4124bff34e3Sthurlow //
4134bff34e3Sthurlow // Comments :
4144bff34e3Sthurlow //    Helper function to calculate an element length.  An element consists
4154bff34e3Sthurlow //    of a sequence token, a type token and then the data.
4164bff34e3Sthurlow //
4174bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
4184bff34e3Sthurlow 
4194bff34e3Sthurlow long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength )
4204bff34e3Sthurlow {
4214bff34e3Sthurlow    // First the type token and the actual data
4224bff34e3Sthurlow    long  nTotalLength = ASNDerCalcTokenLength( nDataLength, nDataLength );
4234bff34e3Sthurlow 
4244bff34e3Sthurlow    // Internal length is the length without the element sequence token
4254bff34e3Sthurlow    if ( NULL != pnInternalLength )
4264bff34e3Sthurlow    {
4274bff34e3Sthurlow       *pnInternalLength = nTotalLength;
4284bff34e3Sthurlow    }
4294bff34e3Sthurlow 
4304bff34e3Sthurlow    // Next add in the element's sequence token (remember that its
4314bff34e3Sthurlow    // length is the total length of the type token and data)
4324bff34e3Sthurlow    nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
4334bff34e3Sthurlow 
4344bff34e3Sthurlow    return nTotalLength;
4354bff34e3Sthurlow }
4364bff34e3Sthurlow 
4374bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
4384bff34e3Sthurlow //
4394bff34e3Sthurlow // Function:
4404bff34e3Sthurlow //    ASNDerCalcMechListLength
4414bff34e3Sthurlow //
4424bff34e3Sthurlow // Parameters:
4434bff34e3Sthurlow //    [in]  mechoid           -  Mech OID to put in list.
4444bff34e3Sthurlow //    [out] pnInternalLength  -  Filled out with length of element
4454bff34e3Sthurlow //                               without the primary sequence token.
4464bff34e3Sthurlow //
4474bff34e3Sthurlow // Returns:
4484bff34e3Sthurlow //    long  Number of bytes necessary to represent a mechList
4494bff34e3Sthurlow //
4504bff34e3Sthurlow // Comments :
4514bff34e3Sthurlow //    Helper function to calculate a MechList length.  A mechlist consists
4524bff34e3Sthurlow //    of a NegTokenInit sequence token, a sequence token for the MechList
4534bff34e3Sthurlow //    and finally a list of OIDs.  In our case, we only really have one
4544bff34e3Sthurlow //    OID.
4554bff34e3Sthurlow //
4564bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
4574bff34e3Sthurlow 
4584bff34e3Sthurlow long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength )
4594bff34e3Sthurlow {
4604bff34e3Sthurlow    // First the OID
4614bff34e3Sthurlow    long  nTotalLength = g_stcMechOIDList[mechoid].iLen;
4624bff34e3Sthurlow 
4634bff34e3Sthurlow    // Next add in a sequence token
4644bff34e3Sthurlow    nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
4654bff34e3Sthurlow 
4664bff34e3Sthurlow    // Internal length is the length without the element sequence token
4674bff34e3Sthurlow    if ( NULL != pnInternalLength )
4684bff34e3Sthurlow    {
4694bff34e3Sthurlow       *pnInternalLength = nTotalLength;
4704bff34e3Sthurlow    }
4714bff34e3Sthurlow 
4724bff34e3Sthurlow    // Finally add in the element's sequence token
4734bff34e3Sthurlow    nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
4744bff34e3Sthurlow 
4754bff34e3Sthurlow    return nTotalLength;
4764bff34e3Sthurlow }
4774bff34e3Sthurlow 
4784bff34e3Sthurlow 
4794bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
4804bff34e3Sthurlow //
4814bff34e3Sthurlow // Function:
4824bff34e3Sthurlow //    ASNDerWriteLength
4834bff34e3Sthurlow //
4844bff34e3Sthurlow // Parameters:
4854bff34e3Sthurlow //    [out] pbData            -  Buffer to write into.
4864bff34e3Sthurlow //    [in]  nLength           -  Length to write out.
4874bff34e3Sthurlow //
4884bff34e3Sthurlow // Returns:
4894bff34e3Sthurlow //    int   Number of bytes written out
4904bff34e3Sthurlow //
4914bff34e3Sthurlow // Comments :
4924bff34e3Sthurlow //    Helper function to write out a length value following DER rules .
4934bff34e3Sthurlow //
4944bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
4954bff34e3Sthurlow 
4964bff34e3Sthurlow int ASNDerWriteLength( unsigned char* pbData, long nLength )
4974bff34e3Sthurlow {
4984bff34e3Sthurlow    int   nNumBytesRequired = ASNDerCalcNumLengthBytes( nLength );
4994bff34e3Sthurlow    int   nNumLengthBytes = nNumBytesRequired - 1;
5004bff34e3Sthurlow 
5014bff34e3Sthurlow 
5024bff34e3Sthurlow    if ( nNumBytesRequired > 1 )
5034bff34e3Sthurlow    {
5044bff34e3Sthurlow 
5054bff34e3Sthurlow       // Write out the number of bytes following which will be used
5064bff34e3Sthurlow       *pbData = (unsigned char ) ( LEN_XTND | nNumLengthBytes );
5074bff34e3Sthurlow 
5084bff34e3Sthurlow       // Point to where we'll actually write the length
5094bff34e3Sthurlow       pbData++;
5104bff34e3Sthurlow 
5114bff34e3Sthurlow #ifdef  _LITTLE_ENDIAN
5124bff34e3Sthurlow 
5134bff34e3Sthurlow       // There may be a cleaner way to do this, but for now, this seems to be
5144bff34e3Sthurlow       // an easy way to do the transformation
5154bff34e3Sthurlow       switch ( nNumLengthBytes )
5164bff34e3Sthurlow       {
5174bff34e3Sthurlow          case 1:
5184bff34e3Sthurlow          {
5194bff34e3Sthurlow             // Cast the length to a single byte, since we know that it
5204bff34e3Sthurlow             // is 0x7F or less (or we wouldn't only need a single byte).
5214bff34e3Sthurlow 
5224bff34e3Sthurlow             *pbData = (unsigned char) nLength;
5234bff34e3Sthurlow             break;
5244bff34e3Sthurlow          }
5254bff34e3Sthurlow 
5264bff34e3Sthurlow          case 2:
5274bff34e3Sthurlow          {
5284bff34e3Sthurlow             *pbData = *( ( (unsigned char*) &nLength ) + 1 );
5294bff34e3Sthurlow             *( pbData + 1) = *( ( (unsigned char*) &nLength ) );
5304bff34e3Sthurlow             break;
5314bff34e3Sthurlow          }
5324bff34e3Sthurlow 
5334bff34e3Sthurlow          case 3:
5344bff34e3Sthurlow          {
5354bff34e3Sthurlow             *pbData = *( ( (unsigned char*) &nLength ) + 3 );
5364bff34e3Sthurlow             *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 );
5374bff34e3Sthurlow             *( pbData + 2) = *( ( (unsigned char*) &nLength ) );
5384bff34e3Sthurlow             break;
5394bff34e3Sthurlow          }
5404bff34e3Sthurlow 
5414bff34e3Sthurlow          case 4:
5424bff34e3Sthurlow          {
5434bff34e3Sthurlow             *pbData = *( ( (unsigned char*) &nLength ) + 3 );
5444bff34e3Sthurlow             *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 );
5454bff34e3Sthurlow             *( pbData + 2) = *( ( (unsigned char*) &nLength ) + 1 );
5464bff34e3Sthurlow             *( pbData + 3) = *( ( (unsigned char*) &nLength ) );
5474bff34e3Sthurlow             break;
5484bff34e3Sthurlow          }
5494bff34e3Sthurlow 
5504bff34e3Sthurlow       }  // SWITCH ( nNumLengthBytes )
5514bff34e3Sthurlow 
5524bff34e3Sthurlow #else
5534bff34e3Sthurlow       // We are Big-Endian, so the length can be copied in from the source
5544bff34e3Sthurlow       // as is.  Ensure that we adjust for the number of bytes we actually
5554bff34e3Sthurlow       // copy.
5564bff34e3Sthurlow 
5574bff34e3Sthurlow       memcpy( pbData,
5584bff34e3Sthurlow                ( (unsigned char *) &nLength ) + ( 4 - nNumLengthBytes ), nNumLengthBytes );
5594bff34e3Sthurlow #endif
5604bff34e3Sthurlow 
5614bff34e3Sthurlow    }  // IF > 1 byte for length
5624bff34e3Sthurlow    else
5634bff34e3Sthurlow    {
5644bff34e3Sthurlow       // Cast the length to a single byte, since we know that it
5654bff34e3Sthurlow       // is 0x7F or less (or we wouldn't only need a single byte).
5664bff34e3Sthurlow 
5674bff34e3Sthurlow       *pbData = (unsigned char) nLength;
5684bff34e3Sthurlow    }
5694bff34e3Sthurlow 
5704bff34e3Sthurlow    return nNumBytesRequired;
5714bff34e3Sthurlow }
5724bff34e3Sthurlow 
5734bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
5744bff34e3Sthurlow //
5754bff34e3Sthurlow // Function:
5764bff34e3Sthurlow //    ASNDerWriteToken
5774bff34e3Sthurlow //
5784bff34e3Sthurlow // Parameters:
5794bff34e3Sthurlow //    [out] pbData            -  Buffer to write into.
5804bff34e3Sthurlow //    [in]  ucType            -  Token Type
5814bff34e3Sthurlow //    [in]  pbTokenValue      -  Actual Value
5824bff34e3Sthurlow //    [in]  nLength           -  Length of Data.
5834bff34e3Sthurlow //
5844bff34e3Sthurlow // Returns:
5854bff34e3Sthurlow //    int   Number of bytes written out
5864bff34e3Sthurlow //
5874bff34e3Sthurlow // Comments :
5884bff34e3Sthurlow //    Helper function to write out a token and any associated data.  If
5894bff34e3Sthurlow //    pbTokenValue is non-NULL, then it is written out in addition to the
5904bff34e3Sthurlow //    token identifier and the length bytes.
5914bff34e3Sthurlow //
5924bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
5934bff34e3Sthurlow 
5944bff34e3Sthurlow int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType,
5954bff34e3Sthurlow                      unsigned char* pbTokenValue, long nLength )
5964bff34e3Sthurlow {
5974bff34e3Sthurlow    int   nTotalBytesWrittenOut = 0L;
5984bff34e3Sthurlow    int   nNumLengthBytesWritten = 0L;
5994bff34e3Sthurlow 
6004bff34e3Sthurlow    // Write out the type
6014bff34e3Sthurlow    *pbData = ucType;
6024bff34e3Sthurlow 
6034bff34e3Sthurlow    // Wrote 1 byte, and move data pointer
6044bff34e3Sthurlow    nTotalBytesWrittenOut++;
6054bff34e3Sthurlow    pbData++;
6064bff34e3Sthurlow 
6074bff34e3Sthurlow    // Now write out the length and adjust the number of bytes written out
6084bff34e3Sthurlow    nNumLengthBytesWritten = ASNDerWriteLength( pbData, nLength );
6094bff34e3Sthurlow 
6104bff34e3Sthurlow    nTotalBytesWrittenOut += nNumLengthBytesWritten;
6114bff34e3Sthurlow    pbData += nNumLengthBytesWritten;
6124bff34e3Sthurlow 
6134bff34e3Sthurlow    // Write out the token value if we got one.  The assumption is that the
6144bff34e3Sthurlow    // nLength value indicates how many bytes are in pbTokenValue.
6154bff34e3Sthurlow 
6164bff34e3Sthurlow    if ( NULL != pbTokenValue )
6174bff34e3Sthurlow    {
6184bff34e3Sthurlow       memcpy( pbData, pbTokenValue, nLength );
6194bff34e3Sthurlow       nTotalBytesWrittenOut += nLength;
6204bff34e3Sthurlow    }
6214bff34e3Sthurlow 
6224bff34e3Sthurlow    return nTotalBytesWrittenOut;
6234bff34e3Sthurlow }
6244bff34e3Sthurlow 
6254bff34e3Sthurlow 
6264bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
6274bff34e3Sthurlow //
6284bff34e3Sthurlow // Function:
6294bff34e3Sthurlow //    ASNDerWriteOID
6304bff34e3Sthurlow //
6314bff34e3Sthurlow // Parameters:
6324bff34e3Sthurlow //    [out] pbData            -  Buffer to write into.
6334bff34e3Sthurlow //    [in]  eMechOID          -  OID to write out.
6344bff34e3Sthurlow //
6354bff34e3Sthurlow // Returns:
6364bff34e3Sthurlow //    int   Number of bytes written out
6374bff34e3Sthurlow //
6384bff34e3Sthurlow // Comments :
6394bff34e3Sthurlow //    Helper function to write out an OID.  For these we have the raw bytes
6404bff34e3Sthurlow //    listed in a global structure.  The caller simply indicates which OID
6414bff34e3Sthurlow //    should be written and we will splat out the data.
6424bff34e3Sthurlow //
6434bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
6444bff34e3Sthurlow 
6454bff34e3Sthurlow int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID )
6464bff34e3Sthurlow {
6474bff34e3Sthurlow 
6484bff34e3Sthurlow    memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen );
6494bff34e3Sthurlow 
6504bff34e3Sthurlow    return g_stcMechOIDList[eMechOID].iLen;
6514bff34e3Sthurlow }
6524bff34e3Sthurlow 
6534bff34e3Sthurlow 
6544bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
6554bff34e3Sthurlow //
6564bff34e3Sthurlow // Function:
6574bff34e3Sthurlow //    ASNDerWriteMechList
6584bff34e3Sthurlow //
6594bff34e3Sthurlow // Parameters:
6604bff34e3Sthurlow //    [out] pbData            -  Buffer to write into.
6614bff34e3Sthurlow //    [in]  eMechOID          -  OID to put in MechList.
6624bff34e3Sthurlow //
6634bff34e3Sthurlow // Returns:
6644bff34e3Sthurlow //    int   Number of bytes written out
6654bff34e3Sthurlow //
6664bff34e3Sthurlow // Comments :
6674bff34e3Sthurlow //    Helper function to write out a MechList.  A MechList consists of the
6684bff34e3Sthurlow //    Init Token Sequence, a sequence token and then the list of OIDs.  In
6694bff34e3Sthurlow //    our case the OID is from a global array of known OIDs.
6704bff34e3Sthurlow //
6714bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
6724bff34e3Sthurlow 
6734bff34e3Sthurlow long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid )
6744bff34e3Sthurlow {
6754bff34e3Sthurlow    // First get the length
6764bff34e3Sthurlow    long  nInternalLength = 0L;
6774bff34e3Sthurlow    long  nMechListLength = ASNDerCalcMechListLength( mechoid, &nInternalLength );
6784bff34e3Sthurlow    long  nTempLength = 0L;
6794bff34e3Sthurlow 
6804bff34e3Sthurlow    nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
6814bff34e3Sthurlow                                     NULL, nInternalLength );
6824bff34e3Sthurlow 
6834bff34e3Sthurlow    // Adjust the data pointer
6844bff34e3Sthurlow    pbData += nTempLength;
6854bff34e3Sthurlow 
6864bff34e3Sthurlow    // Now write the Sequence token and the OID (the OID is a BLOB in the global
6874bff34e3Sthurlow    // structure.
6884bff34e3Sthurlow 
6894bff34e3Sthurlow    nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE,
6904bff34e3Sthurlow                                     g_stcMechOIDList[mechoid].ucOid,
6914bff34e3Sthurlow                                     g_stcMechOIDList[mechoid].iLen );
6924bff34e3Sthurlow 
6934bff34e3Sthurlow    return nMechListLength;
6944bff34e3Sthurlow }
6954bff34e3Sthurlow 
6964bff34e3Sthurlow 
6974bff34e3Sthurlow /////////////////////////////////////////////////////////////////////////////
6984bff34e3Sthurlow //
6994bff34e3Sthurlow // Function:
7004bff34e3Sthurlow //    ASNDerWriteElement
7014bff34e3Sthurlow //
7024bff34e3Sthurlow // Parameters:
7034bff34e3Sthurlow //    [out] pbData            -  Buffer to write into.
7044bff34e3Sthurlow //    [in]  ucElementSequence -  Sequence Token
7054bff34e3Sthurlow //    [in]  ucType            -  Token Type
7064bff34e3Sthurlow //    [in]  pbTokenValue      -  Actual Value
7074bff34e3Sthurlow //    [in]  nLength           -  Length of Data.
7084bff34e3Sthurlow //
7094bff34e3Sthurlow // Returns:
7104bff34e3Sthurlow //    int   Number of bytes written out
7114bff34e3Sthurlow //
7124bff34e3Sthurlow // Comments :
7134bff34e3Sthurlow //    Helper function to write out a SPNEGO Token element.  An element
7144bff34e3Sthurlow //    consists of a sequence token, a type token and the associated data.
7154bff34e3Sthurlow //
7164bff34e3Sthurlow ////////////////////////////////////////////////////////////////////////////
7174bff34e3Sthurlow 
7184bff34e3Sthurlow int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence,
7194bff34e3Sthurlow                         unsigned char ucType, unsigned char* pbTokenValue, long nLength )
7204bff34e3Sthurlow {
7214bff34e3Sthurlow    // First get the length
7224bff34e3Sthurlow    long  nInternalLength = 0L;
7234bff34e3Sthurlow    long  nElementLength = ASNDerCalcElementLength( nLength, &nInternalLength );
7244bff34e3Sthurlow    long  nTempLength = 0L;
7254bff34e3Sthurlow 
7264bff34e3Sthurlow    // Write out the sequence byte and the length of the type and data
7274bff34e3Sthurlow    nTempLength = ASNDerWriteToken( pbData, ucElementSequence, NULL, nInternalLength );
7284bff34e3Sthurlow 
7294bff34e3Sthurlow    // Adjust the data pointer
7304bff34e3Sthurlow    pbData += nTempLength;
7314bff34e3Sthurlow 
7324bff34e3Sthurlow    // Now write the type and the data.
7334bff34e3Sthurlow    nTempLength = ASNDerWriteToken( pbData, ucType, pbTokenValue, nLength );
7344bff34e3Sthurlow 
7354bff34e3Sthurlow    return nElementLength;
7364bff34e3Sthurlow }
737