1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/network/cellular_utils.h"
#include <algorithm>
#include "ash/constants/ash_features.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/logging.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/ash/components/cryptohome/system_salt_getter.h"
#include "chromeos/ash/components/dbus/hermes/hermes_euicc_client.h"
#include "chromeos/ash/components/dbus/hermes/hermes_manager_client.h"
#include "chromeos/ash/components/dbus/hermes/hermes_profile_client.h"
#include "chromeos/ash/components/network/cellular_esim_profile.h"
#include "chromeos/ash/components/network/network_handler.h"
#include "chromeos/ash/components/network/network_profile.h"
#include "chromeos/ash/components/network/network_profile_handler.h"
#include "crypto/sha2.h"
namespace ash {
namespace cellular_utils {
const char kSmdsGsma[] = "1$lpa.ds.gsma.com$";
const char kSmdsStork[] = "1$prod.smds.rsp.goog$";
const char kSmdsAndroidProduction[] = "1$lpa.live.esimdiscovery.com$";
const char kSmdsAndroidStaging[] = "1$lpa.live.esimdiscovery.dev$";
} // namespace cellular_utils
namespace {
const char kNonShillCellularNetworkPathPrefix[] = "/non-shill-cellular/";
std::string GetLogSafeEid(const std::string& eid) {
const SystemSaltGetter::RawSalt* salt = SystemSaltGetter::Get()->GetRawSalt();
if (!salt) {
return std::string();
}
return crypto::SHA256HashString(
eid + SystemSaltGetter::ConvertRawSaltToHexString(*salt));
}
} // namespace
base::flat_set<dbus::ObjectPath> GetProfilePathsFromEuicc(
HermesEuiccClient::Properties* euicc_properties) {
base::flat_set<dbus::ObjectPath> profile_paths;
for (const dbus::ObjectPath& path : euicc_properties->profiles().value()) {
profile_paths.insert(path);
}
return profile_paths;
}
CellularESimProfile::State FromProfileState(hermes::profile::State state) {
switch (state) {
case hermes::profile::State::kPending:
return CellularESimProfile::State::kPending;
case hermes::profile::State::kInactive:
return CellularESimProfile::State::kInactive;
case hermes::profile::State::kActive:
return CellularESimProfile::State::kActive;
default:
NOTREACHED() << "Unexpected Hermes profile state: " << state;
}
}
std::vector<CellularESimProfile> GenerateProfilesFromEuicc(
const dbus::ObjectPath& euicc_path) {
std::vector<CellularESimProfile> profiles;
HermesEuiccClient::Properties* euicc_properties =
HermesEuiccClient::Get()->GetProperties(euicc_path);
std::string eid = euicc_properties->eid().value();
for (const dbus::ObjectPath& profile_path :
GetProfilePathsFromEuicc(euicc_properties)) {
HermesProfileClient::Properties* profile_properties =
HermesProfileClient::Get()->GetProperties(profile_path);
// Hermes only exposes eSIM profiles with relevant profile class. e.g.
// Test profiles are exposed only when Hermes is put into test mode.
// No additional profile filtering is done on Chrome side.
profiles.emplace_back(
FromProfileState(profile_properties->state().value()), profile_path,
eid, profile_properties->iccid().value(),
base::UTF8ToUTF16(profile_properties->name().value()),
base::UTF8ToUTF16(profile_properties->nick_name().value()),
base::UTF8ToUTF16(profile_properties->service_provider().value()),
profile_properties->activation_code().value());
}
return profiles;
}
const base::flat_map<int32_t, std::string> GetESimSlotToEidMap() {
base::flat_map<int32_t, std::string> esim_slot_to_eid;
const std::vector<dbus::ObjectPath>& available_euiccs =
HermesManagerClient::Get()->GetAvailableEuiccs();
VLOG(1) << "GetESimSlotToEidMap(): Num available EUICCs: "
<< available_euiccs.size();
for (auto& euicc_path : available_euiccs) {
HermesEuiccClient::Properties* properties =
HermesEuiccClient::Get()->GetProperties(euicc_path);
int32_t slot_id = properties->physical_slot().value();
std::string eid = properties->eid().value();
esim_slot_to_eid.emplace(slot_id, eid);
VLOG(1) << "EUICC: " << euicc_path.value() << ", slot id: " << slot_id
<< ", eid: " << GetLogSafeEid(eid);
}
return esim_slot_to_eid;
}
namespace cellular_utils {
std::vector<CellularESimProfile> GenerateProfilesFromHermes() {
std::vector<CellularESimProfile> profiles;
for (const dbus::ObjectPath& euicc_path :
HermesManagerClient::Get()->GetAvailableEuiccs()) {
std::vector<CellularESimProfile> profiles_from_euicc =
GenerateProfilesFromEuicc(euicc_path);
std::ranges::copy(profiles_from_euicc, std::back_inserter(profiles));
}
return profiles;
}
const DeviceState::CellularSIMSlotInfos GetSimSlotInfosWithUpdatedEid(
const DeviceState* device) {
const base::flat_map<int32_t, std::string> esim_slot_to_eid =
GetESimSlotToEidMap();
DeviceState::CellularSIMSlotInfos sim_slot_infos = device->GetSimSlotInfos();
VLOG(1) << "GetSimSlotInfosWithUpdatedEid(): Num SIM slot infos: "
<< sim_slot_infos.size();
for (auto& sim_slot_info : sim_slot_infos) {
const std::string shill_provided_eid = sim_slot_info.eid;
VLOG(1) << "SIM slot id: " << sim_slot_info.slot_id
<< ", Shill provided eid: " << GetLogSafeEid(shill_provided_eid);
// If there is no associated |slot_id| in the map, the SIM slot info refers
// to a pSIM, and the Hermes provided data is irrelevant.
auto it = esim_slot_to_eid.find(sim_slot_info.slot_id);
if (it == esim_slot_to_eid.end())
continue;
const std::string hermes_provided_eid = it->second;
if (!shill_provided_eid.empty() &&
hermes_provided_eid != shill_provided_eid) {
LOG(ERROR) << "Hermes provided EID of " << hermes_provided_eid
<< " does not match Shill provided non-empty EID of "
<< shill_provided_eid << ". Defaulting to Shill provided EID.";
} else {
sim_slot_info.eid = hermes_provided_eid;
}
}
return sim_slot_infos;
}
bool IsSimPrimary(const std::string& iccid, const DeviceState* device) {
for (const auto& sim_slot_info : device->GetSimSlotInfos()) {
if (sim_slot_info.iccid == iccid && sim_slot_info.primary) {
return true;
}
}
return false;
}
std::string GenerateStubCellularServicePath(const std::string& iccid) {
return base::StrCat({kNonShillCellularNetworkPathPrefix, iccid});
}
const NetworkProfile* GetCellularProfile(
const NetworkProfileHandler* network_profile_handler) {
DCHECK(network_profile_handler);
return network_profile_handler->GetProfileForUserhash(
/*userhash=*/std::string());
}
bool IsStubCellularServicePath(const std::string& service_path) {
return base::StartsWith(service_path, kNonShillCellularNetworkPathPrefix);
}
std::optional<dbus::ObjectPath> GetCurrentEuiccPath() {
// Always use the first Euicc if Hermes only exposes one Euicc.
// If useSecondEuicc flag is set and there are two Euicc available,
// use the second available Euicc.
const std::vector<dbus::ObjectPath>& euicc_paths =
HermesManagerClient::Get()->GetAvailableEuiccs();
if (euicc_paths.empty())
return std::nullopt;
if (euicc_paths.size() == 1)
return euicc_paths[0];
bool use_second_euicc =
base::FeatureList::IsEnabled(features::kCellularUseSecondEuicc);
return use_second_euicc ? euicc_paths[1] : euicc_paths[0];
}
std::vector<std::string> GetSmdsActivationCodes() {
std::vector<std::string> activation_codes;
if (features::ShouldUseStorkSmds()) {
activation_codes.emplace_back(kSmdsStork);
}
if (features::ShouldUseAndroidStagingSmds()) {
activation_codes.emplace_back(kSmdsAndroidStaging);
}
if (activation_codes.empty()) {
activation_codes = {
kSmdsAndroidProduction,
kSmdsGsma,
};
}
return activation_codes;
}
} // namespace cellular_utils
} // namespace ash
|