aboutsummaryrefslogtreecommitdiff
path: root/src/java/com/android/ike/ikev2/exceptions/IkeProtocolException.java
blob: 0ff47d6d3f44e8ed35fb05bfc0ea08b5d502b9c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.ike.ikev2.exceptions;

import android.annotation.IntDef;

import com.android.ike.ikev2.message.IkeNotifyPayload;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;

/**
 * IkeProtocolException is an abstract class that represents the common information for all IKE
 * protocol errors.
 *
 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.10.1">RFC 7296, Internet Key Exchange
 *     Protocol Version 2 (IKEv2)</a>
 */
public abstract class IkeProtocolException extends IkeException {
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({
        ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD,
        ERROR_TYPE_INVALID_IKE_SPI,
        ERROR_TYPE_INVALID_MAJOR_VERSION,
        ERROR_TYPE_INVALID_SYNTAX,
        ERROR_TYPE_INVALID_MESSAGE_ID,
        ERROR_TYPE_NO_PROPOSAL_CHOSEN,
        ERROR_TYPE_INVALID_KE_PAYLOAD,
        ERROR_TYPE_AUTHENTICATION_FAILED,
        ERROR_TYPE_SINGLE_PAIR_REQUIRED,
        ERROR_TYPE_NO_ADDITIONAL_SAS,
        ERROR_TYPE_INTERNAL_ADDRESS_FAILURE,
        ERROR_TYPE_FAILED_CP_REQUIRED,
        ERROR_TYPE_TS_UNACCEPTABLE,
        ERROR_TYPE_INVALID_SELECTORS,
        ERROR_TYPE_TEMPORARY_FAILURE,
        ERROR_TYPE_CHILD_SA_NOT_FOUND,
    })
    public @interface ErrorType {}

    public static final int ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1;
    public static final int ERROR_TYPE_INVALID_IKE_SPI = 4;
    public static final int ERROR_TYPE_INVALID_MAJOR_VERSION = 5;
    public static final int ERROR_TYPE_INVALID_SYNTAX = 7;
    public static final int ERROR_TYPE_INVALID_MESSAGE_ID = 9;
    public static final int ERROR_TYPE_NO_PROPOSAL_CHOSEN = 14;
    public static final int ERROR_TYPE_INVALID_KE_PAYLOAD = 17;
    public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24;
    public static final int ERROR_TYPE_SINGLE_PAIR_REQUIRED = 34;
    public static final int ERROR_TYPE_NO_ADDITIONAL_SAS = 35;
    public static final int ERROR_TYPE_INTERNAL_ADDRESS_FAILURE = 36;
    public static final int ERROR_TYPE_FAILED_CP_REQUIRED = 37;
    public static final int ERROR_TYPE_TS_UNACCEPTABLE = 38;
    public static final int ERROR_TYPE_INVALID_SELECTORS = 39;
    public static final int ERROR_TYPE_TEMPORARY_FAILURE = 43;
    public static final int ERROR_TYPE_CHILD_SA_NOT_FOUND = 44;

    public static final byte[] ERROR_DATA_NOT_INCLUDED = new byte[0];

    private static final int INTEGER_BYTE_SIZE = 4;

    @ErrorType private final int mErrorType;
    private final byte[] mErrorData;

    protected IkeProtocolException(@ErrorType int code) {
        super();
        mErrorType = code;
        mErrorData = ERROR_DATA_NOT_INCLUDED;
    }

    protected IkeProtocolException(@ErrorType int code, String message) {
        super(message);
        mErrorType = code;
        mErrorData = ERROR_DATA_NOT_INCLUDED;
    }

    protected IkeProtocolException(@ErrorType int code, Throwable cause) {
        super(cause);
        mErrorType = code;
        mErrorData = ERROR_DATA_NOT_INCLUDED;
    }

    protected IkeProtocolException(@ErrorType int code, String message, Throwable cause) {
        super(message, cause);
        mErrorType = code;
        mErrorData = ERROR_DATA_NOT_INCLUDED;
    }

    // Construct an instance from a notify Payload.
    protected IkeProtocolException(@ErrorType int code, byte[] notifyData) {
        super();

        if (!isValidDataLength(notifyData.length)) {
            throw new IllegalArgumentException(
                    "Invalid error data for error type: "
                            + code
                            + " Received error data size: "
                            + notifyData.length);
        }

        mErrorType = code;
        mErrorData = notifyData;
    }

    protected abstract boolean isValidDataLength(int dataLen);

    protected static byte[] integerToByteArray(int integer, int arraySize) {
        if (arraySize > INTEGER_BYTE_SIZE) {
            throw new IllegalArgumentException(
                    "Cannot convert integer to a byte array of length: " + arraySize);
        }

        ByteBuffer dataBuffer = ByteBuffer.allocate(INTEGER_BYTE_SIZE);
        dataBuffer.putInt(integer);
        dataBuffer.rewind();

        byte[] zeroPad = new byte[INTEGER_BYTE_SIZE - arraySize];
        byte[] byteData = new byte[arraySize];
        dataBuffer.get(zeroPad).get(byteData);

        return byteData;
    }

    protected static int byteArrayToInteger(byte[] byteArray) {
        if (byteArray == null || byteArray.length > INTEGER_BYTE_SIZE) {
            throw new IllegalArgumentException("Cannot convert the byte array to integer");
        }

        ByteBuffer dataBuffer = ByteBuffer.allocate(INTEGER_BYTE_SIZE);
        byte[] zeroPad = new byte[INTEGER_BYTE_SIZE - byteArray.length];
        dataBuffer.put(zeroPad).put(byteArray);
        dataBuffer.rewind();

        return dataBuffer.getInt();
    }

    /**
     * Returns the IKE standard protocol error type of this {@link IkeProtocolException} instance.
     *
     * @return the IKE standard protocol error type.
     */
    @ErrorType
    public int getErrorType() {
        return mErrorType;
    }

    /**
     * Returns the included error data of this {@link IkeProtocolException} instance.
     *
     * <p>Note that only few error types will go with an error data. This data has different meaning
     * with different error types. Users should first check if an error data is included before they
     * call this method.
     *
     * @return the included error data in byte array.
     */
    public byte[] getErrorData() {
        return mErrorData;
    }

    /**
     * Build an IKE Notification Payload for this {@link IkeProtocolException} instance.
     *
     * @return the notification payload.
     */
    public IkeNotifyPayload buildNotifyPayload() {
        return new IkeNotifyPayload(mErrorType, mErrorData);
    }
}