1 // Copyright 2012 Nexenta Systems, Inc. All rights reserved.
2 // Copyright (C) 2002 Microsoft Corporation
3 // All rights reserved.
4 //
5 // THIS CODE AND INFORMATION IS PROVIDED "AS IS"
6 // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
7 // OR IMPLIED, INCLUDING BUT NOT LIMITED
8 // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
9 // AND/OR FITNESS FOR A PARTICULAR PURPOSE.
10 //
11 // Date - 10/08/2002
12 // Author - Sanj Surati
13
14 /////////////////////////////////////////////////////////////
15 //
16 // SPNEGOPARSE.C
17 //
18 // SPNEGO Token Handler Source File
19 //
20 // Contains implementation of SPNEGO Token parsing functions.
21 //
22 /////////////////////////////////////////////////////////////
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <memory.h>
27 #include "spnego.h"
28 #include "derparse.h"
29 #include "spnegoparse.h"
30
31 //
32 // Defined in DERPARSE.C
33 //
34
35 extern MECH_OID g_stcMechOIDList [];
36
37 /**********************************************************************/
38 /** **/
39 /** **/
40 /** **/
41 /** **/
42 /** Local SPNEGO Helper definitions **/
43 /** **/
44 /** **/
45 /** **/
46 /** **/
47 /**********************************************************************/
48
49
50 /////////////////////////////////////////////////////////////////////////////
51 //
52 // Function:
53 // CalculateMinSpnegoInitTokenSize
54 //
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.
64 //
65 // Returns:
66 // int Success - SPNEGO_E_SUCCESS
67 // Failure - SPNEGO API Error code
68 //
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.
76 //
77 ////////////////////////////////////////////////////////////////////////////
78
CalculateMinSpnegoInitTokenSize(long nMechTokenLength,long nMechListMICLength,SPNEGO_MECH_OID * mechOidLst,int mechOidCnt,int nReqFlagsAvailable,long * pnTokenSize,long * pnInternalTokenLength)79 int CalculateMinSpnegoInitTokenSize( long nMechTokenLength,
80 long nMechListMICLength, SPNEGO_MECH_OID *mechOidLst, int mechOidCnt,
81 int nReqFlagsAvailable, long* pnTokenSize,
82 long* pnInternalTokenLength )
83 {
84 int nReturn = SPNEGO_E_INVALID_LENGTH;
85
86 // Start at 0.
87 long nTotalLength = 0;
88 long nTempLength= 0L;
89
90 // We will calculate this by walking the token backwards
91
92 // Start with MIC Element (or negHints)
93 if ( nMechListMICLength > 0L )
94 {
95 nTempLength = ASNDerCalcElementLength( nMechListMICLength, NULL );
96
97 // Check for rollover error
98 if ( nTempLength < nMechListMICLength )
99 {
100 goto xEndTokenInitLength;
101 }
102
103 nTotalLength += nTempLength;
104 }
105
106 // Next is the MechToken
107 if ( nMechTokenLength > 0L )
108 {
109 nTempLength += ASNDerCalcElementLength( nMechTokenLength, NULL );
110
111 // Check for rollover error
112 if ( nTempLength < nTotalLength )
113 {
114 goto xEndTokenInitLength;
115 }
116
117 nTotalLength = nTempLength;
118 }
119
120 // Next is the ReqFlags
121 if ( nReqFlagsAvailable )
122 {
123 nTempLength += ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, NULL );
124
125 // Check for rollover error
126 if ( nTempLength < nTotalLength )
127 {
128 goto xEndTokenInitLength;
129 }
130
131 nTotalLength = nTempLength;
132 }
133
134 // Next is the MechList - This is REQUIRED
135 nTempLength += ASNDerCalcMechListLength( mechOidLst, mechOidCnt, NULL );
136
137 // Check for rollover error
138 if ( nTempLength < nTotalLength )
139 {
140 goto xEndTokenInitLength;
141 }
142
143 nTotalLength = nTempLength;
144
145 // Following four fields are the basic header tokens
146
147 // Sequence Token
148 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
149
150 // Check for rollover error
151 if ( nTempLength < nTotalLength )
152 {
153 goto xEndTokenInitLength;
154 }
155
156 nTotalLength = nTempLength;
157
158 // Neg Token Identifier Token
159 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
160
161 // Check for rollover error
162 if ( nTempLength < nTotalLength )
163 {
164 goto xEndTokenInitLength;
165 }
166
167 nTotalLength = nTempLength;
168
169 // SPNEGO OID Token
170 nTempLength += g_stcMechOIDList[spnego_mech_oid_Spnego].iLen;
171
172 // Check for rollover error
173 if ( nTempLength < nTotalLength )
174 {
175 goto xEndTokenInitLength;
176 }
177
178 nTotalLength = nTempLength;
179
180 // App Constructed Token
181 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
182
183 // Check for rollover error
184 if ( nTempLength < nTotalLength )
185 {
186 goto xEndTokenInitLength;
187 }
188
189 // The internal length doesn't include the number of bytes
190 // for the initial token
191 *pnInternalTokenLength = nTotalLength;
192 nTotalLength = nTempLength;
193
194 // We're done
195 *pnTokenSize = nTotalLength;
196 nReturn = SPNEGO_E_SUCCESS;
197
198 xEndTokenInitLength:
199
200 return nReturn;
201
202 }
203
204 /////////////////////////////////////////////////////////////////////////////
205 //
206 // Function:
207 // CreateSpnegoInitToken
208 //
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.
221 //
222 // Returns:
223 // int Success - SPNEGO_E_SUCCESS
224 // Failure - SPNEGO API Error code
225 //
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.
232 //
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.
241 //
242 ////////////////////////////////////////////////////////////////////////////
243
CreateSpnegoInitToken(SPNEGO_MECH_OID * pMechTypeList,long MechTypeCnt,unsigned char ucContextFlags,unsigned char * pbMechToken,unsigned long ulMechTokenLen,unsigned char * pbMechListMIC,unsigned long ulMechListMICLen,unsigned char * pbTokenData,long nTokenLength,long nInternalTokenLength)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 )
249 {
250 int nReturn = SPNEGO_E_INVALID_LENGTH;
251
252 // Start at 0.
253 long nTempLength= 0L;
254 long nTotalBytesWritten = 0L;
255 long nInternalLength = 0L;
256
257 unsigned char* pbWriteTokenData = pbTokenData + nTokenLength;
258
259 // Temporary buffer to hold the REQ Flags as BIT String Data
260 unsigned char abTempReqFlags[SPNEGO_NEGINIT_MAXLEN_REQFLAGS];
261
262
263 // We will write the token out backwards to properly handle the cases
264 // where the length bytes become adjustable
265
266 // Start with MIC Element (or negHints)
267 if ( ulMechListMICLen > 0L )
268 {
269 unsigned char ucType;
270 nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength );
271
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;
278
279 pbWriteTokenData -= nTempLength;
280 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC,
281 ucType, pbMechListMIC, ulMechListMICLen );
282
283 // Adjust Values and sanity check
284 nTotalBytesWritten += nTempLength;
285 nInternalTokenLength -= nTempLength;
286
287 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
288 {
289 goto xEndWriteNegTokenInit;
290 }
291
292 } // IF MechListMIC is present
293
294 // Next is the MechToken
295 if ( ulMechTokenLen > 0L )
296 {
297 nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength );
298
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;
307
308 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
309 {
310 goto xEndWriteNegTokenInit;
311 }
312
313 } // IF MechToken Length is present
314
315 // Next is the ReqFlags
316 if ( ucContextFlags > 0L )
317 {
318
319 nTempLength = ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, &nInternalLength );
320
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)
323
324 abTempReqFlags[0] = SPNEGO_NEGINIT_REQFLAGS_BITDIFF;
325 abTempReqFlags[1] = ucContextFlags;
326
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 );
332
333 // Adjust Values and sanity check
334 nTotalBytesWritten += nTempLength;
335 nInternalTokenLength -= nTempLength;
336
337 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
338 {
339 goto xEndWriteNegTokenInit;
340 }
341
342 } // IF ContextFlags
343
344 // Next is the MechList - This is REQUIRED
345 nTempLength = ASNDerCalcMechListLength( pMechTypeList, MechTypeCnt, &nInternalLength );
346
347 // Decrease the pbWriteTokenData, now we know the length and
348 // write it out.
349 pbWriteTokenData -= nTempLength;
350 nTempLength = ASNDerWriteMechList( pbWriteTokenData, pMechTypeList, MechTypeCnt );
351
352 // Adjust Values and sanity check
353 nTotalBytesWritten += nTempLength;
354 nInternalTokenLength -= nTempLength;
355
356 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
357 {
358 goto xEndWriteNegTokenInit;
359 }
360
361 // The next tokens we're writing out reflect the total number of bytes
362 // we have actually written out.
363
364 // Sequence Token
365 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
366
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 );
372
373 // Adjust Values and sanity check
374 nTotalBytesWritten += nTempLength;
375 nInternalTokenLength -= nTempLength;
376
377 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
378 {
379 goto xEndWriteNegTokenInit;
380 }
381
382 // Neg Init Token Identifier Token
383 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
384
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 );
390
391 // Adjust Values and sanity check
392 nTotalBytesWritten += nTempLength;
393 nInternalTokenLength -= nTempLength;
394
395 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
396 {
397 goto xEndWriteNegTokenInit;
398 }
399
400 // SPNEGO OID Token
401 nTempLength = g_stcMechOIDList[spnego_mech_oid_Spnego].iLen;
402
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 );
407
408 // Adjust Values and sanity check
409 nTotalBytesWritten += nTempLength;
410 nInternalTokenLength -= nTempLength;
411
412 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
413 {
414 goto xEndWriteNegTokenInit;
415 }
416
417 // App Constructed Token
418 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
419
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 );
425
426 // Adjust Values and sanity check
427 nTotalBytesWritten += nTempLength;
428
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).
434
435 if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 &&
436 pbWriteTokenData == pbTokenData )
437 {
438 nReturn = SPNEGO_E_SUCCESS;
439 }
440
441 xEndWriteNegTokenInit:
442
443 return nReturn;
444
445 }
446
447 /////////////////////////////////////////////////////////////////////////////
448 //
449 // Function:
450 // CalculateMinSpnegoTargTokenSize
451 //
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.
460 //
461 // Returns:
462 // int Success - SPNEGO_E_SUCCESS
463 // Failure - SPNEGO API Error code
464 //
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.
472 //
473 ////////////////////////////////////////////////////////////////////////////
474
CalculateMinSpnegoTargTokenSize(SPNEGO_MECH_OID MechType,SPNEGO_NEGRESULT spnegoNegResult,long nMechTokenLen,long nMechListMICLen,long * pnTokenSize,long * pnInternalTokenLength)475 int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType,
476 SPNEGO_NEGRESULT spnegoNegResult, long nMechTokenLen,
477 long nMechListMICLen, long* pnTokenSize,
478 long* pnInternalTokenLength )
479 {
480 int nReturn = SPNEGO_E_INVALID_LENGTH;
481
482 // Start at 0.
483 long nTotalLength = 0;
484 long nTempLength= 0L;
485
486 // We will calculate this by walking the token backwards
487
488 // Start with MIC Element
489 if ( nMechListMICLen > 0L )
490 {
491 nTempLength = ASNDerCalcElementLength( nMechListMICLen, NULL );
492
493 // Check for rollover error
494 if ( nTempLength < nMechListMICLen )
495 {
496 goto xEndTokenTargLength;
497 }
498
499 nTotalLength += nTempLength;
500 }
501
502 // Next is the MechToken
503 if ( nMechTokenLen > 0L )
504 {
505 nTempLength += ASNDerCalcElementLength( nMechTokenLen, NULL );
506
507 // Check for rollover error
508 if ( nTempLength < nTotalLength )
509 {
510 goto xEndTokenTargLength;
511 }
512
513 nTotalLength = nTempLength;
514 }
515
516 // Supported MechType
517 if ( spnego_mech_oid_NotUsed != MechType )
518 {
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 );
523
524 // Check for rollover error
525 if ( nTempLength < nTotalLength )
526 {
527 goto xEndTokenTargLength;
528 }
529
530 nTotalLength = nTempLength;
531
532 } // IF MechType is available
533
534 // NegResult Element
535 if ( spnego_negresult_NotUsed != spnegoNegResult )
536 {
537 nTempLength += ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, NULL );
538
539 // Check for rollover error
540 if ( nTempLength < nTotalLength )
541 {
542 goto xEndTokenTargLength;
543 }
544
545 nTotalLength = nTempLength;
546
547 } // IF negResult is available
548
549 // Following two fields are the basic header tokens
550
551 // Sequence Token
552 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
553
554 // Check for rollover error
555 if ( nTempLength < nTotalLength )
556 {
557 goto xEndTokenTargLength;
558 }
559
560 nTotalLength = nTempLength;
561
562 // Neg Token Identifier Token
563 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
564
565 // Check for rollover error
566 if ( nTempLength < nTotalLength )
567 {
568 goto xEndTokenTargLength;
569 }
570
571 // The internal length doesn't include the number of bytes
572 // for the initial token
573 *pnInternalTokenLength = nTotalLength;
574 nTotalLength = nTempLength;
575
576 // We're done
577 *pnTokenSize = nTotalLength;
578 nReturn = SPNEGO_E_SUCCESS;
579
580 xEndTokenTargLength:
581
582 return nReturn;
583
584 }
585
586 /////////////////////////////////////////////////////////////////////////////
587 //
588 // Function:
589 // CreateSpnegoTargToken
590 //
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.
602 //
603 // Returns:
604 // int Success - SPNEGO_E_SUCCESS
605 // Failure - SPNEGO API Error code
606 //
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.
613 //
614 ////////////////////////////////////////////////////////////////////////////
615
CreateSpnegoTargToken(SPNEGO_MECH_OID MechType,SPNEGO_NEGRESULT eNegResult,unsigned char * pbMechToken,unsigned long ulMechTokenLen,unsigned char * pbMechListMIC,unsigned long ulMechListMICLen,unsigned char * pbTokenData,long nTokenLength,long nInternalTokenLength)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 )
621 {
622 int nReturn = SPNEGO_E_INVALID_LENGTH;
623
624 // Start at 0.
625 long nTempLength= 0L;
626 long nTotalBytesWritten = 0L;
627 long nInternalLength = 0L;
628
629 unsigned char ucTemp = 0;
630
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.
634
635 unsigned char* pbWriteTokenData = pbTokenData + nTokenLength;
636
637
638 // Start with MIC Element
639 if ( ulMechListMICLen > 0L )
640 {
641 nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength );
642
643 // Decrease the pbWriteTokenData, now we know the length and
644 // write it out.
645
646 pbWriteTokenData -= nTempLength;
647 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC,
648 OCTETSTRING, pbMechListMIC, ulMechListMICLen );
649
650 // Adjust Values and sanity check
651 nTotalBytesWritten += nTempLength;
652 nInternalTokenLength -= nTempLength;
653
654 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
655 {
656 goto xEndWriteNegTokenTarg;
657 }
658
659 } // IF MechListMIC is present
660
661 // Next is the MechToken
662 if ( ulMechTokenLen > 0L )
663 {
664 nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength );
665
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;
674
675 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
676 {
677 goto xEndWriteNegTokenTarg;
678 }
679
680 } // IF MechToken Length is present
681
682 // Supported Mech Type
683 if ( spnego_mech_oid_NotUsed != MechType )
684 {
685
686 nTempLength = ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen,
687 &nInternalLength );
688
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 );
695
696 // Adjust Values and sanity check
697 nTotalBytesWritten += nTempLength;
698 nInternalTokenLength -= nTempLength;
699
700 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
701 {
702 goto xEndWriteNegTokenTarg;
703 }
704
705 } // IF MechType is present
706
707 // Neg Result
708 // NegResult Element
709 if ( spnego_negresult_NotUsed != eNegResult )
710 {
711 ucTemp = (unsigned char) eNegResult;
712
713 nTempLength = ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, &nInternalLength );
714
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 );
720
721 // Adjust Values and sanity check
722 nTotalBytesWritten += nTempLength;
723 nInternalTokenLength -= nTempLength;
724
725 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
726 {
727 goto xEndWriteNegTokenTarg;
728 }
729
730 } // If eNegResult is available
731
732 // The next tokens we're writing out reflect the total number of bytes
733 // we have actually written out.
734
735 // Sequence Token
736 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
737
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 );
743
744 // Adjust Values and sanity check
745 nTotalBytesWritten += nTempLength;
746 nInternalTokenLength -= nTempLength;
747
748 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
749 {
750 goto xEndWriteNegTokenTarg;
751 }
752
753 // Neg Targ Token Identifier Token
754 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
755
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 );
761
762 // Adjust Values and sanity check
763 nTotalBytesWritten += nTempLength;
764
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).
770
771 if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 &&
772 pbWriteTokenData == pbTokenData )
773 {
774 nReturn = SPNEGO_E_SUCCESS;
775 }
776
777
778 xEndWriteNegTokenTarg:
779
780 return nReturn;
781
782
783 }
784
785
786 /////////////////////////////////////////////////////////////////////////////
787 //
788 // Function:
789 // AllocEmptySpnegoToken
790 //
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.
796 //
797 // Returns:
798 // SPNEGO_TOKEN* Success - Pointer to initialized SPNEGO_TOKEN struct
799 // Failure - NULL
800 //
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.
806 //
807 ////////////////////////////////////////////////////////////////////////////
808
AllocEmptySpnegoToken(unsigned char ucCopyData,unsigned long ulFlags,unsigned char * pbTokenData,unsigned long ulTokenSize)809 SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags,
810 unsigned char * pbTokenData, unsigned long ulTokenSize )
811 {
812 SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) calloc( 1, sizeof(SPNEGO_TOKEN) );
813
814 if ( NULL != pSpnegoToken )
815 {
816 // Set the token size
817 pSpnegoToken->nStructSize = SPNEGO_TOKEN_SIZE;
818
819 // Initialize the element array
820 InitSpnegoTokenElementArray( pSpnegoToken );
821
822 // Assign the flags value
823 pSpnegoToken->ulFlags = ulFlags;
824
825 //
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
829 //
830
831 if ( SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA == ucCopyData )
832 {
833 // Alloc the internal buffer. Cleanup on failure.
834 pSpnegoToken->pbBinaryData = (unsigned char*) calloc( ulTokenSize, sizeof(unsigned char) );
835
836 if ( NULL != pSpnegoToken->pbBinaryData )
837 {
838 // We must ALWAYS free this buffer
839 pSpnegoToken->ulFlags |= SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA;
840
841 // Copy the data locally
842 memcpy( pSpnegoToken->pbBinaryData, pbTokenData, ulTokenSize );
843 pSpnegoToken->ulBinaryDataLen = ulTokenSize;
844 }
845 else
846 {
847 free( pSpnegoToken );
848 pSpnegoToken = NULL;
849 }
850
851 } // IF ucCopyData
852 else
853 {
854 // Copy the pointer and the length directly - ulFlags will control whether or not
855 // we are allowed to free the value
856
857 pSpnegoToken->pbBinaryData = pbTokenData;
858 pSpnegoToken->ulBinaryDataLen = ulTokenSize;
859 }
860
861 }
862
863 return pSpnegoToken;
864 }
865
866 /////////////////////////////////////////////////////////////////////////////
867 //
868 // Function:
869 // FreeSpnegoToken
870 //
871 // Parameters:
872 // [in] pSpnegoToken - Points to SPNEGO_TOKEN to free.
873 //
874 // Returns:
875 // void
876 //
877 // Comments :
878 // If non-NULL, interprets pSpnegoToken, freeing any internal allocations
879 // and finally the actual structure.
880 //
881 ////////////////////////////////////////////////////////////////////////////
882
FreeSpnegoToken(SPNEGO_TOKEN * pSpnegoToken)883 void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken )
884 {
885 if ( NULL != pSpnegoToken )
886 {
887
888 // Cleanup internal allocation per the flags
889 if ( pSpnegoToken->ulFlags & SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA &&
890 NULL != pSpnegoToken->pbBinaryData )
891 {
892 free( pSpnegoToken->pbBinaryData );
893 pSpnegoToken->pbBinaryData = NULL;
894 }
895
896 free ( pSpnegoToken );
897 }
898 }
899
900 /////////////////////////////////////////////////////////////////////////////
901 //
902 // Function:
903 // InitSpnegoTokenElementArray
904 //
905 // Parameters:
906 // [in] pSpnegoToken - Points to SPNEGO_TOKEN structure.
907 //
908 // Returns:
909 // void
910 //
911 // Comments :
912 // Initializes the element array data member of a SPNEGO_TOKEN data
913 // structure.
914 //
915 ////////////////////////////////////////////////////////////////////////////
916
InitSpnegoTokenElementArray(SPNEGO_TOKEN * pSpnegoToken)917 void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken )
918 {
919 int nCtr;
920
921 // Set the number of elemnts
922 pSpnegoToken->nNumElements = MAX_NUM_TOKEN_ELEMENTS;
923
924 //
925 // Initially, all elements are unavailable
926 //
927
928 for ( nCtr = 0; nCtr < MAX_NUM_TOKEN_ELEMENTS; nCtr++ )
929 {
930 // Set the element size as well
931 pSpnegoToken->aElementArray[ nCtr ].nStructSize = SPNEGO_ELEMENT_SIZE;
932 pSpnegoToken->aElementArray[ nCtr ].iElementPresent = SPNEGO_TOKEN_ELEMENT_UNAVAILABLE;
933 }
934
935 }
936
937 /////////////////////////////////////////////////////////////////////////////
938 //
939 // Function:
940 // InitSpnegoTokenType
941 //
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.
949 //
950 // Returns:
951 // int Success - SPNEGO_E_SUCCESS
952 // Failure - SPNEGO API Error code
953 //
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.
958 //
959 ////////////////////////////////////////////////////////////////////////////
960
InitSpnegoTokenType(SPNEGO_TOKEN * pSpnegoToken,long * pnTokenLength,long * pnRemainingTokenLength,unsigned char ** ppbFirstElement)961 int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength,
962 long* pnRemainingTokenLength, unsigned char** ppbFirstElement )
963 {
964 int nReturn = SPNEGO_E_INVALID_TOKEN;
965 long nActualTokenLength = 0L;
966 long nBoundaryLength = pSpnegoToken->ulBinaryDataLen;
967 unsigned char* pbTokenData = pSpnegoToken->pbBinaryData;
968
969 //
970 // First byte MUST be either an APP_CONSTRUCT or the NEGTARG_TOKEN_TARG
971 //
972
973 if ( SPNEGO_NEGINIT_APP_CONSTRUCT == *pbTokenData )
974 {
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 )
980 {
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;
986
987 // Make adjustments to next token
988 pbTokenData += nActualTokenLength;
989 nBoundaryLength -= nActualTokenLength;
990
991 // The next token should be an OID
992 if ( ( nReturn = ASNDerCheckOID( pbTokenData, spnego_mech_oid_Spnego, nBoundaryLength,
993 &nActualTokenLength ) ) == SPNEGO_E_SUCCESS )
994 {
995 // Make adjustments to next token
996 pbTokenData += nActualTokenLength;
997 nBoundaryLength -= nActualTokenLength;
998 *pnRemainingTokenLength -= nActualTokenLength;
999
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 )
1005 {
1006 // Make adjustments to next token
1007 pbTokenData += nActualTokenLength;
1008 nBoundaryLength -= nActualTokenLength;
1009 *pnRemainingTokenLength -= nActualTokenLength;
1010
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 )
1016 {
1017 // NegTokenInit header is now checked out!
1018
1019 // Make adjustments to next token
1020 *pnRemainingTokenLength -= nActualTokenLength;
1021
1022 // Store pointer to first element
1023 *ppbFirstElement = pbTokenData + nActualTokenLength;
1024 pSpnegoToken->ucTokenType = SPNEGO_TOKEN_INIT;
1025 } // IF Check Sequence Token
1026
1027 } // IF Check NegTokenInit token
1028
1029
1030 } // IF Check for SPNEGO OID
1031
1032
1033 } // IF check app construct token
1034
1035 }
1036 else if ( SPNEGO_NEGTARG_TOKEN_IDENTIFIER == *pbTokenData )
1037 {
1038
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 )
1044 {
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;
1050
1051 // Make adjustments to next token
1052 pbTokenData += nActualTokenLength;
1053 nBoundaryLength -= nActualTokenLength;
1054
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 )
1060 {
1061 // NegTokenInit header is now checked out!
1062
1063 // Make adjustments to next token
1064 *pnRemainingTokenLength -= nActualTokenLength;
1065
1066 // Store pointer to first element
1067 *ppbFirstElement = pbTokenData + nActualTokenLength;
1068 pSpnegoToken->ucTokenType = SPNEGO_TOKEN_TARG;
1069 } // IF Check Sequence Token
1070
1071 } // IF Check NegTokenInit token
1072
1073 } // ELSE IF it's a NegTokenTarg
1074
1075 return nReturn;
1076 }
1077
1078
1079 /////////////////////////////////////////////////////////////////////////////
1080 //
1081 // Function:
1082 // GetSpnegoInitTokenMechList
1083 //
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.
1090 //
1091 // Returns:
1092 // int Success - SPNEGO_E_SUCCESS
1093 // Failure - SPNEGO API Error code
1094 //
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.
1099 //
1100 ////////////////////////////////////////////////////////////////////////////
1101
GetSpnegoInitTokenMechList(unsigned char * pbTokenData,int nMechListLength,SPNEGO_ELEMENT * pSpnegoElement)1102 int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength,
1103 SPNEGO_ELEMENT* pSpnegoElement )
1104 {
1105 int nReturn = SPNEGO_E_INVALID_TOKEN;
1106 long nLength = 0L;
1107 long nActualTokenLength = 0L;
1108
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 )
1114 {
1115 // Adjust for this token
1116 nMechListLength -= nActualTokenLength;
1117 pbTokenData += nActualTokenLength;
1118
1119 // Perform simple validation of the actual MechList (i.e. ensure that
1120 // the OIDs in the MechList are reasonable).
1121
1122 if ( ( nReturn = ValidateMechList( pbTokenData, nLength ) ) == SPNEGO_E_SUCCESS )
1123 {
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;
1130 }
1131
1132 } // IF Check Token
1133
1134 return nReturn;
1135 }
1136
1137 /////////////////////////////////////////////////////////////////////////////
1138 //
1139 // Function:
1140 // InitSpnegoTokenElementFromBasicType
1141 //
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.
1149 //
1150 // Returns:
1151 // int Success - SPNEGO_E_SUCCESS
1152 // Failure - SPNEGO API Error code
1153 //
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.
1158 //
1159 ////////////////////////////////////////////////////////////////////////////
1160
InitSpnegoTokenElementFromBasicType(unsigned char * pbTokenData,int nElementLength,unsigned char ucExpectedType,SPNEGO_ELEMENT_TYPE spnegoElementType,SPNEGO_ELEMENT * pSpnegoElement)1161 int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength,
1162 unsigned char ucExpectedType,
1163 SPNEGO_ELEMENT_TYPE spnegoElementType,
1164 SPNEGO_ELEMENT* pSpnegoElement )
1165 {
1166 int nReturn = SPNEGO_E_UNEXPECTED_TYPE;
1167 long nLength = 0L;
1168 long nActualTokenLength = 0L;
1169
1170 // The type BYTE must match our token data or something is badly wrong
1171 if ( *pbTokenData == ucExpectedType )
1172 {
1173
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 )
1179 {
1180 // Adjust for this token
1181 nElementLength -= nActualTokenLength;
1182 pbTokenData += nActualTokenLength;
1183
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;
1190 }
1191
1192 } // IF type makes sense
1193
1194 return nReturn;
1195 }
1196
1197
1198 /////////////////////////////////////////////////////////////////////////////
1199 //
1200 // Function:
1201 // InitSpnegoTokenElementFromOID
1202 //
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.
1209 //
1210 // Returns:
1211 // int Success - SPNEGO_E_SUCCESS
1212 // Failure - SPNEGO API Error code
1213 //
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.
1219 //
1220 ////////////////////////////////////////////////////////////////////////////
1221
InitSpnegoTokenElementFromOID(unsigned char * pbTokenData,int nElementLength,SPNEGO_ELEMENT_TYPE spnegoElementType,SPNEGO_ELEMENT * pSpnegoElement)1222 int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength,
1223 SPNEGO_ELEMENT_TYPE spnegoElementType,
1224 SPNEGO_ELEMENT* pSpnegoElement )
1225 {
1226 int nReturn = SPNEGO_E_UNEXPECTED_TYPE;
1227 long nLength = 0L;
1228 long nActualTokenLength = 0L;
1229
1230 // The type BYTE must match our token data or something is badly wrong
1231 if ( *pbTokenData == OID )
1232 {
1233
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 )
1239 {
1240 // Don't adjust any values for this function
1241
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;
1248 }
1249
1250 } // IF type makes sense
1251
1252 return nReturn;
1253 }
1254
1255
1256 /////////////////////////////////////////////////////////////////////////////
1257 //
1258 // Function:
1259 // InitSpnegoTokenElements
1260 //
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
1266 //
1267 // Returns:
1268 // int Success - SPNEGO_E_SUCCESS
1269 // Failure - SPNEGO API Error code
1270 //
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.
1276 //
1277 ////////////////////////////////////////////////////////////////////////////
1278
InitSpnegoTokenElements(SPNEGO_TOKEN * pSpnegoToken,unsigned char * pbTokenData,long nRemainingTokenLength)1279 int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData,
1280 long nRemainingTokenLength )
1281 {
1282 //
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.
1286 //
1287
1288 static unsigned char abNegTokenInitElements[] =
1289 { SPNEGO_NEGINIT_ELEMENT_MECHTYPES, SPNEGO_NEGINIT_ELEMENT_REQFLAGS,
1290 SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC };
1291
1292 static unsigned char abNegTokenTargElements[] =
1293 { SPNEGO_NEGTARG_ELEMENT_NEGRESULT, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH,
1294 SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC };
1295
1296 int nReturn = SPNEGO_E_SUCCESS;
1297 int nCtr = 0L;
1298 long nElementLength = 0L;
1299 long nActualTokenLength = 0L;
1300 unsigned char* pbElements = NULL;
1301
1302 // Point to the correct array
1303 switch( pSpnegoToken->ucTokenType )
1304 {
1305 case SPNEGO_TOKEN_INIT:
1306 {
1307 pbElements = abNegTokenInitElements;
1308 }
1309 break;
1310
1311 case SPNEGO_TOKEN_TARG:
1312 {
1313 pbElements = abNegTokenTargElements;
1314 }
1315 break;
1316
1317 } // SWITCH tokentype
1318
1319 //
1320 // Enumerate the element arrays and look for the tokens at our current location
1321 //
1322
1323 for ( nCtr = 0L;
1324 SPNEGO_E_SUCCESS == nReturn &&
1325 nCtr < MAX_NUM_TOKEN_ELEMENTS &&
1326 nRemainingTokenLength > 0L;
1327 nCtr++ )
1328 {
1329
1330 // Check if the token exists
1331 if ( ( nReturn = ASNDerCheckToken( pbTokenData, pbElements[nCtr],
1332 0L, nRemainingTokenLength,
1333 &nElementLength, &nActualTokenLength ) )
1334 == SPNEGO_E_SUCCESS )
1335 {
1336
1337 // Token data should skip over the sequence token and then
1338 // call the appropriate function to initialize the element
1339 pbTokenData += nActualTokenLength;
1340
1341 // Lengths in the elements should NOT go beyond the element
1342 // length
1343
1344 // Different tokens mean different elements
1345 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
1346 {
1347
1348 // Handle each element as appropriate
1349 switch( pbElements[nCtr] )
1350 {
1351
1352 case SPNEGO_NEGINIT_ELEMENT_MECHTYPES:
1353 {
1354 //
1355 // This is a Mech List that specifies which OIDs the
1356 // originator of the Init Token supports.
1357 //
1358
1359 nReturn = GetSpnegoInitTokenMechList( pbTokenData, nElementLength,
1360 &pSpnegoToken->aElementArray[nCtr] );
1361
1362 }
1363 break;
1364
1365 case SPNEGO_NEGINIT_ELEMENT_REQFLAGS:
1366 {
1367 //
1368 // This is a BITSTRING which specifies the flags that the receiver
1369 // pass to the gss_accept_sec_context() function.
1370 //
1371
1372 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1373 BITSTRING, spnego_init_reqFlags,
1374 &pSpnegoToken->aElementArray[nCtr] );
1375 }
1376 break;
1377
1378 case SPNEGO_NEGINIT_ELEMENT_MECHTOKEN:
1379 {
1380 //
1381 // This is an OCTETSTRING which contains a GSSAPI token corresponding
1382 // to the first OID in the MechList.
1383 //
1384
1385 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1386 OCTETSTRING, spnego_init_mechToken,
1387 &pSpnegoToken->aElementArray[nCtr] );
1388 }
1389 break;
1390
1391 case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC: // xA3
1392 {
1393 //
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)
1400 //
1401
1402 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1403 OCTETSTRING, spnego_init_mechListMIC,
1404 &pSpnegoToken->aElementArray[nCtr] );
1405
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 );
1413 }
1414 }
1415 break;
1416
1417 } // SWITCH Element
1418 }
1419 else
1420 {
1421 /* pSpnegoToken->ucTokenType == SPNEGO_TOKEN_TARG */
1422
1423 switch( pbElements[nCtr] )
1424 {
1425
1426 case SPNEGO_NEGTARG_ELEMENT_NEGRESULT:
1427 {
1428 //
1429 // This is an ENUMERATION which specifies result of the last GSS
1430 // token negotiation call.
1431 //
1432
1433 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1434 ENUMERATED, spnego_targ_negResult,
1435 &pSpnegoToken->aElementArray[nCtr] );
1436 }
1437 break;
1438
1439 case SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH:
1440 {
1441 //
1442 // This is an OID which specifies a supported mechanism.
1443 //
1444
1445 nReturn = InitSpnegoTokenElementFromOID( pbTokenData, nElementLength,
1446 spnego_targ_mechListMIC,
1447 &pSpnegoToken->aElementArray[nCtr] );
1448 }
1449 break;
1450
1451 case SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN:
1452 {
1453 //
1454 // This is an OCTETSTRING which specifies results of the last GSS
1455 // token negotiation call.
1456 //
1457
1458 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1459 OCTETSTRING, spnego_targ_responseToken,
1460 &pSpnegoToken->aElementArray[nCtr] );
1461 }
1462 break;
1463
1464 case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC:
1465 {
1466 //
1467 // This is an OCTETSTRING, typically 16 bytes,
1468 // which contains a message integrity BLOB.
1469 //
1470
1471 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1472 OCTETSTRING, spnego_targ_mechListMIC,
1473 &pSpnegoToken->aElementArray[nCtr] );
1474 }
1475 break;
1476
1477 } // SWITCH Element
1478
1479 } // ELSE !NegTokenInit
1480
1481 // Account for the entire token and following data
1482 nRemainingTokenLength -= ( nActualTokenLength + nElementLength );
1483
1484 // Token data should skip past the element length now
1485 pbTokenData += nElementLength;
1486
1487 } // IF Token found
1488 else if ( SPNEGO_E_TOKEN_NOT_FOUND == nReturn )
1489 {
1490 // For now, this is a benign error (remember, all elements are optional, so
1491 // if we don't find one, it's okay).
1492
1493 nReturn = SPNEGO_E_SUCCESS;
1494 }
1495
1496 } // FOR enum elements
1497
1498 //
1499 // We should always run down to 0 remaining bytes in the token. If not, we've got
1500 // a bad token.
1501 //
1502
1503 if ( SPNEGO_E_SUCCESS == nReturn && nRemainingTokenLength != 0L )
1504 {
1505 nReturn = SPNEGO_E_INVALID_TOKEN;
1506 }
1507
1508 return nReturn;
1509 }
1510
1511
1512 /////////////////////////////////////////////////////////////////////////////
1513 //
1514 // Function:
1515 // FindMechOIDInMechList
1516 //
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
1522 //
1523 // Returns:
1524 // int Success - SPNEGO_E_SUCCESS
1525 // Failure - SPNEGO API Error code
1526 //
1527 // Comments :
1528 // Walks the MechList for MechOID. When it is found, the index in the
1529 // list is written to piMechTypeIndex.
1530 //
1531 ////////////////////////////////////////////////////////////////////////////
1532
FindMechOIDInMechList(SPNEGO_ELEMENT * pSpnegoElement,SPNEGO_MECH_OID MechOID,int * piMechTypeIndex)1533 int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID,
1534 int * piMechTypeIndex )
1535 {
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;
1541
1542 while( SPNEGO_E_SUCCESS != nReturn && nBoundaryLength > 0L )
1543 {
1544
1545 // Use the helper function to check the OID
1546 if ( ( nReturn = ASNDerCheckOID( pbMechListData, MechOID, nBoundaryLength, &nLength ) )
1547 == SPNEGO_E_SUCCESS )
1548 {
1549 *piMechTypeIndex = nCtr;
1550 }
1551
1552 // Adjust for the current OID
1553 pbMechListData += nLength;
1554 nBoundaryLength -= nLength;
1555 nCtr++;
1556
1557 } // WHILE enuming OIDs
1558
1559 return nReturn;
1560
1561 }
1562
1563
1564 /////////////////////////////////////////////////////////////////////////////
1565 //
1566 // Function:
1567 // ValidateMechList
1568 //
1569 // Parameters:
1570 // [in] pbMechListData - Pointer to binary MechList data
1571 // [in] nBoundaryLength - Length we must not exceed
1572 //
1573 // Returns:
1574 // int Success - SPNEGO_E_SUCCESS
1575 // Failure - SPNEGO API Error code
1576 //
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.
1581 //
1582 ////////////////////////////////////////////////////////////////////////////
1583
ValidateMechList(unsigned char * pbMechListData,long nBoundaryLength)1584 int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength )
1585 {
1586 int nReturn = SPNEGO_E_SUCCESS;
1587 long nLength = 0L;
1588 long nTokenLength = 0L;
1589
1590 while( SPNEGO_E_SUCCESS == nReturn && nBoundaryLength > 0L )
1591 {
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 );
1597
1598 // Adjust for the current OID
1599 pbMechListData += ( nLength + nTokenLength );
1600 nBoundaryLength -= ( nLength + nTokenLength );
1601
1602 } // WHILE enuming OIDs
1603
1604 return nReturn;
1605
1606 }
1607
1608 /////////////////////////////////////////////////////////////////////////////
1609 //
1610 // Function:
1611 // IsValidMechOid
1612 //
1613 // Parameters:
1614 // [in] mechOid - mechOID id enumeration
1615 //
1616 // Returns:
1617 // int Success - 1
1618 // Failure - 0
1619 //
1620 // Comments :
1621 // Checks for a valid mechOid value.
1622 //
1623 ////////////////////////////////////////////////////////////////////////////
1624
IsValidMechOid(SPNEGO_MECH_OID mechOid)1625 int IsValidMechOid( SPNEGO_MECH_OID mechOid )
1626 {
1627 return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy &&
1628 mechOid <= spnego_mech_oid_NTLMSSP );
1629 }
1630
1631 /////////////////////////////////////////////////////////////////////////////
1632 //
1633 // Function:
1634 // IsValidContextFlags
1635 //
1636 // Parameters:
1637 // [in] ucContextFlags - ContextFlags value
1638 //
1639 // Returns:
1640 // int Success - 1
1641 // Failure - 0
1642 //
1643 // Comments :
1644 // Checks for a valid ContextFlags value.
1645 //
1646 ////////////////////////////////////////////////////////////////////////////
1647
IsValidContextFlags(unsigned char ucContextFlags)1648 int IsValidContextFlags( unsigned char ucContextFlags )
1649 {
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 );
1653 }
1654
1655 /////////////////////////////////////////////////////////////////////////////
1656 //
1657 // Function:
1658 // IsValidNegResult
1659 //
1660 // Parameters:
1661 // [in] negResult - NegResult value
1662 //
1663 // Returns:
1664 // int Success - 1
1665 // Failure - 0
1666 //
1667 // Comments :
1668 // Checks for a valid NegResult value.
1669 //
1670 ////////////////////////////////////////////////////////////////////////////
1671
IsValidNegResult(SPNEGO_NEGRESULT negResult)1672 int IsValidNegResult( SPNEGO_NEGRESULT negResult )
1673 {
1674 return ( negResult >= spnego_negresult_success &&
1675 negResult <= spnego_negresult_rejected );
1676 }
1677
1678 /////////////////////////////////////////////////////////////////////////////
1679 //
1680 // Function:
1681 // IsValidSpnegoToken
1682 //
1683 // Parameters:
1684 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1685 //
1686 // Returns:
1687 // int Success - 1
1688 // Failure - 0
1689 //
1690 // Comments :
1691 // Performs simple heuristic on location pointed to by pSpnegoToken.
1692 //
1693 ////////////////////////////////////////////////////////////////////////////
1694
IsValidSpnegoToken(SPNEGO_TOKEN * pSpnegoToken)1695 int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken )
1696 {
1697 int nReturn = 0;
1698
1699 // Parameter should be non-NULL
1700 if ( NULL != pSpnegoToken )
1701 {
1702 // Length should be at least the size defined in the header
1703 if ( pSpnegoToken->nStructSize >= SPNEGO_TOKEN_SIZE )
1704 {
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 )
1708 {
1709 // Check for proper token type
1710 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ||
1711 SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
1712 {
1713 nReturn = 1;
1714 }
1715 }
1716
1717 } // IF struct size makes sense
1718
1719 } // IF non-NULL spnego Token
1720
1721 return nReturn;
1722 }
1723
1724 /////////////////////////////////////////////////////////////////////////////
1725 //
1726 // Function:
1727 // IsValidSpnegoElement
1728 //
1729 // Parameters:
1730 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1731 // [in] spnegoElement - spnegoElement Type from enumeration
1732 //
1733 // Returns:
1734 // int Success - 1
1735 // Failure - 0
1736 //
1737 // Comments :
1738 // Checks that spnegoElement has a valid value and is appropriate for
1739 // the SPNEGO token encapsulated by pSpnegoToken.
1740 //
1741 ////////////////////////////////////////////////////////////////////////////
1742
IsValidSpnegoElement(SPNEGO_TOKEN * pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement)1743 int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement )
1744 {
1745 int nReturn = 0;
1746
1747 // Check boundaries
1748 if ( spnegoElement > spnego_element_min &&
1749 spnegoElement < spnego_element_max )
1750 {
1751
1752 // Check for appropriateness to token type
1753 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
1754 {
1755 nReturn = ( spnegoElement >= spnego_init_mechtypes &&
1756 spnegoElement <= spnego_init_mechListMIC );
1757 }
1758 else
1759 {
1760 nReturn = ( spnegoElement >= spnego_targ_negResult &&
1761 spnegoElement <= spnego_targ_mechListMIC );
1762 }
1763
1764 } // IF boundary conditions are met
1765
1766 return nReturn;
1767 }
1768
1769 /////////////////////////////////////////////////////////////////////////////
1770 //
1771 // Function:
1772 // CalculateElementArrayIndex
1773 //
1774 // Parameters:
1775 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1776 // [in] spnegoElement - spnegoElement Type from enumeration
1777 //
1778 // Returns:
1779 // int index in the SPNEGO_TOKEN element array that the element can
1780 // can be found
1781 //
1782 // Comments :
1783 // Based on the Token Type, calculates the index in the element array
1784 // at which the specified element can be found.
1785 //
1786 ////////////////////////////////////////////////////////////////////////////
1787
CalculateElementArrayIndex(SPNEGO_TOKEN * pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement)1788 int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement )
1789 {
1790 int nReturn = 0;
1791
1792 // Offset is difference between value and initial element identifier
1793 // (these differ based on ucTokenType)
1794
1795 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
1796 {
1797 nReturn = spnegoElement - spnego_init_mechtypes;
1798 }
1799 else
1800 {
1801 nReturn = spnegoElement - spnego_targ_negResult;
1802 }
1803
1804 return nReturn;
1805 }
1806
1807 /////////////////////////////////////////////////////////////////////////////
1808 //
1809 // Function:
1810 // InitTokenFromBinary
1811 //
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
1819 //
1820 // Returns:
1821 // int Success - SPNEGO_E_SUCCESS
1822 // Failure - SPNEGO API Error code
1823 //
1824 // Comments :
1825 // Allocates a SPNEGO_TOKEN data structure and fills it out as
1826 // appropriate based in the flags passed into the function.
1827 //
1828 ////////////////////////////////////////////////////////////////////////////
1829
1830
1831 // Initializes SPNEGO_TOKEN structure from DER encoded binary data
InitTokenFromBinary(unsigned char ucCopyData,unsigned long ulFlags,unsigned char * pbTokenData,unsigned long ulLength,SPNEGO_TOKEN ** ppSpnegoToken)1832 int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags,
1833 unsigned char* pbTokenData, unsigned long ulLength,
1834 SPNEGO_TOKEN** ppSpnegoToken )
1835 {
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;
1841
1842 // Basic Parameter Validation
1843
1844 if ( NULL != pbTokenData &&
1845 NULL != ppSpnegoToken &&
1846 0L != ulLength )
1847 {
1848
1849 //
1850 // Allocate the empty token, then initialize the data structure.
1851 //
1852
1853 pSpnegoToken = AllocEmptySpnegoToken( ucCopyData, ulFlags, pbTokenData, ulLength );
1854
1855 if ( NULL != pSpnegoToken )
1856 {
1857
1858 // Copy the binary data locally
1859
1860
1861 // Initialize the token type
1862 if ( ( nReturn = InitSpnegoTokenType( pSpnegoToken, &nTokenLength,
1863 &nRemainingTokenLength, &pbFirstElement ) )
1864 == SPNEGO_E_SUCCESS )
1865 {
1866
1867 // Initialize the element array
1868 if ( ( nReturn = InitSpnegoTokenElements( pSpnegoToken, pbFirstElement,
1869 nRemainingTokenLength ) )
1870 == SPNEGO_E_SUCCESS )
1871 {
1872 *ppSpnegoToken = pSpnegoToken;
1873 }
1874
1875 } // IF Init Token Type
1876
1877 // Cleanup on error condition
1878 if ( SPNEGO_E_SUCCESS != nReturn )
1879 {
1880 spnegoFreeData( pSpnegoToken );
1881 }
1882
1883 }
1884 else
1885 {
1886 nReturn = SPNEGO_E_OUT_OF_MEMORY;
1887 }
1888
1889 } // IF Valid parameters
1890
1891
1892 return nReturn;
1893 }
1894