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