1 // Copyright 2012 Nexenta Systems, Inc. All rights reserved.
2 // Copyright (C) 2002 Microsoft Corporation
3 // All rights reserved.
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.
12 // Author - Sanj Surati
14 /////////////////////////////////////////////////////////////
18 // SPNEGO Token Handler Source File
20 // Contains implementation of SPNEGO Token parsing functions.
22 /////////////////////////////////////////////////////////////
29 #include "spnegoparse.h"
32 // Defined in DERPARSE.C
35 extern MECH_OID g_stcMechOIDList
[];
37 /**********************************************************************/
42 /** Local SPNEGO Helper definitions **/
47 /**********************************************************************/
50 /////////////////////////////////////////////////////////////////////////////
53 // CalculateMinSpnegoInitTokenSize
56 // [in] nMechTokenLength - Length of the MechToken Element
57 // [in] nMechListMICLength - Length of the MechListMIC Element
58 // (or negHints, if no MechToken)
59 // [in] mechOID - OID for MechList
60 // [in] nReqFlagsAvailable - Is ContextFlags element available
61 // [out] pnTokenSize - Filled out with total size of token
62 // [out] pnInternalTokenLength - Filled out with length minus length
66 // int Success - SPNEGO_E_SUCCESS
67 // Failure - SPNEGO API Error code
70 // Calculates the required length for a SPNEGO NegTokenInit token based
71 // on the supplied variable length values and which elements are present.
72 // Note that because the lengths can be represented by an arbitrary
73 // number of bytes in DER encodings, we actually calculate the lengths
74 // backwards, so we always know how many bytes we will potentially be
77 ////////////////////////////////////////////////////////////////////////////
79 int CalculateMinSpnegoInitTokenSize( long nMechTokenLength
,
80 long nMechListMICLength
, SPNEGO_MECH_OID
*mechOidLst
, int mechOidCnt
,
81 int nReqFlagsAvailable
, long* pnTokenSize
,
82 long* pnInternalTokenLength
)
84 int nReturn
= SPNEGO_E_INVALID_LENGTH
;
87 long nTotalLength
= 0;
90 // We will calculate this by walking the token backwards
92 // Start with MIC Element (or negHints)
93 if ( nMechListMICLength
> 0L )
95 nTempLength
= ASNDerCalcElementLength( nMechListMICLength
, NULL
);
97 // Check for rollover error
98 if ( nTempLength
< nMechListMICLength
)
100 goto xEndTokenInitLength
;
103 nTotalLength
+= nTempLength
;
106 // Next is the MechToken
107 if ( nMechTokenLength
> 0L )
109 nTempLength
+= ASNDerCalcElementLength( nMechTokenLength
, NULL
);
111 // Check for rollover error
112 if ( nTempLength
< nTotalLength
)
114 goto xEndTokenInitLength
;
117 nTotalLength
= nTempLength
;
120 // Next is the ReqFlags
121 if ( nReqFlagsAvailable
)
123 nTempLength
+= ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS
, NULL
);
125 // Check for rollover error
126 if ( nTempLength
< nTotalLength
)
128 goto xEndTokenInitLength
;
131 nTotalLength
= nTempLength
;
134 // Next is the MechList - This is REQUIRED
135 nTempLength
+= ASNDerCalcMechListLength( mechOidLst
, mechOidCnt
, NULL
);
137 // Check for rollover error
138 if ( nTempLength
< nTotalLength
)
140 goto xEndTokenInitLength
;
143 nTotalLength
= nTempLength
;
145 // Following four fields are the basic header tokens
148 nTempLength
+= ASNDerCalcTokenLength( nTotalLength
, 0L );
150 // Check for rollover error
151 if ( nTempLength
< nTotalLength
)
153 goto xEndTokenInitLength
;
156 nTotalLength
= nTempLength
;
158 // Neg Token Identifier Token
159 nTempLength
+= ASNDerCalcTokenLength( nTotalLength
, 0L );
161 // Check for rollover error
162 if ( nTempLength
< nTotalLength
)
164 goto xEndTokenInitLength
;
167 nTotalLength
= nTempLength
;
170 nTempLength
+= g_stcMechOIDList
[spnego_mech_oid_Spnego
].iLen
;
172 // Check for rollover error
173 if ( nTempLength
< nTotalLength
)
175 goto xEndTokenInitLength
;
178 nTotalLength
= nTempLength
;
180 // App Constructed Token
181 nTempLength
+= ASNDerCalcTokenLength( nTotalLength
, 0L );
183 // Check for rollover error
184 if ( nTempLength
< nTotalLength
)
186 goto xEndTokenInitLength
;
189 // The internal length doesn't include the number of bytes
190 // for the initial token
191 *pnInternalTokenLength
= nTotalLength
;
192 nTotalLength
= nTempLength
;
195 *pnTokenSize
= nTotalLength
;
196 nReturn
= SPNEGO_E_SUCCESS
;
204 /////////////////////////////////////////////////////////////////////////////
207 // CreateSpnegoInitToken
210 // [in] pMechTypeList - OID array
211 // [in] MechTypeCnt - OID array length
212 // [in] ucContextFlags - ContextFlags value
213 // [in] pbMechToken - Mech Token Binary Data
214 // [in] ulMechTokenLen - Length of Mech Token
215 // [in] pbMechListMIC - MechListMIC Binary Data (or negHints)
216 // [in] ulMechListMICn - Length of MechListMIC
217 // [out] pbTokenData - Buffer to write token into.
218 // [in] nTokenLength - Length of pbTokenData buffer
219 // [in] nInternalTokenLength - Length of full token without leading
223 // int Success - SPNEGO_E_SUCCESS
224 // Failure - SPNEGO API Error code
227 // Uses DER to fill out pbTokenData with a SPNEGO NegTokenInit Token
228 // Note that because the lengths can be represented by an arbitrary
229 // number of bytes in DER encodings, we actually calculate the lengths
230 // backwards, so we always know how many bytes we will potentially be
233 // This function is also used to create an SPNEGO "hint", as described in
234 // [MS-SPNG] sec. 2.2.1 negTokenInit2. The "hint" looks almost identical
235 // to a NegTokenInit, but has a "negHints" field inserted before the MIC.
236 // A normal SPNEGO negTokenInit2 contains only the mech list and the
237 // negHints. To avoid a giant copy/paste of this function, we pass the
238 // negHints as the MIC arg, and pass NULL as the MechToken to indicate
239 // that we're creating a Hint rather than an Init, and use the correct
240 // type when writing out the MIC (or negHints) element.
242 ////////////////////////////////////////////////////////////////////////////
244 int CreateSpnegoInitToken( SPNEGO_MECH_OID
*pMechTypeList
, long MechTypeCnt
,
245 unsigned char ucContextFlags
, unsigned char* pbMechToken
,
246 unsigned long ulMechTokenLen
, unsigned char* pbMechListMIC
,
247 unsigned long ulMechListMICLen
, unsigned char* pbTokenData
,
248 long nTokenLength
, long nInternalTokenLength
)
250 int nReturn
= SPNEGO_E_INVALID_LENGTH
;
253 long nTempLength
= 0L;
254 long nTotalBytesWritten
= 0L;
255 long nInternalLength
= 0L;
257 unsigned char* pbWriteTokenData
= pbTokenData
+ nTokenLength
;
259 // Temporary buffer to hold the REQ Flags as BIT String Data
260 unsigned char abTempReqFlags
[SPNEGO_NEGINIT_MAXLEN_REQFLAGS
];
263 // We will write the token out backwards to properly handle the cases
264 // where the length bytes become adjustable
266 // Start with MIC Element (or negHints)
267 if ( ulMechListMICLen
> 0L )
269 unsigned char ucType
;
270 nTempLength
= ASNDerCalcElementLength( ulMechListMICLen
, &nInternalLength
);
272 // Decrease the pbWriteTokenData, now we know the length and write it out.
273 // Note: When MechTokenLen == 0, we're writing a negTokenInit2 and the
274 // MIC arg is really negHints, written as a constructed sequence.
275 // Otherwise we're writing a negTokenInit, and the MIC is an OCTETSTRING.
276 ucType
= (ulMechTokenLen
== 0) ?
277 SPNEGO_CONSTRUCTED_SEQUENCE
: OCTETSTRING
;
279 pbWriteTokenData
-= nTempLength
;
280 nTempLength
= ASNDerWriteElement( pbWriteTokenData
, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC
,
281 ucType
, pbMechListMIC
, ulMechListMICLen
);
283 // Adjust Values and sanity check
284 nTotalBytesWritten
+= nTempLength
;
285 nInternalTokenLength
-= nTempLength
;
287 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
289 goto xEndWriteNegTokenInit
;
292 } // IF MechListMIC is present
294 // Next is the MechToken
295 if ( ulMechTokenLen
> 0L )
297 nTempLength
= ASNDerCalcElementLength( ulMechTokenLen
, &nInternalLength
);
299 // Decrease the pbWriteTokenData, now we know the length and
301 pbWriteTokenData
-= nTempLength
;
302 nTempLength
= ASNDerWriteElement( pbWriteTokenData
, SPNEGO_NEGINIT_ELEMENT_MECHTOKEN
,
303 OCTETSTRING
, pbMechToken
, ulMechTokenLen
);
304 // Adjust Values and sanity check
305 nTotalBytesWritten
+= nTempLength
;
306 nInternalTokenLength
-= nTempLength
;
308 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
310 goto xEndWriteNegTokenInit
;
313 } // IF MechToken Length is present
315 // Next is the ReqFlags
316 if ( ucContextFlags
> 0L )
319 nTempLength
= ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS
, &nInternalLength
);
321 // We need a byte that indicates how many bits difference between the number
322 // of bits used in final octet (we only have one) and the max (8)
324 abTempReqFlags
[0] = SPNEGO_NEGINIT_REQFLAGS_BITDIFF
;
325 abTempReqFlags
[1] = ucContextFlags
;
327 // Decrease the pbWriteTokenData, now we know the length and
329 pbWriteTokenData
-= nTempLength
;
330 nTempLength
= ASNDerWriteElement( pbWriteTokenData
, SPNEGO_NEGINIT_ELEMENT_REQFLAGS
,
331 BITSTRING
, abTempReqFlags
, SPNEGO_NEGINIT_MAXLEN_REQFLAGS
);
333 // Adjust Values and sanity check
334 nTotalBytesWritten
+= nTempLength
;
335 nInternalTokenLength
-= nTempLength
;
337 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
339 goto xEndWriteNegTokenInit
;
344 // Next is the MechList - This is REQUIRED
345 nTempLength
= ASNDerCalcMechListLength( pMechTypeList
, MechTypeCnt
, &nInternalLength
);
347 // Decrease the pbWriteTokenData, now we know the length and
349 pbWriteTokenData
-= nTempLength
;
350 nTempLength
= ASNDerWriteMechList( pbWriteTokenData
, pMechTypeList
, MechTypeCnt
);
352 // Adjust Values and sanity check
353 nTotalBytesWritten
+= nTempLength
;
354 nInternalTokenLength
-= nTempLength
;
356 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
358 goto xEndWriteNegTokenInit
;
361 // The next tokens we're writing out reflect the total number of bytes
362 // we have actually written out.
365 nTempLength
= ASNDerCalcTokenLength( nTotalBytesWritten
, 0L );
367 // Decrease the pbWriteTokenData, now we know the length and
369 pbWriteTokenData
-= nTempLength
;
370 nTempLength
= ASNDerWriteToken( pbWriteTokenData
, SPNEGO_CONSTRUCTED_SEQUENCE
,
371 NULL
, nTotalBytesWritten
);
373 // Adjust Values and sanity check
374 nTotalBytesWritten
+= nTempLength
;
375 nInternalTokenLength
-= nTempLength
;
377 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
379 goto xEndWriteNegTokenInit
;
382 // Neg Init Token Identifier Token
383 nTempLength
= ASNDerCalcTokenLength( nTotalBytesWritten
, 0L );
385 // Decrease the pbWriteTokenData, now we know the length and
387 pbWriteTokenData
-= nTempLength
;
388 nTempLength
= ASNDerWriteToken( pbWriteTokenData
, SPNEGO_NEGINIT_TOKEN_IDENTIFIER
,
389 NULL
, nTotalBytesWritten
);
391 // Adjust Values and sanity check
392 nTotalBytesWritten
+= nTempLength
;
393 nInternalTokenLength
-= nTempLength
;
395 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
397 goto xEndWriteNegTokenInit
;
401 nTempLength
= g_stcMechOIDList
[spnego_mech_oid_Spnego
].iLen
;
403 // Decrease the pbWriteTokenData, now we know the length and
405 pbWriteTokenData
-= nTempLength
;
406 nTempLength
= ASNDerWriteOID( pbWriteTokenData
, spnego_mech_oid_Spnego
);
408 // Adjust Values and sanity check
409 nTotalBytesWritten
+= nTempLength
;
410 nInternalTokenLength
-= nTempLength
;
412 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
414 goto xEndWriteNegTokenInit
;
417 // App Constructed Token
418 nTempLength
= ASNDerCalcTokenLength( nTotalBytesWritten
, 0L );
420 // Decrease the pbWriteTokenData, now we know the length and
422 pbWriteTokenData
-= nTempLength
;
423 nTempLength
= ASNDerWriteToken( pbWriteTokenData
, SPNEGO_NEGINIT_APP_CONSTRUCT
,
424 NULL
, nTotalBytesWritten
);
426 // Adjust Values and sanity check
427 nTotalBytesWritten
+= nTempLength
;
429 // Don't adjust the internal token length here, it doesn't account
430 // the initial bytes written out (we really don't need to keep
431 // a running count here, but for debugging, it helps to be able
432 // to see the total number of bytes written out as well as the
433 // number of bytes left to write).
435 if ( nTotalBytesWritten
== nTokenLength
&& nInternalTokenLength
== 0 &&
436 pbWriteTokenData
== pbTokenData
)
438 nReturn
= SPNEGO_E_SUCCESS
;
441 xEndWriteNegTokenInit
:
447 /////////////////////////////////////////////////////////////////////////////
450 // CalculateMinSpnegoTargTokenSize
453 // [in] MechType - Supported MechType
454 // [in] spnegoNegResult - Neg Result
455 // [in] nMechTokenLength - Length of the MechToken Element
456 // [in] nMechListMICLength - Length of the MechListMIC Element
457 // [out] pnTokenSize - Filled out with total size of token
458 // [out] pnInternalTokenLength - Filled out with length minus length
459 // for initial token.
462 // int Success - SPNEGO_E_SUCCESS
463 // Failure - SPNEGO API Error code
466 // Calculates the required length for a SPNEGO NegTokenTarg token based
467 // on the supplied variable length values and which elements are present.
468 // Note that because the lengths can be represented by an arbitrary
469 // number of bytes in DER encodings, we actually calculate the lengths
470 // backwards, so we always know how many bytes we will potentially be
473 ////////////////////////////////////////////////////////////////////////////
475 int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType
,
476 SPNEGO_NEGRESULT spnegoNegResult
, long nMechTokenLen
,
477 long nMechListMICLen
, long* pnTokenSize
,
478 long* pnInternalTokenLength
)
480 int nReturn
= SPNEGO_E_INVALID_LENGTH
;
483 long nTotalLength
= 0;
484 long nTempLength
= 0L;
486 // We will calculate this by walking the token backwards
488 // Start with MIC Element
489 if ( nMechListMICLen
> 0L )
491 nTempLength
= ASNDerCalcElementLength( nMechListMICLen
, NULL
);
493 // Check for rollover error
494 if ( nTempLength
< nMechListMICLen
)
496 goto xEndTokenTargLength
;
499 nTotalLength
+= nTempLength
;
502 // Next is the MechToken
503 if ( nMechTokenLen
> 0L )
505 nTempLength
+= ASNDerCalcElementLength( nMechTokenLen
, NULL
);
507 // Check for rollover error
508 if ( nTempLength
< nTotalLength
)
510 goto xEndTokenTargLength
;
513 nTotalLength
= nTempLength
;
516 // Supported MechType
517 if ( spnego_mech_oid_NotUsed
!= MechType
)
519 // Supported MechOID element - we use the token function since
520 // we already know the size of the OID token and value
521 nTempLength
+= ASNDerCalcElementLength( g_stcMechOIDList
[MechType
].iActualDataLen
,
524 // Check for rollover error
525 if ( nTempLength
< nTotalLength
)
527 goto xEndTokenTargLength
;
530 nTotalLength
= nTempLength
;
532 } // IF MechType is available
535 if ( spnego_negresult_NotUsed
!= spnegoNegResult
)
537 nTempLength
+= ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT
, NULL
);
539 // Check for rollover error
540 if ( nTempLength
< nTotalLength
)
542 goto xEndTokenTargLength
;
545 nTotalLength
= nTempLength
;
547 } // IF negResult is available
549 // Following two fields are the basic header tokens
552 nTempLength
+= ASNDerCalcTokenLength( nTotalLength
, 0L );
554 // Check for rollover error
555 if ( nTempLength
< nTotalLength
)
557 goto xEndTokenTargLength
;
560 nTotalLength
= nTempLength
;
562 // Neg Token Identifier Token
563 nTempLength
+= ASNDerCalcTokenLength( nTotalLength
, 0L );
565 // Check for rollover error
566 if ( nTempLength
< nTotalLength
)
568 goto xEndTokenTargLength
;
571 // The internal length doesn't include the number of bytes
572 // for the initial token
573 *pnInternalTokenLength
= nTotalLength
;
574 nTotalLength
= nTempLength
;
577 *pnTokenSize
= nTotalLength
;
578 nReturn
= SPNEGO_E_SUCCESS
;
586 /////////////////////////////////////////////////////////////////////////////
589 // CreateSpnegoTargToken
592 // [in] MechType - Supported MechType
593 // [in] eNegResult - NegResult value
594 // [in] pbMechToken - Mech Token Binary Data
595 // [in] ulMechTokenLen - Length of Mech Token
596 // [in] pbMechListMIC - MechListMIC Binary Data
597 // [in] ulMechListMICn - Length of MechListMIC
598 // [out] pbTokenData - Buffer to write token into.
599 // [in] nTokenLength - Length of pbTokenData buffer
600 // [in] nInternalTokenLength - Length of full token without leading
604 // int Success - SPNEGO_E_SUCCESS
605 // Failure - SPNEGO API Error code
608 // Uses DER to fill out pbTokenData with a SPNEGO NegTokenTarg Token
609 // Note that because the lengths can be represented by an arbitrary
610 // number of bytes in DER encodings, we actually calculate the lengths
611 // backwards, so we always know how many bytes we will potentially be
614 ////////////////////////////////////////////////////////////////////////////
616 int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType
,
617 SPNEGO_NEGRESULT eNegResult
, unsigned char* pbMechToken
,
618 unsigned long ulMechTokenLen
, unsigned char* pbMechListMIC
,
619 unsigned long ulMechListMICLen
, unsigned char* pbTokenData
,
620 long nTokenLength
, long nInternalTokenLength
)
622 int nReturn
= SPNEGO_E_INVALID_LENGTH
;
625 long nTempLength
= 0L;
626 long nTotalBytesWritten
= 0L;
627 long nInternalLength
= 0L;
629 unsigned char ucTemp
= 0;
631 // We will write the token out backwards to properly handle the cases
632 // where the length bytes become adjustable, so the write location
633 // is initialized to point *just* past the end of the buffer.
635 unsigned char* pbWriteTokenData
= pbTokenData
+ nTokenLength
;
638 // Start with MIC Element
639 if ( ulMechListMICLen
> 0L )
641 nTempLength
= ASNDerCalcElementLength( ulMechListMICLen
, &nInternalLength
);
643 // Decrease the pbWriteTokenData, now we know the length and
646 pbWriteTokenData
-= nTempLength
;
647 nTempLength
= ASNDerWriteElement( pbWriteTokenData
, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC
,
648 OCTETSTRING
, pbMechListMIC
, ulMechListMICLen
);
650 // Adjust Values and sanity check
651 nTotalBytesWritten
+= nTempLength
;
652 nInternalTokenLength
-= nTempLength
;
654 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
656 goto xEndWriteNegTokenTarg
;
659 } // IF MechListMIC is present
661 // Next is the MechToken
662 if ( ulMechTokenLen
> 0L )
664 nTempLength
= ASNDerCalcElementLength( ulMechTokenLen
, &nInternalLength
);
666 // Decrease the pbWriteTokenData, now we know the length and
668 pbWriteTokenData
-= nTempLength
;
669 nTempLength
= ASNDerWriteElement( pbWriteTokenData
, SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN
,
670 OCTETSTRING
, pbMechToken
, ulMechTokenLen
);
671 // Adjust Values and sanity check
672 nTotalBytesWritten
+= nTempLength
;
673 nInternalTokenLength
-= nTempLength
;
675 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
677 goto xEndWriteNegTokenTarg
;
680 } // IF MechToken Length is present
682 // Supported Mech Type
683 if ( spnego_mech_oid_NotUsed
!= MechType
)
686 nTempLength
= ASNDerCalcElementLength( g_stcMechOIDList
[MechType
].iActualDataLen
,
689 // Decrease the pbWriteTokenData, now we know the length and
691 pbWriteTokenData
-= nTempLength
;
692 nTempLength
= ASNDerWriteToken( pbWriteTokenData
, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH
,
693 g_stcMechOIDList
[MechType
].ucOid
,
694 g_stcMechOIDList
[MechType
].iLen
);
696 // Adjust Values and sanity check
697 nTotalBytesWritten
+= nTempLength
;
698 nInternalTokenLength
-= nTempLength
;
700 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
702 goto xEndWriteNegTokenTarg
;
705 } // IF MechType is present
709 if ( spnego_negresult_NotUsed
!= eNegResult
)
711 ucTemp
= (unsigned char) eNegResult
;
713 nTempLength
= ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT
, &nInternalLength
);
715 // Decrease the pbWriteTokenData, now we know the length and
717 pbWriteTokenData
-= nTempLength
;
718 nTempLength
= ASNDerWriteElement( pbWriteTokenData
, SPNEGO_NEGTARG_ELEMENT_NEGRESULT
,
719 ENUMERATED
, &ucTemp
, SPNEGO_NEGTARG_MAXLEN_NEGRESULT
);
721 // Adjust Values and sanity check
722 nTotalBytesWritten
+= nTempLength
;
723 nInternalTokenLength
-= nTempLength
;
725 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
727 goto xEndWriteNegTokenTarg
;
730 } // If eNegResult is available
732 // The next tokens we're writing out reflect the total number of bytes
733 // we have actually written out.
736 nTempLength
= ASNDerCalcTokenLength( nTotalBytesWritten
, 0L );
738 // Decrease the pbWriteTokenData, now we know the length and
740 pbWriteTokenData
-= nTempLength
;
741 nTempLength
= ASNDerWriteToken( pbWriteTokenData
, SPNEGO_CONSTRUCTED_SEQUENCE
,
742 NULL
, nTotalBytesWritten
);
744 // Adjust Values and sanity check
745 nTotalBytesWritten
+= nTempLength
;
746 nInternalTokenLength
-= nTempLength
;
748 if ( nTotalBytesWritten
> nTokenLength
|| nInternalTokenLength
< 0 )
750 goto xEndWriteNegTokenTarg
;
753 // Neg Targ Token Identifier Token
754 nTempLength
= ASNDerCalcTokenLength( nTotalBytesWritten
, 0L );
756 // Decrease the pbWriteTokenData, now we know the length and
758 pbWriteTokenData
-= nTempLength
;
759 nTempLength
= ASNDerWriteToken( pbWriteTokenData
, SPNEGO_NEGTARG_TOKEN_IDENTIFIER
,
760 NULL
, nTotalBytesWritten
);
762 // Adjust Values and sanity check
763 nTotalBytesWritten
+= nTempLength
;
765 // Don't adjust the internal token length here, it doesn't account
766 // the initial bytes written out (we really don't need to keep
767 // a running count here, but for debugging, it helps to be able
768 // to see the total number of bytes written out as well as the
769 // number of bytes left to write).
771 if ( nTotalBytesWritten
== nTokenLength
&& nInternalTokenLength
== 0 &&
772 pbWriteTokenData
== pbTokenData
)
774 nReturn
= SPNEGO_E_SUCCESS
;
778 xEndWriteNegTokenTarg
:
786 /////////////////////////////////////////////////////////////////////////////
789 // AllocEmptySpnegoToken
792 // [in] ucCopyData - Flag to copy data or pointer.
793 // [in] ulFlags - Flags for SPNEGO_TOKEN data member.
794 // [in] pbTokenData - Binary token data.
795 // [in] ulTokenSize - Size of pbTokenData.
798 // SPNEGO_TOKEN* Success - Pointer to initialized SPNEGO_TOKEN struct
802 // Allocates a SPNEGO_TOKEN data structure and initializes it. Based on
803 // the value of ucCopyData, if non-zero, we copy the data into a buffer
804 // we allocate in this function, otherwise, we copy the data pointer
807 ////////////////////////////////////////////////////////////////////////////
809 SPNEGO_TOKEN
* AllocEmptySpnegoToken( unsigned char ucCopyData
, unsigned long ulFlags
,
810 unsigned char * pbTokenData
, unsigned long ulTokenSize
)
812 SPNEGO_TOKEN
* pSpnegoToken
= (SPNEGO_TOKEN
*) calloc( 1, sizeof(SPNEGO_TOKEN
) );
814 if ( NULL
!= pSpnegoToken
)
816 // Set the token size
817 pSpnegoToken
->nStructSize
= SPNEGO_TOKEN_SIZE
;
819 // Initialize the element array
820 InitSpnegoTokenElementArray( pSpnegoToken
);
822 // Assign the flags value
823 pSpnegoToken
->ulFlags
= ulFlags
;
826 // IF ucCopyData is TRUE, we will allocate a buffer and copy data into it.
827 // Otherwise, we will just copy the pointer and the length. This is so we
828 // can cut out additional allocations for performance reasons
831 if ( SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA
== ucCopyData
)
833 // Alloc the internal buffer. Cleanup on failure.
834 pSpnegoToken
->pbBinaryData
= (unsigned char*) calloc( ulTokenSize
, sizeof(unsigned char) );
836 if ( NULL
!= pSpnegoToken
->pbBinaryData
)
838 // We must ALWAYS free this buffer
839 pSpnegoToken
->ulFlags
|= SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA
;
841 // Copy the data locally
842 memcpy( pSpnegoToken
->pbBinaryData
, pbTokenData
, ulTokenSize
);
843 pSpnegoToken
->ulBinaryDataLen
= ulTokenSize
;
847 free( pSpnegoToken
);
854 // Copy the pointer and the length directly - ulFlags will control whether or not
855 // we are allowed to free the value
857 pSpnegoToken
->pbBinaryData
= pbTokenData
;
858 pSpnegoToken
->ulBinaryDataLen
= ulTokenSize
;
866 /////////////////////////////////////////////////////////////////////////////
872 // [in] pSpnegoToken - Points to SPNEGO_TOKEN to free.
878 // If non-NULL, interprets pSpnegoToken, freeing any internal allocations
879 // and finally the actual structure.
881 ////////////////////////////////////////////////////////////////////////////
883 void FreeSpnegoToken( SPNEGO_TOKEN
* pSpnegoToken
)
885 if ( NULL
!= pSpnegoToken
)
888 // Cleanup internal allocation per the flags
889 if ( pSpnegoToken
->ulFlags
& SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA
&&
890 NULL
!= pSpnegoToken
->pbBinaryData
)
892 free( pSpnegoToken
->pbBinaryData
);
893 pSpnegoToken
->pbBinaryData
= NULL
;
896 free ( pSpnegoToken
);
900 /////////////////////////////////////////////////////////////////////////////
903 // InitSpnegoTokenElementArray
906 // [in] pSpnegoToken - Points to SPNEGO_TOKEN structure.
912 // Initializes the element array data member of a SPNEGO_TOKEN data
915 ////////////////////////////////////////////////////////////////////////////
917 void InitSpnegoTokenElementArray( SPNEGO_TOKEN
* pSpnegoToken
)
921 // Set the number of elemnts
922 pSpnegoToken
->nNumElements
= MAX_NUM_TOKEN_ELEMENTS
;
925 // Initially, all elements are unavailable
928 for ( nCtr
= 0; nCtr
< MAX_NUM_TOKEN_ELEMENTS
; nCtr
++ )
930 // Set the element size as well
931 pSpnegoToken
->aElementArray
[ nCtr
].nStructSize
= SPNEGO_ELEMENT_SIZE
;
932 pSpnegoToken
->aElementArray
[ nCtr
].iElementPresent
= SPNEGO_TOKEN_ELEMENT_UNAVAILABLE
;
937 /////////////////////////////////////////////////////////////////////////////
940 // InitSpnegoTokenType
943 // [in] pSpnegoToken - Points to SPNEGO_TOKEN structure.
944 // [out] pnTokenLength - Filled out with total token length
945 // [out] pnRemainingTokenLength - Filled out with remaining length
946 // after header is parsed
947 // [out] ppbFirstElement - Filled out with pointer to first
948 // element after header info.
951 // int Success - SPNEGO_E_SUCCESS
952 // Failure - SPNEGO API Error code
955 // Walks the underlying binary data for a SPNEGO_TOKEN data structure
956 // and determines the type of the underlying token based on token header
959 ////////////////////////////////////////////////////////////////////////////
961 int InitSpnegoTokenType( SPNEGO_TOKEN
* pSpnegoToken
, long* pnTokenLength
,
962 long* pnRemainingTokenLength
, unsigned char** ppbFirstElement
)
964 int nReturn
= SPNEGO_E_INVALID_TOKEN
;
965 long nActualTokenLength
= 0L;
966 long nBoundaryLength
= pSpnegoToken
->ulBinaryDataLen
;
967 unsigned char* pbTokenData
= pSpnegoToken
->pbBinaryData
;
970 // First byte MUST be either an APP_CONSTRUCT or the NEGTARG_TOKEN_TARG
973 if ( SPNEGO_NEGINIT_APP_CONSTRUCT
== *pbTokenData
)
975 // Validate the above token - this will tell us the actual length of the token
976 // per the encoding (minus the actual token bytes)
977 if ( ( nReturn
= ASNDerCheckToken( pbTokenData
, SPNEGO_NEGINIT_APP_CONSTRUCT
, 0L, nBoundaryLength
,
978 pnTokenLength
, &nActualTokenLength
) )
979 == SPNEGO_E_SUCCESS
)
981 // Initialize the remaining token length value. This will be used
982 // to tell the caller how much token there is left once we've parsed
983 // the header (they could calculate it from the other values, but this
984 // is a bit friendlier)
985 *pnRemainingTokenLength
= *pnTokenLength
;
987 // Make adjustments to next token
988 pbTokenData
+= nActualTokenLength
;
989 nBoundaryLength
-= nActualTokenLength
;
991 // The next token should be an OID
992 if ( ( nReturn
= ASNDerCheckOID( pbTokenData
, spnego_mech_oid_Spnego
, nBoundaryLength
,
993 &nActualTokenLength
) ) == SPNEGO_E_SUCCESS
)
995 // Make adjustments to next token
996 pbTokenData
+= nActualTokenLength
;
997 nBoundaryLength
-= nActualTokenLength
;
998 *pnRemainingTokenLength
-= nActualTokenLength
;
1000 // The next token should specify the NegTokenInit
1001 if ( ( nReturn
= ASNDerCheckToken( pbTokenData
, SPNEGO_NEGINIT_TOKEN_IDENTIFIER
,
1002 *pnRemainingTokenLength
, nBoundaryLength
, pnTokenLength
,
1003 &nActualTokenLength
) )
1004 == SPNEGO_E_SUCCESS
)
1006 // Make adjustments to next token
1007 pbTokenData
+= nActualTokenLength
;
1008 nBoundaryLength
-= nActualTokenLength
;
1009 *pnRemainingTokenLength
-= nActualTokenLength
;
1011 // The next token should specify the start of a sequence
1012 if ( ( nReturn
= ASNDerCheckToken( pbTokenData
, SPNEGO_CONSTRUCTED_SEQUENCE
,
1013 *pnRemainingTokenLength
, nBoundaryLength
, pnTokenLength
,
1014 &nActualTokenLength
) )
1015 == SPNEGO_E_SUCCESS
)
1017 // NegTokenInit header is now checked out!
1019 // Make adjustments to next token
1020 *pnRemainingTokenLength
-= nActualTokenLength
;
1022 // Store pointer to first element
1023 *ppbFirstElement
= pbTokenData
+ nActualTokenLength
;
1024 pSpnegoToken
->ucTokenType
= SPNEGO_TOKEN_INIT
;
1025 } // IF Check Sequence Token
1027 } // IF Check NegTokenInit token
1030 } // IF Check for SPNEGO OID
1033 } // IF check app construct token
1036 else if ( SPNEGO_NEGTARG_TOKEN_IDENTIFIER
== *pbTokenData
)
1039 // The next token should specify the NegTokenInit
1040 if ( ( nReturn
= ASNDerCheckToken( pbTokenData
, SPNEGO_NEGTARG_TOKEN_IDENTIFIER
,
1041 *pnRemainingTokenLength
, nBoundaryLength
, pnTokenLength
,
1042 &nActualTokenLength
) )
1043 == SPNEGO_E_SUCCESS
)
1045 // Initialize the remaining token length value. This will be used
1046 // to tell the caller how much token there is left once we've parsed
1047 // the header (they could calculate it from the other values, but this
1048 // is a bit friendlier)
1049 *pnRemainingTokenLength
= *pnTokenLength
;
1051 // Make adjustments to next token
1052 pbTokenData
+= nActualTokenLength
;
1053 nBoundaryLength
-= nActualTokenLength
;
1055 // The next token should specify the start of a sequence
1056 if ( ( nReturn
= ASNDerCheckToken( pbTokenData
, SPNEGO_CONSTRUCTED_SEQUENCE
,
1057 *pnRemainingTokenLength
, nBoundaryLength
, pnTokenLength
,
1058 &nActualTokenLength
) )
1059 == SPNEGO_E_SUCCESS
)
1061 // NegTokenInit header is now checked out!
1063 // Make adjustments to next token
1064 *pnRemainingTokenLength
-= nActualTokenLength
;
1066 // Store pointer to first element
1067 *ppbFirstElement
= pbTokenData
+ nActualTokenLength
;
1068 pSpnegoToken
->ucTokenType
= SPNEGO_TOKEN_TARG
;
1069 } // IF Check Sequence Token
1071 } // IF Check NegTokenInit token
1073 } // ELSE IF it's a NegTokenTarg
1079 /////////////////////////////////////////////////////////////////////////////
1082 // GetSpnegoInitTokenMechList
1085 // [in] pbTokenData - Points to binary MechList element
1087 // [in] nMechListLength - Length of the MechList
1088 // [out] pSpnegoElement - Filled out with MechList Element
1092 // int Success - SPNEGO_E_SUCCESS
1093 // Failure - SPNEGO API Error code
1096 // Checks that pbTokenData is pointing at something that at least
1097 // *looks* like a MechList and then fills out the supplied
1098 // SPNEGO_ELEMENT structure.
1100 ////////////////////////////////////////////////////////////////////////////
1102 int GetSpnegoInitTokenMechList( unsigned char* pbTokenData
, int nMechListLength
,
1103 SPNEGO_ELEMENT
* pSpnegoElement
)
1105 int nReturn
= SPNEGO_E_INVALID_TOKEN
;
1107 long nActualTokenLength
= 0L;
1109 // Actual MechList is prepended by a Constructed Sequence Token
1110 if ( ( nReturn
= ASNDerCheckToken( pbTokenData
, SPNEGO_CONSTRUCTED_SEQUENCE
,
1111 nMechListLength
, nMechListLength
,
1112 &nLength
, &nActualTokenLength
) )
1113 == SPNEGO_E_SUCCESS
)
1115 // Adjust for this token
1116 nMechListLength
-= nActualTokenLength
;
1117 pbTokenData
+= nActualTokenLength
;
1119 // Perform simple validation of the actual MechList (i.e. ensure that
1120 // the OIDs in the MechList are reasonable).
1122 if ( ( nReturn
= ValidateMechList( pbTokenData
, nLength
) ) == SPNEGO_E_SUCCESS
)
1124 // Initialize the element now
1125 pSpnegoElement
->eElementType
= spnego_init_mechtypes
;
1126 pSpnegoElement
->iElementPresent
= SPNEGO_TOKEN_ELEMENT_AVAILABLE
;
1127 pSpnegoElement
->type
= SPNEGO_MECHLIST_TYPE
;
1128 pSpnegoElement
->nDatalength
= nLength
;
1129 pSpnegoElement
->pbData
= pbTokenData
;
1137 /////////////////////////////////////////////////////////////////////////////
1140 // InitSpnegoTokenElementFromBasicType
1143 // [in] pbTokenData - Points to binary element data in
1145 // [in] nElementLength - Length of the element
1146 // [in] ucExpectedType - Expected DER type.
1147 // [in] spnegoElementType - Which element is this?
1148 // [out] pSpnegoElement - Filled out with element data.
1151 // int Success - SPNEGO_E_SUCCESS
1152 // Failure - SPNEGO API Error code
1155 // Checks that pbTokenData is pointing at the specified DER type. If so,
1156 // then we verify that lengths are proper and then fill out the
1157 // SPNEGO_ELEMENT data structure.
1159 ////////////////////////////////////////////////////////////////////////////
1161 int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData
, int nElementLength
,
1162 unsigned char ucExpectedType
,
1163 SPNEGO_ELEMENT_TYPE spnegoElementType
,
1164 SPNEGO_ELEMENT
* pSpnegoElement
)
1166 int nReturn
= SPNEGO_E_UNEXPECTED_TYPE
;
1168 long nActualTokenLength
= 0L;
1170 // The type BYTE must match our token data or something is badly wrong
1171 if ( *pbTokenData
== ucExpectedType
)
1174 // Check that we are pointing at the specified type
1175 if ( ( nReturn
= ASNDerCheckToken( pbTokenData
, ucExpectedType
,
1176 nElementLength
, nElementLength
,
1177 &nLength
, &nActualTokenLength
) )
1178 == SPNEGO_E_SUCCESS
)
1180 // Adjust for this token
1181 nElementLength
-= nActualTokenLength
;
1182 pbTokenData
+= nActualTokenLength
;
1184 // Initialize the element now
1185 pSpnegoElement
->eElementType
= spnegoElementType
;
1186 pSpnegoElement
->iElementPresent
= SPNEGO_TOKEN_ELEMENT_AVAILABLE
;
1187 pSpnegoElement
->type
= ucExpectedType
;
1188 pSpnegoElement
->nDatalength
= nLength
;
1189 pSpnegoElement
->pbData
= pbTokenData
;
1192 } // IF type makes sense
1198 /////////////////////////////////////////////////////////////////////////////
1201 // InitSpnegoTokenElementFromOID
1204 // [in] pbTokenData - Points to binary element data in
1206 // [in] nElementLength - Length of the element
1207 // [in] spnegoElementType - Which element is this?
1208 // [out] pSpnegoElement - Filled out with element data.
1211 // int Success - SPNEGO_E_SUCCESS
1212 // Failure - SPNEGO API Error code
1215 // Initializes a SpnegoElement from an OID - normally, this would have
1216 // used the Basic Type function above, but since we do binary compares
1217 // on the OIDs against the DER information as well as the OID, we need
1218 // to account for that.
1220 ////////////////////////////////////////////////////////////////////////////
1222 int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData
, int nElementLength
,
1223 SPNEGO_ELEMENT_TYPE spnegoElementType
,
1224 SPNEGO_ELEMENT
* pSpnegoElement
)
1226 int nReturn
= SPNEGO_E_UNEXPECTED_TYPE
;
1228 long nActualTokenLength
= 0L;
1230 // The type BYTE must match our token data or something is badly wrong
1231 if ( *pbTokenData
== OID
)
1234 // Check that we are pointing at an OID type
1235 if ( ( nReturn
= ASNDerCheckToken( pbTokenData
, OID
,
1236 nElementLength
, nElementLength
,
1237 &nLength
, &nActualTokenLength
) )
1238 == SPNEGO_E_SUCCESS
)
1240 // Don't adjust any values for this function
1242 // Initialize the element now
1243 pSpnegoElement
->eElementType
= spnegoElementType
;
1244 pSpnegoElement
->iElementPresent
= SPNEGO_TOKEN_ELEMENT_AVAILABLE
;
1245 pSpnegoElement
->type
= OID
;
1246 pSpnegoElement
->nDatalength
= nElementLength
;
1247 pSpnegoElement
->pbData
= pbTokenData
;
1250 } // IF type makes sense
1256 /////////////////////////////////////////////////////////////////////////////
1259 // InitSpnegoTokenElements
1262 // [in] pSpnegoToken - Points to SPNEGO_TOKEN struct
1263 // [in] pbTokenData - Points to initial binary element
1264 // data in a SPNEGO token.
1265 // [in] nRemainingTokenLength - Length remaining past header
1268 // int Success - SPNEGO_E_SUCCESS
1269 // Failure - SPNEGO API Error code
1272 // Interprets the data at pbTokenData based on the TokenType in
1273 // pSpnegoToken. Since some elements are optional (technically all are
1274 // but the token becomes quite useless if this is so), we check if
1275 // an element exists before filling out the element in the array.
1277 ////////////////////////////////////////////////////////////////////////////
1279 int InitSpnegoTokenElements( SPNEGO_TOKEN
* pSpnegoToken
, unsigned char* pbTokenData
,
1280 long nRemainingTokenLength
)
1283 // The following arrays contain the token identifiers for the elements
1284 // comprising the actual token. All values are optional, and there are
1288 static unsigned char abNegTokenInitElements
[] =
1289 { SPNEGO_NEGINIT_ELEMENT_MECHTYPES
, SPNEGO_NEGINIT_ELEMENT_REQFLAGS
,
1290 SPNEGO_NEGINIT_ELEMENT_MECHTOKEN
, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC
};
1292 static unsigned char abNegTokenTargElements
[] =
1293 { SPNEGO_NEGTARG_ELEMENT_NEGRESULT
, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH
,
1294 SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN
, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC
};
1296 int nReturn
= SPNEGO_E_SUCCESS
;
1298 long nElementLength
= 0L;
1299 long nActualTokenLength
= 0L;
1300 unsigned char* pbElements
= NULL
;
1302 // Point to the correct array
1303 switch( pSpnegoToken
->ucTokenType
)
1305 case SPNEGO_TOKEN_INIT
:
1307 pbElements
= abNegTokenInitElements
;
1311 case SPNEGO_TOKEN_TARG
:
1313 pbElements
= abNegTokenTargElements
;
1317 } // SWITCH tokentype
1320 // Enumerate the element arrays and look for the tokens at our current location
1324 SPNEGO_E_SUCCESS
== nReturn
&&
1325 nCtr
< MAX_NUM_TOKEN_ELEMENTS
&&
1326 nRemainingTokenLength
> 0L;
1330 // Check if the token exists
1331 if ( ( nReturn
= ASNDerCheckToken( pbTokenData
, pbElements
[nCtr
],
1332 0L, nRemainingTokenLength
,
1333 &nElementLength
, &nActualTokenLength
) )
1334 == SPNEGO_E_SUCCESS
)
1337 // Token data should skip over the sequence token and then
1338 // call the appropriate function to initialize the element
1339 pbTokenData
+= nActualTokenLength
;
1341 // Lengths in the elements should NOT go beyond the element
1344 // Different tokens mean different elements
1345 if ( SPNEGO_TOKEN_INIT
== pSpnegoToken
->ucTokenType
)
1348 // Handle each element as appropriate
1349 switch( pbElements
[nCtr
] )
1352 case SPNEGO_NEGINIT_ELEMENT_MECHTYPES
:
1355 // This is a Mech List that specifies which OIDs the
1356 // originator of the Init Token supports.
1359 nReturn
= GetSpnegoInitTokenMechList( pbTokenData
, nElementLength
,
1360 &pSpnegoToken
->aElementArray
[nCtr
] );
1365 case SPNEGO_NEGINIT_ELEMENT_REQFLAGS
:
1368 // This is a BITSTRING which specifies the flags that the receiver
1369 // pass to the gss_accept_sec_context() function.
1372 nReturn
= InitSpnegoTokenElementFromBasicType( pbTokenData
, nElementLength
,
1373 BITSTRING
, spnego_init_reqFlags
,
1374 &pSpnegoToken
->aElementArray
[nCtr
] );
1378 case SPNEGO_NEGINIT_ELEMENT_MECHTOKEN
:
1381 // This is an OCTETSTRING which contains a GSSAPI token corresponding
1382 // to the first OID in the MechList.
1385 nReturn
= InitSpnegoTokenElementFromBasicType( pbTokenData
, nElementLength
,
1386 OCTETSTRING
, spnego_init_mechToken
,
1387 &pSpnegoToken
->aElementArray
[nCtr
] );
1391 case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC
: // xA3
1394 // Don't yet know if this is a negTokenInit, or negTokenInit2.
1395 // Unfortunately, both have the same type: SPNEGO_TOKEN_INIT
1396 // If it's negTokenInit, this element should be an OCTETSTRING
1397 // containing the MIC. If it's a negTokenInit2, this element
1398 // should be an SPNEGO_CONSTRUCTED_SEQUENCE containing the
1399 // negHints (GENERALSTR, ignored)
1402 nReturn
= InitSpnegoTokenElementFromBasicType( pbTokenData
, nElementLength
,
1403 OCTETSTRING
, spnego_init_mechListMIC
,
1404 &pSpnegoToken
->aElementArray
[nCtr
] );
1406 if (nReturn
== SPNEGO_E_UNEXPECTED_TYPE
) {
1407 // This is really a negHints element. Check the type and length,
1408 // but otherwise just ignore it.
1410 nReturn
= ASNDerCheckToken( pbTokenData
, SPNEGO_CONSTRUCTED_SEQUENCE
,
1411 nElementLength
, nElementLength
,
1421 /* pSpnegoToken->ucTokenType == SPNEGO_TOKEN_TARG */
1423 switch( pbElements
[nCtr
] )
1426 case SPNEGO_NEGTARG_ELEMENT_NEGRESULT
:
1429 // This is an ENUMERATION which specifies result of the last GSS
1430 // token negotiation call.
1433 nReturn
= InitSpnegoTokenElementFromBasicType( pbTokenData
, nElementLength
,
1434 ENUMERATED
, spnego_targ_negResult
,
1435 &pSpnegoToken
->aElementArray
[nCtr
] );
1439 case SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH
:
1442 // This is an OID which specifies a supported mechanism.
1445 nReturn
= InitSpnegoTokenElementFromOID( pbTokenData
, nElementLength
,
1446 spnego_targ_mechListMIC
,
1447 &pSpnegoToken
->aElementArray
[nCtr
] );
1451 case SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN
:
1454 // This is an OCTETSTRING which specifies results of the last GSS
1455 // token negotiation call.
1458 nReturn
= InitSpnegoTokenElementFromBasicType( pbTokenData
, nElementLength
,
1459 OCTETSTRING
, spnego_targ_responseToken
,
1460 &pSpnegoToken
->aElementArray
[nCtr
] );
1464 case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC
:
1467 // This is an OCTETSTRING, typically 16 bytes,
1468 // which contains a message integrity BLOB.
1471 nReturn
= InitSpnegoTokenElementFromBasicType( pbTokenData
, nElementLength
,
1472 OCTETSTRING
, spnego_targ_mechListMIC
,
1473 &pSpnegoToken
->aElementArray
[nCtr
] );
1479 } // ELSE !NegTokenInit
1481 // Account for the entire token and following data
1482 nRemainingTokenLength
-= ( nActualTokenLength
+ nElementLength
);
1484 // Token data should skip past the element length now
1485 pbTokenData
+= nElementLength
;
1488 else if ( SPNEGO_E_TOKEN_NOT_FOUND
== nReturn
)
1490 // For now, this is a benign error (remember, all elements are optional, so
1491 // if we don't find one, it's okay).
1493 nReturn
= SPNEGO_E_SUCCESS
;
1496 } // FOR enum elements
1499 // We should always run down to 0 remaining bytes in the token. If not, we've got
1503 if ( SPNEGO_E_SUCCESS
== nReturn
&& nRemainingTokenLength
!= 0L )
1505 nReturn
= SPNEGO_E_INVALID_TOKEN
;
1512 /////////////////////////////////////////////////////////////////////////////
1515 // FindMechOIDInMechList
1518 // [in] pSpnegoElement - SPNEGO_ELEMENT for MechList
1519 // [in] MechOID - OID we're looking for.
1520 // [out] piMechTypeIndex - Index in the list where OID was
1524 // int Success - SPNEGO_E_SUCCESS
1525 // Failure - SPNEGO API Error code
1528 // Walks the MechList for MechOID. When it is found, the index in the
1529 // list is written to piMechTypeIndex.
1531 ////////////////////////////////////////////////////////////////////////////
1533 int FindMechOIDInMechList( SPNEGO_ELEMENT
* pSpnegoElement
, SPNEGO_MECH_OID MechOID
,
1534 int * piMechTypeIndex
)
1536 int nReturn
= SPNEGO_E_NOT_FOUND
;
1539 long nBoundaryLength
= pSpnegoElement
->nDatalength
;
1540 unsigned char* pbMechListData
= pSpnegoElement
->pbData
;
1542 while( SPNEGO_E_SUCCESS
!= nReturn
&& nBoundaryLength
> 0L )
1545 // Use the helper function to check the OID
1546 if ( ( nReturn
= ASNDerCheckOID( pbMechListData
, MechOID
, nBoundaryLength
, &nLength
) )
1547 == SPNEGO_E_SUCCESS
)
1549 *piMechTypeIndex
= nCtr
;
1552 // Adjust for the current OID
1553 pbMechListData
+= nLength
;
1554 nBoundaryLength
-= nLength
;
1557 } // WHILE enuming OIDs
1564 /////////////////////////////////////////////////////////////////////////////
1570 // [in] pbMechListData - Pointer to binary MechList data
1571 // [in] nBoundaryLength - Length we must not exceed
1574 // int Success - SPNEGO_E_SUCCESS
1575 // Failure - SPNEGO API Error code
1578 // Checks the data at pbMechListData to see if it looks like a MechList.
1579 // As part of this, we walk the list and ensure that none of the OIDs
1580 // have a length that takes us outside of nBoundaryLength.
1582 ////////////////////////////////////////////////////////////////////////////
1584 int ValidateMechList( unsigned char* pbMechListData
, long nBoundaryLength
)
1586 int nReturn
= SPNEGO_E_SUCCESS
;
1588 long nTokenLength
= 0L;
1590 while( SPNEGO_E_SUCCESS
== nReturn
&& nBoundaryLength
> 0L )
1592 // Verify that we have something that at least *looks* like an OID - in other
1593 // words it has an OID identifier and specifies a length that doesn't go beyond
1594 // the size of the list.
1595 nReturn
= ASNDerCheckToken( pbMechListData
, OID
, 0L, nBoundaryLength
,
1596 &nLength
, &nTokenLength
);
1598 // Adjust for the current OID
1599 pbMechListData
+= ( nLength
+ nTokenLength
);
1600 nBoundaryLength
-= ( nLength
+ nTokenLength
);
1602 } // WHILE enuming OIDs
1608 /////////////////////////////////////////////////////////////////////////////
1614 // [in] mechOid - mechOID id enumeration
1621 // Checks for a valid mechOid value.
1623 ////////////////////////////////////////////////////////////////////////////
1625 int IsValidMechOid( SPNEGO_MECH_OID mechOid
)
1627 return ( mechOid
>= spnego_mech_oid_Kerberos_V5_Legacy
&&
1628 mechOid
<= spnego_mech_oid_NTLMSSP
);
1631 /////////////////////////////////////////////////////////////////////////////
1634 // IsValidContextFlags
1637 // [in] ucContextFlags - ContextFlags value
1644 // Checks for a valid ContextFlags value.
1646 ////////////////////////////////////////////////////////////////////////////
1648 int IsValidContextFlags( unsigned char ucContextFlags
)
1650 // Mask out our valid bits. If there is anything leftover, this
1651 // is not a valid value for Context Flags
1652 return ( ( ucContextFlags
& ~SPNEGO_NEGINIT_CONTEXT_MASK
) == 0 );
1655 /////////////////////////////////////////////////////////////////////////////
1661 // [in] negResult - NegResult value
1668 // Checks for a valid NegResult value.
1670 ////////////////////////////////////////////////////////////////////////////
1672 int IsValidNegResult( SPNEGO_NEGRESULT negResult
)
1674 return ( negResult
>= spnego_negresult_success
&&
1675 negResult
<= spnego_negresult_rejected
);
1678 /////////////////////////////////////////////////////////////////////////////
1681 // IsValidSpnegoToken
1684 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1691 // Performs simple heuristic on location pointed to by pSpnegoToken.
1693 ////////////////////////////////////////////////////////////////////////////
1695 int IsValidSpnegoToken( SPNEGO_TOKEN
* pSpnegoToken
)
1699 // Parameter should be non-NULL
1700 if ( NULL
!= pSpnegoToken
)
1702 // Length should be at least the size defined in the header
1703 if ( pSpnegoToken
->nStructSize
>= SPNEGO_TOKEN_SIZE
)
1705 // Number of elements should be >= our maximum - if it's greater, that's
1706 // okay, since we'll only be accessing the elements up to MAX_NUM_TOKEN_ELEMENTS
1707 if ( pSpnegoToken
->nNumElements
>= MAX_NUM_TOKEN_ELEMENTS
)
1709 // Check for proper token type
1710 if ( SPNEGO_TOKEN_INIT
== pSpnegoToken
->ucTokenType
||
1711 SPNEGO_TOKEN_TARG
== pSpnegoToken
->ucTokenType
)
1717 } // IF struct size makes sense
1719 } // IF non-NULL spnego Token
1724 /////////////////////////////////////////////////////////////////////////////
1727 // IsValidSpnegoElement
1730 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1731 // [in] spnegoElement - spnegoElement Type from enumeration
1738 // Checks that spnegoElement has a valid value and is appropriate for
1739 // the SPNEGO token encapsulated by pSpnegoToken.
1741 ////////////////////////////////////////////////////////////////////////////
1743 int IsValidSpnegoElement( SPNEGO_TOKEN
* pSpnegoToken
,SPNEGO_ELEMENT_TYPE spnegoElement
)
1748 if ( spnegoElement
> spnego_element_min
&&
1749 spnegoElement
< spnego_element_max
)
1752 // Check for appropriateness to token type
1753 if ( SPNEGO_TOKEN_INIT
== pSpnegoToken
->ucTokenType
)
1755 nReturn
= ( spnegoElement
>= spnego_init_mechtypes
&&
1756 spnegoElement
<= spnego_init_mechListMIC
);
1760 nReturn
= ( spnegoElement
>= spnego_targ_negResult
&&
1761 spnegoElement
<= spnego_targ_mechListMIC
);
1764 } // IF boundary conditions are met
1769 /////////////////////////////////////////////////////////////////////////////
1772 // CalculateElementArrayIndex
1775 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1776 // [in] spnegoElement - spnegoElement Type from enumeration
1779 // int index in the SPNEGO_TOKEN element array that the element can
1783 // Based on the Token Type, calculates the index in the element array
1784 // at which the specified element can be found.
1786 ////////////////////////////////////////////////////////////////////////////
1788 int CalculateElementArrayIndex( SPNEGO_TOKEN
* pSpnegoToken
,SPNEGO_ELEMENT_TYPE spnegoElement
)
1792 // Offset is difference between value and initial element identifier
1793 // (these differ based on ucTokenType)
1795 if ( SPNEGO_TOKEN_INIT
== pSpnegoToken
->ucTokenType
)
1797 nReturn
= spnegoElement
- spnego_init_mechtypes
;
1801 nReturn
= spnegoElement
- spnego_targ_negResult
;
1807 /////////////////////////////////////////////////////////////////////////////
1810 // InitTokenFromBinary
1813 // [in] ucCopyData - Flag indicating if data should be copied
1814 // [in] ulFlags - Flags value for structure
1815 // [in] pnTokenData - Binary Token Data
1816 // [in] ulLength - Length of the data
1817 // [out] ppSpnegoToken - Pointer to call allocated SPNEGO Token
1821 // int Success - SPNEGO_E_SUCCESS
1822 // Failure - SPNEGO API Error code
1825 // Allocates a SPNEGO_TOKEN data structure and fills it out as
1826 // appropriate based in the flags passed into the function.
1828 ////////////////////////////////////////////////////////////////////////////
1831 // Initializes SPNEGO_TOKEN structure from DER encoded binary data
1832 int InitTokenFromBinary( unsigned char ucCopyData
, unsigned long ulFlags
,
1833 unsigned char* pbTokenData
, unsigned long ulLength
,
1834 SPNEGO_TOKEN
** ppSpnegoToken
)
1836 int nReturn
= SPNEGO_E_INVALID_PARAMETER
;
1837 SPNEGO_TOKEN
* pSpnegoToken
= NULL
;
1838 unsigned char* pbFirstElement
= NULL
;
1839 long nTokenLength
= 0L;
1840 long nRemainingTokenLength
= 0L;
1842 // Basic Parameter Validation
1844 if ( NULL
!= pbTokenData
&&
1845 NULL
!= ppSpnegoToken
&&
1850 // Allocate the empty token, then initialize the data structure.
1853 pSpnegoToken
= AllocEmptySpnegoToken( ucCopyData
, ulFlags
, pbTokenData
, ulLength
);
1855 if ( NULL
!= pSpnegoToken
)
1858 // Copy the binary data locally
1861 // Initialize the token type
1862 if ( ( nReturn
= InitSpnegoTokenType( pSpnegoToken
, &nTokenLength
,
1863 &nRemainingTokenLength
, &pbFirstElement
) )
1864 == SPNEGO_E_SUCCESS
)
1867 // Initialize the element array
1868 if ( ( nReturn
= InitSpnegoTokenElements( pSpnegoToken
, pbFirstElement
,
1869 nRemainingTokenLength
) )
1870 == SPNEGO_E_SUCCESS
)
1872 *ppSpnegoToken
= pSpnegoToken
;
1875 } // IF Init Token Type
1877 // Cleanup on error condition
1878 if ( SPNEGO_E_SUCCESS
!= nReturn
)
1880 spnegoFreeData( pSpnegoToken
);
1886 nReturn
= SPNEGO_E_OUT_OF_MEMORY
;
1889 } // IF Valid parameters