blob: 69a405c1b65fa1dad4c00cc03026a4fd00b84bae [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "hermes/lpd.h"
#include <string>
#include <utility>
#include <base/bind.h>
#include <base/callback.h>
#include <base/strings/string_number_conversions.h>
#include "hermes/qmi_constants.h"
namespace hermes {
// TODO(jruthe): remove header length once ASN.1 parsing is complete
constexpr uint8_t kChallengeHeaderLength = 5;
constexpr uint8_t kEsimChallengeLength = 16;
Lpd::Lpd(std::unique_ptr<Esim> esim, std::unique_ptr<Smdp> smdp)
: esim_(std::move(esim)), smdp_(std::move(smdp)) {}
Lpd::~Lpd() = default;
void Lpd::InstallProfile(const SuccessCallback& success_callback,
const Lpd::LpdErrorCallback& error_callback) {
user_success_ = success_callback;
user_error_ = error_callback;
esim_error_handler_ =
base::Bind(&Lpd::HandleEsimError, base::Unretained(this), error_callback);
smdp_error_handler_ =
base::Bind(&Lpd::HandleSmdpError, base::Unretained(this), error_callback);
Authenticate();
}
void Lpd::Initialize(const SuccessCallback& success_callback,
const Lpd::LpdErrorCallback& error_callback) {
esim_->Initialize(success_callback, esim_error_handler_);
}
void Lpd::Authenticate() {
esim_->OpenLogicalChannel(
base::Bind(&Lpd::OnOpenLogicalChannel, base::Unretained(this)),
esim_error_handler_);
}
void Lpd::OnOpenLogicalChannel(const std::vector<uint8_t>&) {
esim_->GetInfo(kEsimInfo1Tag,
base::Bind(&Lpd::OnEsimInfoResult, base::Unretained(this)),
esim_error_handler_);
}
void Lpd::OnAuthenticateSuccess(const std::string& transaction_id,
const std::vector<uint8_t>& profile_metadata,
const std::vector<uint8_t>& smdp_signed2,
const std::vector<uint8_t>& smdp_signature2,
const std::vector<uint8_t>& smdp_certificate) {
if (transaction_id != transaction_id_) {
LOG(ERROR) << __func__ << ": transaction_id does not match";
user_error_.Run(LpdError::kFailure);
return;
}
// TODO(jruthe): DownloadProfile call
esim_->PrepareDownloadRequest(
smdp_signed2, smdp_signature2, smdp_certificate,
base::Bind(&Lpd::OnPrepareDownloadRequest, base::Unretained(this)),
esim_error_handler_);
}
void Lpd::OnPrepareDownloadRequest(const std::vector<uint8_t>& data) {
smdp_->GetBoundProfilePackage(
transaction_id_, data,
base::Bind(&Lpd::OnGetBoundProfilePackage, base::Unretained(this)),
smdp_error_handler_);
}
void Lpd::OnGetBoundProfilePackage(
const std::string& transaction_id,
const std::vector<uint8_t>& bound_profile_package) {
if (transaction_id != transaction_id_) {
LOG(ERROR) << __func__ << ": transaction id does not match";
user_error_.Run(LpdError::kFailure);
return;
}
VLOG(1) << __func__ << ": bound_profile_package : "
<< base::HexEncode(bound_profile_package.data(),
bound_profile_package.size());
// TODO(jruthe): Install |bound_profile_package| through Esim interface
user_success_.Run();
}
void Lpd::OnEsimInfoResult(const std::vector<uint8_t>& info) {
esim_->GetChallenge(
base::Bind(&Lpd::OnEsimChallengeResult, base::Unretained(this), info),
esim_error_handler_);
}
void Lpd::OnLoadBoundProfilePackage(
const std::vector<uint8_t>& profile_installation_result) {
LOG(INFO) << __func__ << ": Profile installation succeeded";
user_success_.Run();
}
void Lpd::OnEsimChallengeResult(const std::vector<uint8_t>& info1,
const std::vector<uint8_t>& challenge) {
if (challenge.size() - kChallengeHeaderLength != kEsimChallengeLength) {
user_error_.Run(LpdError::kFailure);
return;
}
// TODO(jruthe): this is currently a trick to send only the value bytes of
// the challenge to SmdpImpl, but should probably be parsed more correctly
// here (along with most of the rest of the ASN.1 encoded data).
smdp_->InitiateAuthentication(
info1,
std::vector<uint8_t>(challenge.begin() + 5 /* length of header */,
challenge.end()),
base::Bind(&Lpd::OnInitiateAuthenticationResult, base::Unretained(this)),
smdp_error_handler_);
}
void Lpd::OnInitiateAuthenticationResult(
const std::string& transaction_id,
const std::vector<uint8_t>& server_signed1,
const std::vector<uint8_t>& server_signature1,
const std::vector<uint8_t>& euicc_ci_pk_id_to_be_used,
const std::vector<uint8_t>& server_certificate) {
transaction_id_ = transaction_id;
esim_->AuthenticateServer(
server_signed1, server_signature1, euicc_ci_pk_id_to_be_used,
server_certificate,
base::Bind(&Lpd::OnAuthenticateServerResult, base::Unretained(this)),
esim_error_handler_);
}
void Lpd::OnAuthenticateServerResult(
const std::vector<uint8_t>& data) {
smdp_->AuthenticateClient(
transaction_id_, data,
base::Bind(&Lpd::OnAuthenticateSuccess, base::Unretained(this)),
smdp_error_handler_);
}
void Lpd::HandleEsimError(const Lpd::LpdErrorCallback& lpd_callback,
EsimError error) {
switch (error) {
case EsimError::kEsimSuccess:
lpd_callback.Run(LpdError::kSuccess);
break;
case EsimError::kEsimError:
lpd_callback.Run(LpdError::kFailure);
break;
case EsimError::kEsimNotConnected:
lpd_callback.Run(LpdError::kRetry);
break;
}
}
// TODO(jruthe): Implement Smdp generic error handling.
void Lpd::HandleSmdpError(const Lpd::LpdErrorCallback& lpd_callback,
const std::vector<uint8_t>& smdp_error_data) {}
} // namespace hermes