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