1 /*
2  * Copyright (C) 2018 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.annotation.IntDef;
20 import android.util.SparseArray;
21 
22 import java.lang.annotation.Retention;
23 import java.lang.annotation.RetentionPolicy;
24 import java.nio.ByteBuffer;
25 import java.util.LinkedList;
26 import java.util.List;
27 
28 /**
29  * IkePayload is an abstract class that represents the common information for all IKE payload types.
30  *
31  * <p>Each types of IKE payload should implement its own subclass with its own decoding and encoding
32  * logic.
33  *
34  * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.2">RFC 7296, Internet Key Exchange
35  *     Protocol Version 2 (IKEv2)</a>
36  */
37 public abstract class IkePayload {
38     // Critical bit and following reserved 7 bits in payload generic header must all be zero
39     private static final byte PAYLOAD_HEADER_CRITICAL_BIT_UNSET = 0;
40     /** Length of a generic IKE payload header */
41     public static final int GENERIC_HEADER_LENGTH = 4;
42 
43     /**
44      * Payload types as defined by IANA:
45      *
46      * @see <a href="https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml">
47      */
48     @Retention(RetentionPolicy.SOURCE)
49     @IntDef({
50         PAYLOAD_TYPE_NO_NEXT,
51         PAYLOAD_TYPE_SA,
52         PAYLOAD_TYPE_KE,
53         PAYLOAD_TYPE_CERT,
54         PAYLOAD_TYPE_CERT_REQUEST,
55         PAYLOAD_TYPE_AUTH,
56         PAYLOAD_TYPE_ID_INITIATOR,
57         PAYLOAD_TYPE_ID_RESPONDER,
58         PAYLOAD_TYPE_NONCE,
59         PAYLOAD_TYPE_NOTIFY,
60         PAYLOAD_TYPE_DELETE,
61         PAYLOAD_TYPE_VENDOR,
62         PAYLOAD_TYPE_TS_INITIATOR,
63         PAYLOAD_TYPE_TS_RESPONDER,
64         PAYLOAD_TYPE_SK,
65         PAYLOAD_TYPE_CP,
66         PAYLOAD_TYPE_EAP,
67         PAYLOAD_TYPE_SKF
68     })
69     public @interface PayloadType {}
70 
71     /** No Next Payload */
72     public static final int PAYLOAD_TYPE_NO_NEXT = 0;
73     /** Security Association Payload */
74     public static final int PAYLOAD_TYPE_SA = 33;
75     /** Key Exchange Payload */
76     public static final int PAYLOAD_TYPE_KE = 34;
77     /** Identification Payload for IKE SA Initiator */
78     public static final int PAYLOAD_TYPE_ID_INITIATOR = 35;
79     /** Identification Payload for IKE SA Responder */
80     public static final int PAYLOAD_TYPE_ID_RESPONDER = 36;
81     /** Certificate Payload */
82     public static final int PAYLOAD_TYPE_CERT = 37;
83     /** Certificate Request Payload */
84     public static final int PAYLOAD_TYPE_CERT_REQUEST = 38;
85     /** Authentication Payload */
86     public static final int PAYLOAD_TYPE_AUTH = 39;
87     /** Nonce Payload */
88     public static final int PAYLOAD_TYPE_NONCE = 40;
89     /** Notify Payload */
90     public static final int PAYLOAD_TYPE_NOTIFY = 41;
91     /** Delete Payload */
92     public static final int PAYLOAD_TYPE_DELETE = 42;
93     /** Vendor Payload */
94     public static final int PAYLOAD_TYPE_VENDOR = 43;
95     /** Traffic Selector Payload of Child SA Initiator */
96     public static final int PAYLOAD_TYPE_TS_INITIATOR = 44;
97     /** Traffic Selector Payload of Child SA Responder */
98     public static final int PAYLOAD_TYPE_TS_RESPONDER = 45;
99     /** Encrypted and Authenticated Payload */
100     public static final int PAYLOAD_TYPE_SK = 46;
101     /** Configuration Payload */
102     public static final int PAYLOAD_TYPE_CP = 47;
103     /** EAP Payload */
104     public static final int PAYLOAD_TYPE_EAP = 48;
105     /** Encrypted and Authenticated Fragment */
106     public static final int PAYLOAD_TYPE_SKF = 53;
107 
108     // TODO: List all payload types.
109 
110     @Retention(RetentionPolicy.SOURCE)
111     @IntDef({
112         PROTOCOL_ID_UNSET,
113         PROTOCOL_ID_IKE,
114         PROTOCOL_ID_AH,
115         PROTOCOL_ID_ESP,
116     })
117     public @interface ProtocolId {}
118 
119     public static final int PROTOCOL_ID_UNSET = 0;
120     public static final int PROTOCOL_ID_IKE = 1;
121     public static final int PROTOCOL_ID_AH = 2;
122     public static final int PROTOCOL_ID_ESP = 3;
123 
124     private static final SparseArray<String> PROTOCOL_TO_STR;
125 
126     static {
127         PROTOCOL_TO_STR = new SparseArray<>();
PROTOCOL_TO_STR.put(PROTOCOL_ID_UNSET, "Protocol Unset")128         PROTOCOL_TO_STR.put(PROTOCOL_ID_UNSET, "Protocol Unset");
PROTOCOL_TO_STR.put(PROTOCOL_ID_IKE, "IKE")129         PROTOCOL_TO_STR.put(PROTOCOL_ID_IKE, "IKE");
PROTOCOL_TO_STR.put(PROTOCOL_ID_AH, "AH")130         PROTOCOL_TO_STR.put(PROTOCOL_ID_AH, "AH");
PROTOCOL_TO_STR.put(PROTOCOL_ID_ESP, "ESP")131         PROTOCOL_TO_STR.put(PROTOCOL_ID_ESP, "ESP");
132     }
133 
134     public static final byte SPI_LEN_NOT_INCLUDED = 0;
135     public static final byte SPI_LEN_IPSEC = 4;
136     public static final byte SPI_LEN_IKE = 8;
137 
138     public static final int SPI_NOT_INCLUDED = 0;
139 
140     /** Length of port number in bytes */
141     public static final int IP_PORT_LEN = 2;
142 
143     public final int payloadType;
144     public final boolean isCritical;
145 
146     /**
147      * Construct a instance of IkePayload in the context of a IkePayloadFactory.
148      *
149      * <p>It should be overrided by subclass of IkePayload
150      *
151      * @param payload the payload type. All supported types will fall in {@link
152      *     IkePayload.PayloadType}
153      * @param critical indicates if this payload is critical. Ignore it when payload type is
154      *     supported.
155      */
IkePayload(int payload, boolean critical)156     IkePayload(int payload, boolean critical) {
157         payloadType = payload;
158         isCritical = critical;
159     }
160 
161     /**
162      * A helper method to quickly obtain payloads with the input payload type in the provided
163      * payload list.
164      *
165      * <p>This method will not check if this payload type can be repeatable in an IKE message
166      * because it does not know the context of the provided payload list. Caller should call this
167      * method if they are expecting more than one payloads in the list.
168      *
169      * @param payloadType the payloadType to look for.
170      * @param payloadClass the class of the desired payload.
171      * @param searchList the payload list to do the search.
172      * @return a list of IkePayloads with the payloadType.
173      */
getPayloadListForTypeInProvidedList( @kePayload.PayloadType int payloadType, Class<T> payloadClass, List<IkePayload> searchList)174     public static <T extends IkePayload> List<T> getPayloadListForTypeInProvidedList(
175             @IkePayload.PayloadType int payloadType,
176             Class<T> payloadClass,
177             List<IkePayload> searchList) {
178         List<T> payloadList = new LinkedList<>();
179 
180         for (IkePayload payload : searchList) {
181             if (payloadType == payload.payloadType) {
182                 payloadList.add(payloadClass.cast(payload));
183             }
184         }
185 
186         return payloadList;
187     }
188 
189     /**
190      * A helper method to quickly obtain the payload with the input payload type in the provided
191      * payload list.
192      *
193      * <p>This method will not check if this payload type can be repeatable in an IKE message
194      * because it does not know the context of the provided payload list. Caller should call this
195      * method if they are expecting no more than one payloads in the list.
196      *
197      * @param payloadType the payloadType to look for.
198      * @param payloadClass the class of the desired payload.
199      * @param searchList the payload list to do the search.
200      * @return the IkePayload with the payloadType.
201      */
getPayloadForTypeInProvidedList( @kePayload.PayloadType int payloadType, Class<T> payloadClass, List<IkePayload> searchList)202     public static <T extends IkePayload> T getPayloadForTypeInProvidedList(
203             @IkePayload.PayloadType int payloadType,
204             Class<T> payloadClass,
205             List<IkePayload> searchList) {
206         List<T> payloadList =
207                 getPayloadListForTypeInProvidedList(payloadType, payloadClass, searchList);
208         return payloadList.isEmpty() ? null : payloadList.get(0);
209     }
210 
211     /**
212      * Encode generic payload header to ByteBuffer.
213      *
214      * @param nextPayload type of payload that follows this payload.
215      * @param payloadLength length of the entire payload
216      * @param byteBuffer destination ByteBuffer that stores encoded payload header
217      */
encodePayloadHeaderToByteBuffer( @ayloadType int nextPayload, int payloadLength, ByteBuffer byteBuffer)218     protected static void encodePayloadHeaderToByteBuffer(
219             @PayloadType int nextPayload, int payloadLength, ByteBuffer byteBuffer) {
220         byteBuffer
221                 .put((byte) nextPayload)
222                 .put(PAYLOAD_HEADER_CRITICAL_BIT_UNSET)
223                 .putShort((short) payloadLength);
224     }
225 
226     /** Retuns protocol type as String. */
getProtocolTypeString(@rotocolId int protocol)227     public static String getProtocolTypeString(@ProtocolId int protocol) {
228         return PROTOCOL_TO_STR.get(protocol);
229     }
230 
231     /**
232      * Encode payload to ByteBuffer.
233      *
234      * @param nextPayload type of payload that follows this payload.
235      * @param byteBuffer destination ByteBuffer that stores encoded payload.
236      */
encodeToByteBuffer(@ayloadType int nextPayload, ByteBuffer byteBuffer)237     protected abstract void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer);
238 
239     /**
240      * Get entire payload length.
241      *
242      * @return entire payload length.
243      */
getPayloadLength()244     protected abstract int getPayloadLength();
245 
246     /**
247      * Return the payload type as a String.
248      *
249      * @return the payload type as a String.
250      */
getTypeString()251     public abstract String getTypeString();
252 }
253