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 com.android.internal.net.eap; 18 19 import static com.android.internal.net.eap.EapAuthenticator.LOG; 20 import static com.android.internal.net.eap.statemachine.EapMethodStateMachine.MIN_EMSK_LEN_BYTES; 21 import static com.android.internal.net.eap.statemachine.EapMethodStateMachine.MIN_MSK_LEN_BYTES; 22 23 import android.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.net.eap.EapInfo; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.internal.net.eap.exceptions.InvalidEapResponseException; 30 import com.android.internal.net.eap.message.EapMessage; 31 32 /** 33 * EapResult represents the return type R for a process operation within the EapStateMachine. 34 */ 35 public abstract class EapResult { 36 /** 37 * EapSuccess represents a success response from the EapStateMachine. 38 * 39 * @see <a href="https://tools.ietf.org/html/rfc3748">RFC 3748, Extensible Authentication 40 * Protocol (EAP)</a> 41 */ 42 public static class EapSuccess extends EapResult { 43 private static final String TAG = EapSuccess.class.getSimpleName(); 44 45 public final byte[] msk; 46 public final byte[] emsk; 47 public final EapInfo mEapInfo; 48 EapSuccess(@onNull byte[] msk, @NonNull byte[] emsk)49 public EapSuccess(@NonNull byte[] msk, @NonNull byte[] emsk) { 50 this(msk, emsk, null); 51 } 52 EapSuccess(@onNull byte[] msk, @NonNull byte[] emsk, @Nullable EapInfo eapInfo)53 public EapSuccess(@NonNull byte[] msk, @NonNull byte[] emsk, @Nullable EapInfo eapInfo) { 54 if (msk == null || emsk == null) { 55 throw new IllegalArgumentException("msk and emsk must not be null"); 56 } 57 if (msk.length < MIN_MSK_LEN_BYTES || emsk.length < MIN_EMSK_LEN_BYTES) { 58 LOG.wtf( 59 TAG, 60 "MSK or EMSK does not meet the required key length: MSK=" 61 + LOG.pii(msk) 62 + " EMSK=" 63 + LOG.pii(emsk)); 64 } 65 this.msk = msk; 66 this.emsk = emsk; 67 this.mEapInfo = eapInfo; 68 } 69 70 @Nullable getEapInfo()71 public EapInfo getEapInfo() { 72 return mEapInfo; 73 } 74 } 75 76 /** 77 * EapFailure represents a failure response from the EapStateMachine. 78 * 79 * @see <a href="https://tools.ietf.org/html/rfc3748">RFC 3748, Extensible Authentication 80 * Protocol (EAP)</a> 81 */ 82 public static class EapFailure extends EapResult {} 83 84 /** 85 * EapResponse represents an outgoing message from the EapStateMachine. 86 * 87 * @see <a href="https://tools.ietf.org/html/rfc3748">RFC 3748, Extensible Authentication 88 * Protocol (EAP)</a> 89 */ 90 public static class EapResponse extends EapResult { 91 public final byte[] packet; 92 // holds bitmask representing multiple flags 93 public final int flagMask; 94 95 // flags to capture additional high level state information 96 @IntDef({RESPONSE_FLAG_EAP_AKA_SERVER_AUTHENTICATED}) 97 public @interface EapResponseFlag {} 98 99 public static final int RESPONSE_FLAG_EAP_AKA_SERVER_AUTHENTICATED = 0; 100 101 @VisibleForTesting EapResponse(byte[] packet, @EapResponseFlag int[] flagsToAdd)102 protected EapResponse(byte[] packet, @EapResponseFlag int[] flagsToAdd) { 103 this.packet = packet; 104 this.flagMask = createFlagMask(flagsToAdd); 105 } 106 107 /** 108 * Constructs and returns an EapResult for the given EapMessage. 109 * 110 * <p>If the given EapMessage is not of type EAP-Response, an EapError object will be 111 * returned. 112 * 113 * @param message the EapMessage to be encoded in the EapResponse instance. 114 * @param flagsToAdd list of EAP auth state related flags 115 * @return an EapResponse instance for the given message. If message.eapCode != {@link 116 * EapMessage#EAP_CODE_RESPONSE}, an EapError instance is returned. 117 */ getEapResponse( @onNull EapMessage message, @EapResponseFlag int[] flagsToAdd)118 public static EapResult getEapResponse( 119 @NonNull EapMessage message, @EapResponseFlag int[] flagsToAdd) { 120 if (message == null) { 121 throw new IllegalArgumentException("EapMessage should not be null"); 122 } else if (message.eapCode != EapMessage.EAP_CODE_RESPONSE) { 123 return new EapError(new InvalidEapResponseException( 124 "Cannot construct an EapResult from a non-EAP-Response message")); 125 } 126 127 return new EapResponse(message.encode(), flagsToAdd); 128 } 129 130 /** 131 * Constructs and returns an EapResult for the given EapMessage. 132 * 133 * <p>If the given EapMessage is not of type EAP-Response, an EapError object will be 134 * returned. 135 * 136 * @param message the EapMessage to be encoded in the EapResponse instance. 137 * @return an EapResponse instance for the given message. If message.eapCode != {@link 138 * EapMessage#EAP_CODE_RESPONSE}, an EapError instance is returned. 139 */ getEapResponse(@onNull EapMessage message)140 public static EapResult getEapResponse(@NonNull EapMessage message) { 141 return getEapResponse(message, null); 142 } 143 144 /** 145 * Utility that clients should use to check presence of a EapResponseFlag in the bitmask 146 * received in IEapCallback.onResponse() 147 * 148 * @param flagMask flags that client received in {@link IEapCallback.onResponse()} 149 * @param flagToCheck flag to test. See {@link EapResult.EapResponse.EapResponseFlag} 150 * @return returns true if flagToCheck is present 151 */ hasFlag(int flagMask, @EapResponseFlag int flagToCheck)152 public static boolean hasFlag(int flagMask, @EapResponseFlag int flagToCheck) { 153 return ((flagMask & (1 << flagToCheck)) != 0); 154 } 155 createFlagMask(@apResponseFlag int[] flagsToAdd)156 private static int createFlagMask(@EapResponseFlag int[] flagsToAdd) { 157 int flagMask = 0; 158 if ((flagsToAdd != null) && flagsToAdd.length > 0) { 159 for (int flag : flagsToAdd) { 160 flagMask |= (1 << flag); 161 } 162 } 163 return flagMask; 164 } 165 } 166 167 /** 168 * EapError represents an error that occurred in the EapStateMachine. 169 * 170 * @see <a href="https://tools.ietf.org/html/rfc3748">RFC 3748, Extensible Authentication 171 * Protocol (EAP)</a> 172 */ 173 public static class EapError extends EapResult { 174 public final Exception cause; 175 176 /** 177 * Constructs an EapError instance for the given cause. 178 * 179 * @param cause the Exception that caused the EapError to be returned from the 180 * EapStateMachine 181 */ EapError(Exception cause)182 public EapError(Exception cause) { 183 this.cause = cause; 184 } 185 } 186 } 187