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