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