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 17 package android.net.ipsec.ike; 18 19 import android.annotation.NonNull; 20 import android.annotation.SystemApi; 21 22 import com.android.internal.net.ipsec.ike.message.IkePayload; 23 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.DhGroupTransform; 24 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EncryptionTransform; 25 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.EsnTransform; 26 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.IntegrityTransform; 27 import com.android.internal.net.ipsec.ike.message.IkeSaPayload.Transform; 28 29 import java.util.Arrays; 30 import java.util.List; 31 32 /** 33 * ChildSaProposal represents a proposed configuration to negotiate a Child SA. 34 * 35 * <p>ChildSaProposal will contain cryptograhic algorithms and key generation materials for the 36 * negotiation of a Child SA. 37 * 38 * <p>User must provide at least one valid ChildSaProposal when they are creating a new Child SA. 39 * 40 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key Exchange 41 * Protocol Version 2 (IKEv2)</a> 42 * @hide 43 */ 44 @SystemApi 45 public final class ChildSaProposal extends SaProposal { 46 private final EsnTransform[] mEsns; 47 48 /** 49 * Construct an instance of ChildSaProposal. 50 * 51 * <p>This constructor is either called by ChildSaPayload for building an inbound proposal from 52 * a decoded packet, or called by the inner Builder to build an outbound proposal from user 53 * provided parameters 54 * 55 * @param encryptionAlgos encryption algorithms 56 * @param integrityAlgos integrity algorithms 57 * @param dhGroups Diffie-Hellman Groups 58 * @param esns ESN policies 59 * @hide 60 */ ChildSaProposal( EncryptionTransform[] encryptionAlgos, IntegrityTransform[] integrityAlgos, DhGroupTransform[] dhGroups, EsnTransform[] esns)61 public ChildSaProposal( 62 EncryptionTransform[] encryptionAlgos, 63 IntegrityTransform[] integrityAlgos, 64 DhGroupTransform[] dhGroups, 65 EsnTransform[] esns) { 66 super(IkePayload.PROTOCOL_ID_ESP, encryptionAlgos, integrityAlgos, dhGroups); 67 mEsns = esns; 68 } 69 70 /** 71 * Gets all ESN policies. 72 * 73 * @hide 74 */ getEsnTransforms()75 public EsnTransform[] getEsnTransforms() { 76 return mEsns; 77 } 78 79 /** 80 * Gets a copy of proposal without all proposed DH groups. 81 * 82 * <p>This is used to avoid negotiating DH Group for negotiating first Child SA. 83 * 84 * @hide 85 */ getCopyWithoutDhTransform()86 public ChildSaProposal getCopyWithoutDhTransform() { 87 return new ChildSaProposal( 88 getEncryptionTransforms(), 89 getIntegrityTransforms(), 90 new DhGroupTransform[0], 91 getEsnTransforms()); 92 } 93 94 /** @hide */ 95 @Override getAllTransforms()96 public Transform[] getAllTransforms() { 97 List<Transform> transformList = getAllTransformsAsList(); 98 transformList.addAll(Arrays.asList(mEsns)); 99 100 return transformList.toArray(new Transform[transformList.size()]); 101 } 102 103 /** @hide */ 104 @Override isNegotiatedFrom(SaProposal reqProposal)105 public boolean isNegotiatedFrom(SaProposal reqProposal) { 106 return super.isNegotiatedFrom(reqProposal) 107 && isTransformSelectedFrom(mEsns, ((ChildSaProposal) reqProposal).mEsns); 108 } 109 110 /** @hide */ isNegotiatedFromExceptDhGroup(SaProposal saProposal)111 public boolean isNegotiatedFromExceptDhGroup(SaProposal saProposal) { 112 return getProtocolId() == saProposal.getProtocolId() 113 && isTransformSelectedFrom( 114 getEncryptionTransforms(), saProposal.getEncryptionTransforms()) 115 && isTransformSelectedFrom( 116 getIntegrityTransforms(), saProposal.getIntegrityTransforms()) 117 && isTransformSelectedFrom(mEsns, ((ChildSaProposal) saProposal).mEsns); 118 } 119 120 /** @hide */ getCopyWithAdditionalDhTransform(int dhGroup)121 public ChildSaProposal getCopyWithAdditionalDhTransform(int dhGroup) { 122 return new ChildSaProposal( 123 getEncryptionTransforms(), 124 getIntegrityTransforms(), 125 new DhGroupTransform[] {new DhGroupTransform(dhGroup)}, 126 getEsnTransforms()); 127 } 128 129 /** 130 * This class is used to incrementally construct a ChildSaProposal. ChildSaProposal instances 131 * are immutable once built. 132 */ 133 public static final class Builder extends SaProposal.Builder { 134 // TODO: Support users to add algorithms from most preferred to least preferred. 135 136 /** 137 * Adds an encryption algorithm with a specific key length to the SA proposal being built. 138 * 139 * @param algorithm encryption algorithm to add to ChildSaProposal. 140 * @param keyLength key length of algorithm. For algorithms that have fixed key length (e.g. 141 * 3DES) only {@link SaProposal.KEY_LEN_UNUSED} is allowed. 142 * @return Builder of ChildSaProposal. 143 */ 144 @NonNull addEncryptionAlgorithm(@ncryptionAlgorithm int algorithm, int keyLength)145 public Builder addEncryptionAlgorithm(@EncryptionAlgorithm int algorithm, int keyLength) { 146 validateAndAddEncryptAlgo(algorithm, keyLength); 147 return this; 148 } 149 150 /** 151 * Adds an integrity algorithm to the SA proposal being built. 152 * 153 * @param algorithm integrity algorithm to add to ChildSaProposal. 154 * @return Builder of ChildSaProposal. 155 */ 156 @NonNull addIntegrityAlgorithm(@ntegrityAlgorithm int algorithm)157 public Builder addIntegrityAlgorithm(@IntegrityAlgorithm int algorithm) { 158 addIntegrityAlgo(algorithm); 159 return this; 160 } 161 162 /** 163 * Adds a Diffie-Hellman Group to the SA proposal being built. 164 * 165 * @param dhGroup to add to ChildSaProposal. 166 * @return Builder of ChildSaProposal. 167 */ 168 @NonNull addDhGroup(@hGroup int dhGroup)169 public Builder addDhGroup(@DhGroup int dhGroup) { 170 addDh(dhGroup); 171 return this; 172 } 173 buildIntegAlgosOrThrow()174 private IntegrityTransform[] buildIntegAlgosOrThrow() { 175 // When building Child SA Proposal with normal-mode ciphers, there is no contraint on 176 // integrity algorithm. When building Child SA Proposal with combined-mode ciphers, 177 // mProposedIntegrityAlgos must be either empty or only have INTEGRITY_ALGORITHM_NONE. 178 for (IntegrityTransform transform : mProposedIntegrityAlgos) { 179 if (transform.id != INTEGRITY_ALGORITHM_NONE && mHasAead) { 180 throw new IllegalArgumentException( 181 ERROR_TAG 182 + "Only INTEGRITY_ALGORITHM_NONE can be" 183 + " proposed with combined-mode ciphers in any proposal."); 184 } 185 } 186 187 return mProposedIntegrityAlgos.toArray( 188 new IntegrityTransform[mProposedIntegrityAlgos.size()]); 189 } 190 191 /** 192 * Validates and builds the ChildSaProposal. 193 * 194 * @return the validated ChildSaProposal. 195 */ 196 @NonNull build()197 public ChildSaProposal build() { 198 EncryptionTransform[] encryptionTransforms = buildEncryptAlgosOrThrow(); 199 IntegrityTransform[] integrityTransforms = buildIntegAlgosOrThrow(); 200 201 return new ChildSaProposal( 202 encryptionTransforms, 203 integrityTransforms, 204 mProposedDhGroups.toArray(new DhGroupTransform[mProposedDhGroups.size()]), 205 new EsnTransform[] {new EsnTransform()}); 206 } 207 } 208 } 209