Home | History | Annotate | Download | only in hotspot2
      1 /*
      2  * Copyright (C) 2016 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.server.wifi.hotspot2;
     18 
     19 import com.android.server.wifi.IMSIParameter;
     20 import com.android.server.wifi.hotspot2.anqp.CellularNetwork;
     21 import com.android.server.wifi.hotspot2.anqp.DomainNameElement;
     22 import com.android.server.wifi.hotspot2.anqp.NAIRealmData;
     23 import com.android.server.wifi.hotspot2.anqp.NAIRealmElement;
     24 import com.android.server.wifi.hotspot2.anqp.RoamingConsortiumElement;
     25 import com.android.server.wifi.hotspot2.anqp.ThreeGPPNetworkElement;
     26 import com.android.server.wifi.hotspot2.anqp.eap.AuthParam;
     27 import com.android.server.wifi.hotspot2.anqp.eap.EAPMethod;
     28 
     29 import java.util.List;
     30 import java.util.Map;
     31 import java.util.Set;
     32 
     33 /**
     34  * Utility class for providing matching functions against ANQP elements.
     35  */
     36 public class ANQPMatcher {
     37     /**
     38      * Match the domain names in the ANQP element against the provider's FQDN and SIM credential.
     39      * The Domain Name ANQP element might contain domains for 3GPP network (e.g.
     40      * wlan.mnc*.mcc*.3gppnetwork.org), so we should match that against the provider's SIM
     41      * credential if one is provided.
     42      *
     43      * @param element The Domain Name ANQP element
     44      * @param fqdn The FQDN to compare against
     45      * @param imsiParam The IMSI parameter of the provider
     46      * @param simImsiList The list of IMSI from the installed SIM cards that matched provider's
     47      *                    IMSI parameter
     48      * @return true if a match is found
     49      */
     50     public static boolean matchDomainName(DomainNameElement element, String fqdn,
     51             IMSIParameter imsiParam, List<String> simImsiList) {
     52         if (element == null) {
     53             return false;
     54         }
     55 
     56         for (String domain : element.getDomains()) {
     57             if (DomainMatcher.arg2SubdomainOfArg1(fqdn, domain)) {
     58                 return true;
     59             }
     60 
     61             // Try to retrieve the MCC-MNC string from the domain (for 3GPP network domain) and
     62             // match against the provider's SIM credential.
     63             if (matchMccMnc(Utils.getMccMnc(Utils.splitDomain(domain)), imsiParam, simImsiList)) {
     64                 return true;
     65             }
     66         }
     67         return false;
     68     }
     69 
     70     /**
     71      * Match the roaming consortium OIs in the ANQP element against the roaming consortium OIs
     72      * of a provider.
     73      *
     74      * @param element The Roaming Consortium ANQP element
     75      * @param providerOIs The roaming consortium OIs of the provider
     76      * @return true if a match is found
     77      */
     78     public static boolean matchRoamingConsortium(RoamingConsortiumElement element,
     79             long[] providerOIs) {
     80         if (element == null) {
     81             return false;
     82         }
     83         if (providerOIs == null) {
     84             return false;
     85         }
     86         List<Long> rcOIs = element.getOIs();
     87         for (long oi : providerOIs) {
     88             if (rcOIs.contains(oi)) {
     89                 return true;
     90             }
     91         }
     92         return false;
     93     }
     94 
     95     /**
     96      * Match the NAI realm in the ANQP element against the realm and authentication method of
     97      * a provider.
     98      *
     99      * @param element The NAI Realm ANQP element
    100      * @param realm The realm of the provider's credential
    101      * @param eapMethodID The EAP Method ID of the provider's credential
    102      * @param authParam The authentication parameter of the provider's credential
    103      * @return an integer indicating the match status
    104      */
    105     public static int matchNAIRealm(NAIRealmElement element, String realm, int eapMethodID,
    106             AuthParam authParam) {
    107         if (element == null || element.getRealmDataList().isEmpty()) {
    108             return AuthMatch.INDETERMINATE;
    109         }
    110 
    111         int bestMatch = AuthMatch.NONE;
    112         for (NAIRealmData realmData : element.getRealmDataList()) {
    113             int match = matchNAIRealmData(realmData, realm, eapMethodID, authParam);
    114             if (match > bestMatch) {
    115                 bestMatch = match;
    116                 if (bestMatch == AuthMatch.EXACT) {
    117                     break;
    118                 }
    119             }
    120         }
    121         return bestMatch;
    122     }
    123 
    124     /**
    125      * Match the 3GPP Network in the ANQP element against the SIM credential of a provider.
    126      *
    127      * @param element 3GPP Network ANQP element
    128      * @param imsiParam The IMSI parameter of the provider's SIM credential
    129      * @param simImsiList The list of IMSI from the installed SIM cards that matched provider's
    130      *                    IMSI parameter
    131      * @return true if a matched is found
    132      */
    133     public static  boolean matchThreeGPPNetwork(ThreeGPPNetworkElement element,
    134             IMSIParameter imsiParam, List<String> simImsiList) {
    135         if (element == null) {
    136             return false;
    137         }
    138         for (CellularNetwork network : element.getNetworks()) {
    139             if (matchCellularNetwork(network, imsiParam, simImsiList)) {
    140                 return true;
    141             }
    142         }
    143         return false;
    144     }
    145 
    146     /**
    147      * Match the given NAI Realm data against the realm and authentication method of a provider.
    148      *
    149      * @param realmData The NAI Realm data
    150      * @param realm The realm of the provider's credential
    151      * @param eapMethodID The EAP Method ID of the provider's credential
    152      * @param authParam The authentication parameter of the provider's credential
    153      * @return an integer indicating the match status
    154      */
    155     private static int matchNAIRealmData(NAIRealmData realmData, String realm, int eapMethodID,
    156             AuthParam authParam) {
    157         // Check for realm domain name match.
    158         int realmMatch = AuthMatch.NONE;
    159         for (String realmStr : realmData.getRealms()) {
    160             if (DomainMatcher.arg2SubdomainOfArg1(realm, realmStr)) {
    161                 realmMatch = AuthMatch.REALM;
    162                 break;
    163             }
    164         }
    165 
    166         if (realmData.getEAPMethods().isEmpty()) {
    167             return realmMatch;
    168         }
    169 
    170         // Check for EAP method match.
    171         int eapMethodMatch = AuthMatch.NONE;
    172         for (EAPMethod eapMethod : realmData.getEAPMethods()) {
    173             eapMethodMatch = matchEAPMethod(eapMethod, eapMethodID, authParam);
    174             if (eapMethodMatch != AuthMatch.NONE) {
    175                 break;
    176             }
    177         }
    178 
    179         if (eapMethodMatch == AuthMatch.NONE) {
    180             return AuthMatch.NONE;
    181         }
    182 
    183         if (realmMatch == AuthMatch.NONE) {
    184             return eapMethodMatch;
    185         }
    186         return realmMatch | eapMethodMatch;
    187     }
    188 
    189     /**
    190      * Match the given EAPMethod against the authentication method of a provider.
    191      *
    192      * @param method The EAP Method
    193      * @param eapMethodID The EAP Method ID of the provider's credential
    194      * @param authParam The authentication parameter of the provider's credential
    195      * @return an integer indicating the match status
    196      */
    197     private static int matchEAPMethod(EAPMethod method, int eapMethodID, AuthParam authParam) {
    198         if (method.getEAPMethodID() != eapMethodID) {
    199             return AuthMatch.NONE;
    200         }
    201         // Check for authentication parameter match.
    202         if (authParam != null) {
    203             Map<Integer, Set<AuthParam>> authParams = method.getAuthParams();
    204             Set<AuthParam> paramSet = authParams.get(authParam.getAuthTypeID());
    205             if (paramSet == null || !paramSet.contains(authParam)) {
    206                 return AuthMatch.NONE;
    207             }
    208             return AuthMatch.METHOD_PARAM;
    209         }
    210         return AuthMatch.METHOD;
    211     }
    212 
    213     /**
    214      * Match a cellular network information in the 3GPP Network ANQP element against the SIM
    215      * credential of a provider.
    216      *
    217      * @param network The cellular network that contained list of PLMNs
    218      * @param imsiParam IMSI parameter of the provider
    219      * @param simImsiList The list of IMSI from the installed SIM cards that matched provider's
    220      *                    IMSI parameter
    221      * @return true if a match is found
    222      */
    223     private static boolean matchCellularNetwork(CellularNetwork network, IMSIParameter imsiParam,
    224             List<String> simImsiList) {
    225         for (String plmn : network.getPlmns()) {
    226             if (matchMccMnc(plmn, imsiParam, simImsiList)) {
    227                 return true;
    228             }
    229         }
    230         return false;
    231     }
    232 
    233     /**
    234      * Match a MCC-MNC against the SIM credential of a provider.
    235      *
    236      * @param mccMnc The string containing MCC-MNC
    237      * @param imsiParam The IMSI parameter of the provider
    238      * @param simImsiList The list of IMSI from the installed SIM cards that matched provider's
    239      *                    IMSI parameter
    240      * @return true if a match is found
    241      */
    242     private static boolean matchMccMnc(String mccMnc, IMSIParameter imsiParam,
    243             List<String> simImsiList) {
    244         if (imsiParam == null || simImsiList == null) {
    245             return false;
    246         }
    247         // Match against the IMSI parameter in the provider.
    248         if (!imsiParam.matchesMccMnc(mccMnc)) {
    249             return false;
    250         }
    251         // Additional check for verifying the match with IMSIs from the SIM cards, since the IMSI
    252         // parameter might not contain the full 6-digit MCC MNC (e.g. IMSI parameter is an IMSI
    253         // prefix that contained less than 6-digit of numbers "12345*").
    254         for (String imsi : simImsiList) {
    255             if (imsi.startsWith(mccMnc)) {
    256                 return true;
    257             }
    258         }
    259         return false;
    260     }
    261 }
    262