Home | History | Annotate | Download | only in trunks
      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 "trunks/session_manager_impl.h"
     18 
     19 #include <string>
     20 
     21 #include <base/logging.h>
     22 #include <base/stl_util.h>
     23 #include <crypto/openssl_util.h>
     24 #include <openssl/bio.h>
     25 #include <openssl/bn.h>
     26 #include <openssl/err.h>
     27 #include <openssl/evp.h>
     28 #if defined(OPENSSL_IS_BORINGSSL)
     29 #include <openssl/mem.h>
     30 #endif
     31 #include <openssl/rand.h>
     32 #include <openssl/rsa.h>
     33 
     34 #include "trunks/error_codes.h"
     35 #include "trunks/tpm_generated.h"
     36 #include "trunks/tpm_utility.h"
     37 
     38 namespace {
     39 const size_t kWellKnownExponent = 0x10001;
     40 
     41 std::string GetOpenSSLError() {
     42   BIO* bio = BIO_new(BIO_s_mem());
     43   ERR_print_errors(bio);
     44   char* data = nullptr;
     45   int data_len = BIO_get_mem_data(bio, &data);
     46   std::string error_string(data, data_len);
     47   BIO_free(bio);
     48   return error_string;
     49 }
     50 }  // namespace
     51 
     52 namespace trunks {
     53 
     54 SessionManagerImpl::SessionManagerImpl(const TrunksFactory& factory)
     55     : factory_(factory), session_handle_(kUninitializedHandle) {
     56   crypto::EnsureOpenSSLInit();
     57 }
     58 
     59 SessionManagerImpl::~SessionManagerImpl() {
     60   CloseSession();
     61 }
     62 
     63 void SessionManagerImpl::CloseSession() {
     64   if (session_handle_ == kUninitializedHandle) {
     65     return;
     66   }
     67   TPM_RC result = factory_.GetTpm()->FlushContextSync(session_handle_, nullptr);
     68   if (result != TPM_RC_SUCCESS) {
     69     LOG(WARNING) << "Error closing tpm session: " << GetErrorString(result);
     70   }
     71   session_handle_ = kUninitializedHandle;
     72 }
     73 
     74 TPM_RC SessionManagerImpl::StartSession(
     75     TPM_SE session_type,
     76     TPMI_DH_ENTITY bind_entity,
     77     const std::string& bind_authorization_value,
     78     bool enable_encryption,
     79     HmacAuthorizationDelegate* delegate) {
     80   CHECK(delegate);
     81   // If we already have an active session, close it.
     82   CloseSession();
     83 
     84   std::string salt(SHA256_DIGEST_SIZE, 0);
     85   unsigned char* salt_buffer =
     86       reinterpret_cast<unsigned char*>(base::string_as_array(&salt));
     87   CHECK_EQ(RAND_bytes(salt_buffer, salt.size()), 1)
     88       << "Error generating a cryptographically random salt.";
     89   // First we encrypt the cryptographically secure salt using PKCS1_OAEP
     90   // padded RSA public key encryption. This is specified in TPM2.0
     91   // Part1 Architecture, Appendix B.10.2.
     92   std::string encrypted_salt;
     93   TPM_RC salt_result = EncryptSalt(salt, &encrypted_salt);
     94   if (salt_result != TPM_RC_SUCCESS) {
     95     LOG(ERROR) << "Error encrypting salt: " << GetErrorString(salt_result);
     96     return salt_result;
     97   }
     98 
     99   TPM2B_ENCRYPTED_SECRET encrypted_secret =
    100       Make_TPM2B_ENCRYPTED_SECRET(encrypted_salt);
    101   // Then we use TPM2_StartAuthSession to start a HMAC session with the TPM.
    102   // The tpm returns the tpm_nonce and the session_handle referencing the
    103   // created session.
    104   TPMI_ALG_HASH hash_algorithm = TPM_ALG_SHA256;
    105   TPMT_SYM_DEF symmetric_algorithm;
    106   symmetric_algorithm.algorithm = TPM_ALG_AES;
    107   symmetric_algorithm.key_bits.aes = 128;
    108   symmetric_algorithm.mode.aes = TPM_ALG_CFB;
    109 
    110   TPM2B_NONCE nonce_caller;
    111   TPM2B_NONCE nonce_tpm;
    112   // We use sha1_digest_size here because that is the minimum length
    113   // needed for the nonce.
    114   nonce_caller.size = SHA1_DIGEST_SIZE;
    115   CHECK_EQ(RAND_bytes(nonce_caller.buffer, nonce_caller.size), 1)
    116       << "Error generating a cryptographically random nonce.";
    117 
    118   Tpm* tpm = factory_.GetTpm();
    119   // The TPM2 command below needs no authorization. This is why we can use
    120   // the empty string "", when referring to the handle names for the salting
    121   // key and the bind entity.
    122   TPM_RC tpm_result = tpm->StartAuthSessionSync(
    123       kSaltingKey,
    124       "",  // salt_handle_name.
    125       bind_entity,
    126       "",  // bind_entity_name.
    127       nonce_caller, encrypted_secret, session_type, symmetric_algorithm,
    128       hash_algorithm, &session_handle_, &nonce_tpm,
    129       nullptr);  // No Authorization.
    130   if (tpm_result) {
    131     LOG(ERROR) << "Error creating an authorization session: "
    132                << GetErrorString(tpm_result);
    133     return tpm_result;
    134   }
    135   bool hmac_result =
    136       delegate->InitSession(session_handle_, nonce_tpm, nonce_caller, salt,
    137                             bind_authorization_value, enable_encryption);
    138   if (!hmac_result) {
    139     LOG(ERROR) << "Failed to initialize an authorization session delegate.";
    140     return TPM_RC_FAILURE;
    141   }
    142   return TPM_RC_SUCCESS;
    143 }
    144 
    145 TPM_RC SessionManagerImpl::EncryptSalt(const std::string& salt,
    146                                        std::string* encrypted_salt) {
    147   TPM2B_NAME out_name;
    148   TPM2B_NAME qualified_name;
    149   TPM2B_PUBLIC public_data;
    150   public_data.public_area.unique.rsa.size = 0;
    151   TPM_RC result = factory_.GetTpm()->ReadPublicSync(
    152       kSaltingKey, "" /*object_handle_name (not used)*/, &public_data,
    153       &out_name, &qualified_name, nullptr /*authorization_delegate*/);
    154   if (result != TPM_RC_SUCCESS) {
    155     LOG(ERROR) << "Error fetching salting key public info: "
    156                << GetErrorString(result);
    157     return result;
    158   }
    159   if (public_data.public_area.type != TPM_ALG_RSA ||
    160       public_data.public_area.unique.rsa.size != 256) {
    161     LOG(ERROR) << "Invalid salting key attributes.";
    162     return TRUNKS_RC_SESSION_SETUP_ERROR;
    163   }
    164   bssl::UniquePtr<RSA> salting_key_rsa(RSA_new());
    165   salting_key_rsa->e = BN_new();
    166   if (!salting_key_rsa->e) {
    167     LOG(ERROR) << "Error creating exponent for RSA: " << GetOpenSSLError();
    168     return TRUNKS_RC_SESSION_SETUP_ERROR;
    169   }
    170   BN_set_word(salting_key_rsa->e, kWellKnownExponent);
    171   salting_key_rsa->n =
    172       BN_bin2bn(public_data.public_area.unique.rsa.buffer,
    173                 public_data.public_area.unique.rsa.size, nullptr);
    174   if (!salting_key_rsa->n) {
    175     LOG(ERROR) << "Error setting public area of rsa key: " << GetOpenSSLError();
    176     return TRUNKS_RC_SESSION_SETUP_ERROR;
    177   }
    178   bssl::UniquePtr<EVP_PKEY> salting_key(EVP_PKEY_new());
    179   if (!EVP_PKEY_set1_RSA(salting_key.get(), salting_key_rsa.get())) {
    180     LOG(ERROR) << "Error setting up EVP_PKEY: " << GetOpenSSLError();
    181     return TRUNKS_RC_SESSION_SETUP_ERROR;
    182   }
    183   // Label for RSAES-OAEP. Defined in TPM2.0 Part1 Architecture,
    184   // Appendix B.10.2.
    185   const size_t kOaepLabelSize = 7;
    186   const char kOaepLabelValue[] = "SECRET\0";
    187   // EVP_PKEY_CTX_set0_rsa_oaep_label takes ownership so we need to malloc.
    188   uint8_t* oaep_label = static_cast<uint8_t*>(OPENSSL_malloc(kOaepLabelSize));
    189   memcpy(oaep_label, kOaepLabelValue, kOaepLabelSize);
    190   bssl::UniquePtr<EVP_PKEY_CTX> salt_encrypt_context(
    191       EVP_PKEY_CTX_new(salting_key.get(), nullptr));
    192   if (!EVP_PKEY_encrypt_init(salt_encrypt_context.get()) ||
    193       !EVP_PKEY_CTX_set_rsa_padding(salt_encrypt_context.get(),
    194                                     RSA_PKCS1_OAEP_PADDING) ||
    195       !EVP_PKEY_CTX_set_rsa_oaep_md(salt_encrypt_context.get(), EVP_sha256()) ||
    196       !EVP_PKEY_CTX_set_rsa_mgf1_md(salt_encrypt_context.get(), EVP_sha256()) ||
    197       !EVP_PKEY_CTX_set0_rsa_oaep_label(salt_encrypt_context.get(), oaep_label,
    198                                         kOaepLabelSize)) {
    199     LOG(ERROR) << "Error setting up salt encrypt context: "
    200                << GetOpenSSLError();
    201     return TRUNKS_RC_SESSION_SETUP_ERROR;
    202   }
    203   size_t out_length = EVP_PKEY_size(salting_key.get());
    204   encrypted_salt->resize(out_length);
    205   if (!EVP_PKEY_encrypt(
    206           salt_encrypt_context.get(),
    207           reinterpret_cast<uint8_t*>(base::string_as_array(encrypted_salt)),
    208           &out_length, reinterpret_cast<const uint8_t*>(salt.data()),
    209           salt.size())) {
    210     LOG(ERROR) << "Error encrypting salt: " << GetOpenSSLError();
    211     return TRUNKS_RC_SESSION_SETUP_ERROR;
    212   }
    213   encrypted_salt->resize(out_length);
    214   return TPM_RC_SUCCESS;
    215 }
    216 
    217 }  // namespace trunks
    218