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 private static final int ERROR_NOTIFY_TYPE_MAX = 16383; 183 184 private static final String NAT_DETECTION_DIGEST_ALGORITHM = "SHA-1"; 185 186 private static final int COOKIE_DATA_LEN_MIN = 1; 187 private static final int COOKIE_DATA_LEN_MAX = 64; 188 189 private static final int COOKIE2_DATA_LEN_MIN = 8; 190 private static final int COOKIE2_DATA_LEN_MAX = 64; 191 192 private static final Set<Integer> VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA; 193 private static final Set<Integer> VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA; 194 195 private static final SparseArray<String> NOTIFY_TYPE_TO_STRING; 196 197 static { 198 VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA = new ArraySet<>(); 199 VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.add(ERROR_TYPE_INVALID_SELECTORS); 200 VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.add(ERROR_TYPE_CHILD_SA_NOT_FOUND); 201 VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.add(NOTIFY_TYPE_REKEY_SA); 202 } 203 204 static { 205 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA = new ArraySet<>(); 206 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN); 207 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD); 208 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add( 209 IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED); 210 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_NO_ADDITIONAL_SAS); 211 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add( 212 IkeProtocolException.ERROR_TYPE_INTERNAL_ADDRESS_FAILURE); 213 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED); 214 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE); 215 216 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE); 217 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_IPCOMP_SUPPORTED); 218 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_USE_TRANSPORT_MODE); 219 VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.add(NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED); 220 } 221 222 static { 223 NOTIFY_TYPE_TO_STRING = new SparseArray<>(); NOTIFY_TYPE_TO_STRING.put( ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, "Unsupported critical payload")224 NOTIFY_TYPE_TO_STRING.put( 225 ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, "Unsupported critical payload"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_IKE_SPI, "Invalid IKE SPI")226 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")227 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_MAJOR_VERSION, "Invalid major version"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_SYNTAX, "Invalid syntax")228 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_SYNTAX, "Invalid syntax"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_MESSAGE_ID, "Invalid message ID")229 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")230 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")231 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_KE_PAYLOAD, "Invalid KE payload"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_AUTHENTICATION_FAILED, "Authentication failed")232 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_AUTHENTICATION_FAILED, "Authentication failed"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_SINGLE_PAIR_REQUIRED, "Single pair required")233 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")234 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")235 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")236 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_FAILED_CP_REQUIRED, "Failed CP required"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_TS_UNACCEPTABLE, "TS unacceptable")237 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_TS_UNACCEPTABLE, "TS unacceptable"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_SELECTORS, "Invalid selectors")238 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_INVALID_SELECTORS, "Invalid selectors"); NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_TEMPORARY_FAILURE, "Temporary failure")239 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")240 NOTIFY_TYPE_TO_STRING.put(ERROR_TYPE_CHILD_SA_NOT_FOUND, "Child SA not found"); 241 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE, "Additional TS possible")242 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_ADDITIONAL_TS_POSSIBLE, "Additional TS possible"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_IPCOMP_SUPPORTED, "IPCOMP supported")243 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")244 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")245 NOTIFY_TYPE_TO_STRING.put( 246 NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP, "NAT detection destination IP"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_COOKIE, "COOKIE")247 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_COOKIE, "COOKIE"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_USE_TRANSPORT_MODE, "Use transport mode")248 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_USE_TRANSPORT_MODE, "Use transport mode"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_REKEY_SA, "Rekey SA")249 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")250 NOTIFY_TYPE_TO_STRING.put( 251 NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED, "ESP TFC Padding not supported"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_MOBIKE_SUPPORTED, "MOBIKE supported")252 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_MOBIKE_SUPPORTED, "MOBIKE supported"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_UPDATE_SA_ADDRESSES, "UPDATE_SA_ADDRESSES")253 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_UPDATE_SA_ADDRESSES, "UPDATE_SA_ADDRESSES"); NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_COOKIE2, "COOKIE2")254 NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_COOKIE2, "COOKIE2"); NOTIFY_TYPE_TO_STRING.put( NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED, "Fragmentation supported")255 NOTIFY_TYPE_TO_STRING.put( 256 NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED, "Fragmentation supported"); NOTIFY_TYPE_TO_STRING.put( NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS, "Generic Digital Signatures supported")257 NOTIFY_TYPE_TO_STRING.put( 258 NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS, "Generic Digital Signatures supported"); 259 } 260 261 public final int protocolId; 262 public final byte spiSize; 263 public final int notifyType; 264 public final int spi; 265 public final byte[] notifyData; 266 267 /** 268 * Construct an instance of IkeNotifyPayload in the context of IkePayloadFactory 269 * 270 * @param critical indicates if this payload is critical. Ignored in supported payload as 271 * instructed by the RFC 7296. 272 * @param payloadBody payload body in byte array 273 * @throws IkeProtocolException if there is any error 274 */ IkeNotifyPayload(boolean isCritical, byte[] payloadBody)275 IkeNotifyPayload(boolean isCritical, byte[] payloadBody) throws IkeProtocolException { 276 super(PAYLOAD_TYPE_NOTIFY, isCritical); 277 278 ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody); 279 280 protocolId = Byte.toUnsignedInt(inputBuffer.get()); 281 spiSize = inputBuffer.get(); 282 notifyType = Short.toUnsignedInt(inputBuffer.getShort()); 283 284 // Validate syntax of spiSize, protocolId and notifyType. 285 // Reference: <https://tools.ietf.org/html/rfc7296#page-100> 286 if (spiSize == SPI_LEN_IPSEC) { 287 // For message concerning existing Child SA 288 validateNotifyPayloadForExistingChildSa(); 289 spi = inputBuffer.getInt(); 290 291 } else if (spiSize == SPI_LEN_NOT_INCLUDED) { 292 // For message concerning IKE SA or for new Child SA that to be negotiated. 293 validateNotifyPayloadForIkeAndNewChild(); 294 spi = SPI_NOT_INCLUDED; 295 296 } else { 297 throw new InvalidSyntaxException("Invalid SPI Size: " + spiSize); 298 } 299 300 notifyData = new byte[payloadBody.length - NOTIFY_HEADER_LEN - spiSize]; 301 inputBuffer.get(notifyData); 302 } 303 validateNotifyPayloadForExistingChildSa()304 private void validateNotifyPayloadForExistingChildSa() throws InvalidSyntaxException { 305 if (protocolId != PROTOCOL_ID_AH && protocolId != PROTOCOL_ID_ESP) { 306 throw new InvalidSyntaxException( 307 "Expected Procotol ID AH(2) or ESP(3): Protocol ID is " + protocolId); 308 } 309 310 if (!VALID_NOTIFY_TYPES_FOR_EXISTING_CHILD_SA.contains(notifyType)) { 311 throw new InvalidSyntaxException( 312 "Expected Notify Type for existing Child SA: Notify Type is " + notifyType); 313 } 314 } 315 validateNotifyPayloadForIkeAndNewChild()316 private void validateNotifyPayloadForIkeAndNewChild() throws InvalidSyntaxException { 317 if (protocolId != PROTOCOL_ID_UNSET) { 318 getIkeLog().w(TAG, "Expected Procotol ID unset: Protocol ID is " + protocolId); 319 } 320 321 if (notifyType == ERROR_TYPE_INVALID_SELECTORS 322 || notifyType == ERROR_TYPE_CHILD_SA_NOT_FOUND) { 323 throw new InvalidSyntaxException( 324 "Expected Notify Type concerning IKE SA or new Child SA under negotiation" 325 + ": Notify Type is " 326 + notifyType); 327 } 328 } 329 330 /** 331 * Generate NAT DETECTION notification data. 332 * 333 * <p>This method calculates NAT DETECTION notification data which is a SHA-1 digest of the IKE 334 * initiator's SPI, IKE responder's SPI, IP address and port. Source address and port should be 335 * used for generating NAT_DETECTION_SOURCE_IP data. Destination address and port should be used 336 * for generating NAT_DETECTION_DESTINATION_IP data. Here "source" and "destination" mean the 337 * direction of this IKE message. 338 * 339 * @param initiatorIkeSpi the SPI of IKE initiator 340 * @param responderIkeSpi the SPI of IKE responder 341 * @param ipAddress the IP address 342 * @param port the port 343 * @return the generated NAT DETECTION notification data as a byte array. 344 */ generateNatDetectionData( long initiatorIkeSpi, long responderIkeSpi, InetAddress ipAddress, int port)345 public static byte[] generateNatDetectionData( 346 long initiatorIkeSpi, long responderIkeSpi, InetAddress ipAddress, int port) { 347 byte[] rawIpAddr = ipAddress.getAddress(); 348 349 ByteBuffer byteBuffer = 350 ByteBuffer.allocate(2 * SPI_LEN_IKE + rawIpAddr.length + IP_PORT_LEN); 351 byteBuffer 352 .putLong(initiatorIkeSpi) 353 .putLong(responderIkeSpi) 354 .put(rawIpAddr) 355 .putShort((short) port); 356 357 try { 358 MessageDigest natDetectionDataDigest = 359 MessageDigest.getInstance(NAT_DETECTION_DIGEST_ALGORITHM); 360 return natDetectionDataDigest.digest(byteBuffer.array()); 361 } catch (NoSuchAlgorithmException e) { 362 throw new ProviderException( 363 "Failed to obtain algorithm :" + NAT_DETECTION_DIGEST_ALGORITHM, e); 364 } 365 } 366 handleCookieAndGenerateCopy( IkeNotifyPayload cookie2Notify, int minLen, int maxLen)367 private static IkeNotifyPayload handleCookieAndGenerateCopy( 368 IkeNotifyPayload cookie2Notify, int minLen, int maxLen) throws InvalidSyntaxException { 369 byte[] notifyData = cookie2Notify.notifyData; 370 if (notifyData.length < minLen || notifyData.length > maxLen) { 371 String cookieType = 372 cookie2Notify.notifyType == NOTIFY_TYPE_COOKIE2 ? "COOKIE2" : "COOKIE"; 373 throw new InvalidSyntaxException( 374 "Invalid " 375 + cookieType 376 + " notification data with length " 377 + notifyData.length); 378 } 379 380 return new IkeNotifyPayload(cookie2Notify.notifyType, notifyData); 381 } 382 383 /** Validate inbound Cookie in IKE_INIT response and build a Cookie notify payload in request */ handleCookieAndGenerateCopy(IkeNotifyPayload cookieNotify)384 public static IkeNotifyPayload handleCookieAndGenerateCopy(IkeNotifyPayload cookieNotify) 385 throws InvalidSyntaxException { 386 return handleCookieAndGenerateCopy(cookieNotify, COOKIE_DATA_LEN_MIN, COOKIE_DATA_LEN_MAX); 387 } 388 389 /** Validate inbound Cookie2 request and build a response Cookie2 notify payload */ handleCookie2AndGenerateCopy(IkeNotifyPayload cookie2Notify)390 public static IkeNotifyPayload handleCookie2AndGenerateCopy(IkeNotifyPayload cookie2Notify) 391 throws InvalidSyntaxException { 392 return handleCookieAndGenerateCopy( 393 cookie2Notify, COOKIE2_DATA_LEN_MIN, COOKIE2_DATA_LEN_MAX); 394 } 395 396 /** 397 * Encode Notify payload to ByteBuffer. 398 * 399 * @param nextPayload type of payload that follows this payload. 400 * @param byteBuffer destination ByteBuffer that stores encoded payload. 401 */ 402 @Override encodeToByteBuffer(@ayloadType int nextPayload, ByteBuffer byteBuffer)403 protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { 404 encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer); 405 byteBuffer.put((byte) protocolId).put(spiSize).putShort((short) notifyType); 406 if (spiSize == SPI_LEN_IPSEC) { 407 byteBuffer.putInt(spi); 408 } 409 byteBuffer.put(notifyData); 410 } 411 412 /** 413 * Get entire payload length. 414 * 415 * @return entire payload length. 416 */ 417 @Override getPayloadLength()418 protected int getPayloadLength() { 419 return GENERIC_HEADER_LENGTH + NOTIFY_HEADER_LEN + spiSize + notifyData.length; 420 } 421 IkeNotifyPayload( @rotocolId int protocolId, byte spiSize, int spi, int notifyType, byte[] notifyData)422 protected IkeNotifyPayload( 423 @ProtocolId int protocolId, byte spiSize, int spi, int notifyType, byte[] notifyData) { 424 super(PAYLOAD_TYPE_NOTIFY, false); 425 this.protocolId = protocolId; 426 this.spiSize = spiSize; 427 this.spi = spi; 428 this.notifyType = notifyType; 429 this.notifyData = notifyData; 430 } 431 432 /** 433 * Construct IkeNotifyPayload concerning either an IKE SA, or Child SA that is going to be 434 * negotiated with associated notification data. 435 * 436 * @param notifyType the notify type concerning IKE SA 437 * @param notifytData status or error data transmitted. Values for this field are notify type 438 * specific. 439 */ IkeNotifyPayload(int notifyType, byte[] notifyData)440 public IkeNotifyPayload(int notifyType, byte[] notifyData) { 441 this(PROTOCOL_ID_UNSET, SPI_LEN_NOT_INCLUDED, SPI_NOT_INCLUDED, notifyType, notifyData); 442 try { 443 validateNotifyPayloadForIkeAndNewChild(); 444 } catch (InvalidSyntaxException e) { 445 throw new IllegalArgumentException(e); 446 } 447 } 448 449 /** 450 * Construct IkeNotifyPayload concerning either an IKE SA, or Child SA that is going to be 451 * negotiated without additional notification data. 452 * 453 * @param notifyType the notify type concerning IKE SA 454 */ IkeNotifyPayload(int notifyType)455 public IkeNotifyPayload(int notifyType) { 456 this(notifyType, new byte[0]); 457 } 458 459 /** 460 * Construct IkeNotifyPayload concerning existing Child SA 461 * 462 * @param notifyType the notify type concerning Child SA 463 * @param notifytData status or error data transmitted. Values for this field are notify type 464 * specific. 465 */ IkeNotifyPayload( @rotocolId int protocolId, int spi, int notifyType, byte[] notifyData)466 public IkeNotifyPayload( 467 @ProtocolId int protocolId, int spi, int notifyType, byte[] notifyData) { 468 this(protocolId, SPI_LEN_IPSEC, spi, notifyType, notifyData); 469 try { 470 validateNotifyPayloadForExistingChildSa(); 471 } catch (InvalidSyntaxException e) { 472 throw new IllegalArgumentException(e); 473 } 474 } 475 476 /** 477 * Indicates if this is an error notification payload. 478 * 479 * @return if this is an error notification payload. 480 */ isErrorNotify()481 public boolean isErrorNotify() { 482 return notifyType <= ERROR_NOTIFY_TYPE_MAX; 483 } 484 485 /** 486 * Indicates if this is an notification for a new Child SA negotiation. 487 * 488 * <p>This notification may provide additional configuration information for negotiating a new 489 * Child SA or is an error notification of the Child SA negotiation failure. 490 * 491 * @return if this is an notification for a new Child SA negotiation. 492 */ isNewChildSaNotify()493 public boolean isNewChildSaNotify() { 494 return VALID_NOTIFY_TYPES_FOR_NEW_CHILD_SA.contains(notifyType); 495 } 496 497 /** 498 * Validate error data and build IkeProtocolException for this error notification. 499 * 500 * @return the IkeProtocolException that represents this error. 501 * @throws InvalidSyntaxException if error data has invalid size. 502 */ validateAndBuildIkeException()503 public IkeProtocolException validateAndBuildIkeException() throws InvalidSyntaxException { 504 if (!isErrorNotify()) { 505 throw new IllegalArgumentException( 506 "Do not support building IkeException for a non-error notificaton. Notify" 507 + " type: " 508 + notifyType); 509 } 510 511 try { 512 switch (notifyType) { 513 case ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD: 514 return new UnsupportedCriticalPayloadException(notifyData); 515 case ERROR_TYPE_INVALID_IKE_SPI: 516 return new InvalidIkeSpiException(notifyData); 517 case ERROR_TYPE_INVALID_MAJOR_VERSION: 518 return new InvalidMajorVersionException(notifyData); 519 case ERROR_TYPE_INVALID_SYNTAX: 520 return new InvalidSyntaxException(notifyData); 521 case ERROR_TYPE_INVALID_MESSAGE_ID: 522 return new InvalidMessageIdException(notifyData); 523 case ERROR_TYPE_NO_PROPOSAL_CHOSEN: 524 return new NoValidProposalChosenException(notifyData); 525 case ERROR_TYPE_INVALID_KE_PAYLOAD: 526 return new InvalidKeException(notifyData); 527 case ERROR_TYPE_AUTHENTICATION_FAILED: 528 return new AuthenticationFailedException(notifyData); 529 case ERROR_TYPE_SINGLE_PAIR_REQUIRED: 530 return new SinglePairRequiredException(notifyData); 531 case ERROR_TYPE_NO_ADDITIONAL_SAS: 532 return new NoAdditionalSasException(notifyData); 533 case ERROR_TYPE_INTERNAL_ADDRESS_FAILURE: 534 return new InternalAddressFailureException(notifyData); 535 case ERROR_TYPE_FAILED_CP_REQUIRED: 536 return new FailedCpRequiredException(notifyData); 537 case ERROR_TYPE_TS_UNACCEPTABLE: 538 return new TsUnacceptableException(notifyData); 539 case ERROR_TYPE_INVALID_SELECTORS: 540 return new InvalidSelectorsException(spi, notifyData); 541 case ERROR_TYPE_TEMPORARY_FAILURE: 542 return new TemporaryFailureException(notifyData); 543 case ERROR_TYPE_CHILD_SA_NOT_FOUND: 544 return new ChildSaNotFoundException(spi, notifyData); 545 default: 546 return new UnrecognizedIkeProtocolException(notifyType, notifyData); 547 } 548 } catch (IllegalArgumentException e) { 549 // Notification data length is invalid. 550 throw new InvalidSyntaxException(e); 551 } 552 } 553 554 /** 555 * Return the payload type as a String. 556 * 557 * @return the payload type as a String. 558 */ 559 @Override getTypeString()560 public String getTypeString() { 561 String notifyTypeString = NOTIFY_TYPE_TO_STRING.get(notifyType); 562 563 if (notifyTypeString == null) { 564 return "Notify(" + notifyType + ")"; 565 } 566 return "Notify(" + notifyTypeString + ")"; 567 } 568 } 569