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 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 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 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 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 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 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 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 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 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 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 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 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