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