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