blob: bc588cb6e230a57ac2f7e6b9dd1efdeeb0416e84 [file] [log] [blame]
// Copyright 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <base/bind.h>
#include <base/files/file_util.h>
#include <base/rand_util.h>
#include <brillo/http/http_request.h>
#include <brillo/mime_utils.h>
#include <firewalld/firewall.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include "webservd/binder_request.h"
#include "webservd/binder_server.h"
#include "webservd/protocol_handler.h"
#include "webservd/request_handler_interface.h"
#include "webservd/utils.h"
#include "android/webservd/BnProtocolHandler.h"
using android::sp;
using android::String8;
using android::binder::Status;
using android::webservd::IProtocolHandler;
using android::webservd::IRequestHandler;
using android::webservd::IHttpRequest;
using android::webservd::HttpRequest;
using std::set;
using std::string;
using std::unique_ptr;
using std::vector;
namespace webservd {
namespace {
#ifdef __ANDROID__
const char kCertificateFile[] = "/data/misc/webservd/certificate";
const char kKeyFile[] = "/data/misc/webservd/key";
#else
const char kCertificateFile[] = "/var/lib/webservd-certificate";
const char kKeyFile[] = "/var/lib/webservd-key";
#endif
class BinderRequestHandler : public RequestHandlerInterface {
public:
explicit BinderRequestHandler(const sp<IRequestHandler>& handler)
: handler_(handler) {}
void HandleRequest(Request* request) override {
sp<IHttpRequest> binder_request(new HttpRequest(request));
if (!handler_->ProcessRequest(binder_request).isOk()) {
request->Complete(brillo::http::status_code::InternalServerError, {},
brillo::mime::text::kPlain, "Internal server error");
}
}
private:
sp<IRequestHandler> handler_;
DISALLOW_COPY_AND_ASSIGN(BinderRequestHandler);
};
class BinderProtocolHandler : public android::webservd::BnProtocolHandler {
public:
BinderProtocolHandler(string name, BinderServer* server,
android::BinderWrapper* binder_wrapper)
: impl_(name, server),
binder_wrapper_(binder_wrapper) {}
bool Start(const Config::ProtocolHandler& config) {
return impl_.Start(config);
}
Status AddRequestHandler(const string& url, const string& method,
const sp<IRequestHandler>& handler, string* ret)
override {
*ret = impl_.AddRequestHandler(url, method,
unique_ptr<RequestHandlerInterface>(new BinderRequestHandler(handler)));
binder_wrapper_->RegisterForDeathNotifications(
IRequestHandler::asBinder(handler),
base::Bind(&BinderProtocolHandler::HandlerDied,
base::Unretained(this), *ret));
return Status::ok();
}
Status RemoveRequestHandler(const string& guid) override {
if (impl_.RemoveRequestHandler(guid)) {
return Status::ok();
}
return Status::fromExceptionCode(
Status::EX_ILLEGAL_ARGUMENT,
String8{"No such handler registered"});
}
Status GetName(string* name) override {
*name = impl_.GetName();
return Status::ok();
}
Status GetPort(int32_t* port) override {
*port = impl_.GetPort();
return Status::ok();
}
Status GetProtocol(string* protocol) override {
*protocol = impl_.GetProtocol();
return Status::ok();
}
Status GetCertificateFingerprint(vector<uint8_t>* fingerprint)
override {
// Note: ProtocolHandler::GetCertificateFingerprint returns a brillo::Blob,
// which at time of writing is an alias to vector<uint8_t>. This will break
// if that changes.
*fingerprint = impl_.GetCertificateFingerprint();
return Status::ok();
}
private:
void HandlerDied(const string& guid) {
impl_.RemoveRequestHandler(guid);
}
ProtocolHandler impl_;
android::BinderWrapper* binder_wrapper_;
DISALLOW_COPY_AND_ASSIGN(BinderProtocolHandler);
};
brillo::SecureBlob LoadAndValidatePrivateKey(const base::FilePath& key_file,
webservd::Encryptor* encryptor) {
std::string encrypted_key_data;
if (!base::ReadFileToString(key_file, &encrypted_key_data))
return {};
std::string key_data;
if (!encryptor->DecryptWithAuthentication(encrypted_key_data, &key_data))
return {};
brillo::SecureBlob key{key_data};
if (!webservd::ValidateRSAPrivateKey(key))
key.clear();
return key;
}
} // namespace
base::FilePath BinderServer::GetUploadDirectory() const {
base::FilePath upload_dir;
#ifdef __ANDROID__
upload_dir = base::FilePath{"/data/misc/webservd/uploads"};
#else
CHECK(base::GetTempDir(&upload_dir));
#endif
return upload_dir;
}
void BinderServer::InitTlsData() {
if (!TLS_certificate_.empty())
return; // Already initialized.
// TODO(avakulenko): verify these constants and provide sensible values
// for the long-term. See brbug.com/227
const int kKeyLengthBits = 1024;
const int64_t kOneYearInSeconds = 31556952; // 365.2425 days
const base::TimeDelta kCertExpiration =
base::TimeDelta::FromSeconds(5 * kOneYearInSeconds);
const char kCommonName[] = "Brillo device";
const base::FilePath certificate_file{kCertificateFile};
const base::FilePath key_file{kKeyFile};
auto cert = LoadAndValidateCertificate(certificate_file);
brillo::SecureBlob private_key =
LoadAndValidatePrivateKey(key_file, encryptor_);
if (!cert || private_key.empty()) {
// Create the X509 certificate.
LOG(INFO) << "Generating new certificate...";
int cert_serial_number = base::RandInt(0, std::numeric_limits<int>::max());
cert = CreateCertificate(cert_serial_number, kCertExpiration, kCommonName);
// Create RSA key pair.
auto rsa_key_pair = GenerateRSAKeyPair(kKeyLengthBits);
// Store the private key to a temp buffer.
// Do not assign it to |TLS_private_key_| yet until the end when we are sure
// everything else has worked out.
private_key = StoreRSAPrivateKey(rsa_key_pair.get());
// Create EVP key and set it to the certificate.
auto key = std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY*)>{EVP_PKEY_new(),
EVP_PKEY_free};
CHECK(key.get());
// Transfer ownership of |rsa_key_pair| to |key|.
CHECK(EVP_PKEY_assign_RSA(key.get(), rsa_key_pair.release()));
CHECK(X509_set_pubkey(cert.get(), key.get()));
// Sign the certificate.
CHECK(X509_sign(cert.get(), key.get(), EVP_sha256()));
// Save the certificate and private key to disk.
StoreCertificate(cert.get(), certificate_file);
std::string encrypted_key;
encryptor_->EncryptWithAuthentication(private_key.to_string(),
&encrypted_key);
base::WriteFile(key_file, encrypted_key.data(), encrypted_key.size());
}
TLS_certificate_ = StoreCertificate(cert.get());
TLS_certificate_fingerprint_ = GetSha256Fingerprint(cert.get());
TLS_private_key_ = std::move(private_key);
// Update the TLS data in protocol handler config.
for (auto& handler_config : config_.protocol_handlers) {
if (handler_config.use_tls) {
handler_config.certificate = TLS_certificate_;
handler_config.certificate_fingerprint = TLS_certificate_fingerprint_;
handler_config.private_key = TLS_private_key_;
}
}
}
BinderServer::BinderServer(const Config& config,
android::BinderWrapper* binder_wrapper)
: config_(config),
default_encryptor_{Encryptor::CreateDefaultEncryptor()},
encryptor_(default_encryptor_.get()) {
InitTlsData();
unique_ptr<firewalld::Firewall> firewall =
firewalld::Firewall::Connect(binder_wrapper);
if (!firewall) {
LOG(ERROR) << "Could not connect to firewall.";
}
for (const auto& handler_config : config_.protocol_handlers) {
sp<BinderProtocolHandler> handler_ptr{
new BinderProtocolHandler(handler_config.name, this, binder_wrapper)};
if (handler_ptr->Start(handler_config)) {
protocol_handlers_.push_back(handler_ptr);
if (firewall &&
!firewall->PunchTcpHole(handler_config.port,
handler_config.interface_name)) {
LOG(ERROR) << "Could not open port " << handler_config.port
<< " for protocol handler.";
}
}
}
}
Status BinderServer::Ping(string* result) {
*result = "Web Server is running.";
return Status::ok();
}
Status BinderServer::GetDefaultRequestTimeout(int32_t* timeout_seconds) {
*timeout_seconds = config_.default_request_timeout_seconds;
return Status::ok();
}
Status BinderServer::GetProtocolHandlers(
const string& name,
vector<sp<IBinder>>* result) {
result->clear();
for (auto handler : protocol_handlers_) {
string handler_name;
if (name.empty()) {
result->push_back(IProtocolHandler::asBinder(handler));
continue;
}
// No reason for this to fail on the server side
CHECK(handler->GetName(&handler_name).isOk());
if (handler_name == name) {
result->push_back(IProtocolHandler::asBinder(handler));
}
}
return Status::ok();
}
} // namespace webservd