1ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpackage com.android.anqp.eap;
2ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
3ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.anqp.Constants;
4ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.AuthMatch;
5ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
6ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.net.ProtocolException;
7ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.nio.ByteBuffer;
8ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.nio.ByteOrder;
9ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Collections;
10ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.EnumMap;
11ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashMap;
12ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashSet;
13ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Map;
14ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Set;
15ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
16ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist/**
17ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * An EAP Method, part of the NAI Realm ANQP element, specified in
18ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * IEEE802.11-2012 section 8.4.4.10, figure 8-420
19ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */
20ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpublic class EAPMethod {
21ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private final EAP.EAPMethodID mEAPMethodID;
22ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private final Map<EAP.AuthInfoID, Set<AuthParam>> mAuthParams;
23ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
24ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public EAPMethod(ByteBuffer payload) throws ProtocolException {
25ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (payload.remaining() < 3) {
26ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new ProtocolException("Runt EAP Method: " + payload.remaining());
27ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
28ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
29ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        int length = payload.get() & Constants.BYTE_MASK;
30ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        int methodID = payload.get() & Constants.BYTE_MASK;
31ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        int count = payload.get() & Constants.BYTE_MASK;
32ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
33ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mEAPMethodID = EAP.mapEAPMethod(methodID);
34ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mAuthParams = new EnumMap<>(EAP.AuthInfoID.class);
35ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
36ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        int realCount = 0;
37ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
38ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        ByteBuffer paramPayload = payload.duplicate().order(ByteOrder.LITTLE_ENDIAN);
39ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        paramPayload.limit(paramPayload.position() + length - 2);
40ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        payload.position(payload.position() + length - 2);
41ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        while (paramPayload.hasRemaining()) {
42ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            int id = paramPayload.get() & Constants.BYTE_MASK;
43ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
44ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            EAP.AuthInfoID authInfoID = EAP.mapAuthMethod(id);
45ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (authInfoID == null) {
46ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new ProtocolException("Unknown auth parameter ID: " + id);
47ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
48ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
49ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            int len = paramPayload.get() & Constants.BYTE_MASK;
50ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (len == 0 || len > paramPayload.remaining()) {
51ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new ProtocolException("Bad auth method length: " + len);
52ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
53ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
54ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            switch (authInfoID) {
55ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                case ExpandedEAPMethod:
56ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    addAuthParam(new ExpandedEAPMethod(authInfoID, len, paramPayload));
57ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    break;
58ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                case NonEAPInnerAuthType:
59ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    addAuthParam(new NonEAPInnerAuth(len, paramPayload));
60ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    break;
61ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                case InnerAuthEAPMethodType:
62ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    addAuthParam(new InnerAuthEAP(len, paramPayload));
63ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    break;
64ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                case ExpandedInnerEAPMethod:
65ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    addAuthParam(new ExpandedEAPMethod(authInfoID, len, paramPayload));
66ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    break;
67ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                case CredentialType:
68ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    addAuthParam(new Credential(authInfoID, len, paramPayload));
69ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    break;
70ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                case TunneledEAPMethodCredType:
71ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    addAuthParam(new Credential(authInfoID, len, paramPayload));
72ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    break;
73ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                case VendorSpecific:
74ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    addAuthParam(new VendorSpecificAuth(len, paramPayload));
75ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    break;
76ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
77ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
78ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            realCount++;
79ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
80ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (realCount != count)
81ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new ProtocolException("Invalid parameter count: " + realCount +
82ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    ", expected " + count);
83ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
84ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
85ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public EAPMethod(EAP.EAPMethodID eapMethodID, AuthParam authParam) {
86ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mEAPMethodID = eapMethodID;
87ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mAuthParams = new HashMap<>(1);
88ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (authParam != null) {
89ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Set<AuthParam> authParams = new HashSet<>();
90ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            authParams.add(authParam);
91ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            mAuthParams.put(authParam.getAuthInfoID(), authParams);
92ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
93ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
94ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
95ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private void addAuthParam(AuthParam param) {
96ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Set<AuthParam> authParams = mAuthParams.get(param.getAuthInfoID());
97ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (authParams == null) {
98ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            authParams = new HashSet<>();
99ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            mAuthParams.put(param.getAuthInfoID(), authParams);
100ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
101ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        authParams.add(param);
102ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
103ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
104ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public Map<EAP.AuthInfoID, Set<AuthParam>> getAuthParams() {
105ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return Collections.unmodifiableMap(mAuthParams);
106ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
107ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
108ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public EAP.EAPMethodID getEAPMethodID() {
109ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return mEAPMethodID;
110ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
111ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
112ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public int match(com.android.hotspot2.pps.Credential credential) {
113ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
114ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        EAPMethod credMethod = credential.getEAPMethod();
115ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (mEAPMethodID != credMethod.getEAPMethodID()) {
116ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return AuthMatch.None;
117ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
118ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
119ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        switch (mEAPMethodID) {
120ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            case EAP_TTLS:
121ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (mAuthParams.isEmpty()) {
122ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    return AuthMatch.Method;
123ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
124ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                int paramCount = 0;
125ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                for (Map.Entry<EAP.AuthInfoID, Set<AuthParam>> entry :
126ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        credMethod.getAuthParams().entrySet()) {
127ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    Set<AuthParam> params = mAuthParams.get(entry.getKey());
128ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    if (params == null) {
129ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        continue;
130ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
131ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
132ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    if (!Collections.disjoint(params, entry.getValue())) {
133ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        return AuthMatch.MethodParam;
134ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
135ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    paramCount += params.size();
136ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
137ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return paramCount > 0 ? AuthMatch.None : AuthMatch.Method;
138ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            case EAP_TLS:
139ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return AuthMatch.MethodParam;
140ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            case EAP_SIM:
141ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            case EAP_AKA:
142ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            case EAP_AKAPrim:
143ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return AuthMatch.Method;
144ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            default:
145ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return AuthMatch.Method;
146ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
147ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
148ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
149ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public AuthParam getAuthParam() {
150ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (mAuthParams.isEmpty()) {
151ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return null;
152ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
153ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Set<AuthParam> params = mAuthParams.values().iterator().next();
154ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (params.isEmpty()) {
155ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return null;
156ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
157ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return params.iterator().next();
158ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
159ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
160ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    @Override
161ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public boolean equals(Object thatObject) {
162ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (this == thatObject) {
163ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return true;
164ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
165ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        else if (thatObject == null || getClass() != thatObject.getClass()) {
166ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return false;
167ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
168ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
169ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        EAPMethod that = (EAPMethod) thatObject;
170ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return mEAPMethodID == that.mEAPMethodID && mAuthParams.equals(that.mAuthParams);
171ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
172ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
173ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    @Override
174ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public int hashCode() {
175ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        int result = mEAPMethodID.hashCode();
176ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        result = 31 * result + mAuthParams.hashCode();
177ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return result;
178ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
179ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
180ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    @Override
181ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public String toString() {
182ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        StringBuilder sb = new StringBuilder();
183ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        sb.append("EAP Method ").append(mEAPMethodID).append('\n');
184ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (Set<AuthParam> paramSet : mAuthParams.values()) {
185ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (AuthParam param : paramSet) {
186ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                sb.append("      ").append(param.toString());
187ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
188ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
189ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return sb.toString();
190ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
191ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist}
192