| // 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 |