1 /* 2 * Copyright (C) 2019 The Android Open Source Project 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 17 package com.android.internal.net.ipsec.ike.message; 18 19 import android.net.ipsec.ike.exceptions.IkeProtocolException; 20 21 import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException; 22 23 import java.nio.ByteBuffer; 24 25 /** 26 * IkeDeletePayload represents a Delete Payload. 27 * 28 * <p>As instructed in RFC 7296, deletion of the IKE SA is indicated by a protocol ID of 1 (IKE) but 29 * no SPIs. Deletion of a Child SA will contain the IPsec protocol ID and SPIs of inbound IPsec 30 * packets. Since IKE library only supports negotiating Child SA using ESP, only the protocol ID of 31 * 3 (ESP) is used for deleting Child SA. 32 * 33 * The possible request/response pairs for deletion are as follows: 34 * - IKE SA deletion: 35 * Incoming: INFORMATIONAL(DELETE(PROTO_IKE)) 36 * Outgoing: INFORMATIONAL() 37 * 38 * - ESP SA deletion: 39 * Incoming: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_OUT)) 40 * Outgoing: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_IN)) 41 * 42 * - ESP SA simultaneous deletion: 43 * Outgoing: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_IN)) 44 * Incoming: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_OUT)) 45 * Outgoing: INFORMATIONAL() // Notice DELETE payload omitted 46 * 47 * - ESP SA simultaneous multi-deletion: 48 * Outgoing: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_IN)) 49 * Incoming: INFORMATIONAL(DELETE(PROTO_ESP, SPI_A_OUT, SPI_B_OUT)) 50 * Outgoing: INFORMATIONAL(DELETE(PROTO_ESP, SPI_B_IN)) // Notice SPI_A_OUT omitted 51 * 52 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.11">RFC 7296, Internet Key Exchange 53 * Protocol Version 2 (IKEv2)</a> 54 */ 55 public final class IkeDeletePayload extends IkeInformationalPayload { 56 private static final int DELETE_HEADER_LEN = 4; 57 58 @ProtocolId public final int protocolId; 59 public final byte spiSize; 60 public final int numSpi; 61 public final int[] spisToDelete; 62 63 /** 64 * Construct an instance of IkeDeletePayload from decoding inbound IKE packet. 65 * 66 * <p>NegativeArraySizeException and BufferUnderflowException will be caught in {@link 67 * IkeMessage} 68 * 69 * @param critical indicates if this payload is critical. Ignored in supported payload as 70 * instructed by the RFC 7296. 71 * @param payloadBody payload body in byte array 72 * @throws IkeProtocolException if there is any error 73 */ IkeDeletePayload(boolean critical, byte[] payloadBody)74 IkeDeletePayload(boolean critical, byte[] payloadBody) throws IkeProtocolException { 75 super(PAYLOAD_TYPE_DELETE, critical); 76 77 ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody); 78 79 protocolId = Byte.toUnsignedInt(inputBuffer.get()); 80 spiSize = inputBuffer.get(); 81 numSpi = Short.toUnsignedInt(inputBuffer.getShort()); 82 spisToDelete = new int[numSpi]; 83 84 switch (protocolId) { 85 case PROTOCOL_ID_IKE: 86 // Delete payload for IKE SA must not include SPI. 87 if (spiSize != SPI_LEN_NOT_INCLUDED 88 || numSpi != 0 89 || inputBuffer.remaining() != 0) { 90 throw new InvalidSyntaxException("Invalid Delete IKE Payload."); 91 } 92 break; 93 case PROTOCOL_ID_ESP: 94 // Delete payload for Child SA must include SPI 95 if (spiSize != SPI_LEN_IPSEC 96 || numSpi == 0 97 || inputBuffer.remaining() != SPI_LEN_IPSEC * numSpi) { 98 throw new InvalidSyntaxException("Invalid Delete Child Payload."); 99 } 100 101 for (int i = 0; i < numSpi; i++) { 102 spisToDelete[i] = inputBuffer.getInt(); 103 } 104 break; 105 default: 106 throw new InvalidSyntaxException("Unrecognized protocol in Delete Payload."); 107 } 108 } 109 110 /** 111 * Constructor for an outbound IKE SA deletion payload. 112 * 113 * <p>This constructor takes no SPI, as IKE SAs are deleted by sending a delete payload within 114 * the negotiated session. As such, the SPIs are shared state that does not need to be sent. 115 */ IkeDeletePayload()116 public IkeDeletePayload() { 117 super(PAYLOAD_TYPE_DELETE, false); 118 protocolId = PROTOCOL_ID_IKE; 119 spiSize = SPI_LEN_NOT_INCLUDED; 120 numSpi = 0; 121 spisToDelete = new int[0]; 122 } 123 124 /** 125 * Constructor for an outbound Child SA deletion payload. 126 * 127 * @param spis array of SPIs of Child SAs to delete. Must contain at least one SPI. 128 */ IkeDeletePayload(int[] spis)129 public IkeDeletePayload(int[] spis) { 130 super(PAYLOAD_TYPE_DELETE, false); 131 132 if (spis == null || spis.length < 1) { 133 throw new IllegalArgumentException("No SPIs provided"); 134 } 135 136 protocolId = PROTOCOL_ID_ESP; 137 spiSize = SPI_LEN_IPSEC; 138 numSpi = spis.length; 139 spisToDelete = spis; 140 } 141 142 /** 143 * Encode Delete Payload to ByteBuffer. 144 * 145 * @param nextPayload type of payload that follows this payload. 146 * @param byteBuffer destination ByteBuffer that stores encoded payload. 147 */ 148 @Override encodeToByteBuffer(@ayloadType int nextPayload, ByteBuffer byteBuffer)149 protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { 150 encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer); 151 byteBuffer.put((byte) protocolId).put(spiSize).putShort((short) numSpi); 152 153 for (int toDelete : spisToDelete) { 154 byteBuffer.putInt(toDelete); 155 } 156 } 157 158 /** 159 * Get entire payload length. 160 * 161 * @return entire payload length. 162 */ 163 @Override getPayloadLength()164 protected int getPayloadLength() { 165 return GENERIC_HEADER_LENGTH + DELETE_HEADER_LEN + spisToDelete.length * spiSize; 166 } 167 168 /** 169 * Return the payload type as a String. 170 * 171 * @return the payload type as a String. 172 */ 173 @Override getTypeString()174 public String getTypeString() { 175 return "Del"; 176 } 177 } 178