1// Copyright 2015 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#include "webservd/server.h" 16 17#include <openssl/evp.h> 18#include <openssl/x509.h> 19 20#include <limits> 21 22#include <base/files/file_util.h> 23#include <base/rand_util.h> 24#include <base/strings/stringprintf.h> 25#include <brillo/dbus/async_event_sequencer.h> 26 27#include "webservd/dbus_protocol_handler.h" 28#include "webservd/encryptor.h" 29#include "webservd/protocol_handler.h" 30#include "webservd/utils.h" 31 32using brillo::dbus_utils::AsyncEventSequencer; 33using brillo::dbus_utils::DBusObject; 34using brillo::dbus_utils::ExportedObjectManager; 35 36namespace { 37 38#ifdef __ANDROID__ 39const char kCertificateFile[] = "/data/misc/webservd/certificate"; 40const char kKeyFile[] = "/data/misc/webservd/key"; 41#else 42const char kCertificateFile[] = "/var/lib/webservd-certificate"; 43const char kKeyFile[] = "/var/lib/webservd-key"; 44#endif 45 46void OnFirewallSuccess(const std::string& itf_name, 47 uint16_t port, 48 bool allowed) { 49 if (allowed) { 50 LOG(INFO) << "Successfully opened up port " << port << " on interface " 51 << itf_name; 52 } else { 53 LOG(ERROR) << "Failed to open up port " << port << ", interface: " 54 << itf_name; 55 } 56} 57 58void IgnoreFirewallDBusMethodError(brillo::Error* /* error */) { 59} 60 61brillo::SecureBlob LoadAndValidatePrivateKey(const base::FilePath& key_file, 62 webservd::Encryptor* encryptor) { 63 std::string encrypted_key_data; 64 if (!base::ReadFileToString(key_file, &encrypted_key_data)) 65 return {}; 66 std::string key_data; 67 if (!encryptor->DecryptWithAuthentication(encrypted_key_data, &key_data)) 68 return {}; 69 brillo::SecureBlob key{key_data}; 70 if (!webservd::ValidateRSAPrivateKey(key)) 71 key.clear(); 72 return key; 73} 74 75} // anonymous namespace 76 77namespace webservd { 78 79Server::Server(ExportedObjectManager* object_manager, const Config& config, 80 std::unique_ptr<FirewallInterface> firewall) 81 : dbus_object_{new DBusObject{ 82 object_manager, object_manager->GetBus(), 83 org::chromium::WebServer::ServerAdaptor::GetObjectPath()}}, 84 default_encryptor_{Encryptor::CreateDefaultEncryptor()}, 85 encryptor_{default_encryptor_.get()}, 86 config_{config}, 87 firewall_{std::move(firewall)} { 88 dbus_adaptor_.SetDefaultRequestTimeout( 89 config_.default_request_timeout_seconds); 90} 91 92Server::~Server() {} 93 94void Server::RegisterAsync( 95 const AsyncEventSequencer::CompletionAction& completion_callback) { 96 scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer()); 97 dbus_adaptor_.RegisterWithDBusObject(dbus_object_.get()); 98 99 InitTlsData(); 100 101 for (auto& handler_config : config_.protocol_handlers) 102 CreateProtocolHandler(&handler_config); 103 104 firewall_->WaitForServiceAsync(dbus_object_->GetBus().get(), 105 base::Bind(&Server::OnFirewallServiceOnline, 106 weak_ptr_factory_.GetWeakPtr())); 107 108 dbus_object_->RegisterAsync( 109 sequencer->GetHandler("Failed exporting Server.", true)); 110 111 for (const auto& pair : protocol_handler_map_) { 112 pair.second->RegisterAsync( 113 sequencer->GetHandler("Failed exporting ProtocolHandler.", false)); 114 } 115 sequencer->OnAllTasksCompletedCall({completion_callback}); 116} 117 118void Server::OnFirewallServiceOnline() { 119 LOG(INFO) << "Firewall service is on-line. " 120 << "Opening firewall for protocol handlers"; 121 for (auto& handler_config : config_.protocol_handlers) { 122 VLOG(1) << "Firewall request: Protocol Handler = " << handler_config.name 123 << ", Port = " << handler_config.port << ", Interface = " 124 << handler_config.interface_name; 125 firewall_->PunchTcpHoleAsync( 126 handler_config.port, 127 handler_config.interface_name, 128 base::Bind(&OnFirewallSuccess, handler_config.interface_name, 129 handler_config.port), 130 base::Bind(&IgnoreFirewallDBusMethodError)); 131 } 132} 133 134std::string Server::Ping() { 135 return "Web Server is running"; 136} 137 138void Server::ProtocolHandlerStarted(ProtocolHandler* handler) { 139 CHECK(protocol_handler_map_.find(handler) == protocol_handler_map_.end()) 140 << "Protocol handler already registered"; 141 std::string path = base::StringPrintf("/org/chromium/WebServer/Servers/%d", 142 ++last_protocol_handler_index_); 143 dbus::ObjectPath object_path{path}; 144 std::unique_ptr<DBusProtocolHandler> dbus_protocol_handler{ 145 new DBusProtocolHandler{dbus_object_->GetObjectManager().get(), 146 object_path, 147 handler, 148 this} 149 }; 150 protocol_handler_map_.emplace(handler, std::move(dbus_protocol_handler)); 151} 152 153void Server::ProtocolHandlerStopped(ProtocolHandler* handler) { 154 CHECK_EQ(1u, protocol_handler_map_.erase(handler)) 155 << "Unknown protocol handler"; 156} 157 158void Server::CreateProtocolHandler(Config::ProtocolHandler* handler_config) { 159 std::unique_ptr<ProtocolHandler> protocol_handler{ 160 new ProtocolHandler{handler_config->name, this}}; 161 if (protocol_handler->Start(handler_config)) 162 protocol_handlers_.push_back(std::move(protocol_handler)); 163} 164 165void Server::InitTlsData() { 166 if (!TLS_certificate_.empty()) 167 return; // Already initialized. 168 169 // TODO(avakulenko): verify these constants and provide sensible values 170 // for the long-term. See brbug.com/227 171 const int kKeyLengthBits = 1024; 172 const int64_t kOneYearInSeconds = 31556952; // 365.2425 days 173 const base::TimeDelta kCertExpiration = 174 base::TimeDelta::FromSeconds(5 * kOneYearInSeconds); 175 const char kCommonName[] = "Brillo device"; 176 177 const base::FilePath certificate_file{kCertificateFile}; 178 const base::FilePath key_file{kKeyFile}; 179 180 auto cert = LoadAndValidateCertificate(certificate_file); 181 brillo::SecureBlob private_key = 182 LoadAndValidatePrivateKey(key_file, encryptor_); 183 if (!cert || private_key.empty()) { 184 // Create the X509 certificate. 185 LOG(INFO) << "Generating new certificate..."; 186 int cert_serial_number = base::RandInt(0, std::numeric_limits<int>::max()); 187 cert = CreateCertificate(cert_serial_number, kCertExpiration, kCommonName); 188 189 // Create RSA key pair. 190 auto rsa_key_pair = GenerateRSAKeyPair(kKeyLengthBits); 191 192 // Store the private key to a temp buffer. 193 // Do not assign it to |TLS_private_key_| yet until the end when we are sure 194 // everything else has worked out. 195 private_key = StoreRSAPrivateKey(rsa_key_pair.get()); 196 197 // Create EVP key and set it to the certificate. 198 auto key = std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY*)>{EVP_PKEY_new(), 199 EVP_PKEY_free}; 200 CHECK(key.get()); 201 // Transfer ownership of |rsa_key_pair| to |key|. 202 CHECK(EVP_PKEY_assign_RSA(key.get(), rsa_key_pair.release())); 203 CHECK(X509_set_pubkey(cert.get(), key.get())); 204 205 // Sign the certificate. 206 CHECK(X509_sign(cert.get(), key.get(), EVP_sha256())); 207 208 // Save the certificate and private key to disk. 209 StoreCertificate(cert.get(), certificate_file); 210 std::string encrypted_key; 211 encryptor_->EncryptWithAuthentication(private_key.to_string(), 212 &encrypted_key); 213 base::WriteFile(key_file, encrypted_key.data(), encrypted_key.size()); 214 } 215 216 TLS_certificate_ = StoreCertificate(cert.get()); 217 TLS_certificate_fingerprint_ = GetSha256Fingerprint(cert.get()); 218 TLS_private_key_ = std::move(private_key); 219 220 // Update the TLS data in protocol handler config. 221 for (auto& handler_config : config_.protocol_handlers) { 222 if (handler_config.use_tls) { 223 handler_config.certificate = TLS_certificate_; 224 handler_config.certificate_fingerprint = TLS_certificate_fingerprint_; 225 handler_config.private_key = TLS_private_key_; 226 } 227 } 228} 229 230base::FilePath Server::GetUploadDirectory() const { 231 base::FilePath upload_dir; 232#ifdef __ANDROID__ 233 upload_dir = base::FilePath{"/data/misc/webservd/uploads"}; 234#else 235 CHECK(base::GetTempDir(&upload_dir)); 236#endif 237 return upload_dir; 238} 239 240} // namespace webservd 241