1 // Copyright 2022 RackTop Systems, Inc.
2 // Copyright 2012 Nexenta Systems, Inc. All rights reserved.
3 // Copyright (C) 2002 Microsoft Corporation
4 // All rights reserved.
5 //
6 // THIS CODE AND INFORMATION IS PROVIDED "AS IS"
7 // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
8 // OR IMPLIED, INCLUDING BUT NOT LIMITED
9 // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
10 // AND/OR FITNESS FOR A PARTICULAR PURPOSE.
11 //
12 // Date - 10/08/2002
13 // Author - Sanj Surati
14
15 /////////////////////////////////////////////////////////////
16 //
17 // SPNEGOPARSE.C
18 //
19 // SPNEGO Token Handler Source File
20 //
21 // Contains implementation of SPNEGO Token parsing functions.
22 //
23 /////////////////////////////////////////////////////////////
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <memory.h>
28 #include "spnego.h"
29 #include "derparse.h"
30 #include "spnegoparse.h"
31
32 //
33 // Defined in DERPARSE.C
34 //
35
36 extern MECH_OID g_stcMechOIDList [];
37
38 /**********************************************************************/
39 /** **/
40 /** **/
41 /** **/
42 /** **/
43 /** Local SPNEGO Helper definitions **/
44 /** **/
45 /** **/
46 /** **/
47 /** **/
48 /**********************************************************************/
49
50
51 /////////////////////////////////////////////////////////////////////////////
52 //
53 // Function:
54 // CalculateMinSpnegoInitTokenSize
55 //
56 // Parameters:
57 // [in] nMechTokenLength - Length of the MechToken Element
58 // [in] nMechListMICLength - Length of the MechListMIC Element
59 // (or negHints, if no MechToken)
60 // [in] mechOID - OID for MechList
61 // [in] nReqFlagsAvailable - Is ContextFlags element available
62 // [out] pnTokenSize - Filled out with total size of token
63 // [out] pnInternalTokenLength - Filled out with length minus length
64 // for initial token.
65 //
66 // Returns:
67 // int Success - SPNEGO_E_SUCCESS
68 // Failure - SPNEGO API Error code
69 //
70 // Comments :
71 // Calculates the required length for a SPNEGO NegTokenInit token based
72 // on the supplied variable length values and which elements are present.
73 // Note that because the lengths can be represented by an arbitrary
74 // number of bytes in DER encodings, we actually calculate the lengths
75 // backwards, so we always know how many bytes we will potentially be
76 // writing out.
77 //
78 ////////////////////////////////////////////////////////////////////////////
79
CalculateMinSpnegoInitTokenSize(long nMechTokenLength,long nMechListMICLength,SPNEGO_MECH_OID * mechOidLst,int mechOidCnt,int nReqFlagsAvailable,long * pnTokenSize,long * pnInternalTokenLength)80 int CalculateMinSpnegoInitTokenSize( long nMechTokenLength,
81 long nMechListMICLength, SPNEGO_MECH_OID *mechOidLst, int mechOidCnt,
82 int nReqFlagsAvailable, long* pnTokenSize,
83 long* pnInternalTokenLength )
84 {
85 int nReturn = SPNEGO_E_INVALID_LENGTH;
86
87 // Start at 0.
88 long nTotalLength = 0;
89 long nTempLength= 0L;
90
91 // We will calculate this by walking the token backwards
92
93 // Start with MIC Element (or negHints)
94 if ( nMechListMICLength > 0L )
95 {
96 nTempLength = ASNDerCalcElementLength( nMechListMICLength, NULL );
97
98 // Check for rollover error
99 if ( nTempLength < nMechListMICLength )
100 {
101 goto xEndTokenInitLength;
102 }
103
104 nTotalLength += nTempLength;
105 }
106
107 // Next is the MechToken
108 if ( nMechTokenLength > 0L )
109 {
110 nTempLength += ASNDerCalcElementLength( nMechTokenLength, NULL );
111
112 // Check for rollover error
113 if ( nTempLength < nTotalLength )
114 {
115 goto xEndTokenInitLength;
116 }
117
118 nTotalLength = nTempLength;
119 }
120
121 // Next is the ReqFlags
122 if ( nReqFlagsAvailable )
123 {
124 nTempLength += ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, NULL );
125
126 // Check for rollover error
127 if ( nTempLength < nTotalLength )
128 {
129 goto xEndTokenInitLength;
130 }
131
132 nTotalLength = nTempLength;
133 }
134
135 // Next is the MechList - This is REQUIRED
136 nTempLength += ASNDerCalcMechListLength( mechOidLst, mechOidCnt, NULL );
137
138 // Check for rollover error
139 if ( nTempLength < nTotalLength )
140 {
141 goto xEndTokenInitLength;
142 }
143
144 nTotalLength = nTempLength;
145
146 // Following four fields are the basic header tokens
147
148 // Sequence Token
149 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
150
151 // Check for rollover error
152 if ( nTempLength < nTotalLength )
153 {
154 goto xEndTokenInitLength;
155 }
156
157 nTotalLength = nTempLength;
158
159 // Neg Token Identifier Token
160 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
161
162 // Check for rollover error
163 if ( nTempLength < nTotalLength )
164 {
165 goto xEndTokenInitLength;
166 }
167
168 nTotalLength = nTempLength;
169
170 // SPNEGO OID Token
171 nTempLength += g_stcMechOIDList[spnego_mech_oid_Spnego].iLen;
172
173 // Check for rollover error
174 if ( nTempLength < nTotalLength )
175 {
176 goto xEndTokenInitLength;
177 }
178
179 nTotalLength = nTempLength;
180
181 // App Constructed Token
182 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
183
184 // Check for rollover error
185 if ( nTempLength < nTotalLength )
186 {
187 goto xEndTokenInitLength;
188 }
189
190 // The internal length doesn't include the number of bytes
191 // for the initial token
192 *pnInternalTokenLength = nTotalLength;
193 nTotalLength = nTempLength;
194
195 // We're done
196 *pnTokenSize = nTotalLength;
197 nReturn = SPNEGO_E_SUCCESS;
198
199 xEndTokenInitLength:
200
201 return nReturn;
202
203 }
204
205 /////////////////////////////////////////////////////////////////////////////
206 //
207 // Function:
208 // CreateSpnegoInitToken
209 //
210 // Parameters:
211 // [in] pMechTypeList - OID array
212 // [in] MechTypeCnt - OID array length
213 // [in] ucContextFlags - ContextFlags value
214 // [in] pbMechToken - Mech Token Binary Data
215 // [in] ulMechTokenLen - Length of Mech Token
216 // [in] pbMechListMIC - MechListMIC Binary Data (or negHints)
217 // [in] ulMechListMICn - Length of MechListMIC
218 // [out] pbTokenData - Buffer to write token into.
219 // [in] nTokenLength - Length of pbTokenData buffer
220 // [in] nInternalTokenLength - Length of full token without leading
221 // token bytes.
222 //
223 // Returns:
224 // int Success - SPNEGO_E_SUCCESS
225 // Failure - SPNEGO API Error code
226 //
227 // Comments :
228 // Uses DER to fill out pbTokenData with a SPNEGO NegTokenInit Token
229 // Note that because the lengths can be represented by an arbitrary
230 // number of bytes in DER encodings, we actually calculate the lengths
231 // backwards, so we always know how many bytes we will potentially be
232 // writing out.
233 //
234 // This function is also used to create an SPNEGO "hint", as described in
235 // [MS-SPNG] sec. 2.2.1 negTokenInit2. The "hint" looks almost identical
236 // to a NegTokenInit, but has a "negHints" field inserted before the MIC.
237 // A normal SPNEGO negTokenInit2 contains only the mech list and the
238 // negHints. To avoid a giant copy/paste of this function, we pass the
239 // negHints as the MIC arg, and pass NULL as the MechToken to indicate
240 // that we're creating a Hint rather than an Init, and use the correct
241 // type when writing out the MIC (or negHints) element.
242 //
243 ////////////////////////////////////////////////////////////////////////////
244
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)245 int CreateSpnegoInitToken( SPNEGO_MECH_OID *pMechTypeList, long MechTypeCnt,
246 unsigned char ucContextFlags, unsigned char* pbMechToken,
247 unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
248 unsigned long ulMechListMICLen, unsigned char* pbTokenData,
249 long nTokenLength, long nInternalTokenLength )
250 {
251 int nReturn = SPNEGO_E_INVALID_LENGTH;
252
253 // Start at 0.
254 long nTempLength= 0L;
255 long nTotalBytesWritten = 0L;
256 long nInternalLength = 0L;
257
258 unsigned char* pbWriteTokenData = pbTokenData + nTokenLength;
259
260 // Temporary buffer to hold the REQ Flags as BIT String Data
261 unsigned char abTempReqFlags[SPNEGO_NEGINIT_MAXLEN_REQFLAGS];
262
263
264 // We will write the token out backwards to properly handle the cases
265 // where the length bytes become adjustable
266
267 // Start with MIC Element (or negHints)
268 if ( ulMechListMICLen > 0L )
269 {
270 unsigned char ucType;
271 nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength );
272
273 // Decrease the pbWriteTokenData, now we know the length and write it out.
274 // Note: When MechTokenLen == 0, we're writing a negTokenInit2 and the
275 // MIC arg is really negHints, written as a constructed sequence.
276 // Otherwise we're writing a negTokenInit, and the MIC is an OCTETSTRING.
277 ucType = (ulMechTokenLen == 0) ?
278 SPNEGO_CONSTRUCTED_SEQUENCE : OCTETSTRING;
279
280 pbWriteTokenData -= nTempLength;
281 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC,
282 ucType, pbMechListMIC, ulMechListMICLen );
283
284 // Adjust Values and sanity check
285 nTotalBytesWritten += nTempLength;
286 nInternalTokenLength -= nTempLength;
287
288 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
289 {
290 goto xEndWriteNegTokenInit;
291 }
292
293 } // IF MechListMIC is present
294
295 // Next is the MechToken
296 if ( ulMechTokenLen > 0L )
297 {
298 nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength );
299
300 // Decrease the pbWriteTokenData, now we know the length and
301 // write it out.
302 pbWriteTokenData -= nTempLength;
303 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHTOKEN,
304 OCTETSTRING, pbMechToken, ulMechTokenLen );
305 // Adjust Values and sanity check
306 nTotalBytesWritten += nTempLength;
307 nInternalTokenLength -= nTempLength;
308
309 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
310 {
311 goto xEndWriteNegTokenInit;
312 }
313
314 } // IF MechToken Length is present
315
316 // Next is the ReqFlags
317 if ( ucContextFlags > 0L )
318 {
319
320 nTempLength = ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, &nInternalLength );
321
322 // We need a byte that indicates how many bits difference between the number
323 // of bits used in final octet (we only have one) and the max (8)
324
325 abTempReqFlags[0] = SPNEGO_NEGINIT_REQFLAGS_BITDIFF;
326 abTempReqFlags[1] = ucContextFlags;
327
328 // Decrease the pbWriteTokenData, now we know the length and
329 // write it out.
330 pbWriteTokenData -= nTempLength;
331 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_REQFLAGS,
332 BITSTRING, abTempReqFlags, SPNEGO_NEGINIT_MAXLEN_REQFLAGS );
333
334 // Adjust Values and sanity check
335 nTotalBytesWritten += nTempLength;
336 nInternalTokenLength -= nTempLength;
337
338 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
339 {
340 goto xEndWriteNegTokenInit;
341 }
342
343 } // IF ContextFlags
344
345 // Next is the MechList - This is REQUIRED
346 nTempLength = ASNDerCalcMechListLength( pMechTypeList, MechTypeCnt, &nInternalLength );
347
348 // Decrease the pbWriteTokenData, now we know the length and
349 // write it out.
350 pbWriteTokenData -= nTempLength;
351 nTempLength = ASNDerWriteMechList( pbWriteTokenData, pMechTypeList, MechTypeCnt );
352
353 // Adjust Values and sanity check
354 nTotalBytesWritten += nTempLength;
355 nInternalTokenLength -= nTempLength;
356
357 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
358 {
359 goto xEndWriteNegTokenInit;
360 }
361
362 // The next tokens we're writing out reflect the total number of bytes
363 // we have actually written out.
364
365 // Sequence Token
366 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
367
368 // Decrease the pbWriteTokenData, now we know the length and
369 // write it out.
370 pbWriteTokenData -= nTempLength;
371 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
372 NULL, nTotalBytesWritten );
373
374 // Adjust Values and sanity check
375 nTotalBytesWritten += nTempLength;
376 nInternalTokenLength -= nTempLength;
377
378 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
379 {
380 goto xEndWriteNegTokenInit;
381 }
382
383 // Neg Init Token Identifier Token
384 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
385
386 // Decrease the pbWriteTokenData, now we know the length and
387 // write it out.
388 pbWriteTokenData -= nTempLength;
389 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER,
390 NULL, nTotalBytesWritten );
391
392 // Adjust Values and sanity check
393 nTotalBytesWritten += nTempLength;
394 nInternalTokenLength -= nTempLength;
395
396 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
397 {
398 goto xEndWriteNegTokenInit;
399 }
400
401 // SPNEGO OID Token
402 nTempLength = g_stcMechOIDList[spnego_mech_oid_Spnego].iLen;
403
404 // Decrease the pbWriteTokenData, now we know the length and
405 // write it out.
406 pbWriteTokenData -= nTempLength;
407 nTempLength = ASNDerWriteOID( pbWriteTokenData, spnego_mech_oid_Spnego );
408
409 // Adjust Values and sanity check
410 nTotalBytesWritten += nTempLength;
411 nInternalTokenLength -= nTempLength;
412
413 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
414 {
415 goto xEndWriteNegTokenInit;
416 }
417
418 // App Constructed Token
419 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
420
421 // Decrease the pbWriteTokenData, now we know the length and
422 // write it out.
423 pbWriteTokenData -= nTempLength;
424 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT,
425 NULL, nTotalBytesWritten );
426
427 // Adjust Values and sanity check
428 nTotalBytesWritten += nTempLength;
429
430 // Don't adjust the internal token length here, it doesn't account
431 // the initial bytes written out (we really don't need to keep
432 // a running count here, but for debugging, it helps to be able
433 // to see the total number of bytes written out as well as the
434 // number of bytes left to write).
435
436 if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 &&
437 pbWriteTokenData == pbTokenData )
438 {
439 nReturn = SPNEGO_E_SUCCESS;
440 }
441
442 xEndWriteNegTokenInit:
443
444 return nReturn;
445
446 }
447
448 /////////////////////////////////////////////////////////////////////////////
449 //
450 // Function:
451 // CalculateMinSpnegoTargTokenSize
452 //
453 // Parameters:
454 // [in] MechType - Supported MechType
455 // [in] spnegoNegResult - Neg Result
456 // [in] nMechTokenLength - Length of the MechToken Element
457 // [in] nMechListMICLength - Length of the MechListMIC Element
458 // [out] pnTokenSize - Filled out with total size of token
459 // [out] pnInternalTokenLength - Filled out with length minus length
460 // for initial token.
461 //
462 // Returns:
463 // int Success - SPNEGO_E_SUCCESS
464 // Failure - SPNEGO API Error code
465 //
466 // Comments :
467 // Calculates the required length for a SPNEGO NegTokenTarg token based
468 // on the supplied variable length values and which elements are present.
469 // Note that because the lengths can be represented by an arbitrary
470 // number of bytes in DER encodings, we actually calculate the lengths
471 // backwards, so we always know how many bytes we will potentially be
472 // writing out.
473 //
474 ////////////////////////////////////////////////////////////////////////////
475
CalculateMinSpnegoTargTokenSize(SPNEGO_MECH_OID MechType,SPNEGO_NEGRESULT spnegoNegResult,long nMechTokenLen,long nMechListMICLen,long * pnTokenSize,long * pnInternalTokenLength)476 int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType,
477 SPNEGO_NEGRESULT spnegoNegResult, long nMechTokenLen,
478 long nMechListMICLen, long* pnTokenSize,
479 long* pnInternalTokenLength )
480 {
481 int nReturn = SPNEGO_E_INVALID_LENGTH;
482
483 // Start at 0.
484 long nTotalLength = 0;
485 long nTempLength= 0L;
486
487 // We will calculate this by walking the token backwards
488
489 // Start with MIC Element
490 if ( nMechListMICLen > 0L )
491 {
492 nTempLength = ASNDerCalcElementLength( nMechListMICLen, NULL );
493
494 // Check for rollover error
495 if ( nTempLength < nMechListMICLen )
496 {
497 goto xEndTokenTargLength;
498 }
499
500 nTotalLength += nTempLength;
501 }
502
503 // Next is the MechToken
504 if ( nMechTokenLen > 0L )
505 {
506 nTempLength += ASNDerCalcElementLength( nMechTokenLen, NULL );
507
508 // Check for rollover error
509 if ( nTempLength < nTotalLength )
510 {
511 goto xEndTokenTargLength;
512 }
513
514 nTotalLength = nTempLength;
515 }
516
517 // Supported MechType
518 if ( spnego_mech_oid_NotUsed != MechType )
519 {
520 // Supported MechOID element - we use the token function since
521 // we already know the size of the OID token and value
522 nTempLength += ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen,
523 NULL );
524
525 // Check for rollover error
526 if ( nTempLength < nTotalLength )
527 {
528 goto xEndTokenTargLength;
529 }
530
531 nTotalLength = nTempLength;
532
533 } // IF MechType is available
534
535 // NegResult Element
536 if ( spnego_negresult_NotUsed != spnegoNegResult )
537 {
538 nTempLength += ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, NULL );
539
540 // Check for rollover error
541 if ( nTempLength < nTotalLength )
542 {
543 goto xEndTokenTargLength;
544 }
545
546 nTotalLength = nTempLength;
547
548 } // IF negResult is available
549
550 // Following two fields are the basic header tokens
551
552 // Sequence Token
553 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
554
555 // Check for rollover error
556 if ( nTempLength < nTotalLength )
557 {
558 goto xEndTokenTargLength;
559 }
560
561 nTotalLength = nTempLength;
562
563 // Neg Token Identifier Token
564 nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
565
566 // Check for rollover error
567 if ( nTempLength < nTotalLength )
568 {
569 goto xEndTokenTargLength;
570 }
571
572 // The internal length doesn't include the number of bytes
573 // for the initial token
574 *pnInternalTokenLength = nTotalLength;
575 nTotalLength = nTempLength;
576
577 // We're done
578 *pnTokenSize = nTotalLength;
579 nReturn = SPNEGO_E_SUCCESS;
580
581 xEndTokenTargLength:
582
583 return nReturn;
584
585 }
586
587 /////////////////////////////////////////////////////////////////////////////
588 //
589 // Function:
590 // CreateSpnegoTargToken
591 //
592 // Parameters:
593 // [in] MechType - Supported MechType
594 // [in] eNegResult - NegResult value
595 // [in] pbMechToken - Mech Token Binary Data
596 // [in] ulMechTokenLen - Length of Mech Token
597 // [in] pbMechListMIC - MechListMIC Binary Data
598 // [in] ulMechListMICn - Length of MechListMIC
599 // [out] pbTokenData - Buffer to write token into.
600 // [in] nTokenLength - Length of pbTokenData buffer
601 // [in] nInternalTokenLength - Length of full token without leading
602 // token bytes.
603 //
604 // Returns:
605 // int Success - SPNEGO_E_SUCCESS
606 // Failure - SPNEGO API Error code
607 //
608 // Comments :
609 // Uses DER to fill out pbTokenData with a SPNEGO NegTokenTarg Token
610 // Note that because the lengths can be represented by an arbitrary
611 // number of bytes in DER encodings, we actually calculate the lengths
612 // backwards, so we always know how many bytes we will potentially be
613 // writing out.
614 //
615 ////////////////////////////////////////////////////////////////////////////
616
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)617 int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType,
618 SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken,
619 unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
620 unsigned long ulMechListMICLen, unsigned char* pbTokenData,
621 long nTokenLength, long nInternalTokenLength )
622 {
623 int nReturn = SPNEGO_E_INVALID_LENGTH;
624
625 // Start at 0.
626 long nTempLength= 0L;
627 long nTotalBytesWritten = 0L;
628 long nInternalLength = 0L;
629
630 unsigned char ucTemp = 0;
631
632 // We will write the token out backwards to properly handle the cases
633 // where the length bytes become adjustable, so the write location
634 // is initialized to point *just* past the end of the buffer.
635
636 unsigned char* pbWriteTokenData = pbTokenData + nTokenLength;
637
638
639 // Start with MIC Element
640 if ( ulMechListMICLen > 0L )
641 {
642 nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength );
643
644 // Decrease the pbWriteTokenData, now we know the length and
645 // write it out.
646
647 pbWriteTokenData -= nTempLength;
648 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC,
649 OCTETSTRING, pbMechListMIC, ulMechListMICLen );
650
651 // Adjust Values and sanity check
652 nTotalBytesWritten += nTempLength;
653 nInternalTokenLength -= nTempLength;
654
655 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
656 {
657 goto xEndWriteNegTokenTarg;
658 }
659
660 } // IF MechListMIC is present
661
662 // Next is the MechToken
663 if ( ulMechTokenLen > 0L )
664 {
665 nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength );
666
667 // Decrease the pbWriteTokenData, now we know the length and
668 // write it out.
669 pbWriteTokenData -= nTempLength;
670 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN,
671 OCTETSTRING, pbMechToken, ulMechTokenLen );
672 // Adjust Values and sanity check
673 nTotalBytesWritten += nTempLength;
674 nInternalTokenLength -= nTempLength;
675
676 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
677 {
678 goto xEndWriteNegTokenTarg;
679 }
680
681 } // IF MechToken Length is present
682
683 // Supported Mech Type
684 if ( spnego_mech_oid_NotUsed != MechType )
685 {
686
687 nTempLength = ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen,
688 &nInternalLength );
689
690 // Decrease the pbWriteTokenData, now we know the length and
691 // write it out.
692 pbWriteTokenData -= nTempLength;
693 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH,
694 g_stcMechOIDList[MechType].ucOid,
695 g_stcMechOIDList[MechType].iLen );
696
697 // Adjust Values and sanity check
698 nTotalBytesWritten += nTempLength;
699 nInternalTokenLength -= nTempLength;
700
701 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
702 {
703 goto xEndWriteNegTokenTarg;
704 }
705
706 } // IF MechType is present
707
708 // Neg Result
709 // NegResult Element
710 if ( spnego_negresult_NotUsed != eNegResult )
711 {
712 ucTemp = (unsigned char) eNegResult;
713
714 nTempLength = ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, &nInternalLength );
715
716 // Decrease the pbWriteTokenData, now we know the length and
717 // write it out.
718 pbWriteTokenData -= nTempLength;
719 nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_NEGRESULT,
720 ENUMERATED, &ucTemp, SPNEGO_NEGTARG_MAXLEN_NEGRESULT );
721
722 // Adjust Values and sanity check
723 nTotalBytesWritten += nTempLength;
724 nInternalTokenLength -= nTempLength;
725
726 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
727 {
728 goto xEndWriteNegTokenTarg;
729 }
730
731 } // If eNegResult is available
732
733 // The next tokens we're writing out reflect the total number of bytes
734 // we have actually written out.
735
736 // Sequence Token
737 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
738
739 // Decrease the pbWriteTokenData, now we know the length and
740 // write it out.
741 pbWriteTokenData -= nTempLength;
742 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
743 NULL, nTotalBytesWritten );
744
745 // Adjust Values and sanity check
746 nTotalBytesWritten += nTempLength;
747 nInternalTokenLength -= nTempLength;
748
749 if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
750 {
751 goto xEndWriteNegTokenTarg;
752 }
753
754 // Neg Targ Token Identifier Token
755 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
756
757 // Decrease the pbWriteTokenData, now we know the length and
758 // write it out.
759 pbWriteTokenData -= nTempLength;
760 nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER,
761 NULL, nTotalBytesWritten );
762
763 // Adjust Values and sanity check
764 nTotalBytesWritten += nTempLength;
765
766 // Don't adjust the internal token length here, it doesn't account
767 // the initial bytes written out (we really don't need to keep
768 // a running count here, but for debugging, it helps to be able
769 // to see the total number of bytes written out as well as the
770 // number of bytes left to write).
771
772 if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 &&
773 pbWriteTokenData == pbTokenData )
774 {
775 nReturn = SPNEGO_E_SUCCESS;
776 }
777
778
779 xEndWriteNegTokenTarg:
780
781 return nReturn;
782
783
784 }
785
786
787 /////////////////////////////////////////////////////////////////////////////
788 //
789 // Function:
790 // AllocEmptySpnegoToken
791 //
792 // Parameters:
793 // [in] ucCopyData - Flag to copy data or pointer.
794 // [in] ulFlags - Flags for SPNEGO_TOKEN data member.
795 // [in] pbTokenData - Binary token data.
796 // [in] ulTokenSize - Size of pbTokenData.
797 //
798 // Returns:
799 // SPNEGO_TOKEN* Success - Pointer to initialized SPNEGO_TOKEN struct
800 // Failure - NULL
801 //
802 // Comments :
803 // Allocates a SPNEGO_TOKEN data structure and initializes it. Based on
804 // the value of ucCopyData, if non-zero, we copy the data into a buffer
805 // we allocate in this function, otherwise, we copy the data pointer
806 // direcly.
807 //
808 ////////////////////////////////////////////////////////////////////////////
809
AllocEmptySpnegoToken(unsigned char ucCopyData,unsigned long ulFlags,unsigned char * pbTokenData,unsigned long ulTokenSize)810 SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags,
811 unsigned char * pbTokenData, unsigned long ulTokenSize )
812 {
813 SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) calloc( 1, sizeof(SPNEGO_TOKEN) );
814
815 if ( NULL != pSpnegoToken )
816 {
817 // Set the token size
818 pSpnegoToken->nStructSize = SPNEGO_TOKEN_SIZE;
819
820 // Initialize the element array
821 InitSpnegoTokenElementArray( pSpnegoToken );
822
823 // Assign the flags value
824 pSpnegoToken->ulFlags = ulFlags;
825
826 //
827 // IF ucCopyData is TRUE, we will allocate a buffer and copy data into it.
828 // Otherwise, we will just copy the pointer and the length. This is so we
829 // can cut out additional allocations for performance reasons
830 //
831
832 if ( SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA == ucCopyData )
833 {
834 // Alloc the internal buffer. Cleanup on failure.
835 pSpnegoToken->pbBinaryData = (unsigned char*) calloc( ulTokenSize, sizeof(unsigned char) );
836
837 if ( NULL != pSpnegoToken->pbBinaryData )
838 {
839 // We must ALWAYS free this buffer
840 pSpnegoToken->ulFlags |= SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA;
841
842 // Copy the data locally
843 memcpy( pSpnegoToken->pbBinaryData, pbTokenData, ulTokenSize );
844 pSpnegoToken->ulBinaryDataLen = ulTokenSize;
845 }
846 else
847 {
848 free( pSpnegoToken );
849 pSpnegoToken = NULL;
850 }
851
852 } // IF ucCopyData
853 else
854 {
855 // Copy the pointer and the length directly - ulFlags will control whether or not
856 // we are allowed to free the value
857
858 pSpnegoToken->pbBinaryData = pbTokenData;
859 pSpnegoToken->ulBinaryDataLen = ulTokenSize;
860 }
861
862 }
863
864 return pSpnegoToken;
865 }
866
867 /////////////////////////////////////////////////////////////////////////////
868 //
869 // Function:
870 // FreeSpnegoToken
871 //
872 // Parameters:
873 // [in] pSpnegoToken - Points to SPNEGO_TOKEN to free.
874 //
875 // Returns:
876 // void
877 //
878 // Comments :
879 // If non-NULL, interprets pSpnegoToken, freeing any internal allocations
880 // and finally the actual structure.
881 //
882 ////////////////////////////////////////////////////////////////////////////
883
FreeSpnegoToken(SPNEGO_TOKEN * pSpnegoToken)884 void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken )
885 {
886 if ( NULL != pSpnegoToken )
887 {
888
889 // Cleanup internal allocation per the flags
890 if ( pSpnegoToken->ulFlags & SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA &&
891 NULL != pSpnegoToken->pbBinaryData )
892 {
893 free( pSpnegoToken->pbBinaryData );
894 pSpnegoToken->pbBinaryData = NULL;
895 }
896
897 free ( pSpnegoToken );
898 }
899 }
900
901 /////////////////////////////////////////////////////////////////////////////
902 //
903 // Function:
904 // InitSpnegoTokenElementArray
905 //
906 // Parameters:
907 // [in] pSpnegoToken - Points to SPNEGO_TOKEN structure.
908 //
909 // Returns:
910 // void
911 //
912 // Comments :
913 // Initializes the element array data member of a SPNEGO_TOKEN data
914 // structure.
915 //
916 ////////////////////////////////////////////////////////////////////////////
917
InitSpnegoTokenElementArray(SPNEGO_TOKEN * pSpnegoToken)918 void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken )
919 {
920 int nCtr;
921
922 // Set the number of elemnts
923 pSpnegoToken->nNumElements = MAX_NUM_TOKEN_ELEMENTS;
924
925 //
926 // Initially, all elements are unavailable
927 //
928
929 for ( nCtr = 0; nCtr < MAX_NUM_TOKEN_ELEMENTS; nCtr++ )
930 {
931 // Set the element size as well
932 pSpnegoToken->aElementArray[ nCtr ].nStructSize = SPNEGO_ELEMENT_SIZE;
933 pSpnegoToken->aElementArray[ nCtr ].iElementPresent = SPNEGO_TOKEN_ELEMENT_UNAVAILABLE;
934 }
935
936 }
937
938 /////////////////////////////////////////////////////////////////////////////
939 //
940 // Function:
941 // InitSpnegoTokenType
942 //
943 // Parameters:
944 // [in] pSpnegoToken - Points to SPNEGO_TOKEN structure.
945 // [out] pnTokenLength - Filled out with total token length
946 // [out] pnRemainingTokenLength - Filled out with remaining length
947 // after header is parsed
948 // [out] ppbFirstElement - Filled out with pointer to first
949 // element after header info.
950 //
951 // Returns:
952 // int Success - SPNEGO_E_SUCCESS
953 // Failure - SPNEGO API Error code
954 //
955 // Comments :
956 // Walks the underlying binary data for a SPNEGO_TOKEN data structure
957 // and determines the type of the underlying token based on token header
958 // information.
959 //
960 ////////////////////////////////////////////////////////////////////////////
961
InitSpnegoTokenType(SPNEGO_TOKEN * pSpnegoToken,long * pnTokenLength,long * pnRemainingTokenLength,unsigned char ** ppbFirstElement)962 int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength,
963 long* pnRemainingTokenLength, unsigned char** ppbFirstElement )
964 {
965 int nReturn = SPNEGO_E_INVALID_TOKEN;
966 long nActualTokenLength = 0L;
967 long nBoundaryLength = pSpnegoToken->ulBinaryDataLen;
968 unsigned char* pbTokenData = pSpnegoToken->pbBinaryData;
969
970 //
971 // First byte MUST be either an APP_CONSTRUCT or the NEGTARG_TOKEN_TARG
972 //
973
974 if ( SPNEGO_NEGINIT_APP_CONSTRUCT == *pbTokenData )
975 {
976 // Validate the above token - this will tell us the actual length of the token
977 // per the encoding (minus the actual token bytes)
978 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, 0L, nBoundaryLength,
979 pnTokenLength, &nActualTokenLength ) )
980 == SPNEGO_E_SUCCESS )
981 {
982 // Initialize the remaining token length value. This will be used
983 // to tell the caller how much token there is left once we've parsed
984 // the header (they could calculate it from the other values, but this
985 // is a bit friendlier)
986 *pnRemainingTokenLength = *pnTokenLength;
987
988 // Make adjustments to next token
989 pbTokenData += nActualTokenLength;
990 nBoundaryLength -= nActualTokenLength;
991
992 // The next token should be an OID
993 if ( ( nReturn = ASNDerCheckOID( pbTokenData, spnego_mech_oid_Spnego, nBoundaryLength,
994 &nActualTokenLength ) ) == SPNEGO_E_SUCCESS )
995 {
996 // Make adjustments to next token
997 pbTokenData += nActualTokenLength;
998 nBoundaryLength -= nActualTokenLength;
999 *pnRemainingTokenLength -= nActualTokenLength;
1000
1001 // The next token should specify the NegTokenInit
1002 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER,
1003 *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
1004 &nActualTokenLength ) )
1005 == SPNEGO_E_SUCCESS )
1006 {
1007 // Make adjustments to next token
1008 pbTokenData += nActualTokenLength;
1009 nBoundaryLength -= nActualTokenLength;
1010 *pnRemainingTokenLength -= nActualTokenLength;
1011
1012 // The next token should specify the start of a sequence
1013 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
1014 *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
1015 &nActualTokenLength ) )
1016 == SPNEGO_E_SUCCESS )
1017 {
1018 // NegTokenInit header is now checked out!
1019
1020 // Make adjustments to next token
1021 *pnRemainingTokenLength -= nActualTokenLength;
1022
1023 // Store pointer to first element
1024 *ppbFirstElement = pbTokenData + nActualTokenLength;
1025 pSpnegoToken->ucTokenType = SPNEGO_TOKEN_INIT;
1026 } // IF Check Sequence Token
1027
1028 } // IF Check NegTokenInit token
1029
1030
1031 } // IF Check for SPNEGO OID
1032
1033
1034 } // IF check app construct token
1035
1036 }
1037 else if ( SPNEGO_NEGTARG_TOKEN_IDENTIFIER == *pbTokenData )
1038 {
1039
1040 // The next token should specify the NegTokenInit
1041 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER,
1042 *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
1043 &nActualTokenLength ) )
1044 == SPNEGO_E_SUCCESS )
1045 {
1046 // Initialize the remaining token length value. This will be used
1047 // to tell the caller how much token there is left once we've parsed
1048 // the header (they could calculate it from the other values, but this
1049 // is a bit friendlier)
1050 *pnRemainingTokenLength = *pnTokenLength;
1051
1052 // Make adjustments to next token
1053 pbTokenData += nActualTokenLength;
1054 nBoundaryLength -= nActualTokenLength;
1055
1056 // The next token should specify the start of a sequence
1057 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
1058 *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
1059 &nActualTokenLength ) )
1060 == SPNEGO_E_SUCCESS )
1061 {
1062 // NegTokenInit header is now checked out!
1063
1064 // Make adjustments to next token
1065 *pnRemainingTokenLength -= nActualTokenLength;
1066
1067 // Store pointer to first element
1068 *ppbFirstElement = pbTokenData + nActualTokenLength;
1069 pSpnegoToken->ucTokenType = SPNEGO_TOKEN_TARG;
1070 } // IF Check Sequence Token
1071
1072 } // IF Check NegTokenInit token
1073
1074 } // ELSE IF it's a NegTokenTarg
1075
1076 return nReturn;
1077 }
1078
1079
1080 /////////////////////////////////////////////////////////////////////////////
1081 //
1082 // Function:
1083 // GetSpnegoInitTokenMechList
1084 //
1085 // Parameters:
1086 // [in] pbTokenData - Points to binary MechList element
1087 // in NegTokenInit.
1088 // [in] nMechListLength - Length of the MechList
1089 // [out] pSpnegoElement - Filled out with MechList Element
1090 // data.
1091 //
1092 // Returns:
1093 // int Success - SPNEGO_E_SUCCESS
1094 // Failure - SPNEGO API Error code
1095 //
1096 // Comments :
1097 // Checks that pbTokenData is pointing at something that at least
1098 // *looks* like a MechList and then fills out the supplied
1099 // SPNEGO_ELEMENT structure.
1100 //
1101 ////////////////////////////////////////////////////////////////////////////
1102
GetSpnegoInitTokenMechList(unsigned char * pbTokenData,int nMechListLength,SPNEGO_ELEMENT * pSpnegoElement)1103 int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength,
1104 SPNEGO_ELEMENT* pSpnegoElement )
1105 {
1106 int nReturn = SPNEGO_E_INVALID_TOKEN;
1107 long nLength = 0L;
1108 long nActualTokenLength = 0L;
1109
1110 // Actual MechList is prepended by a Constructed Sequence Token
1111 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
1112 nMechListLength, nMechListLength,
1113 &nLength, &nActualTokenLength ) )
1114 == SPNEGO_E_SUCCESS )
1115 {
1116 // Adjust for this token
1117 nMechListLength -= nActualTokenLength;
1118 pbTokenData += nActualTokenLength;
1119
1120 // Perform simple validation of the actual MechList (i.e. ensure that
1121 // the OIDs in the MechList are reasonable).
1122
1123 if ( ( nReturn = ValidateMechList( pbTokenData, nLength ) ) == SPNEGO_E_SUCCESS )
1124 {
1125 // Initialize the element now
1126 pSpnegoElement->eElementType = spnego_init_mechtypes;
1127 pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE;
1128 pSpnegoElement->type = SPNEGO_MECHLIST_TYPE;
1129 pSpnegoElement->nDatalength = nLength;
1130 pSpnegoElement->pbData = pbTokenData;
1131 }
1132
1133 } // IF Check Token
1134
1135 return nReturn;
1136 }
1137
1138 /////////////////////////////////////////////////////////////////////////////
1139 //
1140 // Function:
1141 // InitSpnegoTokenElementFromBasicType
1142 //
1143 // Parameters:
1144 // [in] pbTokenData - Points to binary element data in
1145 // a SPNEGO token.
1146 // [in] nElementLength - Length of the element
1147 // [in] ucExpectedType - Expected DER type.
1148 // [in] spnegoElementType - Which element is this?
1149 // [out] pSpnegoElement - Filled out with element data.
1150 //
1151 // Returns:
1152 // int Success - SPNEGO_E_SUCCESS
1153 // Failure - SPNEGO API Error code
1154 //
1155 // Comments :
1156 // Checks that pbTokenData is pointing at the specified DER type. If so,
1157 // then we verify that lengths are proper and then fill out the
1158 // SPNEGO_ELEMENT data structure.
1159 //
1160 ////////////////////////////////////////////////////////////////////////////
1161
InitSpnegoTokenElementFromBasicType(unsigned char * pbTokenData,int nElementLength,unsigned char ucExpectedType,SPNEGO_ELEMENT_TYPE spnegoElementType,SPNEGO_ELEMENT * pSpnegoElement)1162 int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength,
1163 unsigned char ucExpectedType,
1164 SPNEGO_ELEMENT_TYPE spnegoElementType,
1165 SPNEGO_ELEMENT* pSpnegoElement )
1166 {
1167 int nReturn = SPNEGO_E_UNEXPECTED_TYPE;
1168 long nLength = 0L;
1169 long nActualTokenLength = 0L;
1170
1171 // The type BYTE must match our token data or something is badly wrong
1172 if ( *pbTokenData == ucExpectedType )
1173 {
1174
1175 // Check that we are pointing at the specified type
1176 if ( ( nReturn = ASNDerCheckToken( pbTokenData, ucExpectedType,
1177 nElementLength, nElementLength,
1178 &nLength, &nActualTokenLength ) )
1179 == SPNEGO_E_SUCCESS )
1180 {
1181 // Adjust for this token
1182 nElementLength -= nActualTokenLength;
1183 pbTokenData += nActualTokenLength;
1184
1185 // Initialize the element now
1186 pSpnegoElement->eElementType = spnegoElementType;
1187 pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE;
1188 pSpnegoElement->type = ucExpectedType;
1189 pSpnegoElement->nDatalength = nLength;
1190 pSpnegoElement->pbData = pbTokenData;
1191 }
1192
1193 } // IF type makes sense
1194
1195 return nReturn;
1196 }
1197
1198
1199 /////////////////////////////////////////////////////////////////////////////
1200 //
1201 // Function:
1202 // InitSpnegoTokenElementFromOID
1203 //
1204 // Parameters:
1205 // [in] pbTokenData - Points to binary element data in
1206 // a SPNEGO token.
1207 // [in] nElementLength - Length of the element
1208 // [in] spnegoElementType - Which element is this?
1209 // [out] pSpnegoElement - Filled out with element data.
1210 //
1211 // Returns:
1212 // int Success - SPNEGO_E_SUCCESS
1213 // Failure - SPNEGO API Error code
1214 //
1215 // Comments :
1216 // Initializes a SpnegoElement from an OID - normally, this would have
1217 // used the Basic Type function above, but since we do binary compares
1218 // on the OIDs against the DER information as well as the OID, we need
1219 // to account for that.
1220 //
1221 ////////////////////////////////////////////////////////////////////////////
1222
InitSpnegoTokenElementFromOID(unsigned char * pbTokenData,int nElementLength,SPNEGO_ELEMENT_TYPE spnegoElementType,SPNEGO_ELEMENT * pSpnegoElement)1223 int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength,
1224 SPNEGO_ELEMENT_TYPE spnegoElementType,
1225 SPNEGO_ELEMENT* pSpnegoElement )
1226 {
1227 int nReturn = SPNEGO_E_UNEXPECTED_TYPE;
1228 long nLength = 0L;
1229 long nActualTokenLength = 0L;
1230
1231 // The type BYTE must match our token data or something is badly wrong
1232 if ( *pbTokenData == OID )
1233 {
1234
1235 // Check that we are pointing at an OID type
1236 if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID,
1237 nElementLength, nElementLength,
1238 &nLength, &nActualTokenLength ) )
1239 == SPNEGO_E_SUCCESS )
1240 {
1241 // Don't adjust any values for this function
1242
1243 // Initialize the element now
1244 pSpnegoElement->eElementType = spnegoElementType;
1245 pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE;
1246 pSpnegoElement->type = OID;
1247 pSpnegoElement->nDatalength = nElementLength;
1248 pSpnegoElement->pbData = pbTokenData;
1249 }
1250
1251 } // IF type makes sense
1252
1253 return nReturn;
1254 }
1255
1256
1257 /////////////////////////////////////////////////////////////////////////////
1258 //
1259 // Function:
1260 // InitSpnegoTokenElements
1261 //
1262 // Parameters:
1263 // [in] pSpnegoToken - Points to SPNEGO_TOKEN struct
1264 // [in] pbTokenData - Points to initial binary element
1265 // data in a SPNEGO token.
1266 // [in] nRemainingTokenLength - Length remaining past header
1267 //
1268 // Returns:
1269 // int Success - SPNEGO_E_SUCCESS
1270 // Failure - SPNEGO API Error code
1271 //
1272 // Comments :
1273 // Interprets the data at pbTokenData based on the TokenType in
1274 // pSpnegoToken. Since some elements are optional (technically all are
1275 // but the token becomes quite useless if this is so), we check if
1276 // an element exists before filling out the element in the array.
1277 //
1278 ////////////////////////////////////////////////////////////////////////////
1279
InitSpnegoTokenElements(SPNEGO_TOKEN * pSpnegoToken,unsigned char * pbTokenData,long nRemainingTokenLength)1280 int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData,
1281 long nRemainingTokenLength )
1282 {
1283 //
1284 // The following arrays contain the token identifiers for the elements
1285 // comprising the actual token. All values are optional, and there are
1286 // no defaults.
1287 //
1288
1289 static unsigned char abNegTokenInitElements[] =
1290 { SPNEGO_NEGINIT_ELEMENT_MECHTYPES, SPNEGO_NEGINIT_ELEMENT_REQFLAGS,
1291 SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC };
1292
1293 static unsigned char abNegTokenTargElements[] =
1294 { SPNEGO_NEGTARG_ELEMENT_NEGRESULT, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH,
1295 SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC };
1296
1297 int nReturn = SPNEGO_E_SUCCESS;
1298 int nCtr = 0L;
1299 long nElementLength = 0L;
1300 long nActualTokenLength = 0L;
1301 unsigned char* pbElements = NULL;
1302
1303 // Point to the correct array
1304 switch( pSpnegoToken->ucTokenType )
1305 {
1306 case SPNEGO_TOKEN_INIT:
1307 {
1308 pbElements = abNegTokenInitElements;
1309 }
1310 break;
1311
1312 case SPNEGO_TOKEN_TARG:
1313 {
1314 pbElements = abNegTokenTargElements;
1315 }
1316 break;
1317
1318 } // SWITCH tokentype
1319
1320 //
1321 // Enumerate the element arrays and look for the tokens at our current location
1322 //
1323
1324 for ( nCtr = 0L;
1325 SPNEGO_E_SUCCESS == nReturn &&
1326 nCtr < MAX_NUM_TOKEN_ELEMENTS &&
1327 nRemainingTokenLength > 0L;
1328 nCtr++ )
1329 {
1330
1331 // Check if the token exists
1332 if ( ( nReturn = ASNDerCheckToken( pbTokenData, pbElements[nCtr],
1333 0L, nRemainingTokenLength,
1334 &nElementLength, &nActualTokenLength ) )
1335 == SPNEGO_E_SUCCESS )
1336 {
1337
1338 // Token data should skip over the sequence token and then
1339 // call the appropriate function to initialize the element
1340 pbTokenData += nActualTokenLength;
1341
1342 // Lengths in the elements should NOT go beyond the element
1343 // length
1344
1345 // Different tokens mean different elements
1346 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
1347 {
1348
1349 // Handle each element as appropriate
1350 switch( pbElements[nCtr] )
1351 {
1352
1353 case SPNEGO_NEGINIT_ELEMENT_MECHTYPES:
1354 {
1355 //
1356 // This is a Mech List that specifies which OIDs the
1357 // originator of the Init Token supports.
1358 //
1359
1360 nReturn = GetSpnegoInitTokenMechList( pbTokenData, nElementLength,
1361 &pSpnegoToken->aElementArray[nCtr] );
1362
1363 }
1364 break;
1365
1366 case SPNEGO_NEGINIT_ELEMENT_REQFLAGS:
1367 {
1368 //
1369 // This is a BITSTRING which specifies the flags that the receiver
1370 // pass to the gss_accept_sec_context() function.
1371 //
1372
1373 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1374 BITSTRING, spnego_init_reqFlags,
1375 &pSpnegoToken->aElementArray[nCtr] );
1376 }
1377 break;
1378
1379 case SPNEGO_NEGINIT_ELEMENT_MECHTOKEN:
1380 {
1381 //
1382 // This is an OCTETSTRING which contains a GSSAPI token corresponding
1383 // to the first OID in the MechList.
1384 //
1385
1386 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1387 OCTETSTRING, spnego_init_mechToken,
1388 &pSpnegoToken->aElementArray[nCtr] );
1389 }
1390 break;
1391
1392 case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC: // xA3
1393 {
1394 //
1395 // Don't yet know if this is a negTokenInit, or negTokenInit2.
1396 // Unfortunately, both have the same type: SPNEGO_TOKEN_INIT
1397 // If it's negTokenInit, this element should be an OCTETSTRING
1398 // containing the MIC. If it's a negTokenInit2, this element
1399 // should be an SPNEGO_CONSTRUCTED_SEQUENCE containing the
1400 // negHints (GENERALSTR, ignored)
1401 //
1402
1403 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1404 OCTETSTRING, spnego_init_mechListMIC,
1405 &pSpnegoToken->aElementArray[nCtr] );
1406
1407 if (nReturn == SPNEGO_E_UNEXPECTED_TYPE) {
1408 // This is really a negHints element. Check the type and length,
1409 // but otherwise just ignore it.
1410 long elen, tlen;
1411 nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
1412 nElementLength, nElementLength,
1413 &elen, &tlen );
1414 }
1415 }
1416 break;
1417
1418 } // SWITCH Element
1419 }
1420 else
1421 {
1422 /* pSpnegoToken->ucTokenType == SPNEGO_TOKEN_TARG */
1423
1424 switch( pbElements[nCtr] )
1425 {
1426
1427 case SPNEGO_NEGTARG_ELEMENT_NEGRESULT:
1428 {
1429 //
1430 // This is an ENUMERATION which specifies result of the last GSS
1431 // token negotiation call.
1432 //
1433
1434 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1435 ENUMERATED, spnego_targ_negResult,
1436 &pSpnegoToken->aElementArray[nCtr] );
1437 }
1438 break;
1439
1440 case SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH:
1441 {
1442 //
1443 // This is an OID which specifies a supported mechanism.
1444 //
1445
1446 nReturn = InitSpnegoTokenElementFromOID( pbTokenData, nElementLength,
1447 spnego_targ_mechListMIC,
1448 &pSpnegoToken->aElementArray[nCtr] );
1449 }
1450 break;
1451
1452 case SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN:
1453 {
1454 //
1455 // This is an OCTETSTRING which specifies results of the last GSS
1456 // token negotiation call.
1457 //
1458
1459 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1460 OCTETSTRING, spnego_targ_responseToken,
1461 &pSpnegoToken->aElementArray[nCtr] );
1462 }
1463 break;
1464
1465 case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC:
1466 {
1467 //
1468 // This is an OCTETSTRING, typically 16 bytes,
1469 // which contains a message integrity BLOB.
1470 //
1471
1472 nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
1473 OCTETSTRING, spnego_targ_mechListMIC,
1474 &pSpnegoToken->aElementArray[nCtr] );
1475 }
1476 break;
1477
1478 } // SWITCH Element
1479
1480 } // ELSE !NegTokenInit
1481
1482 // Account for the entire token and following data
1483 nRemainingTokenLength -= ( nActualTokenLength + nElementLength );
1484
1485 // Token data should skip past the element length now
1486 pbTokenData += nElementLength;
1487
1488 } // IF Token found
1489 else if ( SPNEGO_E_TOKEN_NOT_FOUND == nReturn )
1490 {
1491 // For now, this is a benign error (remember, all elements are optional, so
1492 // if we don't find one, it's okay).
1493
1494 nReturn = SPNEGO_E_SUCCESS;
1495 }
1496
1497 } // FOR enum elements
1498
1499 //
1500 // We should always run down to 0 remaining bytes in the token. If not, we've got
1501 // a bad token.
1502 //
1503
1504 if ( SPNEGO_E_SUCCESS == nReturn && nRemainingTokenLength != 0L )
1505 {
1506 nReturn = SPNEGO_E_INVALID_TOKEN;
1507 }
1508
1509 return nReturn;
1510 }
1511
1512
1513 /////////////////////////////////////////////////////////////////////////////
1514 //
1515 // Function:
1516 // FindMechOIDInMechList
1517 //
1518 // Parameters:
1519 // [in] pSpnegoElement - SPNEGO_ELEMENT for MechList
1520 // [in] MechOID - OID we're looking for.
1521 // [out] piMechTypeIndex - Index in the list where OID was
1522 // found
1523 //
1524 // Returns:
1525 // int Success - SPNEGO_E_SUCCESS
1526 // Failure - SPNEGO API Error code
1527 //
1528 // Comments :
1529 // Walks the MechList for MechOID. When it is found, the index in the
1530 // list is written to piMechTypeIndex.
1531 //
1532 ////////////////////////////////////////////////////////////////////////////
1533
FindMechOIDInMechList(SPNEGO_ELEMENT * pSpnegoElement,SPNEGO_MECH_OID MechOID,int * piMechTypeIndex)1534 int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID,
1535 int * piMechTypeIndex )
1536 {
1537 int nReturn = SPNEGO_E_NOT_FOUND;
1538 int nCtr = 0;
1539 long nLength = 0L;
1540 long nBoundaryLength = pSpnegoElement->nDatalength;
1541 unsigned char* pbMechListData = pSpnegoElement->pbData;
1542
1543 while( SPNEGO_E_SUCCESS != nReturn && nBoundaryLength > 0L )
1544 {
1545
1546 // Use the helper function to check the OID
1547 if ( ( nReturn = ASNDerCheckOID( pbMechListData, MechOID, nBoundaryLength, &nLength ) )
1548 == SPNEGO_E_SUCCESS )
1549 {
1550 *piMechTypeIndex = nCtr;
1551 }
1552
1553 // Adjust for the current OID
1554 pbMechListData += nLength;
1555 nBoundaryLength -= nLength;
1556 nCtr++;
1557
1558 } // WHILE enuming OIDs
1559
1560 return nReturn;
1561
1562 }
1563
1564
1565 /////////////////////////////////////////////////////////////////////////////
1566 //
1567 // Function:
1568 // ValidateMechList
1569 //
1570 // Parameters:
1571 // [in] pbMechListData - Pointer to binary MechList data
1572 // [in] nBoundaryLength - Length we must not exceed
1573 //
1574 // Returns:
1575 // int Success - SPNEGO_E_SUCCESS
1576 // Failure - SPNEGO API Error code
1577 //
1578 // Comments :
1579 // Checks the data at pbMechListData to see if it looks like a MechList.
1580 // As part of this, we walk the list and ensure that none of the OIDs
1581 // have a length that takes us outside of nBoundaryLength.
1582 //
1583 ////////////////////////////////////////////////////////////////////////////
1584
ValidateMechList(unsigned char * pbMechListData,long nBoundaryLength)1585 int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength )
1586 {
1587 int nReturn = SPNEGO_E_SUCCESS;
1588 long nLength = 0L;
1589 long nTokenLength = 0L;
1590
1591 while( SPNEGO_E_SUCCESS == nReturn && nBoundaryLength > 0L )
1592 {
1593 // Verify that we have something that at least *looks* like an OID - in other
1594 // words it has an OID identifier and specifies a length that doesn't go beyond
1595 // the size of the list.
1596 nReturn = ASNDerCheckToken( pbMechListData, OID, 0L, nBoundaryLength,
1597 &nLength, &nTokenLength );
1598
1599 // Adjust for the current OID
1600 pbMechListData += ( nLength + nTokenLength );
1601 nBoundaryLength -= ( nLength + nTokenLength );
1602
1603 } // WHILE enuming OIDs
1604
1605 return nReturn;
1606
1607 }
1608
1609 /////////////////////////////////////////////////////////////////////////////
1610 //
1611 // Function:
1612 // IsValidMechOid
1613 //
1614 // Parameters:
1615 // [in] mechOid - mechOID id enumeration
1616 //
1617 // Returns:
1618 // int Success - 1
1619 // Failure - 0
1620 //
1621 // Comments :
1622 // Checks for a valid mechOid value.
1623 //
1624 ////////////////////////////////////////////////////////////////////////////
1625
IsValidMechOid(SPNEGO_MECH_OID mechOid)1626 int IsValidMechOid( SPNEGO_MECH_OID mechOid )
1627 {
1628 return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy &&
1629 mechOid <= spnego_mech_oid_NTLMSSP );
1630 }
1631
1632 /////////////////////////////////////////////////////////////////////////////
1633 //
1634 // Function:
1635 // IsValidContextFlags
1636 //
1637 // Parameters:
1638 // [in] ucContextFlags - ContextFlags value
1639 //
1640 // Returns:
1641 // int Success - 1
1642 // Failure - 0
1643 //
1644 // Comments :
1645 // Checks for a valid ContextFlags value.
1646 //
1647 ////////////////////////////////////////////////////////////////////////////
1648
IsValidContextFlags(unsigned char ucContextFlags)1649 int IsValidContextFlags( unsigned char ucContextFlags )
1650 {
1651 // Mask out our valid bits. If there is anything leftover, this
1652 // is not a valid value for Context Flags
1653 return ( ( ucContextFlags & ~SPNEGO_NEGINIT_CONTEXT_MASK ) == 0 );
1654 }
1655
1656 /////////////////////////////////////////////////////////////////////////////
1657 //
1658 // Function:
1659 // IsValidNegResult
1660 //
1661 // Parameters:
1662 // [in] negResult - NegResult value
1663 //
1664 // Returns:
1665 // int Success - 1
1666 // Failure - 0
1667 //
1668 // Comments :
1669 // Checks for a valid NegResult value.
1670 //
1671 ////////////////////////////////////////////////////////////////////////////
1672
IsValidNegResult(SPNEGO_NEGRESULT negResult)1673 int IsValidNegResult( SPNEGO_NEGRESULT negResult )
1674 {
1675 return ( negResult >= spnego_negresult_success &&
1676 negResult <= spnego_negresult_request_mic );
1677 }
1678
1679 /////////////////////////////////////////////////////////////////////////////
1680 //
1681 // Function:
1682 // IsValidSpnegoToken
1683 //
1684 // Parameters:
1685 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1686 //
1687 // Returns:
1688 // int Success - 1
1689 // Failure - 0
1690 //
1691 // Comments :
1692 // Performs simple heuristic on location pointed to by pSpnegoToken.
1693 //
1694 ////////////////////////////////////////////////////////////////////////////
1695
IsValidSpnegoToken(SPNEGO_TOKEN * pSpnegoToken)1696 int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken )
1697 {
1698 int nReturn = 0;
1699
1700 // Parameter should be non-NULL
1701 if ( NULL != pSpnegoToken )
1702 {
1703 // Length should be at least the size defined in the header
1704 if ( pSpnegoToken->nStructSize >= SPNEGO_TOKEN_SIZE )
1705 {
1706 // Number of elements should be >= our maximum - if it's greater, that's
1707 // okay, since we'll only be accessing the elements up to MAX_NUM_TOKEN_ELEMENTS
1708 if ( pSpnegoToken->nNumElements >= MAX_NUM_TOKEN_ELEMENTS )
1709 {
1710 // Check for proper token type
1711 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ||
1712 SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
1713 {
1714 nReturn = 1;
1715 }
1716 }
1717
1718 } // IF struct size makes sense
1719
1720 } // IF non-NULL spnego Token
1721
1722 return nReturn;
1723 }
1724
1725 /////////////////////////////////////////////////////////////////////////////
1726 //
1727 // Function:
1728 // IsValidSpnegoElement
1729 //
1730 // Parameters:
1731 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1732 // [in] spnegoElement - spnegoElement Type from enumeration
1733 //
1734 // Returns:
1735 // int Success - 1
1736 // Failure - 0
1737 //
1738 // Comments :
1739 // Checks that spnegoElement has a valid value and is appropriate for
1740 // the SPNEGO token encapsulated by pSpnegoToken.
1741 //
1742 ////////////////////////////////////////////////////////////////////////////
1743
IsValidSpnegoElement(SPNEGO_TOKEN * pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement)1744 int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement )
1745 {
1746 int nReturn = 0;
1747
1748 // Check boundaries
1749 if ( spnegoElement > spnego_element_min &&
1750 spnegoElement < spnego_element_max )
1751 {
1752
1753 // Check for appropriateness to token type
1754 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
1755 {
1756 nReturn = ( spnegoElement >= spnego_init_mechtypes &&
1757 spnegoElement <= spnego_init_mechListMIC );
1758 }
1759 else
1760 {
1761 nReturn = ( spnegoElement >= spnego_targ_negResult &&
1762 spnegoElement <= spnego_targ_mechListMIC );
1763 }
1764
1765 } // IF boundary conditions are met
1766
1767 return nReturn;
1768 }
1769
1770 /////////////////////////////////////////////////////////////////////////////
1771 //
1772 // Function:
1773 // CalculateElementArrayIndex
1774 //
1775 // Parameters:
1776 // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
1777 // [in] spnegoElement - spnegoElement Type from enumeration
1778 //
1779 // Returns:
1780 // int index in the SPNEGO_TOKEN element array that the element can
1781 // can be found
1782 //
1783 // Comments :
1784 // Based on the Token Type, calculates the index in the element array
1785 // at which the specified element can be found.
1786 //
1787 ////////////////////////////////////////////////////////////////////////////
1788
CalculateElementArrayIndex(SPNEGO_TOKEN * pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement)1789 int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement )
1790 {
1791 int nReturn = 0;
1792
1793 // Offset is difference between value and initial element identifier
1794 // (these differ based on ucTokenType)
1795
1796 if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
1797 {
1798 nReturn = spnegoElement - spnego_init_mechtypes;
1799 }
1800 else
1801 {
1802 nReturn = spnegoElement - spnego_targ_negResult;
1803 }
1804
1805 return nReturn;
1806 }
1807
1808 /////////////////////////////////////////////////////////////////////////////
1809 //
1810 // Function:
1811 // InitTokenFromBinary
1812 //
1813 // Parameters:
1814 // [in] ucCopyData - Flag indicating if data should be copied
1815 // [in] ulFlags - Flags value for structure
1816 // [in] pnTokenData - Binary Token Data
1817 // [in] ulLength - Length of the data
1818 // [out] ppSpnegoToken - Pointer to call allocated SPNEGO Token
1819 // data structure
1820 //
1821 // Returns:
1822 // int Success - SPNEGO_E_SUCCESS
1823 // Failure - SPNEGO API Error code
1824 //
1825 // Comments :
1826 // Allocates a SPNEGO_TOKEN data structure and fills it out as
1827 // appropriate based in the flags passed into the function.
1828 //
1829 ////////////////////////////////////////////////////////////////////////////
1830
1831
1832 // 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)1833 int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags,
1834 unsigned char* pbTokenData, unsigned long ulLength,
1835 SPNEGO_TOKEN** ppSpnegoToken )
1836 {
1837 int nReturn = SPNEGO_E_INVALID_PARAMETER;
1838 SPNEGO_TOKEN* pSpnegoToken = NULL;
1839 unsigned char* pbFirstElement = NULL;
1840 long nTokenLength = 0L;
1841 long nRemainingTokenLength = 0L;
1842
1843 // Basic Parameter Validation
1844
1845 if ( NULL != pbTokenData &&
1846 NULL != ppSpnegoToken &&
1847 0L != ulLength )
1848 {
1849
1850 //
1851 // Allocate the empty token, then initialize the data structure.
1852 //
1853
1854 pSpnegoToken = AllocEmptySpnegoToken( ucCopyData, ulFlags, pbTokenData, ulLength );
1855
1856 if ( NULL != pSpnegoToken )
1857 {
1858
1859 // Copy the binary data locally
1860
1861
1862 // Initialize the token type
1863 if ( ( nReturn = InitSpnegoTokenType( pSpnegoToken, &nTokenLength,
1864 &nRemainingTokenLength, &pbFirstElement ) )
1865 == SPNEGO_E_SUCCESS )
1866 {
1867
1868 // Initialize the element array
1869 if ( ( nReturn = InitSpnegoTokenElements( pSpnegoToken, pbFirstElement,
1870 nRemainingTokenLength ) )
1871 == SPNEGO_E_SUCCESS )
1872 {
1873 *ppSpnegoToken = pSpnegoToken;
1874 }
1875
1876 } // IF Init Token Type
1877
1878 // Cleanup on error condition
1879 if ( SPNEGO_E_SUCCESS != nReturn )
1880 {
1881 spnegoFreeData( pSpnegoToken );
1882 }
1883
1884 }
1885 else
1886 {
1887 nReturn = SPNEGO_E_OUT_OF_MEMORY;
1888 }
1889
1890 } // IF Valid parameters
1891
1892
1893 return nReturn;
1894 }
1895