dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libsmbfs / smb / spnegoparse.c
blobea5fb03a704457633f078ae9c20e663e58a5b2ea
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.
11 // Date - 10/08/2002
12 // Author - Sanj Surati
14 /////////////////////////////////////////////////////////////
16 // SPNEGOPARSE.C
18 // SPNEGO Token Handler Source File
20 // Contains implementation of SPNEGO Token parsing functions.
22 /////////////////////////////////////////////////////////////
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <memory.h>
27 #include "spnego.h"
28 #include "derparse.h"
29 #include "spnegoparse.h"
32 // Defined in DERPARSE.C
35 extern MECH_OID g_stcMechOIDList [];
37 /**********************************************************************/
38 /** **/
39 /** **/
40 /** **/
41 /** **/
42 /** Local SPNEGO Helper definitions **/
43 /** **/
44 /** **/
45 /** **/
46 /** **/
47 /**********************************************************************/
50 /////////////////////////////////////////////////////////////////////////////
52 // Function:
53 // CalculateMinSpnegoInitTokenSize
55 // Parameters:
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
63 // for initial token.
65 // Returns:
66 // int Success - SPNEGO_E_SUCCESS
67 // Failure - SPNEGO API Error code
69 // Comments :
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
75 // writing out.
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;
86 // Start at 0.
87 long nTotalLength = 0;
88 long nTempLength= 0L;
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
147 // Sequence Token
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;
169 // SPNEGO OID Token
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;
194 // We're done
195 *pnTokenSize = nTotalLength;
196 nReturn = SPNEGO_E_SUCCESS;
198 xEndTokenInitLength:
200 return nReturn;
204 /////////////////////////////////////////////////////////////////////////////
206 // Function:
207 // CreateSpnegoInitToken
209 // Parameters:
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
220 // token bytes.
222 // Returns:
223 // int Success - SPNEGO_E_SUCCESS
224 // Failure - SPNEGO API Error code
226 // Comments :
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
231 // writing out.
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;
252 // Start at 0.
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
300 // write it out.
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
328 // write it out.
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;
342 } // IF ContextFlags
344 // Next is the MechList - This is REQUIRED
345 nTempLength = ASNDerCalcMechListLength( pMechTypeList, MechTypeCnt, &nInternalLength );
347 // Decrease the pbWriteTokenData, now we know the length and
348 // write it out.
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.
364 // Sequence Token
365 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
367 // Decrease the pbWriteTokenData, now we know the length and
368 // write it out.
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
386 // write it out.
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;
400 // SPNEGO OID Token
401 nTempLength = g_stcMechOIDList[spnego_mech_oid_Spnego].iLen;
403 // Decrease the pbWriteTokenData, now we know the length and
404 // write it out.
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
421 // write it out.
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:
443 return nReturn;
447 /////////////////////////////////////////////////////////////////////////////
449 // Function:
450 // CalculateMinSpnegoTargTokenSize
452 // Parameters:
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.
461 // Returns:
462 // int Success - SPNEGO_E_SUCCESS
463 // Failure - SPNEGO API Error code
465 // Comments :
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
471 // writing out.
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;
482 // Start at 0.
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,
522 NULL );
524 // Check for rollover error
525 if ( nTempLength < nTotalLength )
527 goto xEndTokenTargLength;
530 nTotalLength = nTempLength;
532 } // IF MechType is available
534 // NegResult Element
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
551 // Sequence Token
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;
576 // We're done
577 *pnTokenSize = nTotalLength;
578 nReturn = SPNEGO_E_SUCCESS;
580 xEndTokenTargLength:
582 return nReturn;
586 /////////////////////////////////////////////////////////////////////////////
588 // Function:
589 // CreateSpnegoTargToken
591 // Parameters:
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
601 // token bytes.
603 // Returns:
604 // int Success - SPNEGO_E_SUCCESS
605 // Failure - SPNEGO API Error code
607 // Comments :
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
612 // writing out.
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;
624 // Start at 0.
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
644 // write it out.
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
667 // write it out.
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,
687 &nInternalLength );
689 // Decrease the pbWriteTokenData, now we know the length and
690 // write it out.
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
707 // Neg Result
708 // NegResult Element
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
716 // write it out.
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.
735 // Sequence Token
736 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
738 // Decrease the pbWriteTokenData, now we know the length and
739 // write it out.
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
757 // write it out.
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:
780 return nReturn;
786 /////////////////////////////////////////////////////////////////////////////
788 // Function:
789 // AllocEmptySpnegoToken
791 // Parameters:
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.
797 // Returns:
798 // SPNEGO_TOKEN* Success - Pointer to initialized SPNEGO_TOKEN struct
799 // Failure - NULL
801 // Comments :
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
805 // direcly.
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;
845 else
847 free( pSpnegoToken );
848 pSpnegoToken = NULL;
851 } // IF ucCopyData
852 else
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;
863 return pSpnegoToken;
866 /////////////////////////////////////////////////////////////////////////////
868 // Function:
869 // FreeSpnegoToken
871 // Parameters:
872 // [in] pSpnegoToken - Points to SPNEGO_TOKEN to free.
874 // Returns:
875 // void
877 // Comments :
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 /////////////////////////////////////////////////////////////////////////////
902 // Function:
903 // InitSpnegoTokenElementArray
905 // Parameters:
906 // [in] pSpnegoToken - Points to SPNEGO_TOKEN structure.
908 // Returns:
909 // void
911 // Comments :
912 // Initializes the element array data member of a SPNEGO_TOKEN data
913 // structure.
915 ////////////////////////////////////////////////////////////////////////////
917 void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken )
919 int nCtr;
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 /////////////////////////////////////////////////////////////////////////////
939 // Function:
940 // InitSpnegoTokenType
942 // Parameters:
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.
950 // Returns:
951 // int Success - SPNEGO_E_SUCCESS
952 // Failure - SPNEGO API Error code
954 // Comments :
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
957 // information.
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
1075 return nReturn;
1079 /////////////////////////////////////////////////////////////////////////////
1081 // Function:
1082 // GetSpnegoInitTokenMechList
1084 // Parameters:
1085 // [in] pbTokenData - Points to binary MechList element
1086 // in NegTokenInit.
1087 // [in] nMechListLength - Length of the MechList
1088 // [out] pSpnegoElement - Filled out with MechList Element
1089 // data.
1091 // Returns:
1092 // int Success - SPNEGO_E_SUCCESS
1093 // Failure - SPNEGO API Error code
1095 // Comments :
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;
1106 long nLength = 0L;
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;
1132 } // IF Check Token
1134 return nReturn;
1137 /////////////////////////////////////////////////////////////////////////////
1139 // Function:
1140 // InitSpnegoTokenElementFromBasicType
1142 // Parameters:
1143 // [in] pbTokenData - Points to binary element data in
1144 // a SPNEGO token.
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.
1150 // Returns:
1151 // int Success - SPNEGO_E_SUCCESS
1152 // Failure - SPNEGO API Error code
1154 // Comments :
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;
1167 long nLength = 0L;
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
1194 return nReturn;
1198 /////////////////////////////////////////////////////////////////////////////
1200 // Function:
1201 // InitSpnegoTokenElementFromOID
1203 // Parameters:
1204 // [in] pbTokenData - Points to binary element data in
1205 // a SPNEGO token.
1206 // [in] nElementLength - Length of the element
1207 // [in] spnegoElementType - Which element is this?
1208 // [out] pSpnegoElement - Filled out with element data.
1210 // Returns:
1211 // int Success - SPNEGO_E_SUCCESS
1212 // Failure - SPNEGO API Error code
1214 // Comments :
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;
1227 long nLength = 0L;
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
1252 return nReturn;
1256 /////////////////////////////////////////////////////////////////////////////
1258 // Function:
1259 // InitSpnegoTokenElements
1261 // Parameters:
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
1267 // Returns:
1268 // int Success - SPNEGO_E_SUCCESS
1269 // Failure - SPNEGO API Error code
1271 // Comments :
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
1285 // no defaults.
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;
1297 int nCtr = 0L;
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;
1309 break;
1311 case SPNEGO_TOKEN_TARG:
1313 pbElements = abNegTokenTargElements;
1315 break;
1317 } // SWITCH tokentype
1320 // Enumerate the element arrays and look for the tokens at our current location
1323 for ( nCtr = 0L;
1324 SPNEGO_E_SUCCESS == nReturn &&
1325 nCtr < MAX_NUM_TOKEN_ELEMENTS &&
1326 nRemainingTokenLength > 0L;
1327 nCtr++ )
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
1342 // length
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] );
1363 break;
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] );
1376 break;
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] );
1389 break;
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.
1409 long elen, tlen;
1410 nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
1411 nElementLength, nElementLength,
1412 &elen, &tlen );
1415 break;
1417 } // SWITCH Element
1419 else
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] );
1437 break;
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] );
1449 break;
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] );
1462 break;
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] );
1475 break;
1477 } // SWITCH Element
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;
1487 } // IF Token found
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
1500 // a bad token.
1503 if ( SPNEGO_E_SUCCESS == nReturn && nRemainingTokenLength != 0L )
1505 nReturn = SPNEGO_E_INVALID_TOKEN;
1508 return nReturn;
1512 /////////////////////////////////////////////////////////////////////////////
1514 // Function:
1515 // FindMechOIDInMechList
1517 // Parameters:
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
1521 // found
1523 // Returns:
1524 // int Success - SPNEGO_E_SUCCESS
1525 // Failure - SPNEGO API Error code
1527 // Comments :
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;
1537 int nCtr = 0;
1538 long nLength = 0L;
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;
1555 nCtr++;
1557 } // WHILE enuming OIDs
1559 return nReturn;
1564 /////////////////////////////////////////////////////////////////////////////
1566 // Function:
1567 // ValidateMechList
1569 // Parameters:
1570 // [in] pbMechListData - Pointer to binary MechList data
1571 // [in] nBoundaryLength - Length we must not exceed
1573 // Returns:
1574 // int Success - SPNEGO_E_SUCCESS
1575 // Failure - SPNEGO API Error code
1577 // Comments :
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;
1587 long nLength = 0L;
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
1604 return nReturn;
1608 /////////////////////////////////////////////////////////////////////////////
1610 // Function:
1611 // IsValidMechOid
1613 // Parameters:
1614 // [in] mechOid - mechOID id enumeration
1616 // Returns:
1617 // int Success - 1
1618 // Failure - 0
1620 // Comments :
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 /////////////////////////////////////////////////////////////////////////////
1633 // Function:
1634 // IsValidContextFlags
1636 // Parameters:
1637 // [in] ucContextFlags - ContextFlags value
1639 // Returns:
1640 // int Success - 1
1641 // Failure - 0
1643 // Comments :
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 /////////////////////////////////////////////////////////////////////////////
1657 // Function:
1658 // IsValidNegResult
1660 // Parameters:
1661 // [in] negResult - NegResult value
1663 // Returns:
1664 // int Success - 1
1665 // Failure - 0
1667 // Comments :
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 /////////////////////////////////////////////////////////////////////////////
1680 // Function:
1681 // IsValidSpnegoToken
1683 // Parameters:
1684 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1686 // Returns:
1687 // int Success - 1
1688 // Failure - 0
1690 // Comments :
1691 // Performs simple heuristic on location pointed to by pSpnegoToken.
1693 ////////////////////////////////////////////////////////////////////////////
1695 int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken )
1697 int nReturn = 0;
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 )
1713 nReturn = 1;
1717 } // IF struct size makes sense
1719 } // IF non-NULL spnego Token
1721 return nReturn;
1724 /////////////////////////////////////////////////////////////////////////////
1726 // Function:
1727 // IsValidSpnegoElement
1729 // Parameters:
1730 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1731 // [in] spnegoElement - spnegoElement Type from enumeration
1733 // Returns:
1734 // int Success - 1
1735 // Failure - 0
1737 // Comments :
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 )
1745 int nReturn = 0;
1747 // Check boundaries
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 );
1758 else
1760 nReturn = ( spnegoElement >= spnego_targ_negResult &&
1761 spnegoElement <= spnego_targ_mechListMIC );
1764 } // IF boundary conditions are met
1766 return nReturn;
1769 /////////////////////////////////////////////////////////////////////////////
1771 // Function:
1772 // CalculateElementArrayIndex
1774 // Parameters:
1775 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1776 // [in] spnegoElement - spnegoElement Type from enumeration
1778 // Returns:
1779 // int index in the SPNEGO_TOKEN element array that the element can
1780 // can be found
1782 // Comments :
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 )
1790 int nReturn = 0;
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;
1799 else
1801 nReturn = spnegoElement - spnego_targ_negResult;
1804 return nReturn;
1807 /////////////////////////////////////////////////////////////////////////////
1809 // Function:
1810 // InitTokenFromBinary
1812 // Parameters:
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
1818 // data structure
1820 // Returns:
1821 // int Success - SPNEGO_E_SUCCESS
1822 // Failure - SPNEGO API Error code
1824 // Comments :
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 &&
1846 0L != ulLength )
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 );
1884 else
1886 nReturn = SPNEGO_E_OUT_OF_MEMORY;
1889 } // IF Valid parameters
1892 return nReturn;