• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/utils.h"
16 
17 #include <sys/socket.h>
18 
19 #include <openssl/bio.h>
20 #include <openssl/evp.h>
21 #include <openssl/pem.h>
22 #include <openssl/rsa.h>
23 
24 #include <base/files/file_util.h>
25 #include <base/logging.h>
26 #include <base/strings/string_number_conversions.h>
27 #include <base/time/time.h>
28 
29 namespace webservd {
30 
31 namespace {
32 
33 // Returns the current date/time. This is used for TLS certificate validation
34 // very early in process start when the system clock might not be adjusted
35 // yet on devices that don't have a real-time clock. So, try to get the system
36 // time and if it is earlier than the build date of this executable, use
37 // the build date instead as a lower limit to the date/time.
38 // See http://b/23897170 for more details.
GetTimeNow()39 base::Time GetTimeNow() {
40   base::Time now = base::Time::Now();
41 
42   base::File::Info info;
43   base::FilePath exe_path;
44   if (!base::ReadSymbolicLink(base::FilePath{"/proc/self/exe"}, &exe_path) ||
45       !base::GetFileInfo(exe_path, &info) || info.creation_time < now) {
46     return now;
47   }
48 
49   LOG(WARNING) << "Current time (" << now
50                << ") is earlier than the application build time. Using "
51                << info.creation_time << " instead!";
52   return info.creation_time;
53 }
54 
55 }  // anonymous namespace
56 
CreateCertificate(int serial_number,const base::TimeDelta & cert_expiration,const std::string & common_name)57 X509Ptr CreateCertificate(int serial_number,
58                           const base::TimeDelta& cert_expiration,
59                           const std::string& common_name) {
60   auto cert = X509Ptr{X509_new(), X509_free};
61   CHECK(cert.get());
62   X509_set_version(cert.get(), 2);  // Using X.509 v3 certificate...
63 
64   // Set certificate properties...
65   ASN1_INTEGER* sn = X509_get_serialNumber(cert.get());
66   ASN1_INTEGER_set(sn, serial_number);
67   time_t current_time = GetTimeNow().ToTimeT();
68   X509_time_adj(X509_get_notBefore(cert.get()), 0, &current_time);
69   X509_time_adj(X509_get_notAfter(cert.get()), cert_expiration.InSeconds(),
70                 &current_time);
71 
72   // The issuer is the same as the subject, since this cert is self-signed.
73   X509_NAME* name = X509_get_subject_name(cert.get());
74   if (!common_name.empty()) {
75     X509_NAME_add_entry_by_txt(
76         name, "CN", MBSTRING_UTF8,
77         reinterpret_cast<const unsigned char*>(common_name.c_str()),
78         common_name.length(), -1, 0);
79   }
80   X509_set_issuer_name(cert.get(), name);
81   return cert;
82 }
83 
GenerateRSAKeyPair(int key_length_bits)84 std::unique_ptr<RSA, void(*)(RSA*)> GenerateRSAKeyPair(int key_length_bits) {
85   // Create RSA key pair.
86   auto rsa_key_pair = std::unique_ptr<RSA, void(*)(RSA*)>{RSA_new(), RSA_free};
87   CHECK(rsa_key_pair.get());
88   auto big_num = std::unique_ptr<BIGNUM, void(*)(BIGNUM*)>{BN_new(), BN_free};
89   CHECK(big_num.get());
90   CHECK(BN_set_word(big_num.get(), 65537));
91   CHECK(RSA_generate_key_ex(rsa_key_pair.get(), key_length_bits, big_num.get(),
92                             nullptr));
93   return rsa_key_pair;
94 }
95 
StoreRSAPrivateKey(RSA * rsa_key_pair)96 brillo::SecureBlob StoreRSAPrivateKey(RSA* rsa_key_pair) {
97   auto bio =
98       std::unique_ptr<BIO, void(*)(BIO*)>{BIO_new(BIO_s_mem()), BIO_vfree};
99   CHECK(bio);
100   CHECK(PEM_write_bio_RSAPrivateKey(bio.get(), rsa_key_pair, nullptr, nullptr,
101                                     0, nullptr, nullptr));
102   uint8_t* buffer = nullptr;
103   size_t size = BIO_get_mem_data(bio.get(), reinterpret_cast<char**>(&buffer));
104   CHECK_GT(size, 0u);
105   CHECK(buffer);
106   brillo::SecureBlob key_blob(buffer, buffer + size);
107   brillo::SecureMemset(buffer, 0, size);
108   return key_blob;
109 }
110 
ValidateRSAPrivateKey(const brillo::SecureBlob & key)111 bool ValidateRSAPrivateKey(const brillo::SecureBlob& key) {
112   std::unique_ptr<BIO, void(*)(BIO*)> bio{
113       BIO_new_mem_buf(const_cast<uint8_t*>(key.data()), key.size()), BIO_vfree};
114   std::unique_ptr<RSA, void(*)(RSA*)> rsa_key{
115       PEM_read_bio_RSAPrivateKey(bio.get(), nullptr, nullptr, nullptr),
116       RSA_free};
117   return rsa_key.get() != nullptr;
118 }
119 
StoreCertificate(X509 * cert)120 brillo::Blob StoreCertificate(X509* cert) {
121   auto bio =
122       std::unique_ptr<BIO, void(*)(BIO*)>{BIO_new(BIO_s_mem()), BIO_vfree};
123   CHECK(bio);
124   CHECK(PEM_write_bio_X509(bio.get(), cert));
125   uint8_t* buffer = nullptr;
126   size_t size = BIO_get_mem_data(bio.get(), reinterpret_cast<char**>(&buffer));
127   CHECK_GT(size, 0u);
128   CHECK(buffer);
129   return brillo::Blob(buffer, buffer + size);
130 }
131 
StoreCertificate(X509 * cert,const base::FilePath & file)132 bool StoreCertificate(X509* cert, const base::FilePath& file) {
133   std::unique_ptr<BIO, void(*)(BIO*)> bio{
134       BIO_new_file(file.value().c_str(), "w"), BIO_vfree};
135   return bio && PEM_write_bio_X509(bio.get(), cert) != 0;
136 }
137 
LoadAndValidateCertificate(const base::FilePath & file)138 X509Ptr LoadAndValidateCertificate(const base::FilePath& file) {
139   X509Ptr cert{nullptr, X509_free};
140   std::unique_ptr<BIO, void(*)(BIO*)> bio{
141       BIO_new_file(file.value().c_str(), "r"), BIO_vfree};
142   if (!bio)
143     return cert;
144   LOG(INFO) << "Loading certificate from " << file.value();
145   cert.reset(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
146   if (cert) {
147     // Regenerate certificate 30 days before it expires.
148     time_t deadline = (GetTimeNow() + base::TimeDelta::FromDays(30)).ToTimeT();
149     if (X509_cmp_time(X509_get_notAfter(cert.get()), &deadline) < 0) {
150       LOG(WARNING) << "Certificate is expiring soon. Regenerating new one.";
151       cert.reset();
152     }
153   }
154   return cert;
155 }
156 
157 // Same as openssl x509 -fingerprint -sha256.
GetSha256Fingerprint(X509 * cert)158 brillo::Blob GetSha256Fingerprint(X509* cert) {
159   brillo::Blob fingerprint(256 / 8);
160   uint32_t len = 0;
161   CHECK(X509_digest(cert, EVP_sha256(), fingerprint.data(), &len));
162   CHECK_EQ(len, fingerprint.size());
163   return fingerprint;
164 }
165 
CreateNetworkInterfaceSocket(const std::string & if_name)166 int CreateNetworkInterfaceSocket(const std::string& if_name) {
167   // The following is basically the steps libmicrohttpd normally takes
168   // when creating a new listening socket and binding it to a port.
169   int socket_fd = socket(PF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
170   if (socket_fd < 0 && errno == EINVAL)
171     socket_fd = socket(PF_INET6, SOCK_STREAM, 0);
172   if (socket_fd < 0) {
173     PLOG(ERROR) << "Unable to create a listening socket";
174     return -1;
175   }
176 
177   // Now, specify that we want this socket to bind only to a particular
178   // network interface. Note, this call requires root privileges, so this
179   // should be done before the privileges are dropped.
180   if (setsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE,
181                  if_name.c_str(), if_name.size()) < 0) {
182     PLOG(WARNING) << "Failed to bind socket (SO_BINDTODEVICE) to " << if_name;
183     close(socket_fd);
184     return -1;
185   }
186   return socket_fd;
187 }
188 
189 }  // namespace webservd
190