• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.statemachine;
18 
19 import static com.android.internal.net.eap.EapAuthenticator.LOG;
20 import static com.android.internal.net.eap.message.EapData.EAP_NOTIFICATION;
21 import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_FAILURE;
22 import static com.android.internal.net.eap.message.EapMessage.EAP_CODE_SUCCESS;
23 
24 import android.annotation.Nullable;
25 import android.net.eap.EapSessionConfig.EapMethodConfig.EapMethod;
26 
27 import com.android.internal.annotations.VisibleForTesting;
28 import com.android.internal.net.eap.EapResult;
29 import com.android.internal.net.eap.EapResult.EapError;
30 import com.android.internal.net.eap.EapResult.EapFailure;
31 import com.android.internal.net.eap.exceptions.EapInvalidRequestException;
32 import com.android.internal.net.eap.message.EapMessage;
33 import com.android.internal.net.utils.SimpleStateMachine;
34 
35 /**
36  * EapMethodStateMachine is an abstract class representing a state machine for EAP Method
37  * implementations.
38  */
39 public abstract class EapMethodStateMachine extends SimpleStateMachine<EapMessage, EapResult> {
40     // Minimum key lengths specified in RFC 3748#1.2
41     public static final int MIN_MSK_LEN_BYTES = 64;
42     public static final int MIN_EMSK_LEN_BYTES = 64;
43 
44     /*
45      * Used for transitioning to a state where EAP-Failure messages are expected next. This
46      * allows all EAP methods to easily transition to a pre-failure state in the event of errors,
47      * failed authentication, etc.
48      */
49     protected boolean mIsExpectingEapFailure = false;
50 
51     /**
52      * Returns the EAP Method type for this EapMethodStateMachine implementation.
53      *
54      * @return the IANA value for the EAP Method represented by this EapMethodStateMachine
55      */
56     @EapMethod
getEapMethod()57     abstract int getEapMethod();
58 
59     @VisibleForTesting
getState()60     protected SimpleState getState() {
61         return mState;
62     }
63 
64     @VisibleForTesting
transitionTo(EapMethodState newState)65     protected void transitionTo(EapMethodState newState) {
66         LOG.d(
67                 this.getClass().getSimpleName(),
68                 "Transitioning from " + mState.getClass().getSimpleName()
69                         + " to " + newState.getClass().getSimpleName());
70         super.transitionTo(newState);
71     }
72 
handleEapNotification(String tag, EapMessage message)73     abstract EapResult handleEapNotification(String tag, EapMessage message);
74 
75     protected abstract class EapMethodState extends SimpleState {
76         /**
77          * Handles premature EAP-Success and EAP-Failure messages, as well as EAP-Notification
78          * messages.
79          *
80          * @param tag the String logging tag to be used while handing message
81          * @param message the EapMessage to be checked for early Success/Failure/Notification
82          *                messages
83          * @return the EapResult generated from handling the give EapMessage, or null if the message
84          * Type matches that of the current EAP method
85          */
86         @Nullable
handleEapSuccessFailureNotification(String tag, EapMessage message)87         EapResult handleEapSuccessFailureNotification(String tag, EapMessage message) {
88             if (message.eapCode == EAP_CODE_SUCCESS) {
89                 // EAP-SUCCESS is required to be the last EAP message sent during the EAP protocol,
90                 // so receiving a premature SUCCESS message is an unrecoverable error.
91                 return new EapError(
92                         new EapInvalidRequestException(
93                                 "Received an EAP-Success in the " + tag));
94             } else if (message.eapCode == EAP_CODE_FAILURE) {
95                 transitionTo(new FinalState());
96                 return new EapFailure();
97             } else if (message.eapData.eapType == EAP_NOTIFICATION) {
98                 return handleEapNotification(tag, message);
99             } else if (mIsExpectingEapFailure) {
100                 // Expecting EAP-Failure message. Didn't receive EAP-Failure or EAP-Notification,
101                 // so log and return EAP-Error.
102                 LOG.e(tag, "Expecting EAP-Failure. Received non-Failure/Notification message");
103                 return new EapError(
104                         new EapInvalidRequestException(
105                                 "Expecting EAP-Failure. Received received "
106                                         + message.eapData.eapType));
107             } else if (message.eapData.eapType != getEapMethod()) {
108                 return new EapError(new EapInvalidRequestException(
109                         "Expected EAP Type " + getEapMethod()
110                                 + ", received " + message.eapData.eapType));
111             }
112 
113             return null;
114         }
115     }
116 
117     protected class FinalState extends EapMethodState {
118         @Override
process(EapMessage msg)119         public EapResult process(EapMessage msg) {
120             return new EapError(
121                     new IllegalStateException("Attempting to process from a FinalState"));
122         }
123     }
124 }
125