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