Squelch a "signed vs. unsigned comparison" warning (which warned of a
[obnox/wireshark/wip.git] / packet-isakmp.c
1 /* packet-isakmp.c
2  * Routines for the Internet Security Association and Key Management Protocol
3  * (ISAKMP) (RFC 2408)
4  * Brad Robel-Forrest <brad.robel-forrest@watchguard.com>
5  *
6  * $Id: packet-isakmp.c,v 1.42 2001/08/31 19:47:07 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <stdio.h>
36 #include <string.h>
37
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
41
42 #include <glib.h>
43
44 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
46 #endif
47
48 #include "packet.h"
49 #include "ipproto.h"
50
51 static int proto_isakmp = -1;
52
53 static gint ett_isakmp = -1;
54 static gint ett_isakmp_flags = -1;
55 static gint ett_isakmp_payload = -1;
56
57 #define UDP_PORT_ISAKMP 500
58 #define TCP_PORT_ISAKMP 500
59
60 #define NUM_PROTO_TYPES 5
61 #define proto2str(t)    \
62   ((t < NUM_PROTO_TYPES) ? prototypestr[t] : "UNKNOWN-PROTO-TYPE")
63
64 static const char *prototypestr[NUM_PROTO_TYPES] = {
65   "RESERVED",
66   "ISAKMP",
67   "IPSEC_AH",
68   "IPSEC_ESP",
69   "IPCOMP"
70 };
71
72 #define NUM_P1_ATT_TYPES        17
73 #define p1_atttype2str(t)       \
74   ((t < NUM_P1_ATT_TYPES) ? p1_atttypestr[t] : "UNKNOWN-ATTRIBUTE-TYPE")
75
76 static const char *p1_atttypestr[NUM_P1_ATT_TYPES] = {
77   "UNKNOWN-ATTRIBUTE-TYPE",
78   "Encryption-Algorithm",
79   "Hash-Algorithm",
80   "Authentication-Method",
81   "Group-Description",
82   "Group-Type",
83   "Group-Prime",
84   "Group-Generator-One",
85   "Group-Generator-Two",
86   "Group-Curve-A",
87   "Group-Curve-B",
88   "Life-Type",
89   "Life-Duration",
90   "PRF",
91   "Key-Length",
92   "Field-Size",
93   "Group-Order"
94 };
95
96 #define NUM_ATT_TYPES   11
97 #define atttype2str(t)  \
98   ((t < NUM_ATT_TYPES) ? atttypestr[t] : "UNKNOWN-ATTRIBUTE-TYPE")
99
100 static const char *atttypestr[NUM_ATT_TYPES] = {
101   "UNKNOWN-ATTRIBUTE-TYPE",
102   "SA-Life-Type",
103   "SA-Life-Duration",
104   "Group-Description",
105   "Encapsulation-Mode",
106   "Authentication-Algorithm",
107   "Key-Length",
108   "Key-Rounds",
109   "Compress-Dictinary-Size",
110   "Compress-Private-Algorithm",
111   "ECN Tunnel"
112 };
113
114 #define NUM_TRANS_TYPES 2
115 #define trans2str(t)    \
116   ((t < NUM_TRANS_TYPES) ? transtypestr[t] : "UNKNOWN-TRANS-TYPE")
117
118 static const char *transtypestr[NUM_TRANS_TYPES] = {
119   "RESERVED",
120   "KEY_IKE"
121 };
122
123 #define NUM_AH_TRANS_TYPES      8
124 #define ah_trans2str(t)         \
125   ((t < NUM_AH_TRANS_TYPES) ? ah_transtypestr[t] : "UNKNOWN-AH-TRANS-TYPE")
126
127 static const char *ah_transtypestr[NUM_AH_TRANS_TYPES] = {
128   "RESERVED",
129   "RESERVED",
130   "MD5",
131   "SHA",
132   "DES",
133   "SHA2-256",
134   "SHA2-384",
135   "SHA2-512"
136 };
137
138 #define NUM_ESP_TRANS_TYPES     13
139 #define esp_trans2str(t)        \
140   ((t < NUM_ESP_TRANS_TYPES) ? esp_transtypestr[t] : "UNKNOWN-ESP-TRANS-TYPE")
141
142 static const char *esp_transtypestr[NUM_ESP_TRANS_TYPES] = {
143   "RESERVED",
144   "DES-IV64",
145   "DES",
146   "3DES",
147   "RC5",
148   "IDEA",
149   "CAST",
150   "BLOWFISH",
151   "3IDEA",
152   "DES-IV32",
153   "RC4",
154   "NULL",
155   "AES"
156 };
157
158 #define NUM_ID_TYPES    12
159 #define id2str(t)       \
160   ((t < NUM_ID_TYPES) ? idtypestr[t] : "UNKNOWN-ID-TYPE")
161
162 static const char *idtypestr[NUM_ID_TYPES] = {
163   "RESERVED",
164   "IPV4_ADDR",
165   "FQDN",
166   "USER_FQDN",
167   "IPV4_ADDR_SUBNET",
168   "IPV6_ADDR",
169   "IPV6_ADDR_SUBNET",
170   "IPV4_ADDR_RANGE",
171   "IPV6_ADDR_RANGE",
172   "DER_ASN1_DN",
173   "DER_ASN1_GN",
174   "KEY_ID"
175 };
176
177 struct isakmp_hdr {
178   guint8        icookie[8];
179   guint8        rcookie[8];
180   guint8        next_payload;
181   guint8        version;
182   guint8        exch_type;
183   guint8        flags;
184 #define E_FLAG          0x01
185 #define C_FLAG          0x02
186 #define A_FLAG          0x04
187   guint8        message_id[4];
188   guint8        length[4];
189 };
190
191 struct udp_encap_hdr {
192   guint8        non_ike_marker[8];
193   guint32       esp_SPI;
194 };
195
196 static proto_tree *dissect_payload_header(tvbuff_t *, int, int, guint8,
197     guint8 *, guint16 *, proto_tree *);
198
199 static void dissect_none(tvbuff_t *, int, int, proto_tree *);
200 static void dissect_sa(tvbuff_t *, int, int, proto_tree *);
201 static void dissect_proposal(tvbuff_t *, int, int, proto_tree *);
202 static void dissect_transform(tvbuff_t *, int, int, proto_tree *, guint8);
203 static void dissect_key_exch(tvbuff_t *, int, int, proto_tree *);
204 static void dissect_id(tvbuff_t *, int, int, proto_tree *);
205 static void dissect_cert(tvbuff_t *, int, int, proto_tree *);
206 static void dissect_certreq(tvbuff_t *, int, int, proto_tree *);
207 static void dissect_hash(tvbuff_t *, int, int, proto_tree *);
208 static void dissect_sig(tvbuff_t *, int, int, proto_tree *);
209 static void dissect_nonce(tvbuff_t *, int, int, proto_tree *);
210 static void dissect_notif(tvbuff_t *, int, int, proto_tree *);
211 static void dissect_delete(tvbuff_t *, int, int, proto_tree *);
212 static void dissect_vid(tvbuff_t *, int, int, proto_tree *);
213 static void dissect_config(tvbuff_t *, int, int, proto_tree *);
214
215 static const char *payloadtype2str(guint8);
216 static const char *exchtype2str(guint8);
217 static const char *doitype2str(guint32);
218 static const char *msgtype2str(guint16);
219 static const char *situation2str(guint32);
220 static const char *value2str(int, guint16, guint16);
221 static const char *attrtype2str(guint8);
222 static const char *cfgattrident2str(guint16);
223 static const char *certtype2str(guint8);
224
225 static gboolean get_num(tvbuff_t *, int, guint16, guint32 *);
226
227 #define LOAD_TYPE_PROPOSAL      2       /* payload type for Proposal */
228 #define LOAD_TYPE_TRANSFORM     3       /* payload type for Transform */
229 #define NUM_LOAD_TYPES          15
230 #define loadtype2str(t) \
231   ((t < NUM_LOAD_TYPES) ? strfuncs[t].str : "Unknown payload type")
232
233 static struct strfunc {
234   const char *  str;
235   void          (*func)(tvbuff_t *, int, int, proto_tree *);
236 } strfuncs[NUM_LOAD_TYPES] = {
237   {"NONE",                      dissect_none      },
238   {"Security Association",      dissect_sa        },
239   {"Proposal",                  dissect_proposal  },
240   {"Transform",                 NULL },
241   {"Key Exchange",              dissect_key_exch  },
242   {"Identification",            dissect_id        },
243   {"Certificate",               dissect_cert      },
244   {"Certificate Request",       dissect_certreq   },
245   {"Hash",                      dissect_hash      },
246   {"Signature",                 dissect_sig       },
247   {"Nonce",                     dissect_nonce     },
248   {"Notification",              dissect_notif     },
249   {"Delete",                    dissect_delete    },
250   {"Vendor ID",                 dissect_vid       },
251   {"Attrib",                    dissect_config    }
252 };
253
254 static dissector_handle_t esp_handle;
255 static dissector_handle_t ah_handle;
256
257 static void
258 dissect_isakmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
259 {
260   int                   offset = 0;
261   struct isakmp_hdr *   hdr;
262   proto_item *          ti;
263   proto_tree *          isakmp_tree = NULL;
264   struct udp_encap_hdr * encap_hdr;
265   guint32               len;
266   guint8                payload, next_payload;
267   guint16               payload_length;
268   proto_tree *          ntree;
269   static const guint8   non_ike_marker[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
270   tvbuff_t *            next_tvb;
271
272   if (check_col(pinfo->fd, COL_PROTOCOL))
273     col_set_str(pinfo->fd, COL_PROTOCOL, "ISAKMP");
274   if (check_col(pinfo->fd, COL_INFO))
275     col_clear(pinfo->fd, COL_INFO);
276
277   hdr = (struct isakmp_hdr *)tvb_get_ptr(tvb, 0, sizeof (struct isakmp_hdr));
278   len = pntohl(&hdr->length);
279   
280   if (tree) {
281     ti = proto_tree_add_item(tree, proto_isakmp, tvb, offset, len, FALSE);
282     isakmp_tree = proto_item_add_subtree(ti, ett_isakmp);
283   }
284     
285   encap_hdr = (struct udp_encap_hdr *)tvb_get_ptr(tvb, 0, sizeof(struct udp_encap_hdr));
286  
287   if (memcmp(encap_hdr->non_ike_marker,non_ike_marker,8) == 0) {
288     if (check_col(pinfo->fd, COL_INFO)) {
289       if (encap_hdr->esp_SPI != 0)
290           col_add_str(pinfo->fd, COL_INFO, "UDP encapsulated IPSec - ESP");
291       else
292          col_add_str(pinfo->fd, COL_INFO, "UDP encapsulated IPSec - AH");
293     } 
294     if (tree)
295       proto_tree_add_text(isakmp_tree, tvb, offset,
296                           sizeof(encap_hdr->non_ike_marker),
297                           "Non-IKE-Marker");
298     offset += sizeof(encap_hdr->non_ike_marker);
299       
300     if (encap_hdr->esp_SPI != 0) {
301       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
302       call_dissector(esp_handle, next_tvb, pinfo, tree);
303     } else {
304       if (tree)
305         proto_tree_add_text(isakmp_tree, tvb, offset,
306                             sizeof(encap_hdr->esp_SPI),
307                             "Non-ESP-Marker");
308       offset += sizeof(encap_hdr->esp_SPI);
309
310       if (tree)
311         proto_tree_add_text(isakmp_tree, tvb, offset, 1,
312                             "AH Envelope Version: %u",
313                             tvb_get_guint8(tvb, offset) >> 4);
314       offset += 1;
315
316       if (tree)
317         proto_tree_add_text(isakmp_tree, tvb, offset, 1,
318                             "AH Envelope Header Length: %u",
319                             (tvb_get_guint8(tvb, offset) & 0xF)*4);
320       offset += 1;
321
322       if (tree)
323         proto_tree_add_text(isakmp_tree, tvb, offset, 2,
324                             "AH Envelope Identification: 0x%04X",
325                             tvb_get_ntohs(tvb, offset));
326       offset += 2;
327
328       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
329       call_dissector(ah_handle, next_tvb, pinfo, tree);
330     }
331     return;
332   }
333
334   if (check_col(pinfo->fd, COL_INFO))
335     col_add_str(pinfo->fd, COL_INFO, exchtype2str(hdr->exch_type));
336
337   if (tree) {
338     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->icookie),
339                         "Initiator cookie");
340     offset += sizeof(hdr->icookie);
341     
342     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->rcookie),
343                         "Responder cookie");
344     offset += sizeof(hdr->rcookie);
345
346     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->next_payload),
347                         "Next payload: %s (%u)",
348                         payloadtype2str(hdr->next_payload), hdr->next_payload);
349     offset += sizeof(hdr->next_payload);
350
351     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->version),
352                         "Version: %u.%u",
353                         hi_nibble(hdr->version), lo_nibble(hdr->version));
354     offset += sizeof(hdr->version);
355     
356     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->exch_type),
357                         "Exchange type: %s (%u)",
358                         exchtype2str(hdr->exch_type), hdr->exch_type);
359     offset += sizeof(hdr->exch_type);
360     
361     {
362       proto_item *      fti;
363       proto_tree *      ftree;
364       
365       fti   = proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->flags), "Flags");
366       ftree = proto_item_add_subtree(fti, ett_isakmp_flags);
367       
368       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
369                           decode_boolean_bitfield(hdr->flags, E_FLAG, sizeof(hdr->flags)*8,
370                                                   "Encryption", "No encryption"));
371       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
372                           decode_boolean_bitfield(hdr->flags, C_FLAG, sizeof(hdr->flags)*8,
373                                                   "Commit", "No commit"));
374       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
375                           decode_boolean_bitfield(hdr->flags, A_FLAG, sizeof(hdr->flags)*8,
376                                                   "Authentication", "No authentication"));
377       offset += sizeof(hdr->flags);
378     }
379
380     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->message_id),
381         "Message ID: 0x%02x%02x%02x%02x", hdr->message_id[0],
382         hdr->message_id[1], hdr->message_id[2], hdr->message_id[3]);
383     offset += sizeof(hdr->message_id);
384     
385     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->length),
386                         "Length: %u", len);
387     offset += sizeof(hdr->length);
388     len -= sizeof(*hdr);
389
390     if (hdr->flags & E_FLAG) {
391       if (len && isakmp_tree) {
392         proto_tree_add_text(isakmp_tree, tvb, offset, len,
393                         "Encrypted payload (%d byte%s)",
394                         len, plurality(len, "", "s"));
395       }
396     } else {
397       for (payload = hdr->next_payload; len != 0; payload = next_payload) {
398         ntree = dissect_payload_header(tvb, offset, len, payload,
399             &next_payload, &payload_length, isakmp_tree);
400         if (ntree == NULL)
401           break;
402         if (payload_length >= 4) {      /* XXX = > 4? */
403           if (payload < NUM_LOAD_TYPES) {
404             if (next_payload == LOAD_TYPE_TRANSFORM)
405               dissect_transform(tvb, offset + 4, payload_length - 4, ntree, 0);
406                 /* XXX - protocol ID? */
407             else
408               (*strfuncs[payload].func)(tvb, offset + 4, payload_length - 4, ntree);
409           }
410           else {
411             proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4,
412                 "Payload");
413           }
414         }
415         else {
416             proto_tree_add_text(ntree, tvb, offset + 4, 0,
417                 "Payload (bogus, length is %u, must be at least 4)",
418                 payload_length);
419             payload_length = 4;
420         }
421         offset += payload_length;
422         len -= payload_length;
423       }
424     }
425   }
426 }
427
428 static proto_tree *
429 dissect_payload_header(tvbuff_t *tvb, int offset, int length, guint8 payload,
430     guint8 *next_payload_p, guint16 *payload_length_p, proto_tree *tree)
431 {
432   guint8                next_payload;
433   guint16               payload_length;
434   proto_item *          ti;
435   proto_tree *          ntree;
436
437   if (length < 4) {
438     proto_tree_add_text(tree, tvb, offset, length,
439           "Not enough room in payload for all transforms");
440     return NULL;
441   }
442   next_payload = tvb_get_guint8(tvb, offset);
443   payload_length = tvb_get_ntohs(tvb, offset + 2);
444
445   ti = proto_tree_add_text(tree, tvb, offset, payload_length,
446             "%s payload", loadtype2str(payload));
447   ntree = proto_item_add_subtree(ti, ett_isakmp_payload);
448
449   proto_tree_add_text(ntree, tvb, offset, 1,
450                       "Next payload: %s (%u)",
451                       payloadtype2str(next_payload), next_payload);
452   proto_tree_add_text(ntree, tvb, offset+2, 2, "Length: %u", payload_length);
453
454   *next_payload_p = next_payload;
455   *payload_length_p = payload_length;
456   return ntree;
457 }
458
459 static void
460 dissect_none(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
461 {
462 }
463
464 static void
465 dissect_sa(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
466 {
467   guint32               doi;
468   guint32               situation;
469   guint8                next_payload;
470   guint16               payload_length;
471   proto_tree *          ntree;
472
473   doi = tvb_get_ntohl(tvb, offset);
474   proto_tree_add_text(tree, tvb, offset, 4,
475                       "Domain of interpretation: %s (%u)",
476                       doitype2str(doi), doi);
477   offset += 4;
478   length -= 4;
479   
480   situation = tvb_get_ntohl(tvb, offset);
481   proto_tree_add_text(tree, tvb, offset, 4,
482                       "Situation: %s (%u)",
483                       situation2str(situation), situation);
484   offset += 4;
485   length -= 4;
486   
487   ntree = dissect_payload_header(tvb, offset, length, LOAD_TYPE_PROPOSAL,
488     &next_payload, &payload_length, tree);
489   if (ntree != NULL)
490     dissect_proposal(tvb, offset + 4, payload_length - 4, ntree);
491 }
492
493 static void
494 dissect_proposal(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
495 {
496   guint8                protocol_id;
497   guint8                spi_size;
498   guint8                num_transforms;
499   guint8                next_payload;
500   guint16               payload_length;
501   proto_tree *          ntree;
502
503   proto_tree_add_text(tree, tvb, offset, 1,
504                       "Proposal number: %u", tvb_get_guint8(tvb, offset));
505   offset += 1;
506   length -= 1;
507   
508   protocol_id = tvb_get_guint8(tvb, offset);
509   proto_tree_add_text(tree, tvb, offset, 1,
510                       "Protocol ID: %s (%u)",
511                       proto2str(protocol_id), protocol_id);
512   offset += 1;
513   length -= 1;
514   
515   spi_size = tvb_get_guint8(tvb, offset);
516   proto_tree_add_text(tree, tvb, offset, 1,
517                       "SPI size: %u", spi_size);
518   offset += 1;
519   length -= 1;
520
521   num_transforms = tvb_get_guint8(tvb, offset);
522   proto_tree_add_text(tree, tvb, offset, 1,
523                       "Number of transforms: %u", num_transforms);
524   offset += 1;
525   length -= 1;
526
527   if (spi_size) {
528     proto_tree_add_text(tree, tvb, offset, spi_size, "SPI");
529     offset += spi_size;
530     length -= spi_size;
531   }
532
533   while (num_transforms > 0) {
534     ntree = dissect_payload_header(tvb, offset, length, LOAD_TYPE_TRANSFORM,
535       &next_payload, &payload_length, tree);
536     if (ntree == NULL)
537       break;
538     if (length < payload_length) {
539       proto_tree_add_text(tree, tvb, offset + 4, length,
540           "Not enough room in payload for all transforms");
541       break;
542     }
543     if (payload_length >= 4)
544       dissect_transform(tvb, offset + 4, payload_length - 4, ntree, protocol_id);
545     else
546       proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4, "Payload");
547     offset += payload_length;
548     length -= payload_length;
549     num_transforms--;
550   }
551 }
552
553 static void
554 dissect_transform(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
555     guint8 protocol_id)
556 {
557   guint8                transform_id;
558
559   proto_tree_add_text(tree, tvb, offset, 1,
560                       "Transform number: %u", tvb_get_guint8(tvb, offset));
561   offset += 1;
562   length -= 1;
563
564   transform_id = tvb_get_guint8(tvb, offset);
565   switch (protocol_id) {
566   default:
567   case 1:       /* ISAKMP */
568     proto_tree_add_text(tree, tvb, offset, 1,
569                         "Transform ID: %s (%u)",
570                         trans2str(transform_id), transform_id);
571     break;
572   case 2:       /* AH */
573     proto_tree_add_text(tree, tvb, offset, 1,
574                         "Transform ID: %s (%u)",
575                         ah_trans2str(transform_id), transform_id);
576     break;
577   case 3:       /* ESP */
578     proto_tree_add_text(tree, tvb, offset, 1,
579                         "Transform ID: %s (%u)",
580                         esp_trans2str(transform_id), transform_id);
581     break;
582   }
583   offset += 3;
584   length -= 3;
585   
586   while (length>0) {
587     const char *str;
588     int ike_phase1 = 0;
589     guint16 aft     = tvb_get_ntohs(tvb, offset);
590     guint16 type    = aft & 0x7fff;
591     guint16 len;
592     guint32 val;
593     guint pack_len;
594
595     if (protocol_id == 1 && transform_id == 1) {
596       ike_phase1 = 1;
597       str = p1_atttype2str(type);
598     }
599     else {
600       str = atttype2str(type);
601     }
602
603     if (aft & 0x8000) {
604       val = tvb_get_ntohs(tvb, offset + 2);
605       proto_tree_add_text(tree, tvb, offset, 4,
606                           "%s (%u): %s (%u)",
607                           str, type,
608                           value2str(ike_phase1, type, val), val);
609       offset += 4;
610       length -= 4;
611     }
612     else {
613       len = tvb_get_ntohs(tvb, offset + 2);
614       pack_len = 4 + len;
615       if (!get_num(tvb, offset + 4, len, &val)) {
616         proto_tree_add_text(tree, tvb, offset, pack_len,
617                             "%s (%u): <too big (%u bytes)>",
618                             str, type, len);
619       } else {
620         proto_tree_add_text(tree, tvb, offset, pack_len,
621                             "%s (%u): %s (%u)",
622                             str, type,
623                             value2str(ike_phase1, type, val), val);
624       }
625       offset += pack_len;
626       length -= pack_len;
627     }
628   }
629 }
630
631 static void
632 dissect_key_exch(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
633 {
634   proto_tree_add_text(tree, tvb, offset, length, "Key Exchange Data");
635 }
636
637 static void
638 dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
639 {
640   guint8                id_type;
641   guint8                protocol_id;
642   guint16               port;
643
644   id_type = tvb_get_guint8(tvb, offset);
645   proto_tree_add_text(tree, tvb, offset, 1,
646                       "ID type: %s (%u)", id2str(id_type), id_type);
647   offset += 1;
648   length -= 1;
649
650   protocol_id = tvb_get_guint8(tvb, offset);
651   if (protocol_id == 0) {
652     proto_tree_add_text(tree, tvb, offset, 1,
653                         "Protocol ID: Unused");
654   } else {
655     proto_tree_add_text(tree, tvb, offset, 1,
656                         "Protocol ID: %s (%u)",
657                         ipprotostr(protocol_id), protocol_id);
658   }
659   offset += 1;
660   length -= 1;
661
662   port = tvb_get_ntohs(tvb, offset);
663   if (port == 0)
664     proto_tree_add_text(tree, tvb, offset, 2, "Port: Unused");
665   else
666     proto_tree_add_text(tree, tvb, offset, 2, "Port: %u", port);
667   offset += 2;
668   length -= 2;
669   
670   switch (id_type) {
671     case 1:
672     case 4:
673       proto_tree_add_text(tree, tvb, offset, length,
674                           "Identification data: %s",
675                           ip_to_str(tvb_get_ptr(tvb, offset, 4)));
676       break;
677     case 2:
678     case 3:
679       proto_tree_add_text(tree, tvb, offset, length,
680                           "Identification data: %.*s", length,
681                           tvb_get_ptr(tvb, offset, length));
682       break;
683     default:
684       proto_tree_add_text(tree, tvb, offset, length, "Identification Data");
685       break;
686   }
687 }
688
689 static void
690 dissect_cert(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
691 {
692   guint8                cert_enc;
693
694   cert_enc = tvb_get_guint8(tvb, offset);
695   proto_tree_add_text(tree, tvb, offset, 1,
696                       "Certificate encoding: %u - %s",
697                       cert_enc, certtype2str(cert_enc));
698   offset += 1;
699   length -= 1;
700
701   proto_tree_add_text(tree, tvb, offset, length, "Certificate Data");
702 }
703
704 static void
705 dissect_certreq(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
706 {
707   guint8                cert_type;
708
709   cert_type = tvb_get_guint8(tvb, offset);
710   proto_tree_add_text(tree, tvb, offset, 1,
711                       "Certificate type: %u - %s",
712                       cert_type, certtype2str(cert_type));
713   offset += 1;
714   length -= 1;
715
716   proto_tree_add_text(tree, tvb, offset, length, "Certificate Authority");
717 }
718
719 static void
720 dissect_hash(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
721 {
722   proto_tree_add_text(tree, tvb, offset, length, "Hash Data");
723 }
724
725 static void
726 dissect_sig(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
727 {
728   proto_tree_add_text(tree, tvb, offset, length, "Signature Data");
729 }
730
731 static void
732 dissect_nonce(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
733 {
734   proto_tree_add_text(tree, tvb, offset, length, "Nonce Data");
735 }
736
737 static void
738 dissect_notif(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
739 {
740   guint32               doi;
741   guint8                protocol_id;
742   guint8                spi_size;
743   guint16               msgtype;
744
745   doi = tvb_get_ntohl(tvb, offset);
746   proto_tree_add_text(tree, tvb, offset, 4,
747                       "Domain of Interpretation: %s (%u)",
748                       doitype2str(doi), doi);
749   offset += 4;
750   length -= 4;
751
752   protocol_id = tvb_get_guint8(tvb, offset);
753   proto_tree_add_text(tree, tvb, offset, 1,
754                       "Protocol ID: %s (%u)",
755                       proto2str(protocol_id), protocol_id);
756   offset += 1;
757   length -= 1;
758   
759   spi_size = tvb_get_guint8(tvb, offset);
760   proto_tree_add_text(tree, tvb, offset, 1,
761                       "SPI size: %u", spi_size);
762   offset += 1;
763   length -= 1;
764   
765   msgtype = tvb_get_ntohs(tvb, offset);
766   proto_tree_add_text(tree, tvb, offset, 2,
767                       "Message type: %s (%u)", msgtype2str(msgtype), msgtype);
768   offset += 2;
769   length -= 2;
770
771   if (spi_size) {
772     proto_tree_add_text(tree, tvb, offset, spi_size, "Security Parameter Index");
773     offset += spi_size;
774     length -= spi_size;
775   }
776
777   if (length > 0)
778     proto_tree_add_text(tree, tvb, offset, length, "Notification Data");
779 }
780
781 static void
782 dissect_delete(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
783 {
784   guint32               doi;
785   guint8                protocol_id;
786   guint8                spi_size;
787   guint16               num_spis;
788   guint16               i;
789   
790   doi = tvb_get_ntohl(tvb, offset);
791   proto_tree_add_text(tree, tvb, offset, 4,
792                       "Domain of Interpretation: %s (%u)",
793                       doitype2str(doi), doi);
794   offset += 4;
795   length -= 4;
796
797   protocol_id = tvb_get_guint8(tvb, offset);
798   proto_tree_add_text(tree, tvb, offset, 1,
799                       "Protocol ID: %s (%u)",
800                       proto2str(protocol_id), protocol_id);
801   offset += 1;
802   length -= 1;
803   
804   spi_size = tvb_get_guint8(tvb, offset);
805   proto_tree_add_text(tree, tvb, offset, 1,
806                       "SPI size: %u", spi_size);
807   offset += 1;
808   length -= 1;
809
810   num_spis = tvb_get_ntohs(tvb, offset);
811   proto_tree_add_text(tree, tvb, offset, 2,
812                       "Number of SPIs: %u", num_spis);
813   offset += 2;
814   length -= 2;
815   
816   for (i = 0; i < num_spis; ++i) {
817     if (length < spi_size) {
818       proto_tree_add_text(tree, tvb, offset, length,
819           "Not enough room in payload for all SPI's");
820       break;
821     }
822     proto_tree_add_text(tree, tvb, offset, spi_size,
823                         "SPI (%d)", i);
824     offset += spi_size;
825     length -= spi_size;
826   }
827 }
828
829 static void
830 dissect_vid(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
831 {
832   proto_tree_add_text(tree, tvb, offset, length, "Vendor ID");
833 }
834
835 static void
836 dissect_config(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
837 {
838   guint8                type;
839
840   type = tvb_get_guint8(tvb, offset);
841   proto_tree_add_text(tree, tvb, offset, 1,
842                       "Type %s (%u)",attrtype2str(type),type);
843   
844   offset += 2;
845   length -= 2;
846   
847   proto_tree_add_text(tree, tvb, offset, 2,
848                       "Identifier: %u", tvb_get_ntohs(tvb, offset));
849   offset += 2;
850   length -= 2;
851   
852   while(length>0) {
853     guint16 aft     = tvb_get_ntohs(tvb, offset);
854     guint16 type    = aft & 0x7fff;
855     guint16 len;
856     guint32 val;
857     guint pack_len;
858
859     if (aft & 0x8000) {
860       val = tvb_get_ntohs(tvb, offset + 2);
861       proto_tree_add_text(tree, tvb, offset, 4,
862                           "%s (%u)", cfgattrident2str(type), val);
863       offset += 4;
864       length -= 4;
865     }
866     else {
867       len = tvb_get_ntohs(tvb, offset + 2);
868       pack_len = 4 + len;
869       if (!get_num(tvb, offset + 4, len, &val)) {
870         proto_tree_add_text(tree, tvb, offset, pack_len,
871                             "%s: <too big (%u bytes)>",
872                             cfgattrident2str(type), len);
873       } else {
874         proto_tree_add_text(tree, tvb, offset, 4,
875                             "%s (%ue)", cfgattrident2str(type),
876                             val);
877       }
878       offset += pack_len;
879       length -= pack_len;
880     }
881   }
882 }
883
884 static const char *
885 payloadtype2str(guint8 type) {
886
887   if (type < NUM_LOAD_TYPES) return strfuncs[type].str;
888   if (type < 128)            return "RESERVED";
889   if (type < 256)            return "Private USE";
890
891   return "Huh? You should never see this! Shame on you!";
892 }
893
894 static const char *
895 exchtype2str(guint8 type) {
896
897 #define NUM_EXCHSTRS    7
898   static const char * exchstrs[NUM_EXCHSTRS] = {
899     "NONE",
900     "Base",
901     "Identity Protection (Main Mode)",
902     "Authentication Only",
903     "Aggressive",
904     "Informational",
905     "Transaction (Config Mode)"
906   };
907   
908   if (type < NUM_EXCHSTRS) return exchstrs[type];
909   if (type < 32)           return "ISAKMP Future Use";
910   switch (type) {
911   case 32:
912     return "Quick Mode";
913   case 33:
914     return "New Group Mode";
915   }
916   if (type < 240)          return "DOI Specific Use";
917   if (type < 256)          return "Private Use";
918   
919   return "Huh? You should never see this! Shame on you!";
920 }
921
922 static const char *
923 doitype2str(guint32 type) {
924   if (type == 1) return "IPSEC";
925   return "Unknown DOI Type";
926 }
927
928 static const char *
929 msgtype2str(guint16 type) {
930
931 #define NUM_PREDEFINED  31
932   static const char *msgs[NUM_PREDEFINED] = {
933     "<UNKNOWN>",
934     "INVALID-PAYLOAD-TYPE",
935     "DOI-NOT-SUPPORTED",
936     "SITUATION-NOT-SUPPORTED",
937     "INVALID-COOKIE",
938     "INVALID-MAJOR-VERSION",
939     "INVALID-MINOR-VERSION",
940     "INVALID-EXCHANGE-TYPE",
941     "INVALID-FLAGS",
942     "INVALID-MESSAGE-ID",
943     "INVALID-PROTOCOL-ID",
944     "INVALID-SPI",
945     "INVALID-TRANSFORM-ID",
946     "ATTRIBUTES-NOT-SUPPORTED",
947     "NO-PROPOSAL-CHOSEN",
948     "BAD-PROPOSAL-SYNTAX",
949     "PAYLOAD-MALFORMED",
950     "INVALID-KEY-INFORMATION",
951     "INVALID-ID-INFORMATION",
952     "INVALID-CERT-ENCODING",
953     "INVALID-CERTIFICATE",
954     "CERT-TYPE-UNSUPPORTED",
955     "INVALID-CERT-AUTHORITY",
956     "INVALID-HASH-INFORMATION",
957     "AUTHENTICATION-FAILED",
958     "INVALID-SIGNATURE",
959     "ADDRESS-NOTIFICATION",
960     "NOTIFY-SA-LIFETIME",
961     "CERTIFICATE-UNAVAILABLE",
962     "UNSUPPORTED-EXCHANGE-TYPE",
963     "UNEQUAL-PAYLOAD-LENGTHS"
964   };
965
966   if (type < NUM_PREDEFINED) return msgs[type];
967   if (type < 8192)           return "RESERVED (Future Use)";
968   if (type < 16384)          return "Private Use";
969   if (type < 16385)          return "CONNECTED";
970   if (type < 24576)          return "RESERVED (Future Use) - status";
971   if (type < 24577)          return "RESPONDER-LIFETIME";
972   if (type < 24578)          return "REPLAY-STATUS";
973   if (type < 24579)          return "INITIAL-CONTACT";
974   if (type < 32768)          return "DOI-specific codes";
975   if (type < 40960)          return "Private Use - status";
976   if (type < 65535)          return "RESERVED (Future Use) - status (2)";
977
978   return "Huh? You should never see this! Shame on you!";
979 }
980
981 static const char *
982 situation2str(guint32 type) {
983
984 #define SIT_MSG_NUM     1024
985 #define SIT_IDENTITY    0x01
986 #define SIT_SECRECY     0x02
987 #define SIT_INTEGRITY   0x04
988
989   static char   msg[SIT_MSG_NUM];
990   int           n = 0;
991   char *        sep = "";
992   
993   if (type & SIT_IDENTITY) {
994     n += snprintf(msg, SIT_MSG_NUM-n, "%sIDENTITY", sep);
995     sep = " & ";
996   }
997   if (type & SIT_SECRECY) {
998     n += snprintf(msg, SIT_MSG_NUM-n, "%sSECRECY", sep);
999     sep = " & ";
1000   }
1001   if (type & SIT_INTEGRITY) {
1002     n += snprintf(msg, SIT_MSG_NUM-n, "%sINTEGRITY", sep);
1003     sep = " & ";
1004   }
1005
1006   return msg;
1007 }
1008
1009 static const char *
1010 value2str(int ike_p1, guint16 att_type, guint16 value) {
1011   
1012   if (value == 0) return "RESERVED";
1013   
1014   if (!ike_p1) {
1015   switch (att_type) {
1016     case 1:
1017       switch (value) {
1018         case 1:  return "Seconds";
1019         case 2:  return "Kilobytes";
1020         default: return "UNKNOWN-SA-VALUE";
1021       }
1022     case 2:
1023       return "Duration-Value";
1024     case 3:
1025       return "Group-Value";
1026     case 4:
1027       switch (value) {
1028         case 1:  return "Tunnel";
1029         case 2:  return "Transport";
1030         case 61440: return "Check Point IPSec UDP Encapsulation";
1031         case 61443: return "UDP-Encapsulated-Tunnel (draft)";
1032         case 61444: return "UDP-Encapsulated-Transport (draft)";
1033         default: return "UNKNOWN-ENCAPSULATION-VALUE";
1034       }
1035     case 5:
1036       switch (value) {
1037         case 1:  return "HMAC-MD5";
1038         case 2:  return "HMAC-SHA";
1039         case 3:  return "DES-MAC";
1040         case 4:  return "KPDK";
1041         case 5:  return "HMAC-SHA2-256";
1042         case 6:  return "HMAC-SHA2-384";
1043         case 7:  return "HMAC-SHA2-512";
1044         default: return "UNKNOWN-AUTHENTICATION-VALUE";
1045       }
1046     case 6:
1047       return "Key-Length";
1048     case 7:
1049       return "Key-Rounds";
1050     case 8:
1051       return "log2-size";
1052     default: return "UNKNOWN-ATTRIBUTE-TYPE";
1053   }
1054   }
1055   else {
1056     switch (att_type) {
1057       case 1:
1058         switch (value) {
1059           case 1:  return "DES-CBC";
1060           case 2:  return "IDEA-CBC";
1061           case 3:  return "BLOWFISH-CBC";
1062           case 4:  return "RC5-R16-B64-CBC";
1063           case 5:  return "3DES-CBC";
1064           case 6:  return "CAST-CBC";
1065           case 7:  return "AES-CBC";
1066           default: return "UNKNOWN-ENCRYPTION-ALG";
1067         }
1068       case 2:
1069         switch (value) {
1070           case 1:  return "MD5";
1071           case 2:  return "SHA";
1072           case 3:  return "TIGER";
1073           case 4:  return "SHA2-256";
1074           case 5:  return "SHA2-384";
1075           case 6:  return "SHA2-512";
1076           default: return "UNKNOWN-HASH-ALG";
1077         }
1078       case 3:
1079         switch (value) {
1080           case 1:  return "PSK";
1081           case 2:  return "DSS-SIG";
1082           case 3:  return "RSA-SIG";
1083           case 4:  return "RSA-ENC";
1084           case 5:  return "RSA-Revised-ENC";
1085           case 64221: return "HybridInitRSA";
1086           case 64222: return "HybridRespRSA";
1087           case 64223: return "HybridInitDSS";
1088           case 64224: return "HybridRespDSS";
1089           case 65001: return "XAUTHInitPreShared";
1090           case 65002: return "XAUTHRespPreShared";
1091           case 65003: return "XAUTHInitDSS";
1092           case 65004: return "XAUTHRespDSS";
1093           case 65005: return "XAUTHInitRSA";
1094           case 65006: return "XAUTHRespRSA";
1095           case 65007: return "XAUTHInitRSAEncryption";
1096           case 65008: return "XAUTHRespRSAEncryption";
1097           case 65009: return "XAUTHInitRSARevisedEncryption";
1098           case 65010: return "XAUTHRespRSARevisedEncryption";
1099           default: return "UNKNOWN-AUTH-METHOD";
1100         }
1101       case 4:
1102       case 6:
1103       case 7:
1104       case 8:
1105       case 9:
1106       case 10:
1107       case 16:
1108         return "Group-Value";
1109       case 5:
1110         switch (value) {
1111           case 1:  return "MODP";
1112           case 2:  return "ECP";
1113           case 3:  return "EC2N";
1114           default: return "UNKNOWN-GROUPT-TYPE";
1115         }
1116       case 11:
1117         switch (value) {
1118           case 1:  return "Seconds";
1119           case 2:  return "Kilobytes";
1120           default: return "UNKNOWN-SA-VALUE";
1121         }
1122       case 12:
1123         return "Duration-Value";
1124       case 13:
1125         return "PRF-Value";
1126       case 14:
1127         return "Key-Length";
1128       case 15:
1129         return "Field-Size";
1130       default: return "UNKNOWN-ATTRIBUTE-TYPE";
1131     }
1132   }
1133 }
1134
1135 static const char * 
1136 attrtype2str(guint8 type) {
1137   switch (type) {
1138   case 0: return "Reserved";
1139   case 1: return "ISAKMP_CFG_REQUEST";
1140   case 2: return "ISAKMP_CFG_REPLY";
1141   case 3: return "ISAKMP_CFG_SET";
1142   case 4: return "ISAKMP_CFG_ACK";
1143   }
1144   if(type < 127)
1145     return "Future use";
1146   return "Private use";
1147 }
1148
1149 static const char * 
1150 cfgattrident2str(guint16 ident) {
1151 #define NUM_ATTR_DEFINED        12
1152   static const char *msgs[NUM_PREDEFINED] = {
1153     "RESERVED",
1154     "INTERNAL_IP4_ADDRESS",
1155     "INTERNAL_IP4_NETMASK",
1156     "INTERNAL_IP4_DNS",
1157     "INTERNAL_IP4_NBNS",
1158     "INTERNAL_ADDRESS_EXPIREY",
1159     "INTERNAL_IP4_DHCP",
1160     "APPLICATION_VERSION"
1161     "INTERNAL_IP6_ADDRESS",
1162     "INTERNAL_IP6_NETMASK",
1163     "INTERNAL_IP6_DNS",
1164     "INTERNAL_IP6_NBNS",
1165     "INTERNAL_IP6_DHCP",
1166   }; 
1167   if(ident < NUM_ATTR_DEFINED)
1168     return msgs[ident];
1169   if(ident < 16383)
1170     return "Future use";
1171   switch(ident) {
1172   case 16520: return "XAUTH_TYPE";
1173   case 16521: return "XAUTH_USER_NAME";
1174   case 16522: return "XAUTH_USER_PASSWORD";
1175   case 16523: return "XAUTH_PASSCODE";
1176   case 16524: return "XAUTH_MESSAGE";
1177   case 16525: return "XAUTH_CHALLANGE";
1178   case 16526: return "XAUTH_DOMAIN";
1179   case 16527: return "XAUTH_STATUS";
1180   default: return "Private use";
1181   }
1182 }
1183
1184 static const char *
1185 certtype2str(guint8 type) {
1186 #define NUM_CERTTYPE 11
1187   static const char *msgs[NUM_CERTTYPE] = {
1188     "NONE",
1189     "PKCS #7 wrapped X.509 certificate",
1190     "PGP Certificate",
1191     "DNS Signed Key",
1192     "X.509 Certificate - Signature",
1193     "X.509 Certificate - Key Exchange",
1194     "Kerberos Tokens",
1195     "Certificate Revocation List (CRL)",
1196     "Authority Revocation List (ARL)",
1197     "SPKI Certificate",
1198     "X.509 Certificate - Attribute",
1199   };
1200   if(type > NUM_CERTTYPE)
1201     return "RESERVED";
1202   return msgs[type];
1203 }
1204
1205 static gboolean
1206 get_num(tvbuff_t *tvb, int offset, guint16 len, guint32 *num_p) {
1207
1208   switch (len) {
1209   case 1:
1210     *num_p = tvb_get_guint8(tvb, offset);
1211     break;
1212   case 2:
1213     *num_p = tvb_get_ntohs(tvb, offset);
1214     break;
1215   case 3:
1216     *num_p = tvb_get_ntoh24(tvb, offset);
1217     break;
1218   case 4:
1219     *num_p = tvb_get_ntohl(tvb, offset);
1220     break;
1221   default:
1222     return FALSE;
1223   }
1224
1225   return TRUE;
1226 }
1227
1228 void
1229 proto_register_isakmp(void)
1230 {
1231 /*  static hf_register_info hf[] = {
1232     { &variable,
1233     { "Name",           "isakmp.abbreviation", TYPE, VALS_POINTER }},
1234   };*/
1235   static gint *ett[] = {
1236     &ett_isakmp,
1237     &ett_isakmp_flags,
1238     &ett_isakmp_payload,
1239   };
1240
1241   proto_isakmp = proto_register_protocol("Internet Security Association and Key Management Protocol",
1242                                                "ISAKMP", "isakmp");
1243 /*  proto_register_field_array(proto_isakmp, hf, array_length(hf));*/
1244   proto_register_subtree_array(ett, array_length(ett));
1245 }
1246
1247 void
1248 proto_reg_handoff_isakmp(void)
1249 {
1250   /*
1251    * Get handle for the AH & ESP dissectors.
1252    */
1253   esp_handle = find_dissector("esp");
1254   ah_handle = find_dissector("ah");
1255
1256   dissector_add("udp.port", UDP_PORT_ISAKMP, dissect_isakmp, proto_isakmp);
1257   dissector_add("tcp.port", TCP_PORT_ISAKMP, dissect_isakmp, proto_isakmp);
1258 }