1 /* 2 * Copyright (C) 2019 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 package android.net.ipsec.ike.exceptions; 17 18 import android.annotation.IntDef; 19 import android.annotation.Nullable; 20 import android.annotation.SystemApi; 21 22 import com.android.internal.net.ipsec.ike.message.IkeNotifyPayload; 23 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 import java.nio.ByteBuffer; 27 28 /** 29 * IkeProtocolException is an abstract class that represents the common information for all IKE 30 * protocol errors. 31 * 32 * <p>Error types are as defined by RFC 7296. 33 * 34 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.10.1">RFC 7296, Internet Key Exchange 35 * Protocol Version 2 (IKEv2)</a> 36 */ 37 public abstract class IkeProtocolException extends IkeException { 38 /** @hide */ 39 @Retention(RetentionPolicy.SOURCE) 40 @IntDef({ 41 ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD, 42 ERROR_TYPE_INVALID_IKE_SPI, 43 ERROR_TYPE_INVALID_MAJOR_VERSION, 44 ERROR_TYPE_INVALID_SYNTAX, 45 ERROR_TYPE_INVALID_MESSAGE_ID, 46 ERROR_TYPE_NO_PROPOSAL_CHOSEN, 47 ERROR_TYPE_INVALID_KE_PAYLOAD, 48 ERROR_TYPE_AUTHENTICATION_FAILED, 49 ERROR_TYPE_SINGLE_PAIR_REQUIRED, 50 ERROR_TYPE_NO_ADDITIONAL_SAS, 51 ERROR_TYPE_INTERNAL_ADDRESS_FAILURE, 52 ERROR_TYPE_FAILED_CP_REQUIRED, 53 ERROR_TYPE_TS_UNACCEPTABLE, 54 ERROR_TYPE_INVALID_SELECTORS, 55 ERROR_TYPE_TEMPORARY_FAILURE, 56 ERROR_TYPE_CHILD_SA_NOT_FOUND, 57 }) 58 public @interface ErrorType {} 59 60 /** Unsupported critical payload */ 61 public static final int ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1; 62 /** Unrecognized destination IKE SPI */ 63 public static final int ERROR_TYPE_INVALID_IKE_SPI = 4; 64 /** Invalid major version */ 65 public static final int ERROR_TYPE_INVALID_MAJOR_VERSION = 5; 66 /** Invalid syntax */ 67 public static final int ERROR_TYPE_INVALID_SYNTAX = 7; 68 /** Invalid message ID */ 69 public static final int ERROR_TYPE_INVALID_MESSAGE_ID = 9; 70 /** No SA Proposal Chosen is acceptable */ 71 public static final int ERROR_TYPE_NO_PROPOSAL_CHOSEN = 14; 72 /** Invalid Key Exchaneg Payload */ 73 public static final int ERROR_TYPE_INVALID_KE_PAYLOAD = 17; 74 /** IKE authentication failed */ 75 public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24; 76 /** Only Traffic Selectors specifying a single pair of addresses are acceptable */ 77 public static final int ERROR_TYPE_SINGLE_PAIR_REQUIRED = 34; 78 /** No additional SAa are acceptable */ 79 public static final int ERROR_TYPE_NO_ADDITIONAL_SAS = 35; 80 /** No internal addresses can be assigned */ 81 public static final int ERROR_TYPE_INTERNAL_ADDRESS_FAILURE = 36; 82 /** Configuration Payload required but not found in IKE setup */ 83 public static final int ERROR_TYPE_FAILED_CP_REQUIRED = 37; 84 /** No Traffic Selectors are acceptable */ 85 public static final int ERROR_TYPE_TS_UNACCEPTABLE = 38; 86 /** 87 * An IPsec Packet was found to have mismatched Traffic Selectors of the IPsec SA on which it 88 * was delivered 89 */ 90 public static final int ERROR_TYPE_INVALID_SELECTORS = 39; 91 /** Temporary failure */ 92 public static final int ERROR_TYPE_TEMPORARY_FAILURE = 43; 93 /** Child SA in the received packet does not exist */ 94 public static final int ERROR_TYPE_CHILD_SA_NOT_FOUND = 44; 95 96 /** @hide */ 97 public static final byte[] ERROR_DATA_NOT_INCLUDED = new byte[0]; 98 99 private static final int INTEGER_BYTE_SIZE = 4; 100 101 @ErrorType private final int mErrorType; 102 private final byte[] mErrorData; 103 104 /** @hide */ IkeProtocolException(@rrorType int code)105 protected IkeProtocolException(@ErrorType int code) { 106 super(); 107 mErrorType = code; 108 mErrorData = ERROR_DATA_NOT_INCLUDED; 109 } 110 111 /** @hide */ IkeProtocolException(@rrorType int code, String message)112 protected IkeProtocolException(@ErrorType int code, String message) { 113 super(message); 114 mErrorType = code; 115 mErrorData = ERROR_DATA_NOT_INCLUDED; 116 } 117 118 /** @hide */ IkeProtocolException(@rrorType int code, Throwable cause)119 protected IkeProtocolException(@ErrorType int code, Throwable cause) { 120 super(cause); 121 mErrorType = code; 122 mErrorData = ERROR_DATA_NOT_INCLUDED; 123 } 124 125 /** @hide */ IkeProtocolException(@rrorType int code, String message, Throwable cause)126 protected IkeProtocolException(@ErrorType int code, String message, Throwable cause) { 127 super(message, cause); 128 mErrorType = code; 129 mErrorData = ERROR_DATA_NOT_INCLUDED; 130 } 131 132 /** 133 * Construct an instance from a notify Payload. 134 * 135 * @hide 136 */ IkeProtocolException(@rrorType int code, byte[] notifyData)137 protected IkeProtocolException(@ErrorType int code, byte[] notifyData) { 138 super(); 139 140 if (!isValidDataLength(notifyData.length)) { 141 throw new IllegalArgumentException( 142 "Invalid error data for error type: " 143 + code 144 + " Received error data size: " 145 + notifyData.length); 146 } 147 148 mErrorType = code; 149 mErrorData = notifyData.clone(); 150 } 151 152 /** @hide */ isValidDataLength(int dataLen)153 protected abstract boolean isValidDataLength(int dataLen); 154 155 /** @hide */ integerToByteArray(int integer, int arraySize)156 protected static byte[] integerToByteArray(int integer, int arraySize) { 157 if (arraySize > INTEGER_BYTE_SIZE) { 158 throw new IllegalArgumentException( 159 "Cannot convert integer to a byte array of length: " + arraySize); 160 } 161 162 ByteBuffer dataBuffer = ByteBuffer.allocate(INTEGER_BYTE_SIZE); 163 dataBuffer.putInt(integer); 164 dataBuffer.rewind(); 165 166 byte[] zeroPad = new byte[INTEGER_BYTE_SIZE - arraySize]; 167 byte[] byteData = new byte[arraySize]; 168 dataBuffer.get(zeroPad).get(byteData); 169 170 return byteData; 171 } 172 173 /** @hide */ byteArrayToInteger(byte[] byteArray)174 protected static int byteArrayToInteger(byte[] byteArray) { 175 if (byteArray == null || byteArray.length > INTEGER_BYTE_SIZE) { 176 throw new IllegalArgumentException("Cannot convert the byte array to integer"); 177 } 178 179 ByteBuffer dataBuffer = ByteBuffer.allocate(INTEGER_BYTE_SIZE); 180 byte[] zeroPad = new byte[INTEGER_BYTE_SIZE - byteArray.length]; 181 dataBuffer.put(zeroPad).put(byteArray); 182 dataBuffer.rewind(); 183 184 return dataBuffer.getInt(); 185 } 186 187 /** 188 * Returns the IKE standard protocol error type of this {@link IkeProtocolException} instance. 189 * 190 * @return the IKE standard protocol error type. 191 */ 192 @ErrorType getErrorType()193 public int getErrorType() { 194 return mErrorType; 195 } 196 197 /** 198 * Returns the included error data of this {@link IkeProtocolException} instance. 199 * 200 * <p>Note that only few error types will go with an error data. This data has different meaning 201 * with different error types. Callers should first check if an error data is included before 202 * they call this method. 203 * 204 * @return the included error data in byte array, or {@code null} if no error data is available. 205 * @hide 206 */ 207 @SystemApi 208 @Nullable getErrorData()209 public byte[] getErrorData() { 210 return mErrorData; 211 } 212 213 /** 214 * Build an IKE Notification Payload for this {@link IkeProtocolException} instance. 215 * 216 * @return the notification payload. 217 * @hide 218 */ buildNotifyPayload()219 public IkeNotifyPayload buildNotifyPayload() { 220 return new IkeNotifyPayload(mErrorType, mErrorData); 221 } 222 } 223