• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2015 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "attestation/common/crypto_utility_impl.h"
18 
19 #include <limits>
20 #include <string>
21 
22 #include <arpa/inet.h>
23 #include <base/sha1.h>
24 #include <base/stl_util.h>
25 #include <crypto/scoped_openssl_types.h>
26 #include <crypto/secure_util.h>
27 #include <crypto/sha2.h>
28 #include <openssl/bio.h>
29 #include <openssl/err.h>
30 #include <openssl/evp.h>
31 #include <openssl/hmac.h>
32 #include <openssl/rand.h>
33 #include <openssl/rsa.h>
34 #include <openssl/sha.h>
35 #include <openssl/x509.h>
36 
37 namespace {
38 
39 const size_t kAesKeySize = 32;
40 const size_t kAesBlockSize = 16;
41 
GetOpenSSLError()42 std::string GetOpenSSLError() {
43   BIO* bio = BIO_new(BIO_s_mem());
44   ERR_print_errors(bio);
45   char* data = nullptr;
46   int data_len = BIO_get_mem_data(bio, &data);
47   std::string error_string(data, data_len);
48   BIO_free(bio);
49   return error_string;
50 }
51 
StringAsOpenSSLBuffer(std::string * s)52 unsigned char* StringAsOpenSSLBuffer(std::string* s) {
53   return reinterpret_cast<unsigned char*>(string_as_array(s));
54 }
55 
56 }  // namespace
57 
58 namespace attestation {
59 
CryptoUtilityImpl(TpmUtility * tpm_utility)60 CryptoUtilityImpl::CryptoUtilityImpl(TpmUtility* tpm_utility)
61     : tpm_utility_(tpm_utility) {
62   OpenSSL_add_all_algorithms();
63   ERR_load_crypto_strings();
64 }
65 
~CryptoUtilityImpl()66 CryptoUtilityImpl::~CryptoUtilityImpl() {
67   EVP_cleanup();
68   ERR_free_strings();
69 }
70 
GetRandom(size_t num_bytes,std::string * random_data) const71 bool CryptoUtilityImpl::GetRandom(size_t num_bytes,
72                                   std::string* random_data) const {
73   // OpenSSL takes a signed integer.
74   if (num_bytes > static_cast<size_t>(std::numeric_limits<int>::max())) {
75     return false;
76   }
77   random_data->resize(num_bytes);
78   unsigned char* buffer = StringAsOpenSSLBuffer(random_data);
79   return (RAND_bytes(buffer, num_bytes) == 1);
80 }
81 
CreateSealedKey(std::string * aes_key,std::string * sealed_key)82 bool CryptoUtilityImpl::CreateSealedKey(std::string* aes_key,
83                                         std::string* sealed_key) {
84   if (!GetRandom(kAesKeySize, aes_key)) {
85     LOG(ERROR) << __func__ << ": GetRandom failed.";
86     return false;
87   }
88   if (!tpm_utility_->SealToPCR0(*aes_key, sealed_key)) {
89     LOG(ERROR) << __func__ << ": Failed to seal cipher key.";
90     return false;
91   }
92   return true;
93 }
94 
EncryptData(const std::string & data,const std::string & aes_key,const std::string & sealed_key,std::string * encrypted_data)95 bool CryptoUtilityImpl::EncryptData(const std::string& data,
96                                     const std::string& aes_key,
97                                     const std::string& sealed_key,
98                                     std::string* encrypted_data) {
99   std::string iv;
100   if (!GetRandom(kAesBlockSize, &iv)) {
101     LOG(ERROR) << __func__ << ": GetRandom failed.";
102     return false;
103   }
104   std::string raw_encrypted_data;
105   if (!AesEncrypt(data, aes_key, iv, &raw_encrypted_data)) {
106     LOG(ERROR) << __func__ << ": AES encryption failed.";
107     return false;
108   }
109   EncryptedData encrypted_pb;
110   encrypted_pb.set_wrapped_key(sealed_key);
111   encrypted_pb.set_iv(iv);
112   encrypted_pb.set_encrypted_data(raw_encrypted_data);
113   encrypted_pb.set_mac(HmacSha512(iv + raw_encrypted_data, aes_key));
114   if (!encrypted_pb.SerializeToString(encrypted_data)) {
115     LOG(ERROR) << __func__ << ": Failed to serialize protobuf.";
116     return false;
117   }
118   return true;
119 }
120 
UnsealKey(const std::string & encrypted_data,std::string * aes_key,std::string * sealed_key)121 bool CryptoUtilityImpl::UnsealKey(const std::string& encrypted_data,
122                                   std::string* aes_key,
123                                   std::string* sealed_key) {
124   EncryptedData encrypted_pb;
125   if (!encrypted_pb.ParseFromString(encrypted_data)) {
126     LOG(ERROR) << __func__ << ": Failed to parse protobuf.";
127     return false;
128   }
129   *sealed_key = encrypted_pb.wrapped_key();
130   if (!tpm_utility_->Unseal(*sealed_key, aes_key)) {
131     LOG(ERROR) << __func__ << ": Cannot unseal aes key.";
132     return false;
133   }
134   return true;
135 }
136 
DecryptData(const std::string & encrypted_data,const std::string & aes_key,std::string * data)137 bool CryptoUtilityImpl::DecryptData(const std::string& encrypted_data,
138                                     const std::string& aes_key,
139                                     std::string* data) {
140   EncryptedData encrypted_pb;
141   if (!encrypted_pb.ParseFromString(encrypted_data)) {
142     LOG(ERROR) << __func__ << ": Failed to parse protobuf.";
143     return false;
144   }
145   std::string mac =
146       HmacSha512(encrypted_pb.iv() + encrypted_pb.encrypted_data(), aes_key);
147   if (mac.length() != encrypted_pb.mac().length()) {
148     LOG(ERROR) << __func__ << ": Corrupted data in encrypted pb.";
149     return false;
150   }
151   if (!crypto::SecureMemEqual(mac.data(), encrypted_pb.mac().data(),
152                               mac.length())) {
153     LOG(ERROR) << __func__ << ": Corrupted data in encrypted pb.";
154     return false;
155   }
156   if (!AesDecrypt(encrypted_pb.encrypted_data(), aes_key, encrypted_pb.iv(),
157                   data)) {
158     LOG(ERROR) << __func__ << ": AES decryption failed.";
159     return false;
160   }
161   return true;
162 }
163 
GetRSASubjectPublicKeyInfo(const std::string & public_key,std::string * public_key_info)164 bool CryptoUtilityImpl::GetRSASubjectPublicKeyInfo(
165     const std::string& public_key,
166     std::string* public_key_info) {
167   auto asn1_ptr = reinterpret_cast<const unsigned char*>(public_key.data());
168   crypto::ScopedRSA rsa(
169       d2i_RSAPublicKey(nullptr, &asn1_ptr, public_key.size()));
170   if (!rsa.get()) {
171     LOG(ERROR) << __func__
172                << ": Failed to decode public key: " << GetOpenSSLError();
173     return false;
174   }
175   unsigned char* buffer = nullptr;
176   int length = i2d_RSA_PUBKEY(rsa.get(), &buffer);
177   if (length <= 0) {
178     LOG(ERROR) << __func__
179                << ": Failed to encode public key: " << GetOpenSSLError();
180     return false;
181   }
182   crypto::ScopedOpenSSLBytes scoped_buffer(buffer);
183   public_key_info->assign(reinterpret_cast<char*>(buffer), length);
184   return true;
185 }
186 
GetRSAPublicKey(const std::string & public_key_info,std::string * public_key)187 bool CryptoUtilityImpl::GetRSAPublicKey(const std::string& public_key_info,
188                                         std::string* public_key) {
189   auto asn1_ptr =
190       reinterpret_cast<const unsigned char*>(public_key_info.data());
191   crypto::ScopedRSA rsa(
192       d2i_RSA_PUBKEY(NULL, &asn1_ptr, public_key_info.size()));
193   if (!rsa.get()) {
194     LOG(ERROR) << __func__
195                << ": Failed to decode public key: " << GetOpenSSLError();
196     return false;
197   }
198   unsigned char* buffer = NULL;
199   int length = i2d_RSAPublicKey(rsa.get(), &buffer);
200   if (length <= 0) {
201     LOG(ERROR) << __func__
202                << ": Failed to encode public key: " << GetOpenSSLError();
203     return false;
204   }
205   crypto::ScopedOpenSSLBytes scoped_buffer(buffer);
206   public_key->assign(reinterpret_cast<char*>(buffer), length);
207   return true;
208 }
209 
EncryptIdentityCredential(const std::string & credential,const std::string & ek_public_key_info,const std::string & aik_public_key,EncryptedIdentityCredential * encrypted)210 bool CryptoUtilityImpl::EncryptIdentityCredential(
211     const std::string& credential,
212     const std::string& ek_public_key_info,
213     const std::string& aik_public_key,
214     EncryptedIdentityCredential* encrypted) {
215   const char kAlgAES256 = 9;   // This comes from TPM_ALG_AES256.
216   const char kEncModeCBC = 2;  // This comes from TPM_SYM_MODE_CBC.
217   const char kAsymContentHeader[] = {0, 0,           0, kAlgAES256,
218                                      0, kEncModeCBC, 0, kAesKeySize};
219   const char kSymContentHeader[12] = {};
220 
221   // Generate an AES key and encrypt the credential.
222   std::string aes_key;
223   if (!GetRandom(kAesKeySize, &aes_key)) {
224     LOG(ERROR) << __func__ << ": GetRandom failed.";
225     return false;
226   }
227   std::string encrypted_credential;
228   if (!TssCompatibleEncrypt(credential, aes_key, &encrypted_credential)) {
229     LOG(ERROR) << __func__ << ": Failed to encrypt credential.";
230     return false;
231   }
232 
233   // Construct a TPM_ASYM_CA_CONTENTS structure.
234   std::string asym_header(std::begin(kAsymContentHeader),
235                           std::end(kAsymContentHeader));
236   std::string asym_content =
237       asym_header + aes_key + base::SHA1HashString(aik_public_key);
238 
239   // Encrypt the TPM_ASYM_CA_CONTENTS with the EK public key.
240   auto asn1_ptr =
241       reinterpret_cast<const unsigned char*>(ek_public_key_info.data());
242   crypto::ScopedRSA rsa(
243       d2i_RSA_PUBKEY(NULL, &asn1_ptr, ek_public_key_info.size()));
244   if (!rsa.get()) {
245     LOG(ERROR) << __func__
246                << ": Failed to decode EK public key: " << GetOpenSSLError();
247     return false;
248   }
249   std::string encrypted_asym_content;
250   if (!TpmCompatibleOAEPEncrypt(asym_content, rsa.get(),
251                                 &encrypted_asym_content)) {
252     LOG(ERROR) << __func__ << ": Failed to encrypt with EK public key.";
253     return false;
254   }
255 
256   // Construct a TPM_SYM_CA_ATTESTATION structure.
257   uint32_t length = htonl(encrypted_credential.size());
258   auto length_bytes = reinterpret_cast<const char*>(&length);
259   std::string length_blob(length_bytes, sizeof(uint32_t));
260   std::string sym_header(std::begin(kSymContentHeader),
261                          std::end(kSymContentHeader));
262   std::string sym_content = length_blob + sym_header + encrypted_credential;
263 
264   encrypted->set_asym_ca_contents(encrypted_asym_content);
265   encrypted->set_sym_ca_attestation(sym_content);
266   return true;
267 }
268 
EncryptForUnbind(const std::string & public_key,const std::string & data,std::string * encrypted_data)269 bool CryptoUtilityImpl::EncryptForUnbind(const std::string& public_key,
270                                          const std::string& data,
271                                          std::string* encrypted_data) {
272   // Construct a TPM_BOUND_DATA structure.
273   const char kBoundDataHeader[] = {1, 1, 0, 0, 2 /* TPM_PT_BIND */};
274   std::string header(std::begin(kBoundDataHeader), std::end(kBoundDataHeader));
275   std::string bound_data = header + data;
276 
277   // Encrypt using the TPM_ES_RSAESOAEP_SHA1_MGF1 scheme.
278   auto asn1_ptr = reinterpret_cast<const unsigned char*>(public_key.data());
279   crypto::ScopedRSA rsa(d2i_RSA_PUBKEY(NULL, &asn1_ptr, public_key.size()));
280   if (!rsa.get()) {
281     LOG(ERROR) << __func__
282                << ": Failed to decode public key: " << GetOpenSSLError();
283     return false;
284   }
285   if (!TpmCompatibleOAEPEncrypt(bound_data, rsa.get(), encrypted_data)) {
286     LOG(ERROR) << __func__ << ": Failed to encrypt with public key.";
287     return false;
288   }
289   return true;
290 }
291 
VerifySignature(const std::string & public_key,const std::string & data,const std::string & signature)292 bool CryptoUtilityImpl::VerifySignature(const std::string& public_key,
293                                         const std::string& data,
294                                         const std::string& signature) {
295   auto asn1_ptr = reinterpret_cast<const unsigned char*>(public_key.data());
296   crypto::ScopedRSA rsa(d2i_RSA_PUBKEY(NULL, &asn1_ptr, public_key.size()));
297   if (!rsa.get()) {
298     LOG(ERROR) << __func__
299                << ": Failed to decode public key: " << GetOpenSSLError();
300     return false;
301   }
302   std::string digest = crypto::SHA256HashString(data);
303   auto digest_buffer = reinterpret_cast<const unsigned char*>(digest.data());
304   std::string mutable_signature(signature);
305   unsigned char* signature_buffer = StringAsOpenSSLBuffer(&mutable_signature);
306   return (RSA_verify(NID_sha256, digest_buffer, digest.size(), signature_buffer,
307                      signature.size(), rsa.get()) == 1);
308 }
309 
AesEncrypt(const std::string & data,const std::string & key,const std::string & iv,std::string * encrypted_data)310 bool CryptoUtilityImpl::AesEncrypt(const std::string& data,
311                                    const std::string& key,
312                                    const std::string& iv,
313                                    std::string* encrypted_data) {
314   if (key.size() != kAesKeySize || iv.size() != kAesBlockSize) {
315     return false;
316   }
317   if (data.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
318     // EVP_EncryptUpdate takes a signed int.
319     return false;
320   }
321   std::string mutable_data(data);
322   unsigned char* input_buffer = StringAsOpenSSLBuffer(&mutable_data);
323   std::string mutable_key(key);
324   unsigned char* key_buffer = StringAsOpenSSLBuffer(&mutable_key);
325   std::string mutable_iv(iv);
326   unsigned char* iv_buffer = StringAsOpenSSLBuffer(&mutable_iv);
327   // Allocate enough space for the output (including padding).
328   encrypted_data->resize(data.size() + kAesBlockSize);
329   auto output_buffer =
330       reinterpret_cast<unsigned char*>(string_as_array(encrypted_data));
331   int output_size = 0;
332   const EVP_CIPHER* cipher = EVP_aes_256_cbc();
333   EVP_CIPHER_CTX encryption_context;
334   EVP_CIPHER_CTX_init(&encryption_context);
335   if (!EVP_EncryptInit_ex(&encryption_context, cipher, nullptr, key_buffer,
336                           iv_buffer)) {
337     LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
338     return false;
339   }
340   if (!EVP_EncryptUpdate(&encryption_context, output_buffer, &output_size,
341                          input_buffer, data.size())) {
342     LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
343     EVP_CIPHER_CTX_cleanup(&encryption_context);
344     return false;
345   }
346   size_t total_size = output_size;
347   output_buffer += output_size;
348   output_size = 0;
349   if (!EVP_EncryptFinal_ex(&encryption_context, output_buffer, &output_size)) {
350     LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
351     EVP_CIPHER_CTX_cleanup(&encryption_context);
352     return false;
353   }
354   total_size += output_size;
355   encrypted_data->resize(total_size);
356   EVP_CIPHER_CTX_cleanup(&encryption_context);
357   return true;
358 }
359 
AesDecrypt(const std::string & encrypted_data,const std::string & key,const std::string & iv,std::string * data)360 bool CryptoUtilityImpl::AesDecrypt(const std::string& encrypted_data,
361                                    const std::string& key,
362                                    const std::string& iv,
363                                    std::string* data) {
364   if (key.size() != kAesKeySize || iv.size() != kAesBlockSize) {
365     return false;
366   }
367   if (encrypted_data.size() >
368       static_cast<size_t>(std::numeric_limits<int>::max())) {
369     // EVP_DecryptUpdate takes a signed int.
370     return false;
371   }
372   std::string mutable_encrypted_data(encrypted_data);
373   unsigned char* input_buffer = StringAsOpenSSLBuffer(&mutable_encrypted_data);
374   std::string mutable_key(key);
375   unsigned char* key_buffer = StringAsOpenSSLBuffer(&mutable_key);
376   std::string mutable_iv(iv);
377   unsigned char* iv_buffer = StringAsOpenSSLBuffer(&mutable_iv);
378   // Allocate enough space for the output.
379   data->resize(encrypted_data.size());
380   unsigned char* output_buffer = StringAsOpenSSLBuffer(data);
381   int output_size = 0;
382   const EVP_CIPHER* cipher = EVP_aes_256_cbc();
383   EVP_CIPHER_CTX decryption_context;
384   EVP_CIPHER_CTX_init(&decryption_context);
385   if (!EVP_DecryptInit_ex(&decryption_context, cipher, nullptr, key_buffer,
386                           iv_buffer)) {
387     LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
388     return false;
389   }
390   if (!EVP_DecryptUpdate(&decryption_context, output_buffer, &output_size,
391                          input_buffer, encrypted_data.size())) {
392     LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
393     EVP_CIPHER_CTX_cleanup(&decryption_context);
394     return false;
395   }
396   size_t total_size = output_size;
397   output_buffer += output_size;
398   output_size = 0;
399   if (!EVP_DecryptFinal_ex(&decryption_context, output_buffer, &output_size)) {
400     LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
401     EVP_CIPHER_CTX_cleanup(&decryption_context);
402     return false;
403   }
404   total_size += output_size;
405   data->resize(total_size);
406   EVP_CIPHER_CTX_cleanup(&decryption_context);
407   return true;
408 }
409 
HmacSha512(const std::string & data,const std::string & key)410 std::string CryptoUtilityImpl::HmacSha512(const std::string& data,
411                                           const std::string& key) {
412   unsigned char mac[SHA512_DIGEST_LENGTH];
413   std::string mutable_data(data);
414   unsigned char* data_buffer = StringAsOpenSSLBuffer(&mutable_data);
415   HMAC(EVP_sha512(), key.data(), key.size(), data_buffer, data.size(), mac,
416        nullptr);
417   return std::string(std::begin(mac), std::end(mac));
418 }
419 
TssCompatibleEncrypt(const std::string & input,const std::string & key,std::string * output)420 bool CryptoUtilityImpl::TssCompatibleEncrypt(const std::string& input,
421                                              const std::string& key,
422                                              std::string* output) {
423   CHECK(output);
424   CHECK_EQ(key.size(), kAesKeySize);
425   std::string iv;
426   if (!GetRandom(kAesBlockSize, &iv)) {
427     LOG(ERROR) << __func__ << ": GetRandom failed.";
428     return false;
429   }
430   std::string encrypted;
431   if (!AesEncrypt(input, key, iv, &encrypted)) {
432     LOG(ERROR) << __func__ << ": Encryption failed.";
433     return false;
434   }
435   *output = iv + encrypted;
436   return true;
437 }
438 
TpmCompatibleOAEPEncrypt(const std::string & input,RSA * key,std::string * output)439 bool CryptoUtilityImpl::TpmCompatibleOAEPEncrypt(const std::string& input,
440                                                  RSA* key,
441                                                  std::string* output) {
442   CHECK(output);
443   // The custom OAEP parameter as specified in TPM Main Part 1, Section 31.1.1.
444   const unsigned char oaep_param[4] = {'T', 'C', 'P', 'A'};
445   std::string padded_input;
446   padded_input.resize(RSA_size(key));
447   auto padded_buffer =
448       reinterpret_cast<unsigned char*>(string_as_array(&padded_input));
449   auto input_buffer = reinterpret_cast<const unsigned char*>(input.data());
450   int result = RSA_padding_add_PKCS1_OAEP(padded_buffer, padded_input.size(),
451                                           input_buffer, input.size(),
452                                           oaep_param, arraysize(oaep_param));
453   if (!result) {
454     LOG(ERROR) << __func__
455                << ": Failed to add OAEP padding: " << GetOpenSSLError();
456     return false;
457   }
458   output->resize(padded_input.size());
459   auto output_buffer =
460       reinterpret_cast<unsigned char*>(string_as_array(output));
461   result = RSA_public_encrypt(padded_input.size(), padded_buffer, output_buffer,
462                               key, RSA_NO_PADDING);
463   if (result == -1) {
464     LOG(ERROR) << __func__ << ": Failed to encrypt OAEP padded input: "
465                << GetOpenSSLError();
466     return false;
467   }
468   return true;
469 }
470 
471 }  // namespace attestation
472