]> The Tcpdump Group git mirrors - tcpdump/blob - print-macsec.c
Merge branch 'master' into macsec
[tcpdump] / print-macsec.c
1 /* Copyright (c) 2017, Sabrina Dubroca <sd@queasysnail.net>
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 * 3. The names of the authors may not be used to endorse or promote
14 * products derived from this software without specific prior
15 * written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 /* \summary: MACsec printer */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <netdissect-stdinc.h>
29
30 #include <string.h>
31
32 #include "netdissect.h"
33 #include "addrtoname.h"
34 #include "ether.h"
35 #include "ethertype.h"
36 #include "extract.h"
37
38 static const char tstr[] = "[|MACsec]";
39
40 #define MACSEC_DEFAULT_ICV_LEN 16
41
42 /* Header format (SecTAG), following an Ethernet header
43 * IEEE 802.1AE-2006 9.3
44 *
45 * +---------------------------------+----------------+----------------+
46 * | (MACsec ethertype) | TCI_AN | SL |
47 * +---------------------------------+----------------+----------------+
48 * | Packet Number |
49 * +-------------------------------------------------------------------+
50 * | Secure Channel Identifier |
51 * | (optional) |
52 * +-------------------------------------------------------------------+
53 *
54 * MACsec ethertype = 0x88e5
55 * TCI: Tag Control Information, set of flags
56 * AN: association number, 2 bits
57 * SL (short length): 6-bit length of the protected payload, if < 48
58 * Packet Number: 32-bits packet identifier
59 * Secure Channel Identifier: 64-bit unique identifier, usually
60 * composed of a MAC address + 16-bit port number
61 */
62 struct macsec_sectag {
63 u_char tci_an;
64 #if __BYTE_ORDER == __LITTLE_ENDIAN
65 u_char short_length:6,
66 unused:2;
67 #else /* __BYTE_ORDER == __BIG_ENDIAN */
68 u_char unused:2,
69 short_length:6;
70 #endif
71 uint32_t packet_number;
72 u_char secure_channel_id[8]; /* optional */
73 } __attribute__((packed));
74
75 /* IEEE 802.1AE-2006 9.5 */
76 #define MACSEC_TCI_VERSION 0x80
77 #define MACSEC_TCI_ES 0x40 /* end station */
78 #define MACSEC_TCI_SC 0x20 /* SCI present */
79 #define MACSEC_TCI_SCB 0x10 /* epon */
80 #define MACSEC_TCI_E 0x08 /* encryption */
81 #define MACSEC_TCI_C 0x04 /* changed text */
82 #define MACSEC_AN_MASK 0x03 /* association number */
83 #define MACSEC_TCI_FLAGS (MACSEC_TCI_ES | MACSEC_TCI_SC | MACSEC_TCI_SCB | MACSEC_TCI_E | MACSEC_TCI_C)
84 #define MACSEC_TCI_CONFID (MACSEC_TCI_E | MACSEC_TCI_C)
85
86 #define MACSEC_SECTAG_LEN_NOSCI 6
87 #define MACSEC_SECTAG_LEN_SCI 14
88 static int
89 ieee8021ae_sectag_len(const struct macsec_sectag *sectag)
90 {
91 return (sectag->tci_an & MACSEC_TCI_SC) ?
92 MACSEC_SECTAG_LEN_SCI :
93 MACSEC_SECTAG_LEN_NOSCI;
94 }
95
96 static int macsec_check_length(const struct macsec_sectag *sectag, u_int length, u_int caplen)
97 {
98 u_int len;
99
100 /* we need the full MACsec header in the capture */
101 if (caplen < (MACSEC_SECTAG_LEN_NOSCI + 2))
102 return 0;
103
104 len = ieee8021ae_sectag_len(sectag);
105 if (caplen < (len + 2))
106 return 0;
107
108 if (sectag->short_length != 0) {
109 /* original packet must have exact length */
110 u_int exact = ETHER_HDRLEN + len + 2 + sectag->short_length;
111 return exact == length;
112 } else {
113 /* original packet must not be short */
114 u_int minlen = ETHER_HDRLEN + len + 2 + 48;
115 return length >= minlen;
116 }
117
118 return 1;
119 }
120
121 #define SCI_FMT "%016" PRIx64
122
123 static const struct tok macsec_flag_values[] = {
124 { MACSEC_TCI_E, "E" },
125 { MACSEC_TCI_C, "C" },
126 { MACSEC_TCI_ES, "S" },
127 { MACSEC_TCI_SCB, "B" },
128 { MACSEC_TCI_SC, "I" },
129 { 0, NULL }
130 };
131
132 /* returns < 0 iff the packet can be decoded completely */
133 int macsec_print(netdissect_options *ndo, const u_char **bp,
134 u_int *lengthp, u_int *caplenp, u_int *hdrlenp,
135 u_short *length_type)
136 {
137 const u_char *p = *bp;
138 u_int length = *lengthp;
139 u_int caplen = *caplenp;
140 u_int hdrlen = *hdrlenp;
141 const struct macsec_sectag *sectag = (const struct macsec_sectag *)p;
142 u_int len;
143
144 if (!macsec_check_length(sectag, length, caplen)) {
145 ND_PRINT((ndo, tstr));
146 return hdrlen + caplen;
147 }
148
149 if (sectag->unused || sectag->tci_an & MACSEC_TCI_VERSION) {
150 ND_PRINT((ndo, "%s", istr));
151 return hdrlen + caplen;
152 }
153
154 if (ndo->ndo_eflag) {
155 char buf[128];
156 int n = snprintf(buf, sizeof(buf), "an %d, pn %d, flags %s",
157 sectag->tci_an & MACSEC_AN_MASK,
158 EXTRACT_32BITS(&sectag->packet_number),
159 bittok2str_nosep(macsec_flag_values, "none",
160 sectag->tci_an & MACSEC_TCI_FLAGS));
161 if (n < 0)
162 return hdrlen + caplen;
163
164
165 if (sectag->short_length) {
166 int r = snprintf(buf + n, sizeof(buf) - n, ", sl %d",
167 sectag->short_length);
168 if (r < 0)
169 return hdrlen + caplen;
170 n += r;
171 }
172
173 if (sectag->tci_an & MACSEC_TCI_SC) {
174 uint64_t sci;
175 int r;
176 sci = EXTRACT_64BITS(sectag->secure_channel_id);
177 r = snprintf(buf + n, sizeof(buf) - n, ", sci " SCI_FMT, sci);
178 if (r < 0)
179 return hdrlen + caplen;
180 n += r;
181 }
182
183 ND_PRINT((ndo, "%s, ", buf));
184 }
185
186 len = ieee8021ae_sectag_len(sectag);
187 *length_type = EXTRACT_16BITS(*bp + len);
188 if (ndo->ndo_eflag && *length_type > ETHERMTU && !(sectag->tci_an & MACSEC_TCI_E))
189 ND_PRINT((ndo, "ethertype %s, ", tok2str(ethertype_values,"0x%04x", *length_type)));
190
191 if ((sectag->tci_an & MACSEC_TCI_CONFID)) {
192 *bp += len;
193 *hdrlenp += len;
194
195 *lengthp -= len;
196 *caplenp -= len;
197 return 0;
198 } else {
199 len += 2;
200 *bp += len;
201 *hdrlenp += len;
202
203 len += MACSEC_DEFAULT_ICV_LEN;
204 *lengthp -= len;
205 *caplenp -= len;
206 return -1;
207 }
208 }