blob: 8f84f9f66917663aa456fc44aea29f5b289213be [file] [log] [blame]
Charles M.C. Chan94f37372015-01-10 17:53:42 +08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Charles M.C. Chan94f37372015-01-10 17:53:42 +08003 *
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.ipv6;
18
19import org.onlab.packet.BasePacket;
20import org.onlab.packet.Data;
Jonathan Hart2a655752015-04-07 16:46:33 -070021import org.onlab.packet.DeserializationException;
22import org.onlab.packet.Deserializer;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080023import org.onlab.packet.IPacket;
24import org.onlab.packet.IPv6;
Jonathan Hart2a655752015-04-07 16:46:33 -070025
Charles M.C. Chan94f37372015-01-10 17:53:42 +080026import java.nio.ByteBuffer;
27import java.util.Arrays;
28
Jian Li5fc14292015-12-04 11:30:46 -080029import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070030import static org.onlab.packet.PacketUtils.checkInput;
31
Charles M.C. Chan94f37372015-01-10 17:53:42 +080032/**
33 * Implements IPv6 authentication extension header format. (RFC 4302)
34 */
35public class Authentication extends BasePacket implements IExtensionHeader {
36 public static final byte FIXED_HEADER_LENGTH = 12; // bytes
37 public static final byte LENGTH_UNIT = 4; // bytes per unit
38 public static final byte MINUS = 2;
39
40 protected byte nextHeader;
41 protected byte payloadLength;
42 protected int securityParamIndex;
43 protected int sequence;
44 protected byte[] integrityCheck;
45
46 @Override
47 public byte getNextHeader() {
48 return this.nextHeader;
49 }
50
51 @Override
52 public Authentication setNextHeader(final byte nextHeader) {
53 this.nextHeader = nextHeader;
54 return this;
55 }
56
57 /**
58 * Gets the payload length of this header.
59 *
60 * @return the payload length
61 */
62 public byte getPayloadLength() {
63 return this.payloadLength;
64 }
65
66 /**
67 * Sets the payload length of this header.
68 *
69 * @param payloadLength the payload length to set
70 * @return this
71 */
72 public Authentication setPayloadLength(final byte payloadLength) {
73 this.payloadLength = payloadLength;
74 return this;
75 }
76
77 /**
78 * Gets the security parameter index of this header.
79 *
80 * @return the security parameter index
81 */
82 public int getSecurityParamIndex() {
83 return this.securityParamIndex;
84 }
85
86 /**
87 * Sets the security parameter index of this header.
88 *
89 * @param securityParamIndex the security parameter index to set
90 * @return this
91 */
92 public Authentication setSecurityParamIndex(final int securityParamIndex) {
93 this.securityParamIndex = securityParamIndex;
94 return this;
95 }
96
97 /**
98 * Gets the sequence number of this header.
99 *
100 * @return the sequence number
101 */
102 public int getSequence() {
103 return this.sequence;
104 }
105
106 /**
107 * Sets the sequence number of this header.
108 *
109 * @param sequence the sequence number to set
110 * @return this
111 */
112 public Authentication setSequence(final int sequence) {
113 this.sequence = sequence;
114 return this;
115 }
116
117 /**
118 * Gets the integrity check value of this header.
119 *
120 * @return the integrity check value
121 */
122 public byte[] getIntegrityCheck() {
123 return this.integrityCheck;
124 }
125
126 /**
127 * Sets the integrity check value of this header.
128 *
129 * @param integrityCheck the integrity check value to set
130 * @return this
131 */
132 public Authentication setIngegrityCheck(final byte[] integrityCheck) {
133 this.integrityCheck =
134 Arrays.copyOfRange(integrityCheck, 0, integrityCheck.length);
135 return this;
136 }
137
138 /**
139 * Gets the total length of this header.
140 * According to spec, payload length should be the total length of this AH
141 * in 4-octet unit, minus 2
142 *
143 * @return the total length
144 */
145 public int getTotalLength() {
146 return (this.payloadLength + MINUS) * LENGTH_UNIT;
147 }
148
149 @Override
150 public byte[] serialize() {
151 byte[] payloadData = null;
152 if (this.payload != null) {
153 this.payload.setParent(this);
154 payloadData = this.payload.serialize();
155 }
156
157 int headerLength = FIXED_HEADER_LENGTH + integrityCheck.length;
158 int payloadLength = 0;
159 if (payloadData != null) {
160 payloadLength = payloadData.length;
161 }
162
163 final byte[] data = new byte[headerLength + payloadLength];
164 final ByteBuffer bb = ByteBuffer.wrap(data);
165
166 bb.put(this.nextHeader);
167 bb.put(this.payloadLength);
168 bb.putShort((short) 0);
169 bb.putInt(this.securityParamIndex);
170 bb.putInt(this.sequence);
171 bb.put(this.integrityCheck, 0, integrityCheck.length);
172
173 if (payloadData != null) {
174 bb.put(payloadData);
175 }
176
177 if (this.parent != null && this.parent instanceof IExtensionHeader) {
178 ((IExtensionHeader) this.parent).setNextHeader(IPv6.PROTOCOL_AH);
179 }
180 return data;
181 }
182
183 @Override
184 public IPacket deserialize(byte[] data, int offset, int length) {
185 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
186 this.nextHeader = bb.get();
187 this.payloadLength = bb.get();
188 bb.getShort();
189 this.securityParamIndex = bb.getInt();
190 this.sequence = bb.getInt();
191 int icvLength = getTotalLength() - FIXED_HEADER_LENGTH;
192 this.integrityCheck = new byte[icvLength];
193 bb.get(this.integrityCheck, 0, icvLength);
194
Jonathan Hart2a655752015-04-07 16:46:33 -0700195 Deserializer<? extends IPacket> deserializer;
196 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
197 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800198 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700199 deserializer = Data.deserializer();
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800200 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700201
202 try {
203 this.payload = deserializer.deserialize(data, bb.position(),
204 bb.limit() - bb.position());
205 this.payload.setParent(this);
206 } catch (DeserializationException e) {
207 return this;
208 }
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800209
210 return this;
211 }
212
213 /*
214 * (non-Javadoc)
215 *
216 * @see java.lang.Object#hashCode()
217 */
218 @Override
219 public int hashCode() {
220 final int prime = 5807;
221 int result = super.hashCode();
222 result = prime * result + this.nextHeader;
223 result = prime * result + this.payloadLength;
224 result = prime * result + this.securityParamIndex;
225 result = prime * result + this.sequence;
226 for (byte b : this.integrityCheck) {
227 result = prime * result + b;
228 }
229 return result;
230 }
231
232 /*
233 * (non-Javadoc)
234 *
235 * @see java.lang.Object#equals(java.lang.Object)
236 */
237 @Override
238 public boolean equals(final Object obj) {
239 if (this == obj) {
240 return true;
241 }
242 if (!super.equals(obj)) {
243 return false;
244 }
245 if (!(obj instanceof Authentication)) {
246 return false;
247 }
248 final Authentication other = (Authentication) obj;
249 if (this.nextHeader != other.nextHeader) {
250 return false;
251 }
252 if (this.payloadLength != other.payloadLength) {
253 return false;
254 }
255 if (this.securityParamIndex != other.securityParamIndex) {
256 return false;
257 }
258 if (this.sequence != other.sequence) {
259 return false;
260 }
261 if (!Arrays.equals(this.integrityCheck, other.integrityCheck)) {
262 return false;
263 }
264 return true;
265 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700266
267 /**
268 * Deserializer function for authentication headers.
269 *
270 * @return deserializer function
271 */
272 public static Deserializer<Authentication> deserializer() {
273 return (data, offset, length) -> {
274 checkInput(data, offset, length, FIXED_HEADER_LENGTH);
275
276 Authentication authentication = new Authentication();
277
278 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
279 authentication.nextHeader = bb.get();
280 authentication.payloadLength = bb.get();
281 bb.getShort();
282 authentication.securityParamIndex = bb.getInt();
283 authentication.sequence = bb.getInt();
284 int icvLength = (authentication.payloadLength + MINUS) * LENGTH_UNIT - FIXED_HEADER_LENGTH;
285 authentication.integrityCheck = new byte[icvLength];
286 bb.get(authentication.integrityCheck, 0, icvLength);
287
288 Deserializer<? extends IPacket> deserializer;
289 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(authentication.nextHeader)) {
290 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(authentication.nextHeader);
291 } else {
292 deserializer = Data.deserializer();
293 }
294 authentication.payload = deserializer.deserialize(data, bb.position(),
295 bb.limit() - bb.position());
296 authentication.payload.setParent(authentication);
297
298 return authentication;
299 };
300 }
Jian Li5fc14292015-12-04 11:30:46 -0800301
302 @Override
303 public String toString() {
304 return toStringHelper(getClass())
305 .add("nextHeader", Byte.toString(nextHeader))
306 .add("payloadLength", Byte.toString(payloadLength))
307 .add("securityParamIndex", Integer.toString(securityParamIndex))
308 .add("sequence", Integer.toString(sequence))
309 .add("integrityCheck", Arrays.toString(integrityCheck))
310 .toString();
311 }
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800312}