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 static android.net.ipsec.ike.IkeManager.getIkeLog; 20 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED; 21 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_CHILD_SA_NOT_FOUND; 22 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED; 23 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE; 24 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_IKE_SPI; 25 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD; 26 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_MAJOR_VERSION; 27 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_MESSAGE_ID; 28 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_SELECTORS; 29 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_INVALID_SYNTAX; 30 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_ADDITIONAL_SAS; 31 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN; 32 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED; 33 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE; 34 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE; 35 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD; 36 37 import android.annotation.IntDef; 38 import android.net.ipsec.ike.exceptions.AuthenticationFailedException; 39 import android.net.ipsec.ike.exceptions.ChildSaNotFoundException; 40 import android.net.ipsec.ike.exceptions.FailedCpRequiredException; 41 import android.net.ipsec.ike.exceptions.IkeProtocolException; 42 import android.net.ipsec.ike.exceptions.InternalAddressFailureException; 43 import android.net.ipsec.ike.exceptions.InvalidIkeSpiException; 44 import android.net.ipsec.ike.exceptions.InvalidKeException; 45 import android.net.ipsec.ike.exceptions.InvalidMajorVersionException; 46 import android.net.ipsec.ike.exceptions.InvalidMessageIdException; 47 import android.net.ipsec.ike.exceptions.InvalidSelectorsException; 48 import android.net.ipsec.ike.exceptions.InvalidSyntaxException; 49 import android.net.ipsec.ike.exceptions.NoAdditionalSasException; 50 import android.net.ipsec.ike.exceptions.NoValidProposalChosenException; 51 import android.net.ipsec.ike.exceptions.SinglePairRequiredException; 52 import android.net.ipsec.ike.exceptions.TemporaryFailureException; 53 import android.net.ipsec.ike.exceptions.TsUnacceptableException; 54 import android.net.ipsec.ike.exceptions.UnrecognizedIkeProtocolException; 55 import android.net.ipsec.ike.exceptions.UnsupportedCriticalPayloadException; 56 import android.util.ArraySet; 57 import android.util.SparseArray; 58 59 import java.lang.annotation.Retention; 60 import java.lang.annotation.RetentionPolicy; 61 import java.net.InetAddress; 62 import java.nio.ByteBuffer; 63 import java.security.MessageDigest; 64 import java.security.NoSuchAlgorithmException; 65 import java.security.ProviderException; 66 import java.util.Set; 67 68 /** 69 * IkeNotifyPayload represents a Notify Payload. 70 * 71 * <p>As instructed by RFC 7296, for IKE SA concerned Notify Payload, Protocol ID and SPI Size must 72 * be zero. Unrecognized notify message type must be ignored but should be logged. 73 * 74 * <p>Notification types that smaller or equal than ERROR_NOTIFY_TYPE_MAX are error types. The rest 75 * of them are status types. 76 * 77 * <p>Critical bit for this payload must be ignored in received packet and must not be set in 78 * outbound packet. 79 * 80 * @see <a href="https://tools.ietf.org/html/rfc7296">RFC 7296, Internet Key Exchange Protocol 81 * Version 2 (IKEv2)</a> 82 */ 83 public final class IkeNotifyPayload extends IkeInformationalPayload { 84 private static final String TAG = IkeNotifyPayload.class.getSimpleName(); 85 86 @Retention(RetentionPolicy.SOURCE) 87 @IntDef({ 88 NOTIFY_TYPE_INITIAL_CONTACT, 89 NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE, 90 NOTIFY_TYPE_IPCOMP_SUPPORTED, 91 NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP, 92 NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP, 93 NOTIFY_TYPE_USE_TRANSPORT_MODE, 94 NOTIFY_TYPE_REKEY_SA, 95 NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED, 96 NOTIFY_TYPE_EAP_ONLY_AUTHENTICATION, 97 NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED, 98 NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS 99 }) 100 public @interface NotifyType {} 101 102 /** 103 * Indicates that the sender supports INITIAL CONTACT functionality for the IKE Session. Only 104 * allowed in the request of first IKE_AUTH exchange Note: Currently IKE only supports sending 105 * this payload & will ignore the received payload 106 */ 107 public static final int NOTIFY_TYPE_INITIAL_CONTACT = 16384; 108 /** 109 * Indicates that the responder has narrowed the proposed Traffic Selectors but other Traffic 110 * Selectors would also have been acceptable. Only allowed in the response for negotiating a 111 * Child SA. 112 */ 113 public static final int NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE = 16386; 114 /** 115 * Indicates a willingness by its sender to use IPComp on this Child SA. Only allowed in the 116 * request/response for negotiating a Child SA. 117 */ 118 public static final int NOTIFY_TYPE_IPCOMP_SUPPORTED = 16387; 119 /** 120 * Used for detecting if the IKE initiator is behind a NAT. Only allowed in the request/response 121 * of IKE_SA_INIT exchange. 122 */ 123 public static final int NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP = 16388; 124 /** 125 * Used for detecting if the IKE responder is behind a NAT. Only allowed in the request/response 126 * of IKE_SA_INIT exchange. 127 */ 128 public static final int NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP = 16389; 129 /** 130 * Might be sent by the IKE responder in an IKE_SA_INIT response, to prevent DoS Attacks. If 131 * receiving it, IKE client MUST retry IKE_SA_INIT request with the same associated data. 132 */ 133 public static final int NOTIFY_TYPE_COOKIE = 16390; 134 /** 135 * Indicates a willingness by its sender to use transport mode rather than tunnel mode on this 136 * Child SA. Only allowed in the request/response for negotiating a Child SA. 137 */ 138 public static final int NOTIFY_TYPE_USE_TRANSPORT_MODE = 16391; 139 /** 140 * Used for rekeying a Child SA or an IKE SA. Only allowed in the request/response of 141 * CREATE_CHILD_SA exchange. 142 */ 143 public static final int NOTIFY_TYPE_REKEY_SA = 16393; 144 /** 145 * Indicates that the sender will not accept packets that contain TFC padding over the Child SA 146 * being negotiated. Only allowed in the request/response for negotiating a Child SA. 147 */ 148 public static final int NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED = 16394; 149 /** 150 * Indicates that the sender supports MOBIKE functionality for the IKE Session. Only allowed in 151 * the request/response of IKE_AUTH exchange. 152 */ 153 public static final int NOTIFY_TYPE_MOBIKE_SUPPORTED = 16396; 154 /** 155 * Used for notifying the Responder that an address change has occurred during a MOBIKE-enabled 156 * IKE Session. Only allowed in Informational exchanges sent after the IKE_AUTH exchange has 157 * finished. 158 */ 159 public static final int NOTIFY_TYPE_UPDATE_SA_ADDRESSES = 16400; 160 161 /** 162 * Used in any INFORMATIONAL request for return routability check purposes when performing 163 * MOBIKE. 164 */ 165 public static final int NOTIFY_TYPE_COOKIE2 = 16401; 166 167 /** Indicates that the sender prefers to use only eap based authentication */ 168 public static final int NOTIFY_TYPE_EAP_ONLY_AUTHENTICATION = 16417; 169 170 /** Indicates that the sender supports IKE fragmentation. */ 171 public static final int NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED = 16430; 172 173 /** 174 * Indicates that the sender supports GENERIC_DIGITAL_SIGNATURE authentication payloads. 175 * 176 * <p>See RFC 7427 - Signature Authentication in the Internet Key Exchange Version 2 (IKEv2) for 177 * more details 178 */ 179 public static final int NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS = 16431; 180 181 private static final int NOTIFY_HEADER_LEN = 4; 182 /** @hide */ 183 public static final int ERROR_NOTIFY_TYPE_MAX = 16383; 184 185 private static final String NAT_DETECTION_DIGEST_ALGORITHM = "SHA-1"; 186 187 private static final int COOKIE_DATA_LEN_MIN = 1; 188 private static final int COOKIE_DATA_LEN_MAX = 64; 189 190 private static final int COOKIE2_DATA_LEN_MIN = 8; 191 private static final int COOKIE2_DATA_LEN_MAX = 64; 192 193 private static final Set<Integer> VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA; 194 private static final Set<Integer> VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA; 195 196 private static final SparseArray<String> NOTIFY_TYPE_TO_STRING; 197 198 static { 199 VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA = new ArraySet<>(); 200 VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.add(ERROR_TYPE_INVALID_SELECTORS); 201 VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.add(ERROR_TYPE_CHILD_SA_NOT_FOUND); 202 VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.add(NOTIFY_TYPE_REKEY_SA); 203 } 204 205 static { 206 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA = new ArraySet<>(); 207 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN); 208 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD); 209 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add( 210 IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED); 211 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_NO_ADDITIONAL_SAS); 212 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add( 213 IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE); 214 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED); 215 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE); 216 217 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE); 218 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_IPCOMP_SUPPORTED); 219 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_USE_TRANSPORT_MODE); 220 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED); 221 } 222 223 static { 224 NOTIFY_TYPE_TO_STRING = new SparseArray<>(); NOTIFY_TYPE_TO_STRING.put( ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, "Unsupported critical payload")225 NOTIFY_TYPE_TO_STRING.put( 226 ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, "Unsupported critical payload"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_IKE_SPI, "Invalid IKE SPI")227 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_IKE_SPI, "Invalid IKE SPI"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_MAJOR_VERSION, "Invalid major version")228 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_MAJOR_VERSION, "Invalid major version"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_SYNTAX, "Invalid syntax")229 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_SYNTAX, "Invalid syntax"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_MESSAGE_ID, "Invalid message ID")230 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_MESSAGE_ID, "Invalid message ID"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_NO_PROPOSAL_CHOSEN, "No proposal chosen")231 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_NO_PROPOSAL_CHOSEN, "No proposal chosen"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_KE_PAYLOAD, "Invalid KE payload")232 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_KE_PAYLOAD, "Invalid KE payload"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_AUTHENTICATION_FAILED, "Authentication failed")233 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_AUTHENTICATION_FAILED, "Authentication failed"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_SINGLE_PAIR_REQUIRED, "Single pair required")234 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_SINGLE_PAIR_REQUIRED, "Single pair required"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_NO_ADDITIONAL_SAS, "No additional SAs")235 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_NO_ADDITIONAL_SAS, "No additional SAs"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INTERNAL_ADDRESS_FAILURE, "Internal address failure")236 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INTERNAL_ADDRESS_FAILURE, "Internal address failure"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_FAILED_CP_REQUIRED, "Failed CP required")237 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_FAILED_CP_REQUIRED, "Failed CP required"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_TS_UNACCEPTABLE, "TS unacceptable")238 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_TS_UNACCEPTABLE, "TS unacceptable"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_SELECTORS, "Invalid selectors")239 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_SELECTORS, "Invalid selectors"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_TEMPORARY_FAILURE, "Temporary failure")240 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_TEMPORARY_FAILURE, "Temporary failure"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_CHILD_SA_NOT_FOUND, "Child SA not found")241 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_CHILD_SA_NOT_FOUND, "Child SA not found"); 242 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE, "Additional TS possible")243 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE, "Additional TS possible"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_IPCOMP_SUPPORTED, "IPCOMP supported")244 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_IPCOMP_SUPPORTED, "IPCOMP supported"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP, "NAT detection source IP")245 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP, "NAT detection source IP"); NOTIFY_TYPE_TO_STRING.put( NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP, "NAT detection destination IP")246 NOTIFY_TYPE_TO_STRING.put( 247 NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP, "NAT detection destination IP"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_COOKIE, "COOKIE")248 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_COOKIE, "COOKIE"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_USE_TRANSPORT_MODE, "Use transport mode")249 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_USE_TRANSPORT_MODE, "Use transport mode"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_REKEY_SA, "Rekey SA")250 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_REKEY_SA, "Rekey SA"); NOTIFY_TYPE_TO_STRING.put( NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED, "ESP TFC Padding not supported")251 NOTIFY_TYPE_TO_STRING.put( 252 NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED, "ESP TFC Padding not supported"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_MOBIKE_SUPPORTED, "MOBIKE supported")253 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_MOBIKE_SUPPORTED, "MOBIKE supported"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_UPDATE_SA_ADDRESSES, "UPDATE_SA_ADDRESSES")254 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_UPDATE_SA_ADDRESSES, "UPDATE_SA_ADDRESSES"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_COOKIE2, "COOKIE2")255 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_COOKIE2, "COOKIE2"); NOTIFY_TYPE_TO_STRING.put( NOTIFY_TYPE_EAP_ONLY_AUTHENTICATION, "EAP-only Authentication")256 NOTIFY_TYPE_TO_STRING.put( 257 NOTIFY_TYPE_EAP_ONLY_AUTHENTICATION, "EAP-only Authentication"); NOTIFY_TYPE_TO_STRING.put( NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED, "Fragmentation supported")258 NOTIFY_TYPE_TO_STRING.put( 259 NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED, "Fragmentation supported"); NOTIFY_TYPE_TO_STRING.put( NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS, "Generic Digital Signatures supported")260 NOTIFY_TYPE_TO_STRING.put( 261 NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS, "Generic Digital Signatures supported"); 262 } 263 264 public final int protocolId; 265 public final byte spiSize; 266 public final int notifyType; 267 public final int spi; 268 public final byte[] notifyData; 269 270 /** 271 * Construct an instance of IkeNotifyPayload in the context of IkePayloadFactory 272 * 273 * @param critical indicates if this payload is critical. Ignored in supported payload as 274 * instructed by the RFC 7296. 275 * @param payloadBody payload body in byte array 276 * @throws IkeProtocolException if there is any error 277 */ IkeNotifyPayload(boolean isCritical, byte[] payloadBody)278 IkeNotifyPayload(boolean isCritical, byte[] payloadBody) throws IkeProtocolException { 279 super(PAYLOAD_TYPE_NOTIFY, isCritical); 280 281 ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody); 282 283 protocolId = Byte.toUnsignedInt(inputBuffer.get()); 284 spiSize = inputBuffer.get(); 285 notifyType = Short.toUnsignedInt(inputBuffer.getShort()); 286 287 // Validate syntax of spiSize, protocolId and notifyType. 288 // Reference: <https://tools.ietf.org/html/rfc7296#page-100> 289 if (spiSize == SPI_LEN_IPSEC) { 290 // For message concerning existing Child SA 291 validateNotifyPayloadForExistingChildSa(); 292 spi = inputBuffer.getInt(); 293 294 } else if (spiSize == SPI_LEN_NOT_INCLUDED) { 295 // For message concerning IKE SA or for new Child SA that to be negotiated. 296 validateNotifyPayloadForIkeAndNewChild(); 297 spi = SPI_NOT_INCLUDED; 298 299 } else { 300 throw new InvalidSyntaxException("Invalid SPI Size: " + spiSize); 301 } 302 303 notifyData = new byte[payloadBody.length - NOTIFY_HEADER_LEN - spiSize]; 304 inputBuffer.get(notifyData); 305 } 306 validateNotifyPayloadForExistingChildSa()307 private void validateNotifyPayloadForExistingChildSa() throws InvalidSyntaxException { 308 if (protocolId != PROTOCOL_ID_AH && protocolId != PROTOCOL_ID_ESP) { 309 throw new InvalidSyntaxException( 310 "Expected Procotol ID AH(2) or ESP(3): Protocol ID is " + protocolId); 311 } 312 313 if (!VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.contains(notifyType)) { 314 throw new InvalidSyntaxException( 315 "Expected Notify Type for existing Child SA: Notify Type is " + notifyType); 316 } 317 } 318 validateNotifyPayloadForIkeAndNewChild()319 private void validateNotifyPayloadForIkeAndNewChild() throws InvalidSyntaxException { 320 if (protocolId != PROTOCOL_ID_UNSET) { 321 getIkeLog().w(TAG, "Expected Procotol ID unset: Protocol ID is " + protocolId); 322 } 323 324 if (notifyType == ERROR_TYPE_INVALID_SELECTORS 325 || notifyType == ERROR_TYPE_CHILD_SA_NOT_FOUND) { 326 throw new InvalidSyntaxException( 327 "Expected Notify Type concerning IKE SA or new Child SA under negotiation" 328 + ": Notify Type is " 329 + notifyType); 330 } 331 } 332 333 /** 334 * Generate NAT DETECTION notification data. 335 * 336 * <p>This method calculates NAT DETECTION notification data which is a SHA-1 digest of the IKE 337 * initiator's SPI, IKE responder's SPI, IP address and port. Source address and port should be 338 * used for generating NAT_DETECTION_SOURCE_IP data. Destination address and port should be used 339 * for generating NAT_DETECTION_DESTINATION_IP data. Here "source" and "destination" mean the 340 * direction of this IKE message. 341 * 342 * @param initiatorIkeSpi the SPI of IKE initiator 343 * @param responderIkeSpi the SPI of IKE responder 344 * @param ipAddress the IP address 345 * @param port the port 346 * @return the generated NAT DETECTION notification data as a byte array. 347 */ generateNatDetectionData( long initiatorIkeSpi, long responderIkeSpi, InetAddress ipAddress, int port)348 public static byte[] generateNatDetectionData( 349 long initiatorIkeSpi, long responderIkeSpi, InetAddress ipAddress, int port) { 350 byte[] rawIpAddr = ipAddress.getAddress(); 351 352 ByteBuffer byteBuffer = 353 ByteBuffer.allocate(2 * SPI_LEN_IKE + rawIpAddr.length + IP_PORT_LEN); 354 byteBuffer 355 .putLong(initiatorIkeSpi) 356 .putLong(responderIkeSpi) 357 .put(rawIpAddr) 358 .putShort((short) port); 359 360 try { 361 MessageDigest natDetectionDataDigest = 362 MessageDigest.getInstance(NAT_DETECTION_DIGEST_ALGORITHM); 363 return natDetectionDataDigest.digest(byteBuffer.array()); 364 } catch (NoSuchAlgorithmException e) { 365 throw new ProviderException( 366 "Failed to obtain algorithm :" + NAT_DETECTION_DIGEST_ALGORITHM, e); 367 } 368 } 369 handleCookieAndGenerateCopy( IkeNotifyPayload cookie2Notify, int minLen, int maxLen)370 private static IkeNotifyPayload handleCookieAndGenerateCopy( 371 IkeNotifyPayload cookie2Notify, int minLen, int maxLen) throws InvalidSyntaxException { 372 byte[] notifyData = cookie2Notify.notifyData; 373 if (notifyData.length < minLen || notifyData.length > maxLen) { 374 String cookieType = 375 cookie2Notify.notifyType == NOTIFY_TYPE_COOKIE2 ? "COOKIE2" : "COOKIE"; 376 throw new InvalidSyntaxException( 377 "Invalid " 378 + cookieType 379 + " notification data with length " 380 + notifyData.length); 381 } 382 383 return new IkeNotifyPayload(cookie2Notify.notifyType, notifyData); 384 } 385 386 /** Validate inbound Cookie in IKE_INIT response and build a Cookie notify payload in request */ handleCookieAndGenerateCopy(IkeNotifyPayload cookieNotify)387 public static IkeNotifyPayload handleCookieAndGenerateCopy(IkeNotifyPayload cookieNotify) 388 throws InvalidSyntaxException { 389 return handleCookieAndGenerateCopy(cookieNotify, COOKIE_DATA_LEN_MIN, COOKIE_DATA_LEN_MAX); 390 } 391 392 /** Validate inbound Cookie2 request and build a response Cookie2 notify payload */ handleCookie2AndGenerateCopy(IkeNotifyPayload cookie2Notify)393 public static IkeNotifyPayload handleCookie2AndGenerateCopy(IkeNotifyPayload cookie2Notify) 394 throws InvalidSyntaxException { 395 return handleCookieAndGenerateCopy( 396 cookie2Notify, COOKIE2_DATA_LEN_MIN, COOKIE2_DATA_LEN_MAX); 397 } 398 399 /** 400 * Encode Notify payload to ByteBuffer. 401 * 402 * @param nextPayload type of payload that follows this payload. 403 * @param byteBuffer destination ByteBuffer that stores encoded payload. 404 */ 405 @Override encodeToByteBuffer(@ayloadType int nextPayload, ByteBuffer byteBuffer)406 protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { 407 encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer); 408 byteBuffer.put((byte) protocolId).put(spiSize).putShort((short) notifyType); 409 if (spiSize == SPI_LEN_IPSEC) { 410 byteBuffer.putInt(spi); 411 } 412 byteBuffer.put(notifyData); 413 } 414 415 /** 416 * Get entire payload length. 417 * 418 * @return entire payload length. 419 */ 420 @Override getPayloadLength()421 protected int getPayloadLength() { 422 return GENERIC_HEADER_LENGTH + NOTIFY_HEADER_LEN + spiSize + notifyData.length; 423 } 424 IkeNotifyPayload( @rotocolId int protocolId, byte spiSize, int spi, int notifyType, byte[] notifyData)425 protected IkeNotifyPayload( 426 @ProtocolId int protocolId, byte spiSize, int spi, int notifyType, byte[] notifyData) { 427 super(PAYLOAD_TYPE_NOTIFY, false); 428 this.protocolId = protocolId; 429 this.spiSize = spiSize; 430 this.spi = spi; 431 this.notifyType = notifyType; 432 this.notifyData = notifyData; 433 } 434 435 /** 436 * Construct IkeNotifyPayload concerning either an IKE SA, or Child SA that is going to be 437 * negotiated with associated notification data. 438 * 439 * @param notifyType the notify type concerning IKE SA 440 * @param notifytData status or error data transmitted. Values for this field are notify type 441 * specific. 442 */ IkeNotifyPayload(int notifyType, byte[] notifyData)443 public IkeNotifyPayload(int notifyType, byte[] notifyData) { 444 this(PROTOCOL_ID_UNSET, SPI_LEN_NOT_INCLUDED, SPI_NOT_INCLUDED, notifyType, notifyData); 445 try { 446 validateNotifyPayloadForIkeAndNewChild(); 447 } catch (InvalidSyntaxException e) { 448 throw new IllegalArgumentException(e); 449 } 450 } 451 452 /** 453 * Construct IkeNotifyPayload concerning either an IKE SA, or Child SA that is going to be 454 * negotiated without additional notification data. 455 * 456 * @param notifyType the notify type concerning IKE SA 457 */ IkeNotifyPayload(int notifyType)458 public IkeNotifyPayload(int notifyType) { 459 this(notifyType, new byte[0]); 460 } 461 462 /** 463 * Construct IkeNotifyPayload concerning existing Child SA 464 * 465 * @param notifyType the notify type concerning Child SA 466 * @param notifytData status or error data transmitted. Values for this field are notify type 467 * specific. 468 */ IkeNotifyPayload( @rotocolId int protocolId, int spi, int notifyType, byte[] notifyData)469 public IkeNotifyPayload( 470 @ProtocolId int protocolId, int spi, int notifyType, byte[] notifyData) { 471 this(protocolId, SPI_LEN_IPSEC, spi, notifyType, notifyData); 472 try { 473 validateNotifyPayloadForExistingChildSa(); 474 } catch (InvalidSyntaxException e) { 475 throw new IllegalArgumentException(e); 476 } 477 } 478 479 /** 480 * Indicates if this is an error notification payload. 481 * 482 * @return if this is an error notification payload. 483 */ isErrorNotify()484 public boolean isErrorNotify() { 485 return notifyType <= ERROR_NOTIFY_TYPE_MAX; 486 } 487 488 /** 489 * Indicates if this is an notification for a new Child SA negotiation. 490 * 491 * <p>This notification may provide additional configuration information for negotiating a new 492 * Child SA or is an error notification of the Child SA negotiation failure. 493 * 494 * @return if this is an notification for a new Child SA negotiation. 495 */ isNewChildSaNotify()496 public boolean isNewChildSaNotify() { 497 return VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.contains(notifyType); 498 } 499 500 /** 501 * Validate error data and build IkeProtocolException for this error notification. 502 * 503 * @return the IkeProtocolException that represents this error. 504 * @throws InvalidSyntaxException if error data has invalid size. 505 */ validateAndBuildIkeException()506 public IkeProtocolException validateAndBuildIkeException() throws InvalidSyntaxException { 507 if (!isErrorNotify()) { 508 throw new IllegalArgumentException( 509 "Do not support building IkeException for a non-error notificaton. Notify" 510 + " type: " 511 + notifyType); 512 } 513 514 try { 515 switch (notifyType) { 516 case ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD: 517 return new UnsupportedCriticalPayloadException(notifyData); 518 case ERROR_TYPE_INVALID_IKE_SPI: 519 return new InvalidIkeSpiException(notifyData); 520 case ERROR_TYPE_INVALID_MAJOR_VERSION: 521 return new InvalidMajorVersionException(notifyData); 522 case ERROR_TYPE_INVALID_SYNTAX: 523 return new InvalidSyntaxException(notifyData); 524 case ERROR_TYPE_INVALID_MESSAGE_ID: 525 return new InvalidMessageIdException(notifyData); 526 case ERROR_TYPE_NO_PROPOSAL_CHOSEN: 527 return new NoValidProposalChosenException(notifyData); 528 case ERROR_TYPE_INVALID_KE_PAYLOAD: 529 return new InvalidKeException(notifyData); 530 case ERROR_TYPE_AUTHENTICATION_FAILED: 531 return new AuthenticationFailedException(notifyData); 532 case ERROR_TYPE_SINGLE_PAIR_REQUIRED: 533 return new SinglePairRequiredException(notifyData); 534 case ERROR_TYPE_NO_ADDITIONAL_SAS: 535 return new NoAdditionalSasException(notifyData); 536 case ERROR_TYPE_INTERNAL_ADDRESS_FAILURE: 537 return new InternalAddressFailureException(notifyData); 538 case ERROR_TYPE_FAILED_CP_REQUIRED: 539 return new FailedCpRequiredException(notifyData); 540 case ERROR_TYPE_TS_UNACCEPTABLE: 541 return new TsUnacceptableException(notifyData); 542 case ERROR_TYPE_INVALID_SELECTORS: 543 return new InvalidSelectorsException(spi, notifyData); 544 case ERROR_TYPE_TEMPORARY_FAILURE: 545 return new TemporaryFailureException(notifyData); 546 case ERROR_TYPE_CHILD_SA_NOT_FOUND: 547 return new ChildSaNotFoundException(spi, notifyData); 548 default: 549 return new UnrecognizedIkeProtocolException(notifyType, notifyData); 550 } 551 } catch (IllegalArgumentException e) { 552 // Notification data length is invalid. 553 throw new InvalidSyntaxException(e); 554 } 555 } 556 557 /** 558 * Return the payload type as a String. 559 * 560 * @return the payload type as a String. 561 */ 562 @Override getTypeString()563 public String getTypeString() { 564 String notifyTypeString = NOTIFY_TYPE_TO_STRING.get(notifyType); 565 566 if (notifyTypeString == null) { 567 return "Notify(" + notifyType + ")"; 568 } 569 return "Notify(" + notifyTypeString + ")"; 570 } 571 } 572