xref: /illumos-gate/usr/src/lib/libsmbfs/smb/derparse.c (revision 4bff34e37def8a90f9194d81bc345c52ba20086a)
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