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