Botan  2.14.0
Crypto and TLS for C++11
tpm.cpp
Go to the documentation of this file.
1 /*
2 * TPM 1.2 interface
3 * (C) 2015 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/tpm.h>
9 #include <botan/rsa.h>
10 #include <botan/hash.h>
11 #include <botan/hash_id.h>
12 #include <botan/der_enc.h>
13 #include <botan/workfactor.h>
14 #include <botan/pk_ops.h>
15 #include <sstream>
16 
17 #include <tss/platform.h>
18 #include <tss/tspi.h>
19 #include <trousers/trousers.h>
20 
21 // TODO: dynamically load the TPM libraries?
22 
23 namespace Botan {
24 
25 namespace {
26 
27 void tss_error(TSS_RESULT res, const char* expr, const char* file, int line)
28  {
29  std::ostringstream err;
30  err << "TPM error " << Trspi_Error_String(res)
31  << " layer " << Trspi_Error_Layer(res)
32  << " in " << expr << " at " << file << ":" << line;
33 
34  throw TPM_Error(err.str());
35  }
36 
37 TSS_FLAG bit_flag(size_t bits)
38  {
39  switch(bits)
40  {
41  // 512 supported, but ignored and rejected here
42  case 1024:
43  return TSS_KEY_SIZE_1024;
44  case 2048:
45  return TSS_KEY_SIZE_2048;
46 
47  // Most? v1.2 TPMs only support 1024 and 2048 bit keys ...
48  case 4096:
49  return TSS_KEY_SIZE_4096;
50  case 8192:
51  return TSS_KEY_SIZE_8192;
52  case 16384:
53  return TSS_KEY_SIZE_16384;
54  default:
55  throw Invalid_Argument("Unsupported TPM key size " + std::to_string(bits));
56  }
57  }
58 
59 #if 0
60 bool is_srk_uuid(const UUID& uuid)
61  {
62  static const uint8_t srk[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
63  const std::vector<uint8_t>& b = uuid.binary_value();
64  return (b.size() == 16 && same_mem(b.data(), srk, 16));
65  }
66 #endif
67 
68 #define TSPI_CHECK_SUCCESS(expr) do { \
69  TSS_RESULT res = expr; \
70  if(res != TSS_SUCCESS) \
71  tss_error(res, #expr, __FILE__, __LINE__); \
72  } while(0)
73 
74 std::vector<uint8_t> get_obj_attr(TSS_HCONTEXT ctx,
75  TSS_HOBJECT obj,
76  TSS_FLAG flag,
77  TSS_FLAG sub_flag)
78  {
79  BYTE *data = nullptr;
80  UINT32 data_len = 0;
81  TSPI_CHECK_SUCCESS(::Tspi_GetAttribData(obj, flag, sub_flag, &data_len, &data));
82 
83  std::vector<uint8_t> r(data, data + data_len);
84 
85  TSPI_CHECK_SUCCESS(::Tspi_Context_FreeMemory(ctx, data));
86 
87  return r;
88  }
89 
90 void set_policy_secret(TSS_HPOLICY policy, const char* secret)
91  {
92  if(secret)
93  {
94  BYTE* as_b = const_cast<BYTE*>(reinterpret_cast<const BYTE*>(secret));
95  TSPI_CHECK_SUCCESS(::Tspi_Policy_SetSecret(policy,
96  TSS_SECRET_MODE_PLAIN,
97  std::strlen(secret),
98  as_b));
99  }
100  else
101  {
102  static const uint8_t nullpass[20] = { 0 };
103 
104  TSPI_CHECK_SUCCESS(::Tspi_Policy_SetSecret(policy,
105  TSS_SECRET_MODE_SHA1,
106  sizeof(nullpass),
107  const_cast<BYTE*>(nullpass)));
108  }
109  }
110 
111 TSS_UUID to_tss_uuid(const UUID& uuid)
112  {
113  static_assert(sizeof(TSS_UUID) == 16, "Expected size of packed UUID");
114 
115  TSS_UUID tss_uuid;
116  typecast_copy(tss_uuid, uuid.binary_value().data());
117  return tss_uuid;
118  }
119 
120 UUID from_tss_uuid(const TSS_UUID& tss_uuid)
121  {
122  static_assert(sizeof(TSS_UUID) == 16, "Expected size of packed UUID");
123 
124  std::vector<uint8_t> mem(16);
125  typecast_copy(mem.data(), tss_uuid);
126  UUID uuid(std::move(mem));
127  return uuid;
128  }
129 
130 TPM_Storage_Type storage_type_from_tss_flag(TSS_FLAG flag)
131  {
132  if(flag == TSS_PS_TYPE_USER)
133  return TPM_Storage_Type::User;
134  else if(flag == TSS_PS_TYPE_SYSTEM)
136  else
137  throw TPM_Error("Invalid storage flag " + std::to_string(flag));
138  }
139 
140 std::string format_url(const UUID& uuid, TPM_Storage_Type storage)
141  {
142  std::string storage_str = (storage == TPM_Storage_Type::User) ? "user" : "system";
143  return "tpmkey:uuid=" + uuid.to_string() + ";storage=" + storage_str;
144  }
145 
146 std::string format_url(const TSS_UUID& tss_uuid, TSS_FLAG store_type)
147  {
148  UUID uuid = from_tss_uuid(tss_uuid);
149 
150  return format_url(from_tss_uuid(tss_uuid),
151  storage_type_from_tss_flag(store_type));
152  }
153 
154 }
155 
156 TPM_Context::TPM_Context(pin_cb cb, const char* srk_password) :
157  m_pin_cb(cb),
158  m_srk_policy(0)
159  {
160  TSPI_CHECK_SUCCESS(::Tspi_Context_Create(&m_ctx));
161  TSPI_CHECK_SUCCESS(::Tspi_Context_Connect(m_ctx, nullptr));
162 
163  TSPI_CHECK_SUCCESS(::Tspi_Context_GetTpmObject(m_ctx, &m_tpm));
164 
165  const TSS_UUID SRK_UUID = TSS_UUID_SRK;
166 
167  TSPI_CHECK_SUCCESS(::Tspi_Context_LoadKeyByUUID(m_ctx, TSS_PS_TYPE_SYSTEM, SRK_UUID, &m_srk));
168 
169  TSPI_CHECK_SUCCESS(::Tspi_GetPolicyObject(m_srk, TSS_POLICY_USAGE, &m_srk_policy));
170  set_policy_secret(m_srk_policy, srk_password);
171 
172  // TODO: do we have to cache it?
173  // TODO: try to use SRK with null, if it fails call the pin cb?
174  }
175 
177  {
178  TSPI_CHECK_SUCCESS(::Tspi_Context_CloseObject(m_ctx, m_srk));
179  //TSPI_CHECK_SUCCESS(::Tspi_Context_CloseObject(m_ctx, m_tpm));
180  TSPI_CHECK_SUCCESS(::Tspi_Context_Close(m_srk_policy));
181  TSPI_CHECK_SUCCESS(::Tspi_Context_Close(m_ctx));
182  }
183 
185  {
186  uint32_t r = 0;
187  TSPI_CHECK_SUCCESS(::Tspi_TPM_ReadCounter(m_tpm, &r));
188  return r;
189  }
190 
191 void TPM_Context::gen_random(uint8_t out[], size_t out_len)
192  {
193  BYTE* mem;
194  TSPI_CHECK_SUCCESS(::Tspi_TPM_GetRandom(m_tpm, out_len, &mem));
195  copy_mem(out, reinterpret_cast<const uint8_t*>(mem), out_len);
196  TSPI_CHECK_SUCCESS(::Tspi_Context_FreeMemory(m_ctx, mem));
197  }
198 
199 void TPM_Context::stir_random(const uint8_t in[], size_t in_len)
200  {
201  TSPI_CHECK_SUCCESS(::Tspi_TPM_StirRandom(m_tpm, in_len, const_cast<BYTE*>(in)));
202  }
203 
205  const char* key_password) : m_ctx(ctx)
206  {
207  // TODO: can also do OAEP decryption via binding keys
208  // TODO: offer signing, binding (decrypt), or legacy (sign + decrypt) keys?
209 
210  TSS_FLAG key_flags = bit_flag(bits) | TSS_KEY_VOLATILE | TSS_KEY_TYPE_SIGNING;
211 
212  TSS_HKEY key;
213  TSPI_CHECK_SUCCESS(::Tspi_Context_CreateObject(m_ctx.handle(), TSS_OBJECT_TYPE_RSAKEY, key_flags, &key));
214 
215  TSPI_CHECK_SUCCESS(::Tspi_SetAttribUint32(key, TSS_TSPATTRIB_KEY_INFO,
216  TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
217  TSS_SS_RSASSAPKCS1V15_DER));
218 
219  TSS_HPOLICY policy;
220  TSPI_CHECK_SUCCESS(::Tspi_Context_CreateObject(m_ctx.handle(), TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &policy));
221  set_policy_secret(policy, key_password);
222  TSPI_CHECK_SUCCESS(::Tspi_Policy_AssignToObject(policy, key));
223 
224  TSPI_CHECK_SUCCESS(::Tspi_Key_CreateKey(key, ctx.srk(), 0));
225  m_key = key;
226  }
227 
228 // reference a registered TPM key
229 TPM_PrivateKey::TPM_PrivateKey(TPM_Context& ctx, const std::string& uuid_str,
230  TPM_Storage_Type storage_type) :
231  m_ctx(ctx),
232  m_uuid(uuid_str),
233  m_storage(storage_type)
234  {
235  const TSS_FLAG key_ps_type =
236  (m_storage == TPM_Storage_Type::User) ? TSS_PS_TYPE_USER : TSS_PS_TYPE_SYSTEM;
237 
238  TSPI_CHECK_SUCCESS(::Tspi_Context_LoadKeyByUUID(m_ctx.handle(),
239  key_ps_type,
240  to_tss_uuid(m_uuid),
241  &m_key));
242  }
243 
245  const std::vector<uint8_t>& blob) : m_ctx(ctx)
246  {
247  TSPI_CHECK_SUCCESS(::Tspi_Context_LoadKeyByBlob(m_ctx.handle(), m_ctx.srk(), blob.size(),
248  const_cast<uint8_t*>(blob.data()),
249  &m_key));
250 
251  //TSPI_CHECK_SUCCESS(::Tspi_Key_LoadKey(m_key, m_ctx.srk()));
252  }
253 
255  {
256  if(!m_uuid.is_valid())
257  {
258  TPM_RNG rng(ctx()); // use system_rng or arg RNG& instead?
259  m_uuid = UUID(rng);
260  m_storage = storage_type;
261 
262  const TSS_UUID key_uuid = to_tss_uuid(m_uuid);
263  const TSS_FLAG key_ps_type =
264  (storage_type == TPM_Storage_Type::User) ? TSS_PS_TYPE_USER : TSS_PS_TYPE_SYSTEM;
265 
266  const TSS_UUID srk_uuid = TSS_UUID_SRK;
267 
268  TSPI_CHECK_SUCCESS(::Tspi_Context_RegisterKey(m_ctx.handle(),
269  m_key,
270  key_ps_type,
271  key_uuid,
272  TSS_PS_TYPE_SYSTEM,
273  srk_uuid));
274 
275  }
276 
277  // Presumably we could re-register in the other store and same UUID
278  // Doesn't seem like what is desired most of the time here
279  if(storage_type != m_storage)
280  {
281  throw TPM_Error("TPM key " + m_uuid.to_string() +
282  " already registered with different storage type");
283  }
284 
285  return format_url(m_uuid, m_storage);
286  }
287 
288 std::vector<std::string> TPM_PrivateKey::registered_keys(TPM_Context& ctx)
289  {
290  TSS_KM_KEYINFO2* key_info;
291  UINT32 key_info_size;
292 
293  // TODO: does the PS type matter here at all?
294  TSPI_CHECK_SUCCESS(::Tspi_Context_GetRegisteredKeysByUUID2(ctx.handle(),
295  TSS_PS_TYPE_SYSTEM,
296  nullptr,
297  &key_info_size,
298  &key_info));
299 
300  std::vector<std::string> r(key_info_size);
301 
302  for(size_t i = 0; i != key_info_size; ++i)
303  {
304  r[i] = format_url(key_info[i].keyUUID, key_info[i].persistentStorageType);
305  }
306 
307  // TODO: are we supposed to free this memory and if so how?
308  //TSPI_CHECK_SUCCESS(::Tspi_Context_FreeMemory(ctx.handle(), key_info));
309 
310  return r;
311  }
312 
314  {
315  if(m_n == 0)
316  {
317  m_n = BigInt::decode(get_obj_attr(m_ctx.handle(), m_key,
318  TSS_TSPATTRIB_RSAKEY_INFO,
319  TSS_TSPATTRIB_KEYINFO_RSA_MODULUS));
320  }
321 
322  return m_n;
323  }
324 
326  {
327  if(m_e == 0)
328  {
329  m_e = BigInt::decode(get_obj_attr(m_ctx.handle(), m_key,
330  TSS_TSPATTRIB_RSAKEY_INFO,
331  TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT));
332  }
333 
334  return m_e;
335  }
336 
338  {
339  return if_work_factor(key_length());
340  }
341 
343  {
344  return get_n().bits();
345  }
346 
348  {
349  return AlgorithmIdentifier(get_oid(),
351  }
352 
353 std::vector<uint8_t> TPM_PrivateKey::public_key_bits() const
354  {
355  std::vector<uint8_t> bits;
356  DER_Encoder(bits)
358  .encode(get_n())
359  .encode(get_e())
360  .end_cons();
361  return bits;
362  }
363 
365  {
366  throw TPM_Error("Private key export not supported for TPM keys");
367  }
368 
369 std::vector<uint8_t> TPM_PrivateKey::export_blob() const
370  {
371  return get_obj_attr(m_ctx.handle(), m_key,
372  TSS_TSPATTRIB_KEY_BLOB,
373  TSS_TSPATTRIB_KEYBLOB_BLOB);
374  }
375 
376 std::unique_ptr<Public_Key> TPM_PrivateKey::public_key() const
377  {
378  return std::unique_ptr<Public_Key>(new RSA_PublicKey(get_n(), get_e()));
379  }
380 
382  {
383  return true; // TODO do a kat or pairwise check
384  }
385 
386 namespace {
387 
388 class TPM_Signing_Operation final : public PK_Ops::Signature
389  {
390  public:
391  TPM_Signing_Operation(const TPM_PrivateKey& key,
392  const std::string& hash_name) :
393  m_key(key),
394  m_hash(HashFunction::create(hash_name)),
395  m_hash_id(pkcs_hash_id(hash_name))
396  {
397  }
398 
399  size_t signature_length() const override
400  {
401  return m_key.get_n().bytes();
402  }
403 
404  void update(const uint8_t msg[], size_t msg_len) override
405  {
406  m_hash->update(msg, msg_len);
407  }
408 
409  secure_vector<uint8_t> sign(RandomNumberGenerator&) override
410  {
411  /*
412  * v1.2 TPMs will only sign with PKCS #1 v1.5 padding. SHA-1 is built
413  * in, all other hash inputs (TSS_HASH_OTHER) are treated as the
414  * concatenation of the hash OID and hash value and signed with just the
415  * 01FFFF... prefix. Even when using SHA-1 we compute the hash locally
416  * since it is going to be much faster than pushing data over the LPC bus.
417  */
418  secure_vector<uint8_t> msg_hash = m_hash->final();
419 
420  std::vector<uint8_t> id_and_msg;
421  id_and_msg.reserve(m_hash_id.size() + msg_hash.size());
422  id_and_msg.insert(id_and_msg.end(), m_hash_id.begin(), m_hash_id.end());
423  id_and_msg.insert(id_and_msg.end(), msg_hash.begin(), msg_hash.end());
424 
425  TSS_HCONTEXT ctx = m_key.ctx().handle();
426  TSS_HHASH tpm_hash;
427  TSPI_CHECK_SUCCESS(::Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER, &tpm_hash));
428  TSPI_CHECK_SUCCESS(::Tspi_Hash_SetHashValue(tpm_hash, id_and_msg.size(), id_and_msg.data()));
429 
430  BYTE* sig_bytes = nullptr;
431  UINT32 sig_len = 0;
432  TSPI_CHECK_SUCCESS(::Tspi_Hash_Sign(tpm_hash, m_key.handle(), &sig_len, &sig_bytes));
433  secure_vector<uint8_t> sig(sig_bytes, sig_bytes + sig_len);
434 
435  // TODO: RAII for Context_FreeMemory
436  TSPI_CHECK_SUCCESS(::Tspi_Context_FreeMemory(ctx, sig_bytes));
437 
438  // TODO: RAII for Context_CloseObject
439  TSPI_CHECK_SUCCESS(::Tspi_Context_CloseObject(ctx, tpm_hash));
440 
441  return sig;
442  }
443 
444  private:
445  const TPM_PrivateKey& m_key;
446  std::unique_ptr<HashFunction> m_hash;
447  std::vector<uint8_t> m_hash_id;
448  };
449 
450 }
451 
452 std::unique_ptr<PK_Ops::Signature>
454  const std::string& params,
455  const std::string& /*provider*/) const
456  {
457  return std::unique_ptr<PK_Ops::Signature>(new TPM_Signing_Operation(*this, params));
458  }
459 
460 }
size_t if_work_factor(size_t bits)
Definition: workfactor.cpp:38
TPM_Storage_Type
Definition: tpm.h:103
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:217
size_t bits() const
Definition: bigint.cpp:297
size_t key_length() const override
Definition: tpm.cpp:342
int(* final)(unsigned char *, CTX *)
TSS_HKEY srk() const
Definition: tpm.h:68
std::vector< uint8_t > public_key_bits() const override
Definition: tpm.cpp:353
#define TSPI_CHECK_SUCCESS(expr)
Definition: tpm.cpp:68
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
TPM_Context & ctx() const
Definition: tpm.h:145
DER_Encoder & end_cons()
Definition: der_enc.cpp:191
void stir_random(const uint8_t in[], size_t in_len)
Definition: tpm.cpp:199
void typecast_copy(uint8_t out[], T in[], size_t N)
Definition: mem_ops.h:145
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:285
secure_vector< uint8_t > private_key_bits() const override
Definition: tpm.cpp:364
TPM_Context(pin_cb cb, const char *srk_password)
Definition: tpm.cpp:156
virtual OID get_oid() const
Definition: pk_keys.cpp:53
std::string to_string() const
Definition: uuid.cpp:67
uint32_t current_counter()
Definition: tpm.cpp:184
BigInt get_e() const
Definition: tpm.cpp:325
std::function< std::string(std::string)> pin_cb
Definition: tpm.h:48
BigInt get_n() const
Definition: tpm.cpp:313
TPM_PrivateKey(TPM_Context &ctx, size_t bits, const char *key_password)
Definition: tpm.cpp:204
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
Definition: alg_id.cpp:13
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, const std::string &params, const std::string &provider) const override
Definition: tpm.cpp:453
AlgorithmIdentifier algorithm_identifier() const override
Definition: tpm.cpp:347
size_t estimated_strength() const override
Definition: tpm.cpp:337
int(* update)(CTX *, const void *, CC_LONG len)
static std::vector< std::string > registered_keys(TPM_Context &ctx)
Definition: tpm.cpp:288
static BigInt decode(const uint8_t buf[], size_t length)
Definition: bigint.h:805
bool check_key(RandomNumberGenerator &rng, bool) const override
Definition: tpm.cpp:381
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:181
std::string register_key(TPM_Storage_Type storage_type)
Definition: tpm.cpp:254
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
TSS_HCONTEXT handle() const
Definition: tpm.h:67
std::vector< uint8_t > export_blob() const
Definition: tpm.cpp:369
void gen_random(uint8_t out[], size_t out_len)
Definition: tpm.cpp:191
bool is_valid() const
Definition: uuid.h:61
std::vector< uint8_t > pkcs_hash_id(const std::string &name)
Definition: hash_id.cpp:77
std::unique_ptr< Public_Key > public_key() const
Definition: tpm.cpp:376