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