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