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