1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <string>
6 
7 #include "base/containers/span.h"
8 #include "base/hash/hash.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/rand_util.h"
11 #include "base/strings/strcat.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h"
14 #include "base/task/post_task.h"
15 #include "base/task_runner.h"
16 #include "chrome/browser/policy/messaging_layer/encryption/decryption.h"
17 #include "chrome/browser/policy/messaging_layer/encryption/encryption.h"
18 #include "chrome/browser/policy/messaging_layer/util/status.h"
19 #include "chrome/browser/policy/messaging_layer/util/statusor.h"
20 #include "crypto/aead.h"
21 #include "crypto/openssl_util.h"
22 #include "third_party/boringssl/src/include/openssl/curve25519.h"
23 #include "third_party/boringssl/src/include/openssl/digest.h"
24 #include "third_party/boringssl/src/include/openssl/hkdf.h"
25 
26 namespace reporting {
27 
Handle(base::StringPiece shared_secret,scoped_refptr<Decryptor> decryptor)28 Decryptor::Handle::Handle(base::StringPiece shared_secret,
29                           scoped_refptr<Decryptor> decryptor)
30     : shared_secret_(shared_secret), decryptor_(decryptor) {}
31 
32 Decryptor::Handle::~Handle() = default;
33 
AddToRecord(base::StringPiece data,base::OnceCallback<void (Status)> cb)34 void Decryptor::Handle::AddToRecord(base::StringPiece data,
35                                     base::OnceCallback<void(Status)> cb) {
36   // Add piece of data to the record.
37   record_.append(data.data(), data.size());
38   std::move(cb).Run(Status::StatusOK());
39 }
40 
CloseRecord(base::OnceCallback<void (StatusOr<base::StringPiece>)> cb)41 void Decryptor::Handle::CloseRecord(
42     base::OnceCallback<void(StatusOr<base::StringPiece>)> cb) {
43   // Make sure the record self-destructs when returning from this method.
44   const auto self_destruct = base::WrapUnique(this);
45 
46   // Decrypt the data with symmetric key using AEAD interface.
47   crypto::Aead aead(crypto::Aead::CHACHA20_POLY1305);
48 
49   // Produce symmetric key from shared secret using HKDF.
50   // Since the original keys were only used once, no salt and context is needed.
51   const auto out_symmetric_key = std::make_unique<uint8_t[]>(aead.KeyLength());
52   if (!HKDF(out_symmetric_key.get(), aead.KeyLength(), /*digest=*/EVP_sha256(),
53             reinterpret_cast<const uint8_t*>(shared_secret_.data()),
54             shared_secret_.size(),
55             /*salt=*/nullptr, /*salt_len=*/0,
56             /*info=*/nullptr, /*info_len=*/0)) {
57     std::move(cb).Run(
58         Status(error::INTERNAL, "Symmetric key extraction failed"));
59     return;
60   }
61 
62   // Use the symmetric key for data decryption.
63   aead.Init(base::make_span(out_symmetric_key.get(), aead.KeyLength()));
64 
65   // Set nonce to 0s, since a symmetric key is only used once.
66   // Note: if we ever start reusing the same symmetric key, we will need
67   // to generate new nonce for every record and transfer it to the peer.
68   std::string nonce(aead.NonceLength(), 0);
69 
70   // Decrypt collected record.
71   std::string decrypted;
72   if (!aead.Open(record_, nonce, std::string(), &decrypted)) {
73     std::move(cb).Run(Status(error::INTERNAL, "Failed to decrypt"));
74     return;
75   }
76   record_.clear();  // Free unused memory.
77 
78   // Return decrypted record.
79   std::move(cb).Run(decrypted);
80 }
81 
OpenRecord(base::StringPiece shared_secret,base::OnceCallback<void (StatusOr<Handle * >)> cb)82 void Decryptor::OpenRecord(base::StringPiece shared_secret,
83                            base::OnceCallback<void(StatusOr<Handle*>)> cb) {
84   std::move(cb).Run(new Handle(shared_secret, this));
85 }
86 
DecryptSecret(base::StringPiece private_key,base::StringPiece peer_public_value)87 StatusOr<std::string> Decryptor::DecryptSecret(
88     base::StringPiece private_key,
89     base::StringPiece peer_public_value) {
90   // Verify the keys.
91   if (private_key.size() != X25519_PRIVATE_KEY_LEN) {
92     return Status(
93         error::FAILED_PRECONDITION,
94         base::StrCat({"Private key size mismatch, expected=",
95                       base::NumberToString(X25519_PRIVATE_KEY_LEN),
96                       " actual=", base::NumberToString(private_key.size())}));
97   }
98   if (peer_public_value.size() != X25519_PUBLIC_VALUE_LEN) {
99     return Status(
100         error::FAILED_PRECONDITION,
101         base::StrCat({"Public key size mismatch, expected=",
102                       base::NumberToString(X25519_PUBLIC_VALUE_LEN), " actual=",
103                       base::NumberToString(peer_public_value.size())}));
104   }
105 
106   // Compute shared secret.
107   uint8_t out_shared_value[X25519_SHARED_KEY_LEN];
108   if (!X25519(out_shared_value,
109               reinterpret_cast<const uint8_t*>(private_key.data()),
110               reinterpret_cast<const uint8_t*>(peer_public_value.data()))) {
111     return Status(error::DATA_LOSS, "Curve25519 decryption failed");
112   }
113 
114   return std::string(reinterpret_cast<const char*>(out_shared_value),
115                      X25519_SHARED_KEY_LEN);
116 }
117 
Decryptor()118 Decryptor::Decryptor()
119     : keys_sequenced_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
120           {base::TaskPriority::BEST_EFFORT, base::MayBlock()})) {
121   DETACH_FROM_SEQUENCE(keys_sequence_checker_);
122 }
123 
124 Decryptor::~Decryptor() = default;
125 
RecordKeyPair(base::StringPiece private_key,base::StringPiece public_key,base::OnceCallback<void (StatusOr<Encryptor::PublicKeyId>)> cb)126 void Decryptor::RecordKeyPair(
127     base::StringPiece private_key,
128     base::StringPiece public_key,
129     base::OnceCallback<void(StatusOr<Encryptor::PublicKeyId>)> cb) {
130   // Schedule key recording on the sequenced task runner.
131   keys_sequenced_task_runner_->PostTask(
132       FROM_HERE,
133       base::BindOnce(
134           [](std::string public_key, KeyInfo key_info,
135              base::OnceCallback<void(StatusOr<Encryptor::PublicKeyId>)> cb,
136              scoped_refptr<Decryptor> decryptor) {
137             DCHECK_CALLED_ON_VALID_SEQUENCE(decryptor->keys_sequence_checker_);
138             StatusOr<Encryptor::PublicKeyId> result;
139             if (key_info.private_key.size() != X25519_PRIVATE_KEY_LEN) {
140               result = Status(
141                   error::FAILED_PRECONDITION,
142                   base::StrCat(
143                       {"Private key size mismatch, expected=",
144                        base::NumberToString(X25519_PRIVATE_KEY_LEN), " actual=",
145                        base::NumberToString(key_info.private_key.size())}));
146             } else if (public_key.size() != X25519_PUBLIC_VALUE_LEN) {
147               result = Status(
148                   error::FAILED_PRECONDITION,
149                   base::StrCat(
150                       {"Public key size mismatch, expected=",
151                        base::NumberToString(X25519_PUBLIC_VALUE_LEN),
152                        " actual=", base::NumberToString(public_key.size())}));
153             } else {
154               // Assign a random number to be public key id for testing purposes
155               // only (in production it will be Java Fingerprint2011 which is
156               // 'long').
157               Encryptor::PublicKeyId public_key_id;
158               base::RandBytes(&public_key_id, sizeof(public_key_id));
159               if (!decryptor->keys_.emplace(public_key_id, key_info).second) {
160                 result = Status(error::ALREADY_EXISTS,
161                                 base::StrCat({"Public key='", public_key,
162                                               "' already recorded"}));
163               } else {
164                 result = public_key_id;
165               }
166             }
167             // Schedule response on a generic thread pool.
168             base::ThreadPool::PostTask(
169                 FROM_HERE, base::BindOnce(
170                                [](base::OnceCallback<void(
171                                       StatusOr<Encryptor::PublicKeyId>)> cb,
172                                   StatusOr<Encryptor::PublicKeyId> result) {
173                                  std::move(cb).Run(result);
174                                },
175                                std::move(cb), result));
176           },
177           std::string(public_key),
178           KeyInfo{.private_key = std::string(private_key),
179                   .time_stamp = base::Time::Now()},
180           std::move(cb), base::WrapRefCounted(this)));
181 }
182 
RetrieveMatchingPrivateKey(Encryptor::PublicKeyId public_key_id,base::OnceCallback<void (StatusOr<std::string>)> cb)183 void Decryptor::RetrieveMatchingPrivateKey(
184     Encryptor::PublicKeyId public_key_id,
185     base::OnceCallback<void(StatusOr<std::string>)> cb) {
186   // Schedule key retrieval on the sequenced task runner.
187   keys_sequenced_task_runner_->PostTask(
188       FROM_HERE,
189       base::BindOnce(
190           [](Encryptor::PublicKeyId public_key_id,
191              base::OnceCallback<void(StatusOr<std::string>)> cb,
192              scoped_refptr<Decryptor> decryptor) {
193             DCHECK_CALLED_ON_VALID_SEQUENCE(decryptor->keys_sequence_checker_);
194             auto key_info_it = decryptor->keys_.find(public_key_id);
195             if (key_info_it != decryptor->keys_.end()) {
196               DCHECK_EQ(key_info_it->second.private_key.size(),
197                         static_cast<size_t>(X25519_PRIVATE_KEY_LEN));
198             }
199             // Schedule response on a generic thread pool.
200             base::ThreadPool::PostTask(
201                 FROM_HERE,
202                 base::BindOnce(
203                     [](base::OnceCallback<void(StatusOr<std::string>)> cb,
204                        StatusOr<std::string> result) {
205                       std::move(cb).Run(result);
206                     },
207                     std::move(cb),
208                     key_info_it == decryptor->keys_.end()
209                         ? StatusOr<std::string>(Status(
210                               error::NOT_FOUND, "Matching key not found"))
211                         : key_info_it->second.private_key));
212           },
213           public_key_id, std::move(cb), base::WrapRefCounted(this)));
214 }
215 
Create()216 StatusOr<scoped_refptr<Decryptor>> Decryptor::Create() {
217   // Make sure OpenSSL is initialized, in order to avoid data races later.
218   crypto::EnsureOpenSSLInit();
219   return base::WrapRefCounted(new Decryptor());
220 }
221 
222 }  // namespace reporting
223