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, ¤t_time);
69 X509_time_adj(X509_get_notAfter(cert.get()), cert_expiration.InSeconds(),
70 ¤t_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