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