aboutsummaryrefslogtreecommitdiff
path: root/src/java/android/net/ipsec/ike/ChildSaProposal.java
blob: c8851a7187b3f117085587f1e0a60dea7015177b (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
/*
 * 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 android.net.ipsec.ike;

import com.android.internal.net.ipsec.ike.message.IkePayload;
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform;
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform;
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EsnTransform;
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform;
import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform;

import java.util.Arrays;
import java.util.List;

/**
 * ChildSaProposal represents a user configured set contains cryptograhic algorithms and key
 * generating materials for negotiating an Child SA.
 *
 * <p>User must provide at least a valid ChildSaProposal when they are creating a new Child SA.
 *
 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key Exchange
 *     Protocol Version 2 (IKEv2)</a>
 */
public final class ChildSaProposal extends SaProposal {
    private final EsnTransform[] mEsns;

    /**
     * Construct an instance of ChildSaProposal.
     *
     * <p>This constructor is either called by ChildSaPayload for building an inbound proposal from
     * a decoded packet, or called by the inner Builder to build an outbound proposal from user
     * provided parameters
     *
     * @param encryptionAlgos encryption algorithms
     * @param integrityAlgos integrity algorithms
     * @param dhGroups Diffie-Hellman Groups
     * @param esns ESN policies
     */
    public ChildSaProposal(
            EncryptionTransform[] encryptionAlgos,
            IntegrityTransform[] integrityAlgos,
            DhGroupTransform[] dhGroups,
            EsnTransform[] esns) {
        super(IkePayload.PROTOCOL_ID_ESP, encryptionAlgos, integrityAlgos, dhGroups);
        mEsns = esns;
    }

    /** Gets all ESN policies. */
    public EsnTransform[] getEsnTransforms() {
        return mEsns;
    }

    /**
     * Gets a copy of proposal without all proposed DH groups.
     *
     * <p>This is used to avoid negotiating DH Group for negotiating first Child SA.
     */
    public ChildSaProposal getCopyWithoutDhTransform() {
        return new ChildSaProposal(
                getEncryptionTransforms(),
                getIntegrityTransforms(),
                new DhGroupTransform[0],
                getEsnTransforms());
    }

    @Override
    public Transform[] getAllTransforms() {
        List<Transform> transformList = getAllTransformsAsList();
        transformList.addAll(Arrays.asList(mEsns));

        return transformList.toArray(new Transform[transformList.size()]);
    }

    @Override
    public boolean isNegotiatedFrom(SaProposal reqProposal) {
        return super.isNegotiatedFrom(reqProposal)
                && isTransformSelectedFrom(mEsns, ((ChildSaProposal) reqProposal).mEsns);
    }

    /**
     * This class can be used to incrementally construct a ChildSaProposal. ChildSaProposal
     * instances are immutable once built.
     *
     * <p>TODO: Support users to add algorithms from most preferred to least preferred.
     */
    public static final class Builder extends SaProposal.Builder {
        /**
         * Adds an encryption algorithm with specific key length to SA proposal being built.
         *
         * @param algorithm encryption algorithm to add to ChildSaProposal.
         * @param keyLength key length of algorithm. For algorithm that has fixed key length (e.g.
         *     3DES) only KEY_LEN_UNUSED is allowed.
         * @return Builder of ChildSaProposal.
         * @throws IllegalArgumentException if AEAD and non-combined mode algorithms are mixed.
         */
        public Builder addEncryptionAlgorithm(@EncryptionAlgorithm int algorithm, int keyLength) {
            validateAndAddEncryptAlgo(algorithm, keyLength);
            return this;
        }

        /**
         * Adds an integrity algorithm to SA proposal being built.
         *
         * @param algorithm integrity algorithm to add to ChildSaProposal.
         * @return Builder of ChildSaProposal.
         */
        public Builder addIntegrityAlgorithm(@IntegrityAlgorithm int algorithm) {
            addIntegrityAlgo(algorithm);
            return this;
        }

        /**
         * Adds a Diffie-Hellman Group to SA proposal being built.
         *
         * @param dhGroup to add to ChildSaProposal.
         * @return Builder of ChildSaProposal.
         */
        public Builder addDhGroup(@DhGroup int dhGroup) {
            addDh(dhGroup);
            return this;
        }

        private IntegrityTransform[] buildIntegAlgosOrThrow() {
            // When building Child SA Proposal with normal-mode ciphers, there is no contraint on
            // integrity algorithm. When building Child SA Proposal with combined-mode ciphers,
            // mProposedIntegrityAlgos must be either empty or only have INTEGRITY_ALGORITHM_NONE.
            for (IntegrityTransform transform : mProposedIntegrityAlgos) {
                if (transform.id != INTEGRITY_ALGORITHM_NONE && mHasAead) {
                    throw new IllegalArgumentException(
                            ERROR_TAG
                                    + "Only INTEGRITY_ALGORITHM_NONE can be"
                                    + " proposed with combined-mode ciphers in any proposal.");
                }
            }

            return mProposedIntegrityAlgos.toArray(
                    new IntegrityTransform[mProposedIntegrityAlgos.size()]);
        }

        /**
         * Validates, builds and returns the ChildSaProposal
         *
         * @return the validated ChildSaProposal.
         * @throws IllegalArgumentException if ChildSaProposal is invalid.
         */
        public ChildSaProposal build() {
            EncryptionTransform[] encryptionTransforms = buildEncryptAlgosOrThrow();
            IntegrityTransform[] integrityTransforms = buildIntegAlgosOrThrow();

            return new ChildSaProposal(
                    encryptionTransforms,
                    integrityTransforms,
                    mProposedDhGroups.toArray(new DhGroupTransform[mProposedDhGroups.size()]),
                    new EsnTransform[] {new EsnTransform()});
        }
    }
}