xref: /onnv-gate/usr/src/lib/libsmbfs/smb/derparse.c (revision 10023:71bf38dba3d6)
16007Sthurlow // Copyright (C) 2002 Microsoft Corporation
26007Sthurlow // All rights reserved.
36007Sthurlow //
46007Sthurlow // THIS CODE AND INFORMATION IS PROVIDED "AS IS"
56007Sthurlow // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
66007Sthurlow // OR IMPLIED, INCLUDING BUT NOT LIMITED
76007Sthurlow // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
86007Sthurlow // AND/OR FITNESS FOR A PARTICULAR PURPOSE.
96007Sthurlow //
106007Sthurlow // Date    - 10/08/2002
116007Sthurlow // Author  - Sanj Surati
126007Sthurlow 
136007Sthurlow 
146007Sthurlow /////////////////////////////////////////////////////////////
156007Sthurlow //
166007Sthurlow // DERPARSE.C
176007Sthurlow //
186007Sthurlow // SPNEGO Token Handler Source File
196007Sthurlow //
206007Sthurlow // Contains implementation of ASN.1 DER read/write functions
216007Sthurlow // as defined in DERPARSE.H.
226007Sthurlow //
236007Sthurlow /////////////////////////////////////////////////////////////
246007Sthurlow 
256007Sthurlow #include <stdlib.h>
266007Sthurlow #include <stdio.h>
276007Sthurlow #include <memory.h>
286007Sthurlow #include <sys/byteorder.h>
296007Sthurlow #include "spnego.h"
306007Sthurlow #include "derparse.h"
316007Sthurlow 
326007Sthurlow //
336007Sthurlow // The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in
346007Sthurlow // the array below, that a mechanism can be found.
356007Sthurlow //
36*10023SGordon.Ross@Sun.COM 
376007Sthurlow #pragma error_messages (off,E_INITIALIZATION_TYPE_MISMATCH)
386007Sthurlow MECH_OID g_stcMechOIDList [] =
396007Sthurlow {
406007Sthurlow 	{"\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02",	11,  9,
416007Sthurlow 	 spnego_mech_oid_Kerberos_V5_Legacy	},	// 1.2.840.48018.1.2.2
426007Sthurlow 	{"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02",	11,  9,
436007Sthurlow 	 spnego_mech_oid_Kerberos_V5		}, // 1.2.840.113554.1.2.2
446007Sthurlow 	{"\x06\x06\x2b\x06\x01\x05\x05\x02",			 8,  6,
456007Sthurlow 	 spnego_mech_oid_Spnego			}, // 1.3.6.1.5.5.2
466007Sthurlow 	{"\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a",	12, 10,
476007Sthurlow 	 spnego_mech_oid_NTLMSSP		}, // 1.3.6.1.4.1.311.2.2.10
486007Sthurlow 	{"", 0,  0, spnego_mech_oid_NotUsed	}  // Placeholder
496007Sthurlow };
506007Sthurlow #pragma error_messages (default,E_INITIALIZATION_TYPE_MISMATCH)
516007Sthurlow 
526007Sthurlow /////////////////////////////////////////////////////////////////////////////
536007Sthurlow //
546007Sthurlow // Function:
556007Sthurlow //    ASNDerGetLength
566007Sthurlow //
576007Sthurlow // Parameters:
586007Sthurlow //    [in]  pbLengthData      -  DER Length Data
596007Sthurlow //    [in]  nBoundaryLength   -  Length that value must not exceed.
606007Sthurlow //    [out] pnLength          -  Filled out with length value
616007Sthurlow //    [out] pnNumLengthBytes  -  Filled out with number of bytes
626007Sthurlow //                               consumed by DER length.
636007Sthurlow //
646007Sthurlow // Returns:
656007Sthurlow //    int   Success - SPNEGO_E_SUCCESS
666007Sthurlow //          Failure - SPNEGO API Error code
676007Sthurlow //
686007Sthurlow // Comments :
696007Sthurlow //    Interprets the data at pbLengthData as a DER length.  The length must
706007Sthurlow //    fit within the bounds of nBoundary length.  We do not currently
716007Sthurlow //    process lengths that take more than 4 bytes.
726007Sthurlow //
736007Sthurlow ////////////////////////////////////////////////////////////////////////////
746007Sthurlow 
ASNDerGetLength(unsigned char * pbLengthData,long nBoundaryLength,long * pnLength,long * pnNumLengthBytes)756007Sthurlow int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength,
766007Sthurlow                      long* pnNumLengthBytes )
776007Sthurlow {
786007Sthurlow    int   nReturn = SPNEGO_E_INVALID_LENGTH;
796007Sthurlow    int   nNumLengthBytes = 0;
806007Sthurlow 
816007Sthurlow    // First check if the extended length bit is set
826007Sthurlow 
836007Sthurlow    if ( *pbLengthData & LEN_XTND )
846007Sthurlow    {
856007Sthurlow       // Lower 7 bits contain the number of trailing bytes that describe the length
866007Sthurlow       nNumLengthBytes = *pbLengthData & LEN_MASK;
876007Sthurlow 
886007Sthurlow       // Check that the number of bytes we are about to read is within our boundary
896007Sthurlow       // constraints
906007Sthurlow 
916007Sthurlow       if ( nNumLengthBytes <= nBoundaryLength - 1 )
926007Sthurlow       {
936007Sthurlow 
946007Sthurlow          // For now, our handler won't deal with lengths greater than 4 bytes
956007Sthurlow          if ( nNumLengthBytes >= 1 && nNumLengthBytes <= 4 )
966007Sthurlow          {
976007Sthurlow             // 0 out the initial length
986007Sthurlow             *pnLength = 0L;
996007Sthurlow 
1006007Sthurlow             // Bump by 1 byte
1016007Sthurlow             pbLengthData++;
1026007Sthurlow 
1036007Sthurlow    #ifdef _LITTLE_ENDIAN
1046007Sthurlow 
1056007Sthurlow             // There may be a cleaner way to do this, but for now, this seems to be
1066007Sthurlow             // an easy way to do the transformation
1076007Sthurlow             switch ( nNumLengthBytes )
1086007Sthurlow             {
1096007Sthurlow                case 1:
1106007Sthurlow                {
1116007Sthurlow                   *( ( (unsigned char*) pnLength ) ) = *pbLengthData;
1126007Sthurlow                   break;
1136007Sthurlow                }
1146007Sthurlow 
1156007Sthurlow                case 2:
1166007Sthurlow                {
1176007Sthurlow                   *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 1);
1186007Sthurlow                   *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData);
1196007Sthurlow 
1206007Sthurlow                   break;
1216007Sthurlow                }
1226007Sthurlow 
1236007Sthurlow                case 3:
1246007Sthurlow                {
1256007Sthurlow                   *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 2);
1266007Sthurlow                   *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1);
1276007Sthurlow                   *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData);
1286007Sthurlow                   break;
1296007Sthurlow                }
1306007Sthurlow 
1316007Sthurlow                case 4:
1326007Sthurlow                {
1336007Sthurlow                   *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 3);
1346007Sthurlow                   *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData + 2);
1356007Sthurlow                   *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1);
1366007Sthurlow                   *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData);
1376007Sthurlow                   break;
1386007Sthurlow                }
1396007Sthurlow 
1406007Sthurlow             }  // SWITCH ( nNumLengthBytes )
1416007Sthurlow 
1426007Sthurlow    #else
1436007Sthurlow             // We are Big-Endian, so the length can be copied in from the source
1446007Sthurlow             // as is.  Ensure that we adjust for the number of bytes we actually
1456007Sthurlow             // copy.
1466007Sthurlow 
1476007Sthurlow             memcpy( ( (unsigned char *) pnLength ) + ( 4 - nNumLengthBytes ),
1486007Sthurlow                      pbLengthData, nNumLengthBytes );
1496007Sthurlow    #endif
1506007Sthurlow 
1516007Sthurlow             // Account for the initial length byte
1526007Sthurlow             *pnNumLengthBytes = nNumLengthBytes + 1;
1536007Sthurlow             nReturn = SPNEGO_E_SUCCESS;
1546007Sthurlow 
1556007Sthurlow          }  // IF Valid Length
1566007Sthurlow 
1576007Sthurlow       }  // IF num bytes to read is within the boundary length
1586007Sthurlow 
1596007Sthurlow    }  // IF xtended length
1606007Sthurlow    else
1616007Sthurlow    {
1626007Sthurlow 
1636007Sthurlow       // Extended bit is not set, so the length is in the value and the one
1646007Sthurlow       // byte describes the length
1656007Sthurlow       *pnLength = *pbLengthData & LEN_MASK;
1666007Sthurlow       *pnNumLengthBytes = 1;
1676007Sthurlow       nReturn = SPNEGO_E_SUCCESS;
1686007Sthurlow 
1696007Sthurlow    }
1706007Sthurlow 
1716007Sthurlow    return nReturn;
1726007Sthurlow }
1736007Sthurlow 
1746007Sthurlow 
1756007Sthurlow /////////////////////////////////////////////////////////////////////////////
1766007Sthurlow //
1776007Sthurlow // Function:
1786007Sthurlow //    ASNDerCheckToken
1796007Sthurlow //
1806007Sthurlow // Parameters:
1816007Sthurlow //    [in]  pbTokenData       -  Token Data
1826007Sthurlow //    [in]  nToken            -  Token identifier to check for
1836007Sthurlow //    [in]  nLengthWithToken  -  Expected token length (with data)
1846007Sthurlow //    [in]  nBoundaryLength   -  Length that value must not exceed.
1856007Sthurlow //    [out] pnLength          -  Filled out with data length
1866007Sthurlow //    [out] pnTokenLength     -  Filled out with number of bytes
1876007Sthurlow //                               consumed by token identifier and length.
1886007Sthurlow //
1896007Sthurlow // Returns:
1906007Sthurlow //    int   Success - SPNEGO_E_SUCCESS
1916007Sthurlow //          Failure - SPNEGO API Error code
1926007Sthurlow //
1936007Sthurlow // Comments :
1946007Sthurlow //    Checks the data pointed to by pbTokenData for the specified token
1956007Sthurlow //    identifier and the length that immediately follows.  If
1966007Sthurlow //    nLengthWithToken is > 0, the calculated length must match.  The
1976007Sthurlow //    length must also not exceed the specified boundary length .
1986007Sthurlow //
1996007Sthurlow ////////////////////////////////////////////////////////////////////////////
2006007Sthurlow 
ASNDerCheckToken(unsigned char * pbTokenData,unsigned char nToken,long nLengthWithToken,long nBoundaryLength,long * pnLength,long * pnTokenLength)2016007Sthurlow int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
2026007Sthurlow                         long nLengthWithToken, long nBoundaryLength,
2036007Sthurlow                         long* pnLength, long* pnTokenLength )
2046007Sthurlow {
2056007Sthurlow 
2066007Sthurlow    int   nReturn = SPNEGO_E_INVALID_LENGTH;
2076007Sthurlow    long  nNumLengthBytes = 0L;
2086007Sthurlow 
2096007Sthurlow    // Make sure that we've at least got 2 bytes of room to work with
2106007Sthurlow 
2116007Sthurlow    if ( nBoundaryLength >= 2 )
2126007Sthurlow    {
2136007Sthurlow       // The first byte of the token data MUST match the specified token
2146007Sthurlow       if ( *pbTokenData == nToken )
2156007Sthurlow       {
2166007Sthurlow          // Next byte indicates the length
2176007Sthurlow          pbTokenData++;
2186007Sthurlow 
2196007Sthurlow          // Get the length described by the token
2206007Sthurlow          if ( ( nReturn = ASNDerGetLength( pbTokenData, nBoundaryLength, pnLength,
2216007Sthurlow                                              &nNumLengthBytes )  ) == SPNEGO_E_SUCCESS )
2226007Sthurlow          {
2236007Sthurlow             // Verify that the length is LESS THAN the boundary length
2246007Sthurlow             // (this should prevent us walking out of our buffer)
2256007Sthurlow             if ( ( nBoundaryLength - ( nNumLengthBytes + 1 ) < *pnLength ) )
2266007Sthurlow             {
2276007Sthurlow 
2286007Sthurlow                nReturn = SPNEGO_E_INVALID_LENGTH;
2296007Sthurlow 
2306007Sthurlow             }
2316007Sthurlow 
2326007Sthurlow             // If we were passed a length to check, do so now
2336007Sthurlow             if ( nLengthWithToken > 0L )
2346007Sthurlow             {
2356007Sthurlow 
2366007Sthurlow                // Check that the expected length matches
2376007Sthurlow                if ( ( nLengthWithToken - ( nNumLengthBytes + 1 ) ) != *pnLength )
2386007Sthurlow                {
2396007Sthurlow 
2406007Sthurlow                   nReturn = SPNEGO_E_INVALID_LENGTH;
2416007Sthurlow 
2426007Sthurlow                }
2436007Sthurlow 
2446007Sthurlow             }  // IF need to validate length
2456007Sthurlow 
2466007Sthurlow             if ( SPNEGO_E_SUCCESS == nReturn )
2476007Sthurlow             {
2486007Sthurlow                *pnTokenLength = nNumLengthBytes + 1;
2496007Sthurlow             }
2506007Sthurlow 
2516007Sthurlow          }  // IF ASNDerGetLength
2526007Sthurlow 
2536007Sthurlow       }  // IF token matches
2546007Sthurlow       else
2556007Sthurlow       {
2566007Sthurlow          nReturn = SPNEGO_E_TOKEN_NOT_FOUND;
2576007Sthurlow       }
2586007Sthurlow 
2596007Sthurlow    }  // IF Boundary Length is at least 2 bytes
2606007Sthurlow 
2616007Sthurlow    return nReturn;
2626007Sthurlow }
2636007Sthurlow 
2646007Sthurlow /////////////////////////////////////////////////////////////////////////////
2656007Sthurlow //
2666007Sthurlow // Function:
2676007Sthurlow //    ASNDerCheckOID
2686007Sthurlow //
2696007Sthurlow // Parameters:
2706007Sthurlow //    [in]  pbTokenData       -  Token Data
2716007Sthurlow //    [in]  nMechOID          -  OID we are looking for
2726007Sthurlow //    [in]  nBoundaryLength   -  Length that value must not exceed.
2736007Sthurlow //    [out] pnTokenLength     -  Filled out with number of bytes
2746007Sthurlow //                               consumed by token and data.
2756007Sthurlow //
2766007Sthurlow // Returns:
2776007Sthurlow //    int   Success - SPNEGO_E_SUCCESS
2786007Sthurlow //          Failure - SPNEGO API Error code
2796007Sthurlow //
2806007Sthurlow // Comments :
2816007Sthurlow //    Checks the data pointed to by pbTokenData for the specified OID.
2826007Sthurlow //
2836007Sthurlow ////////////////////////////////////////////////////////////////////////////
2846007Sthurlow 
ASNDerCheckOID(unsigned char * pbTokenData,SPNEGO_MECH_OID nMechOID,long nBoundaryLength,long * pnTokenLength)2856007Sthurlow int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength,
2866007Sthurlow                      long* pnTokenLength )
2876007Sthurlow {
2886007Sthurlow    int   nReturn = 0L;
2896007Sthurlow    long  nLength = 0L;
2906007Sthurlow 
2916007Sthurlow    // Verify that we have an OID token
2926007Sthurlow    if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, 0L, nBoundaryLength,
2936007Sthurlow                                        &nLength, pnTokenLength ) ) == SPNEGO_E_SUCCESS )
2946007Sthurlow    {
2956007Sthurlow       // Add the data length to the Token Length
2966007Sthurlow       *pnTokenLength += nLength;
2976007Sthurlow 
2986007Sthurlow       // Token Lengths plus the actual length must match the length in our OID list element.
2996007Sthurlow       // If it doesn't, we're done
3006007Sthurlow       if ( *pnTokenLength == g_stcMechOIDList[nMechOID].iLen )
3016007Sthurlow       {
3026007Sthurlow          // Memcompare the token and the expected field
3036007Sthurlow          if ( memcmp( pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength ) != 0 )
3046007Sthurlow          {
3056007Sthurlow             nReturn = SPNEGO_E_UNEXPECTED_OID;
3066007Sthurlow          }
3076007Sthurlow       }
3086007Sthurlow       else
3096007Sthurlow       {
3106007Sthurlow          nReturn = SPNEGO_E_UNEXPECTED_OID;
3116007Sthurlow       }
3126007Sthurlow 
3136007Sthurlow    }  // IF OID Token CHecks
3146007Sthurlow 
3156007Sthurlow    return nReturn;
3166007Sthurlow }
3176007Sthurlow 
3186007Sthurlow /////////////////////////////////////////////////////////////////////////////
3196007Sthurlow //
3206007Sthurlow // Function:
3216007Sthurlow //    ASNDerCalcNumLengthBytes
3226007Sthurlow //
3236007Sthurlow // Parameters:
3246007Sthurlow //    [in]  nLength           -  Length to calculate length bytes for.
3256007Sthurlow //
3266007Sthurlow // Returns:
3276007Sthurlow //    int   Number of bytes necessary to represent length
3286007Sthurlow //
3296007Sthurlow // Comments :
3306007Sthurlow //    Helper function to calculate the number of length bytes necessary to
3316007Sthurlow //    represent a length value.  For our purposes, a 32-bit value should be
3326007Sthurlow //    enough to describea length.
3336007Sthurlow //
3346007Sthurlow ////////////////////////////////////////////////////////////////////////////
3356007Sthurlow 
ASNDerCalcNumLengthBytes(long nLength)3366007Sthurlow int ASNDerCalcNumLengthBytes( long nLength )
3376007Sthurlow {
3386007Sthurlow       if ( nLength <= 0x7F )
3396007Sthurlow       {
3406007Sthurlow          // A single byte will be sufficient for describing this length.
3416007Sthurlow          // The byte will simply contain the length
3426007Sthurlow          return 1;
3436007Sthurlow       }
3446007Sthurlow       else if ( nLength <= 0xFF )
3456007Sthurlow       {
3466007Sthurlow          // Two bytes are necessary, one to say how many following bytes
3476007Sthurlow          // describe the length, and one to give the length
3486007Sthurlow          return 2;
3496007Sthurlow       }
3506007Sthurlow       else if ( nLength <= 0xFFFF )
3516007Sthurlow       {
3526007Sthurlow          // Three bytes are necessary, one to say how many following bytes
3536007Sthurlow          // describe the length, and two to give the length
3546007Sthurlow          return 3;
3556007Sthurlow       }
3566007Sthurlow       else if ( nLength <= 0xFFFFFF )
3576007Sthurlow       {
3586007Sthurlow          // Four bytes are necessary, one to say how many following bytes
3596007Sthurlow          // describe the length, and three to give the length
3606007Sthurlow          return 4;
3616007Sthurlow       }
3626007Sthurlow       else
3636007Sthurlow       {
3646007Sthurlow          // Five bytes are necessary, one to say how many following bytes
3656007Sthurlow          // describe the length, and four to give the length
3666007Sthurlow          return 5;
3676007Sthurlow       }
3686007Sthurlow }
3696007Sthurlow 
3706007Sthurlow 
3716007Sthurlow /////////////////////////////////////////////////////////////////////////////
3726007Sthurlow //
3736007Sthurlow // Function:
3746007Sthurlow //    ASNDerCalcTokenLength
3756007Sthurlow //
3766007Sthurlow // Parameters:
3776007Sthurlow //    [in]  nLength           -  Length to calculate length bytes for.
3786007Sthurlow //    [in]  nDataLength       -  Actual Data length value.
3796007Sthurlow //
3806007Sthurlow // Returns:
3816007Sthurlow //    long  Number of bytes necessary to represent a token, length and data
3826007Sthurlow //
3836007Sthurlow // Comments :
3846007Sthurlow //    Helper function to calculate a token and value size, based on a
3856007Sthurlow //    supplied length value, and any binary data that will need to be
3866007Sthurlow //    written out.
3876007Sthurlow //
3886007Sthurlow ////////////////////////////////////////////////////////////////////////////
3896007Sthurlow 
ASNDerCalcTokenLength(long nLength,long nDataLength)3906007Sthurlow long ASNDerCalcTokenLength( long nLength, long nDataLength )
3916007Sthurlow {
3926007Sthurlow    // Add a byte to the length size to account for a single byte to
3936007Sthurlow    // hold the token type.
3946007Sthurlow    long  nTotalLength = ASNDerCalcNumLengthBytes( nLength ) + 1;
3956007Sthurlow 
3966007Sthurlow    return nTotalLength + nDataLength;
3976007Sthurlow }
3986007Sthurlow 
3996007Sthurlow 
4006007Sthurlow /////////////////////////////////////////////////////////////////////////////
4016007Sthurlow //
4026007Sthurlow // Function:
4036007Sthurlow //    ASNDerCalcElementLength
4046007Sthurlow //
4056007Sthurlow // Parameters:
4066007Sthurlow //    [in]  nDataLength       -  Length of data.
4076007Sthurlow //    [out] pnInternalLength  -  Filled out with length of element
4086007Sthurlow //                               without sequence info.
4096007Sthurlow //
4106007Sthurlow // Returns:
4116007Sthurlow //    long  Number of bytes necessary to represent an element
4126007Sthurlow //
4136007Sthurlow // Comments :
4146007Sthurlow //    Helper function to calculate an element length.  An element consists
4156007Sthurlow //    of a sequence token, a type token and then the data.
4166007Sthurlow //
4176007Sthurlow ////////////////////////////////////////////////////////////////////////////
4186007Sthurlow 
ASNDerCalcElementLength(long nDataLength,long * pnInternalLength)4196007Sthurlow long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength )
4206007Sthurlow {
4216007Sthurlow    // First the type token and the actual data
4226007Sthurlow    long  nTotalLength = ASNDerCalcTokenLength( nDataLength, nDataLength );
4236007Sthurlow 
4246007Sthurlow    // Internal length is the length without the element sequence token
4256007Sthurlow    if ( NULL != pnInternalLength )
4266007Sthurlow    {
4276007Sthurlow       *pnInternalLength = nTotalLength;
4286007Sthurlow    }
4296007Sthurlow 
4306007Sthurlow    // Next add in the element's sequence token (remember that its
4316007Sthurlow    // length is the total length of the type token and data)
4326007Sthurlow    nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
4336007Sthurlow 
4346007Sthurlow    return nTotalLength;
4356007Sthurlow }
4366007Sthurlow 
4376007Sthurlow /////////////////////////////////////////////////////////////////////////////
4386007Sthurlow //
4396007Sthurlow // Function:
4406007Sthurlow //    ASNDerCalcMechListLength
4416007Sthurlow //
4426007Sthurlow // Parameters:
4436007Sthurlow //    [in]  mechoid           -  Mech OID to put in list.
4446007Sthurlow //    [out] pnInternalLength  -  Filled out with length of element
4456007Sthurlow //                               without the primary sequence token.
4466007Sthurlow //
4476007Sthurlow // Returns:
4486007Sthurlow //    long  Number of bytes necessary to represent a mechList
4496007Sthurlow //
4506007Sthurlow // Comments :
4516007Sthurlow //    Helper function to calculate a MechList length.  A mechlist consists
4526007Sthurlow //    of a NegTokenInit sequence token, a sequence token for the MechList
4536007Sthurlow //    and finally a list of OIDs.  In our case, we only really have one
4546007Sthurlow //    OID.
4556007Sthurlow //
4566007Sthurlow ////////////////////////////////////////////////////////////////////////////
4576007Sthurlow 
ASNDerCalcMechListLength(SPNEGO_MECH_OID mechoid,long * pnInternalLength)4586007Sthurlow long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength )
4596007Sthurlow {
4606007Sthurlow    // First the OID
4616007Sthurlow    long  nTotalLength = g_stcMechOIDList[mechoid].iLen;
4626007Sthurlow 
4636007Sthurlow    // Next add in a sequence token
4646007Sthurlow    nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
4656007Sthurlow 
4666007Sthurlow    // Internal length is the length without the element sequence token
4676007Sthurlow    if ( NULL != pnInternalLength )
4686007Sthurlow    {
4696007Sthurlow       *pnInternalLength = nTotalLength;
4706007Sthurlow    }
4716007Sthurlow 
4726007Sthurlow    // Finally add in the element's sequence token
4736007Sthurlow    nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
4746007Sthurlow 
4756007Sthurlow    return nTotalLength;
4766007Sthurlow }
4776007Sthurlow 
4786007Sthurlow 
4796007Sthurlow /////////////////////////////////////////////////////////////////////////////
4806007Sthurlow //
4816007Sthurlow // Function:
4826007Sthurlow //    ASNDerWriteLength
4836007Sthurlow //
4846007Sthurlow // Parameters:
4856007Sthurlow //    [out] pbData            -  Buffer to write into.
4866007Sthurlow //    [in]  nLength           -  Length to write out.
4876007Sthurlow //
4886007Sthurlow // Returns:
4896007Sthurlow //    int   Number of bytes written out
4906007Sthurlow //
4916007Sthurlow // Comments :
4926007Sthurlow //    Helper function to write out a length value following DER rules .
4936007Sthurlow //
4946007Sthurlow ////////////////////////////////////////////////////////////////////////////
4956007Sthurlow 
ASNDerWriteLength(unsigned char * pbData,long nLength)4966007Sthurlow int ASNDerWriteLength( unsigned char* pbData, long nLength )
4976007Sthurlow {
4986007Sthurlow    int   nNumBytesRequired = ASNDerCalcNumLengthBytes( nLength );
4996007Sthurlow    int   nNumLengthBytes = nNumBytesRequired - 1;
5006007Sthurlow 
5016007Sthurlow 
5026007Sthurlow    if ( nNumBytesRequired > 1 )
5036007Sthurlow    {
5046007Sthurlow 
5056007Sthurlow       // Write out the number of bytes following which will be used
5066007Sthurlow       *pbData = (unsigned char ) ( LEN_XTND | nNumLengthBytes );
5076007Sthurlow 
5086007Sthurlow       // Point to where we'll actually write the length
5096007Sthurlow       pbData++;
5106007Sthurlow 
5116007Sthurlow #ifdef  _LITTLE_ENDIAN
5126007Sthurlow 
5136007Sthurlow       // There may be a cleaner way to do this, but for now, this seems to be
5146007Sthurlow       // an easy way to do the transformation
5156007Sthurlow       switch ( nNumLengthBytes )
5166007Sthurlow       {
5176007Sthurlow          case 1:
5186007Sthurlow          {
5196007Sthurlow             // Cast the length to a single byte, since we know that it
5206007Sthurlow             // is 0x7F or less (or we wouldn't only need a single byte).
5216007Sthurlow 
5226007Sthurlow             *pbData = (unsigned char) nLength;
5236007Sthurlow             break;
5246007Sthurlow          }
5256007Sthurlow 
5266007Sthurlow          case 2:
5276007Sthurlow          {
5286007Sthurlow             *pbData = *( ( (unsigned char*) &nLength ) + 1 );
5296007Sthurlow             *( pbData + 1) = *( ( (unsigned char*) &nLength ) );
5306007Sthurlow             break;
5316007Sthurlow          }
5326007Sthurlow 
5336007Sthurlow          case 3:
5346007Sthurlow          {
5356007Sthurlow             *pbData = *( ( (unsigned char*) &nLength ) + 3 );
5366007Sthurlow             *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 );
5376007Sthurlow             *( pbData + 2) = *( ( (unsigned char*) &nLength ) );
5386007Sthurlow             break;
5396007Sthurlow          }
5406007Sthurlow 
5416007Sthurlow          case 4:
5426007Sthurlow          {
5436007Sthurlow             *pbData = *( ( (unsigned char*) &nLength ) + 3 );
5446007Sthurlow             *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 );
5456007Sthurlow             *( pbData + 2) = *( ( (unsigned char*) &nLength ) + 1 );
5466007Sthurlow             *( pbData + 3) = *( ( (unsigned char*) &nLength ) );
5476007Sthurlow             break;
5486007Sthurlow          }
5496007Sthurlow 
5506007Sthurlow       }  // SWITCH ( nNumLengthBytes )
5516007Sthurlow 
5526007Sthurlow #else
5536007Sthurlow       // We are Big-Endian, so the length can be copied in from the source
5546007Sthurlow       // as is.  Ensure that we adjust for the number of bytes we actually
5556007Sthurlow       // copy.
5566007Sthurlow 
5576007Sthurlow       memcpy( pbData,
5586007Sthurlow                ( (unsigned char *) &nLength ) + ( 4 - nNumLengthBytes ), nNumLengthBytes );
5596007Sthurlow #endif
5606007Sthurlow 
5616007Sthurlow    }  // IF > 1 byte for length
5626007Sthurlow    else
5636007Sthurlow    {
5646007Sthurlow       // Cast the length to a single byte, since we know that it
5656007Sthurlow       // is 0x7F or less (or we wouldn't only need a single byte).
5666007Sthurlow 
5676007Sthurlow       *pbData = (unsigned char) nLength;
5686007Sthurlow    }
5696007Sthurlow 
5706007Sthurlow    return nNumBytesRequired;
5716007Sthurlow }
5726007Sthurlow 
5736007Sthurlow /////////////////////////////////////////////////////////////////////////////
5746007Sthurlow //
5756007Sthurlow // Function:
5766007Sthurlow //    ASNDerWriteToken
5776007Sthurlow //
5786007Sthurlow // Parameters:
5796007Sthurlow //    [out] pbData            -  Buffer to write into.
5806007Sthurlow //    [in]  ucType            -  Token Type
5816007Sthurlow //    [in]  pbTokenValue      -  Actual Value
5826007Sthurlow //    [in]  nLength           -  Length of Data.
5836007Sthurlow //
5846007Sthurlow // Returns:
5856007Sthurlow //    int   Number of bytes written out
5866007Sthurlow //
5876007Sthurlow // Comments :
5886007Sthurlow //    Helper function to write out a token and any associated data.  If
5896007Sthurlow //    pbTokenValue is non-NULL, then it is written out in addition to the
5906007Sthurlow //    token identifier and the length bytes.
5916007Sthurlow //
5926007Sthurlow ////////////////////////////////////////////////////////////////////////////
5936007Sthurlow 
ASNDerWriteToken(unsigned char * pbData,unsigned char ucType,unsigned char * pbTokenValue,long nLength)5946007Sthurlow int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType,
5956007Sthurlow                      unsigned char* pbTokenValue, long nLength )
5966007Sthurlow {
5976007Sthurlow    int   nTotalBytesWrittenOut = 0L;
5986007Sthurlow    int   nNumLengthBytesWritten = 0L;
5996007Sthurlow 
6006007Sthurlow    // Write out the type
6016007Sthurlow    *pbData = ucType;
6026007Sthurlow 
6036007Sthurlow    // Wrote 1 byte, and move data pointer
6046007Sthurlow    nTotalBytesWrittenOut++;
6056007Sthurlow    pbData++;
6066007Sthurlow 
6076007Sthurlow    // Now write out the length and adjust the number of bytes written out
6086007Sthurlow    nNumLengthBytesWritten = ASNDerWriteLength( pbData, nLength );
6096007Sthurlow 
6106007Sthurlow    nTotalBytesWrittenOut += nNumLengthBytesWritten;
6116007Sthurlow    pbData += nNumLengthBytesWritten;
6126007Sthurlow 
6136007Sthurlow    // Write out the token value if we got one.  The assumption is that the
6146007Sthurlow    // nLength value indicates how many bytes are in pbTokenValue.
6156007Sthurlow 
6166007Sthurlow    if ( NULL != pbTokenValue )
6176007Sthurlow    {
6186007Sthurlow       memcpy( pbData, pbTokenValue, nLength );
6196007Sthurlow       nTotalBytesWrittenOut += nLength;
6206007Sthurlow    }
6216007Sthurlow 
6226007Sthurlow    return nTotalBytesWrittenOut;
6236007Sthurlow }
6246007Sthurlow 
6256007Sthurlow 
6266007Sthurlow /////////////////////////////////////////////////////////////////////////////
6276007Sthurlow //
6286007Sthurlow // Function:
6296007Sthurlow //    ASNDerWriteOID
6306007Sthurlow //
6316007Sthurlow // Parameters:
6326007Sthurlow //    [out] pbData            -  Buffer to write into.
6336007Sthurlow //    [in]  eMechOID          -  OID to write out.
6346007Sthurlow //
6356007Sthurlow // Returns:
6366007Sthurlow //    int   Number of bytes written out
6376007Sthurlow //
6386007Sthurlow // Comments :
6396007Sthurlow //    Helper function to write out an OID.  For these we have the raw bytes
6406007Sthurlow //    listed in a global structure.  The caller simply indicates which OID
6416007Sthurlow //    should be written and we will splat out the data.
6426007Sthurlow //
6436007Sthurlow ////////////////////////////////////////////////////////////////////////////
6446007Sthurlow 
ASNDerWriteOID(unsigned char * pbData,SPNEGO_MECH_OID eMechOID)6456007Sthurlow int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID )
6466007Sthurlow {
6476007Sthurlow 
6486007Sthurlow    memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen );
6496007Sthurlow 
6506007Sthurlow    return g_stcMechOIDList[eMechOID].iLen;
6516007Sthurlow }
6526007Sthurlow 
6536007Sthurlow 
6546007Sthurlow /////////////////////////////////////////////////////////////////////////////
6556007Sthurlow //
6566007Sthurlow // Function:
6576007Sthurlow //    ASNDerWriteMechList
6586007Sthurlow //
6596007Sthurlow // Parameters:
6606007Sthurlow //    [out] pbData            -  Buffer to write into.
6616007Sthurlow //    [in]  eMechOID          -  OID to put in MechList.
6626007Sthurlow //
6636007Sthurlow // Returns:
6646007Sthurlow //    int   Number of bytes written out
6656007Sthurlow //
6666007Sthurlow // Comments :
6676007Sthurlow //    Helper function to write out a MechList.  A MechList consists of the
6686007Sthurlow //    Init Token Sequence, a sequence token and then the list of OIDs.  In
6696007Sthurlow //    our case the OID is from a global array of known OIDs.
6706007Sthurlow //
6716007Sthurlow ////////////////////////////////////////////////////////////////////////////
6726007Sthurlow 
ASNDerWriteMechList(unsigned char * pbData,SPNEGO_MECH_OID mechoid)6736007Sthurlow long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid )
6746007Sthurlow {
6756007Sthurlow    // First get the length
6766007Sthurlow    long  nInternalLength = 0L;
6776007Sthurlow    long  nMechListLength = ASNDerCalcMechListLength( mechoid, &nInternalLength );
6786007Sthurlow    long  nTempLength = 0L;
6796007Sthurlow 
6806007Sthurlow    nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
6816007Sthurlow                                     NULL, nInternalLength );
6826007Sthurlow 
6836007Sthurlow    // Adjust the data pointer
6846007Sthurlow    pbData += nTempLength;
6856007Sthurlow 
6866007Sthurlow    // Now write the Sequence token and the OID (the OID is a BLOB in the global
6876007Sthurlow    // structure.
6886007Sthurlow 
6896007Sthurlow    nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE,
6906007Sthurlow                                     g_stcMechOIDList[mechoid].ucOid,
6916007Sthurlow                                     g_stcMechOIDList[mechoid].iLen );
6926007Sthurlow 
6936007Sthurlow    return nMechListLength;
6946007Sthurlow }
6956007Sthurlow 
6966007Sthurlow 
6976007Sthurlow /////////////////////////////////////////////////////////////////////////////
6986007Sthurlow //
6996007Sthurlow // Function:
7006007Sthurlow //    ASNDerWriteElement
7016007Sthurlow //
7026007Sthurlow // Parameters:
7036007Sthurlow //    [out] pbData            -  Buffer to write into.
7046007Sthurlow //    [in]  ucElementSequence -  Sequence Token
7056007Sthurlow //    [in]  ucType            -  Token Type
7066007Sthurlow //    [in]  pbTokenValue      -  Actual Value
7076007Sthurlow //    [in]  nLength           -  Length of Data.
7086007Sthurlow //
7096007Sthurlow // Returns:
7106007Sthurlow //    int   Number of bytes written out
7116007Sthurlow //
7126007Sthurlow // Comments :
7136007Sthurlow //    Helper function to write out a SPNEGO Token element.  An element
7146007Sthurlow //    consists of a sequence token, a type token and the associated data.
7156007Sthurlow //
7166007Sthurlow ////////////////////////////////////////////////////////////////////////////
7176007Sthurlow 
ASNDerWriteElement(unsigned char * pbData,unsigned char ucElementSequence,unsigned char ucType,unsigned char * pbTokenValue,long nLength)7186007Sthurlow int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence,
7196007Sthurlow                         unsigned char ucType, unsigned char* pbTokenValue, long nLength )
7206007Sthurlow {
7216007Sthurlow    // First get the length
7226007Sthurlow    long  nInternalLength = 0L;
7236007Sthurlow    long  nElementLength = ASNDerCalcElementLength( nLength, &nInternalLength );
7246007Sthurlow    long  nTempLength = 0L;
7256007Sthurlow 
7266007Sthurlow    // Write out the sequence byte and the length of the type and data
7276007Sthurlow    nTempLength = ASNDerWriteToken( pbData, ucElementSequence, NULL, nInternalLength );
7286007Sthurlow 
7296007Sthurlow    // Adjust the data pointer
7306007Sthurlow    pbData += nTempLength;
7316007Sthurlow 
7326007Sthurlow    // Now write the type and the data.
7336007Sthurlow    nTempLength = ASNDerWriteToken( pbData, ucType, pbTokenValue, nLength );
7346007Sthurlow 
7356007Sthurlow    return nElementLength;
7366007Sthurlow }
737