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