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