1#!/usr/bin/python2 2 3# 4# Copyright (C) 2014 The Android Open Source Project 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19"""A code generator for TPM 2.0 structures and commands. 20 21The generator takes as input a structures file as emitted by the 22extract_structures.sh script and a commands file as emitted by the 23extract_commands.sh script. It outputs valid C++ into tpm_generated.{h,cc}. 24 25The input grammar is documented in the extract_* scripts. Sample input for 26structures looks like this: 27_BEGIN_TYPES 28_OLD_TYPE UINT32 29_NEW_TYPE TPM_HANDLE 30_END 31_BEGIN_CONSTANTS 32_CONSTANTS (UINT32) TPM_SPEC 33_TYPE UINT32 34_NAME TPM_SPEC_FAMILY 35_VALUE 0x322E3000 36_NAME TPM_SPEC_LEVEL 37_VALUE 00 38_END 39_BEGIN_STRUCTURES 40_STRUCTURE TPMS_TIME_INFO 41_TYPE UINT64 42_NAME time 43_TYPE TPMS_CLOCK_INFO 44_NAME clockInfo 45_END 46 47Sample input for commands looks like this: 48_BEGIN 49_INPUT_START TPM2_Startup 50_TYPE TPMI_ST_COMMAND_TAG 51_NAME tag 52_COMMENT TPM_ST_NO_SESSIONS 53_TYPE UINT32 54_NAME commandSize 55_TYPE TPM_CC 56_NAME commandCode 57_COMMENT TPM_CC_Startup {NV} 58_TYPE TPM_SU 59_NAME startupType 60_COMMENT TPM_SU_CLEAR or TPM_SU_STATE 61_OUTPUT_START TPM2_Startup 62_TYPE TPM_ST 63_NAME tag 64_COMMENT see clause 8 65_TYPE UINT32 66_NAME responseSize 67_TYPE TPM_RC 68_NAME responseCode 69_END 70""" 71 72from __future__ import print_function 73 74import argparse 75import re 76import subprocess 77 78import union_selectors 79 80_BASIC_TYPES = ['uint8_t', 'int8_t', 'int', 'uint16_t', 'int16_t', 81 'uint32_t', 'int32_t', 'uint64_t', 'int64_t'] 82_OUTPUT_FILE_H = 'tpm_generated.h' 83_OUTPUT_FILE_CC = 'tpm_generated.cc' 84_COPYRIGHT_HEADER = ( 85 '//\n' 86 '// Copyright (C) 2015 The Android Open Source Project\n' 87 '//\n' 88 '// Licensed under the Apache License, Version 2.0 (the "License");\n' 89 '// you may not use this file except in compliance with the License.\n' 90 '// You may obtain a copy of the License at\n' 91 '//\n' 92 '// http://www.apache.org/licenses/LICENSE-2.0\n' 93 '//\n' 94 '// Unless required by applicable law or agreed to in writing, software\n' 95 '// distributed under the License is distributed on an "AS IS" BASIS,\n' 96 '// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ' 97 'implied.\n' 98 '// See the License for the specific language governing permissions and\n' 99 '// limitations under the License.\n' 100 '//\n\n' 101 '// THIS CODE IS GENERATED - DO NOT MODIFY!\n') 102_HEADER_FILE_GUARD_HEADER = """ 103#ifndef %(name)s 104#define %(name)s 105""" 106_HEADER_FILE_GUARD_FOOTER = """ 107#endif // %(name)s 108""" 109_HEADER_FILE_INCLUDES = """ 110#include <string> 111 112#include <base/callback_forward.h> 113#include <base/macros.h> 114 115#include "trunks/trunks_export.h" 116""" 117_IMPLEMENTATION_FILE_INCLUDES = """ 118#include <memory> 119#include <string> 120 121#include <base/bind.h> 122#include <base/callback.h> 123#include <base/logging.h> 124#include <base/macros.h> 125#include <base/stl_util.h> 126#include <base/strings/string_number_conversions.h> 127#include <base/sys_byteorder.h> 128#include <crypto/secure_hash.h> 129 130#include "trunks/authorization_delegate.h" 131#include "trunks/command_transceiver.h" 132#include "trunks/error_codes.h" 133 134""" 135_LOCAL_INCLUDE = """ 136#include "trunks/%(filename)s" 137""" 138_NAMESPACE_BEGIN = """ 139namespace trunks { 140""" 141_NAMESPACE_END = """ 142} // namespace trunks 143""" 144_FORWARD_DECLARATIONS = """ 145class AuthorizationDelegate; 146class CommandTransceiver; 147""" 148_FUNCTION_DECLARATIONS = """ 149TRUNKS_EXPORT size_t GetNumberOfRequestHandles(TPM_CC command_code); 150TRUNKS_EXPORT size_t GetNumberOfResponseHandles(TPM_CC command_code); 151""" 152_CLASS_BEGIN = """ 153class TRUNKS_EXPORT Tpm { 154 public: 155 // Does not take ownership of |transceiver|. 156 explicit Tpm(CommandTransceiver* transceiver) : transceiver_(transceiver) {} 157 virtual ~Tpm() {} 158 159""" 160_CLASS_END = """ 161 private: 162 CommandTransceiver* transceiver_; 163 164 DISALLOW_COPY_AND_ASSIGN(Tpm); 165}; 166""" 167_SERIALIZE_BASIC_TYPE = """ 168TPM_RC Serialize_%(type)s(const %(type)s& value, std::string* buffer) { 169 VLOG(3) << __func__; 170 %(type)s value_net = value; 171 switch (sizeof(%(type)s)) { 172 case 2: 173 value_net = base::HostToNet16(value); 174 break; 175 case 4: 176 value_net = base::HostToNet32(value); 177 break; 178 case 8: 179 value_net = base::HostToNet64(value); 180 break; 181 default: 182 break; 183 } 184 const char* value_bytes = reinterpret_cast<const char*>(&value_net); 185 buffer->append(value_bytes, sizeof(%(type)s)); 186 return TPM_RC_SUCCESS; 187} 188 189TPM_RC Parse_%(type)s( 190 std::string* buffer, 191 %(type)s* value, 192 std::string* value_bytes) { 193 VLOG(3) << __func__; 194 if (buffer->size() < sizeof(%(type)s)) 195 return TPM_RC_INSUFFICIENT; 196 %(type)s value_net = 0; 197 memcpy(&value_net, buffer->data(), sizeof(%(type)s)); 198 switch (sizeof(%(type)s)) { 199 case 2: 200 *value = base::NetToHost16(value_net); 201 break; 202 case 4: 203 *value = base::NetToHost32(value_net); 204 break; 205 case 8: 206 *value = base::NetToHost64(value_net); 207 break; 208 default: 209 *value = value_net; 210 } 211 if (value_bytes) { 212 value_bytes->append(buffer->substr(0, sizeof(%(type)s))); 213 } 214 buffer->erase(0, sizeof(%(type)s)); 215 return TPM_RC_SUCCESS; 216} 217""" 218_SERIALIZE_DECLARATION = """ 219TRUNKS_EXPORT TPM_RC Serialize_%(type)s( 220 const %(type)s& value, 221 std::string* buffer); 222 223TRUNKS_EXPORT TPM_RC Parse_%(type)s( 224 std::string* buffer, 225 %(type)s* value, 226 std::string* value_bytes); 227""" 228 229_SIMPLE_TPM2B_HELPERS_DECLARATION = """ 230TRUNKS_EXPORT %(type)s Make_%(type)s( 231 const std::string& bytes); 232TRUNKS_EXPORT std::string StringFrom_%(type)s( 233 const %(type)s& tpm2b); 234""" 235_COMPLEX_TPM2B_HELPERS_DECLARATION = """ 236TRUNKS_EXPORT %(type)s Make_%(type)s( 237 const %(inner_type)s& inner); 238""" 239 240_HANDLE_COUNT_FUNCTION_START = """ 241size_t GetNumberOf%(handle_type)sHandles(TPM_CC command_code) { 242 switch (command_code) {""" 243_HANDLE_COUNT_FUNCTION_CASE = """ 244 case %(command_code)s: return %(handle_count)s;""" 245_HANDLE_COUNT_FUNCTION_END = """ 246 default: LOG(WARNING) << "Unknown command code: " << command_code; 247 } 248 return 0; 249} 250""" 251 252def FixName(name): 253 """Fixes names to conform to Chromium style.""" 254 # Handle names with array notation. E.g. 'myVar[10]' is grouped as 'myVar' and 255 # '[10]'. 256 match = re.search(r'([^\[]*)(\[.*\])*', name) 257 # Transform the name to Chromium style. E.g. 'myVarAgain' becomes 258 # 'my_var_again'. 259 fixed_name = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', match.group(1)).lower() 260 return fixed_name + match.group(2) if match.group(2) else fixed_name 261 262 263def IsTPM2B(name): 264 return name.startswith('TPM2B_') 265 266 267def GetCppBool(condition): 268 if condition: 269 return 'true' 270 return 'false' 271 272 273class Typedef(object): 274 """Represents a TPM typedef. 275 276 Attributes: 277 old_type: The existing type in a typedef statement. 278 new_type: The new type in a typedef statement. 279 """ 280 281 _TYPEDEF = 'typedef %(old_type)s %(new_type)s;\n' 282 _SERIALIZE_FUNCTION = """ 283TPM_RC Serialize_%(new)s( 284 const %(new)s& value, 285 std::string* buffer) { 286 VLOG(3) << __func__; 287 return Serialize_%(old)s(value, buffer); 288} 289""" 290 _PARSE_FUNCTION = """ 291TPM_RC Parse_%(new)s( 292 std::string* buffer, 293 %(new)s* value, 294 std::string* value_bytes) { 295 VLOG(3) << __func__; 296 return Parse_%(old)s(buffer, value, value_bytes); 297} 298""" 299 300 def __init__(self, old_type, new_type): 301 """Initializes a Typedef instance. 302 303 Args: 304 old_type: The existing type in a typedef statement. 305 new_type: The new type in a typedef statement. 306 """ 307 self.old_type = old_type 308 self.new_type = new_type 309 310 def OutputForward(self, out_file, defined_types, typemap): 311 """Writes a typedef definition to |out_file|. 312 313 Any outstanding dependencies will be forward declared. This method is the 314 same as Output() because forward declarations do not apply for typedefs. 315 316 Args: 317 out_file: The output file. 318 defined_types: A set of types for which definitions have already been 319 generated. 320 typemap: A dict mapping type names to the corresponding object. 321 """ 322 self.Output(out_file, defined_types, typemap) 323 324 def Output(self, out_file, defined_types, typemap): 325 """Writes a typedef definition to |out_file|. 326 327 Any outstanding dependencies will be forward declared. 328 329 Args: 330 out_file: The output file. 331 defined_types: A set of types for which definitions have already been 332 generated. 333 typemap: A dict mapping type names to the corresponding object. 334 """ 335 if self.new_type in defined_types: 336 return 337 # Make sure the dependency is already defined. 338 if self.old_type not in defined_types: 339 typemap[self.old_type].OutputForward(out_file, defined_types, typemap) 340 out_file.write(self._TYPEDEF % {'old_type': self.old_type, 341 'new_type': self.new_type}) 342 defined_types.add(self.new_type) 343 344 def OutputSerialize(self, out_file, serialized_types, typemap): 345 """Writes a serialize and parse function for the typedef to |out_file|. 346 347 Args: 348 out_file: The output file. 349 serialized_types: A set of types for which serialize and parse functions 350 have already been generated. 351 typemap: A dict mapping type names to the corresponding object. 352 """ 353 if self.new_type in serialized_types: 354 return 355 if self.old_type not in serialized_types: 356 typemap[self.old_type].OutputSerialize(out_file, serialized_types, 357 typemap) 358 out_file.write(self._SERIALIZE_FUNCTION % {'old': self.old_type, 359 'new': self.new_type}) 360 out_file.write(self._PARSE_FUNCTION % {'old': self.old_type, 361 'new': self.new_type}) 362 serialized_types.add(self.new_type) 363 364 365class Constant(object): 366 """Represents a TPM constant. 367 368 Attributes: 369 const_type: The type of the constant (e.g. 'int'). 370 name: The name of the constant (e.g. 'kMyConstant'). 371 value: The value of the constant (e.g. '7'). 372 """ 373 374 _CONSTANT = 'constexpr %(type)s %(name)s = %(value)s;\n' 375 376 def __init__(self, const_type, name, value): 377 """Initializes a Constant instance. 378 379 Args: 380 const_type: The type of the constant (e.g. 'int'). 381 name: The name of the constant (e.g. 'kMyConstant'). 382 value: The value of the constant (e.g. '7'). 383 """ 384 self.const_type = const_type 385 self.name = name 386 self.value = value 387 388 def Output(self, out_file, defined_types, typemap): 389 """Writes a constant definition to |out_file|. 390 391 Any outstanding dependencies will be forward declared. 392 393 Args: 394 out_file: The output file. 395 defined_types: A set of types for which definitions have already been 396 generated. 397 typemap: A dict mapping type names to the corresponding object. 398 """ 399 # Make sure the dependency is already defined. 400 if self.const_type not in defined_types: 401 typemap[self.const_type].OutputForward(out_file, defined_types, typemap) 402 out_file.write(self._CONSTANT % {'type': self.const_type, 403 'name': self.name, 404 'value': self.value}) 405 406 407class Structure(object): 408 """Represents a TPM structure or union. 409 410 Attributes: 411 name: The name of the structure. 412 is_union: A boolean indicating whether this is a union. 413 fields: A list of (type, name) tuples representing the struct fields. 414 depends_on: A list of strings for types this struct depends on other than 415 field types. See AddDependency() for more details. 416 """ 417 418 _STRUCTURE = 'struct %(name)s {\n' 419 _STRUCTURE_FORWARD = 'struct %(name)s;\n' 420 _UNION = 'union %(name)s {\n' 421 _UNION_FORWARD = 'union %(name)s;\n' 422 _STRUCTURE_END = '};\n\n' 423 _STRUCTURE_FIELD = ' %(type)s %(name)s;\n' 424 _SERIALIZE_FUNCTION_START = """ 425TPM_RC Serialize_%(type)s( 426 const %(type)s& value, 427 std::string* buffer) { 428 TPM_RC result = TPM_RC_SUCCESS; 429 VLOG(3) << __func__; 430""" 431 _SERIALIZE_FIELD = """ 432 result = Serialize_%(type)s(value.%(name)s, buffer); 433 if (result) { 434 return result; 435 } 436""" 437 _SERIALIZE_FIELD_ARRAY = """ 438 if (arraysize(value.%(name)s) < value.%(count)s) { 439 return TPM_RC_INSUFFICIENT; 440 } 441 for (uint32_t i = 0; i < value.%(count)s; ++i) { 442 result = Serialize_%(type)s(value.%(name)s[i], buffer); 443 if (result) { 444 return result; 445 } 446 } 447""" 448 _SERIALIZE_FIELD_WITH_SELECTOR = """ 449 result = Serialize_%(type)s( 450 value.%(name)s, 451 value.%(selector_name)s, 452 buffer); 453 if (result) { 454 return result; 455 } 456""" 457 _SERIALIZE_COMPLEX_TPM2B = """ 458 std::string field_bytes; 459 result = Serialize_%(type)s(value.%(name)s, &field_bytes); 460 if (result) { 461 return result; 462 } 463 std::string size_bytes; 464 result = Serialize_UINT16(field_bytes.size(), &size_bytes); 465 if (result) { 466 return result; 467 } 468 buffer->append(size_bytes + field_bytes); 469""" 470 _PARSE_FUNCTION_START = """ 471TPM_RC Parse_%(type)s( 472 std::string* buffer, 473 %(type)s* value, 474 std::string* value_bytes) { 475 TPM_RC result = TPM_RC_SUCCESS; 476 VLOG(3) << __func__; 477""" 478 _PARSE_FIELD = """ 479 result = Parse_%(type)s( 480 buffer, 481 &value->%(name)s, 482 value_bytes); 483 if (result) { 484 return result; 485 } 486""" 487 _PARSE_FIELD_ARRAY = """ 488 if (arraysize(value->%(name)s) < value->%(count)s) { 489 return TPM_RC_INSUFFICIENT; 490 } 491 for (uint32_t i = 0; i < value->%(count)s; ++i) { 492 result = Parse_%(type)s( 493 buffer, 494 &value->%(name)s[i], 495 value_bytes); 496 if (result) { 497 return result; 498 } 499 } 500""" 501 _PARSE_FIELD_WITH_SELECTOR = """ 502 result = Parse_%(type)s( 503 buffer, 504 value->%(selector_name)s, 505 &value->%(name)s, 506 value_bytes); 507 if (result) { 508 return result; 509 } 510""" 511 _SERIALIZE_FUNCTION_END = ' return result;\n}\n' 512 _ARRAY_FIELD_RE = re.compile(r'(.*)\[(.*)\]') 513 _ARRAY_FIELD_SIZE_RE = re.compile(r'^(count|size)') 514 _UNION_TYPE_RE = re.compile(r'^TPMU_.*') 515 _SERIALIZE_UNION_FUNCTION_START = """ 516TPM_RC Serialize_%(union_type)s( 517 const %(union_type)s& value, 518 %(selector_type)s selector, 519 std::string* buffer) { 520 TPM_RC result = TPM_RC_SUCCESS; 521 VLOG(3) << __func__; 522""" 523 _SERIALIZE_UNION_FIELD = """ 524 if (selector == %(selector_value)s) { 525 result = Serialize_%(field_type)s(value.%(field_name)s, buffer); 526 if (result) { 527 return result; 528 } 529 } 530""" 531 _SERIALIZE_UNION_FIELD_ARRAY = """ 532 if (selector == %(selector_value)s) { 533 if (arraysize(value.%(field_name)s) < %(count)s) { 534 return TPM_RC_INSUFFICIENT; 535 } 536 for (uint32_t i = 0; i < %(count)s; ++i) { 537 result = Serialize_%(field_type)s(value.%(field_name)s[i], buffer); 538 if (result) { 539 return result; 540 } 541 } 542 } 543""" 544 _PARSE_UNION_FUNCTION_START = """ 545TPM_RC Parse_%(union_type)s( 546 std::string* buffer, 547 %(selector_type)s selector, 548 %(union_type)s* value, 549 std::string* value_bytes) { 550 TPM_RC result = TPM_RC_SUCCESS; 551 VLOG(3) << __func__; 552""" 553 _PARSE_UNION_FIELD = """ 554 if (selector == %(selector_value)s) { 555 result = Parse_%(field_type)s( 556 buffer, 557 &value->%(field_name)s, 558 value_bytes); 559 if (result) { 560 return result; 561 } 562 } 563""" 564 _PARSE_UNION_FIELD_ARRAY = """ 565 if (selector == %(selector_value)s) { 566 if (arraysize(value->%(field_name)s) < %(count)s) { 567 return TPM_RC_INSUFFICIENT; 568 } 569 for (uint32_t i = 0; i < %(count)s; ++i) { 570 result = Parse_%(field_type)s( 571 buffer, 572 &value->%(field_name)s[i], 573 value_bytes); 574 if (result) { 575 return result; 576 } 577 } 578 } 579""" 580 _EMPTY_UNION_CASE = """ 581 if (selector == %(selector_value)s) { 582 // Do nothing. 583 } 584""" 585 _SIMPLE_TPM2B_HELPERS = """ 586%(type)s Make_%(type)s( 587 const std::string& bytes) { 588 %(type)s tpm2b; 589 CHECK(bytes.size() <= sizeof(tpm2b.%(buffer_name)s)); 590 memset(&tpm2b, 0, sizeof(%(type)s)); 591 tpm2b.size = bytes.size(); 592 memcpy(tpm2b.%(buffer_name)s, bytes.data(), bytes.size()); 593 return tpm2b; 594} 595 596std::string StringFrom_%(type)s( 597 const %(type)s& tpm2b) { 598 const char* char_buffer = reinterpret_cast<const char*>( 599 tpm2b.%(buffer_name)s); 600 return std::string(char_buffer, tpm2b.size); 601} 602""" 603 _COMPLEX_TPM2B_HELPERS = """ 604%(type)s Make_%(type)s( 605 const %(inner_type)s& inner) { 606 %(type)s tpm2b; 607 tpm2b.size = sizeof(%(inner_type)s); 608 tpm2b.%(inner_name)s = inner; 609 return tpm2b; 610} 611""" 612 613 def __init__(self, name, is_union): 614 """Initializes a Structure instance. 615 616 Initially the instance will have no fields and no dependencies. Those can be 617 added with the AddField() and AddDependency() methods. 618 619 Args: 620 name: The name of the structure. 621 is_union: A boolean indicating whether this is a union. 622 """ 623 self.name = name 624 self.is_union = is_union 625 self.fields = [] 626 self.depends_on = [] 627 self._forwarded = False 628 629 def AddField(self, field_type, field_name): 630 """Adds a field for this struct. 631 632 Args: 633 field_type: The type of the field. 634 field_name: The name of the field. 635 """ 636 self.fields.append((field_type, FixName(field_name))) 637 638 def AddDependency(self, required_type): 639 """Adds an explicit dependency on another type. 640 641 This is used in cases where there is an additional dependency other than the 642 field types, which are implicit dependencies. For example, a field like 643 FIELD_TYPE value[sizeof(OTHER_TYPE)] would need OTHER_TYPE to be already 644 declared. 645 646 Args: 647 required_type: The type this structure depends on. 648 """ 649 self.depends_on.append(required_type) 650 651 def IsSimpleTPM2B(self): 652 """Returns whether this struct is a TPM2B structure with raw bytes.""" 653 return self.name.startswith('TPM2B_') and self.fields[1][0] == 'BYTE' 654 655 def IsComplexTPM2B(self): 656 """Returns whether this struct is a TPM2B structure with an inner struct.""" 657 return self.name.startswith('TPM2B_') and self.fields[1][0] != 'BYTE' 658 659 def _GetFieldTypes(self): 660 """Creates a set which holds all current field types. 661 662 Returns: 663 A set of field types. 664 """ 665 return set([field[0] for field in self.fields]) 666 667 def OutputForward(self, out_file, unused_defined_types, unused_typemap): 668 """Writes a structure forward declaration to |out_file|. 669 670 This method needs to match the OutputForward method in other type classes 671 (e.g. Typedef) which is why the unused_* args exist. 672 673 Args: 674 out_file: The output file. 675 unused_defined_types: Not used. 676 unused_typemap: Not used. 677 """ 678 if self._forwarded: 679 return 680 if self.is_union: 681 out_file.write(self._UNION_FORWARD % {'name': self.name}) 682 else: 683 out_file.write(self._STRUCTURE_FORWARD % {'name': self.name}) 684 self._forwarded = True 685 686 def Output(self, out_file, defined_types, typemap): 687 """Writes a structure definition to |out_file|. 688 689 Any outstanding dependencies will be defined. 690 691 Args: 692 out_file: The output file. 693 defined_types: A set of types for which definitions have already been 694 generated. 695 typemap: A dict mapping type names to the corresponding object. 696 """ 697 if self.name in defined_types: 698 return 699 # Make sure any dependencies are already defined. 700 for field_type in self._GetFieldTypes(): 701 if field_type not in defined_types: 702 typemap[field_type].Output(out_file, defined_types, typemap) 703 for required_type in self.depends_on: 704 if required_type not in defined_types: 705 typemap[required_type].Output(out_file, defined_types, typemap) 706 if self.is_union: 707 out_file.write(self._UNION % {'name': self.name}) 708 else: 709 out_file.write(self._STRUCTURE % {'name': self.name}) 710 for field in self.fields: 711 out_file.write(self._STRUCTURE_FIELD % {'type': field[0], 712 'name': field[1]}) 713 out_file.write(self._STRUCTURE_END) 714 defined_types.add(self.name) 715 716 def OutputSerialize(self, out_file, serialized_types, typemap): 717 """Writes serialize and parse functions for a structure to |out_file|. 718 719 Args: 720 out_file: The output file. 721 serialized_types: A set of types for which serialize and parse functions 722 have already been generated. This type name of this structure will be 723 added on success. 724 typemap: A dict mapping type names to the corresponding object. 725 """ 726 if (self.name in serialized_types or 727 self.name == 'TPMU_NAME' or 728 self.name == 'TPMU_ENCRYPTED_SECRET'): 729 return 730 # Make sure any dependencies already have serialize functions defined. 731 for field_type in self._GetFieldTypes(): 732 if field_type not in serialized_types: 733 typemap[field_type].OutputSerialize(out_file, serialized_types, typemap) 734 if self.is_union: 735 self._OutputUnionSerialize(out_file) 736 serialized_types.add(self.name) 737 return 738 out_file.write(self._SERIALIZE_FUNCTION_START % {'type': self.name}) 739 if self.IsComplexTPM2B(): 740 field_type = self.fields[1][0] 741 field_name = self.fields[1][1] 742 out_file.write(self._SERIALIZE_COMPLEX_TPM2B % {'type': field_type, 743 'name': field_name}) 744 else: 745 for field in self.fields: 746 if self._ARRAY_FIELD_RE.search(field[1]): 747 self._OutputArrayField(out_file, field, self._SERIALIZE_FIELD_ARRAY) 748 elif self._UNION_TYPE_RE.search(field[0]): 749 self._OutputUnionField(out_file, field, 750 self._SERIALIZE_FIELD_WITH_SELECTOR) 751 else: 752 out_file.write(self._SERIALIZE_FIELD % {'type': field[0], 753 'name': field[1]}) 754 out_file.write(self._SERIALIZE_FUNCTION_END) 755 out_file.write(self._PARSE_FUNCTION_START % {'type': self.name}) 756 for field in self.fields: 757 if self._ARRAY_FIELD_RE.search(field[1]): 758 self._OutputArrayField(out_file, field, self._PARSE_FIELD_ARRAY) 759 elif self._UNION_TYPE_RE.search(field[0]): 760 self._OutputUnionField(out_file, field, self._PARSE_FIELD_WITH_SELECTOR) 761 else: 762 out_file.write(self._PARSE_FIELD % {'type': field[0], 763 'name': field[1]}) 764 out_file.write(self._SERIALIZE_FUNCTION_END) 765 # If this is a TPM2B structure throw in a few convenience functions. 766 if self.IsSimpleTPM2B(): 767 field_name = self._ARRAY_FIELD_RE.search(self.fields[1][1]).group(1) 768 out_file.write(self._SIMPLE_TPM2B_HELPERS % {'type': self.name, 769 'buffer_name': field_name}) 770 elif self.IsComplexTPM2B(): 771 field_type = self.fields[1][0] 772 field_name = self.fields[1][1] 773 out_file.write(self._COMPLEX_TPM2B_HELPERS % {'type': self.name, 774 'inner_type': field_type, 775 'inner_name': field_name}) 776 serialized_types.add(self.name) 777 778 def _OutputUnionSerialize(self, out_file): 779 """Writes serialize and parse functions for a union to |out_file|. 780 781 This is more complex than the struct case because only one field of the 782 union is serialized / parsed based on the value of a selector. Arrays are 783 also handled differently: the full size of the array is serialized instead 784 of looking for a field which specifies the count. 785 786 Args: 787 out_file: The output file 788 """ 789 selector_type = union_selectors.GetUnionSelectorType(self.name) 790 selector_values = union_selectors.GetUnionSelectorValues(self.name) 791 field_types = {f[1]: f[0] for f in self.fields} 792 out_file.write(self._SERIALIZE_UNION_FUNCTION_START % 793 {'union_type': self.name, 'selector_type': selector_type}) 794 for selector in selector_values: 795 field_name = FixName(union_selectors.GetUnionSelectorField(self.name, 796 selector)) 797 if not field_name: 798 out_file.write(self._EMPTY_UNION_CASE % {'selector_value': selector}) 799 continue 800 field_type = field_types[field_name] 801 array_match = self._ARRAY_FIELD_RE.search(field_name) 802 if array_match: 803 field_name = array_match.group(1) 804 count = array_match.group(2) 805 out_file.write(self._SERIALIZE_UNION_FIELD_ARRAY % 806 {'selector_value': selector, 807 'count': count, 808 'field_type': field_type, 809 'field_name': field_name}) 810 else: 811 out_file.write(self._SERIALIZE_UNION_FIELD % 812 {'selector_value': selector, 813 'field_type': field_type, 814 'field_name': field_name}) 815 out_file.write(self._SERIALIZE_FUNCTION_END) 816 out_file.write(self._PARSE_UNION_FUNCTION_START % 817 {'union_type': self.name, 'selector_type': selector_type}) 818 for selector in selector_values: 819 field_name = FixName(union_selectors.GetUnionSelectorField(self.name, 820 selector)) 821 if not field_name: 822 out_file.write(self._EMPTY_UNION_CASE % {'selector_value': selector}) 823 continue 824 field_type = field_types[field_name] 825 array_match = self._ARRAY_FIELD_RE.search(field_name) 826 if array_match: 827 field_name = array_match.group(1) 828 count = array_match.group(2) 829 out_file.write(self._PARSE_UNION_FIELD_ARRAY % 830 {'selector_value': selector, 831 'count': count, 832 'field_type': field_type, 833 'field_name': field_name}) 834 else: 835 out_file.write(self._PARSE_UNION_FIELD % 836 {'selector_value': selector, 837 'field_type': field_type, 838 'field_name': field_name}) 839 out_file.write(self._SERIALIZE_FUNCTION_END) 840 841 def _OutputUnionField(self, out_file, field, code_format): 842 """Writes serialize / parse code for a union field. 843 844 In this case |self| may not necessarily represent a union but |field| does. 845 This requires that a field of an acceptable selector type appear somewhere 846 in the struct. The value of this field is used as the selector value when 847 calling the serialize / parse function for the union. 848 849 Args: 850 out_file: The output file. 851 field: The union field to be processed as a (type, name) tuple. 852 code_format: Must be (_SERIALIZE|_PARSE)_FIELD_WITH_SELECTOR 853 """ 854 selector_types = union_selectors.GetUnionSelectorTypes(field[0]) 855 selector_name = '' 856 for tmp in self.fields: 857 if tmp[0] in selector_types: 858 selector_name = tmp[1] 859 break 860 assert selector_name, 'Missing selector for %s in %s!' % (field[1], 861 self.name) 862 out_file.write(code_format % {'type': field[0], 863 'selector_name': selector_name, 864 'name': field[1]}) 865 866 def _OutputArrayField(self, out_file, field, code_format): 867 """Writes serialize / parse code for an array field. 868 869 The allocated size of the array is ignored and a field which holds the 870 actual count of items in the array must exist. Only the number of items 871 represented by the value of that count field are serialized / parsed. 872 873 Args: 874 out_file: The output file. 875 field: The array field to be processed as a (type, name) tuple. 876 code_format: Must be (_SERIALIZE|_PARSE)_FIELD_ARRAY 877 """ 878 field_name = self._ARRAY_FIELD_RE.search(field[1]).group(1) 879 for count_field in self.fields: 880 assert count_field != field, ('Missing count field for %s in %s!' % 881 (field[1], self.name)) 882 if self._ARRAY_FIELD_SIZE_RE.search(count_field[1]): 883 out_file.write(code_format % {'count': count_field[1], 884 'type': field[0], 885 'name': field_name}) 886 break 887 888 889class Define(object): 890 """Represents a preprocessor define. 891 892 Attributes: 893 name: The name being defined. 894 value: The value being assigned to the name. 895 """ 896 897 _DEFINE = '#if !defined(%(name)s)\n#define %(name)s %(value)s\n#endif\n' 898 899 def __init__(self, name, value): 900 """Initializes a Define instance. 901 902 Args: 903 name: The name being defined. 904 value: The value being assigned to the name. 905 """ 906 self.name = name 907 # Prepend 'trunks::' to types. 908 self.value = re.sub(r'(TPM.?_|U?INT[0-9]{2})', r'trunks::\1', value) 909 910 def Output(self, out_file): 911 """Writes a preprocessor define to |out_file|. 912 913 Args: 914 out_file: The output file. 915 """ 916 out_file.write(self._DEFINE % {'name': self.name, 'value': self.value}) 917 918 919class StructureParser(object): 920 """Structure definition parser. 921 922 The input text file is extracted from the PDF file containing the TPM 923 structures specification from the Trusted Computing Group. The syntax 924 of the text file is defined by extract_structures.sh. 925 926 - Parses typedefs to a list of Typedef objects. 927 - Parses constants to a list of Constant objects. 928 - Parses structs and unions to a list of Structure objects. 929 - Parses defines to a list of Define objects. 930 931 The parser also creates 'typemap' dict which maps every type to its generator 932 object. This typemap helps manage type dependencies. 933 934 Example usage: 935 parser = StructureParser(open('myfile')) 936 types, constants, structs, defines, typemap = parser.Parse() 937 """ 938 939 # Compile regular expressions. 940 _BEGIN_TYPES_TOKEN = '_BEGIN_TYPES' 941 _BEGIN_CONSTANTS_TOKEN = '_BEGIN_CONSTANTS' 942 _BEGIN_STRUCTURES_TOKEN = '_BEGIN_STRUCTURES' 943 _BEGIN_UNIONS_TOKEN = '_BEGIN_UNIONS' 944 _BEGIN_DEFINES_TOKEN = '_BEGIN_DEFINES' 945 _END_TOKEN = '_END' 946 _OLD_TYPE_RE = re.compile(r'^_OLD_TYPE\s+(\w+)$') 947 _NEW_TYPE_RE = re.compile(r'^_NEW_TYPE\s+(\w+)$') 948 _CONSTANTS_SECTION_RE = re.compile(r'^_CONSTANTS.* (\w+)$') 949 _STRUCTURE_SECTION_RE = re.compile(r'^_STRUCTURE\s+(\w+)$') 950 _UNION_SECTION_RE = re.compile(r'^_UNION\s+(\w+)$') 951 _TYPE_RE = re.compile(r'^_TYPE\s+(\w+)$') 952 _NAME_RE = re.compile(r'^_NAME\s+([a-zA-Z0-9_()\[\]/\*\+\-]+)$') 953 _VALUE_RE = re.compile(r'^_VALUE\s+(.+)$') 954 _SIZEOF_RE = re.compile(r'^.*sizeof\(([a-zA-Z0-9_]*)\).*$') 955 956 def __init__(self, in_file): 957 """Initializes a StructureParser instance. 958 959 Args: 960 in_file: A file as returned by open() which has been opened for reading. 961 """ 962 self._line = None 963 self._in_file = in_file 964 965 def _NextLine(self): 966 """Gets the next input line. 967 968 Returns: 969 The next input line if another line is available, None otherwise. 970 """ 971 try: 972 self._line = self._in_file.next() 973 except StopIteration: 974 self._line = None 975 976 def Parse(self): 977 """Parse everything in a structures file. 978 979 Returns: 980 Lists of objects and a type-map as described in the class documentation. 981 Returns these in the following order: types, constants, structs, defines, 982 typemap. 983 """ 984 self._NextLine() 985 types = [] 986 constants = [] 987 structs = [] 988 defines = [] 989 typemap = {} 990 while self._line: 991 if self._BEGIN_TYPES_TOKEN == self._line.rstrip(): 992 types += self._ParseTypes(typemap) 993 elif self._BEGIN_CONSTANTS_TOKEN == self._line.rstrip(): 994 constants += self._ParseConstants(types, typemap) 995 elif self._BEGIN_STRUCTURES_TOKEN == self._line.rstrip(): 996 structs += self._ParseStructures(self._STRUCTURE_SECTION_RE, typemap) 997 elif self._BEGIN_UNIONS_TOKEN == self._line.rstrip(): 998 structs += self._ParseStructures(self._UNION_SECTION_RE, typemap) 999 elif self._BEGIN_DEFINES_TOKEN == self._line.rstrip(): 1000 defines += self._ParseDefines() 1001 else: 1002 print('Invalid file format: %s' % self._line) 1003 break 1004 self._NextLine() 1005 # Empty structs not handled by the extractor. 1006 self._AddEmptyStruct('TPMU_SYM_DETAILS', True, structs, typemap) 1007 # Defines which are used in TPM 2.0 Part 2 but not defined there. 1008 defines.append(Define( 1009 'MAX_CAP_DATA', '(MAX_CAP_BUFFER-sizeof(TPM_CAP)-sizeof(UINT32))')) 1010 defines.append(Define( 1011 'MAX_CAP_ALGS', '(TPM_ALG_LAST - TPM_ALG_FIRST + 1)')) 1012 defines.append(Define( 1013 'MAX_CAP_HANDLES', '(MAX_CAP_DATA/sizeof(TPM_HANDLE))')) 1014 defines.append(Define( 1015 'MAX_CAP_CC', '((TPM_CC_LAST - TPM_CC_FIRST) + 1)')) 1016 defines.append(Define( 1017 'MAX_TPM_PROPERTIES', '(MAX_CAP_DATA/sizeof(TPMS_TAGGED_PROPERTY))')) 1018 defines.append(Define( 1019 'MAX_PCR_PROPERTIES', '(MAX_CAP_DATA/sizeof(TPMS_TAGGED_PCR_SELECT))')) 1020 defines.append(Define( 1021 'MAX_ECC_CURVES', '(MAX_CAP_DATA/sizeof(TPM_ECC_CURVE))')) 1022 defines.append(Define('HASH_COUNT', '3')) 1023 return types, constants, structs, defines, typemap 1024 1025 def _AddEmptyStruct(self, name, is_union, structs, typemap): 1026 """Adds an empty Structure object to |structs| and |typemap|. 1027 1028 Args: 1029 name: The name to assign the new structure. 1030 is_union: A boolean indicating whether the new structure is a union. 1031 structs: A list of structures to which the new object is appended. 1032 typemap: A map of type names to objects to which the new name and object 1033 are added. 1034 """ 1035 s = Structure(name, is_union) 1036 structs.append(s) 1037 typemap[name] = s 1038 return 1039 1040 def _ParseTypes(self, typemap): 1041 """Parses a typedefs section. 1042 1043 The current line should be _BEGIN_TYPES and the method will stop parsing 1044 when an _END line is found. 1045 1046 Args: 1047 typemap: A dictionary to which parsed types are added. 1048 1049 Returns: 1050 A list of Typedef objects. 1051 """ 1052 types = [] 1053 self._NextLine() 1054 while self._END_TOKEN != self._line.rstrip(): 1055 match = self._OLD_TYPE_RE.search(self._line) 1056 if not match: 1057 print('Invalid old type: %s' % self._line) 1058 return types 1059 old_type = match.group(1) 1060 self._NextLine() 1061 match = self._NEW_TYPE_RE.search(self._line) 1062 if not match: 1063 print('Invalid new type: %s' % self._line) 1064 return types 1065 new_type = match.group(1) 1066 t = Typedef(old_type, new_type) 1067 types.append(t) 1068 typemap[new_type] = t 1069 self._NextLine() 1070 return types 1071 1072 def _ParseConstants(self, types, typemap): 1073 """Parses a constants section. 1074 1075 The current line should be _BEGIN_CONSTANTS and the method will stop parsing 1076 when an _END line is found. Each group of constants has an associated type 1077 alias. A Typedef object is created for each of these aliases and added to 1078 both |types| and |typemap|. 1079 1080 Args: 1081 types: A list of Typedef objects. 1082 typemap: A dictionary to which parsed types are added. 1083 1084 Returns: 1085 A list of Constant objects. 1086 """ 1087 constants = [] 1088 self._NextLine() 1089 while self._END_TOKEN != self._line.rstrip(): 1090 match = self._CONSTANTS_SECTION_RE.search(self._line) 1091 if not match: 1092 print('Invalid constants section: %s' % self._line) 1093 return constants 1094 constant_typename = match.group(1) 1095 self._NextLine() 1096 match = self._TYPE_RE.search(self._line) 1097 if not match: 1098 print('Invalid constants type: %s' % self._line) 1099 return constants 1100 constant_type = match.group(1) 1101 # Create a typedef for the constant group name (e.g. TPM_RC). 1102 typedef = Typedef(constant_type, constant_typename) 1103 typemap[constant_typename] = typedef 1104 types.append(typedef) 1105 self._NextLine() 1106 match = self._NAME_RE.search(self._line) 1107 if not match: 1108 print('Invalid constant name: %s' % self._line) 1109 return constants 1110 while match: 1111 name = match.group(1) 1112 self._NextLine() 1113 match = self._VALUE_RE.search(self._line) 1114 if not match: 1115 print('Invalid constant value: %s' % self._line) 1116 return constants 1117 value = match.group(1) 1118 constants.append(Constant(constant_typename, name, value)) 1119 self._NextLine() 1120 match = self._NAME_RE.search(self._line) 1121 return constants 1122 1123 def _ParseStructures(self, section_re, typemap): 1124 """Parses structures and unions. 1125 1126 The current line should be _BEGIN_STRUCTURES or _BEGIN_UNIONS and the method 1127 will stop parsing when an _END line is found. 1128 1129 Args: 1130 section_re: The regular expression to use for matching section tokens. 1131 typemap: A dictionary to which parsed types are added. 1132 1133 Returns: 1134 A list of Structure objects. 1135 """ 1136 structures = [] 1137 is_union = section_re == self._UNION_SECTION_RE 1138 self._NextLine() 1139 while self._END_TOKEN != self._line.rstrip(): 1140 match = section_re.search(self._line) 1141 if not match: 1142 print('Invalid structure section: %s' % self._line) 1143 return structures 1144 current_structure_name = match.group(1) 1145 current_structure = Structure(current_structure_name, is_union) 1146 self._NextLine() 1147 match = self._TYPE_RE.search(self._line) 1148 if not match: 1149 print('Invalid field type: %s' % self._line) 1150 return structures 1151 while match: 1152 field_type = match.group(1) 1153 self._NextLine() 1154 match = self._NAME_RE.search(self._line) 1155 if not match: 1156 print('Invalid field name: %s' % self._line) 1157 return structures 1158 field_name = match.group(1) 1159 # If the field name includes 'sizeof(SOME_TYPE)', record the dependency 1160 # on SOME_TYPE. 1161 match = self._SIZEOF_RE.search(field_name) 1162 if match: 1163 current_structure.AddDependency(match.group(1)) 1164 # Manually change unfortunate names. 1165 if field_name == 'xor': 1166 field_name = 'xor_' 1167 current_structure.AddField(field_type, field_name) 1168 self._NextLine() 1169 match = self._TYPE_RE.search(self._line) 1170 structures.append(current_structure) 1171 typemap[current_structure_name] = current_structure 1172 return structures 1173 1174 def _ParseDefines(self): 1175 """Parses preprocessor defines. 1176 1177 The current line should be _BEGIN_DEFINES and the method will stop parsing 1178 when an _END line is found. 1179 1180 Returns: 1181 A list of Define objects. 1182 """ 1183 defines = [] 1184 self._NextLine() 1185 while self._END_TOKEN != self._line.rstrip(): 1186 match = self._NAME_RE.search(self._line) 1187 if not match: 1188 print('Invalid name: %s' % self._line) 1189 return defines 1190 name = match.group(1) 1191 self._NextLine() 1192 match = self._VALUE_RE.search(self._line) 1193 if not match: 1194 print('Invalid value: %s' % self._line) 1195 return defines 1196 value = match.group(1) 1197 defines.append(Define(name, value)) 1198 self._NextLine() 1199 return defines 1200 1201 1202class Command(object): 1203 """Represents a TPM command. 1204 1205 Attributes: 1206 name: The command name (e.g. 'TPM2_Startup'). 1207 command_code: The name of the command code constant (e.g. TPM2_CC_Startup). 1208 request_args: A list to hold command input arguments. Each element is a dict 1209 and has these keys: 1210 'type': The argument type. 1211 'name': The argument name. 1212 'command_code': The optional value of the command code constant. 1213 'description': Optional descriptive text for the argument. 1214 response_args: A list identical in form to request_args but to hold command 1215 output arguments. 1216 """ 1217 1218 _HANDLE_RE = re.compile(r'TPMI_.H_.*') 1219 _CALLBACK_ARG = """ 1220 const %(method_name)sResponse& callback""" 1221 _DELEGATE_ARG = """ 1222 AuthorizationDelegate* authorization_delegate""" 1223 _SERIALIZE_ARG = """ 1224 std::string* serialized_command""" 1225 _PARSE_ARG = """ 1226 const std::string& response""" 1227 _SERIALIZE_FUNCTION_START = """ 1228TPM_RC Tpm::SerializeCommand_%(method_name)s(%(method_args)s) { 1229 VLOG(3) << __func__; 1230 TPM_RC rc = TPM_RC_SUCCESS; 1231 TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS; 1232 UINT32 command_size = 10; // Header size. 1233 std::string handle_section_bytes; 1234 std::string parameter_section_bytes;""" 1235 _DECLARE_COMMAND_CODE = """ 1236 TPM_CC command_code = %(command_code)s;""" 1237 _DECLARE_BOOLEAN = """ 1238 bool %(var_name)s = %(value)s;""" 1239 _SERIALIZE_LOCAL_VAR = """ 1240 std::string %(var_name)s_bytes; 1241 rc = Serialize_%(var_type)s( 1242 %(var_name)s, 1243 &%(var_name)s_bytes); 1244 if (rc != TPM_RC_SUCCESS) { 1245 return rc; 1246 }""" 1247 _ENCRYPT_PARAMETER = """ 1248 if (authorization_delegate) { 1249 // Encrypt just the parameter data, not the size. 1250 std::string tmp = %(var_name)s_bytes.substr(2); 1251 if (!authorization_delegate->EncryptCommandParameter(&tmp)) { 1252 return TRUNKS_RC_ENCRYPTION_FAILED; 1253 } 1254 %(var_name)s_bytes.replace(2, std::string::npos, tmp); 1255 }""" 1256 _HASH_START = """ 1257 std::unique_ptr<crypto::SecureHash> hash(crypto::SecureHash::Create( 1258 crypto::SecureHash::SHA256));""" 1259 _HASH_UPDATE = """ 1260 hash->Update(%(var_name)s.data(), 1261 %(var_name)s.size());""" 1262 _APPEND_COMMAND_HANDLE = """ 1263 handle_section_bytes += %(var_name)s_bytes; 1264 command_size += %(var_name)s_bytes.size();""" 1265 _APPEND_COMMAND_PARAMETER = """ 1266 parameter_section_bytes += %(var_name)s_bytes; 1267 command_size += %(var_name)s_bytes.size();""" 1268 _AUTHORIZE_COMMAND = """ 1269 std::string command_hash(32, 0); 1270 hash->Finish(string_as_array(&command_hash), command_hash.size()); 1271 std::string authorization_section_bytes; 1272 std::string authorization_size_bytes; 1273 if (authorization_delegate) { 1274 if (!authorization_delegate->GetCommandAuthorization( 1275 command_hash, 1276 is_command_parameter_encryption_possible, 1277 is_response_parameter_encryption_possible, 1278 &authorization_section_bytes)) { 1279 return TRUNKS_RC_AUTHORIZATION_FAILED; 1280 } 1281 if (!authorization_section_bytes.empty()) { 1282 tag = TPM_ST_SESSIONS; 1283 std::string tmp; 1284 rc = Serialize_UINT32(authorization_section_bytes.size(), 1285 &authorization_size_bytes); 1286 if (rc != TPM_RC_SUCCESS) { 1287 return rc; 1288 } 1289 command_size += authorization_size_bytes.size() + 1290 authorization_section_bytes.size(); 1291 } 1292 }""" 1293 _SERIALIZE_FUNCTION_END = """ 1294 *serialized_command = tag_bytes + 1295 command_size_bytes + 1296 command_code_bytes + 1297 handle_section_bytes + 1298 authorization_size_bytes + 1299 authorization_section_bytes + 1300 parameter_section_bytes; 1301 CHECK(serialized_command->size() == command_size) << "Command size mismatch!"; 1302 VLOG(2) << "Command: " << base::HexEncode(serialized_command->data(), 1303 serialized_command->size()); 1304 return TPM_RC_SUCCESS; 1305} 1306""" 1307 _RESPONSE_PARSER_START = """ 1308TPM_RC Tpm::ParseResponse_%(method_name)s(%(method_args)s) { 1309 VLOG(3) << __func__; 1310 VLOG(2) << "Response: " << base::HexEncode(response.data(), response.size()); 1311 TPM_RC rc = TPM_RC_SUCCESS; 1312 std::string buffer(response);""" 1313 _PARSE_LOCAL_VAR = """ 1314 %(var_type)s %(var_name)s; 1315 std::string %(var_name)s_bytes; 1316 rc = Parse_%(var_type)s( 1317 &buffer, 1318 &%(var_name)s, 1319 &%(var_name)s_bytes); 1320 if (rc != TPM_RC_SUCCESS) { 1321 return rc; 1322 }""" 1323 _PARSE_ARG_VAR = """ 1324 std::string %(var_name)s_bytes; 1325 rc = Parse_%(var_type)s( 1326 &buffer, 1327 %(var_name)s, 1328 &%(var_name)s_bytes); 1329 if (rc != TPM_RC_SUCCESS) { 1330 return rc; 1331 }""" 1332 _RESPONSE_ERROR_CHECK = """ 1333 if (response_size != response.size()) { 1334 return TPM_RC_SIZE; 1335 } 1336 if (response_code != TPM_RC_SUCCESS) { 1337 return response_code; 1338 }""" 1339 _RESPONSE_SECTION_SPLIT = """ 1340 std::string authorization_section_bytes; 1341 if (tag == TPM_ST_SESSIONS) { 1342 UINT32 parameter_section_size = buffer.size(); 1343 rc = Parse_UINT32(&buffer, ¶meter_section_size, nullptr); 1344 if (rc != TPM_RC_SUCCESS) { 1345 return rc; 1346 } 1347 if (parameter_section_size > buffer.size()) { 1348 return TPM_RC_INSUFFICIENT; 1349 } 1350 authorization_section_bytes = buffer.substr(parameter_section_size); 1351 // Keep the parameter section in |buffer|. 1352 buffer.erase(parameter_section_size); 1353 }""" 1354 _AUTHORIZE_RESPONSE = """ 1355 std::string response_hash(32, 0); 1356 hash->Finish(string_as_array(&response_hash), response_hash.size()); 1357 if (tag == TPM_ST_SESSIONS) { 1358 CHECK(authorization_delegate) << "Authorization delegate missing!"; 1359 if (!authorization_delegate->CheckResponseAuthorization( 1360 response_hash, 1361 authorization_section_bytes)) { 1362 return TRUNKS_RC_AUTHORIZATION_FAILED; 1363 } 1364 }""" 1365 _DECRYPT_PARAMETER = """ 1366 if (tag == TPM_ST_SESSIONS) { 1367 CHECK(authorization_delegate) << "Authorization delegate missing!"; 1368 // Decrypt just the parameter data, not the size. 1369 std::string tmp = %(var_name)s_bytes.substr(2); 1370 if (!authorization_delegate->DecryptResponseParameter(&tmp)) { 1371 return TRUNKS_RC_ENCRYPTION_FAILED; 1372 } 1373 %(var_name)s_bytes.replace(2, std::string::npos, tmp); 1374 rc = Parse_%(var_type)s( 1375 &%(var_name)s_bytes, 1376 %(var_name)s, 1377 nullptr); 1378 if (rc != TPM_RC_SUCCESS) { 1379 return rc; 1380 } 1381 }""" 1382 _RESPONSE_PARSER_END = """ 1383 return TPM_RC_SUCCESS; 1384} 1385""" 1386 _ERROR_CALLBACK_START = """ 1387void %(method_name)sErrorCallback( 1388 const Tpm::%(method_name)sResponse& callback, 1389 TPM_RC response_code) { 1390 VLOG(1) << __func__; 1391 callback.Run(response_code""" 1392 _ERROR_CALLBACK_ARG = """, 1393 %(arg_type)s()""" 1394 _ERROR_CALLBACK_END = """); 1395} 1396""" 1397 _RESPONSE_CALLBACK_START = """ 1398void %(method_name)sResponseParser( 1399 const Tpm::%(method_name)sResponse& callback, 1400 AuthorizationDelegate* authorization_delegate, 1401 const std::string& response) { 1402 VLOG(1) << __func__; 1403 base::Callback<void(TPM_RC)> error_reporter = 1404 base::Bind(%(method_name)sErrorCallback, callback);""" 1405 _DECLARE_ARG_VAR = """ 1406 %(var_type)s %(var_name)s;""" 1407 _RESPONSE_CALLBACK_END = """ 1408 TPM_RC rc = Tpm::ParseResponse_%(method_name)s( 1409 response,%(method_arg_names_out)s 1410 authorization_delegate); 1411 if (rc != TPM_RC_SUCCESS) { 1412 error_reporter.Run(rc); 1413 return; 1414 } 1415 callback.Run( 1416 rc%(method_arg_names_in)s); 1417} 1418""" 1419 _ASYNC_METHOD = """ 1420void Tpm::%(method_name)s(%(method_args)s) { 1421 VLOG(1) << __func__; 1422 base::Callback<void(TPM_RC)> error_reporter = 1423 base::Bind(%(method_name)sErrorCallback, callback); 1424 base::Callback<void(const std::string&)> parser = 1425 base::Bind(%(method_name)sResponseParser, 1426 callback, 1427 authorization_delegate); 1428 std::string command; 1429 TPM_RC rc = SerializeCommand_%(method_name)s(%(method_arg_names)s 1430 &command, 1431 authorization_delegate); 1432 if (rc != TPM_RC_SUCCESS) { 1433 error_reporter.Run(rc); 1434 return; 1435 } 1436 transceiver_->SendCommand(command, parser); 1437} 1438""" 1439 _SYNC_METHOD = """ 1440TPM_RC Tpm::%(method_name)sSync(%(method_args)s) { 1441 VLOG(1) << __func__; 1442 std::string command; 1443 TPM_RC rc = SerializeCommand_%(method_name)s(%(method_arg_names_in)s 1444 &command, 1445 authorization_delegate); 1446 if (rc != TPM_RC_SUCCESS) { 1447 return rc; 1448 } 1449 std::string response = transceiver_->SendCommandAndWait(command); 1450 rc = ParseResponse_%(method_name)s( 1451 response,%(method_arg_names_out)s 1452 authorization_delegate); 1453 return rc; 1454} 1455""" 1456 1457 def __init__(self, name): 1458 """Initializes a Command instance. 1459 1460 Initially the request_args and response_args attributes are not set. 1461 1462 Args: 1463 name: The command name (e.g. 'TPM2_Startup'). 1464 """ 1465 self.name = name 1466 self.command_code = '' 1467 self.request_args = None 1468 self.response_args = None 1469 1470 def OutputDeclarations(self, out_file): 1471 """Prints method and callback declaration statements for this command. 1472 1473 Args: 1474 out_file: The output file. 1475 """ 1476 self._OutputCallbackSignature(out_file) 1477 self._OutputMethodSignatures(out_file) 1478 1479 def OutputSerializeFunction(self, out_file): 1480 """Generates a serialize function for the command inputs. 1481 1482 Args: 1483 out_file: Generated code is written to this file. 1484 """ 1485 # Categorize arguments as either handles or parameters. 1486 handles, parameters = self._SplitArgs(self.request_args) 1487 response_parameters = self._SplitArgs(self.response_args)[1] 1488 out_file.write(self._SERIALIZE_FUNCTION_START % { 1489 'method_name': self._MethodName(), 1490 'method_args': self._SerializeArgs()}) 1491 out_file.write(self._DECLARE_COMMAND_CODE % {'command_code': 1492 self.command_code}) 1493 out_file.write(self._DECLARE_BOOLEAN % { 1494 'var_name': 'is_command_parameter_encryption_possible', 1495 'value': GetCppBool(parameters and IsTPM2B(parameters[0]['type']))}) 1496 out_file.write(self._DECLARE_BOOLEAN % { 1497 'var_name': 'is_response_parameter_encryption_possible', 1498 'value': GetCppBool(response_parameters and 1499 IsTPM2B(response_parameters[0]['type']))}) 1500 # Serialize the command code and all the handles and parameters. 1501 out_file.write(self._SERIALIZE_LOCAL_VAR % {'var_name': 'command_code', 1502 'var_type': 'TPM_CC'}) 1503 for arg in self.request_args: 1504 out_file.write(self._SERIALIZE_LOCAL_VAR % {'var_name': arg['name'], 1505 'var_type': arg['type']}) 1506 # Encrypt the first parameter (before doing authorization) if necessary. 1507 if parameters and IsTPM2B(parameters[0]['type']): 1508 out_file.write(self._ENCRYPT_PARAMETER % {'var_name': 1509 parameters[0]['name']}) 1510 # Compute the command hash and construct handle and parameter sections. 1511 out_file.write(self._HASH_START) 1512 out_file.write(self._HASH_UPDATE % {'var_name': 'command_code_bytes'}) 1513 for handle in handles: 1514 out_file.write(self._HASH_UPDATE % {'var_name': 1515 '%s_name' % handle['name']}) 1516 out_file.write(self._APPEND_COMMAND_HANDLE % {'var_name': 1517 handle['name']}) 1518 for parameter in parameters: 1519 out_file.write(self._HASH_UPDATE % {'var_name': 1520 '%s_bytes' % parameter['name']}) 1521 out_file.write(self._APPEND_COMMAND_PARAMETER % {'var_name': 1522 parameter['name']}) 1523 # Do authorization based on the hash. 1524 out_file.write(self._AUTHORIZE_COMMAND) 1525 # Now that the tag and size are finalized, serialize those. 1526 out_file.write(self._SERIALIZE_LOCAL_VAR % 1527 {'var_name': 'tag', 1528 'var_type': 'TPMI_ST_COMMAND_TAG'}) 1529 out_file.write(self._SERIALIZE_LOCAL_VAR % {'var_name': 'command_size', 1530 'var_type': 'UINT32'}) 1531 out_file.write(self._SERIALIZE_FUNCTION_END) 1532 1533 def OutputParseFunction(self, out_file): 1534 """Generates a parse function for the command outputs. 1535 1536 Args: 1537 out_file: Generated code is written to this file. 1538 """ 1539 out_file.write(self._RESPONSE_PARSER_START % { 1540 'method_name': self._MethodName(), 1541 'method_args': self._ParseArgs()}) 1542 # Parse the header -- this should always exist. 1543 out_file.write(self._PARSE_LOCAL_VAR % {'var_name': 'tag', 1544 'var_type': 'TPM_ST'}) 1545 out_file.write(self._PARSE_LOCAL_VAR % {'var_name': 'response_size', 1546 'var_type': 'UINT32'}) 1547 out_file.write(self._PARSE_LOCAL_VAR % {'var_name': 'response_code', 1548 'var_type': 'TPM_RC'}) 1549 # Handle the error case. 1550 out_file.write(self._RESPONSE_ERROR_CHECK) 1551 # Categorize arguments as either handles or parameters. 1552 handles, parameters = self._SplitArgs(self.response_args) 1553 # Parse any handles. 1554 for handle in handles: 1555 out_file.write(self._PARSE_ARG_VAR % {'var_name': handle['name'], 1556 'var_type': handle['type']}) 1557 # Setup a serialized command code which is needed for the response hash. 1558 out_file.write(self._DECLARE_COMMAND_CODE % {'command_code': 1559 self.command_code}) 1560 out_file.write(self._SERIALIZE_LOCAL_VAR % {'var_name': 'command_code', 1561 'var_type': 'TPM_CC'}) 1562 # Split out the authorization section. 1563 out_file.write(self._RESPONSE_SECTION_SPLIT) 1564 # Compute the response hash. 1565 out_file.write(self._HASH_START) 1566 out_file.write(self._HASH_UPDATE % {'var_name': 'response_code_bytes'}) 1567 out_file.write(self._HASH_UPDATE % {'var_name': 'command_code_bytes'}) 1568 out_file.write(self._HASH_UPDATE % {'var_name': 'buffer'}) 1569 # Do authorization related stuff. 1570 out_file.write(self._AUTHORIZE_RESPONSE) 1571 # Parse response parameters. 1572 for arg in parameters: 1573 out_file.write(self._PARSE_ARG_VAR % {'var_name': arg['name'], 1574 'var_type': arg['type']}) 1575 if parameters and IsTPM2B(parameters[0]['type']): 1576 out_file.write(self._DECRYPT_PARAMETER % {'var_name': 1577 parameters[0]['name'], 1578 'var_type': 1579 parameters[0]['type']}) 1580 out_file.write(self._RESPONSE_PARSER_END) 1581 1582 def OutputMethodImplementation(self, out_file): 1583 """Generates the implementation of a Tpm class method for this command. 1584 1585 The method assembles a command to be sent unmodified to the TPM and invokes 1586 the CommandTransceiver with the command. Errors are reported directly to the 1587 response callback via the error callback (see OutputErrorCallback). 1588 1589 Args: 1590 out_file: Generated code is written to this file. 1591 """ 1592 out_file.write(self._ASYNC_METHOD % { 1593 'method_name': self._MethodName(), 1594 'method_args': self._AsyncArgs(), 1595 'method_arg_names': self._ArgNameList(self._RequestArgs(), 1596 trailing_comma=True)}) 1597 out_file.write(self._SYNC_METHOD % { 1598 'method_name': self._MethodName(), 1599 'method_args': self._SyncArgs(), 1600 'method_arg_names_in': self._ArgNameList(self._RequestArgs(), 1601 trailing_comma=True), 1602 'method_arg_names_out': self._ArgNameList(self.response_args, 1603 trailing_comma=True)}) 1604 1605 def OutputErrorCallback(self, out_file): 1606 """Generates the implementation of an error callback for this command. 1607 1608 The error callback simply calls the command response callback with the error 1609 as the first argument and default values for all other arguments. 1610 1611 Args: 1612 out_file: Generated code is written to this file. 1613 """ 1614 out_file.write(self._ERROR_CALLBACK_START % {'method_name': 1615 self._MethodName()}) 1616 for arg in self.response_args: 1617 out_file.write(self._ERROR_CALLBACK_ARG % {'arg_type': arg['type']}) 1618 out_file.write(self._ERROR_CALLBACK_END) 1619 1620 def OutputResponseCallback(self, out_file): 1621 """Generates the implementation of a response callback for this command. 1622 1623 The response callback takes the unmodified response from the TPM, parses it, 1624 and invokes the original response callback with the parsed response args. 1625 Errors during parsing or from the TPM are reported directly to the response 1626 callback via the error callback (see OutputErrorCallback). 1627 1628 Args: 1629 out_file: Generated code is written to this file. 1630 """ 1631 out_file.write(self._RESPONSE_CALLBACK_START % {'method_name': 1632 self._MethodName()}) 1633 for arg in self.response_args: 1634 out_file.write(self._DECLARE_ARG_VAR % {'var_type': arg['type'], 1635 'var_name': arg['name']}) 1636 out_file.write(self._RESPONSE_CALLBACK_END % { 1637 'method_name': self._MethodName(), 1638 'method_arg_names_in': self._ArgNameList(self.response_args, 1639 leading_comma=True), 1640 'method_arg_names_out': self._ArgNameList(self.response_args, 1641 prefix='&', 1642 trailing_comma=True)}) 1643 1644 def GetNumberOfRequestHandles(self): 1645 """Returns the number of input handles for this command.""" 1646 return len(self._SplitArgs(self.request_args)[0]) 1647 1648 def GetNumberOfResponseHandles(self): 1649 """Returns the number of output handles for this command.""" 1650 return len(self._SplitArgs(self.response_args)[0]) 1651 1652 def _OutputMethodSignatures(self, out_file): 1653 """Prints method declaration statements for this command. 1654 1655 This includes a method to serialize a request, a method to parse a response, 1656 and methods for synchronous and asynchronous calls. 1657 1658 Args: 1659 out_file: The output file. 1660 """ 1661 out_file.write(' static TPM_RC SerializeCommand_%s(%s);\n' % ( 1662 self._MethodName(), self._SerializeArgs())) 1663 out_file.write(' static TPM_RC ParseResponse_%s(%s);\n' % ( 1664 self._MethodName(), self._ParseArgs())) 1665 out_file.write(' virtual void %s(%s);\n' % (self._MethodName(), 1666 self._AsyncArgs())) 1667 out_file.write(' virtual TPM_RC %sSync(%s);\n' % (self._MethodName(), 1668 self._SyncArgs())) 1669 1670 def _OutputCallbackSignature(self, out_file): 1671 """Prints a callback typedef for this command. 1672 1673 Args: 1674 out_file: The output file. 1675 """ 1676 args = self._InputArgList(self.response_args) 1677 if args: 1678 args = ',' + args 1679 args = '\n TPM_RC response_code' + args 1680 out_file.write(' typedef base::Callback<void(%s)> %sResponse;\n' % 1681 (args, self._MethodName())) 1682 1683 def _MethodName(self): 1684 """Creates an appropriate generated method name for the command. 1685 1686 We use the command name without the TPM2_ prefix. 1687 1688 Returns: 1689 The method name. 1690 """ 1691 if not self.name.startswith('TPM2_'): 1692 return self.name 1693 return self.name[5:] 1694 1695 def _InputArgList(self, args): 1696 """Formats a list of input arguments for use in a function declaration. 1697 1698 Args: 1699 args: An argument list in the same form as the request_args and 1700 response_args attributes. 1701 1702 Returns: 1703 A string which can be used in a function declaration. 1704 """ 1705 if args: 1706 arg_list = ['const %(type)s& %(name)s' % a for a in args] 1707 return '\n ' + ',\n '.join(arg_list) 1708 return '' 1709 1710 def _OutputArgList(self, args): 1711 """Formats a list of output arguments for use in a function declaration. 1712 1713 Args: 1714 args: An argument list in the same form as the request_args and 1715 response_args attributes. 1716 1717 Returns: 1718 A string which can be used in a function declaration. 1719 """ 1720 if args: 1721 arg_list = ['%(type)s* %(name)s' % a for a in args] 1722 return '\n ' + ',\n '.join(arg_list) 1723 return '' 1724 1725 def _ArgNameList(self, args, prefix='', leading_comma=False, 1726 trailing_comma=False): 1727 """Formats a list of arguments for use in a function call statement. 1728 1729 Args: 1730 args: An argument list in the same form as the request_args and 1731 response_args attributes. 1732 prefix: A prefix to be prepended to each argument. 1733 leading_comma: Whether to include a comma before the first argument. 1734 trailing_comma: Whether to include a comma after the last argument. 1735 1736 Returns: 1737 A string which can be used in a function call statement. 1738 """ 1739 if args: 1740 arg_list = [(prefix + a['name']) for a in args] 1741 header = '' 1742 if leading_comma: 1743 header = ',' 1744 trailer = '' 1745 if trailing_comma: 1746 trailer = ',' 1747 return header + '\n ' + ',\n '.join(arg_list) + trailer 1748 return '' 1749 1750 def _SplitArgs(self, args): 1751 """Splits a list of args into handles and parameters.""" 1752 handles = [] 1753 parameters = [] 1754 # These commands have handles that are serialized into the parameter 1755 # section. 1756 command_handle_parameters = { 1757 'TPM_CC_FlushContext': 'TPMI_DH_CONTEXT', 1758 'TPM_CC_Hash': 'TPMI_RH_HIERARCHY', 1759 'TPM_CC_LoadExternal': 'TPMI_RH_HIERARCHY', 1760 'TPM_CC_SequenceComplete': 'TPMI_RH_HIERARCHY', 1761 } 1762 # Handle type that appears in the handle section. 1763 always_handle = set(['TPM_HANDLE']) 1764 # Handle types that always appear as command parameters. 1765 always_parameter = set(['TPMI_RH_ENABLES', 'TPMI_DH_PERSISTENT']) 1766 if self.command_code in command_handle_parameters: 1767 always_parameter.add(command_handle_parameters[self.command_code]) 1768 for arg in args: 1769 if (arg['type'] in always_handle or 1770 (self._HANDLE_RE.search(arg['type']) and 1771 arg['type'] not in always_parameter)): 1772 handles.append(arg) 1773 else: 1774 parameters.append(arg) 1775 return handles, parameters 1776 1777 def _RequestArgs(self): 1778 """Computes the argument list for a Tpm request. 1779 1780 For every handle argument a handle name argument is added. 1781 """ 1782 handles, parameters = self._SplitArgs(self.request_args) 1783 args = [] 1784 # Add a name argument for every handle. We'll need it to compute cpHash. 1785 for handle in handles: 1786 args.append(handle) 1787 args.append({'type': 'std::string', 1788 'name': '%s_name' % handle['name']}) 1789 for parameter in parameters: 1790 args.append(parameter) 1791 return args 1792 1793 def _AsyncArgs(self): 1794 """Returns a formatted argument list for an asynchronous method.""" 1795 args = self._InputArgList(self._RequestArgs()) 1796 if args: 1797 args += ',' 1798 return (args + self._DELEGATE_ARG + ',' + 1799 self._CALLBACK_ARG % {'method_name': self._MethodName()}) 1800 1801 def _SyncArgs(self): 1802 """Returns a formatted argument list for a synchronous method.""" 1803 request_arg_list = self._InputArgList(self._RequestArgs()) 1804 if request_arg_list: 1805 request_arg_list += ',' 1806 response_arg_list = self._OutputArgList(self.response_args) 1807 if response_arg_list: 1808 response_arg_list += ',' 1809 return request_arg_list + response_arg_list + self._DELEGATE_ARG 1810 1811 def _SerializeArgs(self): 1812 """Returns a formatted argument list for a request-serialize method.""" 1813 args = self._InputArgList(self._RequestArgs()) 1814 if args: 1815 args += ',' 1816 return args + self._SERIALIZE_ARG + ',' + self._DELEGATE_ARG 1817 1818 def _ParseArgs(self): 1819 """Returns a formatted argument list for a response-parse method.""" 1820 args = self._OutputArgList(self.response_args) 1821 if args: 1822 args = ',' + args 1823 return self._PARSE_ARG + args + ',' + self._DELEGATE_ARG 1824 1825 1826class CommandParser(object): 1827 """Command definition parser. 1828 1829 The input text file is extracted from the PDF file containing the TPM 1830 command specification from the Trusted Computing Group. The syntax 1831 of the text file is defined by extract_commands.sh. 1832 """ 1833 1834 # Regular expressions to pull relevant bits from annotated lines. 1835 _INPUT_START_RE = re.compile(r'^_INPUT_START\s+(\w+)$') 1836 _OUTPUT_START_RE = re.compile(r'^_OUTPUT_START\s+(\w+)$') 1837 _TYPE_RE = re.compile(r'^_TYPE\s+(\w+)$') 1838 _NAME_RE = re.compile(r'^_NAME\s+(\w+)$') 1839 # Pull the command code from a comment like: _COMMENT TPM_CC_Startup {NV}. 1840 _COMMENT_CC_RE = re.compile(r'^_COMMENT\s+(TPM_CC_\w+).*$') 1841 _COMMENT_RE = re.compile(r'^_COMMENT\s+(.*)') 1842 # Args which are handled internally by the generated method. 1843 _INTERNAL_ARGS = ('tag', 'Tag', 'commandSize', 'commandCode', 'responseSize', 1844 'responseCode', 'returnCode') 1845 1846 def __init__(self, in_file): 1847 """Initializes a CommandParser instance. 1848 1849 Args: 1850 in_file: A file as returned by open() which has been opened for reading. 1851 """ 1852 self._line = None 1853 self._in_file = in_file 1854 1855 def _NextLine(self): 1856 """Gets the next input line. 1857 1858 Returns: 1859 The next input line if another line is available, None otherwise. 1860 """ 1861 try: 1862 self._line = self._in_file.next() 1863 except StopIteration: 1864 self._line = None 1865 1866 def Parse(self): 1867 """Parses everything in a commands file. 1868 1869 Returns: 1870 A list of extracted Command objects. 1871 """ 1872 commands = [] 1873 self._NextLine() 1874 if self._line != '_BEGIN\n': 1875 print('Invalid format for first line: %s\n' % self._line) 1876 return commands 1877 self._NextLine() 1878 1879 while self._line != '_END\n': 1880 cmd = self._ParseCommand() 1881 if not cmd: 1882 break 1883 commands.append(cmd) 1884 return commands 1885 1886 def _ParseCommand(self): 1887 """Parses inputs and outputs for a single TPM command. 1888 1889 Returns: 1890 A single Command object. 1891 """ 1892 match = self._INPUT_START_RE.search(self._line) 1893 if not match: 1894 print('Cannot match command input from line: %s\n' % self._line) 1895 return None 1896 name = match.group(1) 1897 cmd = Command(name) 1898 self._NextLine() 1899 cmd.request_args = self._ParseCommandArgs(cmd) 1900 match = self._OUTPUT_START_RE.search(self._line) 1901 if not match or match.group(1) != name: 1902 print('Cannot match command output from line: %s\n' % self._line) 1903 return None 1904 self._NextLine() 1905 cmd.response_args = self._ParseCommandArgs(cmd) 1906 request_var_names = set([arg['name'] for arg in cmd.request_args]) 1907 for arg in cmd.response_args: 1908 if arg['name'] in request_var_names: 1909 arg['name'] += '_out' 1910 if not cmd.command_code: 1911 print('Command code not found for %s' % name) 1912 return None 1913 return cmd 1914 1915 def _ParseCommandArgs(self, cmd): 1916 """Parses a set of arguments for a command. 1917 1918 The arguments may be input or output arguments. 1919 1920 Args: 1921 cmd: The current Command object. The command_code attribute will be set if 1922 such a constant is parsed. 1923 1924 Returns: 1925 A list of arguments in the same form as the Command.request_args and 1926 Command.response_args attributes. 1927 """ 1928 args = [] 1929 match = self._TYPE_RE.search(self._line) 1930 while match: 1931 arg_type = match.group(1) 1932 self._NextLine() 1933 match = self._NAME_RE.search(self._line) 1934 if not match: 1935 print('Cannot match argument name from line: %s\n' % self._line) 1936 break 1937 arg_name = match.group(1) 1938 self._NextLine() 1939 match = self._COMMENT_CC_RE.search(self._line) 1940 if match: 1941 cmd.command_code = match.group(1) 1942 match = self._COMMENT_RE.search(self._line) 1943 if match: 1944 self._NextLine() 1945 if arg_name not in self._INTERNAL_ARGS: 1946 args.append({'type': arg_type, 1947 'name': FixName(arg_name)}) 1948 match = self._TYPE_RE.search(self._line) 1949 return args 1950 1951 1952def GenerateHandleCountFunctions(commands, out_file): 1953 """Generates the GetNumberOf*Handles functions given a list of commands. 1954 1955 Args: 1956 commands: A list of Command objects. 1957 out_file: The output file. 1958 """ 1959 out_file.write(_HANDLE_COUNT_FUNCTION_START % {'handle_type': 'Request'}) 1960 for command in commands: 1961 out_file.write(_HANDLE_COUNT_FUNCTION_CASE % 1962 {'command_code': command.command_code, 1963 'handle_count': command.GetNumberOfRequestHandles()}) 1964 out_file.write(_HANDLE_COUNT_FUNCTION_END) 1965 out_file.write(_HANDLE_COUNT_FUNCTION_START % {'handle_type': 'Response'}) 1966 for command in commands: 1967 out_file.write(_HANDLE_COUNT_FUNCTION_CASE % 1968 {'command_code': command.command_code, 1969 'handle_count': command.GetNumberOfResponseHandles()}) 1970 out_file.write(_HANDLE_COUNT_FUNCTION_END) 1971 1972 1973def GenerateHeader(types, constants, structs, defines, typemap, commands): 1974 """Generates a header file with declarations for all given generator objects. 1975 1976 Args: 1977 types: A list of Typedef objects. 1978 constants: A list of Constant objects. 1979 structs: A list of Structure objects. 1980 defines: A list of Define objects. 1981 typemap: A dict mapping type names to the corresponding object. 1982 commands: A list of Command objects. 1983 """ 1984 out_file = open(_OUTPUT_FILE_H, 'w') 1985 out_file.write(_COPYRIGHT_HEADER) 1986 guard_name = 'TRUNKS_%s_' % _OUTPUT_FILE_H.upper().replace('.', '_') 1987 out_file.write(_HEADER_FILE_GUARD_HEADER % {'name': guard_name}) 1988 out_file.write(_HEADER_FILE_INCLUDES) 1989 out_file.write(_NAMESPACE_BEGIN) 1990 out_file.write(_FORWARD_DECLARATIONS) 1991 out_file.write('\n') 1992 # These types are built-in or defined by <stdint.h>; they serve as base cases 1993 # when defining type dependencies. 1994 defined_types = set(_BASIC_TYPES) 1995 # Generate defines. These must be generated before any other code. 1996 for define in defines: 1997 define.Output(out_file) 1998 out_file.write('\n') 1999 # Generate typedefs. These are declared before structs because they are not 2000 # likely to depend on structs and when they do a simple forward declaration 2001 # for the struct can be generated. This improves the readability of the 2002 # generated code. 2003 for typedef in types: 2004 typedef.Output(out_file, defined_types, typemap) 2005 out_file.write('\n') 2006 # Generate constant definitions. Again, generated before structs to improve 2007 # readability. 2008 for constant in constants: 2009 constant.Output(out_file, defined_types, typemap) 2010 out_file.write('\n') 2011 # Generate structs. All non-struct dependencies should be already declared. 2012 for struct in structs: 2013 struct.Output(out_file, defined_types, typemap) 2014 # Helper function declarations. 2015 out_file.write(_FUNCTION_DECLARATIONS) 2016 # Generate serialize / parse function declarations. 2017 for basic_type in _BASIC_TYPES: 2018 out_file.write(_SERIALIZE_DECLARATION % {'type': basic_type}) 2019 for typedef in types: 2020 out_file.write(_SERIALIZE_DECLARATION % {'type': typedef.new_type}) 2021 for struct in structs: 2022 out_file.write(_SERIALIZE_DECLARATION % {'type': struct.name}) 2023 if struct.IsSimpleTPM2B(): 2024 out_file.write(_SIMPLE_TPM2B_HELPERS_DECLARATION % {'type': struct.name}) 2025 elif struct.IsComplexTPM2B(): 2026 out_file.write(_COMPLEX_TPM2B_HELPERS_DECLARATION % { 2027 'type': struct.name, 2028 'inner_type': struct.fields[1][0]}) 2029 # Generate a declaration for a 'Tpm' class, which includes one method for 2030 # every TPM 2.0 command. 2031 out_file.write(_CLASS_BEGIN) 2032 for command in commands: 2033 command.OutputDeclarations(out_file) 2034 out_file.write(_CLASS_END) 2035 out_file.write(_NAMESPACE_END) 2036 out_file.write(_HEADER_FILE_GUARD_FOOTER % {'name': guard_name}) 2037 out_file.close() 2038 2039 2040def GenerateImplementation(types, structs, typemap, commands): 2041 """Generates implementation code for each command. 2042 2043 Args: 2044 types: A list of Typedef objects. 2045 structs: A list of Structure objects. 2046 typemap: A dict mapping type names to the corresponding object. 2047 commands: A list of Command objects. 2048 """ 2049 out_file = open(_OUTPUT_FILE_CC, 'w') 2050 out_file.write(_COPYRIGHT_HEADER) 2051 out_file.write(_LOCAL_INCLUDE % {'filename': _OUTPUT_FILE_H}) 2052 out_file.write(_IMPLEMENTATION_FILE_INCLUDES) 2053 out_file.write(_NAMESPACE_BEGIN) 2054 GenerateHandleCountFunctions(commands, out_file) 2055 serialized_types = set(_BASIC_TYPES) 2056 for basic_type in _BASIC_TYPES: 2057 out_file.write(_SERIALIZE_BASIC_TYPE % {'type': basic_type}) 2058 for typedef in types: 2059 typedef.OutputSerialize(out_file, serialized_types, typemap) 2060 for struct in structs: 2061 struct.OutputSerialize(out_file, serialized_types, typemap) 2062 for command in commands: 2063 command.OutputSerializeFunction(out_file) 2064 command.OutputParseFunction(out_file) 2065 command.OutputErrorCallback(out_file) 2066 command.OutputResponseCallback(out_file) 2067 command.OutputMethodImplementation(out_file) 2068 out_file.write(_NAMESPACE_END) 2069 out_file.close() 2070 2071 2072def FormatFile(filename): 2073 subprocess.call(['clang-format', '-i', '-style=file', filename]) 2074 2075 2076def main(): 2077 """A main function. 2078 2079 Both a TPM structures file and commands file are parsed and C++ header and C++ 2080 implementation file are generated. 2081 2082 Positional Args: 2083 structures_file: The extracted TPM structures file. 2084 commands_file: The extracted TPM commands file. 2085 """ 2086 parser = argparse.ArgumentParser(description='TPM 2.0 code generator') 2087 parser.add_argument('structures_file') 2088 parser.add_argument('commands_file') 2089 args = parser.parse_args() 2090 structure_parser = StructureParser(open(args.structures_file)) 2091 types, constants, structs, defines, typemap = structure_parser.Parse() 2092 command_parser = CommandParser(open(args.commands_file)) 2093 commands = command_parser.Parse() 2094 GenerateHeader(types, constants, structs, defines, typemap, commands) 2095 GenerateImplementation(types, structs, typemap, commands) 2096 FormatFile(_OUTPUT_FILE_H) 2097 FormatFile(_OUTPUT_FILE_CC) 2098 print('Processed %d commands.' % len(commands)) 2099 2100 2101if __name__ == '__main__': 2102 main() 2103