📄 derparse.c
字号:
// Copyright (C) 2002 Microsoft Corporation// All rights reserved.//// THIS CODE AND INFORMATION IS PROVIDED "AS IS"// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED// OR IMPLIED, INCLUDING BUT NOT LIMITED// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY// AND/OR FITNESS FOR A PARTICULAR PURPOSE.//// Date - 10/08/2002// Author - Sanj Surati///////////////////////////////////////////////////////////////// DERPARSE.C//// SPNEGO Token Handler Source File//// Contains implementation of ASN.1 DER read/write functions// as defined in DERPARSE.H.///////////////////////////////////////////////////////////////#include <stdlib.h>#include <stdio.h>#include <memory.h>#include "spnego.h"#include "derparse.h"//// The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in// the array below, that a mechanism can be found.//MECH_OID g_stcMechOIDList [] ={ { (unsigned char*) "\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02", 11, 9, spnego_mech_oid_Kerberos_V5_Legacy }, // 1.2.840.48018.1.2.2 { (unsigned char*) "\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02", 11, 9, spnego_mech_oid_Kerberos_V5 }, // 1.2.840.113554.1.2.2 { (unsigned char*) "\x06\x06\x2b\x06\x01\x05\x05\x02", 8, 6, spnego_mech_oid_Spnego }, // 1.3.6.1.1.5.5.2 { (unsigned char*) "", 0, 0, spnego_mech_oid_NotUsed } // Placeholder};///////////////////////////////////////////////////////////////////////////////// Function:// ASNDerGetLength//// Parameters:// [in] pbLengthData - DER Length Data// [in] nBoundaryLength - Length that value must not exceed.// [out] pnLength - Filled out with length value// [out] pnNumLengthBytes - Filled out with number of bytes// consumed by DER length.//// Returns:// int Success - SPNEGO_E_SUCCESS// Failure - SPNEGO API Error code//// Comments :// Interprets the data at pbLengthData as a DER length. The length must// fit within the bounds of nBoundary length. We do not currently// process lengths that take more than 4 bytes.//////////////////////////////////////////////////////////////////////////////int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength, long* pnNumLengthBytes ){ int nReturn = SPNEGO_E_INVALID_LENGTH; int nNumLengthBytes = 0; // First check if the extended length bit is set if ( *pbLengthData & LEN_XTND ) { // Lower 7 bits contain the number of trailing bytes that describe the length nNumLengthBytes = *pbLengthData & LEN_MASK; // Check that the number of bytes we are about to read is within our boundary // constraints if ( nNumLengthBytes <= nBoundaryLength - 1 ) { // For now, our handler won't deal with lengths greater than 4 bytes if ( nNumLengthBytes >= 1 && nNumLengthBytes <= 4 ) { // 0 out the initial length *pnLength = 0L; // Bump by 1 byte pbLengthData++; #ifdef __LITTLE_ENDIAN__ // There may be a cleaner way to do this, but for now, this seems to be // an easy way to do the transformation switch ( nNumLengthBytes ) { case 1: { *( ( (unsigned char*) pnLength ) ) = *pbLengthData; break; } case 2: { *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 1); *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData); break; } case 3: { *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 2); *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1); *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData); break; } case 4: { *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 3); *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData + 2); *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1); *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData); break; } } // SWITCH ( nNumLengthBytes ) #else // We are Big-Endian, so the length can be copied in from the source // as is. Ensure that we adjust for the number of bytes we actually // copy. memcpy( ( (unsigned char *) pnLength ) + ( 4 - nNumLengthBytes ), pbLengthData, nNumLengthBytes ); #endif // Account for the initial length byte *pnNumLengthBytes = nNumLengthBytes + 1; nReturn = SPNEGO_E_SUCCESS; } // IF Valid Length } // IF num bytes to read is within the boundary length } // IF xtended length else { // Extended bit is not set, so the length is in the value and the one // byte describes the length *pnLength = *pbLengthData & LEN_MASK; *pnNumLengthBytes = 1; nReturn = SPNEGO_E_SUCCESS; } LOG(("ASNDerGetLength returned %d\n",nReturn)); return nReturn;}///////////////////////////////////////////////////////////////////////////////// Function:// ASNDerCheckToken//// Parameters:// [in] pbTokenData - Token Data// [in] nToken - Token identifier to check for// [in] nLengthWithToken - Expected token length (with data)// [in] nBoundaryLength - Length that value must not exceed.// [out] pnLength - Filled out with data length// [out] pnTokenLength - Filled out with number of bytes // consumed by token identifier and length.//// Returns:// int Success - SPNEGO_E_SUCCESS// Failure - SPNEGO API Error code//// Comments :// Checks the data pointed to by pbTokenData for the specified token// identifier and the length that immediately follows. If// nLengthWithToken is > 0, the calculated length must match. The// length must also not exceed the specified boundary length .//////////////////////////////////////////////////////////////////////////////int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken, long nLengthWithToken, long nBoundaryLength, long* pnLength, long* pnTokenLength ){ int nReturn = SPNEGO_E_INVALID_LENGTH; long nNumLengthBytes = 0L; // Make sure that we've at least got 2 bytes of room to work with if ( nBoundaryLength >= 2 ) { // The first byte of the token data MUST match the specified token if ( *pbTokenData == nToken ) { // Next byte indicates the length pbTokenData++; // Get the length described by the token if ( ( nReturn = ASNDerGetLength( pbTokenData, nBoundaryLength, pnLength, &nNumLengthBytes ) ) == SPNEGO_E_SUCCESS ) { // Verify that the length is LESS THAN the boundary length // (this should prevent us walking out of our buffer) if ( ( nBoundaryLength - ( nNumLengthBytes + 1 ) < *pnLength ) ) { nReturn = SPNEGO_E_INVALID_LENGTH; } // If we were passed a length to check, do so now if ( nLengthWithToken > 0L ) { // Check that the expected length matches if ( ( nLengthWithToken - ( nNumLengthBytes + 1 ) ) != *pnLength ) { nReturn = SPNEGO_E_INVALID_LENGTH; } } // IF need to validate length if ( SPNEGO_E_SUCCESS == nReturn ) { *pnTokenLength = nNumLengthBytes + 1; } } // IF ASNDerGetLength } // IF token matches else { nReturn = SPNEGO_E_TOKEN_NOT_FOUND; } } // IF Boundary Length is at least 2 bytes LOG(("ASNDerCheckToken returned %d\n",nReturn)); return nReturn;}///////////////////////////////////////////////////////////////////////////////// Function:// ASNDerCheckOID//// Parameters:// [in] pbTokenData - Token Data// [in] nMechOID - OID we are looking for// [in] nBoundaryLength - Length that value must not exceed.// [out] pnTokenLength - Filled out with number of bytes// consumed by token and data.//// Returns:// int Success - SPNEGO_E_SUCCESS// Failure - SPNEGO API Error code//// Comments :// Checks the data pointed to by pbTokenData for the specified OID.//////////////////////////////////////////////////////////////////////////////int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength, long* pnTokenLength ){ int nReturn = 0L; long nLength = 0L; // Verify that we have an OID token if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, 0L, nBoundaryLength, &nLength, pnTokenLength ) ) == SPNEGO_E_SUCCESS ) { // Add the data length to the Token Length *pnTokenLength += nLength; // Token Lengths plus the actual length must match the length in our OID list element. // If it doesn't, we're done if ( *pnTokenLength == g_stcMechOIDList[nMechOID].iLen ) { // Memcompare the token and the expected field if ( memcmp( pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength ) != 0 ) { LOG(("ASNDerCheckOID memcmp failed\n")); nReturn = SPNEGO_E_UNEXPECTED_OID; } } else { LOG(("ASNDerCheckOID token length failed\n")); nReturn = SPNEGO_E_UNEXPECTED_OID; } } // IF OID Token CHecks LOG(("ASNDerCheckOID returned %d\n",nReturn)); return nReturn;}///////////////////////////////////////////////////////////////////////////////// Function:// ASNDerCalcNumLengthBytes//// Parameters:// [in] nLength - Length to calculate length bytes for.//// Returns:// int Number of bytes necessary to represent length//// Comments :// Helper function to calculate the number of length bytes necessary to// represent a length value. For our purposes, a 32-bit value should be// enough to describea length.//////////////////////////////////////////////////////////////////////////////int ASNDerCalcNumLengthBytes( long nLength ){ if ( nLength <= 0x7F ) { // A single byte will be sufficient for describing this length. // The byte will simply contain the length return 1; } else if ( nLength <= 0xFF ) { // Two bytes are necessary, one to say how many following bytes // describe the length, and one to give the length return 2; } else if ( nLength <= 0xFFFF ) { // Three bytes are necessary, one to say how many following bytes // describe the length, and two to give the length return 3; } else if ( nLength <= 0xFFFFFF ) { // Four bytes are necessary, one to say how many following bytes // describe the length, and three to give the length return 4; } else { // Five bytes are necessary, one to say how many following bytes // describe the length, and four to give the length return 5; }}///////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -