blob: 9efe64b36b6ccb30b68c58aa16eac2d5cbd815d9 [file] [log] [blame]
Anjali K K4a694f62018-07-12 19:09:19 +05301/*
2 * Copyright 2017-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onlab.packet;
18
19import java.nio.ByteBuffer;
20import java.util.Arrays;
21
22/**
23 * Class representing EAPOL MKPDU Basic Parameter Set.
24 * IEEE 802.1X Clause 11; Figure 11-8
25 */
26public class EAPOLMkpduBasicParameterSet extends BasePacket implements EAPOLMkpduParameterSet {
27
28 // Parameter Set fields.
29 private byte mkaVersion;
30 private byte keyServerPriority;
31 private boolean keyServer;
32 private boolean macSecDesired;
33 private byte capability;
34 private short bodyLength;
35 private SCI sci;
36 private byte[] mi;
37 private int mn;
38 private byte[] algAgility;
39 private byte[] ckn;
40 private byte[] padding;
41
42 // Various fixed parameter widths. IEEE 802.1X Table 11-6.
43 public static final int FIELD_ALGAG_LENGTH = 4;
44 public static final int TOTAL_BPS_BODY_LENGTH = 32;
45
46
47 // Basic Parameter Set field masks.
48 public static final byte KEYSERVER_MASK = (byte) 0x80;
49 public static final byte KEYSERVER_OFFSET = (byte) 0x07;
50 public static final byte MACSEC_DESIRED_MASK = (byte) 0x70;
51 public static final byte MACSEC_DESIRED_OFFSET = (byte) 0x06;
52 public static final byte MACSEC_CAPABILITY_MASK = (byte) 0x30;
53 public static final byte MACSEC_CAPABILITY_OFFSET = (byte) 0x04;
54
55 /**
56 * MKA Secure Channel Identifier.
57 */
58 public static class SCI {
59 private byte[] address;
60 private short port;
61
62 public static final int SYSTEM_IDENTIFIER_LENGTH = 6;
63 public static final int PORT_OFFSET = 6;
64
65
66 /**
67 * Validate SCI has <MAC (6 bytes)><Port (2 bytes)> length.
68 *
69 * @param sci ,byte[]
70 * @return true ,boolean
71 */
72 private boolean validateSCI(byte[] sci) {
73 if (sci != null && sci.length < EAPOLMkpduBasicParameterSet.FIELD_SCI_LENGTH) {
74 throw new IllegalArgumentException(
75 "Invalid SCI argument. Enough bytes are not provided."
76 );
77 }
78 return true;
79 }
80
81 /**
82 * Validate System Identifier.
83 *
84 * @param address , byte[]
85 * @return true , boolean
86 */
87 private boolean validateAddress(byte[] address) {
88 if (address != null && address.length < SCI.SYSTEM_IDENTIFIER_LENGTH) {
89 throw new IllegalArgumentException(
90 "Invalid System Identifier argument. Expects 6 bytes eg. MAC address.");
91 }
92 return true;
93 }
94
95 /**
96 * To set SCI from MAC address and port stream.
97 *
98 * @param sci , type byte[]
99 */
100
101 public SCI(byte[] sci) {
102 validateSCI(sci);
103 address = Arrays.copyOfRange(sci, 0, SYSTEM_IDENTIFIER_LENGTH);
104 port = (short) ((((short) (sci[PORT_OFFSET] & 0xFF)) << 8)
105 | ((short) (sci[PORT_OFFSET + 1] & 0xFF)));
106 }
107
108 /**
109 * To set SCI from MAC address and port number.
110 *
111 * @param address ,type byte[]
112 * @param port ,type short
113 * @throws IllegalArgumentException Exceptions
114 */
115 public SCI(byte[] address, short port) throws IllegalArgumentException {
116 validateAddress(address);
117 this.address = address;
118 this.port = port;
119 }
120
121 /**
122 * To set address.
123 *
124 * @param address , type byte[]
125 * @throws IllegalArgumentException if address is not set
126 */
127 public void setAdddress(byte[] address) throws IllegalArgumentException {
128 validateAddress(address);
129 this.address = address;
130 }
131
132 /**
133 * To return address.
134 *
135 * @return address , type byte[]
136 */
137 public byte[] address() {
138 return address;
139 }
140
141 /**
142 * TO set Port.
143 *
144 * @param port , type short
145 */
146 public void setPort(short port) {
147 this.port = port;
148 }
149
150 /**
151 * To return Port.
152 *
153 * @return port , type short
154 */
155 public short port() {
156 return port;
157 }
158
159 /**
160 * Convert to byte array.
161 *
162 * @return bb.array() ,type byte[]
163 */
164 public byte[] array() {
165 byte[] data = new byte[address.length + 2];
166 ByteBuffer bb = ByteBuffer.wrap(data);
167 bb.put(address);
168 bb.putShort(port);
169 return bb.array();
170 }
171 }
172
173 // Basic Parameter Set fixed header portion size.
174 public static final short BPS_FIXED_PART_SIZE_UPTO_LENGTH_FIELD = 4;
175 public static final short BPS_FIXED_PART_TOTAL_SIZE = 32;
176
177 /**
178 * To set MKA Version.
179 *
180 * @param version , type byte
181 */
182 public void setMkaVersion(byte version) {
183 this.mkaVersion = version;
184 }
185
186 /**
187 * To get MKA Version.
188 *
189 * @return mkaVersion , type byte
190 */
191 public byte getMkaVersion() {
192 return mkaVersion;
193 }
194
195 /**
196 * To set Key Server Priority.
197 *
198 * @param priority , type byte
199 */
200
201 public void setKeyServerPriority(byte priority) {
202 this.keyServerPriority = priority;
203 }
204
205 /**
206 * To get Key Server Priority.
207 *
208 * @return keyServerPriority, type byte
209 */
210 public byte getKeyServerPriority() {
211 return keyServerPriority;
212 }
213
214 /**
215 * To set Key Server.
216 *
217 * @param isKeyServer , type boolean
218 */
219 public void setKeyServer(boolean isKeyServer) {
220 this.keyServer = isKeyServer;
221 }
222
223 /**
224 * To get Key Server.
225 *
226 * @return keyServer, type boolean
227 */
228 public boolean getKeyServer() {
229 return keyServer;
230 }
231
232 /**
233 * To set MACSec Desired.
234 *
235 * @param desired , type boolean
236 */
237 public void setMacSecDesired(boolean desired) {
238 this.macSecDesired = desired;
239 }
240
241 /**
242 * To get MACSec Desired.
243 *
244 * @return macSecDesired , type boolean
245 */
246 public boolean getMacSecDesired() {
247 return macSecDesired;
248 }
249
250 /**
251 * To set MACSec Capacity.
252 *
253 * @param capability ,type byte
254 */
255 public void setMacSecCapability(byte capability) {
256 this.capability = capability;
257 }
258
259 /**
260 * To get MACSec Capacity.
261 *
262 * @return capability, type byte
263 */
264 public byte getMacSecCapacity() {
265 return capability;
266 }
267
268 /**
269 * To set body length.
270 *
271 * @param length , type short
272 */
273 public void setBodyLength(short length) {
274 this.bodyLength = length;
275 }
276
277 public short getBodyLength() {
278 return bodyLength;
279 }
280
281 /**
282 * To set SCI.
283 *
284 * @param sci , byte[]
285 */
286 public void setSci(byte[] sci) {
287 this.sci = new SCI(sci);
288 }
289
290 /**
291 * To set SCI.
292 *
293 * @param sci , SCI
294 */
295 public void setSci(SCI sci) {
296 // TODO: Ensure sci valid.
297 this.sci = sci;
298 }
299
300 /**
301 * To get SCI.
302 *
303 * @return sci, type SCI
304 */
305 public SCI getSci() {
306 return sci;
307 }
308
309 /**
310 * To set Member Identifier.
311 *
312 * @param mi , type byte[]
313 * @throws IllegalArgumentException if mi is not set.
314 */
315
316 public void setActorMI(byte[] mi) throws IllegalArgumentException {
317 if (mi != null && mi.length < EAPOLMkpduParameterSet.FIELD_MI_LENGTH) {
318 throw new IllegalArgumentException("Actor Message Identifier doesn't have enough length.");
319 }
320 this.mi = mi;
321 }
322
323 /**
324 * To get Member Identifier.
325 *
326 * @return mi, type byte[]
327 */
328 public byte[] getActorMI() {
329 return mi;
330 }
331
332 /**
333 * To set Member Identifier.
334 *
335 * @param mn , type byte[]
336 * @throws IllegalArgumentException if mn is not set.
337 */
338 public void setActorMN(byte[] mn) throws IllegalArgumentException {
339 if (mn != null && mn.length < EAPOLMkpduParameterSet.FIELD_MN_LENGTH) {
340 throw new IllegalArgumentException("Actor Message Number doesn't have enough length.");
341 }
342 final ByteBuffer bf = ByteBuffer.wrap(mn);
343 this.mn = bf.getInt();
344 }
345
346 /**
347 * To set Member Identifier.
348 *
349 * @param mn , type int
350 */
351 public void setActorMN(int mn) {
352 this.mn = mn;
353 }
354
355 /**
356 * To get Member Identifier.
357 *
358 * @return mn, type int
359 */
360 public int getActorMN() {
361 return mn;
362 }
363
364 /**
365 * To set Algorithm Agility.
366 *
367 * @param algAgility , type byte[]
368 * @throws IllegalArgumentException if algAgility is not set or in incorrect format
369 */
370 public void setAlgAgility(byte[] algAgility) throws IllegalArgumentException {
371 if (algAgility != null && algAgility.length < EAPOLMkpduBasicParameterSet.FIELD_ALGAG_LENGTH) {
372 throw new IllegalArgumentException("Algorithm Agility doesn't have enough length.");
373 }
374 this.algAgility = algAgility;
375 }
376
377 /**
378 * To get Algorithm Agility.
379 *
380 * @return algAgility, type byte[]
381 */
382 public byte[] getAlgAgility() {
383 return algAgility;
384 }
385
386 /**
387 * To set CAK name.
388 *
389 * @param ckn , type byte[]
390 */
391 public void setCKN(byte[] ckn) {
392 int cakNameLength = bodyLength - EAPOLMkpduBasicParameterSet.TOTAL_BPS_BODY_LENGTH;
393 if (ckn != null && ckn.length < cakNameLength) {
394 throw new IllegalArgumentException("CAK name doesn't have enough length.");
395 }
396 this.ckn = ckn;
397 }
398
399 /**
400 * To get CAK name.
401 *
402 * @return ckn , type byte[]
403 */
404 public byte[] getCKN() {
405 return ckn;
406 }
407
408 /**
409 * To set padding.
410 *
411 * @param padding , type byte[]
412 */
413 public void setPadding(byte[] padding) {
414 this.padding = padding;
415 }
416
417 /**
418 * Deserializer function for Basic Parameter Set.
419 *
420 * @return deserializer function
421 */
422 public static Deserializer<EAPOLMkpduBasicParameterSet> deserializer() {
423 return (data, offset, length) -> {
424
425 // Ensure buffer has enough details.
426 if (length < TOTAL_BPS_BODY_LENGTH) {
427 return null;
428 }
429
430 // Various tools for deserialization.
431 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
432 EAPOLMkpduBasicParameterSet basicParameterSet = new EAPOLMkpduBasicParameterSet();
433
434 // Deserialize Basic Parameter Set fields.
435 basicParameterSet.setMkaVersion(bb.get());
436 basicParameterSet.setKeyServerPriority(bb.get());
437
438 byte[] mbField = new byte[1];
439 mbField[0] = bb.get();
440 basicParameterSet.setKeyServer(((mbField[0] & EAPOLMkpduBasicParameterSet.KEYSERVER_MASK) > 0) ?
441 true : false);
442 basicParameterSet.setMacSecDesired(((mbField[0]
443 & EAPOLMkpduBasicParameterSet.MACSEC_DESIRED_MASK) > 0) ?
444 true : false);
445 basicParameterSet.setMacSecCapability((byte) ((mbField[0]
446 & EAPOLMkpduBasicParameterSet.MACSEC_CAPABILITY_MASK)
447 >> EAPOLMkpduBasicParameterSet.MACSEC_CAPABILITY_OFFSET));
448
449 short bodyLength = (short) (((short) (mbField[0] & EAPOLMkpduParameterSet.BODY_LENGTH_MSB_MASK))
450 << EAPOLMkpduBasicParameterSet.BODY_LENGTH_MSB_SHIFT);
451 bodyLength |= (short) (bb.get());
452 basicParameterSet.setBodyLength(bodyLength);
453
454 mbField = new byte[EAPOLMkpduParameterSet.FIELD_SCI_LENGTH];
455 bb.get(mbField, 0, EAPOLMkpduParameterSet.FIELD_SCI_LENGTH);
456 basicParameterSet.setSci(mbField);
457
458 mbField = new byte[EAPOLMkpduParameterSet.FIELD_MI_LENGTH];
459 bb.get(mbField, 0, EAPOLMkpduParameterSet.FIELD_MI_LENGTH);
460 basicParameterSet.setActorMI(mbField);
461
462 mbField = new byte[EAPOLMkpduParameterSet.FIELD_MN_LENGTH];
463 bb.get(mbField, 0, EAPOLMkpduParameterSet.FIELD_MN_LENGTH);
464 basicParameterSet.setActorMN(mbField);
465
466 mbField = new byte[EAPOLMkpduBasicParameterSet.FIELD_ALGAG_LENGTH];
467 bb.get(mbField, 0, EAPOLMkpduBasicParameterSet.FIELD_ALGAG_LENGTH);
468 basicParameterSet.setAlgAgility(mbField);
469
470 int cakNameLength = basicParameterSet.getBodyLength() + EAPOLMkpduParameterSet.BODY_LENGTH_OCTET_OFFSET -
471 EAPOLMkpduBasicParameterSet.TOTAL_BPS_BODY_LENGTH;
472 mbField = new byte[cakNameLength];
473 bb.get(mbField, 0, cakNameLength);
474 basicParameterSet.setCKN(mbField);
475
476 int padLength = basicParameterSet.getBodyLength() + EAPOLMkpduParameterSet.BODY_LENGTH_OCTET_OFFSET -
477 (EAPOLMkpduBasicParameterSet.TOTAL_BPS_BODY_LENGTH + cakNameLength);
478 if (padLength > 0) {
479 mbField = new byte[padLength];
480 bb.get(mbField, 0, padLength);
481 basicParameterSet.setPadding(mbField);
482 }
483 return basicParameterSet;
484 };
485 }
486
487 @Override
488 public byte[] serialize() {
489 short paddedLength = getTotalLength();
490
491 // Serialize Basic Parameter Set. IEEE 802.1x, Figure 11.8
492 ByteBuffer data = ByteBuffer.wrap(new byte[paddedLength]);
493
494 // Octet 1,2
495 data.put(mkaVersion);
496 data.put(keyServerPriority);
497
498 // Octet 3
499 byte octet3 = (byte) ((byte) ((keyServer) ? 0x01 : 0x00) << KEYSERVER_OFFSET);
500 octet3 |= (byte) ((byte) ((macSecDesired) ? 0x01 : 0x00) << MACSEC_DESIRED_OFFSET);
501 octet3 |= capability << MACSEC_CAPABILITY_OFFSET;
502
503 // Remove header length upto "Length" field from total packet length.
504 paddedLength -= BPS_FIXED_PART_SIZE_UPTO_LENGTH_FIELD;
505 octet3 |= (byte) (paddedLength >> BODY_LENGTH_MSB_SHIFT & BODY_LENGTH_MSB_MASK);
506 data.put(octet3);
507
508 // Octet 4
509 data.put((byte) paddedLength);
510
511 // Octet 5-12
512 data.put(sci.array());
513
514 // Octet 13-24
515 data.put(mi);
516
517 // Octet 25-28
518 data.putInt(mn);
519
520 // Octet 29-32
521 data.put(algAgility);
522
523 // Octet 33-
524 data.put(ckn);
525
526 // TODO: Filling Padding if needed.
527
528 return data.array();
529 }
530
531
532 @Override
533 public byte getParameterSetType() {
534 return PARAMETERSET_TYPE_BASIC;
535 }
536
537 @Override
538 public short getTotalLength() {
539 /*
540 * Total size calculation.
541 * 4 byte aligned padded length calculation.
542 * ie. padded_length = (length + 3) & ~3
543 */
544 short paddedLength = (short) (((BPS_FIXED_PART_TOTAL_SIZE + ckn.length) + 0x03) & ~0x03);
545 return paddedLength;
546 }
547
548}