Minor cleanup mostly related to proto_reg_handoff
[obnox/wireshark/wip.git] / asn1 / spnego / packet-spnego-template.c
1 /* packet-spnego.c
2  * Routines for the simple and protected GSS-API negotiation mechanism
3  * as described in RFC 2478.
4  * Copyright 2002, Tim Potter <tpot@samba.org>
5  * Copyright 2002, Richard Sharpe <rsharpe@ns.aus.com>
6  * Copyright 2003, Richard Sharpe <rsharpe@richardsharpe.com>
7  * Copyright 2005, Ronnie Sahlberg (krb decryption)
8  * Copyright 2005, Anders Broman (converted to asn2wrs generated dissector)
9  *
10  * $Id$
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  */
30 /* The heimdal code for decryption of GSSAPI wrappers using heimdal comes from
31    Heimdal 1.6 and has been modified for wireshark's requirements.
32 */
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <glib.h>
39 #include <epan/packet.h>
40 #include <epan/asn1.h>
41 #include "packet-dcerpc.h"
42 #include "packet-gssapi.h"
43 #include "packet-kerberos.h"
44 #include <epan/crypt/crypt-rc4.h>
45 #include <epan/conversation.h>
46 #include <epan/emem.h>
47 #include <epan/asn1.h>
48
49 #include <stdio.h>
50 #include <string.h>
51
52 #include "packet-ber.h"
53
54
55 #define PNAME  "Simple Protected Negotiation"
56 #define PSNAME "SPNEGO"
57 #define PFNAME "spnego"
58
59 /* Initialize the protocol and registered fields */
60 static int proto_spnego = -1;
61 static int proto_spnego_krb5 = -1;
62
63
64 static int hf_spnego = -1;
65 static int hf_spnego_wraptoken = -1;
66 static int hf_spnego_krb5_oid;
67 static int hf_spnego_krb5 = -1;
68 static int hf_spnego_krb5_tok_id = -1;
69 static int hf_spnego_krb5_sgn_alg = -1;
70 static int hf_spnego_krb5_seal_alg = -1;
71 static int hf_spnego_krb5_snd_seq = -1;
72 static int hf_spnego_krb5_sgn_cksum = -1;
73 static int hf_spnego_krb5_confounder = -1;
74 static int hf_spnego_krb5_filler = -1;
75 static int hf_spnego_krb5_cfx_flags = -1;
76 static int hf_spnego_krb5_cfx_flags_01 = -1;
77 static int hf_spnego_krb5_cfx_flags_02 = -1;
78 static int hf_spnego_krb5_cfx_flags_04 = -1;
79 static int hf_spnego_krb5_cfx_ec = -1;
80 static int hf_spnego_krb5_cfx_rrc = -1;
81 static int hf_spnego_krb5_cfx_seq = -1;
82
83 #include "packet-spnego-hf.c"
84
85 /* Global variables */
86 static const char *MechType_oid;
87 gssapi_oid_value *next_level_value;
88 gboolean saw_mechanism = FALSE;
89
90
91 /* Initialize the subtree pointers */
92 static gint ett_spnego;
93 static gint ett_spnego_wraptoken;
94 static gint ett_spnego_krb5 = -1;
95 static gint ett_spnego_krb5_cfx_flags = -1;
96
97 #include "packet-spnego-ett.c"
98
99 /*
100  * Unfortunately, we have to have a forward declaration of this,
101  * as the code generated by asn2wrs includes a call before the
102  * definition.
103  */
104 static int dissect_spnego_PrincipalSeq(gboolean implicit_tag, tvbuff_t *tvb,
105                                        int offset, asn1_ctx_t *actx _U_,
106                                        proto_tree *tree, int hf_index);
107
108 #include "packet-spnego-fn.c"
109 /*
110  * This is the SPNEGO KRB5 dissector. It is not true KRB5, but some ASN.1
111  * wrapped blob with an OID, USHORT token ID, and a Ticket, that is also
112  * ASN.1 wrapped by the looks of it. It conforms to RFC1964.
113  */
114
115 #define KRB_TOKEN_AP_REQ                0x0001
116 #define KRB_TOKEN_AP_REP                0x0002
117 #define KRB_TOKEN_AP_ERR                0x0003
118 #define KRB_TOKEN_GETMIC                0x0101
119 #define KRB_TOKEN_WRAP                  0x0102
120 #define KRB_TOKEN_DELETE_SEC_CONTEXT    0x0201
121 #define KRB_TOKEN_CFX_GETMIC            0x0404
122 #define KRB_TOKEN_CFX_WRAP              0x0405
123
124 static const value_string spnego_krb5_tok_id_vals[] = {
125   { KRB_TOKEN_AP_REQ,             "KRB5_AP_REQ"},
126   { KRB_TOKEN_AP_REP,             "KRB5_AP_REP"},
127   { KRB_TOKEN_AP_ERR,             "KRB5_ERROR"},
128   { KRB_TOKEN_GETMIC,             "KRB5_GSS_GetMIC" },
129   { KRB_TOKEN_WRAP,               "KRB5_GSS_Wrap" },
130   { KRB_TOKEN_DELETE_SEC_CONTEXT, "KRB5_GSS_Delete_sec_context" },
131   { KRB_TOKEN_CFX_GETMIC,         "KRB_TOKEN_CFX_GetMic" },
132   { KRB_TOKEN_CFX_WRAP,           "KRB_TOKEN_CFX_WRAP" },
133   { 0, NULL}
134 };
135
136 #define KRB_SGN_ALG_DES_MAC_MD5 0x0000
137 #define KRB_SGN_ALG_MD2_5       0x0001
138 #define KRB_SGN_ALG_DES_MAC     0x0002
139 #define KRB_SGN_ALG_HMAC        0x0011
140
141 static const value_string spnego_krb5_sgn_alg_vals[] = {
142   { KRB_SGN_ALG_DES_MAC_MD5, "DES MAC MD5"},
143   { KRB_SGN_ALG_MD2_5,       "MD2.5"},
144   { KRB_SGN_ALG_DES_MAC,     "DES MAC"},
145   { KRB_SGN_ALG_HMAC,        "HMAC"},
146   { 0, NULL}
147 };
148
149 #define KRB_SEAL_ALG_DES_CBC    0x0000
150 #define KRB_SEAL_ALG_RC4        0x0010
151 #define KRB_SEAL_ALG_NONE       0xffff
152
153 static const value_string spnego_krb5_seal_alg_vals[] = {
154   { KRB_SEAL_ALG_DES_CBC, "DES CBC"},
155   { KRB_SEAL_ALG_RC4,     "RC4"},
156   { KRB_SEAL_ALG_NONE,    "None"},
157   { 0, NULL}
158 };
159
160 /*
161  * XXX - is this for SPNEGO or just GSS-API?
162  * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
163  * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
164  * than designating SPNEGO as the mechanism, offering Kerberos V5, and
165  * getting it accepted.
166  */
167 static int
168 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
169 static int
170 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
171 static int
172 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
173 static int
174 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint16 token_id);
175
176 static void
177 dissect_spnego_krb5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
178 {
179         proto_item *item;
180         proto_tree *subtree;
181         int offset = 0;
182         guint16 token_id;
183         const char *oid;
184         gssapi_oid_value *value;
185         tvbuff_t *krb5_tvb;
186         gint8 class;
187         gboolean pc, ind = 0;
188         gint32 tag;
189         guint32 len;
190         asn1_ctx_t asn1_ctx;
191         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
192
193         item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, offset,
194                                    -1, FALSE);
195
196         subtree = proto_item_add_subtree(item, ett_spnego_krb5);
197
198         /*
199          * The KRB5 blob conforms to RFC1964:
200          * [APPLICATION 0] {
201          *   OID,
202          *   USHORT (0x0001 == AP-REQ, 0x0002 == AP-REP, 0x0003 == ERROR),
203          *   OCTET STRING }
204          *
205          * However, for some protocols, the KRB5 blob starts at the SHORT
206          * and has no DER encoded header etc.
207          *
208          * It appears that for some other protocols the KRB5 blob is just
209          * a Kerberos message, with no [APPLICATION 0] header, no OID,
210          * and no USHORT.
211          *
212          * So:
213          *
214          *      If we see an [APPLICATION 0] HEADER, we show the OID and
215          *      the USHORT, and then dissect the rest as a Kerberos message.
216          *
217          *      If we see an [APPLICATION 14] or [APPLICATION 15] header,
218          *      we assume it's an AP-REQ or AP-REP message, and dissect
219          *      it all as a Kerberos message.
220          *
221          *      Otherwise, we show the USHORT, and then dissect the rest
222          *      as a Kerberos message.
223          */
224
225         /*
226          * Get the first header ...
227          */
228         get_ber_identifier(tvb, offset, &class, &pc, &tag);
229         if (class == BER_CLASS_APP && pc) {
230             /*
231              * [APPLICATION <tag>]
232              */
233             offset = dissect_ber_identifier(pinfo, subtree, tvb, offset, &class, &pc, &tag);
234             offset = dissect_ber_length(pinfo, subtree, tvb, offset, &len, &ind);
235
236             switch (tag) {
237
238             case 0:
239                 /*
240                  * [APPLICATION 0]
241                  */
242
243                 /* Next, the OID */
244                 offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, tvb, offset, hf_spnego_krb5_oid, &oid);
245
246                 value = gssapi_lookup_oid_str(oid);
247
248                 token_id = tvb_get_letohs(tvb, offset);
249                 proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
250                                     token_id);
251
252                 offset += 2;
253
254                 break;
255
256             case 14:    /* [APPLICATION 14] */
257             case 15:    /* [APPLICATION 15] */
258                 /*
259                  * No token ID - just dissect as a Kerberos message and
260                  * return.
261                  */
262                 offset = dissect_kerberos_main(tvb, pinfo, subtree, FALSE, NULL);
263                 return;
264
265             default:
266                 proto_tree_add_text(subtree, tvb, offset, 0,
267                         "Unknown header (class=%d, pc=%d, tag=%d)",
268                         class, pc, tag);
269                 goto done;
270             }
271         } else {
272             /* Next, the token ID ... */
273
274             token_id = tvb_get_letohs(tvb, offset);
275             proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
276                                 token_id);
277
278             offset += 2;
279         }
280
281         switch (token_id) {
282
283         case KRB_TOKEN_AP_REQ:
284         case KRB_TOKEN_AP_REP:
285         case KRB_TOKEN_AP_ERR:
286           krb5_tvb = tvb_new_subset(tvb, offset, -1, -1);
287           offset = dissect_kerberos_main(krb5_tvb, pinfo, subtree, FALSE, NULL);
288           break;
289
290         case KRB_TOKEN_GETMIC:
291           offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
292           break;
293
294         case KRB_TOKEN_WRAP:
295           offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
296           break;
297
298         case KRB_TOKEN_DELETE_SEC_CONTEXT:
299
300           break;
301
302         case KRB_TOKEN_CFX_GETMIC:
303           offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
304           break;
305
306         case KRB_TOKEN_CFX_WRAP:
307           offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
308           break;
309
310         default:
311
312           break;
313         }
314
315  done:
316         proto_item_set_len(item, offset);
317         return;
318 }
319
320 #ifdef HAVE_KERBEROS
321 #include <epan/crypt/crypt-md5.h>
322
323 #ifndef KEYTYPE_ARCFOUR_56
324 # define KEYTYPE_ARCFOUR_56 24
325 #endif
326 /* XXX - We should probably do a configure-time check for this instead */
327 #ifndef KRB5_KU_USAGE_SEAL
328 # define KRB5_KU_USAGE_SEAL 22
329 #endif
330
331 static int
332 arcfour_mic_key(void *key_data, size_t key_size, int key_type,
333                 void *cksum_data, size_t cksum_size,
334                 void *key6_data)
335 {
336     guint8 k5_data[16];
337     guint8 T[4];
338
339     memset(T, 0, 4);
340
341     if (key_type == KEYTYPE_ARCFOUR_56) {
342         guint8 L40[14] = "fortybits";
343
344         memcpy(L40 + 10, T, sizeof(T));
345         md5_hmac(
346                 L40, 14,
347                 key_data,
348                 key_size,
349                 k5_data);
350         memset(&k5_data[7], 0xAB, 9);
351     } else {
352         md5_hmac(
353                 T, 4,
354                 key_data,
355                 key_size,
356                 k5_data);
357     }
358
359     md5_hmac(
360         cksum_data, cksum_size,
361         k5_data,
362         16,
363         key6_data);
364
365     return 0;
366 }
367
368 static int
369 usage2arcfour(int usage)
370 {
371     switch (usage) {
372     case 3: /*KRB5_KU_AS_REP_ENC_PART 3 */
373     case 9: /*KRB5_KU_TGS_REP_ENC_PART_SUB_KEY 9 */
374         return 8;
375     case 22: /*KRB5_KU_USAGE_SEAL 22 */
376         return 13;
377     case 23: /*KRB5_KU_USAGE_SIGN 23 */
378         return 15;
379     case 24: /*KRB5_KU_USAGE_SEQ 24 */
380         return 0;
381     default :
382         return 0;
383     }
384 }
385
386 static int
387 arcfour_mic_cksum(guint8 *key_data, int key_length,
388                   unsigned usage,
389                   guint8 sgn_cksum[8],
390                   const void *v1, size_t l1,
391                   const void *v2, size_t l2,
392                   const void *v3, size_t l3)
393 {
394     const guint8 signature[] = "signaturekey";
395     guint8 ksign_c[16];
396     unsigned char t[4];
397     md5_state_t ms;
398     unsigned char digest[16];
399     int rc4_usage;
400     guint8 cksum[16];
401
402     rc4_usage=usage2arcfour(usage);
403     md5_hmac(signature, sizeof(signature),
404                 key_data, key_length,
405                 ksign_c);
406     md5_init(&ms);
407     t[0] = (rc4_usage >>  0) & 0xFF;
408     t[1] = (rc4_usage >>  8) & 0xFF;
409     t[2] = (rc4_usage >> 16) & 0xFF;
410     t[3] = (rc4_usage >> 24) & 0xFF;
411     md5_append(&ms, t, 4);
412     md5_append(&ms, v1, l1);
413     md5_append(&ms, v2, l2);
414     md5_append(&ms, v3, l3);
415     md5_finish(&ms, digest);
416     md5_hmac(digest, 16, ksign_c, 16, cksum);
417
418     memcpy(sgn_cksum, cksum, 8);
419
420     return 0;
421 }
422
423 /*
424  * Verify padding of a gss wrapped message and return its length.
425  */
426 static int
427 gssapi_verify_pad(unsigned char *wrapped_data, int wrapped_length,
428                    size_t datalen,
429                    size_t *padlen)
430 {
431     unsigned char *pad;
432     size_t padlength;
433     int i;
434
435     pad = wrapped_data + wrapped_length - 1;
436     padlength = *pad;
437
438     if (padlength > datalen)
439         return 1;
440
441     for (i = padlength; i > 0 && *pad == padlength; i--, pad--)
442         ;
443     if (i != 0)
444         return 2;
445
446     *padlen = padlength;
447
448     return 0;
449 }
450
451 static int
452 decrypt_arcfour(packet_info *pinfo,
453          guint8 *input_message_buffer,
454          guint8 *output_message_buffer,
455          guint8 *key_value, int key_size, int key_type)
456 {
457     guint8 Klocaldata[16];
458     int ret;
459     gint32 seq_number;
460     size_t datalen;
461     guint8 k6_data[16];
462     guint32 SND_SEQ[2];
463     guint8 Confounder[8];
464     guint8 cksum_data[8];
465     int cmp;
466     int conf_flag;
467     size_t padlen = 0;
468
469     datalen = tvb_length(pinfo->gssapi_encrypted_tvb);
470
471     if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0x1000){
472         conf_flag=1;
473     } else if (tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 4)==0xffff){
474         conf_flag=0;
475     } else {
476         return -3;
477     }
478
479     if(tvb_get_ntohs(pinfo->gssapi_wrap_tvb, 6)!=0xffff){
480         return -4;
481     }
482
483     ret = arcfour_mic_key(key_value, key_size, key_type,
484                           (void *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
485                           8, /* SGN_CKSUM */
486                           k6_data);
487     if (ret) {
488         return -5;
489     }
490
491     {
492         rc4_state_struct rc4_state;
493
494         crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
495         memcpy(SND_SEQ, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 8, 8), 8);
496         crypt_rc4(&rc4_state, (unsigned char *)SND_SEQ, 8);
497
498         memset(k6_data, 0, sizeof(k6_data));
499     }
500
501     seq_number=g_ntohl(SND_SEQ[0]);
502
503     if (SND_SEQ[1] != 0xFFFFFFFF && SND_SEQ[1] != 0x00000000) {
504         return -6;
505     }
506
507     {
508         int i;
509
510         for (i = 0; i < 16; i++)
511             Klocaldata[i] = ((guint8 *)key_value)[i] ^ 0xF0;
512     }
513     ret = arcfour_mic_key(Klocaldata,sizeof(Klocaldata),key_type,
514                           (unsigned char *)SND_SEQ, 4,
515                           k6_data);
516     memset(Klocaldata, 0, sizeof(Klocaldata));
517     if (ret) {
518         return -7;
519     }
520
521     if(conf_flag) {
522         rc4_state_struct rc4_state;
523
524         crypt_rc4_init(&rc4_state, k6_data, sizeof(k6_data));
525         memcpy(Confounder, (unsigned char *)tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8), 8);
526         crypt_rc4(&rc4_state, Confounder, 8);
527         memcpy(output_message_buffer, input_message_buffer, datalen);
528         crypt_rc4(&rc4_state, output_message_buffer, datalen);
529     } else {
530         memcpy(Confounder,
531                 tvb_get_ptr(pinfo->gssapi_wrap_tvb, 24, 8),
532                 8); /* Confounder */
533         memcpy(output_message_buffer,
534                 input_message_buffer,
535                 datalen);
536     }
537     memset(k6_data, 0, sizeof(k6_data));
538
539     /* only normal (i.e. non DCE style  wrapping use padding ? */
540     if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
541         ret = gssapi_verify_pad(output_message_buffer,datalen,datalen, &padlen);
542         if (ret) {
543             return -9;
544         }
545         datalen -= padlen;
546     }
547
548     /* dont know what the checksum looks like for dce style gssapi */
549     if(pinfo->decrypt_gssapi_tvb==DECRYPT_GSSAPI_NORMAL){
550         ret = arcfour_mic_cksum(key_value, key_size,
551                             KRB5_KU_USAGE_SEAL,
552                             cksum_data,
553                             tvb_get_ptr(pinfo->gssapi_wrap_tvb, 0, 8), 8,
554                             Confounder, sizeof(Confounder),
555                             output_message_buffer,
556                             datalen + padlen);
557         if (ret) {
558             return -10;
559         }
560
561         cmp = memcmp(cksum_data,
562             tvb_get_ptr(pinfo->gssapi_wrap_tvb, 16, 8),
563             8); /* SGN_CKSUM */
564         if (cmp) {
565             return -11;
566         }
567     }
568
569     return datalen;
570 }
571
572
573
574 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
575
576 static void
577 decrypt_gssapi_krb_arcfour_wrap(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int keytype)
578 {
579         int ret;
580         enc_key_t *ek;
581         int length;
582         const guint8 *original_data;
583
584         static int omb_index=0;
585         static guint8 *omb_arr[4]={NULL,NULL,NULL,NULL};
586         static guint8 *cryptocopy=NULL; /* workaround for pre-0.6.1 heimdal bug */
587         guint8 *output_message_buffer;
588
589         omb_index++;
590         if(omb_index>=4){
591                 omb_index=0;
592         }
593         output_message_buffer=omb_arr[omb_index];
594
595
596         length=tvb_length(pinfo->gssapi_encrypted_tvb);
597         original_data=tvb_get_ptr(pinfo->gssapi_encrypted_tvb, 0, length);
598
599         /* dont do anything if we are not attempting to decrypt data */
600 /*
601         if(!krb_decrypt){
602                 return;
603         }
604 */
605         /* XXX we should only do this for first time, then store somewhere */
606         /* XXX We also need to re-read the keytab when the preference changes */
607
608         cryptocopy=ep_alloc(length);
609         if(output_message_buffer){
610                 g_free(output_message_buffer);
611                 output_message_buffer=NULL;
612         }
613         output_message_buffer=g_malloc(length);
614
615         for(ek=enc_key_list;ek;ek=ek->next){
616                 /* shortcircuit and bail out if enctypes are not matching */
617                 if(ek->keytype!=keytype){
618                         continue;
619                 }
620
621                 /* pre-0.6.1 versions of Heimdal would sometimes change
622                   the cryptotext data even when the decryption failed.
623                   This would obviously not work since we iterate over the
624                   keys. So just give it a copy of the crypto data instead.
625                   This has been seen for RC4-HMAC blobs.
626                 */
627                 memcpy(cryptocopy, original_data, length);
628                 ret=decrypt_arcfour(pinfo,
629                                 cryptocopy,
630                                 output_message_buffer,
631                                 ek->keyvalue,
632                                 ek->keylength,
633                                 ek->keytype
634                                             );
635                 if (ret >= 0) {
636                         proto_tree_add_text(tree, NULL, 0, 0, "[Decrypted using: %s]", ek->key_origin);
637                         pinfo->gssapi_decrypted_tvb=tvb_new_real_data(
638                                 output_message_buffer,
639                                 ret, ret);
640                         tvb_set_child_real_data_tvbuff(tvb, pinfo->gssapi_decrypted_tvb);
641                         add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
642                         return;
643                 }
644         }
645         return;
646 }
647
648 /* borrowed from heimdal */
649 static int
650 rrc_rotate(void *data, int len, guint16 rrc, int unrotate)
651 {
652         unsigned char *tmp, buf[256];
653         size_t left;
654
655         if (len == 0)
656                 return 0;
657
658         rrc %= len;
659
660         if (rrc == 0)
661                 return 0;
662
663         left = len - rrc;
664
665         if (rrc <= sizeof(buf)) {
666                 tmp = buf;
667         } else {
668                 tmp = g_malloc(rrc);
669                 if (tmp == NULL)
670                         return -1;
671         }
672
673         if (unrotate) {
674                 memcpy(tmp, data, rrc);
675                 memmove(data, (unsigned char *)data + rrc, left);
676                 memcpy((unsigned char *)data + left, tmp, rrc);
677         } else {
678                 memcpy(tmp, (unsigned char *)data + left, rrc);
679                 memmove((unsigned char *)data + rrc, data, left);
680                 memcpy(data, tmp, rrc);
681         }
682
683         if (rrc > sizeof(buf))
684                 g_free(tmp);
685
686         return 0;
687 }
688
689
690 #define KRB5_KU_USAGE_ACCEPTOR_SEAL     22
691 #define KRB5_KU_USAGE_ACCEPTOR_SIGN     23
692 #define KRB5_KU_USAGE_INITIATOR_SEAL    24
693 #define KRB5_KU_USAGE_INITIATOR_SIGN    25
694
695 static void
696 decrypt_gssapi_krb_cfx_wrap(proto_tree *tree _U_, packet_info *pinfo _U_, tvbuff_t *tvb _U_, guint16 ec _U_, guint16 rrc _U_, int keytype, unsigned int usage)
697 {
698         int res;
699         char *rotated;
700         char *output;
701         int datalen;
702
703         /* dont do anything if we are not attempting to decrypt data */
704         if(!krb_decrypt){
705                 return;
706         }
707
708         rotated = ep_alloc(tvb_length(tvb));
709
710         tvb_memcpy(tvb, rotated, 0, tvb_length(tvb));
711         res = rrc_rotate(rotated, tvb_length(tvb), rrc, TRUE);
712
713         output = decrypt_krb5_data(tree, pinfo, usage, tvb_length(tvb),
714                   rotated, keytype, &datalen);
715
716         if (output) {
717                 char *outdata;
718
719                 outdata = ep_alloc(tvb_length(tvb));
720                 memcpy(outdata, output, tvb_length(tvb));
721                 g_free(output);
722
723                 pinfo->gssapi_decrypted_tvb=tvb_new_real_data(
724                         outdata,
725                         datalen-16,
726                         datalen-16);
727                 tvb_set_child_real_data_tvbuff(tvb, pinfo->gssapi_decrypted_tvb);
728                 add_new_data_source(pinfo, pinfo->gssapi_decrypted_tvb, "Decrypted GSS-Krb5");
729                 return;
730         }
731         return;
732 }
733
734 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
735
736
737 #endif
738
739 /*
740  * This is for GSSAPI Wrap tokens ...
741  */
742 static int
743 dissect_spnego_krb5_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
744 #ifndef HAVE_KERBEROS
745         _U_
746 #endif
747     , proto_tree *tree, guint16 token_id
748 #ifndef HAVE_KERBEROS
749         _U_
750 #endif
751     )
752 {
753         guint16 sgn_alg, seal_alg;
754 #ifdef HAVE_KERBEROS
755         int start_offset=offset;
756 #endif
757
758         /*
759          * The KRB5 blob conforms to RFC1964:
760          *   USHORT (0x0102 == GSS_Wrap)
761          *   and so on }
762          */
763
764         /* Now, the sign and seal algorithms ... */
765
766         sgn_alg = tvb_get_letohs(tvb, offset);
767         proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
768                             sgn_alg);
769
770         offset += 2;
771
772         seal_alg = tvb_get_letohs(tvb, offset);
773         proto_tree_add_uint(tree, hf_spnego_krb5_seal_alg, tvb, offset, 2,
774                             seal_alg);
775
776         offset += 2;
777
778         /* Skip the filler */
779
780         offset += 2;
781
782         /* Encrypted sequence number */
783
784         proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
785                             TRUE);
786
787         offset += 8;
788
789         /* Checksum of plaintext padded data */
790
791         proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
792                             TRUE);
793
794         offset += 8;
795
796         /*
797          * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
798          * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
799          * extra 8 bytes of "Random confounder" after the checksum.
800          * It certainly confounds code expecting all Kerberos 5
801          * GSS_Wrap() tokens to look the same....
802          */
803         if ((sgn_alg == KRB_SGN_ALG_HMAC) ||
804             /* there also seems to be a confounder for DES MAC MD5 - certainly seen when using with
805                SASL with LDAP between a Java client and Active Directory. If this breaks other things
806                we may need to make this an option. gal 17/2/06 */
807             (sgn_alg == KRB_SGN_ALG_DES_MAC_MD5)) {
808           proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
809                               TRUE);
810           offset += 8;
811         }
812
813         /* Is the data encrypted? */
814         pinfo->gssapi_data_encrypted=(seal_alg!=KRB_SEAL_ALG_NONE);
815
816 #ifdef HAVE_KERBEROS
817 #define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32
818         if(pinfo->decrypt_gssapi_tvb){
819                 /* if the caller did not provide a tvb, then we just use
820                    whatever is left of our current tvb.
821                 */
822                 if(!pinfo->gssapi_encrypted_tvb){
823                         int len;
824                         len=tvb_reported_length_remaining(tvb,offset);
825                         if(len>tvb_length_remaining(tvb, offset)){
826                                 /* no point in trying to decrypt,
827                                    we dont have the full pdu.
828                                 */
829                                 return offset;
830                         }
831                         pinfo->gssapi_encrypted_tvb = tvb_new_subset(
832                                         tvb, offset, len, len);
833                 }
834
835                 /* if this is KRB5 wrapped rc4-hmac */
836                 if((token_id==KRB_TOKEN_WRAP)
837                  &&(sgn_alg==KRB_SGN_ALG_HMAC)
838                  &&(seal_alg==KRB_SEAL_ALG_RC4)){
839                         /* do we need to create a tvb for the wrapper
840                            as well ?
841                         */
842                         if(!pinfo->gssapi_wrap_tvb){
843                                 pinfo->gssapi_wrap_tvb = tvb_new_subset(
844                                         tvb, start_offset-2,
845                                         GSS_ARCFOUR_WRAP_TOKEN_SIZE,
846                                         GSS_ARCFOUR_WRAP_TOKEN_SIZE);
847                         }
848 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
849                         decrypt_gssapi_krb_arcfour_wrap(tree,
850                                 pinfo,
851                                 tvb,
852                                 23 /* rc4-hmac */);
853 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
854                 }
855         }
856 #endif
857         /*
858          * Return the offset past the checksum, so that we know where
859          * the data we're wrapped around starts.  Also, set the length
860          * of our top-level item to that offset, so it doesn't cover
861          * the data we're wrapped around.
862          *
863          * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
864          * not before.
865          */
866         return offset;
867 }
868
869 /*
870  * XXX - This is for GSSAPI GetMIC tokens ...
871  */
872 static int
873 dissect_spnego_krb5_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
874 {
875         guint16 sgn_alg;
876
877         /*
878          * The KRB5 blob conforms to RFC1964:
879          *   USHORT (0x0101 == GSS_GetMIC)
880          *   and so on }
881          */
882
883         /* Now, the sign algorithm ... */
884
885         sgn_alg = tvb_get_letohs(tvb, offset);
886         proto_tree_add_uint(tree, hf_spnego_krb5_sgn_alg, tvb, offset, 2,
887                             sgn_alg);
888
889         offset += 2;
890
891         /* Skip the filler */
892
893         offset += 4;
894
895         /* Encrypted sequence number */
896
897         proto_tree_add_item(tree, hf_spnego_krb5_snd_seq, tvb, offset, 8,
898                             TRUE);
899
900         offset += 8;
901
902         /* Checksum of plaintext padded data */
903
904         proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset, 8,
905                             TRUE);
906
907         offset += 8;
908
909         /*
910          * At least according to draft-brezak-win2k-krb-rc4-hmac-04,
911          * if the signing algorithm is KRB_SGN_ALG_HMAC, there's an
912          * extra 8 bytes of "Random confounder" after the checksum.
913          * It certainly confounds code expecting all Kerberos 5
914          * GSS_Wrap() tokens to look the same....
915          *
916          * The exception is DNS/TSIG where there is no such confounder
917          * so we need to test here if there are more bytes in our tvb or not.
918          *  -- ronnie
919          */
920         if (tvb_length_remaining(tvb, offset)) {
921           if (sgn_alg == KRB_SGN_ALG_HMAC) {
922             proto_tree_add_item(tree, hf_spnego_krb5_confounder, tvb, offset, 8,
923                               TRUE);
924
925             offset += 8;
926           }
927         }
928
929         /*
930          * Return the offset past the checksum, so that we know where
931          * the data we're wrapped around starts.  Also, set the length
932          * of our top-level item to that offset, so it doesn't cover
933          * the data we're wrapped around.
934          */
935
936         return offset;
937 }
938
939 static int
940 dissect_spnego_krb5_cfx_flags(tvbuff_t *tvb, int offset,
941                               proto_tree *spnego_krb5_tree,
942                               guint8 cfx_flags)
943 {
944         proto_tree *cfx_flags_tree = NULL;
945         proto_item *tf = NULL;
946
947         if (spnego_krb5_tree) {
948                 tf = proto_tree_add_uint(spnego_krb5_tree,
949                                          hf_spnego_krb5_cfx_flags,
950                                          tvb, offset, 1, cfx_flags);
951                 cfx_flags_tree = proto_item_add_subtree(tf, ett_spnego_krb5_cfx_flags);
952         }
953
954         proto_tree_add_boolean(cfx_flags_tree,
955                                hf_spnego_krb5_cfx_flags_04,
956                                tvb, offset, 1, cfx_flags);
957         proto_tree_add_boolean(cfx_flags_tree,
958                                hf_spnego_krb5_cfx_flags_02,
959                                tvb, offset, 1, cfx_flags);
960         proto_tree_add_boolean(cfx_flags_tree,
961                                hf_spnego_krb5_cfx_flags_01,
962                                tvb, offset, 1, cfx_flags);
963
964         return (offset + 1);
965 }
966
967 /*
968  * This is for GSSAPI CFX Wrap tokens ...
969  */
970 static int
971 dissect_spnego_krb5_cfx_wrap_base(tvbuff_t *tvb, int offset, packet_info *pinfo
972 #ifndef HAVE_KERBEROS
973         _U_
974 #endif
975     , proto_tree *tree, guint16 token_id _U_
976     )
977 {
978         guint8 flags;
979         guint16 ec;
980         guint16 rrc;
981         int checksum_size;
982         int start_offset=offset;
983
984         /*
985          * The KRB5 blob conforms to RFC4121:
986          *   USHORT (0x0504)
987          *   and so on }
988          */
989
990         /* Now, the sign and seal algorithms ... */
991
992         flags = tvb_get_guint8(tvb, offset);
993         offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
994
995         pinfo->gssapi_data_encrypted=(flags & 2);
996
997         /* Skip the filler */
998
999         proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 1,
1000                             FALSE);
1001         offset += 1;
1002
1003         /* EC */
1004         ec = tvb_get_ntohs(tvb, offset);
1005         proto_tree_add_item(tree, hf_spnego_krb5_cfx_ec, tvb, offset, 2,
1006                             FALSE);
1007         offset += 2;
1008
1009         /* RRC */
1010         rrc = tvb_get_ntohs(tvb, offset);
1011         proto_tree_add_item(tree, hf_spnego_krb5_cfx_rrc, tvb, offset, 2,
1012                             FALSE);
1013         offset += 2;
1014
1015         /* sequence number */
1016
1017         proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1018                             FALSE);
1019         offset += 8;
1020
1021         /* Checksum of plaintext padded data */
1022
1023         if (pinfo->gssapi_data_encrypted) {
1024                 checksum_size = 44 + ec;
1025         } else {
1026                 checksum_size = 12;
1027         }
1028
1029         proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1030                             checksum_size, FALSE);
1031         offset += checksum_size;
1032
1033         if(pinfo->decrypt_gssapi_tvb){
1034                 /* if the caller did not provide a tvb, then we just use
1035                    whatever is left of our current tvb.
1036                 */
1037                 if(!pinfo->gssapi_encrypted_tvb){
1038                         int len;
1039                         len=tvb_reported_length_remaining(tvb,offset);
1040                         if(len>tvb_length_remaining(tvb, offset)){
1041                                 /* no point in trying to decrypt,
1042                                    we dont have the full pdu.
1043                                 */
1044                                 return offset;
1045                         }
1046                         pinfo->gssapi_encrypted_tvb = tvb_new_subset(
1047                                         tvb, offset, len, len);
1048                 }
1049
1050                 if (pinfo->gssapi_data_encrypted) {
1051                         /* do we need to create a tvb for the wrapper
1052                            as well ?
1053                         */
1054                         if(!pinfo->gssapi_wrap_tvb){
1055                                 pinfo->gssapi_wrap_tvb = tvb_new_subset(
1056                                         tvb, start_offset-2,
1057                                         offset - (start_offset-2),
1058                                         offset - (start_offset-2));
1059                         }
1060                 }
1061         }
1062
1063 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
1064         pinfo->gssapi_encrypted_tvb = tvb_new_subset(tvb, 16, -1, -1);
1065
1066         if (flags & 0x0002) {
1067                 if(pinfo->gssapi_encrypted_tvb){
1068                         decrypt_gssapi_krb_cfx_wrap(tree,
1069                                 pinfo,
1070                                 pinfo->gssapi_encrypted_tvb,
1071                                 ec,
1072                                 rrc,
1073                                 -1,
1074                                 (flags & 0x0001)?
1075                                 KRB5_KU_USAGE_ACCEPTOR_SEAL:
1076                                 KRB5_KU_USAGE_INITIATOR_SEAL);
1077                 }
1078         }
1079 #endif /* HAVE_HEIMDAL_KERBEROS || HAVE_MIT_KERBEROS */
1080
1081         /*
1082          * Return the offset past the checksum, so that we know where
1083          * the data we're wrapped around starts.  Also, set the length
1084          * of our top-level item to that offset, so it doesn't cover
1085          * the data we're wrapped around.
1086          *
1087          * Note that for DCERPC the GSSAPI blobs comes after the data it wraps,
1088          * not before.
1089          */
1090         return offset;
1091 }
1092
1093 /*
1094  * XXX - This is for GSSAPI CFX GetMIC tokens ...
1095  */
1096 static int
1097 dissect_spnego_krb5_cfx_getmic_base(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
1098 {
1099         guint8 flags;
1100         int checksum_size;
1101
1102         /*
1103          * The KRB5 blob conforms to RFC4121:
1104          *   USHORT (0x0404 == GSS_GetMIC)
1105          *   and so on }
1106          */
1107
1108         flags = tvb_get_guint8(tvb, offset);
1109         offset = dissect_spnego_krb5_cfx_flags(tvb, offset, tree, flags);
1110
1111         /* Skip the filler */
1112
1113         proto_tree_add_item(tree, hf_spnego_krb5_filler, tvb, offset, 5,
1114                             FALSE);
1115         offset += 5;
1116
1117         /* sequence number */
1118
1119         proto_tree_add_item(tree, hf_spnego_krb5_cfx_seq, tvb, offset, 8,
1120                             FALSE);
1121         offset += 8;
1122
1123         /* Checksum of plaintext padded data */
1124
1125         checksum_size = tvb_length_remaining(tvb, offset);
1126
1127         proto_tree_add_item(tree, hf_spnego_krb5_sgn_cksum, tvb, offset,
1128                             checksum_size, FALSE);
1129         offset += checksum_size;
1130
1131         /*
1132          * Return the offset past the checksum, so that we know where
1133          * the data we're wrapped around starts.  Also, set the length
1134          * of our top-level item to that offset, so it doesn't cover
1135          * the data we're wrapped around.
1136          */
1137
1138         return offset;
1139 }
1140
1141 /*
1142  * XXX - is this for SPNEGO or just GSS-API?
1143  * RFC 1964 is "The Kerberos Version 5 GSS-API Mechanism"; presumably one
1144  * can directly designate Kerberos V5 as a mechanism in GSS-API, rather
1145  * than designating SPNEGO as the mechanism, offering Kerberos V5, and
1146  * getting it accepted.
1147  */
1148 static int
1149 dissect_spnego_krb5_wrap(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1150 {
1151         proto_item *item;
1152         proto_tree *subtree;
1153         int offset = 0;
1154         guint16 token_id;
1155
1156         item = proto_tree_add_item(tree, hf_spnego_krb5, tvb, 0, -1, FALSE);
1157
1158         subtree = proto_item_add_subtree(item, ett_spnego_krb5);
1159
1160         /*
1161          * The KRB5 blob conforms to RFC1964:
1162          *   USHORT (0x0102 == GSS_Wrap)
1163          *   and so on }
1164          */
1165
1166         /* First, the token ID ... */
1167
1168         token_id = tvb_get_letohs(tvb, offset);
1169         proto_tree_add_uint(subtree, hf_spnego_krb5_tok_id, tvb, offset, 2,
1170                             token_id);
1171
1172         offset += 2;
1173
1174         switch (token_id) {
1175         case KRB_TOKEN_GETMIC:
1176           offset = dissect_spnego_krb5_getmic_base(tvb, offset, pinfo, subtree);
1177           break;
1178
1179         case KRB_TOKEN_WRAP:
1180           offset = dissect_spnego_krb5_wrap_base(tvb, offset, pinfo, subtree, token_id);
1181           break;
1182
1183         case KRB_TOKEN_CFX_GETMIC:
1184           offset = dissect_spnego_krb5_cfx_getmic_base(tvb, offset, pinfo, subtree);
1185           break;
1186
1187         case KRB_TOKEN_CFX_WRAP:
1188           offset = dissect_spnego_krb5_cfx_wrap_base(tvb, offset, pinfo, subtree, token_id);
1189           break;
1190
1191         default:
1192
1193           break;
1194         }
1195
1196         /*
1197          * Return the offset past the checksum, so that we know where
1198          * the data we're wrapped around starts.  Also, set the length
1199          * of our top-level item to that offset, so it doesn't cover
1200          * the data we're wrapped around.
1201          */
1202         proto_item_set_len(item, offset);
1203         return offset;
1204 }
1205
1206 /* Spnego stuff from here */
1207
1208 static int
1209 dissect_spnego_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1210 {
1211         proto_item *item;
1212         proto_tree *subtree;
1213         int offset = 0;
1214         asn1_ctx_t asn1_ctx;
1215         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1216
1217
1218
1219         /*
1220          * We need this later, so lets get it now ...
1221          * It has to be per-frame as there can be more than one GSS-API
1222          * negotiation in a conversation.
1223          */
1224
1225
1226         item = proto_tree_add_item(tree, hf_spnego, tvb, offset,
1227                                    -1, FALSE);
1228
1229         subtree = proto_item_add_subtree(item, ett_spnego);
1230         /*
1231          * The TVB contains a [0] header and a sequence that consists of an
1232          * object ID and a blob containing the data ...
1233          * XXX - is this RFC 2743's "Mechanism-Independent Token Format",
1234          * with the "optional" "use in non-initial tokens" being chosen.
1235          * ASN1 code addet to spnego.asn to handle this.
1236          */
1237
1238         offset = dissect_spnego_InitialContextToken(FALSE, tvb, offset, &asn1_ctx , subtree, -1);
1239
1240         return offset;
1241 }
1242
1243
1244 static void
1245 dissect_spnego(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
1246 {
1247         proto_item *item;
1248         proto_tree *subtree;
1249         int offset = 0;
1250         conversation_t *conversation;
1251         asn1_ctx_t asn1_ctx;
1252         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1253
1254         /*
1255          * We need this later, so lets get it now ...
1256          * It has to be per-frame as there can be more than one GSS-API
1257          * negotiation in a conversation.
1258          */
1259         next_level_value = p_get_proto_data(pinfo->fd, proto_spnego);
1260         if (!next_level_value && !pinfo->fd->flags.visited) {
1261             /*
1262              * No handle attached to this frame, but it's the first
1263              * pass, so it'd be attached to the conversation.
1264              * If we have a conversation, try to get the handle,
1265              * and if we get one, attach it to the frame.
1266              */
1267             conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
1268                                              pinfo->ptype, pinfo->srcport,
1269                                              pinfo->destport, 0);
1270
1271             if (conversation) {
1272                 next_level_value = conversation_get_proto_data(conversation,
1273                                                                proto_spnego);
1274                 if (next_level_value)
1275                     p_add_proto_data(pinfo->fd, proto_spnego, next_level_value);
1276             }
1277         }
1278
1279         item = proto_tree_add_item(parent_tree, hf_spnego, tvb, offset,
1280                                    -1, FALSE);
1281
1282         subtree = proto_item_add_subtree(item, ett_spnego);
1283
1284         /*
1285          * The TVB contains a [0] header and a sequence that consists of an
1286          * object ID and a blob containing the data ...
1287          * Actually, it contains, according to RFC2478:
1288          * NegotiationToken ::= CHOICE {
1289          *          negTokenInit [0] NegTokenInit,
1290          *          negTokenTarg [1] NegTokenTarg }
1291          * NegTokenInit ::= SEQUENCE {
1292          *          mechTypes [0] MechTypeList OPTIONAL,
1293          *          reqFlags [1] ContextFlags OPTIONAL,
1294          *          mechToken [2] OCTET STRING OPTIONAL,
1295          *          mechListMIC [3] OCTET STRING OPTIONAL }
1296          * NegTokenTarg ::= SEQUENCE {
1297          *          negResult [0] ENUMERATED {
1298          *              accept_completed (0),
1299          *              accept_incomplete (1),
1300          *              reject (2) } OPTIONAL,
1301          *          supportedMech [1] MechType OPTIONAL,
1302          *          responseToken [2] OCTET STRING OPTIONAL,
1303          *          mechListMIC [3] OCTET STRING OPTIONAL }
1304          *
1305          * Windows typically includes mechTypes and mechListMic ('NONE'
1306          * in the case of NTLMSSP only).
1307          * It seems to duplicate the responseToken into the mechListMic field
1308          * as well. Naughty, naughty.
1309          *
1310          */
1311         offset = dissect_spnego_NegotiationToken(FALSE, tvb, offset, &asn1_ctx, subtree, -1);
1312
1313 }
1314
1315 /*--- proto_register_spnego -------------------------------------------*/
1316 void proto_register_spnego(void) {
1317
1318         /* List of fields */
1319         static hf_register_info hf[] = {
1320                 { &hf_spnego,
1321                   { "SPNEGO", "spnego", FT_NONE, BASE_NONE, NULL, 0x0,
1322                     "SPNEGO", HFILL }},
1323                 { &hf_spnego_wraptoken,
1324                   { "wrapToken", "spnego.wraptoken",
1325                     FT_NONE, BASE_NONE, NULL, 0x0, "SPNEGO wrapToken",
1326                     HFILL}},
1327                 { &hf_spnego_krb5,
1328                   { "krb5_blob", "spnego.krb5.blob", FT_BYTES,
1329                     BASE_NONE, NULL, 0, "krb5_blob", HFILL }},
1330                 { &hf_spnego_krb5_oid,
1331                   { "KRB5 OID", "spnego.krb5_oid", FT_STRING,
1332                     BASE_NONE, NULL, 0, "KRB5 OID", HFILL }},
1333                 { &hf_spnego_krb5_tok_id,
1334                   { "krb5_tok_id", "spnego.krb5.tok_id", FT_UINT16, BASE_HEX,
1335                     VALS(spnego_krb5_tok_id_vals), 0, "KRB5 Token Id", HFILL}},
1336                 { &hf_spnego_krb5_sgn_alg,
1337                   { "krb5_sgn_alg", "spnego.krb5.sgn_alg", FT_UINT16, BASE_HEX,
1338                     VALS(spnego_krb5_sgn_alg_vals), 0, "KRB5 Signing Algorithm", HFILL}},
1339                 { &hf_spnego_krb5_seal_alg,
1340                   { "krb5_seal_alg", "spnego.krb5.seal_alg", FT_UINT16, BASE_HEX,
1341                     VALS(spnego_krb5_seal_alg_vals), 0, "KRB5 Sealing Algorithm", HFILL}},
1342                 { &hf_spnego_krb5_snd_seq,
1343                   { "krb5_snd_seq", "spnego.krb5.snd_seq", FT_BYTES, BASE_NONE,
1344                     NULL, 0, "KRB5 Encrypted Sequence Number", HFILL}},
1345                 { &hf_spnego_krb5_sgn_cksum,
1346                   { "krb5_sgn_cksum", "spnego.krb5.sgn_cksum", FT_BYTES, BASE_NONE,
1347                     NULL, 0, "KRB5 Data Checksum", HFILL}},
1348                 { &hf_spnego_krb5_confounder,
1349                   { "krb5_confounder", "spnego.krb5.confounder", FT_BYTES, BASE_NONE,
1350                     NULL, 0, "KRB5 Confounder", HFILL}},
1351                 { &hf_spnego_krb5_filler,
1352                   { "krb5_filler", "spnego.krb5.filler", FT_BYTES, BASE_HEX,
1353                     NULL, 0, "KRB5 Filler", HFILL}},
1354                 { &hf_spnego_krb5_cfx_flags,
1355                   { "krb5_cfx_flags", "spnego.krb5.cfx_flags", FT_UINT8, BASE_HEX,
1356                     NULL, 0, "KRB5 CFX Flags", HFILL}},
1357                 { &hf_spnego_krb5_cfx_flags_01,
1358                   { "SendByAcceptor", "spnego.krb5.send_by_acceptor", FT_BOOLEAN, 8,
1359                     TFS (&flags_set_truth), 0x01, "", HFILL}},
1360                 { &hf_spnego_krb5_cfx_flags_02,
1361                   { "Sealed", "spnego.krb5.sealed", FT_BOOLEAN, 8,
1362                     TFS (&flags_set_truth), 0x02, "", HFILL}},
1363                 { &hf_spnego_krb5_cfx_flags_04,
1364                   { "AcceptorSubkey", "spnego.krb5.acceptor_subkey", FT_BOOLEAN, 8,
1365                     TFS (&flags_set_truth), 0x04, "", HFILL}},
1366                 { &hf_spnego_krb5_cfx_ec,
1367                   { "krb5_cfx_ec", "spnego.krb5.cfx_ec", FT_UINT16, BASE_DEC,
1368                     NULL, 0, "KRB5 CFX Extra Count", HFILL}},
1369                 { &hf_spnego_krb5_cfx_rrc,
1370                   { "krb5_cfx_rrc", "spnego.krb5.cfx_rrc", FT_UINT16, BASE_DEC,
1371                     NULL, 0, "KRB5 CFX Right Rotation Count", HFILL}},
1372                 { &hf_spnego_krb5_cfx_seq,
1373                   { "krb5_cfx_seq", "spnego.krb5.cfx_seq", FT_UINT64, BASE_DEC,
1374                     NULL, 0, "KRB5 Sequence Number", HFILL}},
1375
1376 #include "packet-spnego-hfarr.c"
1377         };
1378
1379         /* List of subtrees */
1380         static gint *ett[] = {
1381                 &ett_spnego,
1382                 &ett_spnego_wraptoken,
1383                 &ett_spnego_krb5,
1384                 &ett_spnego_krb5_cfx_flags,
1385
1386 #include "packet-spnego-ettarr.c"
1387         };
1388
1389         /* Register protocol */
1390         proto_spnego = proto_register_protocol(PNAME, PSNAME, PFNAME);
1391
1392         register_dissector("spnego", dissect_spnego, proto_spnego);
1393
1394         proto_spnego_krb5 = proto_register_protocol("SPNEGO-KRB5",
1395                                                     "SPNEGO-KRB5",
1396                                                     "spnego-krb5");
1397
1398         register_dissector("spnego-krb5", dissect_spnego_krb5, proto_spnego_krb5);
1399         new_register_dissector("spnego-krb5-wrap", dissect_spnego_krb5_wrap, proto_spnego_krb5);
1400
1401         /* Register fields and subtrees */
1402         proto_register_field_array(proto_spnego, hf, array_length(hf));
1403         proto_register_subtree_array(ett, array_length(ett));
1404 }
1405
1406
1407 /*--- proto_reg_handoff_spnego ---------------------------------------*/
1408 void proto_reg_handoff_spnego(void) {
1409
1410         dissector_handle_t spnego_handle, spnego_wrap_handle;
1411         dissector_handle_t spnego_krb5_handle, spnego_krb5_wrap_handle;
1412
1413         /* Register protocol with GSS-API module */
1414
1415         spnego_handle = find_dissector("spnego");
1416         spnego_wrap_handle = new_create_dissector_handle(dissect_spnego_wrap,  proto_spnego);
1417         gssapi_init_oid("1.3.6.1.5.5.2", proto_spnego, ett_spnego,
1418             spnego_handle, spnego_wrap_handle,
1419             "SPNEGO - Simple Protected Negotiation");
1420
1421         /* Register both the one MS created and the real one */
1422         /*
1423          * Thanks to Jean-Baptiste Marchand and Richard B Ward, the
1424          * mystery of the MS KRB5 OID is cleared up. It was due to a library
1425          * that did not handle OID components greater than 16 bits, and was
1426          * fixed in Win2K SP2 as well as WinXP.
1427          * See the archive of <ietf-krb-wg@anl.gov> for the thread topic
1428          * SPNEGO implementation issues. 3-Dec-2002.
1429          */
1430         spnego_krb5_handle = find_dissector("spnego-krb5");
1431         spnego_krb5_wrap_handle = find_dissector("spnego-krb5-wrap");
1432         gssapi_init_oid("1.2.840.48018.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1433                         spnego_krb5_handle, spnego_krb5_wrap_handle,
1434                         "MS KRB5 - Microsoft Kerberos 5");
1435         gssapi_init_oid("1.2.840.113554.1.2.2", proto_spnego_krb5, ett_spnego_krb5,
1436                         spnego_krb5_handle, spnego_krb5_wrap_handle,
1437                         "KRB5 - Kerberos 5");
1438         gssapi_init_oid("1.2.840.113554.1.2.2.3", proto_spnego_krb5, ett_spnego_krb5,
1439                         spnego_krb5_handle, spnego_krb5_wrap_handle,
1440                         "KRB5 - Kerberos 5 - User to User");
1441
1442 }