2 * Dissect the NEGOEX security protocol
3 * as described here: http://tools.ietf.org/id/draft-zhu-negoex-04.txt
4 * Copyright 2012 Richard Sharpe <realrichardsharpe@gmail.com>
5 * Routines for SPNEGO Extended Negotiation Security Mechanism
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <epan/packet.h>
30 #include <epan/exceptions.h>
31 #include <epan/show_exception.h>
33 #include "packet-dcerpc.h"
34 #include "packet-gssapi.h"
36 void proto_register_negoex(void);
37 void proto_reg_handoff_negoex(void);
39 static int proto_negoex = -1;
40 static int hf_negoex_sig = -1;
41 static int hf_negoex_message_type = -1;
42 static int hf_negoex_sequence_num = -1;
43 static int hf_negoex_header_len = -1;
44 static int hf_negoex_message_len = -1;
45 static int hf_negoex_conversation_id = -1;
46 static int hf_negoex_random = -1;
47 static int hf_negoex_proto_version = -1;
48 static int hf_negoex_authscheme = -1;
49 static int hf_negoex_authscheme_vector_offset = -1;
50 static int hf_negoex_authscheme_vector_count = -1;
51 static int hf_negoex_authscheme_vector_pad = -1;
52 static int hf_negoex_extension = -1;
53 static int hf_negoex_extension_vector_offset = -1;
54 static int hf_negoex_extension_vector_count = -1;
55 static int hf_negoex_extension_vector_pad = -1;
56 static int hf_negoex_exchange_vector_offset = -1;
57 static int hf_negoex_exchange_vector_count = -1;
58 static int hf_negoex_exchange_vector_pad = -1;
59 static int hf_negoex_exchange = -1;
60 static int hf_negoex_checksum_scheme = -1;
61 static int hf_negoex_checksum_type = -1;
62 static int hf_negoex_checksum_vector_offset = -1;
63 static int hf_negoex_checksum_vector_count = -1;
64 static int hf_negoex_checksum_vector_pad = -1;
65 static int hf_negoex_checksum = -1;
66 static int hf_negoex_errorcode = -1;
68 static gint ett_negoex = -1;
69 static gint ett_negoex_msg = -1;
70 static gint ett_negoex_hdr = -1;
71 static gint ett_negoex_authscheme_vector = -1;
72 static gint ett_negoex_extension_vector = -1;
73 static gint ett_negoex_exchange = -1;
74 static gint ett_negoex_checksum = -1;
75 static gint ett_negoex_checksum_vector = -1;
76 static gint ett_negoex_byte_vector = -1;
78 /* If you add more message types, add them in sequence and update MAX_MSG */
79 #define MESSAGE_TYPE_INITIATOR_NEGO 0
80 #define MESSAGE_TYPE_ACCEPTOR_NEGO 1
81 #define MESSAGE_TYPE_INITIATOR_META_DATA 2
82 #define MESSAGE_TYPE_ACCEPTOR_META_DATA 3
83 #define MESSAGE_TYPE_CHALLENGE 4
84 #define MESSAGE_TYPE_AP_REQUEST 5
85 #define MESSAGE_TYPE_VERIFY 6
86 #define MESSAGE_TYPE_ALERT 7
87 #define MESSAGE_TYPE_MAX_MSG MESSAGE_TYPE_ALERT
89 static const value_string negoex_message_types[] = {
90 {MESSAGE_TYPE_INITIATOR_NEGO, "INITATOR_NEGO"},
91 {MESSAGE_TYPE_ACCEPTOR_NEGO, "ACCEPTOR_NEGO"},
92 {MESSAGE_TYPE_INITIATOR_META_DATA, "INITIATOR_META_DATA"},
93 {MESSAGE_TYPE_ACCEPTOR_META_DATA, "ACCEPTOR_META_DATA"},
94 {MESSAGE_TYPE_CHALLENGE, "CHALLENGE"},
95 {MESSAGE_TYPE_AP_REQUEST, "AP_REQUEST"},
96 {MESSAGE_TYPE_VERIFY, "VERIFY"},
97 {MESSAGE_TYPE_ALERT, "ALERT"},
101 static const value_string checksum_schemes[] = {
107 static const value_string alert_types[] = {
108 {1, "ALERT_TYPE_PULSE"},
112 static const value_string alert_reasons[] = {
113 {1, "ALERT_VERIFY_NO_KEY"},
119 dissect_negoex_alert_message(tvbuff_t *tvb,
120 packet_info *pinfo _U_,
129 proto_tree_add_item(tree, hf_negoex_authscheme, tvb, offset, 16, ENC_LITTLE_ENDIAN);
132 /* ErrorCode, an NTSTATUS :-) */
133 proto_tree_add_item(tree, hf_negoex_errorcode, tvb, offset, 4, ENC_LITTLE_ENDIAN);
137 proto_tree_add_text(tree, tvb, offset, tvb_length(tvb) - offset,
138 "The rest of the alert message");
143 dissect_negoex_verify_message(tvbuff_t *tvb,
144 packet_info *pinfo _U_,
149 guint32 checksum_vector_offset;
150 guint32 checksum_vector_count;
152 proto_tree *checksum;
154 proto_tree *checksum_vector;
159 proto_tree_add_item(tree, hf_negoex_authscheme, tvb, offset, 16, ENC_LITTLE_ENDIAN);
163 pi = proto_tree_add_text(tree, tvb, offset, 20, "Checksum");
164 checksum = proto_item_add_subtree(pi, ett_negoex_checksum);
167 proto_tree_add_item(checksum, hf_negoex_header_len, tvb, offset, 4, ENC_LITTLE_ENDIAN);
171 proto_tree_add_item(checksum, hf_negoex_checksum_scheme, tvb, offset, 4, ENC_LITTLE_ENDIAN);
175 proto_tree_add_item(checksum, hf_negoex_checksum_type, tvb, offset, 4, ENC_LITTLE_ENDIAN);
178 /* Checksum Byte Vector */
179 checksum_vector_offset = tvb_get_letohl(tvb, offset);
180 checksum_vector_count = tvb_get_letohs(tvb, offset + 4);
182 pi_chk = proto_tree_add_text(checksum, tvb, offset, 8,
183 "Checksum Vector: %u at %u",
184 checksum_vector_count,
185 checksum_vector_offset);
186 checksum_vector = proto_item_add_subtree(pi_chk, ett_negoex_checksum_vector);
188 proto_tree_add_item(checksum_vector, hf_negoex_checksum_vector_offset, tvb,
189 offset, 4, ENC_LITTLE_ENDIAN);
192 proto_tree_add_item(checksum_vector, hf_negoex_checksum_vector_count, tvb,
193 offset, 2, ENC_LITTLE_ENDIAN);
196 proto_tree_add_item(checksum_vector, hf_negoex_checksum_vector_pad, tvb,
200 proto_tree_add_item(checksum_vector, hf_negoex_checksum, tvb,
201 checksum_vector_offset, checksum_vector_count, ENC_NA);
206 dissect_negoex_exchange_message(tvbuff_t *tvb,
207 packet_info *pinfo _U_,
212 guint32 exchange_vector_offset;
213 guint32 exchange_vector_count;
215 proto_tree *exchange_vector;
220 proto_tree_add_item(tree, hf_negoex_authscheme, tvb, offset, 16, ENC_LITTLE_ENDIAN);
223 /* Exchange Byte Vector */
224 exchange_vector_offset = tvb_get_letohl(tvb, offset);
225 exchange_vector_count = tvb_get_letohs(tvb, offset + 4);
227 pi = proto_tree_add_text(tree, tvb, offset, 8, "Exchange: %u bytes at %u",
228 exchange_vector_count, exchange_vector_offset);
229 exchange_vector = proto_item_add_subtree(pi, ett_negoex_exchange);
231 proto_tree_add_item(exchange_vector, hf_negoex_exchange_vector_offset, tvb,
232 offset, 4, ENC_LITTLE_ENDIAN);
235 proto_tree_add_item(exchange_vector, hf_negoex_exchange_vector_count, tvb,
236 offset, 2, ENC_LITTLE_ENDIAN);
239 proto_tree_add_item(exchange_vector, hf_negoex_exchange_vector_pad, tvb,
243 proto_tree_add_item(exchange_vector, hf_negoex_exchange, tvb,
244 exchange_vector_offset, exchange_vector_count, ENC_NA);
248 * In each of the subdissectors we are handed the whole message, but the
249 * header is already dissected. The offset tells us where in the buffer the
250 * actual data starts. This is a bit redundant, but it allows for changes
251 * to the header structure ...
253 * Eventually we want to treat the header and body differently perhaps.
256 dissect_negoex_nego_message(tvbuff_t *tvb,
257 packet_info *pinfo _U_,
261 volatile guint32 offset;
262 guint32 authscheme_vector_offset;
263 guint16 authscheme_vector_count;
264 guint32 extension_vector_offset;
265 guint32 extension_vector_count;
266 proto_item *pi, *ext_pi;
267 proto_tree *authscheme_vector;
268 proto_tree *extension_vector;
274 /* The Random field */
275 proto_tree_add_item(tree, hf_negoex_random, tvb, offset, 32, ENC_ASCII);
278 /* Protocol version */
279 proto_tree_add_item(tree, hf_negoex_proto_version, tvb, offset, 8, ENC_LITTLE_ENDIAN);
282 /* AuthScheme offset and count */
283 authscheme_vector_offset = tvb_get_letohl(tvb, offset);
284 authscheme_vector_count = tvb_get_letohs(tvb, offset + 4);
286 pi = proto_tree_add_text(tree, tvb, offset, 8, "AuthSchemes: %u at %u",
287 authscheme_vector_count, authscheme_vector_offset);
288 authscheme_vector = proto_item_add_subtree(pi, ett_negoex_authscheme_vector);
289 proto_tree_add_item(authscheme_vector, hf_negoex_authscheme_vector_offset,
290 tvb, offset, 4, ENC_LITTLE_ENDIAN);
293 proto_tree_add_item(authscheme_vector, hf_negoex_authscheme_vector_count,
294 tvb, offset, 2, ENC_LITTLE_ENDIAN);
297 proto_tree_add_item(authscheme_vector, hf_negoex_authscheme_vector_pad,
298 tvb, offset, 2, ENC_NA);
301 /* Now, add the various items */
302 for (i = 0; i < authscheme_vector_count; i++) {
303 proto_tree_add_item(authscheme_vector, hf_negoex_authscheme, tvb,
304 authscheme_vector_offset + i * 16, 16, ENC_LITTLE_ENDIAN);
307 extension_vector_offset = tvb_get_letohl(tvb, offset);
308 extension_vector_count = tvb_get_letohs(tvb, offset + 4);
310 ext_pi = proto_tree_add_text(tree, tvb, offset, 8, "Extensions: %u at %u",
311 extension_vector_count, extension_vector_count);
312 extension_vector = proto_item_add_subtree(ext_pi, ett_negoex_extension_vector);
314 proto_tree_add_item(extension_vector, hf_negoex_extension_vector_offset,
315 tvb, offset, 4, ENC_LITTLE_ENDIAN);
318 proto_tree_add_item(extension_vector, hf_negoex_extension_vector_count,
319 tvb, offset, 2, ENC_LITTLE_ENDIAN);
322 proto_tree_add_item(extension_vector, hf_negoex_extension_vector_pad,
323 tvb, offset, 2, ENC_NA);
326 for (i = 0; i < extension_vector_count; i++) {
327 guint32 byte_vector_offset, byte_vector_count;
332 * Dissect these things ... they consist of a byte vector, so we
333 * add a subtree and point to the relevant bytes
335 byte_vector_offset = tvb_get_letohl(tvb, offset);
336 byte_vector_count = tvb_get_letohs(tvb, offset + 4);
338 bv_pi = proto_tree_add_text(extension_vector, tvb,
339 extension_vector_offset + i * 8, 8,
340 "Extension: %u bytes at %u",
341 byte_vector_count, byte_vector_offset);
342 bv_tree = proto_item_add_subtree(bv_pi, ett_negoex_byte_vector);
344 proto_tree_add_item(bv_tree, hf_negoex_extension, tvb,
345 byte_vector_offset, byte_vector_count, ENC_NA);
354 dissect_negoex(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
356 volatile guint32 offset;
357 proto_tree * volatile negoex_tree;
359 volatile gboolean done;
362 guint32 message_type;
369 payload_len = tvb_length(tvb);
371 /* Set up the initial NEGOEX payload */
373 tf = proto_tree_add_item(tree, proto_negoex, tvb, offset, -1, ENC_NA);
374 negoex_tree = proto_item_add_subtree(tf, ett_negoex);
378 * There can be multiple negoex messages, each with a header with a length.
379 * However, the payload might not have been reassembled ...
382 while (offset < payload_len && !done) {
383 proto_tree *negoex_msg_tree;
384 proto_tree *negoex_hdr_tree;
388 guint32 start_offset;
390 start_offset = offset;
393 /* Message type, it is after the signature */
394 message_type = tvb_get_letohl(tvb, offset + 8);
396 /* Add the message type tree ... set its length below */
397 msg = proto_tree_add_text(negoex_tree, tvb, offset, -1,
399 val_to_str_const(message_type,
400 negoex_message_types,
401 "Unknown NEGOEX message type"));
403 /* Add a subtree for the message */
404 negoex_msg_tree = proto_item_add_subtree(msg, ett_negoex_msg);
406 /* Add a subtree for the header */
407 hdr = proto_tree_add_text(negoex_msg_tree, tvb, offset, 40, "Header");
408 negoex_hdr_tree = proto_item_add_subtree(hdr, ett_negoex_hdr);
410 /* Signature, NEGOEXTS */
411 proto_tree_add_item(negoex_hdr_tree, hf_negoex_sig,
412 tvb, offset, 8, ENC_ASCII | ENC_NA);
415 col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s",
416 val_to_str_const(message_type,
417 negoex_message_types,
418 "Unknown NEGOEX message type"));
419 proto_tree_add_uint(negoex_hdr_tree, hf_negoex_message_type,
420 tvb, offset, 4, message_type);
423 * If this is an unknown message type, we have to punt because anything
424 * following cannot be handled
426 if (message_type > MESSAGE_TYPE_MAX_MSG) {
427 offset = payload_len; /* Can't do any more */
433 /* Sequence Number */
434 proto_tree_add_item(negoex_hdr_tree, hf_negoex_sequence_num,
435 tvb, offset, 4, ENC_LITTLE_ENDIAN);
439 header_len = tvb_get_letohl(tvb, offset);
440 proto_tree_add_uint(negoex_hdr_tree, hf_negoex_header_len,
441 tvb, offset, 4, header_len);
445 message_len = tvb_get_letohl(tvb, offset);
446 proto_tree_add_uint(negoex_hdr_tree, hf_negoex_message_len,
447 tvb, offset, 4, message_len);
450 /* Set the message len so the tree item has correct len */
451 proto_item_set_len(msg, message_len);
453 /* Conversation ID */
454 proto_tree_add_item(negoex_hdr_tree, hf_negoex_conversation_id,
455 tvb, offset, 16, ENC_LITTLE_ENDIAN);
459 * Construct a new TVB covering just this message and pass to the
462 msg_tvb = tvb_new_subset(tvb,
464 MIN(message_len, tvb_length(tvb)),
467 switch (message_type) {
468 case MESSAGE_TYPE_INITIATOR_NEGO:
469 case MESSAGE_TYPE_ACCEPTOR_NEGO:
470 dissect_negoex_nego_message(msg_tvb,
473 offset - start_offset);
476 case MESSAGE_TYPE_INITIATOR_META_DATA:
477 case MESSAGE_TYPE_ACCEPTOR_META_DATA:
478 case MESSAGE_TYPE_CHALLENGE:
479 case MESSAGE_TYPE_AP_REQUEST:
480 dissect_negoex_exchange_message(msg_tvb,
483 offset - start_offset);
486 case MESSAGE_TYPE_VERIFY:
487 dissect_negoex_verify_message(msg_tvb,
490 offset - start_offset);
493 case MESSAGE_TYPE_ALERT:
494 dissect_negoex_alert_message(msg_tvb,
497 offset - start_offset);
501 proto_tree_add_text(negoex_msg_tree, tvb, offset, message_len - 40,
502 "The rest of the message");
505 offset = start_offset + message_len;
507 /* We cannot branch out of the TRY block, but we can branch here */
511 } CATCH_NONFATAL_ERRORS {
513 show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
520 proto_register_negoex(void)
523 static hf_register_info hf[] = {
525 { "Signature", "negoex.message.sig", FT_STRING, BASE_NONE,
526 NULL, 0x0, NULL, HFILL }},
527 { &hf_negoex_message_type,
528 { "MessageType", "negoex.message.type", FT_UINT32, BASE_HEX,
529 VALS(negoex_message_types), 0x00, NULL, HFILL }},
530 { &hf_negoex_sequence_num,
531 { "SequencNum", "negoex.message.seq_num", FT_UINT32, BASE_DEC,
532 NULL, 0x0, NULL, HFILL }},
533 { &hf_negoex_header_len,
534 { "cbHeaderLength", "negoex.header.len", FT_UINT32, BASE_DEC,
535 NULL, 0x0, NULL, HFILL }},
536 { &hf_negoex_message_len,
537 { "cbMessageLength", "negoex.message.len", FT_UINT32, BASE_DEC,
538 NULL, 0x0, NULL, HFILL }},
539 { &hf_negoex_conversation_id,
540 { "ConversationID", "negoex.message.conv_id", FT_GUID, BASE_NONE,
541 NULL, 0x0, NULL, HFILL}},
543 { "Random", "negoex.message.random", FT_BYTES, BASE_NONE,
544 NULL, 0x0, "Random data", HFILL }},
545 { &hf_negoex_proto_version,
546 { "ProtocolVersion", "negoex.proto_version", FT_UINT64, BASE_DEC,
547 NULL, 0x0, NULL, HFILL}},
548 { &hf_negoex_authscheme,
549 { "AuthScheme", "negoex.auth_scheme", FT_GUID, BASE_NONE,
550 NULL, 0x0, NULL, HFILL}},
551 { &hf_negoex_authscheme_vector_offset,
552 { "AuthSchemeArrayOffset", "negoex.auth_scheme_array_offset", FT_UINT32,
553 BASE_DEC, NULL, 0x0, NULL, HFILL }},
554 { &hf_negoex_authscheme_vector_count,
555 { "AuthSchemeCount", "negoex.auth_scheme_array_count", FT_UINT16,
556 BASE_DEC, NULL, 0x0, NULL, HFILL }},
557 { &hf_negoex_authscheme_vector_pad,
558 { "AuthSchemePad", "negoex.auth_scheme_array_pad", FT_BYTES,
559 BASE_NONE, NULL, 0x0, NULL, HFILL }},
560 { &hf_negoex_extension,
561 { "Extension", "negoex.extension", FT_BYTES, BASE_NONE,
562 NULL, 0x0, "Extension data", HFILL }},
563 { &hf_negoex_extension_vector_offset,
564 { "ExtensionArrayOffset", "negoex.extension_array_offset", FT_UINT32,
565 BASE_DEC, NULL, 0x0, NULL, HFILL }},
566 { &hf_negoex_extension_vector_count,
567 { "ExtensionCount", "negoex.extension_array_count", FT_UINT16,
568 BASE_DEC, NULL, 0x0, NULL, HFILL }},
569 { &hf_negoex_extension_vector_pad,
570 { "ExtensionPad", "negoex.extension_pad", FT_BYTES,
571 BASE_NONE, NULL, 0x0, NULL, HFILL }},
572 { &hf_negoex_exchange_vector_offset,
573 { "ExchangeOffset", "negoex.exchange_vec_offset", FT_UINT32, BASE_DEC,
574 NULL, 0x0, NULL, HFILL}},
575 { &hf_negoex_exchange_vector_count,
576 { "ExchangeByteCount", "negoex.exchange_vec_byte_count", FT_UINT16,
577 BASE_DEC, NULL, 0x0, NULL, HFILL}},
578 { &hf_negoex_exchange_vector_pad,
579 { "ExchangePad", "negoex.exchange_vec_pad", FT_BYTES, BASE_NONE,
580 NULL, 0x0, NULL, HFILL}},
581 { &hf_negoex_exchange,
582 { "Exchange Bytes", "negoex.exchange", FT_BYTES, BASE_NONE,
583 NULL, 0x0, NULL, HFILL}},
584 { &hf_negoex_checksum_scheme,
585 { "ChecksumScheme", "negoex.checksum_scheme", FT_UINT32, BASE_DEC,
586 VALS(checksum_schemes), 0x0, NULL, HFILL}},
587 { &hf_negoex_checksum_vector_offset,
588 { "ChecksumOffset", "negoex.checksum_vec_offset", FT_UINT32, BASE_DEC,
589 NULL, 0x0, NULL, HFILL}},
590 { &hf_negoex_checksum_vector_count,
591 { "ChecksumCount", "negoex.checksum_vec_count", FT_UINT16, BASE_DEC,
592 NULL, 0x0, NULL, HFILL}},
593 { &hf_negoex_checksum_vector_pad,
594 { "ChecksumPad", "negoex.checksum_pad", FT_BYTES, BASE_NONE,
595 NULL, 0x0, NULL, HFILL}},
596 { &hf_negoex_checksum_type,
597 { "ChecksumType", "negoex.checksum_type", FT_UINT32, BASE_DEC,
598 NULL, 0x0, NULL, HFILL}},
599 { &hf_negoex_checksum,
600 { "Checksum", "negoex.checksum", FT_BYTES, BASE_NONE,
601 NULL, 0x0, NULL, HFILL}},
602 { &hf_negoex_errorcode,
603 { "ErrorCode", "negoex.errorcode", FT_UINT32, BASE_HEX,
604 NULL, 0x0, NULL, HFILL}},
607 static gint *ett[] = {
611 &ett_negoex_authscheme_vector,
612 &ett_negoex_extension_vector,
613 &ett_negoex_exchange,
614 &ett_negoex_checksum,
615 &ett_negoex_checksum_vector,
616 &ett_negoex_byte_vector,
618 /*module_t *negoex_module = NULL; */
620 proto_negoex = proto_register_protocol (
621 "SPNEGO Extended Negotiation Security Mechanism", /* name */
622 "NEGOEX", /* short name */
623 "negoex" /* abbrev */
625 proto_register_field_array(proto_negoex, hf, array_length(hf));
626 proto_register_subtree_array(ett, array_length(ett));
628 /* negoex_module = prefs_register_protocol(proto_negoex, NULL);*/
630 register_dissector("negoex", dissect_negoex, proto_negoex);
634 proto_reg_handoff_negoex(void)
636 dissector_handle_t negoex_handle;
638 /* Register protocol with the GSS-API module */
640 negoex_handle = find_dissector("negoex");
641 gssapi_init_oid("1.3.6.1.4.1.311.2.2.30", proto_negoex, ett_negoex,
643 "NEGOEX - SPNEGO Extended Negotiation Security Mechanism");
648 * Editor modelines - http://www.wireshark.org/tools/modelines.html
653 * indent-tabs-mode: nil
656 * vi: set shiftwidth=2 tabstop=8 expandtab:
657 * :indentSize=2:tabSize=8:noTabs=true: