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