1*4bff34e3Sthurlow /* 2*4bff34e3Sthurlow // Copyright (C) 2002 Microsoft Corporation 3*4bff34e3Sthurlow // All rights reserved. 4*4bff34e3Sthurlow // 5*4bff34e3Sthurlow // THIS CODE AND INFORMATION IS PROVIDED "AS IS" 6*4bff34e3Sthurlow // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 7*4bff34e3Sthurlow // OR IMPLIED, INCLUDING BUT NOT LIMITED 8*4bff34e3Sthurlow // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY 9*4bff34e3Sthurlow // AND/OR FITNESS FOR A PARTICULAR PURPOSE. 10*4bff34e3Sthurlow // 11*4bff34e3Sthurlow // Date - 10/08/2002 12*4bff34e3Sthurlow // Author - Sanj Surati 13*4bff34e3Sthurlow 14*4bff34e3Sthurlow 15*4bff34e3Sthurlow ///////////////////////////////////////////////////////////// 16*4bff34e3Sthurlow // 17*4bff34e3Sthurlow // DERPARSE.C 18*4bff34e3Sthurlow // 19*4bff34e3Sthurlow // SPNEGO Token Handler Source File 20*4bff34e3Sthurlow // 21*4bff34e3Sthurlow // Contains implementation of ASN.1 DER read/write functions 22*4bff34e3Sthurlow // as defined in DERPARSE.H. 23*4bff34e3Sthurlow // 24*4bff34e3Sthurlow ///////////////////////////////////////////////////////////// 25*4bff34e3Sthurlow 26*4bff34e3Sthurlow */ 27*4bff34e3Sthurlow 28*4bff34e3Sthurlow #pragma ident "%Z%%M% %I% %E% SMI" 29*4bff34e3Sthurlow 30*4bff34e3Sthurlow #include <stdlib.h> 31*4bff34e3Sthurlow #include <stdio.h> 32*4bff34e3Sthurlow #include <memory.h> 33*4bff34e3Sthurlow #include <sys/byteorder.h> 34*4bff34e3Sthurlow #include "spnego.h" 35*4bff34e3Sthurlow #include "derparse.h" 36*4bff34e3Sthurlow 37*4bff34e3Sthurlow /* 38*4bff34e3Sthurlow // 39*4bff34e3Sthurlow // The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in 40*4bff34e3Sthurlow // the array below, that a mechanism can be found. 41*4bff34e3Sthurlow // 42*4bff34e3Sthurlow */ 43*4bff34e3Sthurlow #pragma error_messages (off,E_INITIALIZATION_TYPE_MISMATCH) 44*4bff34e3Sthurlow MECH_OID g_stcMechOIDList [] = 45*4bff34e3Sthurlow { 46*4bff34e3Sthurlow {"\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02", 11, 9, 47*4bff34e3Sthurlow spnego_mech_oid_Kerberos_V5_Legacy }, // 1.2.840.48018.1.2.2 48*4bff34e3Sthurlow {"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02", 11, 9, 49*4bff34e3Sthurlow spnego_mech_oid_Kerberos_V5 }, // 1.2.840.113554.1.2.2 50*4bff34e3Sthurlow {"\x06\x06\x2b\x06\x01\x05\x05\x02", 8, 6, 51*4bff34e3Sthurlow spnego_mech_oid_Spnego }, // 1.3.6.1.5.5.2 52*4bff34e3Sthurlow {"\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a", 12, 10, 53*4bff34e3Sthurlow spnego_mech_oid_NTLMSSP }, // 1.3.6.1.4.1.311.2.2.10 54*4bff34e3Sthurlow {"", 0, 0, spnego_mech_oid_NotUsed } // Placeholder 55*4bff34e3Sthurlow }; 56*4bff34e3Sthurlow #pragma error_messages (default,E_INITIALIZATION_TYPE_MISMATCH) 57*4bff34e3Sthurlow 58*4bff34e3Sthurlow /* 59*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 60*4bff34e3Sthurlow // 61*4bff34e3Sthurlow // Function: 62*4bff34e3Sthurlow // ASNDerGetLength 63*4bff34e3Sthurlow // 64*4bff34e3Sthurlow // Parameters: 65*4bff34e3Sthurlow // [in] pbLengthData - DER Length Data 66*4bff34e3Sthurlow // [in] nBoundaryLength - Length that value must not exceed. 67*4bff34e3Sthurlow // [out] pnLength - Filled out with length value 68*4bff34e3Sthurlow // [out] pnNumLengthBytes - Filled out with number of bytes 69*4bff34e3Sthurlow // consumed by DER length. 70*4bff34e3Sthurlow // 71*4bff34e3Sthurlow // Returns: 72*4bff34e3Sthurlow // int Success - SPNEGO_E_SUCCESS 73*4bff34e3Sthurlow // Failure - SPNEGO API Error code 74*4bff34e3Sthurlow // 75*4bff34e3Sthurlow // Comments : 76*4bff34e3Sthurlow // Interprets the data at pbLengthData as a DER length. The length must 77*4bff34e3Sthurlow // fit within the bounds of nBoundary length. We do not currently 78*4bff34e3Sthurlow // process lengths that take more than 4 bytes. 79*4bff34e3Sthurlow // 80*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 81*4bff34e3Sthurlow */ 82*4bff34e3Sthurlow 83*4bff34e3Sthurlow int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength, 84*4bff34e3Sthurlow long* pnNumLengthBytes ) 85*4bff34e3Sthurlow { 86*4bff34e3Sthurlow int nReturn = SPNEGO_E_INVALID_LENGTH; 87*4bff34e3Sthurlow int nNumLengthBytes = 0; 88*4bff34e3Sthurlow 89*4bff34e3Sthurlow // First check if the extended length bit is set 90*4bff34e3Sthurlow 91*4bff34e3Sthurlow if ( *pbLengthData & LEN_XTND ) 92*4bff34e3Sthurlow { 93*4bff34e3Sthurlow // Lower 7 bits contain the number of trailing bytes that describe the length 94*4bff34e3Sthurlow nNumLengthBytes = *pbLengthData & LEN_MASK; 95*4bff34e3Sthurlow 96*4bff34e3Sthurlow // Check that the number of bytes we are about to read is within our boundary 97*4bff34e3Sthurlow // constraints 98*4bff34e3Sthurlow 99*4bff34e3Sthurlow if ( nNumLengthBytes <= nBoundaryLength - 1 ) 100*4bff34e3Sthurlow { 101*4bff34e3Sthurlow 102*4bff34e3Sthurlow // For now, our handler won't deal with lengths greater than 4 bytes 103*4bff34e3Sthurlow if ( nNumLengthBytes >= 1 && nNumLengthBytes <= 4 ) 104*4bff34e3Sthurlow { 105*4bff34e3Sthurlow // 0 out the initial length 106*4bff34e3Sthurlow *pnLength = 0L; 107*4bff34e3Sthurlow 108*4bff34e3Sthurlow // Bump by 1 byte 109*4bff34e3Sthurlow pbLengthData++; 110*4bff34e3Sthurlow 111*4bff34e3Sthurlow #ifdef _LITTLE_ENDIAN 112*4bff34e3Sthurlow 113*4bff34e3Sthurlow // There may be a cleaner way to do this, but for now, this seems to be 114*4bff34e3Sthurlow // an easy way to do the transformation 115*4bff34e3Sthurlow switch ( nNumLengthBytes ) 116*4bff34e3Sthurlow { 117*4bff34e3Sthurlow case 1: 118*4bff34e3Sthurlow { 119*4bff34e3Sthurlow *( ( (unsigned char*) pnLength ) ) = *pbLengthData; 120*4bff34e3Sthurlow break; 121*4bff34e3Sthurlow } 122*4bff34e3Sthurlow 123*4bff34e3Sthurlow case 2: 124*4bff34e3Sthurlow { 125*4bff34e3Sthurlow *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 1); 126*4bff34e3Sthurlow *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData); 127*4bff34e3Sthurlow 128*4bff34e3Sthurlow break; 129*4bff34e3Sthurlow } 130*4bff34e3Sthurlow 131*4bff34e3Sthurlow case 3: 132*4bff34e3Sthurlow { 133*4bff34e3Sthurlow *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 2); 134*4bff34e3Sthurlow *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1); 135*4bff34e3Sthurlow *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData); 136*4bff34e3Sthurlow break; 137*4bff34e3Sthurlow } 138*4bff34e3Sthurlow 139*4bff34e3Sthurlow case 4: 140*4bff34e3Sthurlow { 141*4bff34e3Sthurlow *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 3); 142*4bff34e3Sthurlow *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData + 2); 143*4bff34e3Sthurlow *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1); 144*4bff34e3Sthurlow *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData); 145*4bff34e3Sthurlow break; 146*4bff34e3Sthurlow } 147*4bff34e3Sthurlow 148*4bff34e3Sthurlow } // SWITCH ( nNumLengthBytes ) 149*4bff34e3Sthurlow 150*4bff34e3Sthurlow #else 151*4bff34e3Sthurlow // We are Big-Endian, so the length can be copied in from the source 152*4bff34e3Sthurlow // as is. Ensure that we adjust for the number of bytes we actually 153*4bff34e3Sthurlow // copy. 154*4bff34e3Sthurlow 155*4bff34e3Sthurlow memcpy( ( (unsigned char *) pnLength ) + ( 4 - nNumLengthBytes ), 156*4bff34e3Sthurlow pbLengthData, nNumLengthBytes ); 157*4bff34e3Sthurlow #endif 158*4bff34e3Sthurlow 159*4bff34e3Sthurlow // Account for the initial length byte 160*4bff34e3Sthurlow *pnNumLengthBytes = nNumLengthBytes + 1; 161*4bff34e3Sthurlow nReturn = SPNEGO_E_SUCCESS; 162*4bff34e3Sthurlow 163*4bff34e3Sthurlow } // IF Valid Length 164*4bff34e3Sthurlow 165*4bff34e3Sthurlow } // IF num bytes to read is within the boundary length 166*4bff34e3Sthurlow 167*4bff34e3Sthurlow } // IF xtended length 168*4bff34e3Sthurlow else 169*4bff34e3Sthurlow { 170*4bff34e3Sthurlow 171*4bff34e3Sthurlow // Extended bit is not set, so the length is in the value and the one 172*4bff34e3Sthurlow // byte describes the length 173*4bff34e3Sthurlow *pnLength = *pbLengthData & LEN_MASK; 174*4bff34e3Sthurlow *pnNumLengthBytes = 1; 175*4bff34e3Sthurlow nReturn = SPNEGO_E_SUCCESS; 176*4bff34e3Sthurlow 177*4bff34e3Sthurlow } 178*4bff34e3Sthurlow 179*4bff34e3Sthurlow return nReturn; 180*4bff34e3Sthurlow } 181*4bff34e3Sthurlow 182*4bff34e3Sthurlow 183*4bff34e3Sthurlow /* 184*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 185*4bff34e3Sthurlow // 186*4bff34e3Sthurlow // Function: 187*4bff34e3Sthurlow // ASNDerCheckToken 188*4bff34e3Sthurlow // 189*4bff34e3Sthurlow // Parameters: 190*4bff34e3Sthurlow // [in] pbTokenData - Token Data 191*4bff34e3Sthurlow // [in] nToken - Token identifier to check for 192*4bff34e3Sthurlow // [in] nLengthWithToken - Expected token length (with data) 193*4bff34e3Sthurlow // [in] nBoundaryLength - Length that value must not exceed. 194*4bff34e3Sthurlow // [out] pnLength - Filled out with data length 195*4bff34e3Sthurlow // [out] pnTokenLength - Filled out with number of bytes 196*4bff34e3Sthurlow // consumed by token identifier and length. 197*4bff34e3Sthurlow // 198*4bff34e3Sthurlow // Returns: 199*4bff34e3Sthurlow // int Success - SPNEGO_E_SUCCESS 200*4bff34e3Sthurlow // Failure - SPNEGO API Error code 201*4bff34e3Sthurlow // 202*4bff34e3Sthurlow // Comments : 203*4bff34e3Sthurlow // Checks the data pointed to by pbTokenData for the specified token 204*4bff34e3Sthurlow // identifier and the length that immediately follows. If 205*4bff34e3Sthurlow // nLengthWithToken is > 0, the calculated length must match. The 206*4bff34e3Sthurlow // length must also not exceed the specified boundary length . 207*4bff34e3Sthurlow // 208*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 209*4bff34e3Sthurlow */ 210*4bff34e3Sthurlow 211*4bff34e3Sthurlow int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken, 212*4bff34e3Sthurlow long nLengthWithToken, long nBoundaryLength, 213*4bff34e3Sthurlow long* pnLength, long* pnTokenLength ) 214*4bff34e3Sthurlow { 215*4bff34e3Sthurlow 216*4bff34e3Sthurlow int nReturn = SPNEGO_E_INVALID_LENGTH; 217*4bff34e3Sthurlow long nNumLengthBytes = 0L; 218*4bff34e3Sthurlow 219*4bff34e3Sthurlow // Make sure that we've at least got 2 bytes of room to work with 220*4bff34e3Sthurlow 221*4bff34e3Sthurlow if ( nBoundaryLength >= 2 ) 222*4bff34e3Sthurlow { 223*4bff34e3Sthurlow // The first byte of the token data MUST match the specified token 224*4bff34e3Sthurlow if ( *pbTokenData == nToken ) 225*4bff34e3Sthurlow { 226*4bff34e3Sthurlow // Next byte indicates the length 227*4bff34e3Sthurlow pbTokenData++; 228*4bff34e3Sthurlow 229*4bff34e3Sthurlow // Get the length described by the token 230*4bff34e3Sthurlow if ( ( nReturn = ASNDerGetLength( pbTokenData, nBoundaryLength, pnLength, 231*4bff34e3Sthurlow &nNumLengthBytes ) ) == SPNEGO_E_SUCCESS ) 232*4bff34e3Sthurlow { 233*4bff34e3Sthurlow // Verify that the length is LESS THAN the boundary length 234*4bff34e3Sthurlow // (this should prevent us walking out of our buffer) 235*4bff34e3Sthurlow if ( ( nBoundaryLength - ( nNumLengthBytes + 1 ) < *pnLength ) ) 236*4bff34e3Sthurlow { 237*4bff34e3Sthurlow 238*4bff34e3Sthurlow nReturn = SPNEGO_E_INVALID_LENGTH; 239*4bff34e3Sthurlow 240*4bff34e3Sthurlow } 241*4bff34e3Sthurlow 242*4bff34e3Sthurlow // If we were passed a length to check, do so now 243*4bff34e3Sthurlow if ( nLengthWithToken > 0L ) 244*4bff34e3Sthurlow { 245*4bff34e3Sthurlow 246*4bff34e3Sthurlow // Check that the expected length matches 247*4bff34e3Sthurlow if ( ( nLengthWithToken - ( nNumLengthBytes + 1 ) ) != *pnLength ) 248*4bff34e3Sthurlow { 249*4bff34e3Sthurlow 250*4bff34e3Sthurlow nReturn = SPNEGO_E_INVALID_LENGTH; 251*4bff34e3Sthurlow 252*4bff34e3Sthurlow } 253*4bff34e3Sthurlow 254*4bff34e3Sthurlow } // IF need to validate length 255*4bff34e3Sthurlow 256*4bff34e3Sthurlow if ( SPNEGO_E_SUCCESS == nReturn ) 257*4bff34e3Sthurlow { 258*4bff34e3Sthurlow *pnTokenLength = nNumLengthBytes + 1; 259*4bff34e3Sthurlow } 260*4bff34e3Sthurlow 261*4bff34e3Sthurlow } // IF ASNDerGetLength 262*4bff34e3Sthurlow 263*4bff34e3Sthurlow } // IF token matches 264*4bff34e3Sthurlow else 265*4bff34e3Sthurlow { 266*4bff34e3Sthurlow nReturn = SPNEGO_E_TOKEN_NOT_FOUND; 267*4bff34e3Sthurlow } 268*4bff34e3Sthurlow 269*4bff34e3Sthurlow } // IF Boundary Length is at least 2 bytes 270*4bff34e3Sthurlow 271*4bff34e3Sthurlow return nReturn; 272*4bff34e3Sthurlow } 273*4bff34e3Sthurlow 274*4bff34e3Sthurlow /* 275*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 276*4bff34e3Sthurlow // 277*4bff34e3Sthurlow // Function: 278*4bff34e3Sthurlow // ASNDerCheckOID 279*4bff34e3Sthurlow // 280*4bff34e3Sthurlow // Parameters: 281*4bff34e3Sthurlow // [in] pbTokenData - Token Data 282*4bff34e3Sthurlow // [in] nMechOID - OID we are looking for 283*4bff34e3Sthurlow // [in] nBoundaryLength - Length that value must not exceed. 284*4bff34e3Sthurlow // [out] pnTokenLength - Filled out with number of bytes 285*4bff34e3Sthurlow // consumed by token and data. 286*4bff34e3Sthurlow // 287*4bff34e3Sthurlow // Returns: 288*4bff34e3Sthurlow // int Success - SPNEGO_E_SUCCESS 289*4bff34e3Sthurlow // Failure - SPNEGO API Error code 290*4bff34e3Sthurlow // 291*4bff34e3Sthurlow // Comments : 292*4bff34e3Sthurlow // Checks the data pointed to by pbTokenData for the specified OID. 293*4bff34e3Sthurlow // 294*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 295*4bff34e3Sthurlow */ 296*4bff34e3Sthurlow 297*4bff34e3Sthurlow int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength, 298*4bff34e3Sthurlow long* pnTokenLength ) 299*4bff34e3Sthurlow { 300*4bff34e3Sthurlow int nReturn = 0L; 301*4bff34e3Sthurlow long nLength = 0L; 302*4bff34e3Sthurlow 303*4bff34e3Sthurlow // Verify that we have an OID token 304*4bff34e3Sthurlow if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, 0L, nBoundaryLength, 305*4bff34e3Sthurlow &nLength, pnTokenLength ) ) == SPNEGO_E_SUCCESS ) 306*4bff34e3Sthurlow { 307*4bff34e3Sthurlow // Add the data length to the Token Length 308*4bff34e3Sthurlow *pnTokenLength += nLength; 309*4bff34e3Sthurlow 310*4bff34e3Sthurlow // Token Lengths plus the actual length must match the length in our OID list element. 311*4bff34e3Sthurlow // If it doesn't, we're done 312*4bff34e3Sthurlow if ( *pnTokenLength == g_stcMechOIDList[nMechOID].iLen ) 313*4bff34e3Sthurlow { 314*4bff34e3Sthurlow // Memcompare the token and the expected field 315*4bff34e3Sthurlow if ( memcmp( pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength ) != 0 ) 316*4bff34e3Sthurlow { 317*4bff34e3Sthurlow nReturn = SPNEGO_E_UNEXPECTED_OID; 318*4bff34e3Sthurlow } 319*4bff34e3Sthurlow } 320*4bff34e3Sthurlow else 321*4bff34e3Sthurlow { 322*4bff34e3Sthurlow nReturn = SPNEGO_E_UNEXPECTED_OID; 323*4bff34e3Sthurlow } 324*4bff34e3Sthurlow 325*4bff34e3Sthurlow } // IF OID Token CHecks 326*4bff34e3Sthurlow 327*4bff34e3Sthurlow return nReturn; 328*4bff34e3Sthurlow } 329*4bff34e3Sthurlow 330*4bff34e3Sthurlow /* 331*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 332*4bff34e3Sthurlow // 333*4bff34e3Sthurlow // Function: 334*4bff34e3Sthurlow // ASNDerCalcNumLengthBytes 335*4bff34e3Sthurlow // 336*4bff34e3Sthurlow // Parameters: 337*4bff34e3Sthurlow // [in] nLength - Length to calculate length bytes for. 338*4bff34e3Sthurlow // 339*4bff34e3Sthurlow // Returns: 340*4bff34e3Sthurlow // int Number of bytes necessary to represent length 341*4bff34e3Sthurlow // 342*4bff34e3Sthurlow // Comments : 343*4bff34e3Sthurlow // Helper function to calculate the number of length bytes necessary to 344*4bff34e3Sthurlow // represent a length value. For our purposes, a 32-bit value should be 345*4bff34e3Sthurlow // enough to describea length. 346*4bff34e3Sthurlow // 347*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 348*4bff34e3Sthurlow */ 349*4bff34e3Sthurlow 350*4bff34e3Sthurlow int ASNDerCalcNumLengthBytes( long nLength ) 351*4bff34e3Sthurlow { 352*4bff34e3Sthurlow if ( nLength <= 0x7F ) 353*4bff34e3Sthurlow { 354*4bff34e3Sthurlow // A single byte will be sufficient for describing this length. 355*4bff34e3Sthurlow // The byte will simply contain the length 356*4bff34e3Sthurlow return 1; 357*4bff34e3Sthurlow } 358*4bff34e3Sthurlow else if ( nLength <= 0xFF ) 359*4bff34e3Sthurlow { 360*4bff34e3Sthurlow // Two bytes are necessary, one to say how many following bytes 361*4bff34e3Sthurlow // describe the length, and one to give the length 362*4bff34e3Sthurlow return 2; 363*4bff34e3Sthurlow } 364*4bff34e3Sthurlow else if ( nLength <= 0xFFFF ) 365*4bff34e3Sthurlow { 366*4bff34e3Sthurlow // Three bytes are necessary, one to say how many following bytes 367*4bff34e3Sthurlow // describe the length, and two to give the length 368*4bff34e3Sthurlow return 3; 369*4bff34e3Sthurlow } 370*4bff34e3Sthurlow else if ( nLength <= 0xFFFFFF ) 371*4bff34e3Sthurlow { 372*4bff34e3Sthurlow // Four bytes are necessary, one to say how many following bytes 373*4bff34e3Sthurlow // describe the length, and three to give the length 374*4bff34e3Sthurlow return 4; 375*4bff34e3Sthurlow } 376*4bff34e3Sthurlow else 377*4bff34e3Sthurlow { 378*4bff34e3Sthurlow // Five bytes are necessary, one to say how many following bytes 379*4bff34e3Sthurlow // describe the length, and four to give the length 380*4bff34e3Sthurlow return 5; 381*4bff34e3Sthurlow } 382*4bff34e3Sthurlow } 383*4bff34e3Sthurlow 384*4bff34e3Sthurlow 385*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 386*4bff34e3Sthurlow // 387*4bff34e3Sthurlow // Function: 388*4bff34e3Sthurlow // ASNDerCalcTokenLength 389*4bff34e3Sthurlow // 390*4bff34e3Sthurlow // Parameters: 391*4bff34e3Sthurlow // [in] nLength - Length to calculate length bytes for. 392*4bff34e3Sthurlow // [in] nDataLength - Actual Data length value. 393*4bff34e3Sthurlow // 394*4bff34e3Sthurlow // Returns: 395*4bff34e3Sthurlow // long Number of bytes necessary to represent a token, length and data 396*4bff34e3Sthurlow // 397*4bff34e3Sthurlow // Comments : 398*4bff34e3Sthurlow // Helper function to calculate a token and value size, based on a 399*4bff34e3Sthurlow // supplied length value, and any binary data that will need to be 400*4bff34e3Sthurlow // written out. 401*4bff34e3Sthurlow // 402*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 403*4bff34e3Sthurlow 404*4bff34e3Sthurlow long ASNDerCalcTokenLength( long nLength, long nDataLength ) 405*4bff34e3Sthurlow { 406*4bff34e3Sthurlow // Add a byte to the length size to account for a single byte to 407*4bff34e3Sthurlow // hold the token type. 408*4bff34e3Sthurlow long nTotalLength = ASNDerCalcNumLengthBytes( nLength ) + 1; 409*4bff34e3Sthurlow 410*4bff34e3Sthurlow return nTotalLength + nDataLength; 411*4bff34e3Sthurlow } 412*4bff34e3Sthurlow 413*4bff34e3Sthurlow 414*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 415*4bff34e3Sthurlow // 416*4bff34e3Sthurlow // Function: 417*4bff34e3Sthurlow // ASNDerCalcElementLength 418*4bff34e3Sthurlow // 419*4bff34e3Sthurlow // Parameters: 420*4bff34e3Sthurlow // [in] nDataLength - Length of data. 421*4bff34e3Sthurlow // [out] pnInternalLength - Filled out with length of element 422*4bff34e3Sthurlow // without sequence info. 423*4bff34e3Sthurlow // 424*4bff34e3Sthurlow // Returns: 425*4bff34e3Sthurlow // long Number of bytes necessary to represent an element 426*4bff34e3Sthurlow // 427*4bff34e3Sthurlow // Comments : 428*4bff34e3Sthurlow // Helper function to calculate an element length. An element consists 429*4bff34e3Sthurlow // of a sequence token, a type token and then the data. 430*4bff34e3Sthurlow // 431*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 432*4bff34e3Sthurlow 433*4bff34e3Sthurlow long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength ) 434*4bff34e3Sthurlow { 435*4bff34e3Sthurlow // First the type token and the actual data 436*4bff34e3Sthurlow long nTotalLength = ASNDerCalcTokenLength( nDataLength, nDataLength ); 437*4bff34e3Sthurlow 438*4bff34e3Sthurlow // Internal length is the length without the element sequence token 439*4bff34e3Sthurlow if ( NULL != pnInternalLength ) 440*4bff34e3Sthurlow { 441*4bff34e3Sthurlow *pnInternalLength = nTotalLength; 442*4bff34e3Sthurlow } 443*4bff34e3Sthurlow 444*4bff34e3Sthurlow // Next add in the element's sequence token (remember that its 445*4bff34e3Sthurlow // length is the total length of the type token and data) 446*4bff34e3Sthurlow nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); 447*4bff34e3Sthurlow 448*4bff34e3Sthurlow return nTotalLength; 449*4bff34e3Sthurlow } 450*4bff34e3Sthurlow 451*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 452*4bff34e3Sthurlow // 453*4bff34e3Sthurlow // Function: 454*4bff34e3Sthurlow // ASNDerCalcMechListLength 455*4bff34e3Sthurlow // 456*4bff34e3Sthurlow // Parameters: 457*4bff34e3Sthurlow // [in] mechoid - Mech OID to put in list. 458*4bff34e3Sthurlow // [out] pnInternalLength - Filled out with length of element 459*4bff34e3Sthurlow // without the primary sequence token. 460*4bff34e3Sthurlow // 461*4bff34e3Sthurlow // Returns: 462*4bff34e3Sthurlow // long Number of bytes necessary to represent a mechList 463*4bff34e3Sthurlow // 464*4bff34e3Sthurlow // Comments : 465*4bff34e3Sthurlow // Helper function to calculate a MechList length. A mechlist consists 466*4bff34e3Sthurlow // of a NegTokenInit sequence token, a sequence token for the MechList 467*4bff34e3Sthurlow // and finally a list of OIDs. In our case, we only really have one 468*4bff34e3Sthurlow // OID. 469*4bff34e3Sthurlow // 470*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 471*4bff34e3Sthurlow 472*4bff34e3Sthurlow long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength ) 473*4bff34e3Sthurlow { 474*4bff34e3Sthurlow // First the OID 475*4bff34e3Sthurlow long nTotalLength = g_stcMechOIDList[mechoid].iLen; 476*4bff34e3Sthurlow 477*4bff34e3Sthurlow // Next add in a sequence token 478*4bff34e3Sthurlow nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); 479*4bff34e3Sthurlow 480*4bff34e3Sthurlow // Internal length is the length without the element sequence token 481*4bff34e3Sthurlow if ( NULL != pnInternalLength ) 482*4bff34e3Sthurlow { 483*4bff34e3Sthurlow *pnInternalLength = nTotalLength; 484*4bff34e3Sthurlow } 485*4bff34e3Sthurlow 486*4bff34e3Sthurlow // Finally add in the element's sequence token 487*4bff34e3Sthurlow nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); 488*4bff34e3Sthurlow 489*4bff34e3Sthurlow return nTotalLength; 490*4bff34e3Sthurlow } 491*4bff34e3Sthurlow 492*4bff34e3Sthurlow 493*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 494*4bff34e3Sthurlow // 495*4bff34e3Sthurlow // Function: 496*4bff34e3Sthurlow // ASNDerWriteLength 497*4bff34e3Sthurlow // 498*4bff34e3Sthurlow // Parameters: 499*4bff34e3Sthurlow // [out] pbData - Buffer to write into. 500*4bff34e3Sthurlow // [in] nLength - Length to write out. 501*4bff34e3Sthurlow // 502*4bff34e3Sthurlow // Returns: 503*4bff34e3Sthurlow // int Number of bytes written out 504*4bff34e3Sthurlow // 505*4bff34e3Sthurlow // Comments : 506*4bff34e3Sthurlow // Helper function to write out a length value following DER rules . 507*4bff34e3Sthurlow // 508*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 509*4bff34e3Sthurlow 510*4bff34e3Sthurlow int ASNDerWriteLength( unsigned char* pbData, long nLength ) 511*4bff34e3Sthurlow { 512*4bff34e3Sthurlow int nNumBytesRequired = ASNDerCalcNumLengthBytes( nLength ); 513*4bff34e3Sthurlow int nNumLengthBytes = nNumBytesRequired - 1; 514*4bff34e3Sthurlow 515*4bff34e3Sthurlow 516*4bff34e3Sthurlow if ( nNumBytesRequired > 1 ) 517*4bff34e3Sthurlow { 518*4bff34e3Sthurlow 519*4bff34e3Sthurlow // Write out the number of bytes following which will be used 520*4bff34e3Sthurlow *pbData = (unsigned char ) ( LEN_XTND | nNumLengthBytes ); 521*4bff34e3Sthurlow 522*4bff34e3Sthurlow // Point to where we'll actually write the length 523*4bff34e3Sthurlow pbData++; 524*4bff34e3Sthurlow 525*4bff34e3Sthurlow #ifdef _LITTLE_ENDIAN 526*4bff34e3Sthurlow 527*4bff34e3Sthurlow // There may be a cleaner way to do this, but for now, this seems to be 528*4bff34e3Sthurlow // an easy way to do the transformation 529*4bff34e3Sthurlow switch ( nNumLengthBytes ) 530*4bff34e3Sthurlow { 531*4bff34e3Sthurlow case 1: 532*4bff34e3Sthurlow { 533*4bff34e3Sthurlow // Cast the length to a single byte, since we know that it 534*4bff34e3Sthurlow // is 0x7F or less (or we wouldn't only need a single byte). 535*4bff34e3Sthurlow 536*4bff34e3Sthurlow *pbData = (unsigned char) nLength; 537*4bff34e3Sthurlow break; 538*4bff34e3Sthurlow } 539*4bff34e3Sthurlow 540*4bff34e3Sthurlow case 2: 541*4bff34e3Sthurlow { 542*4bff34e3Sthurlow *pbData = *( ( (unsigned char*) &nLength ) + 1 ); 543*4bff34e3Sthurlow *( pbData + 1) = *( ( (unsigned char*) &nLength ) ); 544*4bff34e3Sthurlow break; 545*4bff34e3Sthurlow } 546*4bff34e3Sthurlow 547*4bff34e3Sthurlow case 3: 548*4bff34e3Sthurlow { 549*4bff34e3Sthurlow *pbData = *( ( (unsigned char*) &nLength ) + 3 ); 550*4bff34e3Sthurlow *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 ); 551*4bff34e3Sthurlow *( pbData + 2) = *( ( (unsigned char*) &nLength ) ); 552*4bff34e3Sthurlow break; 553*4bff34e3Sthurlow } 554*4bff34e3Sthurlow 555*4bff34e3Sthurlow case 4: 556*4bff34e3Sthurlow { 557*4bff34e3Sthurlow *pbData = *( ( (unsigned char*) &nLength ) + 3 ); 558*4bff34e3Sthurlow *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 ); 559*4bff34e3Sthurlow *( pbData + 2) = *( ( (unsigned char*) &nLength ) + 1 ); 560*4bff34e3Sthurlow *( pbData + 3) = *( ( (unsigned char*) &nLength ) ); 561*4bff34e3Sthurlow break; 562*4bff34e3Sthurlow } 563*4bff34e3Sthurlow 564*4bff34e3Sthurlow } // SWITCH ( nNumLengthBytes ) 565*4bff34e3Sthurlow 566*4bff34e3Sthurlow #else 567*4bff34e3Sthurlow // We are Big-Endian, so the length can be copied in from the source 568*4bff34e3Sthurlow // as is. Ensure that we adjust for the number of bytes we actually 569*4bff34e3Sthurlow // copy. 570*4bff34e3Sthurlow 571*4bff34e3Sthurlow memcpy( pbData, 572*4bff34e3Sthurlow ( (unsigned char *) &nLength ) + ( 4 - nNumLengthBytes ), nNumLengthBytes ); 573*4bff34e3Sthurlow #endif 574*4bff34e3Sthurlow 575*4bff34e3Sthurlow } // IF > 1 byte for length 576*4bff34e3Sthurlow else 577*4bff34e3Sthurlow { 578*4bff34e3Sthurlow // Cast the length to a single byte, since we know that it 579*4bff34e3Sthurlow // is 0x7F or less (or we wouldn't only need a single byte). 580*4bff34e3Sthurlow 581*4bff34e3Sthurlow *pbData = (unsigned char) nLength; 582*4bff34e3Sthurlow } 583*4bff34e3Sthurlow 584*4bff34e3Sthurlow return nNumBytesRequired; 585*4bff34e3Sthurlow } 586*4bff34e3Sthurlow 587*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 588*4bff34e3Sthurlow // 589*4bff34e3Sthurlow // Function: 590*4bff34e3Sthurlow // ASNDerWriteToken 591*4bff34e3Sthurlow // 592*4bff34e3Sthurlow // Parameters: 593*4bff34e3Sthurlow // [out] pbData - Buffer to write into. 594*4bff34e3Sthurlow // [in] ucType - Token Type 595*4bff34e3Sthurlow // [in] pbTokenValue - Actual Value 596*4bff34e3Sthurlow // [in] nLength - Length of Data. 597*4bff34e3Sthurlow // 598*4bff34e3Sthurlow // Returns: 599*4bff34e3Sthurlow // int Number of bytes written out 600*4bff34e3Sthurlow // 601*4bff34e3Sthurlow // Comments : 602*4bff34e3Sthurlow // Helper function to write out a token and any associated data. If 603*4bff34e3Sthurlow // pbTokenValue is non-NULL, then it is written out in addition to the 604*4bff34e3Sthurlow // token identifier and the length bytes. 605*4bff34e3Sthurlow // 606*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 607*4bff34e3Sthurlow 608*4bff34e3Sthurlow int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType, 609*4bff34e3Sthurlow unsigned char* pbTokenValue, long nLength ) 610*4bff34e3Sthurlow { 611*4bff34e3Sthurlow int nTotalBytesWrittenOut = 0L; 612*4bff34e3Sthurlow int nNumLengthBytesWritten = 0L; 613*4bff34e3Sthurlow 614*4bff34e3Sthurlow // Write out the type 615*4bff34e3Sthurlow *pbData = ucType; 616*4bff34e3Sthurlow 617*4bff34e3Sthurlow // Wrote 1 byte, and move data pointer 618*4bff34e3Sthurlow nTotalBytesWrittenOut++; 619*4bff34e3Sthurlow pbData++; 620*4bff34e3Sthurlow 621*4bff34e3Sthurlow // Now write out the length and adjust the number of bytes written out 622*4bff34e3Sthurlow nNumLengthBytesWritten = ASNDerWriteLength( pbData, nLength ); 623*4bff34e3Sthurlow 624*4bff34e3Sthurlow nTotalBytesWrittenOut += nNumLengthBytesWritten; 625*4bff34e3Sthurlow pbData += nNumLengthBytesWritten; 626*4bff34e3Sthurlow 627*4bff34e3Sthurlow // Write out the token value if we got one. The assumption is that the 628*4bff34e3Sthurlow // nLength value indicates how many bytes are in pbTokenValue. 629*4bff34e3Sthurlow 630*4bff34e3Sthurlow if ( NULL != pbTokenValue ) 631*4bff34e3Sthurlow { 632*4bff34e3Sthurlow memcpy( pbData, pbTokenValue, nLength ); 633*4bff34e3Sthurlow nTotalBytesWrittenOut += nLength; 634*4bff34e3Sthurlow } 635*4bff34e3Sthurlow 636*4bff34e3Sthurlow return nTotalBytesWrittenOut; 637*4bff34e3Sthurlow } 638*4bff34e3Sthurlow 639*4bff34e3Sthurlow 640*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 641*4bff34e3Sthurlow // 642*4bff34e3Sthurlow // Function: 643*4bff34e3Sthurlow // ASNDerWriteOID 644*4bff34e3Sthurlow // 645*4bff34e3Sthurlow // Parameters: 646*4bff34e3Sthurlow // [out] pbData - Buffer to write into. 647*4bff34e3Sthurlow // [in] eMechOID - OID to write out. 648*4bff34e3Sthurlow // 649*4bff34e3Sthurlow // Returns: 650*4bff34e3Sthurlow // int Number of bytes written out 651*4bff34e3Sthurlow // 652*4bff34e3Sthurlow // Comments : 653*4bff34e3Sthurlow // Helper function to write out an OID. For these we have the raw bytes 654*4bff34e3Sthurlow // listed in a global structure. The caller simply indicates which OID 655*4bff34e3Sthurlow // should be written and we will splat out the data. 656*4bff34e3Sthurlow // 657*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 658*4bff34e3Sthurlow 659*4bff34e3Sthurlow int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID ) 660*4bff34e3Sthurlow { 661*4bff34e3Sthurlow 662*4bff34e3Sthurlow memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen ); 663*4bff34e3Sthurlow 664*4bff34e3Sthurlow return g_stcMechOIDList[eMechOID].iLen; 665*4bff34e3Sthurlow } 666*4bff34e3Sthurlow 667*4bff34e3Sthurlow 668*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 669*4bff34e3Sthurlow // 670*4bff34e3Sthurlow // Function: 671*4bff34e3Sthurlow // ASNDerWriteMechList 672*4bff34e3Sthurlow // 673*4bff34e3Sthurlow // Parameters: 674*4bff34e3Sthurlow // [out] pbData - Buffer to write into. 675*4bff34e3Sthurlow // [in] eMechOID - OID to put in MechList. 676*4bff34e3Sthurlow // 677*4bff34e3Sthurlow // Returns: 678*4bff34e3Sthurlow // int Number of bytes written out 679*4bff34e3Sthurlow // 680*4bff34e3Sthurlow // Comments : 681*4bff34e3Sthurlow // Helper function to write out a MechList. A MechList consists of the 682*4bff34e3Sthurlow // Init Token Sequence, a sequence token and then the list of OIDs. In 683*4bff34e3Sthurlow // our case the OID is from a global array of known OIDs. 684*4bff34e3Sthurlow // 685*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 686*4bff34e3Sthurlow 687*4bff34e3Sthurlow long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid ) 688*4bff34e3Sthurlow { 689*4bff34e3Sthurlow // First get the length 690*4bff34e3Sthurlow long nInternalLength = 0L; 691*4bff34e3Sthurlow long nMechListLength = ASNDerCalcMechListLength( mechoid, &nInternalLength ); 692*4bff34e3Sthurlow long nTempLength = 0L; 693*4bff34e3Sthurlow 694*4bff34e3Sthurlow nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES, 695*4bff34e3Sthurlow NULL, nInternalLength ); 696*4bff34e3Sthurlow 697*4bff34e3Sthurlow // Adjust the data pointer 698*4bff34e3Sthurlow pbData += nTempLength; 699*4bff34e3Sthurlow 700*4bff34e3Sthurlow // Now write the Sequence token and the OID (the OID is a BLOB in the global 701*4bff34e3Sthurlow // structure. 702*4bff34e3Sthurlow 703*4bff34e3Sthurlow nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE, 704*4bff34e3Sthurlow g_stcMechOIDList[mechoid].ucOid, 705*4bff34e3Sthurlow g_stcMechOIDList[mechoid].iLen ); 706*4bff34e3Sthurlow 707*4bff34e3Sthurlow return nMechListLength; 708*4bff34e3Sthurlow } 709*4bff34e3Sthurlow 710*4bff34e3Sthurlow 711*4bff34e3Sthurlow ///////////////////////////////////////////////////////////////////////////// 712*4bff34e3Sthurlow // 713*4bff34e3Sthurlow // Function: 714*4bff34e3Sthurlow // ASNDerWriteElement 715*4bff34e3Sthurlow // 716*4bff34e3Sthurlow // Parameters: 717*4bff34e3Sthurlow // [out] pbData - Buffer to write into. 718*4bff34e3Sthurlow // [in] ucElementSequence - Sequence Token 719*4bff34e3Sthurlow // [in] ucType - Token Type 720*4bff34e3Sthurlow // [in] pbTokenValue - Actual Value 721*4bff34e3Sthurlow // [in] nLength - Length of Data. 722*4bff34e3Sthurlow // 723*4bff34e3Sthurlow // Returns: 724*4bff34e3Sthurlow // int Number of bytes written out 725*4bff34e3Sthurlow // 726*4bff34e3Sthurlow // Comments : 727*4bff34e3Sthurlow // Helper function to write out a SPNEGO Token element. An element 728*4bff34e3Sthurlow // consists of a sequence token, a type token and the associated data. 729*4bff34e3Sthurlow // 730*4bff34e3Sthurlow //////////////////////////////////////////////////////////////////////////// 731*4bff34e3Sthurlow 732*4bff34e3Sthurlow int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence, 733*4bff34e3Sthurlow unsigned char ucType, unsigned char* pbTokenValue, long nLength ) 734*4bff34e3Sthurlow { 735*4bff34e3Sthurlow // First get the length 736*4bff34e3Sthurlow long nInternalLength = 0L; 737*4bff34e3Sthurlow long nElementLength = ASNDerCalcElementLength( nLength, &nInternalLength ); 738*4bff34e3Sthurlow long nTempLength = 0L; 739*4bff34e3Sthurlow 740*4bff34e3Sthurlow // Write out the sequence byte and the length of the type and data 741*4bff34e3Sthurlow nTempLength = ASNDerWriteToken( pbData, ucElementSequence, NULL, nInternalLength ); 742*4bff34e3Sthurlow 743*4bff34e3Sthurlow // Adjust the data pointer 744*4bff34e3Sthurlow pbData += nTempLength; 745*4bff34e3Sthurlow 746*4bff34e3Sthurlow // Now write the type and the data. 747*4bff34e3Sthurlow nTempLength = ASNDerWriteToken( pbData, ucType, pbTokenValue, nLength ); 748*4bff34e3Sthurlow 749*4bff34e3Sthurlow return nElementLength; 750*4bff34e3Sthurlow } 751