blob: c6d5bd54f50b6fcc95986f2d77c23b38196580b3 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ike.ikev2.message;
import static com.android.ike.ikev2.message.IkePayload.PayloadType;
import android.util.Pair;
import com.android.ike.ikev2.exceptions.IkeException;
import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
import com.android.ike.ikev2.exceptions.UnsupportedCriticalPayloadException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;
/**
* IkeMessage represents an IKE message.
*
* <p>It contains all attributes and provides methods for encoding, decoding, encrypting and
* decrypting.
*
* @see <a href="https://tools.ietf.org/html/rfc7296#section-3">RFC 7296, Internet Key Exchange
* Protocol Version 2 (IKEv2).
*/
public final class IkeMessage {
public final IkeHeader ikeHeader;
public final List<IkePayload> ikePayloadList;
/**
* Conctruct an instance of IkeMessage. It is called by decode or for building outbound message.
*
* @param header the header of this IKE message
* @param payloadList the list of decoded IKE payloads in this IKE message
*/
public IkeMessage(IkeHeader header, List<IkePayload> payloadList) {
ikeHeader = header;
ikePayloadList = payloadList;
}
/**
* Decode unenrypted IKE message body and create an instance of IkeMessage.
*
* @param header the IKE header that is decoded but not validated
* @param inputPacket the byte array contains the whole IKE message
* @throws IkeException if there is any error
*/
public static IkeMessage decode(IkeHeader header, byte[] inputPacket) throws IkeException {
header.validate();
ByteBuffer inputBuffer =
ByteBuffer.wrap(
inputPacket,
IkeHeader.IKE_HEADER_LENGTH,
inputPacket.length - IkeHeader.IKE_HEADER_LENGTH);
@PayloadType int currentPayloadType = header.nextPayloadType;
// For supported payload
List<IkePayload> supportedPayloadList = new LinkedList<>();
// For unsupported critical payload
List<Integer> unsupportedCriticalPayloadList = new LinkedList<>();
while (currentPayloadType != IkePayload.PAYLOAD_TYPE_NO_NEXT) {
try {
Pair<IkePayload, Integer> pair =
IkePayloadFactory.getIkePayload(currentPayloadType, inputBuffer);
IkePayload payload = pair.first;
if (!(payload instanceof IkeUnsupportedPayload)) {
supportedPayloadList.add(payload);
} else if (payload.isCritical) {
unsupportedCriticalPayloadList.add(payload.payloadType);
}
// Simply ignore unsupported uncritical payload.
currentPayloadType = pair.second;
} catch (NegativeArraySizeException | BufferUnderflowException e) {
throw new InvalidSyntaxException("Malformed IKE Payload");
}
}
if (unsupportedCriticalPayloadList.size() > 0) {
throw new UnsupportedCriticalPayloadException(unsupportedCriticalPayloadList);
}
return new IkeMessage(header, supportedPayloadList);
}
}