aboutsummaryrefslogtreecommitdiff
path: root/src/java/com/android/ike/ikev2/IkeSessionOptions.java
blob: 964e89e98a0162b06a84486dc7a8b7f699e6addb (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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
/*
 * 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;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.net.IpSecManager.UdpEncapsulationSocket;

import com.android.ike.eap.EapSessionConfig;
import com.android.ike.ikev2.message.IkePayload;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.LinkedList;
import java.util.List;

/**
 * IkeSessionOptions contains all user provided configurations for negotiating an IKE SA.
 *
 * <p>TODO: Make this doc more user-friendly.
 */
public final class IkeSessionOptions {
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({IKE_AUTH_METHOD_PSK, IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, IKE_AUTH_METHOD_EAP})
    public @interface IkeAuthMethod {}

    // Package private constants to describe user configured authentication methods.
    static final int IKE_AUTH_METHOD_PSK = 1;
    static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2;
    static final int IKE_AUTH_METHOD_EAP = 3;

    private final InetAddress mServerAddress;
    private final UdpEncapsulationSocket mUdpEncapSocket;
    private final IkeSaProposal[] mSaProposals;

    private final IkeIdentification mLocalIdentification;
    private final IkeIdentification mRemoteIdentification;

    private final IkeAuthConfig mLocalAuthConfig;
    private final IkeAuthConfig mRemoteAuthConfig;

    private final boolean mIsIkeFragmentationSupported;

    private IkeSessionOptions(
            InetAddress serverAddress,
            UdpEncapsulationSocket udpEncapsulationSocket,
            IkeSaProposal[] proposals,
            IkeIdentification localIdentification,
            IkeIdentification remoteIdentification,
            IkeAuthConfig localAuthConfig,
            IkeAuthConfig remoteAuthConfig,
            boolean isIkeFragmentationSupported) {
        mServerAddress = serverAddress;
        mUdpEncapSocket = udpEncapsulationSocket;
        mSaProposals = proposals;

        mLocalIdentification = localIdentification;
        mRemoteIdentification = remoteIdentification;

        mLocalAuthConfig = localAuthConfig;
        mRemoteAuthConfig = remoteAuthConfig;

        mIsIkeFragmentationSupported = isIkeFragmentationSupported;
    }

    /** Package private */
    InetAddress getServerAddress() {
        return mServerAddress;
    }
    /** Package private */
    UdpEncapsulationSocket getUdpEncapsulationSocket() {
        return mUdpEncapSocket;
    }
    /** Package private */
    IkeSaProposal[] getSaProposals() {
        return mSaProposals;
    }
    /** Package private */
    IkeIdentification getLocalIdentification() {
        return mLocalIdentification;
    }
    /** Package private */
    IkeIdentification getRemoteIdentification() {
        return mRemoteIdentification;
    }
    /** Package private */
    IkeAuthConfig getLocalAuthConfig() {
        return mLocalAuthConfig;
    }
    /** Package private */
    IkeAuthConfig getRemoteAuthConfig() {
        return mRemoteAuthConfig;
    }
    /** Package private */
    boolean isIkeFragmentationSupported() {
        return mIsIkeFragmentationSupported;
    }
    /**
     * Package private class that contains common information of an IKEv2 authentication
     * configuration.
     */
    abstract static class IkeAuthConfig {
        @IkeAuthMethod final int mAuthMethod;

        protected IkeAuthConfig(@IkeAuthMethod int authMethod) {
            mAuthMethod = authMethod;
        }
    }

    /**
     * Package private class that contains configuration to do IKEv2 pre-shared-key-based
     * authentication of local or remote side.
     */
    static class IkeAuthPskConfig extends IkeAuthConfig {
        final byte[] mPsk;

        private IkeAuthPskConfig(byte[] psk) {
            super(IKE_AUTH_METHOD_PSK);
            mPsk = psk;
        }
    }

    /**
     * Package private class that contains configuration to do IKEv2 public-key-based authentication
     * of the remote side.
     */
    static class IkeAuthDigitalSignRemoteConfig extends IkeAuthConfig {
        final TrustAnchor mTrustAnchor;

        private IkeAuthDigitalSignRemoteConfig(TrustAnchor trustAnchor) {
            super(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE);
            mTrustAnchor = trustAnchor;
        }
    }

    // TODO: Create IkeAuthDigitalSignLocalConfig to store signature hash algorithm and
    // certificates to do authentication of local side to the remote.

    /**
     * Package private class that contains configuration to do EAP authentication of the local side.
     *
     * <p>EAP MUST be used with IKEv2 public-key-based authentication of the responder to the
     * initiator. Currently IKE library does not support the IKEv2 protocol extension(RFC 5998)
     * which allows EAP methods that provide mutual authentication and key agreement to be used to
     * provide extensible responder authentication for IKEv2 based on methods other than public key
     * signatures.
     *
     * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998, An Extension for EAP-Only
     *     Authentication in IKEv2</a>
     */
    static class IkeAuthEapConfig extends IkeAuthConfig {
        final EapSessionConfig mEapConfig;

        private IkeAuthEapConfig(EapSessionConfig eapConfig) {
            super(IKE_AUTH_METHOD_EAP);

            mEapConfig = eapConfig;
        }
    }

    /** This class can be used to incrementally construct a IkeSessionOptions. */
    public static final class Builder {
        private final InetAddress mServerAddress;
        private final UdpEncapsulationSocket mUdpEncapSocket;
        private final List<IkeSaProposal> mSaProposalList = new LinkedList<>();

        private IkeIdentification mLocalIdentification;
        private IkeIdentification mRemoteIdentification;

        private IkeAuthConfig mLocalAuthConfig;
        private IkeAuthConfig mRemoteAuthConfig;

        private boolean mIsIkeFragmentationSupported = false;

        /**
         * Returns a new Builder for an IkeSessionOptions.
         *
         * @param serverAddress IP address of remote IKE server.
         * @param udpEncapsulationSocket {@link IpSecManager.UdpEncapsulationSocket} for sending and
         *     receiving IKE message.
         * @return Builder for an IkeSessionOptions.
         */
        public Builder(InetAddress serverAddress, UdpEncapsulationSocket udpEncapsulationSocket) {
            mServerAddress = serverAddress;
            mUdpEncapSocket = udpEncapsulationSocket;
        }

        /**
         * Sets local IKE identification.
         *
         * @param identification the local IKE identification.
         * @return Builder this, to facilitate chaining.
         */
        public Builder setLocalIdentification(IkeIdentification identification) {
            mLocalIdentification = identification;
            return this;
        }

        /**
         * Sets remote IKE identification.
         *
         * @param identification the remote IKE identification.
         * @return Builder this, to facilitate chaining.
         */
        public Builder setRemoteIdentification(IkeIdentification identification) {
            mRemoteIdentification = identification;
            return this;
        }

        /**
         * Adds an IKE SA proposal to IkeSessionOptions being built.
         *
         * @param proposal IKE SA proposal.
         * @return Builder this, to facilitate chaining.
         * @throws IllegalArgumentException if input proposal is not IKE SA proposal.
         */
        public Builder addSaProposal(IkeSaProposal proposal) {
            if (proposal.getProtocolId() != IkePayload.PROTOCOL_ID_IKE) {
                throw new IllegalArgumentException(
                        "Expected IKE SA Proposal but received Child SA proposal");
            }
            mSaProposalList.add(proposal);
            return this;
        }

        /**
         * Uses pre-shared key to do IKE authentication.
         *
         * <p>Both client and server MUST be authenticated using the provided shared key. IKE
         * authentication will fail if the remote peer tries to use other authentication methods.
         *
         * <p>Users MUST declare only one authentication method. Calling this function will override
         * the previously set authentication configuration.
         *
         * @param sharedKey the shared key.
         * @return Builder this, to facilitate chaining.
         */
        public Builder setAuthPsk(@NonNull byte[] sharedKey) {
            mLocalAuthConfig = new IkeAuthPskConfig(sharedKey);
            mRemoteAuthConfig = new IkeAuthPskConfig(sharedKey);
            return this;
        }

        /**
         * Uses EAP to do IKE authentication.
         *
         * <p>EAP are typically used to authenticate the IKE client to the server. It MUST be used
         * in conjunction with a public-key-signature-based authentication of the server to the
         * client.
         *
         * <p>Users MUST declare only one authentication method. Calling this function will override
         * the previously set authentication configuration.
         *
         * <p>TODO: Add input to take EAP configucations.
         *
         * <p>TODO: Investigate if we need to support the name constraints extension.
         *
         * @see <a href="https://tools.ietf.org/html/rfc5280">RFC 5280, Internet X.509 Public Key
         *     Infrastructure Certificate and Certificate Revocation List (CRL) Profile</a>
         * @param caCert the CA certificate for validating the received server certificate(s).
         * @return Builder this, to facilitate chaining.
         */
        public Builder setAuthEap(
                @NonNull X509Certificate caCert, @NonNull EapSessionConfig eapConfig) {
            mLocalAuthConfig = new IkeAuthEapConfig(eapConfig);

            // The name constraints extension, defined in RFC 5280, indicates a name space within
            // which all subject names in subsequent certificates in a certification path MUST be
            // located.
            mRemoteAuthConfig =
                    new IkeAuthDigitalSignRemoteConfig(
                            new TrustAnchor(caCert, null /*nameConstraints*/));
            return this;
        }

        // TODO: Add methods to set authentication method to public key signature and EAP.

        /**
         * Validates, builds and returns the IkeSessionOptions
         *
         * @return IkeSessionOptions the validated IkeSessionOptions
         * @throws IllegalArgumentException if no IKE SA proposal is provided
         */
        public IkeSessionOptions build() {
            if (mSaProposalList.isEmpty()) {
                throw new IllegalArgumentException("IKE SA proposal not found");
            }
            if (mLocalIdentification == null
                    || mRemoteIdentification == null
                    || mLocalAuthConfig == null
                    || mRemoteAuthConfig == null) {
                throw new IllegalArgumentException(
                        "IKE identification or IKE authentication method is not set.");
            }

            return new IkeSessionOptions(
                    mServerAddress,
                    mUdpEncapSocket,
                    mSaProposalList.toArray(new IkeSaProposal[mSaProposalList.size()]),
                    mLocalIdentification,
                    mRemoteIdentification,
                    mLocalAuthConfig,
                    mRemoteAuthConfig,
                    mIsIkeFragmentationSupported);
        }

        // TODO: add methods for supporting IKE fragmentation.
    }
}