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