blob: fa6c2f9dfb60a0cc886ebe00bad24f8388b3edca [file] [log] [blame]
package com.android.anqp.eap;
import com.android.anqp.Constants;
import com.android.hotspot2.AuthMatch;
import java.net.ProtocolException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* An EAP Method, part of the NAI Realm ANQP element, specified in
* IEEE802.11-2012 section 8.4.4.10, figure 8-420
*/
public class EAPMethod {
private final EAP.EAPMethodID mEAPMethodID;
private final Map<EAP.AuthInfoID, Set<AuthParam>> mAuthParams;
public EAPMethod(ByteBuffer payload) throws ProtocolException {
if (payload.remaining() < 3) {
throw new ProtocolException("Runt EAP Method: " + payload.remaining());
}
int length = payload.get() & Constants.BYTE_MASK;
int methodID = payload.get() & Constants.BYTE_MASK;
int count = payload.get() & Constants.BYTE_MASK;
mEAPMethodID = EAP.mapEAPMethod(methodID);
mAuthParams = new EnumMap<>(EAP.AuthInfoID.class);
int realCount = 0;
ByteBuffer paramPayload = payload.duplicate().order(ByteOrder.LITTLE_ENDIAN);
paramPayload.limit(paramPayload.position() + length - 2);
payload.position(payload.position() + length - 2);
while (paramPayload.hasRemaining()) {
int id = paramPayload.get() & Constants.BYTE_MASK;
EAP.AuthInfoID authInfoID = EAP.mapAuthMethod(id);
if (authInfoID == null) {
throw new ProtocolException("Unknown auth parameter ID: " + id);
}
int len = paramPayload.get() & Constants.BYTE_MASK;
if (len == 0 || len > paramPayload.remaining()) {
throw new ProtocolException("Bad auth method length: " + len);
}
switch (authInfoID) {
case ExpandedEAPMethod:
addAuthParam(new ExpandedEAPMethod(authInfoID, len, paramPayload));
break;
case NonEAPInnerAuthType:
addAuthParam(new NonEAPInnerAuth(len, paramPayload));
break;
case InnerAuthEAPMethodType:
addAuthParam(new InnerAuthEAP(len, paramPayload));
break;
case ExpandedInnerEAPMethod:
addAuthParam(new ExpandedEAPMethod(authInfoID, len, paramPayload));
break;
case CredentialType:
addAuthParam(new Credential(authInfoID, len, paramPayload));
break;
case TunneledEAPMethodCredType:
addAuthParam(new Credential(authInfoID, len, paramPayload));
break;
case VendorSpecific:
addAuthParam(new VendorSpecificAuth(len, paramPayload));
break;
}
realCount++;
}
if (realCount != count)
throw new ProtocolException("Invalid parameter count: " + realCount +
", expected " + count);
}
public EAPMethod(EAP.EAPMethodID eapMethodID, AuthParam authParam) {
mEAPMethodID = eapMethodID;
mAuthParams = new HashMap<>(1);
if (authParam != null) {
Set<AuthParam> authParams = new HashSet<>();
authParams.add(authParam);
mAuthParams.put(authParam.getAuthInfoID(), authParams);
}
}
private void addAuthParam(AuthParam param) {
Set<AuthParam> authParams = mAuthParams.get(param.getAuthInfoID());
if (authParams == null) {
authParams = new HashSet<>();
mAuthParams.put(param.getAuthInfoID(), authParams);
}
authParams.add(param);
}
public Map<EAP.AuthInfoID, Set<AuthParam>> getAuthParams() {
return Collections.unmodifiableMap(mAuthParams);
}
public EAP.EAPMethodID getEAPMethodID() {
return mEAPMethodID;
}
public int match(com.android.hotspot2.pps.Credential credential) {
EAPMethod credMethod = credential.getEAPMethod();
if (mEAPMethodID != credMethod.getEAPMethodID()) {
return AuthMatch.None;
}
switch (mEAPMethodID) {
case EAP_TTLS:
if (mAuthParams.isEmpty()) {
return AuthMatch.Method;
}
int paramCount = 0;
for (Map.Entry<EAP.AuthInfoID, Set<AuthParam>> entry :
credMethod.getAuthParams().entrySet()) {
Set<AuthParam> params = mAuthParams.get(entry.getKey());
if (params == null) {
continue;
}
if (!Collections.disjoint(params, entry.getValue())) {
return AuthMatch.MethodParam;
}
paramCount += params.size();
}
return paramCount > 0 ? AuthMatch.None : AuthMatch.Method;
case EAP_TLS:
return AuthMatch.MethodParam;
case EAP_SIM:
case EAP_AKA:
case EAP_AKAPrim:
return AuthMatch.Method;
default:
return AuthMatch.Method;
}
}
public AuthParam getAuthParam() {
if (mAuthParams.isEmpty()) {
return null;
}
Set<AuthParam> params = mAuthParams.values().iterator().next();
if (params.isEmpty()) {
return null;
}
return params.iterator().next();
}
@Override
public boolean equals(Object thatObject) {
if (this == thatObject) {
return true;
}
else if (thatObject == null || getClass() != thatObject.getClass()) {
return false;
}
EAPMethod that = (EAPMethod) thatObject;
return mEAPMethodID == that.mEAPMethodID && mAuthParams.equals(that.mAuthParams);
}
@Override
public int hashCode() {
int result = mEAPMethodID.hashCode();
result = 31 * result + mAuthParams.hashCode();
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("EAP Method ").append(mEAPMethodID).append('\n');
for (Set<AuthParam> paramSet : mAuthParams.values()) {
for (AuthParam param : paramSet) {
sb.append(" ").append(param.toString());
}
}
return sb.toString();
}
}